diff --git a/.cargo/audit.toml b/.cargo/audit.toml index fbc8447a84..8690df36b1 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -5,59 +5,23 @@ [advisories] # Known vulnerabilities that are tracked in https://github.com/cowprotocol/services/issues/3338 ignore = [ - # alloy-dyn-abi - DoS vulnerability (RUSTSEC-2025-0073) - # Needs upgrade to 1.4.1+ (part of alloy migration) - "RUSTSEC-2025-0073", + # rsa - Marvin Attack timing sidechannel (RUSTSEC-2023-0071) + # No patch available yet (cryptography vulnerability) + "RUSTSEC-2023-0071", - # idna - Punycode label vulnerability (RUSTSEC-2024-0421) - # Needs upgrade to 1.0.0+ (transitive dependency) - "RUSTSEC-2024-0421", + # derivative - Unmaintained (RUSTSEC-2024-0388) + # Evaluate alternatives (tracked in #3338) + "RUSTSEC-2024-0388", - # protobuf - Uncontrolled recursion (RUSTSEC-2024-0437) - # Needs upgrade to 3.7.2+ (transitive dependency) - "RUSTSEC-2024-0437", + # instant - Unmaintained (RUSTSEC-2024-0384) + # Use web-time instead (tracked in #3338) + "RUSTSEC-2024-0384", - # rsa - Marvin Attack timing sidechannel (RUSTSEC-2023-0071) - # No patch available yet (cryptography vulnerability) - "RUSTSEC-2023-0071", + # paste - Unmaintained (RUSTSEC-2024-0436) + # Archived upstream (tracked in #3338) + "RUSTSEC-2024-0436", - # sqlx - Binary protocol overflow (RUSTSEC-2024-0363) - # Needs upgrade to 0.8.1+ (breaking changes, tracked in #3338) - "RUSTSEC-2024-0363", - - # tracing-subscriber - ANSI escape injection (RUSTSEC-2025-0055) - # Needs upgrade to 0.3.20+ (minimal risk in current usage) - "RUSTSEC-2025-0055", - - # atty - Unmaintained (RUSTSEC-2024-0375) - # Migrate to std::io::IsTerminal (tracked in #3338) - "RUSTSEC-2024-0375", - - # atty - Unsound potential unaligned read (RUSTSEC-2021-0145) - # Will be removed when migrating to std::io::IsTerminal - "RUSTSEC-2021-0145", - - # derivative - Unmaintained (RUSTSEC-2024-0388) - # Evaluate alternatives (tracked in #3338) - "RUSTSEC-2024-0388", - - # adler - Unmaintained (RUSTSEC-2025-0056) - # Use adler2 instead (tracked in #3338) - "RUSTSEC-2025-0056", - - # instant - Unmaintained (RUSTSEC-2024-0384) - # Use web-time instead (tracked in #3338) - "RUSTSEC-2024-0384", - - # paste - Unmaintained (RUSTSEC-2024-0436) - # Archived upstream (tracked in #3338) - "RUSTSEC-2024-0436", - - # proc-macro-error - Unmaintained (RUSTSEC-2024-0370) - # Transitive dependency (tracked in #3338) - "RUSTSEC-2024-0370", - - # model crate - data race in Shared (RUSTSEC-2020-0140) - # Internal crate issue (tracked in #3338) - "RUSTSEC-2020-0140", + # model crate - data race in Shared (RUSTSEC-2020-0140) + # Internal crate issue (tracked in #3338) + "RUSTSEC-2020-0140", ] diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index bff29e6e17..0000000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -rustflags = ["--cfg", "tokio_unstable"] diff --git a/.claude/commands/debug-order.md b/.claude/commands/debug-order.md new file mode 100644 index 0000000000..359648cf0a --- /dev/null +++ b/.claude/commands/debug-order.md @@ -0,0 +1,28 @@ +--- +description: Debug why a CoW Protocol order failed to match +--- + +Debug order: $ARGUMENTS + +Read and follow the instructions in ./docs/COW_ORDER_DEBUG_SKILL.md to investigate this order. + +Key steps: +1. Parse the order UID and network from arguments (default: mainnet) +2. **Start with the debug endpoint** — fetch the comprehensive debug report first: + ```bash + source .env.claude && curl -s -H "X-API-Key: $COW_DEBUG_API_KEY" "https://partners.cow.fi/$NETWORK/restricted/api/v1/debug/order/$ORDER_UID" | jq . + ``` + This returns order details, lifecycle events, auction participation, proposed solutions, executions, trades, and settlement attempts — all in one call. +3. Analyze the debug report — key event meanings: + - `ready` = order made it into an auction (was sent to solvers) + - `considered` = a solver included this order in a solution but that solution didn't win + - `executing` = order is in the winning solution, being submitted on-chain + - `traded` = order was settled on-chain + - `filtered` / `invalid` = order was excluded (check the `reason` field) +4. Search Victoria Logs for additional context (filter reasons, error details, solver logs) + - For finding discarded solutions where the order UID appears in calldata, use regex: `.*ORDER_UID_WITHOUT_0X.*` plus `discarded` +5. Use DB queries or API calls only if the debug report is missing info or you need deeper investigation +6. Identify root cause and report findings with evidence +7. If you haven't found anything go wild and try all SQL / log searches / codebase searches you can think of + +Always show your evidence (log lines, DB results, API responses) when presenting findings. diff --git a/.clippy.toml b/.clippy.toml index df1ed0d00a..5d402a93d8 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,7 +1,6 @@ disallowed-methods = [ - { path = "web3::api::Net::version", reason = "Calling `eth().chain_id().await?.to_string()` is equivalent and is better supported." }, - { path = "alloy::rpc::client::RpcClient::new_batch", reason = "There is no need to manually send batched requests because the alloy transport layer batches requests automatically under the hood." }, - { path = "alloy::rpc::client::BatchRequest::new", reason = "There is no need to manually send batched requests because the alloy transport layer batches requests automatically under the hood." }, + { path = "alloy::rpc::client::RpcClient::new_batch", reason = "There is no need to manually send batched requests because the alloy transport layer batches requests automatically under the hood." }, + { path = "alloy::rpc::client::BatchRequest::new", reason = "There is no need to manually send batched requests because the alloy transport layer batches requests automatically under the hood." }, ] await-holding-invalid-types = [ "tracing::span::Entered", diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 15dfe48771..ddbfcc5790 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/base:bullseye +FROM mcr.microsoft.com/devcontainers/base:bookworm RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ # Remove imagemagick due to https://security-tracker.debian.org/tracker/CVE-2019-10131 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 00c2bca3c9..50617d50d9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,7 +16,7 @@ }, "ghcr.io/devcontainers/features/rust:1": {}, "ghcr.io/devcontainers/features/git:1": {}, - "ghcr.io/nlordell/features/foundry": {}, + "ghcr.io/nlordell/features/foundry": { "version": "v1.7.1" }, "ghcr.io/devcontainers/features/docker-in-docker:2": { "dockerDashComposeVersion": "v2" }, @@ -33,6 +33,17 @@ "seccomp=unconfined" ], + "containerEnv": { + "PGHOST": "localhost", + "PGPORT": "5432", + "PGUSER": "vscode", + "PGDATABASE": "vscode", + // Drop debug info from dev/test builds: the e2e test binary's debug info + // is large enough to get the linker OOM-killed on a stock setup. + "CARGO_PROFILE_DEV_DEBUG": "0", + "CARGO_PROFILE_TEST_DEBUG": "0" + }, + "customizations": { "vscode": { "settings": { @@ -51,7 +62,10 @@ // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "rustc --version", - "postCreateCommand": "rustup toolchain install nightly && cargo install flamegraph", + "postCreateCommand": "rustup toolchain install nightly --component rustfmt && cargo install flamegraph && cargo install cargo-nextest --locked && cargo install just --locked && bash .devcontainer/setup-e2e.sh", + + // (Re)start the local Postgres cluster on every container start. + "postStartCommand": "bash .devcontainer/start-postgres.sh", // Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "vscode" diff --git a/.devcontainer/setup-e2e.sh b/.devcontainer/setup-e2e.sh new file mode 100755 index 0000000000..044740f317 --- /dev/null +++ b/.devcontainer/setup-e2e.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# +# Provisions the one thing the e2e test suite needs but the base image can't +# provide out of the box: +# +# * Postgres server – we run a native server (rather than the docker-compose +# one) so it survives container restarts and is up before any test +# runs, then apply the flyway migrations the harness expects to +# already exist. +# +# anvil/forge come from the foundry devcontainer feature; their prebuilt binaries +# run directly on the bookworm base image (glibc >= 2.32), so nothing to do here. +# +# Runs as `postCreateCommand` (once, when the container is created). +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +# ----------------------------------------------------------------------------- +echo "==> postgres" +# Install a server only if no cluster exists yet (fresh container). Reuse whatever +# version is already present otherwise, so this is safe to re-run. +if ! ls -d /etc/postgresql/*/main >/dev/null 2>&1; then + echo " installing postgresql-16..." + sudo apt-get update -qq + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq postgresql-16 +fi +PG_VERSION="$(ls /etc/postgresql | sort -n | tail -1)" +echo " using cluster ${PG_VERSION}/main" + +# Start the cluster (shared with postStart so the two can't drift). +bash "$REPO_ROOT/.devcontainer/start-postgres.sh" + +# Trust auth for local connections (development container only). +HBA="/etc/postgresql/${PG_VERSION}/main/pg_hba.conf" +sudo tee "$HBA" >/dev/null <<'EOF' +local all all trust +host all all 127.0.0.1/32 trust +host all all ::1/128 trust +EOF +sudo pg_ctlcluster "$PG_VERSION" main reload + +# The e2e harness connects with the bare url `postgresql://`, which resolves to a +# role and database named after $PGUSER/$PGDATABASE (see containerEnv in +# devcontainer.json and DatabasePoolConfig::test_default). +psql -h 127.0.0.1 -U postgres -d postgres -tAc \ + "SELECT 1 FROM pg_roles WHERE rolname='${PGUSER}'" | grep -q 1 \ + || psql -h 127.0.0.1 -U postgres -d postgres -c \ + "CREATE ROLE \"${PGUSER}\" LOGIN SUPERUSER;" +psql -h 127.0.0.1 -U postgres -d postgres -tAc \ + "SELECT 1 FROM pg_database WHERE datname='${PGDATABASE}'" | grep -q 1 \ + || psql -h 127.0.0.1 -U postgres -d postgres -c \ + "CREATE DATABASE \"${PGDATABASE}\" OWNER \"${PGUSER}\";" + +# Apply the migrations with the same flyway image the rest of the repo uses +# (see docker-compose.yaml). Flyway tracks what it has already applied, so this is +# incremental and idempotent: re-running only applies new migrations and fails +# loudly if one is incompatible with the current schema. The native server runs +# on the host network namespace, so `--network=host` lets flyway reach it on +# 127.0.0.1:${PGPORT}. +echo " applying flyway migrations..." +docker run --rm --network=host \ + -v "$REPO_ROOT/database/sql:/flyway/sql:ro" \ + -v "$REPO_ROOT/database/conf:/flyway/conf:ro" \ + flyway/flyway:10.7.1 \ + -url="jdbc:postgresql://127.0.0.1:${PGPORT}/${PGDATABASE}?user=${PGUSER}&password=" \ + migrate + +echo "==> e2e environment ready (postgres)" diff --git a/.devcontainer/start-postgres.sh b/.devcontainer/start-postgres.sh new file mode 100755 index 0000000000..95a9db5755 --- /dev/null +++ b/.devcontainer/start-postgres.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# +# Starts the local Postgres cluster on every container start. There is no init +# system in the container, so the cluster does not come up on its own after a +# stop/start. Provisioning (install, role, db, migrations) is done once by +# setup-e2e.sh; this only (re)starts what already exists. +# +# Runs as `postStartCommand`. +set -euo pipefail + +PG_VERSION="$(ls /etc/postgresql | sort -n | tail -1)" + +# `start` errors if the cluster is already running, so only start it when it +# isn't online; a genuine start failure then surfaces instead of being swallowed. +if ! pg_lsclusters -h "$PG_VERSION" main | grep -q online; then + sudo pg_ctlcluster "$PG_VERSION" main start +fi diff --git a/.gemini/config.yaml b/.gemini/config.yaml new file mode 100644 index 0000000000..d4a86ca56a --- /dev/null +++ b/.gemini/config.yaml @@ -0,0 +1,5 @@ +code_review: + pull_request_opened: + summary: false + code_review: true + include_drafts: false diff --git a/.gemini/styleguide.md b/.gemini/styleguide.md new file mode 100644 index 0000000000..0ad79576e1 --- /dev/null +++ b/.gemini/styleguide.md @@ -0,0 +1,15 @@ +# Code Review Style Guide: Stricter & Actionable Feedback Only + +## 1. Interaction & Noise Reduction +* **No Positive Feedback:** Do not post comments that praise the code, highlight "good solutions," or confirm that a change is a "good improvement." +* **Confirm Clean Reviews:** If no critical issues are found, post a single summary comment stating "No critical issues found" rather than staying silent. +* **Severity Threshold:** Only surface findings that meet the "High" or "Critical" severity criteria. Treat "Medium" findings as "Low" and ignore them unless they represent a direct logic error. +* **Focus on Changed Code:** Only comment on code that was actually modified in the PR. Do not flag issues in unchanged code or code that was simply moved/refactored without logic changes, unless the issue is a severe security vulnerability or critical bug. + +## 2. Technical Standards +* **Actionability:** Every comment must include a clear, actionable suggestion for improvement. Do not leave "FYI" or informational comments. +* **Edge Cases & Logic:** Focus exclusively on identifying missing edge cases, potential race conditions, or logic that deviates from the PR's stated goals. +* **Security & Performance:** Prioritize findings related to resource leaks, unnecessary complexity, or potential security vulnerabilities. + +## 3. Formatting +* **Conciseness:** Keep comments concise, direct and technical. Skip the introductory and concluding pleasantries. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9b233fde8e..a624f2439b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ * @cowprotocol/backend - +.github/workflows/ @cowprotocol/devops @cowprotocol/backend diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000000..3db817d664 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,4 @@ +name: "CoW Protocol CodeQL Config" + +paths-ignore: + - crates/e2e diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8384695eaf..b55ab18b58 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,8 +4,8 @@ # Changes -- [ ] ... -- [ ] ... +* ... +* ... ## How to test \ No newline at end of file +--> diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 0000000000..76bf9bc767 --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,27 @@ +// This file follows JSON5 syntax, to make it +// easier to maintain. +{ + $schema: "https://docs.renovatebot.com/renovate-schema.json", + // Disable every built-in manager (npm, dockerfile, ...) except github-actions. + enabledManagers: ["github-actions"], + // PR titles use Conventional Commits: `deps(): ...` + semanticCommits: "enabled", + semanticCommitType: "deps", + packageRules: [ + // GitHub Actions updates: run weekly, skip releases newer than 2 weeks + // to avoid picking up freshly published versions that may be unstable or + // compromised, and pin to full commit SHAs (with the version as a + // trailing comment) rather than mutable tags. + // When both major and minor releases exist, propose only the latest bump + // (typically major) instead of a separate minor PR. + { + matchManagers: ["github-actions"], + schedule: ["on monday"], + minimumReleaseAge: "14 days", + pinDigests: true, + separateMajorMinor: false, + semanticCommitScope: "{{depName}}", + commitMessageTopic: "{{depName}}", + }, + ], +} diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml index c162c1639c..ba0bdfe448 100644 --- a/.github/workflows/add-to-project.yml +++ b/.github/workflows/add-to-project.yml @@ -10,7 +10,7 @@ jobs: name: Add issue to project runs-on: ubuntu-latest steps: - - uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2 + - uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2.0.0 with: project-url: https://github.com/orgs/cowprotocol/projects/8 github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml new file mode 100644 index 0000000000..12c2c36cf7 --- /dev/null +++ b/.github/workflows/claude-review.yml @@ -0,0 +1,64 @@ +name: Claude PR Review +on: + pull_request: + types: [opened, ready_for_review] + issue_comment: + types: [created] + +jobs: + authorize: + # Payload-only pre-filter: no API call for bots / drafts / skip-label. + # Bots excluded HERE (not via the permission check) so they're skipped + # even if a bot account is ever granted write access. + if: > + ( + github.event_name == 'pull_request' && + github.event.pull_request.draft == false && + github.event.pull_request.user.type != 'Bot' && + !contains(github.event.pull_request.labels.*.name, 'skip-claude-review') + ) || ( + github.event_name == 'issue_comment' && + github.event.issue.pull_request != null && + github.event.comment.user.type != 'Bot' && + contains(github.event.comment.body, '@claude') + ) + runs-on: ubuntu-latest + outputs: + allowed: ${{ steps.check.outputs.allowed }} + steps: + - id: check + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + AUTHOR: ${{ github.event.pull_request.user.login || github.event.comment.user.login }} + run: | + allowed=$(gh api "repos/$REPO/collaborators/$AUTHOR/permission" \ + --jq '.user.permissions.push' 2>/dev/null || echo false) + echo "allowed=$allowed" >> "$GITHUB_OUTPUT" + review: + needs: authorize + if: needs.authorize.outputs.allowed == 'true' + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + pull-requests: write + issues: write + id-token: write + actions: read + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + # Full history lets the action compute an accurate diff vs the base + # branch instead of just the latest commit. + fetch-depth: 0 + + - uses: anthropics/claude-code-action@4d7e1f0cd85743fdc93b1c8040ab54395da024e2 # v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + trigger_phrase: "@claude" + track_progress: true + claude_args: | + --model claude-opus-4-7 + --max-turns 30 + prompt: "Review this PR. Use the pr-review skill if available." diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 60b13c2982..c18d8df2a3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -26,15 +26,16 @@ jobs: build-mode: none steps: - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Initialize CodeQL - uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} + config-file: .github/codeql/codeql-config.yml - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index a5078d998a..bff137cbcd 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -4,6 +4,21 @@ on: branches: [main] tags: [v*] workflow_dispatch: + inputs: + predefined_feature: + description: 'Select a predefined feature' + type: choice + options: + - 'None' + - 'mimalloc-allocator' + - 'tokio-console' + default: 'None' + required: false + custom_features: + description: 'Additional custom features (space-separated, e.g., "feature1 feature2")' + type: string + required: false + default: '' jobs: deploy: @@ -13,43 +28,81 @@ jobs: packages: write steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # Without this the fetch depth defaults to 1, which only includes the most recent commit. We want to know the full history so that `git describe` can give more information when it is invoked in the orderbook's crate build script. fetch-depth: '0' persist-credentials: false - - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Prepare build features + id: features + run: | + FEATURES="" + + if [ "${{ github.event.inputs.predefined_feature }}" != "None" ]; then + FEATURES="${{ github.event.inputs.predefined_feature }}" + fi + + if [ -n "${{ github.event.inputs.custom_features }}" ]; then + FEATURES="${FEATURES:+$FEATURES }${{ github.event.inputs.custom_features }}" + fi + + if [ -n "$FEATURES" ]; then + CARGO_FEATURES="--features $FEATURES" + fi + + if echo "$FEATURES" | grep -q "tokio-console"; then + RUSTFLAGS="--cfg tokio_unstable" + fi + + echo "cargo_features=$CARGO_FEATURES" >> $GITHUB_OUTPUT + echo "rustflags=$RUSTFLAGS" >> $GITHUB_OUTPUT + echo "Combined features: $FEATURES" + echo "Cargo features arg: $CARGO_FEATURES" + echo "RUSTFLAGS: $RUSTFLAGS" + - name: Services image metadata id: meta_services - uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 + uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 with: images: ghcr.io/${{ github.repository }} + tags: | + type=sha + type=ref,event=branch + type=ref,event=tag labels: | org.opencontainers.image.licenses=GPL-3.0-or-later - name: Services image build - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . file: Dockerfile push: true tags: ${{ steps.meta_services.outputs.tags }} labels: ${{ steps.meta_services.outputs.labels }} + build-args: | + CARGO_BUILD_FEATURES=${{ steps.features.outputs.cargo_features }} + RUSTFLAGS=${{ steps.features.outputs.rustflags }} - name: Migration image metadata id: meta_migration - uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 + uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 with: images: ghcr.io/${{ github.repository }}-migration + tags: | + type=sha + type=ref,event=branch + type=ref,event=tag labels: | org.opencontainers.image.licenses=GPL-3.0-or-later - name: Migration image build - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . file: Dockerfile diff --git a/.github/workflows/hotfix.yml b/.github/workflows/hotfix.yml index 79091f0ad4..c9955942d9 100644 --- a/.github/workflows/hotfix.yml +++ b/.github/workflows/hotfix.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: token: "${{ secrets.HOTFIX_ACTION_TOKEN }}" fetch-depth: 0 @@ -73,7 +73,7 @@ jobs: BUMP: ${{ steps.bump.outputs.tag }} - name: "Create hotfix release" - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: "${{ secrets.HOTFIX_ACTION_TOKEN }}" script: | diff --git a/.github/workflows/playground-check.yaml b/.github/workflows/playground-check.yaml index 329298ce84..b4e1cc83ce 100644 --- a/.github/workflows/playground-check.yaml +++ b/.github/workflows/playground-check.yaml @@ -24,7 +24,7 @@ jobs: swap-storage: false - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -32,7 +32,7 @@ jobs: run: sudo apt-get -qq update && sudo apt-get -y -q install curl jq - name: Install Foundry - uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0 + uses: foundry-rs/foundry-toolchain@c7450ba673e133f5ee30098b3b54f444d3a2ca2d # v1.8.0 - name: Setup environment run: | @@ -68,7 +68,7 @@ jobs: - name: Upload logs to GitHub if: failure() id: artifact-upload-step - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: logs.tgz path: ./logs.tgz @@ -76,8 +76,10 @@ jobs: - name: Slack notification on failure if: failure() id: slack - uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 + uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3 with: + webhook: ${{ secrets.SLACK_PLAYGROUND_CI_WEBHOOK_URL }} + webhook-type: webhook-trigger payload: | { "channel_id": "C037PB929ME", @@ -89,5 +91,3 @@ jobs: "step_test_script":"${{ steps.test_script.conclusion }}", "log_artifcat":"${{ steps.artifact-upload-step.outputs.artifact-url }}" } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_PLAYGROUND_CI_WEBHOOK_URL }} diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index a6703d8377..72ceb88b16 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -5,57 +5,62 @@ on: # We require PRs to be up to date before merging so technically it is not needed run the rust job # on main. However for the cache to be usable in PRs we do need the job on main. push: - branches: [ main ] + branches: [main] jobs: lint: timeout-minutes: 60 runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - - uses: actions-rs/toolchain@b2417cde72dcf67f306c0ae8e0828a81bf0b189f # v1.0.6 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: profile: minimal toolchain: nightly components: rustfmt - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 + - uses: tombi-toml/setup-tombi@74c3f4f31e7915e27c3397831e4c628463e3e0da # v1.1.1 + with: + version: "1.1.0" - run: | rustup --version rustup show cargo --version cargo +nightly fmt --version cargo clippy --version + tombi --version - run: just fmt --check - - run: just clippy - + - run: just clippy + - run: just fmt-toml --check + trivy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Run Trivy - uses: aquasecurity/trivy-action@dc5a429b52fcf669ce959baa2c2dd26090d2a6c4 # v0.32.0 + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: - scan-type: 'fs' - format: 'sarif' - output: 'trivy-results.sarif' + scan-type: "fs" + format: "sarif" + output: "trivy-results.sarif" - name: Upload Trivy scan results to GitHub Security - uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 + uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: - sarif_file: 'trivy-results.sarif' + sarif_file: "trivy-results.sarif" cargo-audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal @@ -66,7 +71,7 @@ jobs: nitpicker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: ethanis/nitpicker@e891622bbd9a6ec97a473bcfacfca7332caf2862 # v1.7 @@ -78,14 +83,14 @@ jobs: timeout-minutes: 60 runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 - run: rustup toolchain install stable --profile minimal - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - run: just test-doc unit-tests: @@ -97,13 +102,15 @@ jobs: CARGO_PROFILE_TEST_DEBUG: 0 CARGO_TERM_COLOR: always steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - - uses: taiki-e/install-action@e4767ccc6762bc4347ef2275c75ea77f5f36e27f # nextest - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1 + with: + tool: nextest + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 - run: cargo build --tests @@ -118,24 +125,20 @@ jobs: CARGO_PROFILE_TEST_DEBUG: 0 CARGO_TERM_COLOR: always steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 # Start the build process in the background. The following cargo test command will automatically # wait for the build process to be done before proceeding. - run: cargo build -p orderbook -p database -p autopilot --tests & - - uses: taiki-e/install-action@e4767ccc6762bc4347ef2275c75ea77f5f36e27f # nextest - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 - with: - file: docker-compose.yaml - up-opts: -d db - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 + - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1 with: - file: docker-compose.yaml - up-opts: migrations --abort-on-container-failure - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + tool: nextest + - run: docker compose -f docker-compose.yaml up -d db + - run: docker compose -f docker-compose.yaml up migrations --abort-on-container-failure + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 - run: just test-db @@ -150,25 +153,21 @@ jobs: CARGO_TERM_COLOR: always TOML_TRACE_ERROR: 1 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal - - uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0 - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 + - uses: foundry-rs/foundry-toolchain@c7450ba673e133f5ee30098b3b54f444d3a2ca2d # v1.8.0 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 # Start the build process in the background. The following cargo test command will automatically # wait for the build process to be done before proceeding. - run: cargo build -p e2e --tests & - - uses: taiki-e/install-action@e4767ccc6762bc4347ef2275c75ea77f5f36e27f # nextest - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 + - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1 with: - file: docker-compose.yaml - up-opts: -d db - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 - with: - file: docker-compose.yaml - up-opts: migrations --abort-on-container-failure - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + tool: nextest + - run: docker compose -f docker-compose.yaml up -d db + - run: docker compose -f docker-compose.yaml up migrations --abort-on-container-failure + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 - run: just test-e2e-local @@ -189,29 +188,25 @@ jobs: FORK_URL_GNOSIS: ${{ secrets.FORK_URL_GNOSIS }} TOML_TRACE_ERROR: 1 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal - - uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0 + - uses: foundry-rs/foundry-toolchain@c7450ba673e133f5ee30098b3b54f444d3a2ca2d # v1.8.0 with: # the latest version introduced a bug caused forked node tests to fail # only switch back to latest stable version after it was fixed in anvil version: v1.0.0 - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 # Start the build process in the background. The following cargo test command will automatically # wait for the build process to be done before proceeding. - run: cargo build -p e2e --tests & - - uses: taiki-e/install-action@e4767ccc6762bc4347ef2275c75ea77f5f36e27f # nextest - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 - with: - file: docker-compose.yaml - up-opts: -d db - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 + - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1 with: - file: docker-compose.yaml - up-opts: migrations --abort-on-container-failure - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + tool: nextest + - run: docker compose -f docker-compose.yaml up -d db + - run: docker compose -f docker-compose.yaml up migrations --abort-on-container-failure + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 - run: just test-e2e-forked @@ -226,14 +221,16 @@ jobs: CARGO_TERM_COLOR: always TOML_TRACE_ERROR: 1 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal - - uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0 - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - - uses: taiki-e/install-action@e4767ccc6762bc4347ef2275c75ea77f5f36e27f # nextest - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + - uses: foundry-rs/foundry-toolchain@c7450ba673e133f5ee30098b3b54f444d3a2ca2d # v1.8.0 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1 + with: + tool: nextest + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 # Build the driver's tests. @@ -241,11 +238,32 @@ jobs: # Don't spawn any docker containers. The driver's tests will spawn anvil itself. - run: just test-driver + solidity-artifacts: + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Build Solidity artifacts + working-directory: contracts/solidity + run: make -B artifacts + - name: Verify no JSON changes + run: | + if git diff --exit-code -- 'contracts/artifacts/*.json'; then + echo "✓ Solidity artifacts are up-to-date" + else + echo "✗ Solidity artifacts are out-of-date. Please run 'cd contracts/solidity && make -B artifacts' and commit the changes." + # run the command again to show exactly what the changes would be + git diff --exit-code -- 'contracts/artifacts/*.json' + exit 1 + fi + openapi: timeout-minutes: 60 runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: npm install @apidevtools/swagger-cli @stoplight/spectral-cli @@ -270,25 +288,21 @@ jobs: FORK_URL_MAINNET: ${{ secrets.FORK_URL_MAINNET }} FORK_URL_GNOSIS: ${{ secrets.FORK_URL_GNOSIS }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - run: rustup toolchain install stable --profile minimal - - uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0 - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 + - uses: foundry-rs/foundry-toolchain@c7450ba673e133f5ee30098b3b54f444d3a2ca2d # v1.8.0 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 # Start the build process in the background. The following cargo test command will automatically # wait for the build process to be done before proceeding. - run: cargo build -p e2e --tests & - - uses: taiki-e/install-action@e4767ccc6762bc4347ef2275c75ea77f5f36e27f # nextest - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 + - uses: taiki-e/install-action@e49978b799e49ff429d162b7a30601a569ab6538 # v2.81.1 with: - file: docker-compose.yaml - up-opts: -d db - - uses: yu-ichiro/spin-up-docker-compose-action@b7808421e139a485cb455f78e66605ca9dbe4334 # v1.2 - with: - file: docker-compose.yaml - up-opts: migrations --abort-on-container-failure - - uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff + tool: nextest + - run: docker compose -f docker-compose.yaml up -d db + - run: docker compose -f docker-compose.yaml up migrations --abort-on-container-failure + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 with: just-version: 1.39.0 - name: Run test in a loop @@ -301,3 +315,29 @@ jobs: fi attempt=$((attempt+1)) done + + generated-contracts: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - run: rustup toolchain install stable --profile minimal + - run: rustup toolchain install nightly --profile minimal --component rustfmt + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + - uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4.0.0 + with: + just-version: 1.39.0 + - uses: tombi-toml/setup-tombi@74c3f4f31e7915e27c3397831e4c628463e3e0da # v1.1.1 + with: + version: "1.1.0" + - name: Verify the code hasn't been tampered with by generating contracts again and making sure there has been no changes + run: | + just generate-contracts + if git diff --exit-code; then + echo "✓ Generated contracts are up-to-date" + else + echo "✗ Generated contracts are out-of-date or were modified by hand. Please run 'just generate-contracts' and commit the changes." + exit 1 + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8a05d78a9f..55897796e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 # Fetch all history for all branches and tags # Requires "Read and Write access to code" permission @@ -53,7 +53,7 @@ jobs: - name: "Create release" if: env.CHANGES_DETECTED == 'true' - uses: "actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea" # v7.0.1 + uses: "actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3" # v9.0.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" script: | diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 0cff4341b2..14ea7a20b0 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Close stale pull requests - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 + uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0 with: days-before-stale: 7 days-before-issue-stale: 60 diff --git a/.gitignore b/.gitignore index 5ff5e4c1e7..b86a4933ba 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /.idea **/testing.*.toml /playground/.env +.env.claude diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000000..609c8b46d2 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,25 @@ +{ + "mcpServers": { + "postgres-protocol": { + "command": "/bin/bash", + "args": [ + "-c", + "set -a && source .env.claude && set +a && npx -y @modelcontextprotocol/server-postgres \"${COW_DB_URL}\"" + ] + }, + "postgres-analytics": { + "command": "/bin/bash", + "args": [ + "-c", + "set -a && source .env.claude && set +a && npx -y @modelcontextprotocol/server-postgres \"${COW_ANALYTICS_DB_URL}\"" + ] + }, + "fetch": { + "command": "/bin/bash", + "args": [ + "-c", + "set -a && source .env.claude && set +a && /opt/homebrew/bin/uvx mcp-server-fetch" + ] + } + } +} diff --git a/.tombi.toml b/.tombi.toml new file mode 100644 index 0000000000..1d08999629 --- /dev/null +++ b/.tombi.toml @@ -0,0 +1,5 @@ +[files] +include = ["**/*.toml"] + +[format.rules] +line-width = 120 diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..190f74c481 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "tombi-toml.tombi" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..eee1ee632a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "[toml]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "tombi-toml.tombi" + }, + "rust-analyzer.rustfmt.overrideCommand": [ + "rustfmt", + "+nightly", + "--edition=2024" + ] +} diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000000..921c386044 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,13 @@ +{ + "languages": { + "TOML": { + "language_servers": ["tombi"], + "formatter": { + "language_server": { + "name": "tombi", + }, + }, + "format_on_save": "on", + }, + }, +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..45269b7fd2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,254 @@ +# Cow Protocol Services + +Backend services for Cow Protocol, a decentralized trading protocol with batch auctions on EVM networks. + +## Project Structure + +This is a Rust workspace containing multiple services and libraries: + +### Main Services (Binaries) +- **orderbook** - HTTP API for order submission and queries +- **autopilot** - Protocol driver that manages auctions +- **driver** - Handles liquidity collection and solution selection +- **solvers** - Internal solver engine (baseline) +- **refunder** - Handles refunds + +### Key Libraries +- **shared** - Common functionality (pricing, liquidity, gas estimation) +- **database** - PostgreSQL abstraction and migrations +- **model** - Serialization models for API +- **contracts** - Smart contract bindings +- **ethrpc** - Extended Ethereum RPC client with batching layer +- **chain** - Blockchain interaction utilities +- **number** - Numerical type extensions and conversions for 256-bit integers +- **app-data** - Order metadata validation with 8KB default size limit +- **alerter** - Monitors orderbook metrics for orders that should be solved but aren't +- **testlib** - Shared helpers for writing unit and end-to-end tests +- **observe** - Initialization and helper functions for logging and metrics + +## Architecture Overview + +``` +User signs order → Orderbook validates → Autopilot includes in auction + ↓ + ┌─────────────────────────┴─────────────────────────┐ + ↓ ↓ + Colocated External Solvers Our Drivers + Non-Colocated Solvers + (run their own driver+solver) ↓ ↓ + │ Our solvers External solver APIs + │ (baseline, (non-colocated partners + │ balancer, ...) like 1inch, 0x, etc) + └─────────────────────────┬─────────────────────────┘ + ↓ + Autopilot ranks solutions, picks winner(s) + ↓ + Winning driver submits to chain (2-3 block window) + ↓ + Settlement contract executes: + 1. Pre-interactions (incl user pre-hooks) + 2. Transfer sell tokens in + 3. Main interactions (swaps/routing) + 4. Pay out buy tokens + 5. Post-interactions (incl user post-hooks) + ↓ + Circuit breaker monitors compliance +``` + +**Solver types:** +- **Colocated**: External partners run their own driver + solver. Full control, full responsibility. +- **Non-colocated**: We run the driver, configured with their solver API endpoint. We handle simulation/submission. + +**Key components:** +- **Orderbook**: Validates + stores orders, handles quoting +- **Autopilot**: Central auctioneer, runs every ~12-15s (eventually every block), filters orders, adds fee policies, sends auction to solvers, ranks solutions +- **Driver**: Fetches liquidity, encodes solutions to calldata, simulates, submits to chain. Handles everything except route-finding. +- **Solver Engine**: Pure math — finds best routes/matches. Can be internal (baseline, balancer) or external API calls. +- **Circuit Breaker**: Monitors on-chain settlements match off-chain auction outcomes. Jails misbehaving solvers. + +## Technology Stack + +- **Language**: Rust 2024 Edition +- **Runtime**: Tokio async +- **Database**: PostgreSQL with sqlx +- **Web3**: Alloy +- **HTTP**: Axum + +## Documentation + +- **Protocol Documentation**: https://docs.cow.fi/ + - Technical Reference: API specs and SDK docs + - Concepts: Protocol fundamentals and architecture +- **Alloy (Web3 library)**: Fetch https://alloy.rs/introduction/prompting for an AI-optimized guide covering providers, transactions, contracts, and migration from ethers-rs + +## Development Commands + +### Testing +- Use `cargo nextest run` instead of `cargo test` (CI uses nextest and handles global state differently) +- Run specific test suites: + - Unit tests: `cargo nextest run` + - Database tests: `cargo nextest run postgres -p orderbook -p database -p autopilot --test-threads 1 --run-ignored ignored-only` + - E2E local tests: `cargo nextest run -p e2e local_node --test-threads 1 --failure-output final --run-ignored ignored-only` + - E2E forked tests: `cargo nextest run -p e2e forked_node --test-threads 1 --run-ignored ignored-only --failure-output final` + - Driver tests: `RUST_MIN_STACK=3145728 cargo nextest run -p driver --test-threads 1 --run-ignored ignored-only` +- E2E tests available in `crates/e2e` + +### Testing Requirements +- PostgreSQL tests require local database: Run `docker compose up -d` first +- Forked network tests require `anvil` (from Foundry) and RPC URLs + - Anvil binary: configurable via `ANVIL_COMMAND` env var (defaults to `"anvil"`, must be in PATH) + - Required env vars: `FORK_URL_MAINNET` and `FORK_URL_GNOSIS` (RPC endpoints for forking) +- Use `--test-threads 1` for database and E2E tests to avoid conflicts +- CI runs doc-tests, unit tests, DB tests, E2E tests (local and forked), and driver tests + +### Linting and Formatting +- Format: **always** run with the nightly toolchain: `cargo +nightly fmt --all` +- Spot format: `cargo +nightly fmt -- ` (never call stable `cargo fmt`) +- Lint: `cargo clippy --locked --workspace --all-features --all-targets -- -D warnings` +- Check format: `cargo +nightly fmt --all -- --check` +- Only format **after** as a final step! — i.e. after checking compilation, running tests, etc. + +### Local Development Environment +- Start local PostgreSQL: `docker compose up -d` +- Full playground environment: `docker compose -f playground/docker-compose.fork.yml up -d` +- For forked network tests, set environment variables: `FORK_URL_MAINNET` and `FORK_URL_GNOSIS` +- Reset playground: `docker compose -f playground/docker-compose.fork.yml down --remove-orphans --volumes` + +## Directory Structure + +``` +crates/ # 25+ Rust crates (binaries + libraries) +database/ # PostgreSQL migrations and schemas +playground/ # Local dev environment +configs/ # Configuration files +``` + +## Workspace Configuration + +- Rust Edition 2024 +- Uses workspace dependencies for consistency +- Tokio-console support: **Only available in playground environment** (set `TOKIO_CONSOLE=true` to activate when running in playground) +- Production builds do **not** include tokio-console overhead +- Runtime log filter changes via UNIX socket at `/tmp/log_filter_override__.sock` +- Memory allocator: Uses jemalloc by default with built-in heap profiling support (enable at runtime via MALLOC_CONF environment variable). Can optionally use mimalloc via `--features mimalloc-allocator` + +## Playground Environment + +- Runs in **Fork** mode: anvil forks a real network via `ETH_RPC_URL` (set in `playground/.env`). A clean local network mode is planned but not yet implemented. +- Access full local development stack with CoW Swap UI at http://localhost:8000 +- CoW Explorer available at http://localhost:8001 +- Orderbook API at http://localhost:8080 +- Database admin (Adminer) at http://localhost:8082 +- Uses test mnemonic: "test test test test test test test test test test test junk" +- First 10 accounts have 10000 ETH balance by default, set by anvil + +## Development Notes + +- Binaries support `--help` for comprehensive command documentation +- OpenAPI documentation available for orderbook, driver, and solver APIs +- Performance profiling: Only available in playground (requires tokio-console feature + tokio_unstable cfg) + +# General Coding Instructions + +If there is a test you can run then run it or `cargo check` or `cargo build`; run it after you have made changes. +Use rust-analyzer MCP when appropriate such as finding usages or renaming. After a change run "cargo +nightly fmt". + +## Code Style + +Instead of using full paths like `volume_fee_bucket_overrides: Vec`, import the type at the beginning so you don't have to use the full path later. + +Don't add a lot of comments. Add comments only if the code is a bit weird or the concept is not clear. + +## CoW Protocol Database Access + +**Always show the SQL query before executing it** against postgres MCP tools (`mcp__postgres-protocol__query`, `mcp__postgres-analytics__query`). + +**Query timeout**: MCP servers are configured with a 120 second timeout. For potentially long-running queries, prefix with `SET statement_timeout = '30s';` (or appropriate duration) to fail fast: +```sql +SET statement_timeout = '30s'; +SELECT ... FROM large_table ...; +``` +If a query times out, try a different approach (add more filters, use a smaller time range, simplify aggregations, or break into smaller queries). + +Read-only replica available via MCP. If that fails for some reason, then you can use psql with: +```bash +source .env.claude && PGPASSWORD="$COW_DB_PASSWORD" psql \ + -h "$COW_DB_HOST" -p "$COW_DB_PORT" -U "$COW_DB_USER" -d -c "" +``` +but use MCP where possible. + +Databases: `mainnet`, `arbitrum-one`, `base`, `linea`, `polygon`, `xdai`, `sepolia`, `plasma`, `ink`, `bnb` etc. + +## RPC Node + +Use `$ETH_MAINNET_RPC` from `.env.claude` for mainnet. Use `cast` or whatever tools you want freely. + +## Victoria Logs Access + +Use the `CoW-Prod` MCP tools to query Victoria Logs directly. + +**Timestamps**: MCP requires RFC3339 format (e.g., `2026-04-09T00:00:00Z`). Compute absolute timestamps from the current date rather than using relative time. + +**IMPORTANT**: Order UIDs and other structured fields (like `quote_id`, `auction_id`) live inside the `all` field in Victoria Logs. You MUST prefix them with `all:` to match. Plain text terms (like `order created`, `filtered`) match the log message directly and don't need the prefix. You can also use parsed fields directly (e.g., `parsed.fields.order_uid:0x...`) for more precise matching. + +**IMPORTANT — Protect context window**: Raw log entries contain ~4KB of kubernetes/ec2 metadata each. **Always** append `| fields _time, _msg, all` (or specific `parsed.fields.*`) to strip noise. Use small `limit` values (10-20) and only increase if needed. Examples: +- General order search: `... | fields _time, _msg, all` +- When you only need specific parsed fields: `... | fields _time, _msg, parsed.fields.err, parsed.fields.driver, parsed.spans.auction.auction_id` + +**Available MCP tools:** +- `victorialogs_query` — Main log search (LogsQL expression + time range + limit) +- `victorialogs_hits` — Count matching logs grouped by time buckets +- `victorialogs_field_names` / `victorialogs_field_values` — Explore available fields +- `victorialogs_facets` — Most frequent values per field +- `victorialogs_stats_query` / `victorialogs_stats_query_range` — Aggregation queries +- `victorialogs_stream_field_names` / `victorialogs_stream_field_values` — Stream metadata + +**Key fields:** +- Stream fields (efficient filters): `container`, `namespace`, `pod` +- `network` — chain name (mainnet, arbitrum-one, base, etc.) +- `all` — full structured JSON log (search with `all:` prefix for UIDs) +- `parsed.fields.*` — individual parsed fields (e.g., `parsed.fields.order_uid`, `parsed.fields.quote_id`) +- `_msg` — the log message text + +**Example queries:** +``` +# Search for order logs (exclude nginx controller, strip metadata) +query: "container:!controller AND network:mainnet AND all:0xabc... | fields _time, _msg, all" +start: "" +limit: 20 + +# Search for order creation on mainnet +query: "container:!controller AND network:mainnet AND \"order created\" AND all:0xabc... | fields _time, _msg, all" +start: "" +limit: 10 + +# Settlement failures with just error details +query: "container:!controller AND network:mainnet AND \"settlement failed\" | fields _time, _msg, parsed.fields.err, parsed.fields.driver, parsed.spans.auction.auction_id" +start: "" +limit: 10 + +# Sort results by time +query: "container:!controller AND network:mainnet AND all:0xabc... | fields _time, _msg, all | sort by (_time) asc" +start: "" +limit: 20 +``` + +## Etherscan API (V2) + +Use MCP `mcp__fetch__fetch` tool. API Key in `.env.claude` as `$ETHERSCAN_API_KEY`. + +**Important**: V1 API is deprecated. Use V2 with the `chainid` parameter: +- Mainnet: `chainid=1` +- Arbitrum: `chainid=42161` +- Base: `chainid=8453` + +Example URL format: +``` +https://api.etherscan.io/v2/api?chainid=1&module=account&action=balance&address=&tag=latest&apikey= +``` + +Read the API key from `.env.claude` and use it directly in the URL (MCP fetch doesn't do shell variable substitution). + +## Investigating orders + +When asked to look into what happened to an order read file ./docs/COW_ORDER_DEBUG_SKILL.md and follow the instructions there. +Make heavy use of logs and DB to find all info you need and present finding to the user with evidence. diff --git a/Cargo.lock b/Cargo.lock index 23628c0732..7d008fdd5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,97 +3,77 @@ version = 4 [[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +name = "account-balances" +version = "0.1.0" dependencies = [ - "lazy_static", - "regex", + "alloy-contract", + "alloy-dyn-abi", + "alloy-primitives", + "alloy-rpc-types", + "alloy-sol-types", + "anyhow", + "async-trait", + "balance-overrides", + "contracts", + "ethrpc", + "futures", + "itertools 0.14.0", + "mockall", + "model", + "tokio", + "tracing", ] [[package]] name = "addr2line" -version = "0.22.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] -name = "ahash" -version = "0.7.8" +name = "aho-corasick" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ - "getrandom 0.2.15", - "once_cell", - "version_check", + "memchr", ] [[package]] -name = "ahash" -version = "0.8.11" +name = "alloc-no-stdlib" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "getrandom 0.2.15", - "once_cell", - "version_check", - "zerocopy", -] +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] -name = "aho-corasick" -version = "1.1.3" +name = "alloc-stdlib" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alerter" -version = "0.1.0" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" dependencies = [ - "alloy", - "anyhow", - "clap", - "humantime", - "mimalloc", - "model", - "number", - "observe", - "prometheus", - "reqwest 0.11.27", - "serde", - "serde_with", - "shared", - "tokio", - "tracing", - "url", - "warp", + "alloc-no-stdlib", ] [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01db470290bb814e0485fa79aba6e36bb5d221c2e3cfeba5fba05a8a2ca8dad" +checksum = "50ab0cd8afe573d1f7dc2353698a51b1f93aec362c8211e28cfd3948c6adba39" dependencies = [ "alloy-consensus", "alloy-contract", @@ -102,7 +82,6 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-provider", - "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types", "alloy-serde", @@ -111,15 +90,14 @@ dependencies = [ "alloy-signer-local", "alloy-transport", "alloy-transport-http", - "alloy-transport-ws", "alloy-trie", ] [[package]] name = "alloy-chains" -version = "0.2.5" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5674914c2cfdb866c21cb0c09d82374ee39a1395cf512e7515f4c014083b3fff" +checksum = "25db5bcdd086f0b1b9610140a12c59b757397be90bd130d8d836fc8da0815a34" dependencies = [ "alloy-primitives", "num_enum", @@ -128,9 +106,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90d103d3e440ad6f703dd71a5b58a6abd24834563bde8a5fabe706e00242f810" +checksum = "7f16daaf7e1f95f62c6c3bf8a3fc3d78b08ae9777810c0bb5e94966c7cd57ef0" dependencies = [ "alloy-eips", "alloy-primitives", @@ -139,24 +117,25 @@ dependencies = [ "alloy-trie", "alloy-tx-macros", "auto_impl", + "borsh", "c-kzg", - "derive_more 2.0.1", + "derive_more 2.1.1", "either", "k256", "once_cell", "rand 0.8.5", - "secp256k1 0.30.0", + "secp256k1", "serde", "serde_json", "serde_with", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "alloy-consensus-any" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ead76c8c84ab3a50c31c56bc2c748c2d64357ad2131c32f9b10ab790a25e1a" +checksum = "118998d9015332ab1b4720ae1f1e3009491966a0349938a1f43ff45a8a4c6299" dependencies = [ "alloy-consensus", "alloy-eips", @@ -168,9 +147,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5903097e4c131ad2dd80d87065f23c715ccb9cdb905fa169dffab8e1e798bae" +checksum = "7ac9e0c34dc6bce643b182049cdfcca1b8ce7d9c260cbdd561f511873b7e26cd" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -179,42 +158,44 @@ dependencies = [ "alloy-network-primitives", "alloy-primitives", "alloy-provider", - "alloy-pubsub", "alloy-rpc-types-eth", "alloy-sol-types", "alloy-transport", "futures", "futures-util", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", + "tracing", ] [[package]] name = "alloy-core" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca96214615ec8cf3fa2a54b32f486eb49100ca7fe7eb0b8c1137cd316e7250a" +checksum = "23e8604b0c092fabc80d075ede181c9b9e596249c70b99253082d7e689836529" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", "alloy-primitives", + "alloy-rlp", "alloy-sol-types", ] [[package]] name = "alloy-dyn-abi" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdff496dd4e98a81f4861e66f7eaf5f2488971848bb42d9c892f871730245c8" +checksum = "cc2db5c583aaef0255aa63a4fe827f826090142528bba48d1bf4119b62780cad" dependencies = [ "alloy-json-abi", "alloy-primitives", "alloy-sol-type-parser", "alloy-sol-types", + "derive_more 2.1.1", "itoa", "serde", "serde_json", - "winnow 0.7.11", + "winnow", ] [[package]] @@ -227,59 +208,74 @@ dependencies = [ "alloy-rlp", "crc", "serde", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "alloy-eip2930" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" +checksum = "9441120fa82df73e8959ae0e4ab8ade03de2aaae61be313fbf5746277847ce25" dependencies = [ "alloy-primitives", "alloy-rlp", + "borsh", "serde", ] [[package]] name = "alloy-eip7702" -version = "0.6.1" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", + "thiserror 2.0.17", +] + +[[package]] +name = "alloy-eip7928" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" +checksum = "d3231de68d5d6e75332b7489cfcc7f4dfabeba94d990a10e4b923af0e6623540" dependencies = [ "alloy-primitives", "alloy-rlp", + "borsh", "serde", - "thiserror 2.0.12", ] [[package]] name = "alloy-eips" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bdbec74583d0067798d77afa43d58f00d93035335d7ceaa5d3f93857d461bb9" +checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8" dependencies = [ "alloy-eip2124", "alloy-eip2930", "alloy-eip7702", + "alloy-eip7928", "alloy-primitives", "alloy-rlp", "alloy-serde", "auto_impl", + "borsh", "c-kzg", - "derive_more 2.0.1", + "derive_more 2.1.1", "either", "serde", "serde_with", "sha2", - "thiserror 2.0.12", ] [[package]] name = "alloy-json-abi" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5513d5e6bd1cba6bdcf5373470f559f320c05c8c59493b6e98912fbe6733943f" +checksum = "e9dbe713da0c737d9e5e387b0ba790eb98b14dd207fe53eef50e19a5a8ec3dac" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -289,24 +285,24 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b67c5a702121e618217f7a86f314918acb2622276d0273490e2d4534490bc0" +checksum = "422d110f1c40f1f8d0e5562b0b649c35f345fccb7093d9f02729943dcd1eef71" dependencies = [ "alloy-primitives", "alloy-sol-types", - "http 1.1.0", + "http 1.4.0", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", ] [[package]] name = "alloy-network" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612296e6b723470bb1101420a73c63dfd535aa9bf738ce09951aedbd4ab7292e" +checksum = "7197a66d94c4de1591cdc16a9bcea5f8cccd0da81b865b49aef97b1b4016e0fa" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -321,18 +317,18 @@ dependencies = [ "alloy-sol-types", "async-trait", "auto_impl", - "derive_more 2.0.1", + "derive_more 2.1.1", "futures-utils-wasm", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "alloy-network-primitives" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e7918396eecd69d9c907046ec8a93fb09b89e2f325d5e7ea9c4e3929aa0dd2" +checksum = "eb82711d59a43fdfd79727c99f270b974c784ec4eb5728a0d0d22f26716c87ef" dependencies = [ "alloy-consensus", "alloy-eips", @@ -343,36 +339,37 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" +checksum = "de3b431b4e72cd8bd0ec7a50b4be18e73dab74de0dba180eef171055e5d5926e" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", - "derive_more 2.0.1", + "derive_more 2.1.1", "foldhash 0.2.0", - "hashbrown 0.16.0", - "indexmap 2.10.0", + "getrandom 0.4.2", + "hashbrown 0.16.1", + "indexmap 2.13.0", "itoa", "k256", "keccak-asm", "paste", "proptest", - "rand 0.9.1", + "rand 0.9.4", + "rapidhash", "ruint", "rustc-hash", "serde", "sha3", - "tiny-keccak", ] [[package]] name = "alloy-provider" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c1313a527a2e464d067c031f3c2ec073754ef615cc0eabca702fd0fe35729c" +checksum = "bf6b18b929ef1d078b834c3631e9c925177f3b23ddc6fa08a722d13047205876" dependencies = [ "alloy-chains", "alloy-consensus", @@ -387,6 +384,7 @@ dependencies = [ "alloy-rpc-types-debug", "alloy-rpc-types-eth", "alloy-rpc-types-trace", + "alloy-rpc-types-txpool", "alloy-signer", "alloy-sol-types", "alloy-transport", @@ -399,13 +397,13 @@ dependencies = [ "either", "futures", "futures-utils-wasm", - "lru 0.13.0", + "lru", "parking_lot", "pin-project", - "reqwest 0.12.12", + "reqwest 0.13.2", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", "tracing", "url", @@ -414,9 +412,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810766eeed6b10ffa11815682b3f37afc5019809e3b470b23555297d5770ce63" +checksum = "5ad54073131e7292d4e03e1aa2287730f737280eb160d8b579fb31939f558c11" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -429,7 +427,7 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower 0.5.2", + "tower 0.5.3", "tracing", "wasmtimer", ] @@ -453,14 +451,14 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "alloy-rpc-client" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f802228273056528dfd6cc8845cc91a7c7e0c6fc1a66d19e8673743dacdc7e" +checksum = "94fcc9604042ca80bd37aa5e232ea1cd851f337e31e2babbbb345bc0b1c30de3" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -470,12 +468,12 @@ dependencies = [ "alloy-transport-ws", "futures", "pin-project", - "reqwest 0.12.12", + "reqwest 0.13.2", "serde", "serde_json", "tokio", "tokio-stream", - "tower 0.5.2", + "tower 0.5.3", "tracing", "url", "wasmtimer", @@ -483,24 +481,25 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ff3df608dcabd6bdd197827ff2b8faaa6cefe0c462f7dc5e74108666a01f56" +checksum = "4faad925d3a669ffc15f43b3deec7fbdf2adeb28a4d6f9cf4bc661698c0f8f4b" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", "alloy-rpc-types-debug", "alloy-rpc-types-eth", "alloy-rpc-types-trace", + "alloy-rpc-types-txpool", "alloy-serde", "serde", ] [[package]] name = "alloy-rpc-types-anvil" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2bc988d7455e02dfb53460e1caa61f932b3f8452e12424e68ba8dcf60bba90" +checksum = "47df51bedb3e6062cb9981187a51e86d0d64a4de66eb0855e9efe6574b044ddf" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -510,9 +509,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbf6d1766ca41e90ac21c4bc5cbc5e9e965978a25873c3f90b3992d905db4cb" +checksum = "3823026d1ed239a40f12364fac50726c8daf1b6ab8077a97212c5123910429ed" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -521,21 +520,21 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977698b458738369ba5ca645d2cdb4d51ba07a81db37306ff85322853161ea3a" +checksum = "2145138f3214928f08cd13da3cb51ef7482b5920d8ac5a02ecd4e38d1a8f6d1e" dependencies = [ "alloy-primitives", - "derive_more 2.0.1", + "derive_more 2.1.1", "serde", "serde_with", ] [[package]] name = "alloy-rpc-types-eth" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15e4831b71eea9d20126a411c1c09facf1d01d5cac84fd51d532d3c429cfc26" +checksum = "59c095f92c4e1ff4981d89e9aa02d5f98c762a1980ab66bec49c44be11349da2" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -549,28 +548,40 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "alloy-rpc-types-trace" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0c800e2ce80829fca1491b3f9063c29092850dc6cf19249d5f678f0ce71bb0" +checksum = "2e5a4d010f86cd4e01e5205ec273911e538e1738e76d8bafe9ecd245910ea5a3" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", "alloy-serde", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", +] + +[[package]] +name = "alloy-rpc-types-txpool" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942d26a2ca8891b26de4a8529d21091e21c1093e27eb99698f1a86405c76b1ff" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", ] [[package]] name = "alloy-serde" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "751d1887f7d202514a82c5b3caf28ee8bd4a2ad9549e4f498b6f0bff99b52add" +checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e" dependencies = [ "alloy-primitives", "serde", @@ -579,24 +590,26 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf0b42ffbf558badfecf1dde0c3c5ed91f29bb7e97876d0bed008c3d5d67171" +checksum = "43f447aefab0f1c0649f71edc33f590992d4e122bc35fb9cdbbf67d4421ace85" dependencies = [ + "alloy-dyn-abi", "alloy-primitives", + "alloy-sol-types", "async-trait", "auto_impl", "either", "elliptic-curve", "k256", - "thiserror 2.0.12", + "thiserror 2.0.17", ] [[package]] name = "alloy-signer-aws" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6b73b812ab342d09de85eb302598a3a0c4d744cbe982ed76e309dcec9ddfa" +checksum = "8194c416115dc27f03796c0075dee0731239e2d7fbce735a74894aa8f6a47d7d" dependencies = [ "alloy-consensus", "alloy-network", @@ -607,15 +620,15 @@ dependencies = [ "aws-sdk-kms", "k256", "spki", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", ] [[package]] name = "alloy-signer-local" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7d555ee5f27be29af4ae312be014b57c6cff9acb23fe2cf008500be6ca7e33" +checksum = "f721f4bf2e4812e5505aaf5de16ef3065a8e26b9139ac885862d00b5a55a659a" dependencies = [ "alloy-consensus", "alloy-network", @@ -626,76 +639,76 @@ dependencies = [ "coins-bip39", "k256", "rand 0.8.5", - "thiserror 2.0.12", + "thiserror 2.0.17", "zeroize", ] [[package]] name = "alloy-sol-macro" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" +checksum = "ab81bab693da9bb79f7a95b64b394718259fdd7e41dceeced4cad57cb71c4f6a" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" +checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", "const-hex", - "heck 0.5.0", - "indexmap 2.10.0", + "heck", + "indexmap 2.13.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.104", + "sha3", + "syn 2.0.114", "syn-solidity", - "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" +checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" dependencies = [ "alloy-json-abi", "const-hex", "dunce", - "heck 0.5.0", + "heck", "macro-string", "proc-macro2", "quote", "serde_json", - "syn 2.0.104", + "syn 2.0.114", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" +checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" dependencies = [ "serde", - "winnow 0.7.11", + "winnow", ] [[package]] name = "alloy-sol-types" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70319350969a3af119da6fb3e9bddb1bce66c9ea933600cb297c8b1850ad2a3c" +checksum = "64612d29379782a5dde6f4b6570d9c756d734d760c0c94c254d361e678a6591f" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -705,22 +718,22 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b3deee699d6f271eab587624a9fa84d02d0755db7a95a043d52a6488d16ebe" +checksum = "8098f965442a9feb620965ba4b4be5e2b320f4ec5a3fff6bfa9e1ff7ef42bed1" dependencies = [ "alloy-json-rpc", "auto_impl", "base64 0.22.1", - "derive_more 2.0.1", + "derive_more 2.1.1", "futures", "futures-utils-wasm", "parking_lot", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.17", "tokio", - "tower 0.5.2", + "tower 0.5.3", "tracing", "url", "wasmtimer", @@ -728,47 +741,49 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1720bd2ba8fe7e65138aca43bb0f680e4e0bcbd3ca39bf9d3035c9d7d2757f24" +checksum = "e8597d36d546e1dab822345ad563243ec3920e199322cb554ce56c8ef1a1e2e7" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.12", + "itertools 0.14.0", + "reqwest 0.13.2", "serde_json", - "tower 0.5.2", + "tower 0.5.3", "tracing", "url", ] [[package]] name = "alloy-transport-ws" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "571aadf0afce0d515a28b2c6352662a39cb9f48b4eeff9a5c34557d6ea126730" +checksum = "ec3ab7a72b180992881acc112628b7668337a19ce15293ee974600ea7b693691" dependencies = [ "alloy-pubsub", "alloy-transport", "futures", - "http 1.1.0", - "rustls 0.23.34", + "http 1.4.0", + "rustls", "serde_json", "tokio", "tokio-tungstenite", "tracing", + "url", "ws_stream_wasm", ] [[package]] name = "alloy-trie" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bada1fc392a33665de0dc50d401a3701b62583c655e3522a323490a5da016962" +checksum = "428aa0f0e0658ff091f8f667c406e034b431cb10abd39de4f507520968acc499" dependencies = [ "alloy-primitives", "alloy-rlp", "arrayvec", - "derive_more 2.0.1", + "derive_more 2.1.1", "nybbles", "serde", "smallvec", @@ -777,22 +792,16 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.1.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7ce8ed34106acd6e21942022b6a15be6454c2c3ead4d76811d3bdcd63cf771" +checksum = "d69722eddcdf1ce096c3ab66cf8116999363f734eb36fe94a148f4f71c85da84" dependencies = [ - "darling 0.21.3", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -804,9 +813,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -819,36 +828,37 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] @@ -861,23 +871,26 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" name = "app-data" version = "0.1.0" dependencies = [ - "alloy", + "alloy-primitives", "anyhow", "bytes-hex", "const-hex", "hex-literal", + "moka", "number", "serde", "serde_json", "serde_with", - "tiny-keccak", ] [[package]] name = "arc-swap" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" +dependencies = [ + "rustversion", +] [[package]] name = "ark-ff" @@ -913,7 +926,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -964,7 +977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1002,7 +1015,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1070,42 +1083,77 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" dependencies = [ "serde", ] [[package]] name = "async-compression" -version = "0.4.11" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" dependencies = [ - "flate2", - "futures-core", - "memchr", + "compression-codecs", + "compression-core", "pin-project-lite", "tokio", ] [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener 5.4.0", + "event-listener", "event-listener-strategy", "pin-project-lite", ] +[[package]] +name = "async-nats" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31811585c7c5bc2f60f8b80d5a6b0f737115611dac47567d7f7d94562ebb180b" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-util", + "memchr", + "nkeys", + "nuid", + "pin-project", + "portable-atomic", + "rand 0.10.1", + "regex", + "ring", + "rustls-native-certs", + "rustls-pki-types", + "rustls-webpki", + "serde", + "serde_json", + "serde_nanos", + "serde_repr", + "thiserror 2.0.17", + "time", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-util", + "tokio-websockets", + "tracing", + "tryhard", + "url", +] + [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -1114,24 +1162,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1142,7 +1190,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -1160,17 +1208,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "auto_impl" version = "1.3.0" @@ -1179,75 +1216,93 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "autopilot" version = "0.1.0" dependencies = [ + "account-balances", "alloy", "anyhow", "app-data", "async-trait", + "axum 0.8.8", + "bad-tokens", "bigdecimal", + "brotli", + "bytes", "bytes-hex", "chain", "chrono", "clap", + "configs", "const-hex", "contracts", "cow-amm", "dashmap", "database", "derive_more 1.0.0", - "ethcontract", + "eth-domain-types", "ethrpc", + "event-indexing", "futures", + "gas-price-estimation", "hex-literal", + "http-client", "humantime", - "indexmap 2.10.0", + "humantime-serde", + "indexmap 2.13.0", "itertools 0.14.0", "maplit", "mimalloc", - "mockall 0.12.1", + "mockall", "model", "num", "number", "observe", "order-validation", - "primitive-types", + "price-estimation", "prometheus", "prometheus-metric-storage", - "rand 0.8.5", - "reqwest 0.11.27", + "rand 0.9.4", + "reqwest 0.13.2", "rust_decimal", "s3", "serde", "serde_json", "serde_with", "shared", + "simulator", "sqlx", "strum", - "thiserror 1.0.61", + "tempfile", + "thiserror 1.0.69", + "tikv-jemallocator", + "token-info", "tokio", + "tokio-stream", + "toml", + "tower 0.5.3", + "tower-http", "tracing", "url", "vergen", - "web3", + "winner-selection", ] [[package]] name = "aws-config" -version = "1.5.1" +version = "1.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac9889352d632214df943e26740c46a0f3da6e329fbd28164fe7ae1b061da7b" +checksum = "11493b0bad143270fb8ad284a096dd529ba91924c5409adeac856cc1bf047dbc" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1264,9 +1319,8 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 0.2.12", - "hyper 0.14.29", - "ring", + "http 1.4.0", + "sha1", "time", "tokio", "tracing", @@ -1276,9 +1330,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.0" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16838e6c9e12125face1c1eff1343c75e3ff540de98ff7ebd61874a89bcfeb9" +checksum = "8f20799b373a1be121fe3005fba0c2090af9411573878f224df44b42727fcaf7" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1286,24 +1340,50 @@ dependencies = [ "zeroize", ] +[[package]] +name = "aws-lc-rs" +version = "1.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "aws-runtime" -version = "1.2.2" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75588e7ee5e8496eed939adac2035a6dbab9f7eb2acdd9ab2d31856dab6f3955" +checksum = "5fc0651c57e384202e47153c1260b84a9936e19803d747615edf199dc3b98d17" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", "aws-smithy-http", + "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "bytes-utils", "fastrand", "http 0.2.12", + "http 1.4.0", "http-body 0.4.6", + "http-body 1.0.1", "percent-encoding", "pin-project-lite", "tracing", @@ -1312,33 +1392,34 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.30.0" +version = "1.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da951fb0dd1a02728a91c58af8464098766f1a0600af932dd3f8361b23e1bfc9" +checksum = "c41ae6a33da941457e89075ef8ca5b4870c8009fe4dceeba82fce2f30f313ac6" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", - "once_cell", + "http 1.4.0", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-s3" -version = "1.34.0" +version = "1.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "724119d8fd2d2638b9979673f3b5c2979fa388c9ca27815e3cb5ad6234fac3f5" +checksum = "151783f64e0dcddeb4965d08e36c276b4400a46caa88805a2e36d497deaf031a" dependencies = [ - "ahash 0.8.11", "aws-credential-types", "aws-runtime", "aws-sigv4", @@ -1347,6 +1428,7 @@ dependencies = [ "aws-smithy-eventstream", "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -1357,9 +1439,9 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http-body 0.4.6", - "lru 0.12.3", - "once_cell", + "http 1.4.0", + "http-body 1.0.1", + "lru", "percent-encoding", "regex-lite", "sha2", @@ -1369,76 +1451,82 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.29.0" +version = "1.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da75cf91cbb46686a27436d639a720a3a198b148efa76dc2467b7e5374a67fc0" +checksum = "9aadc669e184501caaa6beafb28c6267fc1baef0810fb58f9b205485ca3f2567" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", - "once_cell", + "http 1.4.0", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-ssooidc" -version = "1.30.0" +version = "1.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2ec8a6687299685ed0a4a3137c129cdb132b5235bc3aa3443f6cffe468b9ff" +checksum = "1342a7db8f358d3de0aed2007a0b54e875458e39848d54cc1d46700b2bfcb0a8" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "fastrand", "http 0.2.12", - "once_cell", + "http 1.4.0", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-sts" -version = "1.29.0" +version = "1.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f1031e094b1411b59b49b19e4118f069e1fe13a9c5b8888e933daaf7ffdd6" +checksum = "ab41ad64e4051ecabeea802d6a17845a91e83287e1dd249e6963ea1ba78c428a" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-query", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-smithy-xml", "aws-types", + "fastrand", "http 0.2.12", - "once_cell", + "http 1.4.0", "regex-lite", "tracing", ] [[package]] name = "aws-sigv4" -version = "1.2.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b56f1cbe6fd4d0c2573df72868f20ab1c125ca9c9dbce17927a463433a2e57" +checksum = "b0b660013a6683ab23797778e21f1f854744fdf05f68204b4cca4c8c04b5d1f4" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", @@ -1450,8 +1538,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.1.0", - "once_cell", + "http 1.4.0", "percent-encoding", "sha2", "time", @@ -1460,9 +1547,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.1" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62220bc6e97f946ddd51b5f1361f78996e704677afc518a4ff66b7a72ea1378c" +checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc" dependencies = [ "futures-util", "pin-project-lite", @@ -1471,18 +1558,18 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.60.9" +version = "0.64.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6242d6a54d3b4b83458f4abd7057ba93c4419dc71e8217e9acd3a748d656d99e" +checksum = "6750f3dd509b0694a4377f0293ed2f9630d710b1cebe281fa8bac8f099f88bc6" dependencies = [ "aws-smithy-http", "aws-smithy-types", "bytes", - "crc32c", - "crc32fast", + "crc-fast", "hex", - "http 0.2.12", - "http-body 0.4.6", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", "md-5", "pin-project-lite", "sha1", @@ -1492,9 +1579,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.4" +version = "0.60.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6363078f927f612b970edf9d1903ef5cef9a64d1e8423525ebb1f0a1633c858" +checksum = "faf09d74e5e32f76b8762da505a3cd59303e367a664ca67295387baa8c1d7548" dependencies = [ "aws-smithy-types", "bytes", @@ -1503,9 +1590,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.60.8" +version = "0.63.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a7de001a1b9a25601016d8057ea16e31a45fdca3751304c8edf4ad72e706c08" +checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -1513,29 +1600,63 @@ dependencies = [ "bytes", "bytes-utils", "futures-core", - "http 0.2.12", - "http-body 0.4.6", - "once_cell", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", "percent-encoding", "pin-project-lite", "pin-utils", "tracing", ] +[[package]] +name = "aws-smithy-http-client" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a2f165a7feee6f263028b899d0a181987f4fa7179a6411a32a439fba7c5f769" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2 0.4.13", + "http 1.4.0", + "hyper 1.8.1", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower 0.5.3", + "tracing", +] + [[package]] name = "aws-smithy-json" -version = "0.60.7" +version = "0.62.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4683df9469ef09468dad3473d129960119a0d3593617542b7d52086c8486f2d6" +checksum = "9648b0bb82a2eedd844052c6ad2a1a822d1f8e3adee5fbf668366717e428856a" dependencies = [ "aws-smithy-types", ] +[[package]] +name = "aws-smithy-observability" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06c2315d173edbf1920da8ba3a7189695827002e4c0fc961973ab1c54abca9c" +dependencies = [ + "aws-smithy-runtime-api", +] + [[package]] name = "aws-smithy-query" -version = "0.60.7" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb" +checksum = "1a56d79744fb3edb5d722ef79d86081e121d3b9422cb209eb03aea6aa4f21ebd" dependencies = [ "aws-smithy-types", "urlencoding", @@ -1543,41 +1664,40 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.5.5" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d3965f6417a92a6d1009c5958a67042f57e46342afb37ca58f9ad26744ec73" +checksum = "028999056d2d2fd58a697232f9eec4a643cf73a71cf327690a7edad1d2af2110" dependencies = [ "aws-smithy-async", "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", "fastrand", - "h2 0.3.26", "http 0.2.12", + "http 1.4.0", "http-body 0.4.6", - "http-body 1.0.0", - "hyper 0.14.29", - "hyper-rustls", - "once_cell", + "http-body 1.0.1", + "http-body-util", "pin-project-lite", "pin-utils", - "rustls 0.21.12", "tokio", "tracing", ] [[package]] name = "aws-smithy-runtime-api" -version = "1.6.2" +version = "1.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4179bd8a1c943e1aceb46c5b9fc014a561bd6c35a2153e816ba29076ee49d245" +checksum = "876ab3c9c29791ba4ba02b780a3049e21ec63dabda09268b175272c3733a79e6" dependencies = [ "aws-smithy-async", "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.1.0", + "http 1.4.0", "pin-project-lite", "tokio", "tracing", @@ -1586,18 +1706,18 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.1.10" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6764ba7e1c5ede1c9f9e4046645534f06c2581402461c559b481a420330a83" +checksum = "9d73dbfbaa8e4bc57b9045137680b958d274823509a360abfd8e1d514d40c95c" dependencies = [ "base64-simd", "bytes", "bytes-utils", "futures-core", "http 0.2.12", - "http 1.1.0", + "http 1.4.0", "http-body 0.4.6", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "itoa", "num-integer", @@ -1612,25 +1732,24 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.8" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d123fbc2a4adc3c301652ba8e149bf4bc1d1725affb9784eb20c953ace06bf55" +checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.1" +version = "1.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f734808d43702a67e57d478a12e227d4d038d0b90c9005a78c87890d3805922" +checksum = "47c8323699dd9b3c8d5b3c13051ae9cdef58fd179957c882f8374dd8725962d9" dependencies = [ "aws-credential-types", "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "http 0.2.12", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "tracing", ] @@ -1641,29 +1760,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.32", "itoa", - "matchit", + "matchit 0.7.3", "memchr", "mime", "percent-encoding", "pin-project-lite", "rustversion", "serde", + "sync_wrapper 0.1.2", + "tower 0.4.13", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core 0.5.6", + "bytes", + "form_urlencoded", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "itoa", + "matchit 0.8.4", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.2", "tokio", - "tower 0.4.13", + "tower 0.5.3", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -1683,19 +1831,82 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-link", +] + +[[package]] +name = "bad-tokens" +version = "0.1.0" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types", + "alloy-rpc-types-trace", + "alloy-sol-types", + "alloy-transport", + "anyhow", + "contracts", + "ethrpc", + "model", + "tracing", +] + +[[package]] +name = "balance-overrides" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types", + "alloy-sol-types", + "alloy-transport", + "anyhow", + "async-trait", + "clap", + "configs", + "contracts", + "ethrpc", + "maplit", + "moka", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tracing", ] [[package]] @@ -1710,6 +1921,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base256emoji" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c" +dependencies = [ + "const-str", + "match-lookup", +] + [[package]] name = "base64" version = "0.21.7" @@ -1734,9 +1955,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bech32" @@ -1746,10 +1967,12 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bigdecimal" -version = "0.3.1" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" dependencies = [ + "autocfg", + "libm", "num-bigint", "num-integer", "num-traits", @@ -1779,15 +2002,15 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitcoin-io" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] name = "bitcoin_hashes" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ "bitcoin-io", "hex-conservative", @@ -1801,11 +2024,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -1831,9 +2054,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" dependencies = [ "cc", "glob", @@ -1843,9 +2066,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ "borsh-derive", "cfg_aliases", @@ -1853,16 +2076,36 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", - "syn_derive", + "syn 2.0.114", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", ] [[package]] @@ -1877,37 +2120,45 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +name = "byos" +version = "0.1.0" dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", + "alloy-primitives", + "alloy-signer", + "alloy-signer-local", + "alloy-sol-types", + "anyhow", + "axum 0.8.8", + "chrono", + "clap", + "const-hex", + "number", + "observe", + "serde", + "serde-ext", + "serde_json", + "serde_with", + "shared", + "solvers-dto", + "tikv-jemallocator", + "tokio", + "toml", + "tower 0.5.3", + "tower-http", + "tracing", + "vergen", ] [[package]] -name = "bytecheck_derive" -version = "0.6.12" +name = "byte-slice-cast" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "byteorder" @@ -1917,9 +2168,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] @@ -1946,9 +2197,9 @@ dependencies = [ [[package]] name = "c-kzg" -version = "2.1.1" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7318cfa722931cb5fe0838b98d3ce5621e75f6a6408abc21721d80de9223f2e4" +checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" dependencies = [ "blst", "cc", @@ -1968,23 +2219,32 @@ dependencies = [ "hashbrown 0.14.5", "instant", "once_cell", - "thiserror 1.0.61", + "thiserror 1.0.69", ] [[package]] name = "cc" -version = "1.2.29" +version = "1.2.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -1992,24 +2252,32 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chain" version = "0.1.0" dependencies = [ - "alloy", - "derive_more 1.0.0", + "alloy-primitives", "serde", "serde_json", - "thiserror 1.0.61", ] [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", "serde", @@ -2018,9 +2286,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.6" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", "clap_derive", @@ -2028,9 +2296,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.6" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5387378c84f6faa26890ebf9f0a92989f8873d4d380467bcd0d8d8620424df" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ "anstream", "anstyle", @@ -2040,21 +2308,30 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" + +[[package]] +name = "cmake" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] [[package]] name = "coins-bip32" @@ -2069,7 +2346,7 @@ dependencies = [ "k256", "serde", "sha2", - "thiserror 1.0.61", + "thiserror 1.0.69", ] [[package]] @@ -2085,7 +2362,7 @@ dependencies = [ "pbkdf2", "rand 0.8.5", "sha2", - "thiserror 1.0.61", + "thiserror 1.0.69", ] [[package]] @@ -2104,14 +2381,42 @@ dependencies = [ "serde", "sha2", "sha3", - "thiserror 1.0.61", + "thiserror 1.0.69", ] [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "compression-codecs" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" [[package]] name = "concurrent-queue" @@ -2122,6 +2427,27 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "configs" +version = "0.1.0" +dependencies = [ + "alloy", + "anyhow", + "bigdecimal", + "chrono", + "humantime-serde", + "rate-limit", + "s3", + "serde", + "serde_json", + "tempfile", + "thiserror 1.0.69", + "tokio", + "toml", + "tracing", + "url", +] + [[package]] name = "console-api" version = "0.7.0" @@ -2167,7 +2493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "proptest", "serde_core", ] @@ -2178,20 +2504,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-str" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" + [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ "proc-macro2", "quote", @@ -2202,36 +2534,106 @@ dependencies = [ name = "contracts" version = "0.1.0" dependencies = [ - "alloy", - "anyhow", - "ethcontract", - "ethcontract-generate", - "paste", - "serde_json", - "tracing", - "tracing-subscriber", + "cow-contract-anyoneauthenticator", + "cow-contract-balancerqueries", + "cow-contract-balancerv2authorizer", + "cow-contract-balancerv2basepool", + "cow-contract-balancerv2basepoolfactory", + "cow-contract-balancerv2composablestablepool", + "cow-contract-balancerv2composablestablepoolfactory", + "cow-contract-balancerv2composablestablepoolfactoryv3", + "cow-contract-balancerv2composablestablepoolfactoryv4", + "cow-contract-balancerv2composablestablepoolfactoryv5", + "cow-contract-balancerv2composablestablepoolfactoryv6", + "cow-contract-balancerv2liquiditybootstrappingpool", + "cow-contract-balancerv2liquiditybootstrappingpoolfactory", + "cow-contract-balancerv2noprotocolfeeliquiditybootstrappingpoolfactory", + "cow-contract-balancerv2stablepool", + "cow-contract-balancerv2stablepoolfactoryv2", + "cow-contract-balancerv2vault", + "cow-contract-balancerv2weightedpool", + "cow-contract-balancerv2weightedpool2tokensfactory", + "cow-contract-balancerv2weightedpoolfactory", + "cow-contract-balancerv2weightedpoolfactoryv3", + "cow-contract-balancerv2weightedpoolfactoryv4", + "cow-contract-balancerv3batchrouter", + "cow-contract-balances", + "cow-contract-baoswaprouter", + "cow-contract-chainalysisoracle", + "cow-contract-counter", + "cow-contract-cowamm", + "cow-contract-cowammconstantproductfactory", + "cow-contract-cowammfactorygetter", + "cow-contract-cowammlegacyhelper", + "cow-contract-cowammuniswapv2priceoracle", + "cow-contract-cowprotocoltoken", + "cow-contract-cowswapethflow", + "cow-contract-cowswaponchainorders", + "cow-contract-erc1271signaturevalidator", + "cow-contract-erc20", + "cow-contract-erc20mintable", + "cow-contract-flashloanrouter", + "cow-contract-gashog", + "cow-contract-gnosissafe", + "cow-contract-gnosissafecompatibilityfallbackhandler", + "cow-contract-gnosissafeproxy", + "cow-contract-gnosissafeproxyfactory", + "cow-contract-gpv2allowlistauthentication", + "cow-contract-gpv2settlement", + "cow-contract-honeyswaprouter", + "cow-contract-hookstrampoline", + "cow-contract-icowwrapper", + "cow-contract-ierc4626", + "cow-contract-iswaprpair", + "cow-contract-iuniswaplikepair", + "cow-contract-iuniswaplikerouter", + "cow-contract-iuniswapv3factory", + "cow-contract-izeroex", + "cow-contract-liquoricesettlement", + "cow-contract-mockerc4626wrapper", + "cow-contract-nonstandarderc20balances", + "cow-contract-pancakerouter", + "cow-contract-permit2", + "cow-contract-remoteerc20balances", + "cow-contract-signatures", + "cow-contract-solver", + "cow-contract-solver7702delegate", + "cow-contract-spardose", + "cow-contract-sushiswaprouter", + "cow-contract-swapper", + "cow-contract-swaprrouter", + "cow-contract-testnetuniswapv2router02", + "cow-contract-uniswapv2factory", + "cow-contract-uniswapv2router02", + "cow-contract-uniswapv3pool", + "cow-contract-uniswapv3quoterv2", + "cow-contract-uniswapv3swaprouterv2", + "cow-contract-weth9", ] [[package]] name = "convert_case" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "convert_case" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ "unicode-segmentation", ] [[package]] name = "cookie" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ "percent-encoding", "time", @@ -2240,12 +2642,13 @@ dependencies = [ [[package]] name = "cookie_store" -version = "0.20.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" dependencies = [ "cookie", - "idna 0.3.0", + "document-features", + "idna", "log", "publicsuffix", "serde", @@ -2265,17 +2668,31 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cow-amm" version = "0.1.0" dependencies = [ - "alloy", + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types", + "alloy-sol-types", "anyhow", "app-data", "async-trait", @@ -2283,32 +2700,866 @@ dependencies = [ "contracts", "database", "ethrpc", + "event-indexing", "futures", - "hex-literal", "model", "observe", "prometheus", "prometheus-metric-storage", - "shared", + "signature-validator", "sqlx", "tokio", "tracing", ] [[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +name = "cow-contract-anyoneauthenticator" +version = "0.1.0" dependencies = [ - "libc", -] - -[[package]] + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerqueries" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2authorizer" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2basepool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2basepoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv3" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv4" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv5" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv6" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2liquiditybootstrappingpool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2liquiditybootstrappingpoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2noprotocolfeeliquiditybootstrappingpoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2stablepool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2stablepoolfactoryv2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2vault" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpool2tokensfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpoolfactoryv3" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpoolfactoryv4" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv3batchrouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balances" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-baoswaprouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-chainalysisoracle" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-counter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowamm" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammconstantproductfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammfactorygetter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammlegacyhelper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammuniswapv2priceoracle" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowprotocoltoken" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowswapethflow" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowswaponchainorders" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-erc1271signaturevalidator" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-erc20" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-erc20mintable" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-flashloanrouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gashog" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafe" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafecompatibilityfallbackhandler" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafeproxy" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafeproxyfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gpv2allowlistauthentication" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gpv2settlement" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-honeyswaprouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-hookstrampoline" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-icowwrapper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-ierc4626" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iswaprpair" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iuniswaplikepair" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iuniswaplikerouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iuniswapv3factory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-izeroex" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-liquoricesettlement" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-mockerc4626wrapper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-nonstandarderc20balances" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-pancakerouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-permit2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-remoteerc20balances" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-signatures" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-solver" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-solver7702delegate" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-spardose" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-sushiswaprouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-swapper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-swaprrouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-testnetuniswapv2router02" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv2factory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv2router02" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv3pool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv3quoterv2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv3swaprouterv2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-weth9" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -2320,19 +3571,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "crc32c" -version = "0.6.5" +name = "crc-fast" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89254598aa9b9fa608de44b3ae54c810f0f06d755e24c50177f1f8f31ff50ce2" +checksum = "2fd92aca2c6001b1bf5ba0ff84ee74ec8501b52bbef0cac80bf25a6c1d87a83d" dependencies = [ - "rustc_version 0.4.0", + "crc", + "digest 0.10.7", + "rustversion", + "spin 0.10.0", ] [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -2357,24 +3611,24 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" @@ -2390,113 +3644,108 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", ] [[package]] -name = "curl" -version = "0.4.46" +name = "curve25519-dalek" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2 0.5.10", - "windows-sys 0.52.0", + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", ] [[package]] -name = "curl-sys" -version = "0.4.72+curl-8.6.0" +name = "curve25519-dalek-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.52.0", + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] name = "darling" -version = "0.20.9" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core 0.20.9", - "darling_macro 0.20.9", + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] name = "darling" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] name = "darling_core" -version = "0.20.9" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "darling_core" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", "serde", "strsim", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core 0.20.9", + "darling_core 0.21.3", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core 0.21.3", + "darling_core 0.23.0", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -2515,15 +3764,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "data-encoding-macro" -version = "0.1.15" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" +checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2531,12 +3780,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.13" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -2558,9 +3807,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "pem-rfc7468", @@ -2569,12 +3818,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -2588,19 +3837,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn 1.0.109", -] - [[package]] name = "derive_more" version = "1.0.0" @@ -2612,11 +3848,11 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ - "derive_more-impl 2.0.1", + "derive_more-impl 2.1.1", ] [[package]] @@ -2628,28 +3864,24 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", "unicode-xid", ] [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ + "convert_case 0.10.0", "proc-macro2", "quote", - "syn 2.0.104", + "rustc_version 0.4.1", + "syn 2.0.114", "unicode-xid", ] -[[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - [[package]] name = "digest" version = "0.9.0" @@ -2671,6 +3903,26 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -2687,31 +3939,37 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" name = "driver" version = "0.1.0" dependencies = [ + "account-balances", "alloy", "anyhow", "app-data", "async-trait", - "axum", + "axum 0.8.8", + "bad-tokens", + "balance-overrides", "bigdecimal", + "bytes", "bytes-hex", "chain", "chrono", "clap", + "configs", "const-hex", "contracts", "cow-amm", "dashmap", "derive_more 1.0.0", - "ethcontract", - "ethereum-types", + "eth-domain-types", "ethrpc", + "event-indexing", "futures", - "gas-estimation", + "gas-price-estimation", "hex-literal", + "http-client", "humantime", "humantime-serde", - "hyper 0.14.29", "itertools 0.14.0", + "liquidity-sources", "maplit", "mimalloc", "model", @@ -2719,29 +3977,33 @@ dependencies = [ "num", "number", "observe", - "primitive-types", + "price-estimation", "prometheus", "prometheus-metric-storage", - "rand 0.8.5", - "reqwest 0.11.27", + "rand 0.9.4", + "request-sharing", + "reqwest 0.13.2", "s3", - "secp256k1 0.27.0", "serde", + "serde-ext", "serde_json", "serde_with", "shared", + "signature-validator", + "simulator", "solver", "solvers-dto", "tempfile", - "thiserror 1.0.61", + "thiserror 1.0.69", + "tikv-jemallocator", + "token-info", "tokio", "toml", - "tower 0.4.13", + "tower 0.5.3", "tower-http", "tracing", "url", "vergen", - "web3", ] [[package]] @@ -2750,47 +4012,62 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "e2e" version = "1.0.0" dependencies = [ "alloy", + "alloy-signer", "anyhow", "app-data", "autopilot", - "axum", + "axum 0.8.8", + "balance-overrides", "bigdecimal", "chrono", "clap", + "configs", "const-hex", "contracts", "cow-amm", "database", "driver", - "ethcontract", + "eth-domain-types", "ethrpc", "futures", "hex-literal", + "itertools 0.14.0", + "liquidity-sources", "model", "number", "observe", "orderbook", + "pool-indexer", + "price-estimation", "refunder", - "reqwest 0.11.27", - "secp256k1 0.27.0", + "reqwest 0.13.2", + "rstest", + "serde", "serde_json", "shared", + "signature-validator", + "simulator", "solver", "solvers", "solvers-dto", "sqlx", "tempfile", + "testlib", "tokio", "toml", "tracing", "url", - "warp", - "web3", ] [[package]] @@ -2808,6 +4085,28 @@ dependencies = [ "spki", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2", + "signature", + "subtle", +] + [[package]] name = "educe" version = "0.6.0" @@ -2817,7 +4116,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -2851,228 +4150,137 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enum-ordinalize" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror 1.0.61", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-rlp", - "impl-serde", - "tiny-keccak", -] - -[[package]] -name = "ethcontract" -version = "0.25.9" -source = "git+https://github.com/cowprotocol/ethcontract-rs?rev=8e112a88988040cde6110379ee6d1be768a13244#8e112a88988040cde6110379ee6d1be768a13244" -dependencies = [ - "arrayvec", - "aws-config", - "aws-sdk-kms", - "ethcontract-common", - "ethcontract-derive", - "futures", - "futures-timer", - "hex", - "jsonrpc-core", - "lazy_static", - "primitive-types", - "rlp", - "secp256k1 0.27.0", - "serde", - "serde_json", - "thiserror 1.0.61", - "uint", - "web3", - "zeroize", +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", ] [[package]] -name = "ethcontract-common" -version = "0.25.9" -source = "git+https://github.com/cowprotocol/ethcontract-rs?rev=8e112a88988040cde6110379ee6d1be768a13244#8e112a88988040cde6110379ee6d1be768a13244" +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ - "ethabi", - "hex", - "serde", - "serde_derive", - "serde_json", - "thiserror 1.0.61", - "tiny-keccak", - "web3", + "enum-ordinalize-derive", ] [[package]] -name = "ethcontract-derive" -version = "0.25.9" -source = "git+https://github.com/cowprotocol/ethcontract-rs?rev=8e112a88988040cde6110379ee6d1be768a13244#8e112a88988040cde6110379ee6d1be768a13244" +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ - "anyhow", - "ethcontract-common", - "ethcontract-generate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] -name = "ethcontract-generate" -version = "0.25.9" -source = "git+https://github.com/cowprotocol/ethcontract-rs?rev=8e112a88988040cde6110379ee6d1be768a13244#8e112a88988040cde6110379ee6d1be768a13244" +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ - "Inflector", - "anyhow", - "curl", - "ethcontract-common", - "proc-macro2", - "quote", - "syn 2.0.104", - "url", + "libc", + "windows-sys 0.61.2", ] [[package]] -name = "ethcontract-mock" -version = "0.25.9" -source = "git+https://github.com/cowprotocol/ethcontract-rs?rev=8e112a88988040cde6110379ee6d1be768a13244#8e112a88988040cde6110379ee6d1be768a13244" +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ - "ethcontract", - "hex", - "mockall 0.11.4", - "predicates 3.1.0", - "rlp", + "cfg-if", + "home", + "windows-sys 0.48.0", ] [[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +name = "eth-domain-types" +version = "0.1.0" dependencies = [ - "ethbloom", - "fixed-hash", - "impl-rlp", - "impl-serde", - "primitive-types", - "uint", + "alloy-eips", + "alloy-primitives", + "alloy-rpc-types", + "derive_more 1.0.0", + "num", + "number", ] [[package]] name = "ethrpc" version = "0.1.0" dependencies = [ - "alloy", + "alloy-consensus", + "alloy-contract", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-signer", + "alloy-transport", + "alloy-transport-ws", "anyhow", "async-trait", "const-hex", - "ethcontract", "futures", - "hex-literal", "itertools 0.14.0", - "maplit", - "mockall 0.12.1", "observe", - "primitive-types", "prometheus", "prometheus-metric-storage", - "rand 0.8.5", - "reqwest 0.11.27", + "rand 0.9.4", + "reqwest 0.13.2", "scopeguard", "serde", "serde_json", - "testlib", "tokio", "tokio-stream", - "tower 0.4.13", + "tower 0.5.3", "tracing", "url", - "web3", ] [[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +name = "event-indexing" +version = "0.1.0" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types", + "alloy-sol-types", + "anyhow", + "async-stream", + "async-trait", + "contracts", + "ethrpc", + "futures", + "mockall", + "observe", + "prometheus", + "prometheus-metric-storage", + "tokio", + "tracing", + "tracing-subscriber", +] [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -3081,19 +4289,19 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.0", + "event-listener", "pin-project-lite", ] [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -3127,6 +4335,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" + [[package]] name = "fixed-hash" version = "0.8.0" @@ -3141,28 +4361,19 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" dependencies = [ "crc32fast", "miniz_oxide", ] -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -3204,18 +4415,24 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "fragile" -version = "2.0.0" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" + +[[package]] +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "funty" @@ -3225,9 +4442,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -3256,9 +4473,9 @@ checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -3290,7 +4507,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -3336,35 +4553,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" [[package]] -name = "gas-estimation" +name = "gas-price-estimation" version = "0.1.0" -source = "git+https://github.com/cowprotocol/gas-estimation?tag=v0.7.3#5384e9d013bf33fed32b3e5366ed01b2d8cacbe4" dependencies = [ + "alloy-eips", + "alloy-provider", "anyhow", "async-trait", + "configs", + "ethrpc", "futures", - "http 0.2.12", - "primitive-types", - "serde", - "serde_json", - "serde_with", + "mockall", + "observe", + "prometheus", + "prometheus-metric-storage", + "reqwest 0.13.2", "tokio", "tracing", "url", - "web3", -] - -[[package]] -name = "generator" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" -dependencies = [ - "cfg-if", - "libc", - "log", - "rustversion", - "windows", ] [[package]] @@ -3380,38 +4586,56 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", + "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasip2", + "wasip3", ] [[package]] name = "gimli" -version = "0.29.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "group" @@ -3426,9 +4650,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -3436,7 +4660,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.10.0", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -3445,17 +4669,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.10.0", + "http 1.4.0", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -3467,25 +4691,18 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.11", - "allocator-api2", -] [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", @@ -3494,21 +4711,24 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ + "allocator-api2", + "equivalent", "foldhash 0.2.0", "serde", + "serde_core", ] [[package]] name = "hashlink" -version = "0.8.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.5", ] [[package]] @@ -3524,39 +4744,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "headers" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" -dependencies = [ - "base64 0.21.7", - "bytes", - "headers-core", - "http 0.2.12", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http 0.2.12", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.5.0" @@ -3565,18 +4752,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -3586,9 +4764,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" dependencies = [ "arrayvec", ] @@ -3619,11 +4797,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3639,12 +4817,11 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -3661,32 +4838,36 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.4.0", ] [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.1.0", - "http-body 1.0.0", + "http 1.4.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +name = "http-client" +version = "0.1.0" +dependencies = [ + "clap", + "configs", + "humantime", + "reqwest 0.13.2", +] [[package]] name = "httparse" @@ -3702,9 +4883,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "humantime-serde" @@ -3718,15 +4899,15 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -3742,19 +4923,22 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", - "h2 0.4.10", - "http 1.1.0", - "http-body 1.0.0", + "futures-core", + "h2 0.4.13", + "http 1.4.0", + "http-body 1.0.1", "httparse", + "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -3762,18 +4946,19 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.29", - "log", - "rustls 0.21.12", + "http 1.4.0", + "hyper 1.8.1", + "hyper-util", + "rustls", "rustls-native-certs", + "rustls-pki-types", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", + "tower-service", ] [[package]] @@ -3782,7 +4967,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.29", + "hyper 0.14.32", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -3794,75 +4979,52 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.6.0", + "hyper 1.8.1", "hyper-util", "pin-project-lite", "tokio", "tower-service", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper 0.14.29", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.6.0", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.6.0", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.8.1", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.1", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core", ] [[package]] @@ -3875,77 +5037,137 @@ dependencies = [ ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "icu_collections" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] [[package]] -name = "idna" -version = "0.3.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "idna" -version = "0.4.0" +name = "icu_normalizer" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "impl-codec" -version = "0.6.0" +name = "icu_properties_data" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ - "parity-scale-codec", + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "impl-rlp" -version = "0.3.0" +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "rlp", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "impl-serde" -version = "0.4.0" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "serde", + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", ] [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -3961,13 +5183,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.1", "serde", + "serde_core", ] [[package]] @@ -3980,27 +5203,26 @@ dependencies = [ ] [[package]] -name = "io-uring" -version = "0.7.9" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "libc", -] +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] -name = "ipnet" -version = "2.9.0" +name = "iri-string" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -4040,32 +5262,67 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] -name = "js-sys" -version = "0.3.69" +name = "jemalloc_pprof" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "74ff642505c7ce8d31c0d43ec0e235c6fd4585d9b8172d8f9dd04d36590200b5" dependencies = [ - "wasm-bindgen", + "anyhow", + "libc", + "mappings", + "once_cell", + "pprof_util", + "tempfile", + "tikv-jemalloc-ctl", + "tokio", + "tracing", ] [[package]] -name = "jsonrpc-core" -version = "18.0.0" +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ - "futures", - "futures-executor", - "futures-util", + "cesu8", + "cfg-if", + "combine", + "jni-sys", "log", - "serde", - "serde_derive", - "serde_json", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", ] [[package]] @@ -4085,18 +5342,18 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] name = "keccak-asm" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +checksum = "b646a74e746cd25045aa0fd42f4f7f78aa6d119380182c7e63a5593c4ab8df6f" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -4104,111 +5361,151 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin 0.9.8", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.174" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.39" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" dependencies = [ "cc", "libc", ] [[package]] -name = "libsqlite3-sys" -version = "0.27.0" +name = "libredox" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "cc", - "pkg-config", - "vcpkg", + "bitflags 2.10.0", + "libc", + "redox_syscall 0.7.0", ] [[package]] -name = "libz-sys" -version = "1.1.18" +name = "libsqlite3-sys" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ - "cc", - "libc", "pkg-config", "vcpkg", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +name = "liquidity-sources" +version = "0.1.0" dependencies = [ - "autocfg", - "scopeguard", + "alloy", + "anyhow", + "async-trait", + "bytes-hex", + "cached", + "chain", + "chrono", + "clap", + "const-hex", + "contracts", + "ethrpc", + "event-indexing", + "futures", + "hex-literal", + "itertools 0.14.0", + "maplit", + "mockall", + "model", + "num", + "number", + "observe", + "prometheus", + "prometheus-metric-storage", + "regex", + "request-sharing", + "reqwest 0.13.2", + "serde", + "serde_json", + "serde_with", + "strum", + "testlib", + "thiserror 1.0.69", + "token-info", + "tokio", + "tracing", ] [[package]] -name = "log" -version = "0.4.21" +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "litrs" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] -name = "loom" -version = "0.7.2" +name = "lock_api" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", + "scopeguard", ] [[package]] -name = "lru" -version = "0.12.3" +name = "log" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" -dependencies = [ - "hashbrown 0.14.5", -] +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru" -version = "0.13.0" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.16.1", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "macro-string" version = "0.1.4" @@ -4217,7 +5514,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -4226,13 +5523,37 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "mappings" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d277bb50d4508057e7bddd7fcd19ef4a4cc38051b6a5a36868d75ae2cbeb9" +dependencies = [ + "anyhow", + "libc", + "once_cell", + "pprof_util", + "tracing", +] + +[[package]] +name = "match-lookup" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1265724d8cb29dbbc2b0f06fffb8bf1a8c0cf73a78eede9ba73a4a66c52a981e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "matchers" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -4241,6 +5562,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "md-5" version = "0.10.6" @@ -4253,15 +5580,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mimalloc" -version = "0.1.43" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" dependencies = [ "libmimalloc-sys", ] @@ -4272,16 +5599,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4290,37 +5607,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "mockall" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive 0.11.4", - "predicates 2.1.5", - "predicates-tree", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -4333,23 +5636,11 @@ dependencies = [ "downcast", "fragile", "lazy_static", - "mockall_derive 0.12.1", - "predicates 3.1.0", + "mockall_derive", + "predicates", "predicates-tree", ] -[[package]] -name = "mockall_derive" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "mockall_derive" version = "0.12.1" @@ -4359,14 +5650,17 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "model" version = "0.1.0" dependencies = [ - "alloy", + "alloy-primitives", + "alloy-signer", + "alloy-signer-local", + "alloy-sol-types", "anyhow", "app-data", "bigdecimal", @@ -4378,66 +5672,78 @@ dependencies = [ "maplit", "num", "number", - "primitive-types", - "secp256k1 0.27.0", "serde", + "serde-ext", "serde_json", "serde_with", "strum", "testlib", - "web3", ] [[package]] name = "moka" -version = "0.12.10" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" +checksum = "a3dec6bd31b08944e08b58fd99373893a6c17054d6f3ea5006cc894f4f4eee2a" dependencies = [ "async-lock", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", - "event-listener 5.4.0", + "equivalent", + "event-listener", "futures-util", - "loom", "parking_lot", "portable-atomic", - "rustc_version 0.4.0", "smallvec", "tagptr", - "thiserror 1.0.61", "uuid", ] [[package]] name = "multibase" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +checksum = "8694bb4835f452b0e3bb06dbebb1d6fc5385b6ca1caf2e55fd165c042390ec77" dependencies = [ "base-x", + "base256emoji", "data-encoding", "data-encoding-macro", ] [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.1.6", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] +[[package]] +name = "nkeys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879011babc47a1c7fdf5a935ae3cfe94f34645ca0cac1c7f6424b36fc743d1bf" +dependencies = [ + "data-encoding", + "ed25519", + "ed25519-dalek", + "getrandom 0.2.17", + "log", + "rand 0.8.5", + "signatory", +] + [[package]] name = "nom" version = "7.1.3" @@ -4449,19 +5755,21 @@ dependencies = [ ] [[package]] -name = "normalize-line-endings" -version = "0.3.0" +name = "nu-ansi-term" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "nuid" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "fc895af95856f929163a0aa20c26a78d26bfdc839f51b9d5aa7a5b79e52b7e83" dependencies = [ - "overload", - "winapi", + "rand 0.8.5", ] [[package]] @@ -4480,9 +5788,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -4490,11 +5798,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -4516,9 +5823,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-integer" @@ -4563,19 +5870,19 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -4583,13 +5890,13 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -4605,20 +5912,20 @@ dependencies = [ name = "number" version = "0.1.0" dependencies = [ - "alloy", + "alloy-primitives", "anyhow", "bigdecimal", "num", - "primitive-types", + "ruint", "serde", "serde_with", ] [[package]] name = "nybbles" -version = "0.4.1" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675b3a54e5b12af997abc8b6638b0aee51a28caedab70d4967e0d5db3a3f1d06" +checksum = "7b5676b5c379cf5b03da1df2b3061c4a4e2aa691086a56ac923e08c143f53f59" dependencies = [ "alloy-rlp", "cfg-if", @@ -4630,9 +5937,9 @@ dependencies = [ [[package]] name = "object" -version = "0.35.0" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -4641,13 +5948,17 @@ dependencies = [ name = "observe" version = "0.1.0" dependencies = [ + "async-nats", "async-trait", - "atty", - "axum", + "axum 0.8.8", + "backtrace", + "bytes", "chrono", "console-subscriber", "futures", + "jemalloc_pprof", "opentelemetry", + "opentelemetry-http", "opentelemetry-otlp", "opentelemetry_sdk", "pin-project-lite", @@ -4662,7 +5973,7 @@ dependencies = [ "tracing-opentelemetry", "tracing-serde", "tracing-subscriber", - "warp", + "url", ] [[package]] @@ -4671,13 +5982,19 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "cfg-if", "foreign-types", "libc", @@ -4694,20 +6011,26 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-probe" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -4717,175 +6040,192 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" dependencies = [ "futures-core", "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.12", + "thiserror 2.0.17", "tracing", ] [[package]] name = "opentelemetry-http" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" dependencies = [ "async-trait", "bytes", - "http 1.1.0", + "http 1.4.0", "opentelemetry", - "reqwest 0.12.12", + "reqwest 0.12.28", ] [[package]] name = "opentelemetry-otlp" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" dependencies = [ - "http 1.1.0", + "http 1.4.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", "opentelemetry_sdk", - "prost 0.13.5", - "reqwest 0.12.12", - "thiserror 2.0.12", + "prost 0.14.3", + "reqwest 0.12.28", + "thiserror 2.0.17", "tokio", - "tonic 0.13.1", + "tonic 0.14.4", "tracing", ] [[package]] name = "opentelemetry-proto" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" dependencies = [ "opentelemetry", "opentelemetry_sdk", - "prost 0.13.5", - "tonic 0.13.1", + "prost 0.14.3", + "tonic 0.14.4", + "tonic-prost", ] [[package]] name = "opentelemetry_sdk" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" dependencies = [ "futures-channel", "futures-executor", "futures-util", "opentelemetry", "percent-encoding", - "rand 0.9.1", - "serde_json", - "thiserror 2.0.12", + "rand 0.9.4", + "thiserror 2.0.17", ] [[package]] name = "order-validation" version = "0.1.0" dependencies = [ - "alloy", + "alloy-contract", + "alloy-primitives", + "async-trait", + "const-hex", "contracts", "futures", + "hmac", "moka", - "thiserror 1.0.61", + "reqwest 0.13.2", + "sha2", + "thiserror 1.0.69", "tokio", "tracing", + "url", ] [[package]] name = "orderbook" version = "0.1.0" dependencies = [ + "account-balances", "alloy", "anyhow", "app-data", "async-trait", + "axum 0.8.8", + "bad-tokens", + "balance-overrides", "bigdecimal", "cached", "chain", "chrono", "clap", + "configs", "const-hex", "contracts", "database", - "ethcontract", + "eth-domain-types", "ethrpc", "futures", + "gas-price-estimation", "hex-literal", + "http-client", "humantime", - "hyper 0.14.29", + "humantime-serde", "mimalloc", - "mockall 0.12.1", + "mockall", "model", "multibase", "num", "number", "observe", "order-validation", - "primitive-types", + "price-estimation", "prometheus", "prometheus-metric-storage", - "reqwest 0.11.27", + "reqwest 0.13.2", "serde", "serde_json", "serde_with", "shared", + "signature-validator", + "simulator", "sqlx", "strum", - "thiserror 1.0.61", + "tempfile", + "thiserror 1.0.69", + "tikv-jemallocator", + "token-info", "tokio", + "toml", + "tower 0.5.3", + "tower-http", "tracing", "url", "vergen", - "warp", ] [[package]] name = "outref" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" - -[[package]] -name = "overload" -version = "0.1.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", + "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -4896,9 +6236,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -4906,15 +6246,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -4944,18 +6284,17 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" dependencies = [ "memchr", - "thiserror 2.0.12", "ucd-trie", ] @@ -4966,34 +6305,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -5024,15 +6363,65 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "pool-indexer" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "anyhow", + "async-trait", + "axum 0.8.8", + "bigdecimal", + "clap", + "configs", + "contracts", + "ethrpc", + "futures", + "itertools 0.14.0", + "mimalloc", + "num", + "number", + "observe", + "prometheus", + "prometheus-metric-storage", + "reqwest 0.13.2", + "scopeguard", + "serde", + "serde_json", + "shared", + "sqlx", + "tikv-jemallocator", + "tokio", + "toml", + "tower 0.5.3", + "tower-http", + "tracing", + "url", +] [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" + +[[package]] +name = "potential_utf" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -5041,98 +6430,139 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "pprof_util" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "4429d44e5e2c8a69399fc0070379201eed018e3df61e04eb7432811df073c224" +dependencies = [ + "anyhow", + "backtrace", + "flate2", + "num", + "paste", + "prost 0.13.5", +] [[package]] -name = "predicates" -version = "2.1.5" +name = "ppv-lite86" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", - "predicates-core", - "regex", + "zerocopy", ] [[package]] name = "predicates" -version = "3.1.0" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", - "difflib", - "float-cmp", - "normalize-line-endings", "predicates-core", - "regex", ] [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", ] [[package]] -name = "primitive-types" -version = "0.12.2" +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "uint", + "proc-macro2", + "syn 2.0.114", ] [[package]] -name = "proc-macro-crate" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +name = "price-estimation" +version = "0.1.0" dependencies = [ - "toml_edit 0.21.1", + "alloy", + "anyhow", + "app-data", + "arc-swap", + "async-trait", + "bad-tokens", + "balance-overrides", + "bigdecimal", + "bytes-hex", + "cached", + "chain", + "chrono", + "clap", + "configs", + "const-hex", + "contracts", + "dashmap", + "derive_more 1.0.0", + "ethrpc", + "futures", + "gas-price-estimation", + "hex-literal", + "http-client", + "humantime", + "humantime-serde", + "itertools 0.14.0", + "maplit", + "mockall", + "model", + "moka", + "num", + "number", + "observe", + "prometheus", + "prometheus-metric-storage", + "rand 0.9.4", + "rate-limit", + "request-sharing", + "reqwest 0.13.2", + "rust_decimal", + "serde", + "serde_json", + "serde_with", + "simulator", + "testlib", + "thiserror 1.0.69", + "token-info", + "tokio", + "toml", + "tracing", + "url", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "primitive-types" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "version_check", + "fixed-hash", + "impl-codec", + "uint", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-crate" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] @@ -5154,23 +6584,23 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.4" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" +checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" dependencies = [ "cfg-if", "fnv", @@ -5178,46 +6608,44 @@ dependencies = [ "memchr", "parking_lot", "protobuf", - "thiserror 1.0.61", + "thiserror 2.0.17", ] [[package]] name = "prometheus-metric-storage" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3282447ea0b07baa9011e45de96794c5963db0162c1001d2867750715d63ff14" +checksum = "53a55c0609963f710688a781fb4de9bfc094dfb0dbfa46331486152c4b011330" dependencies = [ - "lazy_static", "prometheus", "prometheus-metric-storage-derive", ] [[package]] name = "prometheus-metric-storage-derive" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239221aa10cd35277c58b8f6509280b2613321760b49584d7a7351a6aacb6963" +checksum = "710d30cd8d768420cf9d0f1727c2709df928cd509810fcb98dd386580dccf919" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] name = "proptest" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.1", - "lazy_static", + "bitflags 2.10.0", "num-traits", - "rand 0.9.1", + "rand 0.9.4", "rand_chacha 0.9.0", "rand_xorshift", - "regex-syntax 0.8.3", + "regex-syntax", "rusty-fork", "tempfile", "unarray", @@ -5243,6 +6671,16 @@ dependencies = [ "prost-derive 0.13.5", ] +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive 0.14.3", +] + [[package]] name = "prost-derive" version = "0.12.6" @@ -5253,20 +6691,33 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -5280,9 +6731,23 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.28.0" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror 1.0.69", +] + +[[package]] +name = "protobuf-support" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" +dependencies = [ + "thiserror 1.0.69", +] [[package]] name = "psl-types" @@ -5291,46 +6756,82 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] -name = "ptr_meta" -version = "0.1.4" +name = "publicsuffix" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" dependencies = [ - "ptr_meta_derive", + "idna", + "psl-types", ] [[package]] -name = "ptr_meta_derive" -version = "0.1.4" +name = "quick-error" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.6.1", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", ] [[package]] -name = "publicsuffix" -version = "2.2.3" +name = "quinn-proto" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ - "idna 0.3.0", - "psl-types", + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "quinn-udp" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.1", + "tracing", + "windows-sys 0.60.2", +] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -5341,6 +6842,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.7.0" @@ -5361,15 +6868,26 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", "serde", ] +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -5387,7 +6905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -5396,26 +6914,42 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "serde", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rand_xorshift" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8b5b858a440a0bc02625b62dd95131b9201aa9f69f411195dd4a7cfb1de3d7" +dependencies = [ + "rand 0.9.4", + "rustversion", ] [[package]] @@ -5423,33 +6957,56 @@ name = "rate-limit" version = "0.1.0" dependencies = [ "anyhow", + "configs", "futures", - "humantime", + "humantime-serde", "observe", "prometheus", "prometheus-metric-storage", - "reqwest 0.11.27", - "thiserror 1.0.61", + "reqwest 0.13.2", + "serde", + "serde_json", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.10.0", ] [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ - "bitflags 2.9.1", + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] @@ -5465,15 +7022,20 @@ dependencies = [ "database", "ethrpc", "futures", - "gas-estimation", + "gas-price-estimation", + "http-client", "humantime", "mimalloc", + "mockall", "number", "observe", "prometheus", "prometheus-metric-storage", + "rand 0.9.4", + "rstest", "shared", "sqlx", + "tikv-jemallocator", "tokio", "tracing", "url", @@ -5481,146 +7043,135 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] name = "regex-lite" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] -name = "regex-syntax" -version = "0.8.3" +name = "relative-path" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +name = "request-sharing" +version = "0.1.0" dependencies = [ - "bytecheck", + "futures", + "observe", + "prometheus", + "prometheus-metric-storage", + "tokio", ] [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "async-compression", - "base64 0.21.7", + "base64 0.22.1", "bytes", - "cookie", - "cookie_store", - "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.29", - "hyper-tls 0.5.0", - "ipnet", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", "js-sys", "log", - "mime", - "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", + "sync_wrapper 1.0.2", "tokio", - "tokio-native-tls", - "tokio-util", + "tower 0.5.3", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", ] [[package]] name = "reqwest" -version = "0.12.12" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64 0.22.1", "bytes", + "cookie", + "cookie_store", + "encoding_rs", "futures-channel", "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.0", + "h2 0.4.13", + "http 1.4.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", - "hyper-tls 0.6.0", + "hyper 1.8.1", + "hyper-rustls", "hyper-util", - "ipnet", "js-sys", "log", "mime", - "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.2.0", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", - "tokio-native-tls", - "tower 0.5.2", + "tokio-rustls", + "tokio-util", + "tower 0.5.3", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", - "windows-registry", ] [[package]] @@ -5641,7 +7192,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -5656,35 +7207,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "rkyv" -version = "0.7.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rlp" version = "0.5.2" @@ -5697,9 +7219,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest 0.10.7", @@ -5715,11 +7237,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rstest" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", +] + +[[package]] +name = "rstest_macros" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version 0.4.1", + "syn 2.0.114", + "unicode-ident", +] + [[package]] name = "ruint" -version = "1.17.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -5735,7 +7286,7 @@ dependencies = [ "primitive-types", "proptest", "rand 0.8.5", - "rand 0.9.1", + "rand 0.9.4", "rlp", "ruint-macro", "serde_core", @@ -5751,31 +7302,28 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" dependencies = [ "arrayvec", - "borsh", - "bytes", "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", ] [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +dependencies = [ + "rand 0.8.5", +] [[package]] name = "rustc-hex" @@ -5794,107 +7342,97 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver 1.0.27", ] [[package]] name = "rustix" -version = "0.38.34" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.34" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ + "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.7", + "rustls-webpki", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", - "rustls-pemfile 1.0.4", + "openssl-probe 0.2.0", + "rustls-pki-types", "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", + "security-framework 3.5.1", ] [[package]] -name = "rustls-pemfile" -version = "2.2.0" +name = "rustls-pki-types" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ - "rustls-pki-types", + "web-time", + "zeroize", ] [[package]] -name = "rustls-pki-types" -version = "1.12.0" +name = "rustls-platform-verifier" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "zeroize", + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework 3.5.1", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", ] [[package]] -name = "rustls-webpki" -version = "0.101.7" +name = "rustls-platform-verifier-android" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -5902,15 +7440,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error", @@ -5920,9 +7458,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "s3" @@ -5931,6 +7469,7 @@ dependencies = [ "anyhow", "aws-config", "aws-sdk-s3", + "bytes", "chrono", "flate2", "serde", @@ -5939,41 +7478,52 @@ dependencies = [ ] [[package]] -name = "schannel" -version = "0.1.23" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "windows-sys 0.52.0", + "winapi-util", ] [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "schannel" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "schemars" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] [[package]] -name = "sct" -version = "0.7.1" +name = "schemars" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ - "ring", - "untrusted", + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] -name = "seahash" -version = "4.1.0" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sec1" @@ -5990,15 +7540,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" -dependencies = [ - "secp256k1-sys 0.8.1", -] - [[package]] name = "secp256k1" version = "0.30.0" @@ -6007,36 +7548,40 @@ checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", "rand 0.8.5", - "secp256k1-sys 0.10.1", + "secp256k1-sys", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] [[package]] -name = "secp256k1-sys" -version = "0.10.1" +name = "security-framework" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "cc", + "bitflags 2.10.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] name = "security-framework" -version = "2.11.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.1", - "core-foundation", + "bitflags 2.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -6044,9 +7589,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -6063,9 +7608,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "semver-parser" @@ -6092,6 +7637,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-ext" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "const-hex", + "serde", + "serde_with", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -6109,35 +7664,58 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "ryu", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_nanos" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93142f0367a4cc53ae0fead1bcda39e85beccfad3dcd717656cacab94b12985" +dependencies = [ "serde", ] [[package]] name = "serde_path_to_error" -version = "0.1.16" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -6156,17 +7734,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.1" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.10.0", - "serde", - "serde_derive", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.0", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -6174,14 +7753,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ - "darling 0.20.9", + "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -6201,18 +7780,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -6228,9 +7807,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +checksum = "b31139435f327c93c6038ed350ae4588e2c70a13d50599509fee6349967ba35a" dependencies = [ "cc", "cfg-if", @@ -6249,59 +7828,66 @@ dependencies = [ name = "shared" version = "0.1.0" dependencies = [ + "account-balances", "alloy", "anyhow", "app-data", + "arc-swap", "async-stream", "async-trait", + "bad-tokens", + "balance-overrides", "bigdecimal", "bytes-hex", "cached", "chain", "chrono", "clap", + "configs", "const-hex", "contracts", "dashmap", "database", - "derivative", "derive_more 1.0.0", - "ethcontract", - "ethcontract-mock", "ethrpc", "futures", - "gas-estimation", + "gas-price-estimation", "hex-literal", "humantime", - "indexmap 2.10.0", + "indexmap 2.13.0", "itertools 0.14.0", + "liquidity-sources", "maplit", - "mockall 0.12.1", + "mockall", "model", + "moka", "num", "number", "observe", "order-validation", - "primitive-types", + "price-estimation", "prometheus", "prometheus-metric-storage", - "rand 0.8.5", + "rand 0.9.4", "rate-limit", "regex", - "reqwest 0.11.27", + "request-sharing", + "reqwest 0.13.2", "rust_decimal", - "secp256k1 0.27.0", "serde", "serde_json", "serde_with", + "signature-validator", + "simulator", "strum", "testlib", - "thiserror 1.0.61", + "thiserror 1.0.69", + "token-info", "tokio", + "toml", "tracing", "tracing-subscriber", "url", - "web3", ] [[package]] @@ -6312,13 +7898,26 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] +[[package]] +name = "signatory" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e303f8205714074f6068773f0e29527e0453937fe837c9717d066635b65f31" +dependencies = [ + "pkcs8", + "rand_core 0.6.4", + "signature", + "zeroize", +] + [[package]] name = "signature" version = "2.2.0" @@ -6330,25 +7929,90 @@ dependencies = [ ] [[package]] -name = "simdutf8" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +name = "signature-validator" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-dyn-abi", + "alloy-primitives", + "alloy-rpc-types", + "alloy-sol-types", + "alloy-transport", + "anyhow", + "async-trait", + "balance-overrides", + "const-hex", + "contracts", + "ethrpc", + "hex-literal", + "mockall", + "model", + "thiserror 1.0.69", + "tracing", +] [[package]] -name = "slab" -version = "0.4.9" +name = "simd-adler32" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simulator" +version = "0.1.0" dependencies = [ - "autocfg", + "alloy-contract", + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types", + "alloy-sol-types", + "alloy-transport", + "anyhow", + "app-data", + "async-trait", + "balance-overrides", + "cached", + "chain", + "configs", + "const-hex", + "contracts", + "derive_more 1.0.0", + "eth-domain-types", + "ethrpc", + "futures", + "gas-price-estimation", + "hex-literal", + "http-client", + "mockall", + "model", + "number", + "observe", + "prometheus", + "prometheus-metric-storage", + "reqwest 0.13.2", + "serde", + "serde-ext", + "serde_json", + "serde_with", + "testlib", + "thiserror 1.0.69", + "tokio", + "tracing", + "url", ] +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] @@ -6365,14 +8029,18 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] +[[package]] +name = "solana-indexer" +version = "0.1.0" + [[package]] name = "solver" version = "0.1.0" @@ -6383,28 +8051,26 @@ dependencies = [ "async-trait", "const-hex", "contracts", - "derivative", - "ethcontract", "ethrpc", "futures", "hex-literal", "itertools 0.14.0", + "liquidity-sources", "maplit", - "mockall 0.12.1", + "mockall", "model", "num", "number", "observe", - "primitive-types", "prometheus", "prometheus-metric-storage", "serde_json", "shared", + "simulator", "strum", "testlib", "tokio", "tracing", - "web3", ] [[package]] @@ -6413,49 +8079,63 @@ version = "0.1.0" dependencies = [ "alloy", "anyhow", - "axum", + "axum 0.8.8", + "base64 0.22.1", "bigdecimal", + "bytes-hex", "chain", "chrono", "clap", + "configs", "const-hex", "contracts", "derive_more 1.0.0", - "ethcontract", - "ethereum-types", "ethrpc", "futures", - "hex-literal", - "hyper 0.14.29", + "glob", + "hmac", + "humantime-serde", "itertools 0.14.0", + "liquidity-sources", + "maplit", "mimalloc", "model", + "moka", "num", + "number", "observe", + "price-estimation", "prometheus", "prometheus-metric-storage", - "reqwest 0.11.27", + "rate-limit", + "reqwest 0.13.2", "serde", "serde_json", "serde_with", + "sha2", "shared", "solver", "solvers-dto", "tempfile", + "testlib", + "thiserror 1.0.69", + "tikv-jemallocator", "tokio", "toml", - "tower 0.4.13", + "tower 0.5.3", "tower-http", "tracing", "url", "vergen", - "web3", ] [[package]] name = "solvers-dto" version = "0.1.0" dependencies = [ + "alloy-primitives", + "alloy-rpc-types", + "alloy-rpc-types-eth", "app-data", "bigdecimal", "bytes-hex", @@ -6463,16 +8143,11 @@ dependencies = [ "const-hex", "number", "serde", + "serde-ext", + "serde_json", "serde_with", - "web3", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -6482,6 +8157,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" + [[package]] name = "spki" version = "0.7.3" @@ -6492,21 +8173,11 @@ dependencies = [ "der", ] -[[package]] -name = "sqlformat" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" -dependencies = [ - "nom", - "unicode_categories", -] - [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" dependencies = [ "sqlx-core", "sqlx-macros", @@ -6517,40 +8188,35 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "ahash 0.8.11", - "atoi", + "base64 0.22.1", "bigdecimal", - "byteorder", "bytes", "chrono", "crc", "crossbeam-queue", "either", - "event-listener 2.5.3", - "futures-channel", + "event-listener", "futures-core", "futures-intrusive", "futures-io", "futures-util", + "hashbrown 0.15.5", "hashlink", - "hex", - "indexmap 2.10.0", + "indexmap 2.13.0", "log", "memchr", "native-tls", "once_cell", - "paste", "percent-encoding", "serde", "serde_json", "sha2", "smallvec", - "sqlformat", - "thiserror 1.0.61", + "thiserror 2.0.17", "tokio", "tokio-stream", "tracing", @@ -6559,26 +8225,26 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" dependencies = [ "dotenvy", "either", - "heck 0.4.1", + "heck", "hex", "once_cell", "proc-macro2", @@ -6590,22 +8256,21 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", - "tempfile", + "syn 2.0.114", "tokio", "url", ] [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", - "bitflags 2.9.1", + "bitflags 2.10.0", "byteorder", "bytes", "chrono", @@ -6635,21 +8300,21 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.61", + "thiserror 2.0.17", "tracing", "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bigdecimal", - "bitflags 2.9.1", + "bitflags 2.10.0", "byteorder", "chrono", "crc", @@ -6657,7 +8322,6 @@ dependencies = [ "etcetera", "futures-channel", "futures-core", - "futures-io", "futures-util", "hex", "hkdf", @@ -6676,16 +8340,16 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.61", + "thiserror 2.0.17", "tracing", "whoami", ] [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" dependencies = [ "atoi", "chrono", @@ -6699,12 +8363,19 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", + "thiserror 2.0.17", "tracing", "url", - "urlencoding", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -6743,17 +8414,53 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", +] + +[[package]] +name = "subsolver" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "alloy-signer", + "alloy-signer-local", + "alloy-sol-types", + "anyhow", + "byos", + "chain", + "chrono", + "clap", + "const-hex", + "contracts", + "ethrpc", + "humantime", + "model", + "number", + "observe", + "reqwest 0.13.2", + "serde", + "serde-ext", + "serde_json", + "serde_with", + "shared", + "solvers", + "solvers-dto", + "tikv-jemallocator", + "tokio", + "toml", + "tracing", + "url", + "vergen", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -6768,9 +8475,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -6779,26 +8486,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" +checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.104", -] - -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -6816,6 +8511,17 @@ dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -6823,7 +8529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6851,81 +8557,80 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.4", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "termtree" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "testlib" version = "0.1.0" dependencies = [ - "alloy", + "alloy-primitives", "anyhow", - "hex-literal", "maplit", "serde_json", ] [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.61", + "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.17", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -6937,11 +8642,42 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "tikv-jemalloc-ctl" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "661f1f6a57b3a36dc9174a2c10f19513b4866816e13425d3e418b11cc37bc24c" +dependencies = [ + "libc", + "paste", + "tikv-jemalloc-sys", +] + +[[package]] +name = "tikv-jemalloc-sys" +version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0359b4327f954e0567e69fb191cf1436617748813819c94b8cd4a431422d053a" +dependencies = [ + "libc", + "tikv-jemalloc-sys", +] + [[package]] name = "time" -version = "0.3.37" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", @@ -6949,41 +8685,42 @@ dependencies = [ "num-conv", "num_threads", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", ] [[package]] -name = "tiny-keccak" -version = "2.0.2" +name = "tinystr" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ - "crunchy", + "displaydoc", + "zerovec", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -6994,31 +8731,45 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "token-info" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "anyhow", + "async-trait", + "contracts", + "ethrpc", + "futures", + "maplit", + "mockall", + "model", + "tokio", + "tracing", +] + [[package]] name = "tokio" -version = "1.47.1" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-io-timeout" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +checksum = "0bd86198d9ee903fedd2f9a2e72014287c0d9167e4ae43b5853007205dda1b76" dependencies = [ "pin-project-lite", "tokio", @@ -7026,33 +8777,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", + "syn 2.0.114", ] [[package]] @@ -7061,15 +8792,15 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.34", + "rustls", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -7079,25 +8810,25 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", - "rustls 0.23.34", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tungstenite", "webpki-roots 0.26.11", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -7106,51 +8837,98 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-websockets" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591660438b3038dd04d16c938271c79e7e06260ad2ea2885a4861bfb238605d" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-sink", + "http 1.4.0", + "httparse", + "rand 0.8.5", + "ring", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tokio-util", + "webpki-roots 0.26.11", +] + [[package]] name = "toml" -version = "0.8.14" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit 0.22.14", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] -name = "toml_edit" -version = "0.21.1" +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ - "indexmap 2.10.0", - "toml_datetime", - "winnow 0.5.40", + "serde_core", ] [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.10.0", + "indexmap 2.13.0", "serde", "serde_spanned", - "toml_datetime", - "winnow 0.6.13", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow", ] +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tonic" version = "0.11.0" @@ -7159,13 +8937,13 @@ checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.7", "bytes", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.32", "hyper-timeout 0.4.1", "percent-encoding", "pin-project", @@ -7180,30 +8958,41 @@ dependencies = [ [[package]] name = "tonic" -version = "0.13.1" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" +checksum = "7f32a6f80051a4111560201420c7885d0082ba9efe2ab61875c587bb6b18b9a0" dependencies = [ "async-trait", "base64 0.22.1", "bytes", - "http 1.1.0", - "http-body 1.0.0", + "http 1.4.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.8.1", "hyper-timeout 0.5.2", "hyper-util", "percent-encoding", "pin-project", - "prost 0.13.5", + "sync_wrapper 1.0.2", "tokio", "tokio-stream", - "tower 0.5.2", + "tower 0.5.3", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tonic-prost" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f86539c0089bfd09b1f8c0ab0239d80392af74c21bc9e0f15e1b4aca4c1647f" +dependencies = [ + "bytes", + "prost 0.14.3", + "tonic 0.14.4", +] + [[package]] name = "tower" version = "0.4.13" @@ -7226,13 +9015,13 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap 2.10.0", + "indexmap 2.13.0", "pin-project-lite", "slab", "sync_wrapper 1.0.2", @@ -7245,18 +9034,23 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.4" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.9.1", + "async-compression", + "bitflags 2.10.0", "bytes", "futures-core", "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "http-range-header", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "iri-string", "pin-project-lite", + "tokio", + "tokio-util", + "tower 0.5.3", "tower-layer", "tower-service", "tracing", @@ -7276,9 +9070,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -7288,20 +9082,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -7320,14 +9114,12 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.31.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c" +checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" dependencies = [ "js-sys", - "once_cell", "opentelemetry", - "opentelemetry_sdk", "smallvec", "tracing", "tracing-core", @@ -7348,14 +9140,14 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex", + "regex-automata", "serde", "serde_json", "sharded-slab", @@ -7374,30 +9166,40 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tryhard" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fe58ebd5edd976e0fe0f8a14d2a04b7c81ef153ea9a54eebc42e67c2c23b4e5" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http 1.1.0", + "http 1.4.0", "httparse", "log", - "rand 0.9.1", - "rustls 0.23.34", + "rand 0.9.4", + "rustls", "rustls-pki-types", "sha1", - "thiserror 2.0.12", + "thiserror 2.0.17", "utf-8", ] [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -7423,59 +9225,44 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "unicode_categories" -version = "0.1.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -7485,14 +9272,15 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -7507,26 +9295,34 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -7536,9 +9332,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "8.3.1" +version = "8.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525" +checksum = "2990d9ea5967266ea0ccf413a4aa5c42a93dbcfda9cb49a97de6931726b12566" dependencies = [ "anyhow", "cfg-if", @@ -7548,9 +9344,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vsimd" @@ -7567,6 +9363,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -7577,44 +9383,27 @@ dependencies = [ ] [[package]] -name = "warp" -version = "0.3.7" -source = "git+https://github.com/cowprotocol/warp.git?rev=586244e#586244eabb564b9f9573436ee0e23edfc73f4861" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "headers", - "http 0.2.12", - "hyper 0.14.29", - "log", - "mime", - "mime_guess", - "percent-encoding", - "pin-project", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-util", - "tower-service", - "tracing", -] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen 0.46.0", +] [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen 0.51.0", ] [[package]] @@ -7625,75 +9414,115 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", "once_cell", - "proc-macro2", - "quote", - "syn 2.0.104", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "wasm-bindgen-backend", - "wasm-bindgen-shared", + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver 1.0.27", ] -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - [[package]] name = "wasmtimer" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8d49b5d6c64e8558d9b1b065014426f35c18de636895d24893dbbd329743446" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" dependencies = [ "futures", "js-sys", @@ -7705,9 +9534,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -7724,34 +9553,12 @@ dependencies = [ ] [[package]] -name = "web3" -version = "0.19.0" +name = "webpki-root-certs" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5388522c899d1e1c96a4c307e3797e0f697ba7c77dd8e0e625ecba9dd0342937" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ - "arrayvec", - "base64 0.21.7", - "bytes", - "derive_more 0.99.17", - "ethabi", - "ethereum-types", - "futures", - "futures-timer", - "headers", - "hex", - "idna 0.4.0", - "jsonrpc-core", - "log", - "once_cell", - "parking_lot", - "pin-project", - "reqwest 0.11.27", - "rlp", - "secp256k1 0.27.0", - "serde", - "serde_json", - "tiny-keccak", - "url", + "rustls-pki-types", ] [[package]] @@ -7760,138 +9567,114 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.3", + "webpki-roots 1.0.6", ] [[package]] name = "webpki-roots" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall 0.4.1", + "libredox", "wasite", ] [[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.52.0" +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-targets 0.52.6", + "windows-sys 0.61.2", ] [[package]] name = "windows-core" -version = "0.58.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", + "windows-link", "windows-result", "windows-strings", - "windows-targets 0.52.6", ] [[package]] name = "windows-implement" -version = "0.58.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "windows-interface" -version = "0.58.0" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" -version = "0.2.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ + "windows-link", "windows-result", "windows-strings", - "windows-targets 0.52.6", ] [[package]] name = "windows-result" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-result", - "windows-targets 0.52.6", + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", ] [[package]] @@ -7914,11 +9697,35 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -7945,13 +9752,36 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -7964,6 +9794,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -7976,6 +9818,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -7988,12 +9842,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -8006,6 +9878,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -8018,6 +9902,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -8030,6 +9926,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -8043,51 +9951,132 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winnow" -version = "0.5.40" +name = "windows_x86_64_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winner-selection" +version = "0.1.0" dependencies = [ - "memchr", + "alloy-primitives", + "anyhow", + "itertools 0.14.0", + "number", + "thiserror 1.0.69", + "tracing", ] [[package]] name = "winnow" -version = "0.6.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] -name = "winnow" -version = "0.7.11" +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "memchr", + "wit-bindgen-rust-macro", ] [[package]] -name = "winreg" -version = "0.50.0" +name = "wit-bindgen-core" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "anyhow", + "heck", + "wit-parser", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.114", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.114", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ - "bitflags 2.9.1", + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver 1.0.27", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", ] +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + [[package]] name = "ws_stream_wasm" version = "0.7.5" @@ -8099,9 +10088,9 @@ dependencies = [ "js-sys", "log", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "send_wrapper", - "thiserror 2.0.12", + "thiserror 2.0.17", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -8122,42 +10111,125 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", + "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] + +[[package]] +name = "zmij" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" diff --git a/Cargo.toml b/Cargo.toml index 9da5d9bfaf..c69aed760f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,104 +1,153 @@ [workspace] resolver = "3" members = ["crates/*"] +exclude = ["contracts/"] [workspace.dependencies] -alloy = { version = "1.1.0", default-features = false } +account-balances = { path = "crates/account-balances" } +alloy = { version = "1.8.3", default-features = false } +alloy-consensus = { version = "1.8.3", default-features = false } +alloy-contract = { version = "1.8.3", default-features = false } +alloy-dyn-abi = { version = "1.5.7", default-features = false } +alloy-eips = { version = "1.8.3", default-features = false } +alloy-json-abi = { version = "1.5.7", default-features = false } +alloy-json-rpc = { version = "1.8.3", default-features = false } +alloy-network = { version = "1.8.3", default-features = false } +alloy-primitives = { version = "1.5.7", default-features = false } +alloy-provider = { version = "1.8.3", default-features = false } +alloy-rpc-client = { version = "1.8.3", default-features = false } +alloy-rpc-types = { version = "1.8.3", default-features = false } +alloy-rpc-types-eth = { version = "1.8.3", default-features = false } +alloy-rpc-types-trace = { version = "1.8.3", default-features = false } +alloy-signer = { version = "1.8.3", default-features = false } +alloy-signer-local = { version = "1.8.3", default-features = false } +alloy-sol-types = { version = "1.5.7" } +alloy-transport = { version = "1.8.3", default-features = false } +alloy-transport-ws = { version = "1.8.3", default-features = false } anyhow = "1.0.100" +app-data = { path = "crates/app-data" } +arc-swap = "1.7.1" +async-nats = "0.48.0" +async-stream = "0.3.5" async-trait = "0.1.80" -axum = "0.6" -bigdecimal = "0.3" +autopilot = { path = "crates/autopilot" } +aws-config = "1.5.1" +aws-sdk-s3 = { version = "1.34.0", default-features = false } +axum = "0.8" +backtrace = { version = "0.3.76", default-features = false } +bad-tokens = { path = "crates/bad-tokens" } +balance-overrides = { path = "crates/balance-overrides" } +base64 = "0.22.1" +bigdecimal = "0.4" +brotli = "8" +bytes = "1.11.1" +bytes-hex = { path = "crates/bytes-hex" } cached = { version = "0.49.3", default-features = false } +chain = { path = "crates/chain" } chrono = { version = "0.4.38", default-features = false } clap = { version = "4.5.6", features = ["derive", "env"] } +configs = { path = "crates/configs/" } +console-subscriber = "0.3.0" +const_format = "0.2.32" +const-hex = "1.17.0" +contracts = { path = "contracts/generated/contracts-facade" } +cow-amm = { path = "crates/cow-amm" } dashmap = "6.1.0" -derivative = "2.2.0" +database = { path = "crates/database" } derive_more = { version = "1.0.0", features = ["full"] } -ethcontract = { git = "https://github.com/cowprotocol/ethcontract-rs", rev = "8e112a88988040cde6110379ee6d1be768a13244", default-features = false, features = ["aws-kms"] } -mimalloc = "0.1.43" -ethcontract-generate = { git = "https://github.com/cowprotocol/ethcontract-rs", rev = "8e112a88988040cde6110379ee6d1be768a13244", default-features = false } -ethcontract-mock = { git = "https://github.com/cowprotocol/ethcontract-rs", rev = "8e112a88988040cde6110379ee6d1be768a13244", default-features = false } -ethereum-types = "0.14.1" +driver = { path = "crates/driver" } +eth-domain-types = { path = "crates/eth-domain-types" } +ethrpc = { path = "crates/ethrpc" } +event-indexing = { path = "crates/event-indexing" } flate2 = "1.0.30" futures = "0.3.30" -gas-estimation = { git = "https://github.com/cowprotocol/gas-estimation", tag = "v0.7.3", features = ["web3_", "tokio_"] } -const-hex = "1.17.0" +gas-price-estimation = { path = "crates/gas-price-estimation" } +hex = "0.4.3" hex-literal = "0.4.1" +hmac = "0.12.1" +http-body = "1" +http-body-util = "0.1" +http-client = { path = "crates/http-client" } humantime = "2.1.0" humantime-serde = "1.1.1" -hyper = "0.14.29" indexmap = "2.2.6" itertools = "0.14" +jemalloc_pprof = { version = "0.8", features = ["symbolize"] } +jsonrpc-core = "18.0.0" +liquidity-sources = { path = "crates/liquidity-sources" } maplit = "1.0.2" +mimalloc = "0.1.43" mockall = "0.12.1" -num = "0.4.3" -primitive-types = "0.12" -prometheus = "0.13.4" -prometheus-metric-storage = "0.5.0" -rand = "0.8.5" -regex = "1.10.4" -reqwest = "0.11.27" -secp256k1 = "0.27.0" -serde = { version = "1.0.203", features = ["derive"] } -serde_json = "1.0.117" -serde_with = "3.8.1" -sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio", "tls-native-tls", "bigdecimal", "chrono", "postgres", "macros"] } -strum = { version = "0.27.2", features = ["derive"] } -tempfile = "3.10.1" -thiserror = "1.0.61" -toml = "0.8.14" -tokio = { version = "1.38.0", features = ["tracing"] } -tokio-stream = { version = "0.1.15", features = ["sync"] } -tracing = "0.1.41" -tracing-subscriber = { version = "0.3.19", features = ["json"] } -url = "2.5.0" -warp = { git = 'https://github.com/cowprotocol/warp.git', rev = "586244e", default-features = false } -web3 = { version = "0.19.0", default-features = false } -app-data = { path = "crates/app-data" } -arc-swap = "1.7.1" -async-stream = "0.3.5" -atty = "0.2" -autopilot = { path = "crates/autopilot" } -aws-config = "1.5.1" -aws-sdk-s3 = { version = "1.34.0", default-features = false } -bytes-hex = { path = "crates/bytes-hex" } -chain = { path = "crates/chain" } -console-subscriber = "0.3.0" -const_format = "0.2.32" -contracts = { path = "crates/contracts" } -cow-amm = { path = "crates/cow-amm" } -database = { path = "crates/database" } -driver = { path = "crates/driver" } -ethrpc = { path = "crates/ethrpc" } model = { path = "crates/model" } moka = "0.12.10" multibase = "0.9" +num = "0.4.3" number = { path = "crates/number" } observe = { path = "crates/observe" } +opentelemetry = { version = "0.31", features = ["tracing"] } +opentelemetry-http = { version = "0.31", default-features = false } # disable internal-logging +opentelemetry-otlp = "0.31" +opentelemetry_sdk = "0.31" order-validation = { path = "crates/order-validation" } -opentelemetry = { version = "0.30", features = ["tracing"] } -opentelemetry-otlp = "0.30" -opentelemetry_sdk = "0.30" orderbook = { path = "crates/orderbook" } paste = "1.0" pin-project-lite = "0.2.14" +pool-indexer = { path = "crates/pool-indexer" } +prettyplease = "0.2.37" +price-estimation = { path = "crates/price-estimation" } +proc-macro2 = "1.0.103" +prometheus = "0.14" +prometheus-metric-storage = "0.6" +quote = "1.0.41" +rand = "0.9.4" rate-limit = { path = "crates/rate-limit" } refunder = { path = "crates/refunder" } -rust_decimal = "1.35.0" +regex = "1.10.4" +request-sharing = { path = "crates/request-sharing" } +reqwest = "0.13" +rstest = "0.26" +ruint = { version = "1.17.2", default-features = false } +rust_decimal = { version = "1.35.0", default-features = false } s3 = { path = "crates/s3" } scopeguard = "1.2.0" +serde = { version = "1.0.203", features = ["derive"] } +serde-ext = { path = "crates/serde-ext" } +serde_json = "1.0.117" +serde_with = "3.8.1" +sha2 = "0.10" shared = { path = "crates/shared" } +signature-validator = { path = "crates/signature-validator" } +simulator = { path = "crates/simulator" } +solana-indexer = { path = "crates/solana-indexer" } solver = { path = "crates/solver" } solvers = { path = "crates/solvers" } solvers-dto = { path = "crates/solvers-dto" } +byos = { path = "crates/byos" } +sqlx = { + version = "0.8", + default-features = false, + features = ["bigdecimal", "chrono", "derive", "macros", "postgres", "runtime-tokio", "tls-native-tls"] +} +strum = { version = "0.27.2", features = ["derive"] } +syn = "2.0.108" +tempfile = "3.10.1" testlib = { path = "crates/testlib" } -time = "0.3.37" -tiny-keccak = "2.0.2" -tower = "0.4" -tower-http = "0.4" -tracing-opentelemetry = "0.31" +thiserror = "1.0.61" +tikv-jemallocator = { version = "0.6", features = ["profiling", "unprefixed_malloc_on_supported_platforms"] } +time = "0.3.47" +token-info = { path = "crates/token-info" } +tokio = { version = "1.38.0", features = ["tracing"] } +tokio-stream = { version = "0.1.15", features = ["sync"] } +toml = "0.8.14" +tower = "0.5" +tower-http = "0.6" +tracing = "0.1.41" +tracing-opentelemetry = "0.32.1" tracing-serde = "0.2" +tracing-subscriber = { version = "0.3.22", features = ["json"] } +url = "2.5.0" vergen = "8" +winner-selection = { path = "crates/winner-selection" } [workspace.lints] clippy.cast_possible_wrap = "deny" diff --git a/Dockerfile b/Dockerfile index e5a8a0d470..b2104f3e31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,22 +5,28 @@ CMD ["migrate"] FROM docker.io/rust:1-slim-bookworm AS cargo-build WORKDIR /src/ +# Accept build arguments for enabling features +ARG CARGO_BUILD_FEATURES="" +ARG RUSTFLAGS="" + # Install dependencies RUN --mount=type=cache,target=/var/cache/apt,sharing=locked apt-get update && \ - apt-get install -y git libssl-dev pkg-config + apt-get install -y git libssl-dev pkg-config build-essential # Install Rust toolchain RUN rustup install stable && rustup default stable # Copy and Build Code COPY . . RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=/src/target \ - CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release && \ - cp target/release/alerter / && \ + CARGO_PROFILE_RELEASE_DEBUG=1 RUSTFLAGS="${RUSTFLAGS}" cargo build --release \ + -p autopilot -p driver -p orderbook -p refunder -p solvers -p pool-indexer \ + ${CARGO_BUILD_FEATURES} && \ cp target/release/autopilot / && \ cp target/release/driver / && \ cp target/release/orderbook / && \ cp target/release/refunder / && \ - cp target/release/solvers / + cp target/release/solvers / && \ + cp target/release/pool-indexer / # Create an intermediate image to extract the binaries FROM docker.io/debian:bookworm-slim AS intermediate @@ -28,10 +34,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked apt-get update && \ apt-get install -y ca-certificates tini gettext-base && \ apt-get clean -FROM intermediate AS alerter -COPY --from=cargo-build /alerter /usr/local/bin/alerter -ENTRYPOINT [ "alerter" ] - FROM intermediate AS autopilot COPY --from=cargo-build /autopilot /usr/local/bin/autopilot ENTRYPOINT [ "autopilot" ] @@ -52,24 +54,19 @@ FROM intermediate AS solvers COPY --from=cargo-build /solvers /usr/local/bin/solvers ENTRYPOINT [ "solvers" ] +FROM intermediate AS pool-indexer +COPY --from=cargo-build /pool-indexer /usr/local/bin/pool-indexer +ENTRYPOINT [ "pool-indexer" ] + # Extract Binary FROM intermediate -RUN apt-get update && \ - apt-get install -y build-essential cmake git zlib1g-dev libelf-dev libdw-dev libboost-dev libboost-iostreams-dev libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libunwind-dev libzstd-dev git -RUN git clone https://invent.kde.org/sdk/heaptrack.git /heaptrack && \ - mkdir /heaptrack/build && cd /heaptrack/build && \ - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF .. && \ - make -j$(nproc) && \ - make install && \ - cd / && rm -rf /heaptrack -COPY --from=cargo-build /alerter /usr/local/bin/alerter + +RUN apt-get update && apt-get install -y netcat-openbsd COPY --from=cargo-build /autopilot /usr/local/bin/autopilot COPY --from=cargo-build /driver /usr/local/bin/driver COPY --from=cargo-build /orderbook /usr/local/bin/orderbook COPY --from=cargo-build /refunder /usr/local/bin/refunder COPY --from=cargo-build /solvers /usr/local/bin/solvers -COPY ./entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh +COPY --from=cargo-build /pool-indexer /usr/local/bin/pool-indexer -ENTRYPOINT ["/usr/bin/tini", "--"] -CMD ["/entrypoint.sh"] +ENTRYPOINT ["/usr/bin/tini", "-s", "--"] diff --git a/Justfile b/Justfile index c5a33ac10c..a9156bda66 100644 --- a/Justfile +++ b/Justfile @@ -1,6 +1,25 @@ help: @just --list +# Bootstrap the crate, will vendor contracts, generate the bindings crates and format everything +setup: + cd contracts && \ + cargo r -r -- vendor && \ + cargo r -r -- generate + just _format_generated_contracts + +# Generate contract bindings +generate-contracts: + cd contracts && \ + cargo r -r -- generate + just _format_generated_contracts + +_format_generated_contracts: + cd contracts && cargo +nightly fmt --all && \ + cd generated && cargo +nightly fmt --all && \ + cd ../.. && \ + tombi format + # Run unit tests test-unit: cargo nextest run @@ -22,8 +41,8 @@ test-e2e-local: (test-e2e "local_node") test-e2e-forked: (test-e2e "forked_node") # Run End-to-end tests with custom filters -test-e2e *filters: - cargo nextest run -p e2e {{filters}} --test-threads 1 --failure-output final --run-ignored ignored-only +test-e2e filters="" *extra="": + cargo nextest run -p e2e '{{filters}}' --test-threads 1 --failure-output final --run-ignored ignored-only {{extra}} test-driver: RUST_MIN_STACK=3145728 cargo nextest run -p driver --test-threads 1 --run-ignored ignored-only @@ -35,6 +54,12 @@ clippy: # Format the repository fmt *extra: cargo +nightly fmt --all -- {{extra}} + cd contracts && cargo +nightly fmt --all -- {{extra}} + +# Format .toml files in the repository +fmt-toml *extra: + tombi format {{extra}} + # Start database for E2E tests start-db: diff --git a/LICENSE-APACHE b/LICENSE-APACHE old mode 100644 new mode 100755 diff --git a/LICENSE-GPL b/LICENSE-GPL old mode 100644 new mode 100755 diff --git a/LICENSE-MIT b/LICENSE-MIT old mode 100644 new mode 100755 diff --git a/README.md b/README.md index a426961198..bcc18a0841 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ This repository contains backend code for [Cow Protocol Services](https://docs.cow.fi/) written in Rust. +New to the repo? Start with the architecture + flow diagrams in [`docs/ONBOARDING.md`](./docs/ONBOARDING.md), then run the stack locally via the [`playground`](./playground/README.md). + ## Order Book The `orderbook` crate provides the http api through which users (usually through a frontend web application) interact with the order book. @@ -31,8 +33,7 @@ The `autopilot` connects to the same PostgreSQL database as the `orderbook` and There are additional crates that live in the cargo workspace. -- `alerter` provides a custom alerter binary that looks at the current orderbook and counts metrics for orders that should be solved but aren't -- `contracts` provides _[ethcontract-rs](https://github.com/gnosis/ethcontract-rs)_ based smart contract bindings +- `contracts` provides Alloy-based smart contract bindings - `database` provides the shared database and storage layer logic shared between the `autopilot` and `orderbook` - `driver` an in-development binary that intends to replace the `solver`; it has a slightly different design that allows co-location with external solvers - `e2e` end-to-end tests @@ -111,6 +112,48 @@ cargo install --locked tokio-console tokio-console ``` +## Heap Profiling + +All binaries use jemalloc as the default memory allocator with built-in heap profiling support. Profiling is enabled at runtime via the `MALLOC_CONF` environment variable, allowing you to analyze memory usage in production environments without recompiling or restarting services. + +**Note:** You can optionally use mimalloc instead of jemalloc by building with `--features mimalloc-allocator`, but this disables heap profiling capability. + +### Enabling Heap Profiling + +To enable heap profiling, run services with the `MALLOC_CONF` environment variable set: +```bash +MALLOC_CONF="prof:true,prof_active:true,lg_prof_sample:22" +``` + +When profiling is enabled, each binary opens a UNIX socket at `/tmp/heap_dump_.sock`. + +### Generating Heap Dumps + +Connect to the socket and send the "dump" command: + +```bash +# From Kubernetes +kubectl exec -n -- sh -c "echo dump | nc -U /tmp/heap_dump_orderbook.sock" > heap.pprof + +# From Docker +docker exec sh -c "echo dump | nc -U /tmp/heap_dump_orderbook.sock" > heap.pprof +``` + +### Analyzing Heap Dumps + +The dumps are in pprof format and can be analyzed using Google's pprof tool: + +```bash +# Install pprof +go install github.com/google/pprof@latest + +# Interactive web UI +pprof -http=:8080 heap.pprof + +# Command-line analysis +pprof -top heap.pprof +``` + ## Changing Log Filters It's possible to change the tracing log filter while the process is running. This can be useful to debug an error that requires more verbose logs but which might no longer appear after restarting the system. @@ -120,3 +163,20 @@ You can also reset the log filter to the filter the program was initially starte See [here](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives) for documentation on the supported log filter format. +## Formatting + +Rust code is formatted with `rustfmt` (nightly) and TOML files are formatted with [Tombi](https://tombi-toml.github.io/tombi/). + +```bash +# Format Rust code +just fmt + +# Format TOML files +just fmt-toml + +# Check formatting without modifying files +just fmt --check +just fmt-toml --check +``` + +Editor extensions are available for [VS Code](https://marketplace.visualstudio.com/items?itemName=tombi-toml.tombi), [Zed](https://tombi-toml.github.io/tombi/docs/editors/zed-extension), and [JetBrains](https://plugins.jetbrains.com/plugin/28017-tombi). diff --git a/REVIEW.md b/REVIEW.md new file mode 100644 index 0000000000..a4105d181e --- /dev/null +++ b/REVIEW.md @@ -0,0 +1,78 @@ +# Code Review Guidelines + +These instructions guide automated code reviews. Focus on real bugs and +correctness issues. Do not pad reviews with praise or filler. + +## Priorities + +Review in priority order. + +1. **Correctness** — logic errors, wrong return values, off-by-one, missing + error propagation, incorrect arithmetic (especially with U256/BigDecimal) +2. **Safety** — panics in production paths (`unwrap` on fallible operations), + unchecked arithmetic overflow, missing bounds checks +3. **Security** — SQL injection, command injection, secrets in logs, + unvalidated external input at system boundaries +4. **Concurrency** — data races, deadlocks, incorrect `Send`/`Sync` bounds, + holding locks across await points +5. **Backwards compatibility** — API breaking changes, database migration + issues, settlement contract interaction changes + +## Always check + +- Token amount conversions between decimal and wei are correct (scaling + direction, precision loss) +- Error types from external APIs (solvers, DEX aggregators) are mapped to the + correct internal variant — wrong mapping produces noisy logs or silently + drops valid quotes +- New `async` code does not block the Tokio runtime (no blocking I/O, no + `std::thread::sleep`, no heavy computation without `spawn_blocking`) +- Database queries that touch large tables have been checked against existing + indexes. If a PR adds or modifies a query on a large table, request + `EXPLAIN ANALYZE` output (before and after) if not already included in the + PR description +- Settlement-related changes are backward-compatible with in-flight auctions +- Changes to auction or solver logic preserve existing solver competition + fairness + +## Do NOT flag + +- Style or formatting issues — `cargo fmt` and `clippy` handle these +- Missing documentation or comments on clear code +- Suggestions to add more tests unless a specific untested edge case is + identified +- Pre-existing issues not introduced by the PR +- Theoretical concerns that require specific unlikely conditions +- `unwrap()` on values that are guaranteed by construction or prior checks +- Differences in naming conventions that are consistent within the changed + file + +## Severity + +Use the code-review plugin's standard categories: + +- **Normal** — a bug or issue that should be fixed before merging +- **Nit** — a minor improvement, not blocking + +Do not flag pre-existing issues not introduced by the PR. If unsure whether +something is a real issue, ask a clarifying question rather than asserting a +bug. + +## Skip these files + +- `Cargo.lock` +- Generated contract bindings under `crates/contracts/` +- Database migration files (review schema changes only, not the generated SQL) +- Test fixture JSON files + +## Format + +For each finding, include: +- File path and line number +- What is wrong (one sentence) +- Why it matters (one sentence) +- For small, self-contained fixes, include a committable GitHub suggestion + block. For larger fixes, describe the recommended approach in prose. + +Do not summarize the PR. Do not list what looks correct. Only report findings. +If you do not find issues, simply comment: LGTM diff --git a/configs/local/baseline.toml b/configs/local/baseline.toml deleted file mode 100644 index c62d9d91eb..0000000000 --- a/configs/local/baseline.toml +++ /dev/null @@ -1,14 +0,0 @@ -chain-id = "1" # Ethereum mainnet -base-tokens = [ - "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # WETH - "0x6B175474E89094C44Da98b954EedeAC495271d0F", # DAI - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", # USDC - "0xdAC17F958D2ee523a2206206994597C13D831ec7", # USDT - "0xc00e94Cb662C3520282E6f5717214004A7f26888", # COMP - "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", # MKR - "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", # WBTC - "0x6810e776880C02933D47DB1b9fc05908e5386b96", # GNO -] -max-hops = 2 -max-partial-attempts = 5 -native-token-price-estimation-amount = "100000000000000000" # 0.1 ETH diff --git a/configs/local/driver.toml b/configs/local/driver.toml deleted file mode 100644 index 89c9cd8621..0000000000 --- a/configs/local/driver.toml +++ /dev/null @@ -1,31 +0,0 @@ -app-data-fetching-enabled = true -orderbook-url = "http://orderbook" -tx-gas-limit = "45000000" - -[[solver]] -name = "baseline" # Arbitrary name given to this solver, must be unique -endpoint = "http://baseline" -absolute-slippage = "40000000000000000" # Denominated in wei, optional -relative-slippage = "0.1" # Percentage in the [0, 1] range -account = "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" # Known test private key - -[submission] -gas-price-cap = "1000000000000" - -[[submission.mempool]] -mempool = "public" - -[liquidity] -base-tokens = [ - "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # WETH - "0x6B175474E89094C44Da98b954EedeAC495271d0F", # DAI - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", # USDC - "0xdAC17F958D2ee523a2206206994597C13D831ec7", # USDT - "0xc00e94Cb662C3520282E6f5717214004A7f26888", # COMP - "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", # MKR - "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", # WBTC - "0x6810e776880C02933D47DB1b9fc05908e5386b96", # GNO -] - -[[liquidity.uniswap-v2]] # Uniswap V2 configuration -preset = "uniswap-v2" diff --git a/contracts/.gitignore b/contracts/.gitignore new file mode 100644 index 0000000000..c0388e3cc4 --- /dev/null +++ b/contracts/.gitignore @@ -0,0 +1,4 @@ +/target +/out +/cache +.DS_Store diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock new file mode 100644 index 0000000000..26c94d60d8 --- /dev/null +++ b/contracts/Cargo.lock @@ -0,0 +1,2302 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "alloy-json-abi" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dbe713da0c737d9e5e387b0ba790eb98b14dd207fe53eef50e19a5a8ec3dac" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-primitives" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3b431b4e72cd8bd0ec7a50b4be18e73dab74de0dba180eef171055e5d5926e" +dependencies = [ + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hashbrown", + "indexmap", + "itoa", + "paste", + "rand 0.9.2", + "ruint", + "rustc-hash", + "serde", + "sha3", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "sha3", + "syn", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "serde_json", + "syn", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.2.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "const-hex" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531185e432bb31db1ecda541e9e7ab21468d4d844ad7505e0546a49b4945d49b" +dependencies = [ + "cfg-if", + "cpufeatures", + "proptest", + "serde_core", +] + +[[package]] +name = "contracts-generate" +version = "0.1.0" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "rayon", + "reqwest", + "serde_json", + "syn", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash", + "serde", + "serde_core", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +dependencies = [ + "equivalent", + "hashbrown", + "serde", + "serde_core", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.184" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bitflags", + "num-traits", + "rand 0.9.2", + "rand_chacha", + "rand_xorshift", + "unarray", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", + "serde", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "reqwest" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ruint" +version = "1.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" +dependencies = [ + "proptest", + "rand 0.8.5", + "rand 0.9.2", + "ruint-macro", + "serde_core", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml new file mode 100644 index 0000000000..1276ea0e99 --- /dev/null +++ b/contracts/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "contracts-generate" +version = "0.1.0" +edition = "2024" +publish = false + +[workspace] + +[dependencies] +alloy-sol-macro-expander = "1.4.1" +alloy-sol-macro-input = { version = "1.4.1", features = ["json"] } +anyhow = "1.0.100" +prettyplease = "0.2.37" +proc-macro2 = "1.0.103" +quote = "1.0.41" +rayon = "1" +reqwest = { version = "0.13", features = ["blocking", "json"] } +serde_json = "1.0.117" +syn = "2.0.108" diff --git a/crates/alerter/LICENSE-APACHE b/contracts/LICENSE-APACHE similarity index 100% rename from crates/alerter/LICENSE-APACHE rename to contracts/LICENSE-APACHE diff --git a/crates/alerter/LICENSE-MIT b/contracts/LICENSE-MIT similarity index 100% rename from crates/alerter/LICENSE-MIT rename to contracts/LICENSE-MIT diff --git a/contracts/README.md b/contracts/README.md new file mode 100644 index 0000000000..e40fd74958 --- /dev/null +++ b/contracts/README.md @@ -0,0 +1,60 @@ +# cow-contracts + +Alloy-based Rust contract bindings for the CoW Protocol ecosystem. + +Each smart contract gets its own crate for parallel compilation. The `contracts` facade crate re-exports everything under a single API. + +## Usage + +Add to your `Cargo.toml`: + +```toml +contracts = { git = "https://github.com/cowprotocol/cow-contracts" } +``` + +Then use: + +```rust +use contracts::alloy::{GPv2Settlement, ERC20, WETH9}; +``` + +## Adding a new contract + +1. Add the ABI artifact JSON to `artifacts/` (manually or via `cargo run -p contracts-generate -- vendor`) +2. Add the contract definition to `crates/contracts-generate/src/main.rs` +3. Run `cargo run -p contracts-generate` +4. Run `cargo check -p contracts` to verify +5. Commit and open a PR + +## Commands + +From the repository root, use `just`: + +```bash +just setup # Vendor artifacts, generate bindings, and format everything +just generate-contracts # Generate bindings from artifacts only +``` + +Or use the `contracts-generate` binary directly: + +```bash +cargo run -p contracts-generate # Generate bindings from artifacts +cargo run -p contracts-generate -- vendor # Download/update ABI artifacts +cargo run -p contracts-generate -- all # Vendor artifacts then generate bindings +``` + +The `generate` command regenerates all per-contract crates in `generated/`, updates the facade module at `crates/contracts/src/alloy/mod.rs`, and updates the dependency section in `crates/contracts/Cargo.toml`. + +## Compiling Solidity contracts + +Custom support/test contracts live in `solidity/`. To recompile: + +```bash +cd solidity && make artifacts +``` + +Requires Docker with the `ethereum/solc:0.8.30` image. + +## License + +Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option. diff --git a/contracts/artifacts/AnyoneAuthenticator.json b/contracts/artifacts/AnyoneAuthenticator.json new file mode 100644 index 0000000000..340ba8b1ae --- /dev/null +++ b/contracts/artifacts/AnyoneAuthenticator.json @@ -0,0 +1,31 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isSolver", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b50609480601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c806302cc250d14602a575b5f5ffd5b603b6035366004604f565b50600190565b604051901515815260200160405180910390f35b5f60208284031215605e575f5ffd5b813573ffffffffffffffffffffffffffffffffffffffff811681146080575f5ffd5b939250505056fea164736f6c634300081e000a", + "deployedBytecode": "0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c806302cc250d14602a575b5f5ffd5b603b6035366004604f565b50600190565b604051901515815260200160405180910390f35b5f60208284031215605e575f5ffd5b813573ffffffffffffffffffffffffffffffffffffffff811681146080575f5ffd5b939250505056fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/crates/contracts/artifacts/BalancerQueries.json b/contracts/artifacts/BalancerQueries.json similarity index 99% rename from crates/contracts/artifacts/BalancerQueries.json rename to contracts/artifacts/BalancerQueries.json index abbc175e1a..d3caf7f0c3 100644 --- a/crates/contracts/artifacts/BalancerQueries.json +++ b/contracts/artifacts/BalancerQueries.json @@ -11,6 +11,19 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [], + "name": "vault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -93,7 +106,9 @@ ], "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [ { @@ -293,19 +308,6 @@ ], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [], - "name": "vault", - "outputs": [ - { - "internalType": "contract IVault", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" } ] } diff --git a/crates/contracts/artifacts/BalancerV2Authorizer.json b/contracts/artifacts/BalancerV2Authorizer.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2Authorizer.json rename to contracts/artifacts/BalancerV2Authorizer.json index d5d65e10ab..57d5ad3163 100644 --- a/crates/contracts/artifacts/BalancerV2Authorizer.json +++ b/contracts/artifacts/BalancerV2Authorizer.json @@ -86,6 +86,90 @@ "name": "RoleRevoked", "type": "event" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "roles", + "type": "bytes32[]" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRoles", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50604051610e1d380380610e1d8339818101604052602081101561003357600080fd5b5051610040600082610046565b5061013d565b6100508282610054565b5050565b6000828152602081815260409091206100769183906108946100b7821b17901c565b156100505760405133906001600160a01b0383169084907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d90600090a45050565b60006100c3838361011c565b61011257508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155610116565b5060005b92915050565b6001600160a01b031660009081526001919091016020526040902054151590565b610cd18061014c6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c8063988360a31161008c578063a73cb2ab11610066578063a73cb2ab1461044b578063ca15c87314610572578063d547741f1461058f578063fcd7627e146105c8576100df565b8063988360a3146103475780639be2a88414610402578063a217fddf14610443576100df565b806336568abe116100bd57806336568abe146102755780639010d07c146102ae57806391d14854146102fa576100df565b806318b2cde9146100e4578063248a9ca31461020d5780632f2ff15d1461023c575b600080fd5b61020b600480360360408110156100fa57600080fd5b81019060208101813564010000000081111561011557600080fd5b82018360208201111561012757600080fd5b8035906020019184602083028401116401000000008311171561014957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561019957600080fd5b8201836020820111156101ab57600080fd5b803590602001918460208302840111640100000000831117156101cd57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610683945050505050565b005b61022a6004803603602081101561022357600080fd5b50356106d8565b60408051918252519081900360200190f35b61020b6004803603604081101561025257600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff166106ed565b61020b6004803603604081101561028b57600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16610723565b6102d1600480360360408110156102c457600080fd5b5080359060200135610751565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6103336004803603604081101561031057600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16610772565b604080519115158252519081900360200190f35b61020b6004803603604081101561035d57600080fd5b81019060208101813564010000000081111561037857600080fd5b82018360208201111561038a57600080fd5b803590602001918460208302840111640100000000831117156103ac57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050903573ffffffffffffffffffffffffffffffffffffffff16915061078a9050565b6103336004803603606081101561041857600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff602082013581169160400135166107bb565b61022a6107cf565b61020b6004803603604081101561046157600080fd5b81019060208101813564010000000081111561047c57600080fd5b82018360208201111561048e57600080fd5b803590602001918460208302840111640100000000831117156104b057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561050057600080fd5b82018360208201111561051257600080fd5b8035906020019184602083028401116401000000008311171561053457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107d4945050505050565b61022a6004803603602081101561058857600080fd5b5035610824565b61020b600480360360408110156105a557600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff1661083b565b61020b600480360360408110156105de57600080fd5b8101906020810181356401000000008111156105f957600080fd5b82018360208201111561060b57600080fd5b8035906020019184602083028401116401000000008311171561062d57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050903573ffffffffffffffffffffffffffffffffffffffff1691506108639050565b61068f8251825161091c565b60005b82518110156106d3576106cb8382815181106106aa57fe5b60200260200101518383815181106106be57fe5b602002602001015161083b565b600101610692565b505050565b60009081526020819052604090206002015490565b6000828152602081905260409020600201546107159061070d9033610772565b6101a6610925565b61071f8282610933565b5050565b61074773ffffffffffffffffffffffffffffffffffffffff821633146101a8610925565b61071f8282610999565b600082815260208190526040812061076990836109ff565b90505b92915050565b60008281526020819052604081206107699083610a1b565b60005b82518110156106d3576107b38382815181106107a557fe5b60200260200101518361083b565b60010161078d565b60006107c78484610772565b949350505050565b600081565b6107e08251825161091c565b60005b82518110156106d35761081c8382815181106107fb57fe5b602002602001015183838151811061080f57fe5b60200260200101516106ed565b6001016107e3565b600081815260208190526040812061076c90610a49565b6000828152602081905260409020600201546107479061085b9033610772565b6101a7610925565b60005b82518110156106d35761088c83828151811061087e57fe5b6020026020010151836106ed565b600101610866565b60006108a08383610a1b565b61091457508154600180820184556000848152602080822090930180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558554908252828601909352604090209190915561076c565b50600061076c565b61071f81831460675b8161071f5761071f81610a4d565b600082815260208190526040902061094b9082610894565b1561071f57604051339073ffffffffffffffffffffffffffffffffffffffff83169084907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d90600090a45050565b60008281526020819052604090206109b19082610aba565b1561071f57604051339073ffffffffffffffffffffffffffffffffffffffff83169084907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b90600090a45050565b8154600090610a119083106064610925565b6107698383610c61565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001919091016020526040902054151590565b5490565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120548015610c575783547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8083019190810190600090879083908110610b2257fe5b600091825260209091200154875473ffffffffffffffffffffffffffffffffffffffff90911691508190889085908110610b5857fe5b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918316815260018981019092526040902090840190558654879080610bc657fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff8816825260018981019091526040822091909155945061076c9350505050565b600091505061076c565b6000826000018281548110610c7257fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16939250505056fea2646970667358221220dfe715d2cd44c733089f2c396b8ba6a91ca4ec5b907632f366d4d8a9814a53d364736f6c63430007010033", + "devdoc": { + "details": "Basic Authorizer implementation, based on OpenZeppelin's Access Control. Users are allowed to perform actions if they have the role with the same identifier. In this sense, roles are not being truly used as such, since they each map to a single action identifier. This temporary implementation is expected to be replaced soon after launch by a more sophisticated one, able to manage permissions across multiple contracts and to natively handle timelocks.", + "kind": "dev", + "methods": { + "getRoleAdmin(bytes32)": { + "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." + }, + "getRoleMember(bytes32,uint256)": { + "details": "Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information." + }, + "getRoleMemberCount(bytes32)": { + "details": "Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role." + }, + "grantRole(bytes32,address)": { + "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role." + }, + "grantRoles(bytes32[],address)": { + "details": "Grants multiple roles to a single account." + }, + "grantRolesToMany(bytes32[],address[])": { + "details": "Grants roles to a list of accounts." + }, + "hasRole(bytes32,address)": { + "details": "Returns `true` if `account` has been granted `role`." + }, + "renounceRole(bytes32,address)": { + "details": "Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`." + }, + "revokeRole(bytes32,address)": { + "details": "Revokes `role` from `account`. If `account` had already been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role." + }, + "revokeRoles(bytes32[],address)": { + "details": "Revokes multiple roles from a single account." + }, + "revokeRolesFromMany(bytes32[],address[])": { + "details": "Revokes roles from a list of accounts." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "_disabled": [ { "inputs": [], "name": "DEFAULT_ADMIN_ROLE", @@ -190,42 +274,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32[]", - "name": "roles", - "type": "bytes32[]" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "grantRoles", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -340,51 +388,5 @@ "stateMutability": "nonpayable", "type": "function" } - ], - "bytecode": "0x608060405234801561001057600080fd5b50604051610e1d380380610e1d8339818101604052602081101561003357600080fd5b5051610040600082610046565b5061013d565b6100508282610054565b5050565b6000828152602081815260409091206100769183906108946100b7821b17901c565b156100505760405133906001600160a01b0383169084907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d90600090a45050565b60006100c3838361011c565b61011257508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155610116565b5060005b92915050565b6001600160a01b031660009081526001919091016020526040902054151590565b610cd18061014c6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c8063988360a31161008c578063a73cb2ab11610066578063a73cb2ab1461044b578063ca15c87314610572578063d547741f1461058f578063fcd7627e146105c8576100df565b8063988360a3146103475780639be2a88414610402578063a217fddf14610443576100df565b806336568abe116100bd57806336568abe146102755780639010d07c146102ae57806391d14854146102fa576100df565b806318b2cde9146100e4578063248a9ca31461020d5780632f2ff15d1461023c575b600080fd5b61020b600480360360408110156100fa57600080fd5b81019060208101813564010000000081111561011557600080fd5b82018360208201111561012757600080fd5b8035906020019184602083028401116401000000008311171561014957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561019957600080fd5b8201836020820111156101ab57600080fd5b803590602001918460208302840111640100000000831117156101cd57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610683945050505050565b005b61022a6004803603602081101561022357600080fd5b50356106d8565b60408051918252519081900360200190f35b61020b6004803603604081101561025257600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff166106ed565b61020b6004803603604081101561028b57600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16610723565b6102d1600480360360408110156102c457600080fd5b5080359060200135610751565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6103336004803603604081101561031057600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16610772565b604080519115158252519081900360200190f35b61020b6004803603604081101561035d57600080fd5b81019060208101813564010000000081111561037857600080fd5b82018360208201111561038a57600080fd5b803590602001918460208302840111640100000000831117156103ac57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050903573ffffffffffffffffffffffffffffffffffffffff16915061078a9050565b6103336004803603606081101561041857600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff602082013581169160400135166107bb565b61022a6107cf565b61020b6004803603604081101561046157600080fd5b81019060208101813564010000000081111561047c57600080fd5b82018360208201111561048e57600080fd5b803590602001918460208302840111640100000000831117156104b057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561050057600080fd5b82018360208201111561051257600080fd5b8035906020019184602083028401116401000000008311171561053457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107d4945050505050565b61022a6004803603602081101561058857600080fd5b5035610824565b61020b600480360360408110156105a557600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff1661083b565b61020b600480360360408110156105de57600080fd5b8101906020810181356401000000008111156105f957600080fd5b82018360208201111561060b57600080fd5b8035906020019184602083028401116401000000008311171561062d57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050903573ffffffffffffffffffffffffffffffffffffffff1691506108639050565b61068f8251825161091c565b60005b82518110156106d3576106cb8382815181106106aa57fe5b60200260200101518383815181106106be57fe5b602002602001015161083b565b600101610692565b505050565b60009081526020819052604090206002015490565b6000828152602081905260409020600201546107159061070d9033610772565b6101a6610925565b61071f8282610933565b5050565b61074773ffffffffffffffffffffffffffffffffffffffff821633146101a8610925565b61071f8282610999565b600082815260208190526040812061076990836109ff565b90505b92915050565b60008281526020819052604081206107699083610a1b565b60005b82518110156106d3576107b38382815181106107a557fe5b60200260200101518361083b565b60010161078d565b60006107c78484610772565b949350505050565b600081565b6107e08251825161091c565b60005b82518110156106d35761081c8382815181106107fb57fe5b602002602001015183838151811061080f57fe5b60200260200101516106ed565b6001016107e3565b600081815260208190526040812061076c90610a49565b6000828152602081905260409020600201546107479061085b9033610772565b6101a7610925565b60005b82518110156106d35761088c83828151811061087e57fe5b6020026020010151836106ed565b600101610866565b60006108a08383610a1b565b61091457508154600180820184556000848152602080822090930180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558554908252828601909352604090209190915561076c565b50600061076c565b61071f81831460675b8161071f5761071f81610a4d565b600082815260208190526040902061094b9082610894565b1561071f57604051339073ffffffffffffffffffffffffffffffffffffffff83169084907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d90600090a45050565b60008281526020819052604090206109b19082610aba565b1561071f57604051339073ffffffffffffffffffffffffffffffffffffffff83169084907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b90600090a45050565b8154600090610a119083106064610925565b6107698383610c61565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001919091016020526040902054151590565b5490565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120548015610c575783547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8083019190810190600090879083908110610b2257fe5b600091825260209091200154875473ffffffffffffffffffffffffffffffffffffffff90911691508190889085908110610b5857fe5b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918316815260018981019092526040902090840190558654879080610bc657fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff8816825260018981019091526040822091909155945061076c9350505050565b600091505061076c565b6000826000018281548110610c7257fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16939250505056fea2646970667358221220dfe715d2cd44c733089f2c396b8ba6a91ca4ec5b907632f366d4d8a9814a53d364736f6c63430007010033", - "devdoc": { - "details": "Basic Authorizer implementation, based on OpenZeppelin's Access Control. Users are allowed to perform actions if they have the role with the same identifier. In this sense, roles are not being truly used as such, since they each map to a single action identifier. This temporary implementation is expected to be replaced soon after launch by a more sophisticated one, able to manage permissions across multiple contracts and to natively handle timelocks.", - "kind": "dev", - "methods": { - "getRoleAdmin(bytes32)": { - "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." - }, - "getRoleMember(bytes32,uint256)": { - "details": "Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information." - }, - "getRoleMemberCount(bytes32)": { - "details": "Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role." - }, - "grantRole(bytes32,address)": { - "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role." - }, - "grantRoles(bytes32[],address)": { - "details": "Grants multiple roles to a single account." - }, - "grantRolesToMany(bytes32[],address[])": { - "details": "Grants roles to a list of accounts." - }, - "hasRole(bytes32,address)": { - "details": "Returns `true` if `account` has been granted `role`." - }, - "renounceRole(bytes32,address)": { - "details": "Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`." - }, - "revokeRole(bytes32,address)": { - "details": "Revokes `role` from `account`. If `account` had already been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role." - }, - "revokeRoles(bytes32[],address)": { - "details": "Revokes multiple roles from a single account." - }, - "revokeRolesFromMany(bytes32[],address[])": { - "details": "Revokes roles from a list of accounts." - } - }, - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": {}, - "version": 1 - } + ] } diff --git a/crates/contracts/artifacts/BalancerV2BasePool.json b/contracts/artifacts/BalancerV2BasePool.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2BasePool.json rename to contracts/artifacts/BalancerV2BasePool.json index 304a555430..34ffd8baca 100644 --- a/crates/contracts/artifacts/BalancerV2BasePool.json +++ b/contracts/artifacts/BalancerV2BasePool.json @@ -170,14 +170,31 @@ "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getPausedState", + "outputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" + "internalType": "bool", + "name": "paused", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodEndTime", + "type": "uint256" } ], - "name": "getActionId", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolId", "outputs": [ { "internalType": "bytes32", @@ -190,12 +207,12 @@ }, { "inputs": [], - "name": "getAuthorizer", + "name": "getSwapFeePercentage", "outputs": [ { - "internalType": "contract IAuthorizer", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -203,74 +220,161 @@ }, { "inputs": [], - "name": "getOwner", + "name": "name", "outputs": [ { - "internalType": "address", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getPausedState", + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", "outputs": [ { - "internalType": "bool", - "name": "paused", - "type": "bool" + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "uint256", - "name": "pauseWindowEndTime", + "name": "value", "type": "uint256" }, { "internalType": "uint256", - "name": "bufferPeriodEndTime", + "name": "deadline", "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "getPoolId", + "name": "symbol", "outputs": [ { - "internalType": "bytes32", + "internalType": "string", "name": "", - "type": "bytes32" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getSwapFeePercentage", - "outputs": [ + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, { "internalType": "uint256", - "name": "", + "name": "amount", "type": "uint256" } ], - "stateMutability": "view", + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getVault", + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", "outputs": [ { - "internalType": "contract IVault", + "internalType": "bool", "name": "", - "type": "address" + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" } ], "stateMutability": "view", @@ -278,31 +382,38 @@ }, { "inputs": [], - "name": "name", + "name": "getAuthorizer", "outputs": [ { - "internalType": "string", + "internalType": "contract IAuthorizer", "name": "", - "type": "string" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getOwner", + "outputs": [ { "internalType": "address", - "name": "owner", + "name": "", "type": "address" } ], - "name": "nonces", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", "outputs": [ { - "internalType": "uint256", + "internalType": "contract IVault", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -416,49 +527,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -593,19 +661,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "totalSupply", @@ -618,59 +673,6 @@ ], "stateMutability": "view", "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" } ] } diff --git a/crates/contracts/artifacts/BalancerV2BasePoolFactory.json b/contracts/artifacts/BalancerV2BasePoolFactory.json similarity index 96% rename from crates/contracts/artifacts/BalancerV2BasePoolFactory.json rename to contracts/artifacts/BalancerV2BasePoolFactory.json index b11b9c2e61..cbdd83ddcb 100644 --- a/crates/contracts/artifacts/BalancerV2BasePoolFactory.json +++ b/contracts/artifacts/BalancerV2BasePoolFactory.json @@ -12,7 +12,9 @@ ], "name": "PoolCreated", "type": "event" - }, + } + ], + "_disabled": [ { "inputs": [], "name": "getVault", diff --git a/crates/contracts/artifacts/BalancerV2ComposableStablePool.json b/contracts/artifacts/BalancerV2ComposableStablePool.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2ComposableStablePool.json rename to contracts/artifacts/BalancerV2ComposableStablePool.json index 9d8717feab..703f50c58c 100644 --- a/crates/contracts/artifacts/BalancerV2ComposableStablePool.json +++ b/contracts/artifacts/BalancerV2ComposableStablePool.json @@ -281,7 +281,74 @@ }, { "inputs": [], - "name": "DELEGATE_PROTOCOL_SWAP_FEES_SENTINEL", + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", "outputs": [ { "internalType": "uint256", @@ -294,7 +361,66 @@ }, { "inputs": [], - "name": "DOMAIN_SEPARATOR", + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAmplificationParameter", + "outputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isUpdating", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "precision", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPausedState", + "outputs": [ + { + "internalType": "bool", + "name": "paused", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodEndTime", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolId", "outputs": [ { "internalType": "bytes32", @@ -305,6 +431,71 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getScalingFactors", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getSwapFeePercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -316,14 +507,46 @@ "internalType": "address", "name": "spender", "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "name": "allowance", + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", "outputs": [ { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", @@ -333,7 +556,7 @@ "inputs": [ { "internalType": "address", - "name": "spender", + "name": "recipient", "type": "address" }, { @@ -342,7 +565,7 @@ "type": "uint256" } ], - "name": "approve", + "name": "transfer", "outputs": [ { "internalType": "bool", @@ -357,29 +580,54 @@ "inputs": [ { "internalType": "address", - "name": "account", + "name": "sender", "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "balanceOf", + "name": "transferFrom", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [], - "name": "decimals", + "name": "DELEGATE_PROTOCOL_SWAP_FEES_SENTINEL", "outputs": [ { - "internalType": "uint8", + "internalType": "uint256", "name": "", - "type": "uint8" + "type": "uint256" } ], "stateMutability": "view", @@ -455,29 +703,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "getAmplificationParameter", - "outputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "isUpdating", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "precision", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "getAuthorizer", @@ -580,42 +805,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "getPausedState", - "outputs": [ - { - "internalType": "bool", - "name": "paused", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "pauseWindowEndTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "bufferPeriodEndTime", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPoolId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -687,32 +876,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "getScalingFactors", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getSwapFeePercentage", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -835,38 +998,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1056,56 +1187,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1288,19 +1369,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "totalSupply", @@ -1314,59 +1382,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "unpause", @@ -1393,19 +1408,6 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" } ] } diff --git a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactory.json b/contracts/artifacts/BalancerV2ComposableStablePoolFactory.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2ComposableStablePoolFactory.json rename to contracts/artifacts/BalancerV2ComposableStablePoolFactory.json index 6fb974332f..75d73ce83d 100644 --- a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactory.json +++ b/contracts/artifacts/BalancerV2ComposableStablePoolFactory.json @@ -111,6 +111,21 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ { "inputs": [ { @@ -262,19 +277,6 @@ ], "stateMutability": "view", "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" } ] } diff --git a/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV3.json b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV3.json new file mode 100644 index 0000000000..75d73ce83d --- /dev/null +++ b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV3.json @@ -0,0 +1,282 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "amplificationParameter", + "type": "uint256" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "tokenRateCacheDurations", + "type": "uint256[]" + }, + { + "internalType": "bool[]", + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract ComposableStablePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV4.json b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV4.json new file mode 100644 index 0000000000..75d73ce83d --- /dev/null +++ b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV4.json @@ -0,0 +1,282 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "amplificationParameter", + "type": "uint256" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "tokenRateCacheDurations", + "type": "uint256[]" + }, + { + "internalType": "bool[]", + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract ComposableStablePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV5.json b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV5.json new file mode 100644 index 0000000000..75d73ce83d --- /dev/null +++ b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV5.json @@ -0,0 +1,282 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "amplificationParameter", + "type": "uint256" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "tokenRateCacheDurations", + "type": "uint256[]" + }, + { + "internalType": "bool[]", + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract ComposableStablePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV6.json b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV6.json new file mode 100644 index 0000000000..75d73ce83d --- /dev/null +++ b/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV6.json @@ -0,0 +1,282 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "amplificationParameter", + "type": "uint256" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "tokenRateCacheDurations", + "type": "uint256[]" + }, + { + "internalType": "bool[]", + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract ComposableStablePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/crates/contracts/artifacts/BalancerV2LiquidityBootstrappingPool.json b/contracts/artifacts/BalancerV2LiquidityBootstrappingPool.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2LiquidityBootstrappingPool.json rename to contracts/artifacts/BalancerV2LiquidityBootstrappingPool.json index 677e6612f0..c1c66b3f2e 100644 --- a/crates/contracts/artifacts/BalancerV2LiquidityBootstrappingPool.json +++ b/contracts/artifacts/BalancerV2LiquidityBootstrappingPool.json @@ -270,38 +270,44 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, + "inputs": [], + "name": "getNormalizedWeights", + "outputs": [ { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" } ], - "name": "decreaseAllowance", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPausedState", "outputs": [ { "internalType": "bool", - "name": "", + "name": "paused", "type": "bool" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodEndTime", + "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "getActionId", + "inputs": [], + "name": "getPoolId", "outputs": [ { "internalType": "bytes32", @@ -314,12 +320,12 @@ }, { "inputs": [], - "name": "getAuthorizer", + "name": "getScalingFactors", "outputs": [ { - "internalType": "contract IAuthorizer", + "internalType": "uint256[]", "name": "", - "type": "address" + "type": "uint256[]" } ], "stateMutability": "view", @@ -327,22 +333,12 @@ }, { "inputs": [], - "name": "getGradualWeightUpdateParams", + "name": "getSwapEnabled", "outputs": [ { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "endTime", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "endWeights", - "type": "uint256[]" + "internalType": "bool", + "name": "", + "type": "bool" } ], "stateMutability": "view", @@ -350,7 +346,7 @@ }, { "inputs": [], - "name": "getInvariant", + "name": "getSwapFeePercentage", "outputs": [ { "internalType": "uint256", @@ -363,69 +359,180 @@ }, { "inputs": [], - "name": "getLastInvariant", + "name": "name", "outputs": [ { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getNormalizedWeights", + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", "outputs": [ { - "internalType": "uint256[]", + "internalType": "uint256", "name": "", - "type": "uint256[]" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], - "name": "getOwner", + "name": "symbol", "outputs": [ { - "internalType": "address", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getPausedState", + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", "outputs": [ { "internalType": "bool", - "name": "paused", + "name": "", "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" }, { "internalType": "uint256", - "name": "pauseWindowEndTime", + "name": "amount", "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "uint256", - "name": "bufferPeriodEndTime", + "name": "amount", "type": "uint256" } ], - "stateMutability": "view", + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getPoolId", + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", "outputs": [ { "internalType": "bytes32", @@ -438,12 +545,12 @@ }, { "inputs": [], - "name": "getRate", + "name": "getAuthorizer", "outputs": [ { - "internalType": "uint256", + "internalType": "contract IAuthorizer", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -451,11 +558,21 @@ }, { "inputs": [], - "name": "getScalingFactors", + "name": "getGradualWeightUpdateParams", "outputs": [ + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + }, { "internalType": "uint256[]", - "name": "", + "name": "endWeights", "type": "uint256[]" } ], @@ -464,12 +581,12 @@ }, { "inputs": [], - "name": "getSwapEnabled", + "name": "getInvariant", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], "stateMutability": "view", @@ -477,7 +594,7 @@ }, { "inputs": [], - "name": "getSwapFeePercentage", + "name": "getLastInvariant", "outputs": [ { "internalType": "uint256", @@ -490,10 +607,10 @@ }, { "inputs": [], - "name": "getVault", + "name": "getOwner", "outputs": [ { - "internalType": "contract IVault", + "internalType": "address", "name": "", "type": "address" } @@ -502,37 +619,26 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "addedValue", - "type": "uint256" - } - ], - "name": "increaseAllowance", + "inputs": [], + "name": "getRate", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "name", + "name": "getVault", "outputs": [ { - "internalType": "string", + "internalType": "contract IVault", "name": "", - "type": "string" + "type": "address" } ], "stateMutability": "view", @@ -542,19 +648,24 @@ "inputs": [ { "internalType": "address", - "name": "owner", + "name": "spender", "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" } ], - "name": "nonces", + "name": "increaseAllowance", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { @@ -741,49 +852,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -949,19 +1017,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "totalSupply", @@ -975,59 +1030,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/crates/contracts/artifacts/BalancerV2LiquidityBootstrappingPoolFactory.json b/contracts/artifacts/BalancerV2LiquidityBootstrappingPoolFactory.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2LiquidityBootstrappingPoolFactory.json rename to contracts/artifacts/BalancerV2LiquidityBootstrappingPoolFactory.json index 17eaf625ba..ab8352a0bb 100644 --- a/crates/contracts/artifacts/BalancerV2LiquidityBootstrappingPoolFactory.json +++ b/contracts/artifacts/BalancerV2LiquidityBootstrappingPoolFactory.json @@ -72,7 +72,9 @@ ], "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [], "name": "getCreationCode", diff --git a/contracts/artifacts/BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory.json b/contracts/artifacts/BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory.json new file mode 100644 index 0000000000..ab8352a0bb --- /dev/null +++ b/contracts/artifacts/BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory.json @@ -0,0 +1,160 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "weights", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bool", + "name": "swapEnabledOnStart", + "type": "bool" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/crates/contracts/artifacts/BalancerV2StablePool.json b/contracts/artifacts/BalancerV2StablePool.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2StablePool.json rename to contracts/artifacts/BalancerV2StablePool.json index 65ee2aacc1..e82fb11951 100644 --- a/crates/contracts/artifacts/BalancerV2StablePool.json +++ b/contracts/artifacts/BalancerV2StablePool.json @@ -265,38 +265,54 @@ "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getAmplificationParameter", + "outputs": [ { - "internalType": "address", - "name": "spender", - "type": "address" + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isUpdating", + "type": "bool" }, { "internalType": "uint256", - "name": "amount", + "name": "precision", "type": "uint256" } ], - "name": "decreaseAllowance", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPausedState", "outputs": [ { "internalType": "bool", - "name": "", + "name": "paused", "type": "bool" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodEndTime", + "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "getActionId", + "inputs": [], + "name": "getPoolId", "outputs": [ { "internalType": "bytes32", @@ -309,21 +325,11 @@ }, { "inputs": [], - "name": "getAmplificationParameter", + "name": "getSwapFeePercentage", "outputs": [ { "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "isUpdating", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "precision", + "name": "", "type": "uint256" } ], @@ -332,105 +338,147 @@ }, { "inputs": [], - "name": "getAuthorizer", + "name": "name", "outputs": [ { - "internalType": "contract IAuthorizer", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getOwner", - "outputs": [ + "inputs": [ { "internalType": "address", - "name": "", + "name": "owner", "type": "address" } ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getPausedState", - "outputs": [ + "inputs": [ { - "internalType": "bool", - "name": "paused", - "type": "bool" + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "uint256", - "name": "pauseWindowEndTime", + "name": "value", "type": "uint256" }, { "internalType": "uint256", - "name": "bufferPeriodEndTime", + "name": "deadline", "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "getPoolId", + "name": "symbol", "outputs": [ { - "internalType": "bytes32", + "internalType": "string", "name": "", - "type": "bytes32" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getRate", - "outputs": [ + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, { "internalType": "uint256", - "name": "", + "name": "amount", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getSwapFeePercentage", + "name": "transfer", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getVault", + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", "outputs": [ { - "internalType": "contract IVault", + "internalType": "bool", "name": "", - "type": "address" + "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [ { @@ -440,11 +488,11 @@ }, { "internalType": "uint256", - "name": "addedValue", + "name": "amount", "type": "uint256" } ], - "name": "increaseAllowance", + "name": "decreaseAllowance", "outputs": [ { "internalType": "bool", @@ -455,28 +503,54 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], - "name": "name", + "name": "getAuthorizer", "outputs": [ { - "internalType": "string", + "internalType": "contract IAuthorizer", "name": "", - "type": "string" + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getOwner", + "outputs": [ { "internalType": "address", - "name": "owner", + "name": "", "type": "address" } ], - "name": "nonces", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRate", "outputs": [ { "internalType": "uint256", @@ -487,6 +561,43 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -752,49 +863,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -972,19 +1040,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "totalSupply", @@ -997,59 +1052,6 @@ ], "stateMutability": "view", "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" } ] } diff --git a/crates/contracts/artifacts/BalancerV2StablePoolFactoryV2.json b/contracts/artifacts/BalancerV2StablePoolFactoryV2.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2StablePoolFactoryV2.json rename to contracts/artifacts/BalancerV2StablePoolFactoryV2.json index 7efac7b724..1492dde6b1 100644 --- a/crates/contracts/artifacts/BalancerV2StablePoolFactoryV2.json +++ b/contracts/artifacts/BalancerV2StablePoolFactoryV2.json @@ -80,7 +80,9 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [ { diff --git a/crates/contracts/artifacts/BalancerV2Vault.json b/contracts/artifacts/BalancerV2Vault.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2Vault.json rename to contracts/artifacts/BalancerV2Vault.json index 52c06f7fd3..e0291e07fe 100644 --- a/crates/contracts/artifacts/BalancerV2Vault.json +++ b/contracts/artifacts/BalancerV2Vault.json @@ -344,6 +344,10 @@ "name": "TokensRegistered", "type": "event" }, + { + "stateMutability": "payable", + "type": "receive" + }, { "inputs": [], "name": "WETH", @@ -453,95 +457,214 @@ { "inputs": [ { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" + "internalType": "contract IFlashLoanRecipient", + "name": "recipient", + "type": "address" }, { "internalType": "contract IERC20[]", "name": "tokens", "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" } ], - "name": "deregisterTokens", + "name": "flashLoan", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "getInternalBalance", + "outputs": [ + { + "internalType": "uint256[]", + "name": "balances", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPausedState", + "outputs": [ + { + "internalType": "bool", + "name": "paused", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodEndTime", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { "internalType": "bytes32", "name": "poolId", "type": "bytes32" - }, + } + ], + "name": "getPool", + "outputs": [ { "internalType": "address", - "name": "sender", + "name": "", "type": "address" }, { - "internalType": "address payable", - "name": "recipient", + "internalType": "enum IVault.PoolSpecialization", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + } + ], + "name": "getPoolTokens", + "outputs": [ + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "balances", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "lastChangeBlock", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", "type": "address" }, + { + "internalType": "address", + "name": "relayer", + "type": "address" + } + ], + "name": "hasApprovedRelayer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "contract IAsset[]", - "name": "assets", - "type": "address[]" + "internalType": "enum IVault.UserBalanceOpKind", + "name": "kind", + "type": "uint8" }, { - "internalType": "uint256[]", - "name": "minAmountsOut", - "type": "uint256[]" + "internalType": "contract IAsset", + "name": "asset", + "type": "address" }, { - "internalType": "bytes", - "name": "userData", - "type": "bytes" + "internalType": "uint256", + "name": "amount", + "type": "uint256" }, { - "internalType": "bool", - "name": "toInternalBalance", - "type": "bool" + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" } ], - "internalType": "struct IVault.ExitPoolRequest", - "name": "request", - "type": "tuple" + "internalType": "struct IVault.UserBalanceOp[]", + "name": "ops", + "type": "tuple[]" } ], - "name": "exitPool", + "name": "manageUserBalance", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { "inputs": [ { - "internalType": "contract IFlashLoanRecipient", - "name": "recipient", + "internalType": "address", + "name": "sender", "type": "address" }, { - "internalType": "contract IERC20[]", - "name": "tokens", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" + "internalType": "address", + "name": "relayer", + "type": "address" }, { - "internalType": "bytes", - "name": "userData", - "type": "bytes" + "internalType": "bool", + "name": "approved", + "type": "bool" } ], - "name": "flashLoan", + "name": "setRelayerApproval", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -549,86 +672,176 @@ { "inputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "getActionId", - "outputs": [ + "components": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "enum IVault.SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "contract IAsset", + "name": "assetIn", + "type": "address" + }, + { + "internalType": "contract IAsset", + "name": "assetOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IVault.SingleSwap", + "name": "singleSwap", + "type": "tuple" + }, { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.FundManagement", + "name": "funds", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getAuthorizer", + "name": "swap", "outputs": [ { - "internalType": "contract IAuthorizer", - "name": "", - "type": "address" + "internalType": "uint256", + "name": "amountCalculated", + "type": "uint256" } ], - "stateMutability": "view", + "stateMutability": "payable", "type": "function" - }, + } + ], + "bytecode": "0x6101806040523480156200001257600080fd5b5060405162006ed638038062006ed6833981016040819052620000359162000253565b8382826040518060400160405280601181526020017010985b185b98d95c88158c8815985d5b1d607a1b81525080604051806040016040528060018152602001603160f81b815250306001600160a01b031660001b89806001600160a01b03166080816001600160a01b031660601b815250505030604051620000b89062000245565b620000c491906200029f565b604051809103906000f080158015620000e1573d6000803e3d6000fd5b5060601b6001600160601b03191660a052600160005560c052815160209283012060e052805191012061010052507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61012052620001486276a70083111561019462000181565b6200015c62278d0082111561019562000181565b429091016101408190520161016052620001768162000196565b5050505050620002cc565b8162000192576200019281620001f2565b5050565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b610be680620062f083390190565b6000806000806080858703121562000269578384fd5b84516200027681620002b3565b60208601519094506200028981620002b3565b6040860151606090960151949790965092505050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114620002c957600080fd5b50565b60805160601c60a05160601c60c05160e05161010051610120516101405161016051615fc06200033060003980611aed525080611ac952508061289f5250806128e15250806128c05250806110fd5250806113b15250806105285250615fc06000f3fe6080604052600436106101a55760003560e01c8063945bcec9116100e1578063e6c460921161008a578063f84d066e11610064578063f84d066e1461048a578063f94d4668146104aa578063fa6e671d146104d9578063fec90d72146104f9576101d3565b8063e6c4609214610427578063ed24911d14610447578063f6c009271461045c576101d3565b8063b05f8e48116100bb578063b05f8e48146103cf578063b95cac28146103ff578063d2946c2b14610412576101d3565b8063945bcec914610385578063aaabadc514610398578063ad5c4648146103ba576101d3565b806352bbbe291161014e5780637d3aeb96116101285780637d3aeb9614610305578063851c1bb3146103255780638bdb39131461034557806390193b7c14610365576101d3565b806352bbbe29146102b25780635c38449e146102c557806366a9c7d2146102e5576101d3565b80630f5a6efa1161017f5780630f5a6efa1461024157806316c38b3c1461026e5780631c0de0511461028e576101d3565b8063058a628f146101d857806309b2760f146101f85780630e8e3e841461022e576101d3565b366101d3576101d16101b5610526565b6001600160a01b0316336001600160a01b03161461020661054b565b005b600080fd5b3480156101e457600080fd5b506101d16101f3366004615157565b61055d565b34801561020457600080fd5b506102186102133660046156e6565b610581565b6040516102259190615d3e565b60405180910390f35b6101d161023c36600461531e565b610634565b34801561024d57600080fd5b5061026161025c3660046151f5565b610770565b6040516102259190615d08565b34801561027a57600080fd5b506101d161028936600461545c565b610806565b34801561029a57600080fd5b506102a361081f565b60405161022593929190615d26565b6102186102c036600461588f565b610848565b3480156102d157600080fd5b506101d16102e036600461565b565b6109e9565b3480156102f157600080fd5b506101d1610300366004615545565b610e06565b34801561031157600080fd5b506101d1610320366004615516565b610fa5565b34801561033157600080fd5b50610218610340366004615633565b6110f9565b34801561035157600080fd5b506101d16103603660046154ac565b61114b565b34801561037157600080fd5b50610218610380366004615157565b611161565b610261610393366004615786565b61117c565b3480156103a457600080fd5b506103ad6112b0565b6040516102259190615b63565b3480156103c657600080fd5b506103ad6112c4565b3480156103db57600080fd5b506103ef6103ea36600461560f565b6112d3565b6040516102259493929190615eb9565b6101d161040d3660046154ac565b611396565b34801561041e57600080fd5b506103ad6113af565b34801561043357600080fd5b506101d1610442366004615243565b6113d3565b34801561045357600080fd5b506102186114ef565b34801561046857600080fd5b5061047c610477366004615494565b6114f9565b604051610225929190615b9b565b34801561049657600080fd5b506102616104a5366004615702565b611523565b3480156104b657600080fd5b506104ca6104c5366004615494565b611620565b60405161022593929190615cd2565b3480156104e557600080fd5b506101d16104f43660046151ab565b611654565b34801561050557600080fd5b50610519610514366004615173565b6116e6565b6040516102259190615d1b565b7f00000000000000000000000000000000000000000000000000000000000000005b90565b8161055957610559816116fb565b5050565b610565611768565b61056d611781565b610576816117af565b61057e611822565b50565b600061058b611768565b610593611829565b60006105a2338460065461183e565b6000818152600560205260409020549091506105c49060ff16156101f461054b565b60008181526005602052604090819020805460ff1916600190811790915560068054909101905551339082907f3c13bc30b8e878c53fd2a36b679409c073afd75950be43d8858768e956fbc20e9061061d908790615e3a565b60405180910390a3905061062f611822565b919050565b61063c611768565b6000806000805b845181101561075b5760008060008060006106718a878151811061066357fe5b60200260200101518961187d565b9c50939850919650945092509050600185600381111561068d57fe5b14156106a45761069f848383866118f5565b61074a565b866106b6576106b1611829565b600196505b60008560038111156106c457fe5b14156106f5576106d684838386611918565b6106df84611938565b1561069f576106ee8984611945565b985061074a565b61070a61070185611938565b1561020761054b565b600061071585610548565b9050600286600381111561072557fe5b141561073c5761073781848487611957565b610748565b61074881848487611970565b505b505060019093019250610643915050565b50610765836119de565b50505061057e611822565b6060815167ffffffffffffffff8111801561078a57600080fd5b506040519080825280602002602001820160405280156107b4578160200160208202803683370190505b50905060005b82518110156107ff576107e0848483815181106107d357fe5b6020026020010151611a01565b8282815181106107ec57fe5b60209081029190910101526001016107ba565b5092915050565b61080e611768565b610816611781565b61057681611a2c565b600080600061082c611aaa565b159250610837611ac7565b9150610841611aeb565b9050909192565b6000610852611768565b61085a611829565b835161086581611b0f565b610874834211156101fc61054b565b61088760008760800151116101fe61054b565b60006108968760400151611b41565b905060006108a78860600151611b41565b90506108ca816001600160a01b0316836001600160a01b031614156101fd61054b565b6108d2614ce1565b885160808201526020890151819060018111156108eb57fe5b908160018111156108f857fe5b9052506001600160a01b03808416602083015282811660408084019190915260808b0151606084015260a08b01516101008401528951821660c08401528901511660e082015260008061094a83611b66565b9198509250905061098160008c60200151600181111561096657fe5b146109745789831115610979565b898210155b6101fb61054b565b6109998b60400151838c600001518d60200151611c5a565b6109b18b60600151828c604001518d60600151611d38565b6109d36109c18c60400151611938565b6109cc5760006109ce565b825b6119de565b5050505050506109e1611822565b949350505050565b6109f1611768565b6109f9611829565b610a0583518351611e12565b6060835167ffffffffffffffff81118015610a1f57600080fd5b50604051908082528060200260200182016040528015610a49578160200160208202803683370190505b5090506060845167ffffffffffffffff81118015610a6657600080fd5b50604051908082528060200260200182016040528015610a90578160200160208202803683370190505b5090506000805b8651811015610c09576000878281518110610aae57fe5b602002602001015190506000878381518110610ac657fe5b60200260200101519050610b11846001600160a01b0316836001600160a01b03161160006001600160a01b0316846001600160a01b031614610b09576066610b0c565b60685b61054b565b819350816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b409190615b63565b60206040518083038186803b158015610b5857600080fd5b505afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190615968565b858481518110610b9c57fe5b602002602001018181525050610bb181611e1f565b868481518110610bbd57fe5b602002602001018181525050610beb81868581518110610bd957fe5b6020026020010151101561021061054b565b610bff6001600160a01b0383168b83611ea6565b5050600101610a97565b506040517ff04f27070000000000000000000000000000000000000000000000000000000081526001600160a01b0388169063f04f270790610c55908990899088908a90600401615c85565b600060405180830381600087803b158015610c6f57600080fd5b505af1158015610c83573d6000803e3d6000fd5b5050505060005b8651811015610df4576000878281518110610ca157fe5b602002602001015190506000848381518110610cb957fe5b602002602001015190506000826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610cf19190615b63565b60206040518083038186803b158015610d0957600080fd5b505afa158015610d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d419190615968565b9050610d528282101561020361054b565b60008282039050610d7b888681518110610d6857fe5b602002602001015182101561025a61054b565b610d858482611f11565b836001600160a01b03168c6001600160a01b03167f0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f08c8881518110610dc657fe5b602002602001015184604051610ddd929190615e4d565b60405180910390a350505050806001019050610c8a565b50505050610e00611822565b50505050565b610e0e611768565b610e16611829565b82610e2081611f33565b610e2c83518351611e12565b60005b8351811015610eca576000848281518110610e4657fe5b60200260200101519050610e7260006001600160a01b0316826001600160a01b0316141561013561054b565b838281518110610e7e57fe5b6020908102919091018101516000888152600a835260408082206001600160a01b0395861683529093529190912080546001600160a01b03191692909116919091179055600101610e2f565b506000610ed685611f64565b90506002816002811115610ee657fe5b1415610f3457610efc845160021461020c61054b565b610f2f8585600081518110610f0d57fe5b602002602001015186600181518110610f2257fe5b6020026020010151611f7e565b610f5c565b6001816002811115610f4257fe5b1415610f5257610f2f858561202a565b610f5c8585612082565b847ff5847d3f2197b16cdcd2098ec95d0905cd1abdaf415f07bb7cef2bba8ac5dec48585604051610f8e929190615bed565b60405180910390a25050610fa0611822565b505050565b610fad611768565b610fb5611829565b81610fbf81611f33565b6000610fca84611f64565b90506002816002811115610fda57fe5b141561102857610ff0835160021461020c61054b565b611023848460008151811061100157fe5b60200260200101518560018151811061101657fe5b60200260200101516120d7565b611050565b600181600281111561103657fe5b1415611046576110238484612145565b61105084846121ff565b60005b83518110156110b657600a6000868152602001908152602001600020600085838151811061107d57fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002080546001600160a01b0319169055600101611053565b50837f7dcdc6d02ef40c7c1a7046a011b058bd7f988fa14e20a66344f9d4e60657d610846040516110e79190615bda565b60405180910390a25050610559611822565b60007f00000000000000000000000000000000000000000000000000000000000000008260405160200161112e929190615ac2565b604051602081830303815290604052805190602001209050919050565b610e00600185858561115c86612262565b61226e565b6001600160a01b031660009081526002602052604090205490565b6060611186611768565b61118e611829565b835161119981611b0f565b6111a8834211156101fc61054b565b6111b486518551611e12565b6111c08787878b6123f4565b91506000805b87518110156112925760008882815181106111dd57fe5b6020026020010151905060008583815181106111f557fe5b6020026020010151905061122188848151811061120e57fe5b60200260200101518213156101fb61054b565b600081131561126157885160208a015182916112409185918491611c5a565b61124983611938565b1561125b576112588582611945565b94505b50611288565b600081121561128857600081600003905061128683828c604001518d60600151611d38565b505b50506001016111c6565b5061129c816119de565b50506112a6611822565b9695505050505050565b60035461010090046001600160a01b031690565b60006112ce610526565b905090565b600080600080856112e381612683565b6000806112ef89611f64565b905060028160028111156112ff57fe5b14156113165761130f89896126a1565b9150611341565b600181600281111561132457fe5b14156113345761130f898961271b565b61133e8989612789565b91505b61134a826127a1565b9650611355826127b4565b9550611360826127ca565b6000998a52600a60209081526040808c206001600160a01b039b8c168d5290915290992054969995989796909616955050505050565b61139e611829565b610e00600085858561115c86612262565b7f000000000000000000000000000000000000000000000000000000000000000090565b6113db611768565b6113e3611829565b6113eb614d31565b60005b82518110156114e55782818151811061140357fe5b6020026020010151915060008260200151905061141f81612683565b604083015161143961143183836127d0565b61020961054b565b6000828152600a602090815260408083206001600160a01b03858116855292529091205461146c911633146101f661054b565b835160608501516000806114828487878661282c565b91509150846001600160a01b0316336001600160a01b0316877f6edcaf6241105b4c94c2efdbf3a6b12458eb3d07be3a0e81d24b13c44045fe7a85856040516114cc929190615e4d565b60405180910390a45050505050508060010190506113ee565b505061057e611822565b60006112ce61289b565b6000808261150681612683565b61150f84612938565b61151885611f64565b925092505b50915091565b60603330146115f6576000306001600160a01b0316600036604051611549929190615ada565b6000604051808303816000865af19150503d8060008114611586576040519150601f19603f3d011682016040523d82523d6000602084013e61158b565b606091505b50509050806000811461159a57fe5b60046000803e6000516001600160e01b0319167ffa61cc120000000000000000000000000000000000000000000000000000000081146115de573d6000803e3d6000fd5b50602060005260043d0380600460203e602081016000f35b6060611604858585896123f4565b9050602081510263fa61cc126020830352600482036024820181fd5b60608060008361162f81612683565b606061163a8661293e565b9095509050611648816129a0565b95979096509350505050565b61165c611768565b611664611829565b8261166e81611b0f565b6001600160a01b0384811660008181526004602090815260408083209488168084529490915290819020805460ff1916861515179055519091907f46961fdb4502b646d5095fba7600486a8ac05041d55cdf0f16ed677180b5cad8906116d5908690615d1b565b60405180910390a350610fa0611822565b60006116f28383612a4f565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b61177a6002600054141561019061054b565b6002600055565b60006117986000356001600160e01b0319166110f9565b905061057e6117a78233612a7d565b61019161054b565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b6001600055565b61183c611834611aaa565b61019261054b565b565b600069ffffffffffffffffffff8216605084600281111561185b57fe5b901b17606085901b6bffffffffffffffffffffffff19161790505b9392505050565b600080600080600080600088606001519050336001600160a01b0316816001600160a01b0316146118cf57876118ba576118b5611781565b600197505b6118cf6118c78233612a4f565b6101f761054b565b885160208a015160408b01516080909b0151919b909a9992985090965090945092505050565b61190a8361190286611b41565b836000612b20565b50610e008482846000611d38565b61192b8261192586611b41565b83612b76565b610e008482856000611c5a565b6001600160a01b03161590565b60008282016116f2848210158361054b565b6119648385836000612b20565b50610e00828583612b76565b8015610e005761198b6001600160a01b038516848484612ba6565b826001600160a01b0316846001600160a01b03167f540a1a3f28340caec336c81d8d7b3df139ee5cdc1839a4f283d7ebb7eaae2d5c84846040516119d0929190615bc1565b60405180910390a350505050565b6119ed8134101561020461054b565b348190038015610559576105593382612bc7565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205490565b8015611a4c57611a47611a3d611ac7565b421061019361054b565b611a61565b611a61611a57611aeb565b42106101a961054b565b6003805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490611a9f908390615d1b565b60405180910390a150565b6000611ab4611aeb565b4211806112ce57505060035460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b336001600160a01b0382161461057e57611b27611781565b611b318133612a4f565b61057e5761057e816101f7612c41565b6000611b4c82611938565b611b5e57611b5982610548565b6116f5565b6116f5610526565b600080600080611b798560800151612938565b90506000611b8a8660800151611f64565b90506002816002811115611b9a57fe5b1415611bb157611baa8683612c75565b9450611bdc565b6001816002811115611bbf57fe5b1415611bcf57611baa8683612d25565b611bd98683612db8565b94505b611bef8660000151876060015187612ff7565b809450819550505085604001516001600160a01b031686602001516001600160a01b031687608001517f2170c741c41531aec20e7c107c24eecfdd15e69c9bb0a8dd37b1840b9e0b207b8787604051611c49929190615e4d565b60405180910390a450509193909250565b82611c6457610e00565b611c6d84611938565b15611cee57611c7f811561020261054b565b611c8e8347101561020461054b565b611c96610526565b6001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611cd057600080fd5b505af1158015611ce4573d6000803e3d6000fd5b5050505050610e00565b6000611cf985610548565b90508115611d16576000611d108483876001612b20565b90940393505b8315611d3157611d316001600160a01b038216843087612ba6565b5050505050565b82611d4257610e00565b611d4b84611938565b15611ddb57611d5d811561020261054b565b611d65610526565b6001600160a01b0316632e1a7d4d846040518263ffffffff1660e01b8152600401611d909190615d3e565b600060405180830381600087803b158015611daa57600080fd5b505af1158015611dbe573d6000803e3d6000fd5b50611dd6925050506001600160a01b03831684612bc7565b610e00565b6000611de685610548565b90508115611dfe57611df9838286612b76565b611d31565b611d316001600160a01b0382168486611ea6565b610559818314606761054b565b600080611e2a6113af565b6001600160a01b031663d877845c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6257600080fd5b505afa158015611e76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9a9190615968565b90506118768382613025565b610fa08363a9059cbb60e01b8484604051602401611ec5929190615bc1565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152613072565b801561055957610559611f226113af565b6001600160a01b0384169083611ea6565b611f3c81612683565b61057e611f4882612938565b6001600160a01b0316336001600160a01b0316146101f561054b565b600061ffff605083901c166116f5600382106101f461054b565b611f9f816001600160a01b0316836001600160a01b0316141561020a61054b565b611fbe816001600160a01b0316836001600160a01b031610606661054b565b60008381526009602052604090208054611ffb906001600160a01b0316158015611ff3575060018201546001600160a01b0316155b61020b61054b565b80546001600160a01b039384166001600160a01b03199182161782556001909101805492909316911617905550565b6000828152600860205260408120905b8251811015610e0057600061206b84838151811061205457fe5b60200260200101518461311290919063ffffffff16565b90506120798161020a61054b565b5060010161203a565b6000828152600160205260408120905b8251811015610e005760006120c08483815181106120ac57fe5b602090810291909101015184906000613175565b90506120ce8161020a61054b565b50600101612092565b60008060006120e7868686613222565b9250925092506121116120f9846132e9565b80156121095750612109836132e9565b61020d61054b565b600095865260096020526040862080546001600160a01b031990811682556001909101805490911690559490945550505050565b6000828152600860205260408120905b8251811015610e0057600083828151811061216c57fe5b602002602001015190506121b8612109600760008881526020019081526020016000206000846001600160a01b03166001600160a01b03168152602001908152602001600020546132e9565b60008581526007602090815260408083206001600160a01b038516845290915281208190556121e7848361330b565b90506121f58161020961054b565b5050600101612155565b6000828152600160205260408120905b8251811015610e0057600083828151811061222657fe5b60200260200101519050600061223c8483613412565b905061224a612109826132e9565b6122548483613421565b50505080600101905061220f565b61226a614d5a565b5090565b612276611768565b8361228081612683565b8361228a81611b0f565b61229e836000015151846020015151611e12565b60606122ad84600001516134c3565b905060606122bb8883613552565b905060608060606122d08c8c8c8c8c896135e3565b92509250925060006122e18c611f64565b905060028160028111156122f157fe5b1415612359576123548c8760008151811061230857fe5b60200260200101518660008151811061231d57fe5b60200260200101518960018151811061233257fe5b60200260200101518860018151811061234757fe5b60200260200101516137a8565b612382565b600181600281111561236757fe5b1415612378576123548c87866137e7565b6123828c85613854565b6000808e600181111561239157fe5b1490508b6001600160a01b03168d7fe5ce249087ce04f05a957192435400fd97868dba0e6a4b4c049abf8af80dae78896123cb888661389d565b876040516123db93929190615c4c565b60405180910390a3505050505050505050611d31611822565b6060835167ffffffffffffffff8111801561240e57600080fd5b50604051908082528060200260200182016040528015612438578160200160208202803683370190505b509050612443614d84565b61244b614ce1565b60008060005b89518110156126765789818151811061246657fe5b6020026020010151945060008951866020015110801561248a575089518660400151105b905061249781606461054b565b60006124b98b8860200151815181106124ac57fe5b6020026020010151611b41565b905060006124d08c8960400151815181106124ac57fe5b90506124f3816001600160a01b0316836001600160a01b031614156101fd61054b565b60608801516125435761250b600085116101fe61054b565b60006125188b8484613945565b6001600160a01b0316876001600160a01b031614905061253a816101ff61054b565b50606088018590525b87516080880152868a600181111561255757fe5b9081600181111561256457fe5b9052506001600160a01b0380831660208901528181166040808a01919091526060808b0151908a015260808a01516101008a01528c51821660c08a01528c01511660e08801526000806125b689611b66565b919850925090506125c88c8585613967565b97506125fc6125d683613981565b8c8c60200151815181106125e657fe5b60200260200101516139b190919063ffffffff16565b8b8b602001518151811061260c57fe5b60200260200101818152505061264a61262482613981565b8c8c604001518151811061263457fe5b60200260200101516139e590919063ffffffff16565b8b8b604001518151811061265a57fe5b6020026020010181815250505050505050806001019050612451565b5050505050949350505050565b60008181526005602052604090205461057e9060ff166101f461054b565b60008060008060006126b287613a19565b945094509450945050836001600160a01b0316866001600160a01b031614156126e157829450505050506116f5565b816001600160a01b0316866001600160a01b031614156127065793506116f592505050565b6127116102096116fb565b5050505092915050565b60008281526007602090815260408083206001600160a01b03851684529091528120548161274882613a8f565b80612766575060008581526008602052604090206127669085613aa1565b9050806127815761277685612683565b6127816102096116fb565b509392505050565b60008281526001602052604081206109e18184613412565b6dffffffffffffffffffffffffffff1690565b60701c6dffffffffffffffffffffffffffff1690565b60e01c90565b6000806127dc84611f64565b905060028160028111156127ec57fe5b1415612804576127fc8484613ac2565b9150506116f5565b600181600281111561281257fe5b1415612822576127fc8484613b13565b6127fc8484613b2b565b600080600061283a86611f64565b9050600087600281111561284a57fe5b14156128665761285c86828787613b43565b9250925050612892565b600187600281111561287457fe5b14156128865761285c86828787613bbe565b61285c86828787613c3a565b94509492505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612908613c9d565b3060405160200161291d959493929190615df0565b60405160208183030381529060405280519060200120905090565b60601c90565b606080600061294c84611f64565b9050600281600281111561295c57fe5b14156129755761296b84613ca1565b925092505061299b565b600181600281111561298357fe5b14156129925761296b84613dd6565b61296b84613efd565b915091565b60606000825167ffffffffffffffff811180156129bc57600080fd5b506040519080825280602002602001820160405280156129e6578160200160208202803683370190505b5091506000905060005b825181101561151d576000848281518110612a0757fe5b60200260200101519050612a1a81613ff9565b848381518110612a2657fe5b602002602001018181525050612a4483612a3f836127ca565b614014565b9250506001016129f0565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b6003546040517f9be2a88400000000000000000000000000000000000000000000000000000000815260009161010090046001600160a01b031690639be2a88490612ad090869086903090600401615d47565b60206040518083038186803b158015612ae857600080fd5b505afa158015612afc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f29190615478565b600080612b2d8686611a01565b9050612b468380612b3e5750848210155b61020161054b565b612b50818561402b565b9150818103612b6c878783612b6487613981565b60000361403a565b5050949350505050565b6000612b828484611a01565b90506000612b908284611945565b9050611d31858583612ba187613981565b61403a565b610e00846323b872dd60e01b858585604051602401611ec593929190615b77565b612bd6814710156101a361054b565b6000826001600160a01b031682604051612bef90610548565b60006040518083038185875af1925050503d8060008114612c2c576040519150601f19603f3d011682016040523d82523d6000602084013e612c31565b606091505b50509050610fa0816101a461054b565b6001600160a01b0382166000908152600260205260409020805460018101909155610fa0612c6f8483614095565b8361054b565b600080600080612c92866080015187602001518860400151613222565b92509250925060008087604001516001600160a01b031688602001516001600160a01b03161015612cc7575083905082612ccd565b50829050835b612cd9888884846141bb565b60408b015160208c01519199509294509092506001600160a01b03918216911610612d0d57612d0881836142d1565b612d17565b612d1782826142d1565b909255509295945050505050565b600080612d3a8460800151856020015161271b565b90506000612d508560800151866040015161271b565b9050612d5e858584846141bb565b6080880180516000908152600760208181526040808420828e01516001600160a01b03908116865290835281852098909855935183529081528282209a830151909516815298909352919096209590955550929392505050565b60808201516000908152600160209081526040822090840151829182918290612de290839061430c565b90506000612dfd88604001518461430c90919063ffffffff16565b9050811580612e0a575080155b15612e2757612e1c8860800151612683565b612e276102096116fb565b60001991820191016000612e3a8461432b565b905060608167ffffffffffffffff81118015612e5557600080fd5b50604051908082528060200260200182016040528015612e7f578160200160208202803683370190505b50600060a08c018190529091505b82811015612eff576000612ea1878361432f565b9050612eac81613ff9565b838381518110612eb857fe5b602002602001018181525050612ed58c60a00151612a3f836127ca565b60a08d015281861415612eea57809850612ef6565b84821415612ef6578097505b50600101612e8d565b506040517f01ec954a0000000000000000000000000000000000000000000000000000000081526001600160a01b038a16906301ec954a90612f4b908d90859089908990600401615e5b565b602060405180830381600087803b158015612f6557600080fd5b505af1158015612f79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9d9190615968565b9750600080612fb58c600001518d606001518c612ff7565b9092509050612fc48983614345565b9850612fd08882614376565b9750612fdd87878b61438c565b612fe887868a61438c565b50505050505050505092915050565b6000808085600181111561300757fe5b141561301757508290508161301d565b50819050825b935093915050565b600082820261304984158061304257508385838161303f57fe5b04145b600361054b565b806130585760009150506116f5565b670de0b6b3a76400006000198201046001019150506116f5565b60006060836001600160a01b03168360405161308e9190615aea565b6000604051808303816000865af19150503d80600081146130cb576040519150601f19603f3d011682016040523d82523d6000602084013e6130d0565b606091505b509150915060008214156130e8573d6000803e3d6000fd5b610e0081516000148061310a57508180602001905181019061310a9190615478565b6101a261054b565b600061311e8383613aa1565b61316d57508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b038616908117909155855490825282860190935260409020919091556116f5565b5060006116f5565b6001600160a01b03821660009081526002840160205260408120548061320257505082546040805180820182526001600160a01b03858116808352602080840187815260008781526001808c018452878220965187546001600160a01b03191696169590951786559051948401949094559482018089559083526002880190945291902091909155611876565b600019016000908152600180860160205260408220018390559050611876565b600080600080600061323487876143a4565b91509150600061324483836143d5565b60008a81526009602090815260408083208484526002019091528120805460018201549197509293509061327783613a8f565b80613286575061328682613a8f565b806132a757506132968c87613ac2565b80156132a757506132a78c86613ac2565b9050806132c2576132b78c612683565b6132c26102096116fb565b6132cc8383614408565b98506132d8838361442d565b975050505050505093509350939050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6001600160a01b03811660009081526001830160205260408120548015613408578354600019808301919081019060009087908390811061334857fe5b60009182526020909120015487546001600160a01b039091169150819088908590811061337157fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b039485161790559183168152600189810190925260409020908401905586548790806133ba57fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506116f59350505050565b60009150506116f5565b60006116f28383610209614444565b6001600160a01b0381166000908152600283016020526040812054801561340857835460001990810160008181526001878101602090815260408084209587018452808420865481546001600160a01b03199081166001600160a01b0392831617835588860180549387019390935588548216875260028d018086528488209a909a5588541690975584905593895593871682529390925281205590506116f5565b606080825167ffffffffffffffff811180156134de57600080fd5b50604051908082528060200260200182016040528015613508578160200160208202803683370190505b50905060005b83518110156107ff576135268482815181106124ac57fe5b82828151811061353257fe5b6001600160a01b039092166020928302919091019091015260010161350e565b60608060606135608561293e565b9150915061357082518551611e12565b613580600083511161020f61054b565b60005b82518110156135da576135d285828151811061359b57fe5b60200260200101516001600160a01b03168483815181106135b857fe5b60200260200101516001600160a01b03161461020861054b565b600101613583565b50949350505050565b60608060608060006135f4866129a0565b9150915060006136038b612938565b905060008c600181111561361357fe5b146136b657806001600160a01b03166374f3b0098c8c8c8787613634614481565b8f604001516040518863ffffffff1660e01b815260040161365b9796959493929190615d66565b600060405180830381600087803b15801561367557600080fd5b505af1158015613689573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136b19190810190615405565b61374f565b806001600160a01b031663d5c096c48c8c8c87876136d2614481565b8f604001516040518863ffffffff1660e01b81526004016136f99796959493929190615d66565b600060405180830381600087803b15801561371357600080fd5b505af1158015613727573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261374f9190810190615405565b80955081965050506137658751865186516144fb565b60008c600181111561377357fe5b1461378a576137858989898888614513565b613797565b6137978a8989888861465a565b955050505096509650969350505050565b60006137b485846143d5565b600087815260096020908152604080832084845260020190915290209091506137dd85846142d1565b9055505050505050565b60005b8251811015610e00578181815181106137ff57fe5b602002602001015160076000868152602001908152602001600020600085848151811061382857fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020556001016137ea565b6000828152600160205260408120905b8251811015610e00576138958184838151811061387d57fe5b60200260200101518461438c9092919063ffffffff16565b600101613864565b6060825167ffffffffffffffff811180156138b757600080fd5b506040519080825280602002602001820160405280156138e1578160200160208202803683370190505b50905060005b83518110156107ff57826139115783818151811061390157fe5b6020026020010151600003613926565b83818151811061391d57fe5b60200260200101515b82828151811061393257fe5b60209081029190910101526001016138e7565b60008084600181111561395457fe5b1461395f57816109e1565b509092915050565b60008084600181111561397657fe5b146107ff57826109e1565b600061226a7f800000000000000000000000000000000000000000000000000000000000000083106101a561054b565b60008282016116f28284128015906139c95750848212155b806139de57506000841280156139de57508482125b600061054b565b60008183036116f28284128015906139fd5750848213155b80613a125750600084128015613a1257508482135b600161054b565b6000818152600960205260408120805460018201546001600160a01b0391821692849290911690829081613a4d86856143d5565b6000818152600284016020526040902080546001820154919950919250613a748282614408565b9650613a80828261442d565b94505050505091939590929450565b6000613a9a826132e9565b1592915050565b6001600160a01b031660009081526001919091016020526040902054151590565b600082815260096020526040812080546001600160a01b0384811691161480613afa575060018101546001600160a01b038481169116145b80156109e1575050506001600160a01b03161515919050565b60008281526008602052604081206109e18184613aa1565b60008281526001602052604081206109e181846147d0565b6000806002856002811115613b5457fe5b1415613b6a57613b658685856147f1565b613b94565b6001856002811115613b7857fe5b1415613b8957613b658685856147ff565b613b9486858561480d565b8215613bae57613bae6001600160a01b0385163385611ea6565b5050600081900394909350915050565b6000806002856002811115613bcf57fe5b1415613be557613be086858561481b565b613c0f565b6001856002811115613bf357fe5b1415613c0457613be0868585614829565b613c0f868585614837565b8215613c2a57613c2a6001600160a01b038516333086612ba6565b5090946000869003945092505050565b6000806002856002811115613c4b57fe5b1415613c6357613c5c868585614845565b9050613c90565b6001856002811115613c7157fe5b1415613c8257613c5c868585614855565b613c8d868585614865565b90505b6000915094509492505050565b4690565b606080600080600080613cb387613a19565b92975090955093509150506001600160a01b0384161580613cdb57506001600160a01b038216155b15613d04575050604080516000808252602082019081528183019092529450925061299b915050565b60408051600280825260608201835290916020830190803683370190505095508386600081518110613d3257fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508186600181518110613d6057fe5b6001600160a01b03929092166020928302919091018201526040805160028082526060820183529092909190830190803683370190505094508285600081518110613da757fe5b6020026020010181815250508085600181518110613dc157fe5b60200260200101818152505050505050915091565b60008181526008602052604090206060908190613df28161432b565b67ffffffffffffffff81118015613e0857600080fd5b50604051908082528060200260200182016040528015613e32578160200160208202803683370190505b509250825167ffffffffffffffff81118015613e4d57600080fd5b50604051908082528060200260200182016040528015613e77578160200160208202803683370190505b50915060005b8351811015613ef6576000613e928383614875565b905080858381518110613ea157fe5b6001600160a01b03928316602091820292909201810191909152600088815260078252604080822093851682529290915220548451859084908110613ee257fe5b602090810291909101015250600101613e7d565b5050915091565b60008181526001602052604090206060908190613f198161432b565b67ffffffffffffffff81118015613f2f57600080fd5b50604051908082528060200260200182016040528015613f59578160200160208202803683370190505b509250825167ffffffffffffffff81118015613f7457600080fd5b50604051908082528060200260200182016040528015613f9e578160200160208202803683370190505b50915060005b8351811015613ef657613fb782826148a2565b858381518110613fc357fe5b60200260200101858481518110613fd657fe5b60209081029190910101919091526001600160a01b039091169052600101613fa4565b6000614004826127b4565b61400d836127a1565b0192915050565b60008183101561402457816116f2565b5090919050565b600081831061402457816116f2565b6001600160a01b038085166000818152600b602090815260408083209488168084529490915290819020859055517f18e1ea4139e68413d7d08aa752e71568e36b2c5bf940893314c2c5b01eaa0c42906119d0908590615d3e565b6000806140a06148c6565b9050428110156140b45760009150506116f5565b60006140be6148d2565b9050806140d0576000925050506116f5565b6000816140db6149e3565b80516020918201206040516140f7939233918a91899101615dc4565b604051602081830303815290604052805190602001209050600061411a82614a32565b90506000806000614129614a4e565b9250925092506000600185858585604051600081526020016040526040516141549493929190615e1c565b6020604051602081039080840390855afa158015614176573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906141ac57508a6001600160a01b0316816001600160a01b0316145b9b9a5050505050505050505050565b6000806000806141ca86613ff9565b905060006141d786613ff9565b90506141ee6141e5886127ca565b612a3f886127ca565b60a08a01526040517f9d2c110c0000000000000000000000000000000000000000000000000000000081526001600160a01b03891690639d2c110c9061423c908c9086908690600401615e94565b602060405180830381600087803b15801561425657600080fd5b505af115801561426a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061428e9190615968565b92506000806142a68b600001518c6060015187612ff7565b90925090506142b58983614345565b96506142c18882614376565b9550505050509450945094915050565b6000806142e96142e0856127ca565b612a3f856127ca565b90506109e16142f7856127a1565b614300856127a1565b8363ffffffff16614a75565b6001600160a01b03166000908152600291909101602052604090205490565b5490565b6000908152600191820160205260409020015490565b60008061435b83614355866127a1565b90611945565b90506000614368856127b4565b9050436112a6838383614a83565b60008061435b83614386866127a1565b90614abc565b60009182526001928301602052604090912090910155565b600080826001600160a01b0316846001600160a01b0316106143c75782846143ca565b83835b915091509250929050565b600082826040516020016143ea929190615b06565b60405160208183030381529060405280519060200120905092915050565b60006116f2614416846127a1565b61441f846127a1565b614428866127ca565b614a83565b60006116f261443b846127b4565b61441f846127b4565b6001600160a01b038216600090815260028401602052604081205461446b8115158461054b565b614478856001830361432f565b95945050505050565b600061448b6113af565b6001600160a01b03166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b1580156144c357600080fd5b505afa1580156144d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190615968565b610fa0828414801561450c57508183145b606761054b565b6060835167ffffffffffffffff8111801561452d57600080fd5b50604051908082528060200260200182016040528015614557578160200160208202803683370190505b50905060005b85515181101561465057600084828151811061457557fe5b602002602001015190506145a58760200151838151811061459257fe5b60200260200101518210156101f961054b565b6000876000015183815181106145b757fe5b602002602001015190506145d181838b8b60600151611d38565b60008584815181106145df57fe5b602002602001015190506145fb6145f583611b41565b82611f11565b61462a6146088483611945565b89868151811061461457fe5b602002602001015161437690919063ffffffff16565b85858151811061463657fe5b60200260200101818152505050505080600101905061455d565b5095945050505050565b60606000845167ffffffffffffffff8111801561467657600080fd5b506040519080825280602002602001820160405280156146a0578160200160208202803683370190505b50915060005b8651518110156147c65760008582815181106146be57fe5b602002602001015190506146ee886020015183815181106146db57fe5b60200260200101518211156101fa61054b565b60008860000151838151811061470057fe5b6020026020010151905061471a81838c8c60600151611c5a565b61472381611938565b15614735576147328483611945565b93505b600086848151811061474357fe5b602002602001015190506147596145f583611b41565b80831015614778576147738382038a868151811061461457fe5b6147a0565b6147a08184038a868151811061478a57fe5b602002602001015161434590919063ffffffff16565b8685815181106147ac57fe5b6020026020010181815250505050508060010190506146a6565b50614650816119de565b6001600160a01b031660009081526002919091016020526040902054151590565b610e008383614ad284614b0d565b610e008383614ad284614bb8565b610e008383614ad284614c13565b610e008383614c6284614b0d565b610e008383614c6284614bb8565b610e008383614c6284614c13565b60006109e18484614c8385614b0d565b60006109e18484614c8385614bb8565b60006109e18484614c8385614c13565b600082600001828154811061488657fe5b6000918252602090912001546001600160a01b03169392505050565b600090815260019182016020526040902080549101546001600160a01b0390911691565b60006112ce6000614c9d565b6000803560e01c8063b95cac28811461491a57638bdb39138114614942576352bbbe29811461496a5763945bcec981146149925763fa6e671d81146149ba57600092506149de565b7f3f7b71252bd19113ff48c19c6e004a9bcfcca320a0d74d58e85877cbd7dcae5892506149de565b7f8bbc57f66ea936902f50a71ce12b92c43f3c5340bb40c27c4e90ab84eeae335392506149de565b7fe192dcbc143b1e244ad73b813fd3c097b832ad260a157340b4e5e5beda067abe92506149de565b7f9bfc43a4d98313c6766986ffd7c916c7481566d9f224c6819af0a53388aced3a92506149de565b7fa3f865aa351e51cfeb40f5178d1564bb629fe9030b83caf6361d1baaf5b90b5a92505b505090565b60606000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505082519293505050608010156105485760803603815290565b6000614a3c61289b565b8260405160200161112e929190615b2d565b6000806000614a5d6020614c9d565b9250614a696040614c9d565b91506108416060614c9d565b60e01b60709190911b010190565b6000838301614ab1858210801590614aa957506e01000000000000000000000000000082105b61020e61054b565b614478858585614a75565b6000614acc83831115600161054b565b50900390565b600080614ae283614386866127a1565b90506000614af384614355876127b4565b90506000614b00866127ca565b90506112a6838383614a83565b6000806000806000614b1e89613a19565b9450509350935093506000836001600160a01b0316896001600160a01b03161415614b69576000614b5384898b63ffffffff16565b9050614b5f8185614ca7565b9093509050614b8b565b6000614b7983898b63ffffffff16565b9050614b858184614ca7565b90925090505b614b9583836142d1565b8555614ba18383614cc3565b600190950194909455509192505050949350505050565b600080614bc5868661271b565b90506000614bd782858763ffffffff16565b60008881526007602090815260408083206001600160a01b038b16845290915290208190559050614c088183614ca7565b979650505050505050565b600084815260016020526040812081614c2c8287613412565b90506000614c3e82868863ffffffff16565b9050614c4b838883613175565b50614c568183614ca7565b98975050505050505050565b600080614c7283614355866127a1565b90506000614af384614386876127b4565b600080614c8f846127a1565b905043614478828583614a83565b3601607f19013590565b6000614cb2826127b4565b614cbb846127b4565b039392505050565b60006116f2614cd1846127b4565b614cda846127b4565b6000614a75565b60408051610120810190915280600081526000602082018190526040820181905260608083018290526080830182905260a0830182905260c0830182905260e08301919091526101009091015290565b604080516080810190915280600081526000602082018190526040820181905260609091015290565b60405180608001604052806060815260200160608152602001606081526020016000151581525090565b6040518060a0016040528060008019168152602001600081526020016000815260200160008152602001606081525090565b80356116f581615f5a565b600082601f830112614dd1578081fd5b8135614de4614ddf82615f04565b615edd565b818152915060208083019084810181840286018201871015614e0557600080fd5b60005b84811015614e2d578135614e1b81615f5a565b84529282019290820190600101614e08565b505050505092915050565b600082601f830112614e48578081fd5b8135614e56614ddf82615f04565b818152915060208083019084810160005b84811015614e2d578135870160a080601f19838c03011215614e8857600080fd5b614e9181615edd565b85830135815260408084013587830152606080850135828401526080915081850135818401525082840135925067ffffffffffffffff831115614ed357600080fd5b614ee18c8885870101614fc0565b90820152865250509282019290820190600101614e67565b600082601f830112614f09578081fd5b8135614f17614ddf82615f04565b818152915060208083019084810181840286018201871015614f3857600080fd5b60005b84811015614e2d57813584529282019290820190600101614f3b565b600082601f830112614f67578081fd5b8151614f75614ddf82615f04565b818152915060208083019084810181840286018201871015614f9657600080fd5b60005b84811015614e2d57815184529282019290820190600101614f99565b80356116f581615f6f565b600082601f830112614fd0578081fd5b813567ffffffffffffffff811115614fe6578182fd5b614ff9601f8201601f1916602001615edd565b915080825283602082850101111561501057600080fd5b8060208401602084013760009082016020015292915050565b80356116f581615f7d565b8035600281106116f557600080fd5b8035600481106116f557600080fd5b600060808284031215615063578081fd5b61506d6080615edd565b9050813567ffffffffffffffff8082111561508757600080fd5b61509385838601614dc1565b835260208401359150808211156150a957600080fd5b6150b585838601614ef9565b602084015260408401359150808211156150ce57600080fd5b506150db84828501614fc0565b6040830152506150ee8360608401614fb5565b606082015292915050565b60006080828403121561510a578081fd5b6151146080615edd565b9050813561512181615f5a565b8152602082013561513181615f6f565b6020820152604082013561514481615f5a565b604082015260608201356150ee81615f6f565b600060208284031215615168578081fd5b81356116f281615f5a565b60008060408385031215615185578081fd5b823561519081615f5a565b915060208301356151a081615f5a565b809150509250929050565b6000806000606084860312156151bf578081fd5b83356151ca81615f5a565b925060208401356151da81615f5a565b915060408401356151ea81615f6f565b809150509250925092565b60008060408385031215615207578182fd5b823561521281615f5a565b9150602083013567ffffffffffffffff81111561522d578182fd5b61523985828601614dc1565b9150509250929050565b60006020808385031215615255578182fd5b823567ffffffffffffffff81111561526b578283fd5b8301601f8101851361527b578283fd5b8035615289614ddf82615f04565b818152838101908385016080808502860187018a10156152a7578788fd5b8795505b848610156153105780828b0312156152c1578788fd5b6152ca81615edd565b6152d48b84615029565b8152878301358882015260406152ec8c828601614db6565b908201526060838101359082015284526001959095019492860192908101906152ab565b509098975050505050505050565b60006020808385031215615330578182fd5b823567ffffffffffffffff811115615346578283fd5b8301601f81018513615356578283fd5b8035615364614ddf82615f04565b8181528381019083850160a0808502860187018a1015615382578788fd5b8795505b848610156153105780828b03121561539c578788fd5b6153a581615edd565b6153af8b84615043565b81526153bd8b898501614db6565b818901526040838101359082015260606153d98c828601614db6565b9082015260806153eb8c858301614db6565b908201528452600195909501949286019290810190615386565b60008060408385031215615417578182fd5b825167ffffffffffffffff8082111561542e578384fd5b61543a86838701614f57565b9350602085015191508082111561544f578283fd5b5061523985828601614f57565b60006020828403121561546d578081fd5b81356116f281615f6f565b600060208284031215615489578081fd5b81516116f281615f6f565b6000602082840312156154a5578081fd5b5035919050565b600080600080608085870312156154c1578182fd5b8435935060208501356154d381615f5a565b925060408501356154e381615f5a565b9150606085013567ffffffffffffffff8111156154fe578182fd5b61550a87828801615052565b91505092959194509250565b60008060408385031215615528578182fd5b82359150602083013567ffffffffffffffff81111561522d578182fd5b600080600060608486031215615559578081fd5b8335925060208085013567ffffffffffffffff80821115615578578384fd5b61558488838901614dc1565b94506040870135915080821115615599578384fd5b508501601f810187136155aa578283fd5b80356155b8614ddf82615f04565b81815283810190838501858402850186018b10156155d4578687fd5b8694505b838510156155ff5780356155eb81615f5a565b8352600194909401939185019185016155d8565b5080955050505050509250925092565b60008060408385031215615621578182fd5b8235915060208301356151a081615f5a565b600060208284031215615644578081fd5b81356001600160e01b0319811681146116f2578182fd5b60008060008060808587031215615670578182fd5b843561567b81615f5a565b9350602085013567ffffffffffffffff80821115615697578384fd5b6156a388838901614dc1565b945060408701359150808211156156b8578384fd5b6156c488838901614ef9565b935060608701359150808211156156d9578283fd5b5061550a87828801614fc0565b6000602082840312156156f7578081fd5b81356116f281615f7d565b60008060008060e08587031215615717578182fd5b6157218686615034565b9350602085013567ffffffffffffffff8082111561573d578384fd5b61574988838901614e38565b9450604087013591508082111561575e578384fd5b5061576b87828801614dc1565b92505061577b86606087016150f9565b905092959194509250565b600080600080600080610120878903121561579f578384fd5b6157a98888615034565b955060208088013567ffffffffffffffff808211156157c6578687fd5b6157d28b838c01614e38565b975060408a01359150808211156157e7578687fd5b6157f38b838c01614dc1565b96506158028b60608c016150f9565b955060e08a0135915080821115615817578485fd5b508801601f81018a13615828578384fd5b8035615836614ddf82615f04565b81815283810190838501858402850186018e1015615852578788fd5b8794505b83851015615874578035835260019490940193918501918501615856565b50809650505050505061010087013590509295509295509295565b60008060008060e085870312156158a4578182fd5b843567ffffffffffffffff808211156158bb578384fd5b9086019060c082890312156158ce578384fd5b6158d860c0615edd565b823581526158e98960208501615034565b602082015260408301356158fc81615f5a565b604082015261590e8960608501614db6565b60608201526080830135608082015260a08301358281111561592e578586fd5b61593a8a828601614fc0565b60a08301525080965050505061595386602087016150f9565b939693955050505060a08201359160c0013590565b600060208284031215615979578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208085019450808401835b838110156159c55781516001600160a01b0316875295820195908201906001016159a0565b509495945050505050565b6000815180845260208085019450808401835b838110156159c5578151875295820195908201906001016159e3565b60008151808452615a17816020860160208601615f24565b601f01601f19169290920160200192915050565b6000610120825160028110615a3c57fe5b808552506020830151615a526020860182615980565b506040830151615a656040860182615980565b50606083015160608501526080830151608085015260a083015160a085015260c0830151615a9660c0860182615980565b5060e0830151615aa960e0860182615980565b506101008084015182828701526112a6838701826159ff565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b60008251615afc818460208701615f24565b9190910192915050565b6bffffffffffffffffffffffff19606093841b811682529190921b16601482015260280190565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038316815260408101615bb483615f50565b8260208301529392505050565b6001600160a01b03929092168252602082015260400190565b6000602082526116f2602083018461598d565b600060408252615c00604083018561598d565b828103602084810191909152845180835285820192820190845b81811015615c3f5784516001600160a01b031683529383019391830191600101615c1a565b5090979650505050505050565b600060608252615c5f606083018661598d565b8281036020840152615c7181866159d0565b905082810360408401526112a681856159d0565b600060808252615c98608083018761598d565b8281036020840152615caa81876159d0565b90508281036040840152615cbe81866159d0565b90508281036060840152614c0881856159ff565b600060608252615ce5606083018661598d565b8281036020840152615cf781866159d0565b915050826040830152949350505050565b6000602082526116f260208301846159d0565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60008882526001600160a01b03808916602084015280881660408401525060e06060830152615d9860e08301876159d0565b8560808401528460a084015282810360c0840152615db681856159ff565b9a9950505050505050505050565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b60208101615e4783615f50565b91905290565b918252602082015260400190565b600060808252615e6e6080830187615a2b565b8281036020840152615e8081876159d0565b604084019590955250506060015292915050565b600060608252615ea76060830186615a2b565b60208301949094525060400152919050565b938452602084019290925260408301526001600160a01b0316606082015260800190565b60405181810167ffffffffffffffff81118282101715615efc57600080fd5b604052919050565b600067ffffffffffffffff821115615f1a578081fd5b5060209081020190565b60005b83811015615f3f578181015183820152602001615f27565b83811115610e005750506000910152565b6003811061057e57fe5b6001600160a01b038116811461057e57600080fd5b801515811461057e57600080fd5b6003811061057e57600080fdfea2646970667358221220201e4f926e390fed8dd5318c58846af735c2bebc61b80693ae936a5fe76dcf1464736f6c6343000701003360c060405234801561001057600080fd5b50604051610be6380380610be683398101604081905261002f9161004d565b30608052600160005560601b6001600160601b03191660a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160a05160601c610b406100a66000398061041352806105495250806102a75250610b406000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063851c1bb311610076578063d877845c1161005b578063d877845c14610129578063e42abf3514610131578063fbfa77cf14610151576100a3565b8063851c1bb314610101578063aaabadc514610114576100a3565b806338e9922e146100a857806355c67628146100bd5780636b6b9f69146100db5780636daefab6146100ee575b600080fd5b6100bb6100b636600461099c565b610159565b005b6100c56101b8565b6040516100d29190610aa6565b60405180910390f35b6100bb6100e936600461099c565b6101be565b6100bb6100fc3660046107d1565b610211565b6100c561010f366004610924565b6102a3565b61011c6102f5565b6040516100d29190610a35565b6100c5610304565b61014461013f366004610852565b61030a565b6040516100d29190610a62565b61011c610411565b610161610435565b6101786706f05b59d3b2000082111561025861047e565b60018190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc906101ad908390610aa6565b60405180910390a150565b60015490565b6101c6610435565b6101dc662386f26fc1000082111561025961047e565b60028190556040517f5a0b7386237e7f07fa741efc64e59c9387d2cccafec760efed4d53387f20e19a906101ad908390610aa6565b610219610490565b610221610435565b61022b84836104a9565b60005b8481101561029357600086868381811061024457fe5b90506020020160208101906102599190610980565b9050600085858481811061026957fe5b6020029190910135915061028990506001600160a01b03831685836104b6565b505060010161022e565b5061029c61053e565b5050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016102d89291906109cc565b604051602081830303815290604052805190602001209050919050565b60006102ff610545565b905090565b60025490565b6060815167ffffffffffffffff8111801561032457600080fd5b5060405190808252806020026020018201604052801561034e578160200160208202803683370190505b50905060005b825181101561040b5782818151811061036957fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161039c9190610a35565b60206040518083038186803b1580156103b457600080fd5b505afa1580156103c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ec91906109b4565b8282815181106103f857fe5b6020908102919091010152600101610354565b50919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006104646000357fffffffff00000000000000000000000000000000000000000000000000000000166102a3565b905061047b61047382336105d8565b61019161047e565b50565b8161048c5761048c8161066a565b5050565b6104a26002600054141561019061047e565b6002600055565b61048c818314606761047e565b6105398363a9059cbb60e01b84846040516024016104d5929190610a49565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526106d7565b505050565b6001600055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b1580156105a057600080fd5b505afa1580156105b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ff9190610964565b60006105e2610545565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b815260040161061193929190610aaf565b60206040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066191906108fd565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006060836001600160a01b0316836040516106f391906109fc565b6000604051808303816000865af19150503d8060008114610730576040519150601f19603f3d011682016040523d82523d6000602084013e610735565b606091505b5091509150600082141561074d573d6000803e3d6000fd5b61077781516000148061076f57508180602001905181019061076f91906108fd565b6101a261047e565b50505050565b60008083601f84011261078e578182fd5b50813567ffffffffffffffff8111156107a5578182fd5b60208301915083602080830285010111156107bf57600080fd5b9250929050565b803561066481610af5565b6000806000806000606086880312156107e8578081fd5b853567ffffffffffffffff808211156107ff578283fd5b61080b89838a0161077d565b90975095506020880135915080821115610823578283fd5b506108308882890161077d565b909450925050604086013561084481610af5565b809150509295509295909350565b60006020808385031215610864578182fd5b823567ffffffffffffffff8082111561087b578384fd5b818501915085601f83011261088e578384fd5b81358181111561089c578485fd5b83810291506108ac848301610ace565b8181528481019084860184860187018a10156108c6578788fd5b8795505b838610156108f0576108dc8a826107c6565b8352600195909501949186019186016108ca565b5098975050505050505050565b60006020828403121561090e578081fd5b8151801515811461091d578182fd5b9392505050565b600060208284031215610935578081fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461091d578182fd5b600060208284031215610975578081fd5b815161091d81610af5565b600060208284031215610991578081fd5b813561091d81610af5565b6000602082840312156109ad578081fd5b5035919050565b6000602082840312156109c5578081fd5b5051919050565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260240190565b60008251815b81811015610a1c5760208186018101518583015201610a02565b81811115610a2a5782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015610a9a57835183529284019291840191600101610a7e565b50909695505050505050565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60405181810167ffffffffffffffff81118282101715610aed57600080fd5b604052919050565b6001600160a01b038116811461047b57600080fdfea2646970667358221220be72bdf8e7a3c38606c5f954fbe2d77798347aaa1cfb76fe77ec2f6c245d24bc64736f6c63430007010033", + "_disabled": [ { - "inputs": [], - "name": "getDomainSeparator", - "outputs": [ + "inputs": [ { "internalType": "bytes32", - "name": "", + "name": "poolId", "type": "bytes32" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" } ], - "stateMutability": "view", + "name": "deregisterTokens", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, { "internalType": "address", - "name": "user", + "name": "sender", "type": "address" }, { - "internalType": "contract IERC20[]", - "name": "tokens", - "type": "address[]" - } - ], - "name": "getInternalBalance", - "outputs": [ + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, { - "internalType": "uint256[]", - "name": "balances", - "type": "uint256[]" + "components": [ + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.ExitPoolRequest", + "name": "request", + "type": "tuple" } ], - "stateMutability": "view", + "name": "exitPool", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "user", - "type": "address" + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" } ], - "name": "getNextNonce", + "name": "getActionId", "outputs": [ { - "internalType": "uint256", + "internalType": "bytes32", "name": "", - "type": "uint256" + "type": "bytes32" } ], "stateMutability": "view", @@ -636,46 +849,44 @@ }, { "inputs": [], - "name": "getPausedState", + "name": "getAuthorizer", "outputs": [ { - "internalType": "bool", - "name": "paused", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "pauseWindowEndTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "bufferPeriodEndTime", - "type": "uint256" + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getDomainSeparator", + "outputs": [ { "internalType": "bytes32", - "name": "poolId", + "name": "", "type": "bytes32" } ], - "name": "getPool", - "outputs": [ + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "address", - "name": "", + "name": "user", "type": "address" - }, + } + ], + "name": "getNextNonce", + "outputs": [ { - "internalType": "enum IVault.PoolSpecialization", + "internalType": "uint256", "name": "", - "type": "uint8" + "type": "uint256" } ], "stateMutability": "view", @@ -720,35 +931,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" - } - ], - "name": "getPoolTokens", - "outputs": [ - { - "internalType": "contract IERC20[]", - "name": "tokens", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "balances", - "type": "uint256[]" - }, - { - "internalType": "uint256", - "name": "lastChangeBlock", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "getProtocolFeesCollector", @@ -762,30 +944,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "relayer", - "type": "address" - } - ], - "name": "hasApprovedRelayer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -871,46 +1029,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "components": [ - { - "internalType": "enum IVault.UserBalanceOpKind", - "name": "kind", - "type": "uint8" - }, - { - "internalType": "contract IAsset", - "name": "asset", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - } - ], - "internalType": "struct IVault.UserBalanceOp[]", - "name": "ops", - "type": "tuple[]" - } - ], - "name": "manageUserBalance", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -1061,122 +1179,6 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "relayer", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setRelayerApproval", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" - }, - { - "internalType": "enum IVault.SwapKind", - "name": "kind", - "type": "uint8" - }, - { - "internalType": "contract IAsset", - "name": "assetIn", - "type": "address" - }, - { - "internalType": "contract IAsset", - "name": "assetOut", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - } - ], - "internalType": "struct IVault.SingleSwap", - "name": "singleSwap", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "bool", - "name": "fromInternalBalance", - "type": "bool" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - }, - { - "internalType": "bool", - "name": "toInternalBalance", - "type": "bool" - } - ], - "internalType": "struct IVault.FundManagement", - "name": "funds", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "limit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swap", - "outputs": [ - { - "internalType": "uint256", - "name": "amountCalculated", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" } - ], - "bytecode": "0x6101806040523480156200001257600080fd5b5060405162006ed638038062006ed6833981016040819052620000359162000253565b8382826040518060400160405280601181526020017010985b185b98d95c88158c8815985d5b1d607a1b81525080604051806040016040528060018152602001603160f81b815250306001600160a01b031660001b89806001600160a01b03166080816001600160a01b031660601b815250505030604051620000b89062000245565b620000c491906200029f565b604051809103906000f080158015620000e1573d6000803e3d6000fd5b5060601b6001600160601b03191660a052600160005560c052815160209283012060e052805191012061010052507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61012052620001486276a70083111561019462000181565b6200015c62278d0082111561019562000181565b429091016101408190520161016052620001768162000196565b5050505050620002cc565b8162000192576200019281620001f2565b5050565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b610be680620062f083390190565b6000806000806080858703121562000269578384fd5b84516200027681620002b3565b60208601519094506200028981620002b3565b6040860151606090960151949790965092505050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114620002c957600080fd5b50565b60805160601c60a05160601c60c05160e05161010051610120516101405161016051615fc06200033060003980611aed525080611ac952508061289f5250806128e15250806128c05250806110fd5250806113b15250806105285250615fc06000f3fe6080604052600436106101a55760003560e01c8063945bcec9116100e1578063e6c460921161008a578063f84d066e11610064578063f84d066e1461048a578063f94d4668146104aa578063fa6e671d146104d9578063fec90d72146104f9576101d3565b8063e6c4609214610427578063ed24911d14610447578063f6c009271461045c576101d3565b8063b05f8e48116100bb578063b05f8e48146103cf578063b95cac28146103ff578063d2946c2b14610412576101d3565b8063945bcec914610385578063aaabadc514610398578063ad5c4648146103ba576101d3565b806352bbbe291161014e5780637d3aeb96116101285780637d3aeb9614610305578063851c1bb3146103255780638bdb39131461034557806390193b7c14610365576101d3565b806352bbbe29146102b25780635c38449e146102c557806366a9c7d2146102e5576101d3565b80630f5a6efa1161017f5780630f5a6efa1461024157806316c38b3c1461026e5780631c0de0511461028e576101d3565b8063058a628f146101d857806309b2760f146101f85780630e8e3e841461022e576101d3565b366101d3576101d16101b5610526565b6001600160a01b0316336001600160a01b03161461020661054b565b005b600080fd5b3480156101e457600080fd5b506101d16101f3366004615157565b61055d565b34801561020457600080fd5b506102186102133660046156e6565b610581565b6040516102259190615d3e565b60405180910390f35b6101d161023c36600461531e565b610634565b34801561024d57600080fd5b5061026161025c3660046151f5565b610770565b6040516102259190615d08565b34801561027a57600080fd5b506101d161028936600461545c565b610806565b34801561029a57600080fd5b506102a361081f565b60405161022593929190615d26565b6102186102c036600461588f565b610848565b3480156102d157600080fd5b506101d16102e036600461565b565b6109e9565b3480156102f157600080fd5b506101d1610300366004615545565b610e06565b34801561031157600080fd5b506101d1610320366004615516565b610fa5565b34801561033157600080fd5b50610218610340366004615633565b6110f9565b34801561035157600080fd5b506101d16103603660046154ac565b61114b565b34801561037157600080fd5b50610218610380366004615157565b611161565b610261610393366004615786565b61117c565b3480156103a457600080fd5b506103ad6112b0565b6040516102259190615b63565b3480156103c657600080fd5b506103ad6112c4565b3480156103db57600080fd5b506103ef6103ea36600461560f565b6112d3565b6040516102259493929190615eb9565b6101d161040d3660046154ac565b611396565b34801561041e57600080fd5b506103ad6113af565b34801561043357600080fd5b506101d1610442366004615243565b6113d3565b34801561045357600080fd5b506102186114ef565b34801561046857600080fd5b5061047c610477366004615494565b6114f9565b604051610225929190615b9b565b34801561049657600080fd5b506102616104a5366004615702565b611523565b3480156104b657600080fd5b506104ca6104c5366004615494565b611620565b60405161022593929190615cd2565b3480156104e557600080fd5b506101d16104f43660046151ab565b611654565b34801561050557600080fd5b50610519610514366004615173565b6116e6565b6040516102259190615d1b565b7f00000000000000000000000000000000000000000000000000000000000000005b90565b8161055957610559816116fb565b5050565b610565611768565b61056d611781565b610576816117af565b61057e611822565b50565b600061058b611768565b610593611829565b60006105a2338460065461183e565b6000818152600560205260409020549091506105c49060ff16156101f461054b565b60008181526005602052604090819020805460ff1916600190811790915560068054909101905551339082907f3c13bc30b8e878c53fd2a36b679409c073afd75950be43d8858768e956fbc20e9061061d908790615e3a565b60405180910390a3905061062f611822565b919050565b61063c611768565b6000806000805b845181101561075b5760008060008060006106718a878151811061066357fe5b60200260200101518961187d565b9c50939850919650945092509050600185600381111561068d57fe5b14156106a45761069f848383866118f5565b61074a565b866106b6576106b1611829565b600196505b60008560038111156106c457fe5b14156106f5576106d684838386611918565b6106df84611938565b1561069f576106ee8984611945565b985061074a565b61070a61070185611938565b1561020761054b565b600061071585610548565b9050600286600381111561072557fe5b141561073c5761073781848487611957565b610748565b61074881848487611970565b505b505060019093019250610643915050565b50610765836119de565b50505061057e611822565b6060815167ffffffffffffffff8111801561078a57600080fd5b506040519080825280602002602001820160405280156107b4578160200160208202803683370190505b50905060005b82518110156107ff576107e0848483815181106107d357fe5b6020026020010151611a01565b8282815181106107ec57fe5b60209081029190910101526001016107ba565b5092915050565b61080e611768565b610816611781565b61057681611a2c565b600080600061082c611aaa565b159250610837611ac7565b9150610841611aeb565b9050909192565b6000610852611768565b61085a611829565b835161086581611b0f565b610874834211156101fc61054b565b61088760008760800151116101fe61054b565b60006108968760400151611b41565b905060006108a78860600151611b41565b90506108ca816001600160a01b0316836001600160a01b031614156101fd61054b565b6108d2614ce1565b885160808201526020890151819060018111156108eb57fe5b908160018111156108f857fe5b9052506001600160a01b03808416602083015282811660408084019190915260808b0151606084015260a08b01516101008401528951821660c08401528901511660e082015260008061094a83611b66565b9198509250905061098160008c60200151600181111561096657fe5b146109745789831115610979565b898210155b6101fb61054b565b6109998b60400151838c600001518d60200151611c5a565b6109b18b60600151828c604001518d60600151611d38565b6109d36109c18c60400151611938565b6109cc5760006109ce565b825b6119de565b5050505050506109e1611822565b949350505050565b6109f1611768565b6109f9611829565b610a0583518351611e12565b6060835167ffffffffffffffff81118015610a1f57600080fd5b50604051908082528060200260200182016040528015610a49578160200160208202803683370190505b5090506060845167ffffffffffffffff81118015610a6657600080fd5b50604051908082528060200260200182016040528015610a90578160200160208202803683370190505b5090506000805b8651811015610c09576000878281518110610aae57fe5b602002602001015190506000878381518110610ac657fe5b60200260200101519050610b11846001600160a01b0316836001600160a01b03161160006001600160a01b0316846001600160a01b031614610b09576066610b0c565b60685b61054b565b819350816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b409190615b63565b60206040518083038186803b158015610b5857600080fd5b505afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190615968565b858481518110610b9c57fe5b602002602001018181525050610bb181611e1f565b868481518110610bbd57fe5b602002602001018181525050610beb81868581518110610bd957fe5b6020026020010151101561021061054b565b610bff6001600160a01b0383168b83611ea6565b5050600101610a97565b506040517ff04f27070000000000000000000000000000000000000000000000000000000081526001600160a01b0388169063f04f270790610c55908990899088908a90600401615c85565b600060405180830381600087803b158015610c6f57600080fd5b505af1158015610c83573d6000803e3d6000fd5b5050505060005b8651811015610df4576000878281518110610ca157fe5b602002602001015190506000848381518110610cb957fe5b602002602001015190506000826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610cf19190615b63565b60206040518083038186803b158015610d0957600080fd5b505afa158015610d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d419190615968565b9050610d528282101561020361054b565b60008282039050610d7b888681518110610d6857fe5b602002602001015182101561025a61054b565b610d858482611f11565b836001600160a01b03168c6001600160a01b03167f0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f08c8881518110610dc657fe5b602002602001015184604051610ddd929190615e4d565b60405180910390a350505050806001019050610c8a565b50505050610e00611822565b50505050565b610e0e611768565b610e16611829565b82610e2081611f33565b610e2c83518351611e12565b60005b8351811015610eca576000848281518110610e4657fe5b60200260200101519050610e7260006001600160a01b0316826001600160a01b0316141561013561054b565b838281518110610e7e57fe5b6020908102919091018101516000888152600a835260408082206001600160a01b0395861683529093529190912080546001600160a01b03191692909116919091179055600101610e2f565b506000610ed685611f64565b90506002816002811115610ee657fe5b1415610f3457610efc845160021461020c61054b565b610f2f8585600081518110610f0d57fe5b602002602001015186600181518110610f2257fe5b6020026020010151611f7e565b610f5c565b6001816002811115610f4257fe5b1415610f5257610f2f858561202a565b610f5c8585612082565b847ff5847d3f2197b16cdcd2098ec95d0905cd1abdaf415f07bb7cef2bba8ac5dec48585604051610f8e929190615bed565b60405180910390a25050610fa0611822565b505050565b610fad611768565b610fb5611829565b81610fbf81611f33565b6000610fca84611f64565b90506002816002811115610fda57fe5b141561102857610ff0835160021461020c61054b565b611023848460008151811061100157fe5b60200260200101518560018151811061101657fe5b60200260200101516120d7565b611050565b600181600281111561103657fe5b1415611046576110238484612145565b61105084846121ff565b60005b83518110156110b657600a6000868152602001908152602001600020600085838151811061107d57fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002080546001600160a01b0319169055600101611053565b50837f7dcdc6d02ef40c7c1a7046a011b058bd7f988fa14e20a66344f9d4e60657d610846040516110e79190615bda565b60405180910390a25050610559611822565b60007f00000000000000000000000000000000000000000000000000000000000000008260405160200161112e929190615ac2565b604051602081830303815290604052805190602001209050919050565b610e00600185858561115c86612262565b61226e565b6001600160a01b031660009081526002602052604090205490565b6060611186611768565b61118e611829565b835161119981611b0f565b6111a8834211156101fc61054b565b6111b486518551611e12565b6111c08787878b6123f4565b91506000805b87518110156112925760008882815181106111dd57fe5b6020026020010151905060008583815181106111f557fe5b6020026020010151905061122188848151811061120e57fe5b60200260200101518213156101fb61054b565b600081131561126157885160208a015182916112409185918491611c5a565b61124983611938565b1561125b576112588582611945565b94505b50611288565b600081121561128857600081600003905061128683828c604001518d60600151611d38565b505b50506001016111c6565b5061129c816119de565b50506112a6611822565b9695505050505050565b60035461010090046001600160a01b031690565b60006112ce610526565b905090565b600080600080856112e381612683565b6000806112ef89611f64565b905060028160028111156112ff57fe5b14156113165761130f89896126a1565b9150611341565b600181600281111561132457fe5b14156113345761130f898961271b565b61133e8989612789565b91505b61134a826127a1565b9650611355826127b4565b9550611360826127ca565b6000998a52600a60209081526040808c206001600160a01b039b8c168d5290915290992054969995989796909616955050505050565b61139e611829565b610e00600085858561115c86612262565b7f000000000000000000000000000000000000000000000000000000000000000090565b6113db611768565b6113e3611829565b6113eb614d31565b60005b82518110156114e55782818151811061140357fe5b6020026020010151915060008260200151905061141f81612683565b604083015161143961143183836127d0565b61020961054b565b6000828152600a602090815260408083206001600160a01b03858116855292529091205461146c911633146101f661054b565b835160608501516000806114828487878661282c565b91509150846001600160a01b0316336001600160a01b0316877f6edcaf6241105b4c94c2efdbf3a6b12458eb3d07be3a0e81d24b13c44045fe7a85856040516114cc929190615e4d565b60405180910390a45050505050508060010190506113ee565b505061057e611822565b60006112ce61289b565b6000808261150681612683565b61150f84612938565b61151885611f64565b925092505b50915091565b60603330146115f6576000306001600160a01b0316600036604051611549929190615ada565b6000604051808303816000865af19150503d8060008114611586576040519150601f19603f3d011682016040523d82523d6000602084013e61158b565b606091505b50509050806000811461159a57fe5b60046000803e6000516001600160e01b0319167ffa61cc120000000000000000000000000000000000000000000000000000000081146115de573d6000803e3d6000fd5b50602060005260043d0380600460203e602081016000f35b6060611604858585896123f4565b9050602081510263fa61cc126020830352600482036024820181fd5b60608060008361162f81612683565b606061163a8661293e565b9095509050611648816129a0565b95979096509350505050565b61165c611768565b611664611829565b8261166e81611b0f565b6001600160a01b0384811660008181526004602090815260408083209488168084529490915290819020805460ff1916861515179055519091907f46961fdb4502b646d5095fba7600486a8ac05041d55cdf0f16ed677180b5cad8906116d5908690615d1b565b60405180910390a350610fa0611822565b60006116f28383612a4f565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b61177a6002600054141561019061054b565b6002600055565b60006117986000356001600160e01b0319166110f9565b905061057e6117a78233612a7d565b61019161054b565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b6001600055565b61183c611834611aaa565b61019261054b565b565b600069ffffffffffffffffffff8216605084600281111561185b57fe5b901b17606085901b6bffffffffffffffffffffffff19161790505b9392505050565b600080600080600080600088606001519050336001600160a01b0316816001600160a01b0316146118cf57876118ba576118b5611781565b600197505b6118cf6118c78233612a4f565b6101f761054b565b885160208a015160408b01516080909b0151919b909a9992985090965090945092505050565b61190a8361190286611b41565b836000612b20565b50610e008482846000611d38565b61192b8261192586611b41565b83612b76565b610e008482856000611c5a565b6001600160a01b03161590565b60008282016116f2848210158361054b565b6119648385836000612b20565b50610e00828583612b76565b8015610e005761198b6001600160a01b038516848484612ba6565b826001600160a01b0316846001600160a01b03167f540a1a3f28340caec336c81d8d7b3df139ee5cdc1839a4f283d7ebb7eaae2d5c84846040516119d0929190615bc1565b60405180910390a350505050565b6119ed8134101561020461054b565b348190038015610559576105593382612bc7565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205490565b8015611a4c57611a47611a3d611ac7565b421061019361054b565b611a61565b611a61611a57611aeb565b42106101a961054b565b6003805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490611a9f908390615d1b565b60405180910390a150565b6000611ab4611aeb565b4211806112ce57505060035460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b336001600160a01b0382161461057e57611b27611781565b611b318133612a4f565b61057e5761057e816101f7612c41565b6000611b4c82611938565b611b5e57611b5982610548565b6116f5565b6116f5610526565b600080600080611b798560800151612938565b90506000611b8a8660800151611f64565b90506002816002811115611b9a57fe5b1415611bb157611baa8683612c75565b9450611bdc565b6001816002811115611bbf57fe5b1415611bcf57611baa8683612d25565b611bd98683612db8565b94505b611bef8660000151876060015187612ff7565b809450819550505085604001516001600160a01b031686602001516001600160a01b031687608001517f2170c741c41531aec20e7c107c24eecfdd15e69c9bb0a8dd37b1840b9e0b207b8787604051611c49929190615e4d565b60405180910390a450509193909250565b82611c6457610e00565b611c6d84611938565b15611cee57611c7f811561020261054b565b611c8e8347101561020461054b565b611c96610526565b6001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611cd057600080fd5b505af1158015611ce4573d6000803e3d6000fd5b5050505050610e00565b6000611cf985610548565b90508115611d16576000611d108483876001612b20565b90940393505b8315611d3157611d316001600160a01b038216843087612ba6565b5050505050565b82611d4257610e00565b611d4b84611938565b15611ddb57611d5d811561020261054b565b611d65610526565b6001600160a01b0316632e1a7d4d846040518263ffffffff1660e01b8152600401611d909190615d3e565b600060405180830381600087803b158015611daa57600080fd5b505af1158015611dbe573d6000803e3d6000fd5b50611dd6925050506001600160a01b03831684612bc7565b610e00565b6000611de685610548565b90508115611dfe57611df9838286612b76565b611d31565b611d316001600160a01b0382168486611ea6565b610559818314606761054b565b600080611e2a6113af565b6001600160a01b031663d877845c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6257600080fd5b505afa158015611e76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9a9190615968565b90506118768382613025565b610fa08363a9059cbb60e01b8484604051602401611ec5929190615bc1565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152613072565b801561055957610559611f226113af565b6001600160a01b0384169083611ea6565b611f3c81612683565b61057e611f4882612938565b6001600160a01b0316336001600160a01b0316146101f561054b565b600061ffff605083901c166116f5600382106101f461054b565b611f9f816001600160a01b0316836001600160a01b0316141561020a61054b565b611fbe816001600160a01b0316836001600160a01b031610606661054b565b60008381526009602052604090208054611ffb906001600160a01b0316158015611ff3575060018201546001600160a01b0316155b61020b61054b565b80546001600160a01b039384166001600160a01b03199182161782556001909101805492909316911617905550565b6000828152600860205260408120905b8251811015610e0057600061206b84838151811061205457fe5b60200260200101518461311290919063ffffffff16565b90506120798161020a61054b565b5060010161203a565b6000828152600160205260408120905b8251811015610e005760006120c08483815181106120ac57fe5b602090810291909101015184906000613175565b90506120ce8161020a61054b565b50600101612092565b60008060006120e7868686613222565b9250925092506121116120f9846132e9565b80156121095750612109836132e9565b61020d61054b565b600095865260096020526040862080546001600160a01b031990811682556001909101805490911690559490945550505050565b6000828152600860205260408120905b8251811015610e0057600083828151811061216c57fe5b602002602001015190506121b8612109600760008881526020019081526020016000206000846001600160a01b03166001600160a01b03168152602001908152602001600020546132e9565b60008581526007602090815260408083206001600160a01b038516845290915281208190556121e7848361330b565b90506121f58161020961054b565b5050600101612155565b6000828152600160205260408120905b8251811015610e0057600083828151811061222657fe5b60200260200101519050600061223c8483613412565b905061224a612109826132e9565b6122548483613421565b50505080600101905061220f565b61226a614d5a565b5090565b612276611768565b8361228081612683565b8361228a81611b0f565b61229e836000015151846020015151611e12565b60606122ad84600001516134c3565b905060606122bb8883613552565b905060608060606122d08c8c8c8c8c896135e3565b92509250925060006122e18c611f64565b905060028160028111156122f157fe5b1415612359576123548c8760008151811061230857fe5b60200260200101518660008151811061231d57fe5b60200260200101518960018151811061233257fe5b60200260200101518860018151811061234757fe5b60200260200101516137a8565b612382565b600181600281111561236757fe5b1415612378576123548c87866137e7565b6123828c85613854565b6000808e600181111561239157fe5b1490508b6001600160a01b03168d7fe5ce249087ce04f05a957192435400fd97868dba0e6a4b4c049abf8af80dae78896123cb888661389d565b876040516123db93929190615c4c565b60405180910390a3505050505050505050611d31611822565b6060835167ffffffffffffffff8111801561240e57600080fd5b50604051908082528060200260200182016040528015612438578160200160208202803683370190505b509050612443614d84565b61244b614ce1565b60008060005b89518110156126765789818151811061246657fe5b6020026020010151945060008951866020015110801561248a575089518660400151105b905061249781606461054b565b60006124b98b8860200151815181106124ac57fe5b6020026020010151611b41565b905060006124d08c8960400151815181106124ac57fe5b90506124f3816001600160a01b0316836001600160a01b031614156101fd61054b565b60608801516125435761250b600085116101fe61054b565b60006125188b8484613945565b6001600160a01b0316876001600160a01b031614905061253a816101ff61054b565b50606088018590525b87516080880152868a600181111561255757fe5b9081600181111561256457fe5b9052506001600160a01b0380831660208901528181166040808a01919091526060808b0151908a015260808a01516101008a01528c51821660c08a01528c01511660e08801526000806125b689611b66565b919850925090506125c88c8585613967565b97506125fc6125d683613981565b8c8c60200151815181106125e657fe5b60200260200101516139b190919063ffffffff16565b8b8b602001518151811061260c57fe5b60200260200101818152505061264a61262482613981565b8c8c604001518151811061263457fe5b60200260200101516139e590919063ffffffff16565b8b8b604001518151811061265a57fe5b6020026020010181815250505050505050806001019050612451565b5050505050949350505050565b60008181526005602052604090205461057e9060ff166101f461054b565b60008060008060006126b287613a19565b945094509450945050836001600160a01b0316866001600160a01b031614156126e157829450505050506116f5565b816001600160a01b0316866001600160a01b031614156127065793506116f592505050565b6127116102096116fb565b5050505092915050565b60008281526007602090815260408083206001600160a01b03851684529091528120548161274882613a8f565b80612766575060008581526008602052604090206127669085613aa1565b9050806127815761277685612683565b6127816102096116fb565b509392505050565b60008281526001602052604081206109e18184613412565b6dffffffffffffffffffffffffffff1690565b60701c6dffffffffffffffffffffffffffff1690565b60e01c90565b6000806127dc84611f64565b905060028160028111156127ec57fe5b1415612804576127fc8484613ac2565b9150506116f5565b600181600281111561281257fe5b1415612822576127fc8484613b13565b6127fc8484613b2b565b600080600061283a86611f64565b9050600087600281111561284a57fe5b14156128665761285c86828787613b43565b9250925050612892565b600187600281111561287457fe5b14156128865761285c86828787613bbe565b61285c86828787613c3a565b94509492505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612908613c9d565b3060405160200161291d959493929190615df0565b60405160208183030381529060405280519060200120905090565b60601c90565b606080600061294c84611f64565b9050600281600281111561295c57fe5b14156129755761296b84613ca1565b925092505061299b565b600181600281111561298357fe5b14156129925761296b84613dd6565b61296b84613efd565b915091565b60606000825167ffffffffffffffff811180156129bc57600080fd5b506040519080825280602002602001820160405280156129e6578160200160208202803683370190505b5091506000905060005b825181101561151d576000848281518110612a0757fe5b60200260200101519050612a1a81613ff9565b848381518110612a2657fe5b602002602001018181525050612a4483612a3f836127ca565b614014565b9250506001016129f0565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b6003546040517f9be2a88400000000000000000000000000000000000000000000000000000000815260009161010090046001600160a01b031690639be2a88490612ad090869086903090600401615d47565b60206040518083038186803b158015612ae857600080fd5b505afa158015612afc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f29190615478565b600080612b2d8686611a01565b9050612b468380612b3e5750848210155b61020161054b565b612b50818561402b565b9150818103612b6c878783612b6487613981565b60000361403a565b5050949350505050565b6000612b828484611a01565b90506000612b908284611945565b9050611d31858583612ba187613981565b61403a565b610e00846323b872dd60e01b858585604051602401611ec593929190615b77565b612bd6814710156101a361054b565b6000826001600160a01b031682604051612bef90610548565b60006040518083038185875af1925050503d8060008114612c2c576040519150601f19603f3d011682016040523d82523d6000602084013e612c31565b606091505b50509050610fa0816101a461054b565b6001600160a01b0382166000908152600260205260409020805460018101909155610fa0612c6f8483614095565b8361054b565b600080600080612c92866080015187602001518860400151613222565b92509250925060008087604001516001600160a01b031688602001516001600160a01b03161015612cc7575083905082612ccd565b50829050835b612cd9888884846141bb565b60408b015160208c01519199509294509092506001600160a01b03918216911610612d0d57612d0881836142d1565b612d17565b612d1782826142d1565b909255509295945050505050565b600080612d3a8460800151856020015161271b565b90506000612d508560800151866040015161271b565b9050612d5e858584846141bb565b6080880180516000908152600760208181526040808420828e01516001600160a01b03908116865290835281852098909855935183529081528282209a830151909516815298909352919096209590955550929392505050565b60808201516000908152600160209081526040822090840151829182918290612de290839061430c565b90506000612dfd88604001518461430c90919063ffffffff16565b9050811580612e0a575080155b15612e2757612e1c8860800151612683565b612e276102096116fb565b60001991820191016000612e3a8461432b565b905060608167ffffffffffffffff81118015612e5557600080fd5b50604051908082528060200260200182016040528015612e7f578160200160208202803683370190505b50600060a08c018190529091505b82811015612eff576000612ea1878361432f565b9050612eac81613ff9565b838381518110612eb857fe5b602002602001018181525050612ed58c60a00151612a3f836127ca565b60a08d015281861415612eea57809850612ef6565b84821415612ef6578097505b50600101612e8d565b506040517f01ec954a0000000000000000000000000000000000000000000000000000000081526001600160a01b038a16906301ec954a90612f4b908d90859089908990600401615e5b565b602060405180830381600087803b158015612f6557600080fd5b505af1158015612f79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9d9190615968565b9750600080612fb58c600001518d606001518c612ff7565b9092509050612fc48983614345565b9850612fd08882614376565b9750612fdd87878b61438c565b612fe887868a61438c565b50505050505050505092915050565b6000808085600181111561300757fe5b141561301757508290508161301d565b50819050825b935093915050565b600082820261304984158061304257508385838161303f57fe5b04145b600361054b565b806130585760009150506116f5565b670de0b6b3a76400006000198201046001019150506116f5565b60006060836001600160a01b03168360405161308e9190615aea565b6000604051808303816000865af19150503d80600081146130cb576040519150601f19603f3d011682016040523d82523d6000602084013e6130d0565b606091505b509150915060008214156130e8573d6000803e3d6000fd5b610e0081516000148061310a57508180602001905181019061310a9190615478565b6101a261054b565b600061311e8383613aa1565b61316d57508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b038616908117909155855490825282860190935260409020919091556116f5565b5060006116f5565b6001600160a01b03821660009081526002840160205260408120548061320257505082546040805180820182526001600160a01b03858116808352602080840187815260008781526001808c018452878220965187546001600160a01b03191696169590951786559051948401949094559482018089559083526002880190945291902091909155611876565b600019016000908152600180860160205260408220018390559050611876565b600080600080600061323487876143a4565b91509150600061324483836143d5565b60008a81526009602090815260408083208484526002019091528120805460018201549197509293509061327783613a8f565b80613286575061328682613a8f565b806132a757506132968c87613ac2565b80156132a757506132a78c86613ac2565b9050806132c2576132b78c612683565b6132c26102096116fb565b6132cc8383614408565b98506132d8838361442d565b975050505050505093509350939050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6001600160a01b03811660009081526001830160205260408120548015613408578354600019808301919081019060009087908390811061334857fe5b60009182526020909120015487546001600160a01b039091169150819088908590811061337157fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b039485161790559183168152600189810190925260409020908401905586548790806133ba57fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506116f59350505050565b60009150506116f5565b60006116f28383610209614444565b6001600160a01b0381166000908152600283016020526040812054801561340857835460001990810160008181526001878101602090815260408084209587018452808420865481546001600160a01b03199081166001600160a01b0392831617835588860180549387019390935588548216875260028d018086528488209a909a5588541690975584905593895593871682529390925281205590506116f5565b606080825167ffffffffffffffff811180156134de57600080fd5b50604051908082528060200260200182016040528015613508578160200160208202803683370190505b50905060005b83518110156107ff576135268482815181106124ac57fe5b82828151811061353257fe5b6001600160a01b039092166020928302919091019091015260010161350e565b60608060606135608561293e565b9150915061357082518551611e12565b613580600083511161020f61054b565b60005b82518110156135da576135d285828151811061359b57fe5b60200260200101516001600160a01b03168483815181106135b857fe5b60200260200101516001600160a01b03161461020861054b565b600101613583565b50949350505050565b60608060608060006135f4866129a0565b9150915060006136038b612938565b905060008c600181111561361357fe5b146136b657806001600160a01b03166374f3b0098c8c8c8787613634614481565b8f604001516040518863ffffffff1660e01b815260040161365b9796959493929190615d66565b600060405180830381600087803b15801561367557600080fd5b505af1158015613689573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136b19190810190615405565b61374f565b806001600160a01b031663d5c096c48c8c8c87876136d2614481565b8f604001516040518863ffffffff1660e01b81526004016136f99796959493929190615d66565b600060405180830381600087803b15801561371357600080fd5b505af1158015613727573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261374f9190810190615405565b80955081965050506137658751865186516144fb565b60008c600181111561377357fe5b1461378a576137858989898888614513565b613797565b6137978a8989888861465a565b955050505096509650969350505050565b60006137b485846143d5565b600087815260096020908152604080832084845260020190915290209091506137dd85846142d1565b9055505050505050565b60005b8251811015610e00578181815181106137ff57fe5b602002602001015160076000868152602001908152602001600020600085848151811061382857fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020556001016137ea565b6000828152600160205260408120905b8251811015610e00576138958184838151811061387d57fe5b60200260200101518461438c9092919063ffffffff16565b600101613864565b6060825167ffffffffffffffff811180156138b757600080fd5b506040519080825280602002602001820160405280156138e1578160200160208202803683370190505b50905060005b83518110156107ff57826139115783818151811061390157fe5b6020026020010151600003613926565b83818151811061391d57fe5b60200260200101515b82828151811061393257fe5b60209081029190910101526001016138e7565b60008084600181111561395457fe5b1461395f57816109e1565b509092915050565b60008084600181111561397657fe5b146107ff57826109e1565b600061226a7f800000000000000000000000000000000000000000000000000000000000000083106101a561054b565b60008282016116f28284128015906139c95750848212155b806139de57506000841280156139de57508482125b600061054b565b60008183036116f28284128015906139fd5750848213155b80613a125750600084128015613a1257508482135b600161054b565b6000818152600960205260408120805460018201546001600160a01b0391821692849290911690829081613a4d86856143d5565b6000818152600284016020526040902080546001820154919950919250613a748282614408565b9650613a80828261442d565b94505050505091939590929450565b6000613a9a826132e9565b1592915050565b6001600160a01b031660009081526001919091016020526040902054151590565b600082815260096020526040812080546001600160a01b0384811691161480613afa575060018101546001600160a01b038481169116145b80156109e1575050506001600160a01b03161515919050565b60008281526008602052604081206109e18184613aa1565b60008281526001602052604081206109e181846147d0565b6000806002856002811115613b5457fe5b1415613b6a57613b658685856147f1565b613b94565b6001856002811115613b7857fe5b1415613b8957613b658685856147ff565b613b9486858561480d565b8215613bae57613bae6001600160a01b0385163385611ea6565b5050600081900394909350915050565b6000806002856002811115613bcf57fe5b1415613be557613be086858561481b565b613c0f565b6001856002811115613bf357fe5b1415613c0457613be0868585614829565b613c0f868585614837565b8215613c2a57613c2a6001600160a01b038516333086612ba6565b5090946000869003945092505050565b6000806002856002811115613c4b57fe5b1415613c6357613c5c868585614845565b9050613c90565b6001856002811115613c7157fe5b1415613c8257613c5c868585614855565b613c8d868585614865565b90505b6000915094509492505050565b4690565b606080600080600080613cb387613a19565b92975090955093509150506001600160a01b0384161580613cdb57506001600160a01b038216155b15613d04575050604080516000808252602082019081528183019092529450925061299b915050565b60408051600280825260608201835290916020830190803683370190505095508386600081518110613d3257fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508186600181518110613d6057fe5b6001600160a01b03929092166020928302919091018201526040805160028082526060820183529092909190830190803683370190505094508285600081518110613da757fe5b6020026020010181815250508085600181518110613dc157fe5b60200260200101818152505050505050915091565b60008181526008602052604090206060908190613df28161432b565b67ffffffffffffffff81118015613e0857600080fd5b50604051908082528060200260200182016040528015613e32578160200160208202803683370190505b509250825167ffffffffffffffff81118015613e4d57600080fd5b50604051908082528060200260200182016040528015613e77578160200160208202803683370190505b50915060005b8351811015613ef6576000613e928383614875565b905080858381518110613ea157fe5b6001600160a01b03928316602091820292909201810191909152600088815260078252604080822093851682529290915220548451859084908110613ee257fe5b602090810291909101015250600101613e7d565b5050915091565b60008181526001602052604090206060908190613f198161432b565b67ffffffffffffffff81118015613f2f57600080fd5b50604051908082528060200260200182016040528015613f59578160200160208202803683370190505b509250825167ffffffffffffffff81118015613f7457600080fd5b50604051908082528060200260200182016040528015613f9e578160200160208202803683370190505b50915060005b8351811015613ef657613fb782826148a2565b858381518110613fc357fe5b60200260200101858481518110613fd657fe5b60209081029190910101919091526001600160a01b039091169052600101613fa4565b6000614004826127b4565b61400d836127a1565b0192915050565b60008183101561402457816116f2565b5090919050565b600081831061402457816116f2565b6001600160a01b038085166000818152600b602090815260408083209488168084529490915290819020859055517f18e1ea4139e68413d7d08aa752e71568e36b2c5bf940893314c2c5b01eaa0c42906119d0908590615d3e565b6000806140a06148c6565b9050428110156140b45760009150506116f5565b60006140be6148d2565b9050806140d0576000925050506116f5565b6000816140db6149e3565b80516020918201206040516140f7939233918a91899101615dc4565b604051602081830303815290604052805190602001209050600061411a82614a32565b90506000806000614129614a4e565b9250925092506000600185858585604051600081526020016040526040516141549493929190615e1c565b6020604051602081039080840390855afa158015614176573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906141ac57508a6001600160a01b0316816001600160a01b0316145b9b9a5050505050505050505050565b6000806000806141ca86613ff9565b905060006141d786613ff9565b90506141ee6141e5886127ca565b612a3f886127ca565b60a08a01526040517f9d2c110c0000000000000000000000000000000000000000000000000000000081526001600160a01b03891690639d2c110c9061423c908c9086908690600401615e94565b602060405180830381600087803b15801561425657600080fd5b505af115801561426a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061428e9190615968565b92506000806142a68b600001518c6060015187612ff7565b90925090506142b58983614345565b96506142c18882614376565b9550505050509450945094915050565b6000806142e96142e0856127ca565b612a3f856127ca565b90506109e16142f7856127a1565b614300856127a1565b8363ffffffff16614a75565b6001600160a01b03166000908152600291909101602052604090205490565b5490565b6000908152600191820160205260409020015490565b60008061435b83614355866127a1565b90611945565b90506000614368856127b4565b9050436112a6838383614a83565b60008061435b83614386866127a1565b90614abc565b60009182526001928301602052604090912090910155565b600080826001600160a01b0316846001600160a01b0316106143c75782846143ca565b83835b915091509250929050565b600082826040516020016143ea929190615b06565b60405160208183030381529060405280519060200120905092915050565b60006116f2614416846127a1565b61441f846127a1565b614428866127ca565b614a83565b60006116f261443b846127b4565b61441f846127b4565b6001600160a01b038216600090815260028401602052604081205461446b8115158461054b565b614478856001830361432f565b95945050505050565b600061448b6113af565b6001600160a01b03166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b1580156144c357600080fd5b505afa1580156144d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190615968565b610fa0828414801561450c57508183145b606761054b565b6060835167ffffffffffffffff8111801561452d57600080fd5b50604051908082528060200260200182016040528015614557578160200160208202803683370190505b50905060005b85515181101561465057600084828151811061457557fe5b602002602001015190506145a58760200151838151811061459257fe5b60200260200101518210156101f961054b565b6000876000015183815181106145b757fe5b602002602001015190506145d181838b8b60600151611d38565b60008584815181106145df57fe5b602002602001015190506145fb6145f583611b41565b82611f11565b61462a6146088483611945565b89868151811061461457fe5b602002602001015161437690919063ffffffff16565b85858151811061463657fe5b60200260200101818152505050505080600101905061455d565b5095945050505050565b60606000845167ffffffffffffffff8111801561467657600080fd5b506040519080825280602002602001820160405280156146a0578160200160208202803683370190505b50915060005b8651518110156147c65760008582815181106146be57fe5b602002602001015190506146ee886020015183815181106146db57fe5b60200260200101518211156101fa61054b565b60008860000151838151811061470057fe5b6020026020010151905061471a81838c8c60600151611c5a565b61472381611938565b15614735576147328483611945565b93505b600086848151811061474357fe5b602002602001015190506147596145f583611b41565b80831015614778576147738382038a868151811061461457fe5b6147a0565b6147a08184038a868151811061478a57fe5b602002602001015161434590919063ffffffff16565b8685815181106147ac57fe5b6020026020010181815250505050508060010190506146a6565b50614650816119de565b6001600160a01b031660009081526002919091016020526040902054151590565b610e008383614ad284614b0d565b610e008383614ad284614bb8565b610e008383614ad284614c13565b610e008383614c6284614b0d565b610e008383614c6284614bb8565b610e008383614c6284614c13565b60006109e18484614c8385614b0d565b60006109e18484614c8385614bb8565b60006109e18484614c8385614c13565b600082600001828154811061488657fe5b6000918252602090912001546001600160a01b03169392505050565b600090815260019182016020526040902080549101546001600160a01b0390911691565b60006112ce6000614c9d565b6000803560e01c8063b95cac28811461491a57638bdb39138114614942576352bbbe29811461496a5763945bcec981146149925763fa6e671d81146149ba57600092506149de565b7f3f7b71252bd19113ff48c19c6e004a9bcfcca320a0d74d58e85877cbd7dcae5892506149de565b7f8bbc57f66ea936902f50a71ce12b92c43f3c5340bb40c27c4e90ab84eeae335392506149de565b7fe192dcbc143b1e244ad73b813fd3c097b832ad260a157340b4e5e5beda067abe92506149de565b7f9bfc43a4d98313c6766986ffd7c916c7481566d9f224c6819af0a53388aced3a92506149de565b7fa3f865aa351e51cfeb40f5178d1564bb629fe9030b83caf6361d1baaf5b90b5a92505b505090565b60606000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505082519293505050608010156105485760803603815290565b6000614a3c61289b565b8260405160200161112e929190615b2d565b6000806000614a5d6020614c9d565b9250614a696040614c9d565b91506108416060614c9d565b60e01b60709190911b010190565b6000838301614ab1858210801590614aa957506e01000000000000000000000000000082105b61020e61054b565b614478858585614a75565b6000614acc83831115600161054b565b50900390565b600080614ae283614386866127a1565b90506000614af384614355876127b4565b90506000614b00866127ca565b90506112a6838383614a83565b6000806000806000614b1e89613a19565b9450509350935093506000836001600160a01b0316896001600160a01b03161415614b69576000614b5384898b63ffffffff16565b9050614b5f8185614ca7565b9093509050614b8b565b6000614b7983898b63ffffffff16565b9050614b858184614ca7565b90925090505b614b9583836142d1565b8555614ba18383614cc3565b600190950194909455509192505050949350505050565b600080614bc5868661271b565b90506000614bd782858763ffffffff16565b60008881526007602090815260408083206001600160a01b038b16845290915290208190559050614c088183614ca7565b979650505050505050565b600084815260016020526040812081614c2c8287613412565b90506000614c3e82868863ffffffff16565b9050614c4b838883613175565b50614c568183614ca7565b98975050505050505050565b600080614c7283614355866127a1565b90506000614af384614386876127b4565b600080614c8f846127a1565b905043614478828583614a83565b3601607f19013590565b6000614cb2826127b4565b614cbb846127b4565b039392505050565b60006116f2614cd1846127b4565b614cda846127b4565b6000614a75565b60408051610120810190915280600081526000602082018190526040820181905260608083018290526080830182905260a0830182905260c0830182905260e08301919091526101009091015290565b604080516080810190915280600081526000602082018190526040820181905260609091015290565b60405180608001604052806060815260200160608152602001606081526020016000151581525090565b6040518060a0016040528060008019168152602001600081526020016000815260200160008152602001606081525090565b80356116f581615f5a565b600082601f830112614dd1578081fd5b8135614de4614ddf82615f04565b615edd565b818152915060208083019084810181840286018201871015614e0557600080fd5b60005b84811015614e2d578135614e1b81615f5a565b84529282019290820190600101614e08565b505050505092915050565b600082601f830112614e48578081fd5b8135614e56614ddf82615f04565b818152915060208083019084810160005b84811015614e2d578135870160a080601f19838c03011215614e8857600080fd5b614e9181615edd565b85830135815260408084013587830152606080850135828401526080915081850135818401525082840135925067ffffffffffffffff831115614ed357600080fd5b614ee18c8885870101614fc0565b90820152865250509282019290820190600101614e67565b600082601f830112614f09578081fd5b8135614f17614ddf82615f04565b818152915060208083019084810181840286018201871015614f3857600080fd5b60005b84811015614e2d57813584529282019290820190600101614f3b565b600082601f830112614f67578081fd5b8151614f75614ddf82615f04565b818152915060208083019084810181840286018201871015614f9657600080fd5b60005b84811015614e2d57815184529282019290820190600101614f99565b80356116f581615f6f565b600082601f830112614fd0578081fd5b813567ffffffffffffffff811115614fe6578182fd5b614ff9601f8201601f1916602001615edd565b915080825283602082850101111561501057600080fd5b8060208401602084013760009082016020015292915050565b80356116f581615f7d565b8035600281106116f557600080fd5b8035600481106116f557600080fd5b600060808284031215615063578081fd5b61506d6080615edd565b9050813567ffffffffffffffff8082111561508757600080fd5b61509385838601614dc1565b835260208401359150808211156150a957600080fd5b6150b585838601614ef9565b602084015260408401359150808211156150ce57600080fd5b506150db84828501614fc0565b6040830152506150ee8360608401614fb5565b606082015292915050565b60006080828403121561510a578081fd5b6151146080615edd565b9050813561512181615f5a565b8152602082013561513181615f6f565b6020820152604082013561514481615f5a565b604082015260608201356150ee81615f6f565b600060208284031215615168578081fd5b81356116f281615f5a565b60008060408385031215615185578081fd5b823561519081615f5a565b915060208301356151a081615f5a565b809150509250929050565b6000806000606084860312156151bf578081fd5b83356151ca81615f5a565b925060208401356151da81615f5a565b915060408401356151ea81615f6f565b809150509250925092565b60008060408385031215615207578182fd5b823561521281615f5a565b9150602083013567ffffffffffffffff81111561522d578182fd5b61523985828601614dc1565b9150509250929050565b60006020808385031215615255578182fd5b823567ffffffffffffffff81111561526b578283fd5b8301601f8101851361527b578283fd5b8035615289614ddf82615f04565b818152838101908385016080808502860187018a10156152a7578788fd5b8795505b848610156153105780828b0312156152c1578788fd5b6152ca81615edd565b6152d48b84615029565b8152878301358882015260406152ec8c828601614db6565b908201526060838101359082015284526001959095019492860192908101906152ab565b509098975050505050505050565b60006020808385031215615330578182fd5b823567ffffffffffffffff811115615346578283fd5b8301601f81018513615356578283fd5b8035615364614ddf82615f04565b8181528381019083850160a0808502860187018a1015615382578788fd5b8795505b848610156153105780828b03121561539c578788fd5b6153a581615edd565b6153af8b84615043565b81526153bd8b898501614db6565b818901526040838101359082015260606153d98c828601614db6565b9082015260806153eb8c858301614db6565b908201528452600195909501949286019290810190615386565b60008060408385031215615417578182fd5b825167ffffffffffffffff8082111561542e578384fd5b61543a86838701614f57565b9350602085015191508082111561544f578283fd5b5061523985828601614f57565b60006020828403121561546d578081fd5b81356116f281615f6f565b600060208284031215615489578081fd5b81516116f281615f6f565b6000602082840312156154a5578081fd5b5035919050565b600080600080608085870312156154c1578182fd5b8435935060208501356154d381615f5a565b925060408501356154e381615f5a565b9150606085013567ffffffffffffffff8111156154fe578182fd5b61550a87828801615052565b91505092959194509250565b60008060408385031215615528578182fd5b82359150602083013567ffffffffffffffff81111561522d578182fd5b600080600060608486031215615559578081fd5b8335925060208085013567ffffffffffffffff80821115615578578384fd5b61558488838901614dc1565b94506040870135915080821115615599578384fd5b508501601f810187136155aa578283fd5b80356155b8614ddf82615f04565b81815283810190838501858402850186018b10156155d4578687fd5b8694505b838510156155ff5780356155eb81615f5a565b8352600194909401939185019185016155d8565b5080955050505050509250925092565b60008060408385031215615621578182fd5b8235915060208301356151a081615f5a565b600060208284031215615644578081fd5b81356001600160e01b0319811681146116f2578182fd5b60008060008060808587031215615670578182fd5b843561567b81615f5a565b9350602085013567ffffffffffffffff80821115615697578384fd5b6156a388838901614dc1565b945060408701359150808211156156b8578384fd5b6156c488838901614ef9565b935060608701359150808211156156d9578283fd5b5061550a87828801614fc0565b6000602082840312156156f7578081fd5b81356116f281615f7d565b60008060008060e08587031215615717578182fd5b6157218686615034565b9350602085013567ffffffffffffffff8082111561573d578384fd5b61574988838901614e38565b9450604087013591508082111561575e578384fd5b5061576b87828801614dc1565b92505061577b86606087016150f9565b905092959194509250565b600080600080600080610120878903121561579f578384fd5b6157a98888615034565b955060208088013567ffffffffffffffff808211156157c6578687fd5b6157d28b838c01614e38565b975060408a01359150808211156157e7578687fd5b6157f38b838c01614dc1565b96506158028b60608c016150f9565b955060e08a0135915080821115615817578485fd5b508801601f81018a13615828578384fd5b8035615836614ddf82615f04565b81815283810190838501858402850186018e1015615852578788fd5b8794505b83851015615874578035835260019490940193918501918501615856565b50809650505050505061010087013590509295509295509295565b60008060008060e085870312156158a4578182fd5b843567ffffffffffffffff808211156158bb578384fd5b9086019060c082890312156158ce578384fd5b6158d860c0615edd565b823581526158e98960208501615034565b602082015260408301356158fc81615f5a565b604082015261590e8960608501614db6565b60608201526080830135608082015260a08301358281111561592e578586fd5b61593a8a828601614fc0565b60a08301525080965050505061595386602087016150f9565b939693955050505060a08201359160c0013590565b600060208284031215615979578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208085019450808401835b838110156159c55781516001600160a01b0316875295820195908201906001016159a0565b509495945050505050565b6000815180845260208085019450808401835b838110156159c5578151875295820195908201906001016159e3565b60008151808452615a17816020860160208601615f24565b601f01601f19169290920160200192915050565b6000610120825160028110615a3c57fe5b808552506020830151615a526020860182615980565b506040830151615a656040860182615980565b50606083015160608501526080830151608085015260a083015160a085015260c0830151615a9660c0860182615980565b5060e0830151615aa960e0860182615980565b506101008084015182828701526112a6838701826159ff565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b60008251615afc818460208701615f24565b9190910192915050565b6bffffffffffffffffffffffff19606093841b811682529190921b16601482015260280190565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038316815260408101615bb483615f50565b8260208301529392505050565b6001600160a01b03929092168252602082015260400190565b6000602082526116f2602083018461598d565b600060408252615c00604083018561598d565b828103602084810191909152845180835285820192820190845b81811015615c3f5784516001600160a01b031683529383019391830191600101615c1a565b5090979650505050505050565b600060608252615c5f606083018661598d565b8281036020840152615c7181866159d0565b905082810360408401526112a681856159d0565b600060808252615c98608083018761598d565b8281036020840152615caa81876159d0565b90508281036040840152615cbe81866159d0565b90508281036060840152614c0881856159ff565b600060608252615ce5606083018661598d565b8281036020840152615cf781866159d0565b915050826040830152949350505050565b6000602082526116f260208301846159d0565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60008882526001600160a01b03808916602084015280881660408401525060e06060830152615d9860e08301876159d0565b8560808401528460a084015282810360c0840152615db681856159ff565b9a9950505050505050505050565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b60208101615e4783615f50565b91905290565b918252602082015260400190565b600060808252615e6e6080830187615a2b565b8281036020840152615e8081876159d0565b604084019590955250506060015292915050565b600060608252615ea76060830186615a2b565b60208301949094525060400152919050565b938452602084019290925260408301526001600160a01b0316606082015260800190565b60405181810167ffffffffffffffff81118282101715615efc57600080fd5b604052919050565b600067ffffffffffffffff821115615f1a578081fd5b5060209081020190565b60005b83811015615f3f578181015183820152602001615f27565b83811115610e005750506000910152565b6003811061057e57fe5b6001600160a01b038116811461057e57600080fd5b801515811461057e57600080fd5b6003811061057e57600080fdfea2646970667358221220201e4f926e390fed8dd5318c58846af735c2bebc61b80693ae936a5fe76dcf1464736f6c6343000701003360c060405234801561001057600080fd5b50604051610be6380380610be683398101604081905261002f9161004d565b30608052600160005560601b6001600160601b03191660a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160a05160601c610b406100a66000398061041352806105495250806102a75250610b406000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063851c1bb311610076578063d877845c1161005b578063d877845c14610129578063e42abf3514610131578063fbfa77cf14610151576100a3565b8063851c1bb314610101578063aaabadc514610114576100a3565b806338e9922e146100a857806355c67628146100bd5780636b6b9f69146100db5780636daefab6146100ee575b600080fd5b6100bb6100b636600461099c565b610159565b005b6100c56101b8565b6040516100d29190610aa6565b60405180910390f35b6100bb6100e936600461099c565b6101be565b6100bb6100fc3660046107d1565b610211565b6100c561010f366004610924565b6102a3565b61011c6102f5565b6040516100d29190610a35565b6100c5610304565b61014461013f366004610852565b61030a565b6040516100d29190610a62565b61011c610411565b610161610435565b6101786706f05b59d3b2000082111561025861047e565b60018190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc906101ad908390610aa6565b60405180910390a150565b60015490565b6101c6610435565b6101dc662386f26fc1000082111561025961047e565b60028190556040517f5a0b7386237e7f07fa741efc64e59c9387d2cccafec760efed4d53387f20e19a906101ad908390610aa6565b610219610490565b610221610435565b61022b84836104a9565b60005b8481101561029357600086868381811061024457fe5b90506020020160208101906102599190610980565b9050600085858481811061026957fe5b6020029190910135915061028990506001600160a01b03831685836104b6565b505060010161022e565b5061029c61053e565b5050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016102d89291906109cc565b604051602081830303815290604052805190602001209050919050565b60006102ff610545565b905090565b60025490565b6060815167ffffffffffffffff8111801561032457600080fd5b5060405190808252806020026020018201604052801561034e578160200160208202803683370190505b50905060005b825181101561040b5782818151811061036957fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161039c9190610a35565b60206040518083038186803b1580156103b457600080fd5b505afa1580156103c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ec91906109b4565b8282815181106103f857fe5b6020908102919091010152600101610354565b50919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006104646000357fffffffff00000000000000000000000000000000000000000000000000000000166102a3565b905061047b61047382336105d8565b61019161047e565b50565b8161048c5761048c8161066a565b5050565b6104a26002600054141561019061047e565b6002600055565b61048c818314606761047e565b6105398363a9059cbb60e01b84846040516024016104d5929190610a49565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526106d7565b505050565b6001600055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b1580156105a057600080fd5b505afa1580156105b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ff9190610964565b60006105e2610545565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b815260040161061193929190610aaf565b60206040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066191906108fd565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006060836001600160a01b0316836040516106f391906109fc565b6000604051808303816000865af19150503d8060008114610730576040519150601f19603f3d011682016040523d82523d6000602084013e610735565b606091505b5091509150600082141561074d573d6000803e3d6000fd5b61077781516000148061076f57508180602001905181019061076f91906108fd565b6101a261047e565b50505050565b60008083601f84011261078e578182fd5b50813567ffffffffffffffff8111156107a5578182fd5b60208301915083602080830285010111156107bf57600080fd5b9250929050565b803561066481610af5565b6000806000806000606086880312156107e8578081fd5b853567ffffffffffffffff808211156107ff578283fd5b61080b89838a0161077d565b90975095506020880135915080821115610823578283fd5b506108308882890161077d565b909450925050604086013561084481610af5565b809150509295509295909350565b60006020808385031215610864578182fd5b823567ffffffffffffffff8082111561087b578384fd5b818501915085601f83011261088e578384fd5b81358181111561089c578485fd5b83810291506108ac848301610ace565b8181528481019084860184860187018a10156108c6578788fd5b8795505b838610156108f0576108dc8a826107c6565b8352600195909501949186019186016108ca565b5098975050505050505050565b60006020828403121561090e578081fd5b8151801515811461091d578182fd5b9392505050565b600060208284031215610935578081fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461091d578182fd5b600060208284031215610975578081fd5b815161091d81610af5565b600060208284031215610991578081fd5b813561091d81610af5565b6000602082840312156109ad578081fd5b5035919050565b6000602082840312156109c5578081fd5b5051919050565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260240190565b60008251815b81811015610a1c5760208186018101518583015201610a02565b81811115610a2a5782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015610a9a57835183529284019291840191600101610a7e565b50909695505050505050565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60405181810167ffffffffffffffff81118282101715610aed57600080fd5b604052919050565b6001600160a01b038116811461047b57600080fdfea2646970667358221220be72bdf8e7a3c38606c5f954fbe2d77798347aaa1cfb76fe77ec2f6c245d24bc64736f6c63430007010033" + ] } diff --git a/crates/contracts/artifacts/BalancerV2WeightedPool.json b/contracts/artifacts/BalancerV2WeightedPool.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2WeightedPool.json rename to contracts/artifacts/BalancerV2WeightedPool.json index e421358d76..4009c41c20 100644 --- a/crates/contracts/artifacts/BalancerV2WeightedPool.json +++ b/contracts/artifacts/BalancerV2WeightedPool.json @@ -221,38 +221,44 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, + "inputs": [], + "name": "getNormalizedWeights", + "outputs": [ { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" } ], - "name": "decreaseApproval", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPausedState", "outputs": [ { "internalType": "bool", - "name": "", + "name": "paused", "type": "bool" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodEndTime", + "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "getActionId", + "inputs": [], + "name": "getPoolId", "outputs": [ { "internalType": "bytes32", @@ -265,12 +271,12 @@ }, { "inputs": [], - "name": "getAuthorizer", + "name": "getSwapFeePercentage", "outputs": [ { - "internalType": "contract IAuthorizer", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -278,20 +284,26 @@ }, { "inputs": [], - "name": "getInvariant", + "name": "name", "outputs": [ { - "internalType": "uint256", + "internalType": "string", "name": "", - "type": "uint256" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getLastInvariant", + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", "outputs": [ { "internalType": "uint256", @@ -303,57 +315,149 @@ "type": "function" }, { - "inputs": [], - "name": "getNormalizedWeights", - "outputs": [ + "inputs": [ { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "stateMutability": "view", + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], - "name": "getOwner", + "name": "symbol", "outputs": [ { - "internalType": "address", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getPausedState", + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", "outputs": [ { "internalType": "bool", - "name": "paused", + "name": "", "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" }, { "internalType": "uint256", - "name": "pauseWindowEndTime", + "name": "amount", "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "uint256", - "name": "bufferPeriodEndTime", + "name": "amount", "type": "uint256" } ], - "stateMutability": "view", + "name": "decreaseApproval", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "getPoolId", + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", "outputs": [ { "internalType": "bytes32", @@ -366,12 +470,12 @@ }, { "inputs": [], - "name": "getRate", + "name": "getAuthorizer", "outputs": [ { - "internalType": "uint256", + "internalType": "contract IAuthorizer", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -379,7 +483,7 @@ }, { "inputs": [], - "name": "getSwapFeePercentage", + "name": "getInvariant", "outputs": [ { "internalType": "uint256", @@ -392,49 +496,51 @@ }, { "inputs": [], - "name": "getVault", + "name": "getLastInvariant", "outputs": [ { - "internalType": "contract IVault", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "getOwner", + "outputs": [ { "internalType": "address", - "name": "spender", + "name": "", "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" } ], - "name": "increaseApproval", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRate", "outputs": [ { - "internalType": "bool", + "internalType": "uint256", "name": "", - "type": "bool" + "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "name", + "name": "getVault", "outputs": [ { - "internalType": "string", + "internalType": "contract IVault", "name": "", - "type": "string" + "type": "address" } ], "stateMutability": "view", @@ -444,19 +550,24 @@ "inputs": [ { "internalType": "address", - "name": "owner", + "name": "spender", "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "nonces", + "name": "increaseApproval", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { @@ -643,49 +754,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -820,19 +888,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "totalSupply", @@ -845,59 +900,6 @@ ], "stateMutability": "view", "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" } ] } diff --git a/crates/contracts/artifacts/BalancerV2WeightedPool2TokensFactory.json b/contracts/artifacts/BalancerV2WeightedPool2TokensFactory.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2WeightedPool2TokensFactory.json rename to contracts/artifacts/BalancerV2WeightedPool2TokensFactory.json index 2e16f6340f..c0a4ff8e54 100644 --- a/crates/contracts/artifacts/BalancerV2WeightedPool2TokensFactory.json +++ b/contracts/artifacts/BalancerV2WeightedPool2TokensFactory.json @@ -72,7 +72,10 @@ ], "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "bytecode": "0x60c060405234801561001057600080fd5b50604051615fe1380380615fe183398101604081905261002f9161004d565b60601b6001600160601b0319166080526276a700420160a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160601c60a051615f3b6100a660003980610221528061024b5250806102a75250615f3b6000f3fe60806040523480156200001157600080fd5b5060043610620000525760003560e01c80631596019b14620000575780632da47c4014620000865780636634b75314620000a05780638d928af814620000c6575b600080fd5b6200006e6200006836600462000548565b620000d0565b6040516200007d91906200068f565b60405180910390f35b620000906200021b565b6040516200007d929190620007a2565b620000b7620000b136600462000522565b62000287565b6040516200007d9190620006a3565b6200006e620002a5565b6000806000620000df6200021b565b91509150620000ed62000315565b60405180610180016040528062000103620002a5565b6001600160a01b031681526020018c81526020018b81526020018a6000815181106200012b57fe5b60200260200101516001600160a01b031681526020018a6001815181106200014f57fe5b60200260200101516001600160a01b03168152602001896000815181106200017357fe5b60200260200101518152602001896001815181106200018e57fe5b602002602001015181526020018881526020018481526020018381526020018715158152602001866001600160a01b03168152509050600081604051620001d5906200039c565b620001e19190620006ae565b604051809103906000f080158015620001fe573d6000803e3d6000fd5b5090506200020c81620002c9565b9b9a5050505050505050505050565b600080427f00000000000000000000000000000000000000000000000000000000000000008110156200027957807f000000000000000000000000000000000000000000000000000000000000000003925062278d00915062000282565b60009250600091505b509091565b6001600160a01b031660009081526020819052604090205460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b038116600081815260208190526040808220805460ff19166001179055517f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9190a250565b60405180610180016040528060006001600160a01b03168152602001606081526020016060815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681525090565b6156f3806200081383390190565b8035620003b781620007f9565b92915050565b600082601f830112620003ce578081fd5b8135620003e5620003df82620007d8565b620007b0565b8181529150602080830190848101818402860182018710156200040757600080fd5b60005b84811015620004335781356200042081620007f9565b845292820192908201906001016200040a565b505050505092915050565b600082601f8301126200044f578081fd5b813562000460620003df82620007d8565b8181529150602080830190848101818402860182018710156200048257600080fd5b60005b84811015620004335781358452928201929082019060010162000485565b80358015158114620003b757600080fd5b600082601f830112620004c5578081fd5b813567ffffffffffffffff811115620004dc578182fd5b620004f1601f8201601f1916602001620007b0565b91508082528360208285010111156200050957600080fd5b8060208401602084013760009082016020015292915050565b60006020828403121562000534578081fd5b81356200054181620007f9565b9392505050565b600080600080600080600060e0888a03121562000563578283fd5b873567ffffffffffffffff808211156200057b578485fd5b620005898b838c01620004b4565b985060208a01359150808211156200059f578485fd5b620005ad8b838c01620004b4565b975060408a0135915080821115620005c3578485fd5b620005d18b838c01620003bd565b965060608a0135915080821115620005e7578485fd5b50620005f68a828b016200043e565b945050608088013592506200060f8960a08a01620004a3565b9150620006208960c08a01620003aa565b905092959891949750929550565b6001600160a01b03169052565b15159052565b60008151808452815b8181101562000668576020818501810151868301820152016200064a565b818111156200067a5782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b901515815260200190565b600060208252620006c46020830184516200062e565b6020830151610180806040850152620006e26101a085018362000641565b91506040850151601f1985840301606086015262000701838262000641565b92505060608501516200071860808601826200062e565b5060808501516200072d60a08601826200062e565b5060a085015160c085015260c085015160e085015260e085015161010081818701528087015191505061012081818701528087015191505061014081818701528087015191505061016062000785818701836200063b565b860151905062000798858301826200062e565b5090949350505050565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715620007d057600080fd5b604052919050565b600067ffffffffffffffff821115620007ef578081fd5b5060209081020190565b6001600160a01b03811681146200080f57600080fd5b5056fe6102a06040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9610120523480156200003757600080fd5b50604051620056f3380380620056f38339810160408190526200005a916200080c565b61010081810151610120830151602080850151604080870151815180830190925260018252603160f81b8285019081526101608901513360805260601b6001600160601b03191660a052835194840194852060c052915190912060e0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f909552805193949293909291620000f391600391906200069f565b508051620001099060049060208401906200069f565b50620001219150506276a7008311156101946200040a565b6200013562278d008211156101956200040a565b4290910161014081815291016101605281015162000153906200041f565b60e081015162000163906200047b565b80516040516309b2760f60e01b81526000916001600160a01b0316906309b2760f90620001969060029060040162000a12565b602060405180830381600087803b158015620001b157600080fd5b505af1158015620001c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ec9190620007f3565b6040805160028082526060808301845293945090916020830190803683370190505090508260600151816000815181106200022357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508260800151816001815181106200025657fe5b6001600160a01b0392831660209182029290920101528351166366a9c7d283836002604051908082528060200260200182016040528015620002a2578160200160208202803683370190505b506040518463ffffffff1660e01b8152600401620002c39392919062000976565b600060405180830381600087803b158015620002de57600080fd5b505af1158015620002f3573d6000803e3d6000fd5b505084516001600160601b0319606091821b8116610180526101a08690528187018051831b82166101c052608088015190921b166101e052516200033a92509050620004f9565b6102605260808301516200034e90620004f9565b6102805260a08301516200036f90662386f26fc10000111561012e6200040a565b62000391662386f26fc100008460c00151101561012e6200040a60201b60201c565b6000620003b58460c001518560a001516200059b60201b620011c61790919060201c565b9050620003cf670de0b6b3a764000082146101346200040a565b60a0840180516102005260c085018051610220525190511015620003f5576001620003f8565b60005b60ff16610240525062000a6392505050565b816200041b576200041b81620005b8565b5050565b6200043b816008546200060b60201b620011d81790919060201c565b6008556040517f3e350b41e86a8e10f804ade6d35340d620be35569cc75ac943e8bb14ab80ead190620004709083906200096b565b60405180910390a150565b6200049064e8d4a5100082101560cb6200040a565b620004a867016345785d8a000082111560ca6200040a565b620004c4816008546200062a60201b620011e61790919060201c565b6008556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc906200047090839062000a27565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200053657600080fd5b505afa1580156200054b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000571919062000948565b60ff1690506000620005906012836200064960201b620011f41760201c565b600a0a949350505050565b6000828201620005af84821015836200040a565b90505b92915050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b6000620005af826055856200066160201b6200120a179092919060201c565b6000620005af826056856200068a60201b62001231179092919060201c565b60006200065b8383111560016200040a565b50900390565b60006001821b1984168284620006795760006200067c565b60015b60ff16901b17949350505050565b6001600160401b03811b1992909216911b1790565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620006e257805160ff191683800117855562000712565b8280016001018555821562000712579182015b8281111562000712578251825591602001919060010190620006f5565b506200072092915062000724565b5090565b5b8082111562000720576000815560010162000725565b80516001600160a01b0381168114620005b257600080fd5b80518015158114620005b257600080fd5b600082601f83011262000775578081fd5b81516001600160401b038111156200078b578182fd5b6020620007a1601f8301601f1916820162000a30565b92508183528481838601011115620007b857600080fd5b60005b82811015620007d8578481018201518482018301528101620007bb565b82811115620007ea5760008284860101525b50505092915050565b60006020828403121562000805578081fd5b5051919050565b6000602082840312156200081e578081fd5b81516001600160401b038082111562000835578283fd5b81840191506101808083870312156200084c578384fd5b620008578162000a30565b90506200086586846200073b565b815260208301518281111562000879578485fd5b620008878782860162000764565b6020830152506040830151828111156200089f578485fd5b620008ad8782860162000764565b604083015250620008c286606085016200073b565b6060820152620008d686608085016200073b565b608082015260a0838101519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101409150620009228683850162000753565b82820152610160915062000939868385016200073b565b91810191909152949350505050565b6000602082840312156200095a578081fd5b815160ff81168114620005af578182fd5b901515815260200190565b60006060820185835260206060818501528186518084526080860191508288019350845b81811015620009c257620009af855162000a57565b835293830193918301916001016200099a565b505084810360408601528551808252908201925081860190845b8181101562000a0457620009f1835162000a57565b85529383019391830191600101620009dc565b509298975050505050505050565b602081016003831062000a2157fe5b91905290565b90815260200190565b6040518181016001600160401b038111828210171562000a4f57600080fd5b604052919050565b6001600160a01b031690565b60805160a05160601c60c05160e051610100516101205161014051610160516101805160601c6101a0516101c05160601c6101e05160601c6102005161022051610240516102605161028051614bb862000b3b60003980611d12525080611d395250806129e25280612a165280612a52525080611d665280611e02525080611d8d5280611de05280611e3052505080610c6a525080610808525080610bb852508061139d525080611379525080610f205250806116a55250806116e75250806116c6525080610b94525080610b1f5250614bb86000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c806374f3b0091161013b578063aaabadc5116100b8578063d5c096c41161007c578063d5c096c4146104e1578063d73dd623146104f4578063dd62ed3e14610507578063f89f27ed1461051a578063ffd088eb1461052257610248565b8063aaabadc5146104a3578063b10be739146104ab578063b48b5b40146104be578063c0ff1a15146104c6578063d505accf146104ce57610248565b80638d928af8116100ff5780638d928af81461046557806395d89b411461046d5780639b02cdde146104755780639d2c110c1461047d578063a9059cbb1461049057610248565b806374f3b009146103f65780637ecebe0014610417578063851c1bb31461042a57806387ec68171461043d578063893d20e81461045057610248565b806338e9922e116101c957806360d1507c1161018d57806360d1507c1461038257806366188463146103a8578063679aefce146103bb5780636b843239146103c357806370a08231146103e357610248565b806338e9922e1461032457806338fff2d0146103375780634a6b0b151461033f57806355c67628146103595780636028bfd41461036157610248565b80631dccd830116102105780631dccd830146102cc57806323b872dd146102ec578063292c914a146102ff578063313ce567146103075780633644e5151461031c57610248565b806306fdde031461024d578063095ea7b31461026b57806316c38b3c1461028b57806318160ddd146102a05780631c0de051146102b5575b600080fd5b61025561052a565b6040516102629190614a93565b60405180910390f35b61027e61027936600461423b565b6105c0565b6040516102629190614970565b61029e6102993660046144a9565b6105d7565b005b6102a86105eb565b6040516102629190614993565b6102bd6105f1565b6040516102629392919061497b565b6102df6102da3660046143ef565b61061a565b6040516102629190614938565b61027e6102fa366004614186565b610722565b61029e6107a5565b61030f6107d9565b6040516102629190614aff565b6102a86107de565b61029e61033236600461484b565b6107ed565b6102a8610806565b61034761082a565b60405161026296959493929190614a69565b6102a8610885565b61037461036f3660046144e1565b610892565b604051610262929190614ae6565b61039561039036600461484b565b6108c3565b6040516102629796959493929190614a39565b61027e6103b636600461423b565b61090c565b6102a8610966565b6103d66103d1366004614331565b61098b565b60405161026291906148f4565b6102a86103f1366004614132565b610a3c565b6104096104043660046144e1565b610a5b565b60405161026292919061494b565b6102a8610425366004614132565b610b00565b6102a86104383660046145dd565b610b1b565b61037461044b3660046144e1565b610b6d565b610458610b92565b60405161026291906148e0565b610458610bb6565b610255610bda565b6102a8610c3b565b6102a861048b366004614750565b610c41565b61027e61049e36600461423b565b610df0565b610458610dfd565b6102a86104b9366004614734565b610e07565b6102a8610e29565b6102a8610e2f565b61029e6104dc3660046141c6565b610eeb565b6104096104ef3660046144e1565b611034565b61027e61050236600461423b565b611154565b6102a861051536600461414e565b61118a565b6102df6111b5565b6102a86111bf565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105b65780601f1061058b576101008083540402835291602001916105b6565b820191906000526020600020905b81548152906001019060200180831161059957829003601f168201915b5050505050905090565b60006105cd338484611246565b5060015b92915050565b6105df6112ae565b6105e8816112dc565b50565b60025490565b60008060006105fe61135a565b159250610609611377565b915061061361139b565b9050909192565b606081516001600160401b038111801561063357600080fd5b5060405190808252806020026020018201604052801561065d578160200160208202803683370190505b509050600061066d6008546113bf565b9050610677613ffe565b60005b845181101561071a5784818151811061068f57fe5b602002602001015191506106ad82602001516000141561013c6113cc565b60006106c883600001518585602001518660400151016113de565b905060006106df84600001518686604001516113de565b90506106f98460200151838303816106f357fe5b05611524565b86848151811061070557fe5b6020908102919091010152505060010161067a565b505050919050565b6001600160a01b038316600081815260016020908152604080832033808552925282205491926107609114806107585750838210155b6101976113cc565b61076b858585611537565b336001600160a01b0386161480159061078657506000198114155b15610798576107988533858403611246565b60019150505b9392505050565b6107ad611606565b6107b56112ae565b6107bf6001611619565b60006107c96105eb565b11156107d7576107d7611659565b565b601290565b60006107e86116a1565b905090565b6107f56112ae565b6107fd611606565b6105e88161173e565b7f000000000000000000000000000000000000000000000000000000000000000090565b60008060008060008060006008549050610843816117a7565b965061084e816117b3565b9550610859816117c0565b9450610864816113bf565b935061086f816117cd565b925061087a816117da565b915050909192939495565b60006107e86008546117da565b600060606108a2865160026117e7565b6108b7898989898989896117f46118ae61192c565b97509795505050505050565b60008060008060008060006108de610400891061013b6113cc565b60006108e989611a4b565b90506108f481611a5d565b959f949e50929c50909a509850965090945092505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106109485761094333856000611246565b61095c565b61095c338561095784876111f4565b611246565b5060019392505050565b60006107e86109736105eb565b61098561097e610e2f565b6002611ac0565b90611ae4565b606081516001600160401b03811180156109a457600080fd5b506040519080825280602002602001820160405280156109ce578160200160208202803683370190505b50905060006109de6008546113bf565b90506109e8614020565b60005b845181101561071a57848181518110610a0057fe5b60200260200101519150610a1d82600001518484602001516113de565b848281518110610a2957fe5b60209081029190910101526001016109eb565b6001600160a01b0381166000908152602081905260409020545b919050565b60608088610a85610a6a610bb6565b6001600160a01b0316336001600160a01b03161460cd6113cc565b610a9a610a90610806565b82146101f46113cc565b610aa387611b35565b6000606080610ab78d8d8d8d8d8d8d6117f4565b925092509250610ac78c84611b97565b610ad0826118ae565b610ad9816118ae565b610ae161135a565b15610aee57610aee611659565b909c909b509950505050505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f000000000000000000000000000000000000000000000000000000000000000082604051602001610b5092919061489d565b604051602081830303815290604052805190602001209050919050565b60006060610b7d865160026117e7565b6108b789898989898989611c2a611cab61192c565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105b65780601f1061058b576101008083540402835291602001916105b6565b60095490565b6000610c4b611606565b8360800151610c5b610a6a610bb6565b610c66610a90610806565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686602001516001600160a01b03161490506000610cae82611d09565b90506000610cbc8315611d09565b90506000610cc984611d5d565b90506000610cd78515611d5d565b9050610ce38985611db1565b9850610cef8884611db1565b9750610d188a60a0015186610d045789610d06565b8a5b87610d11578b610d13565b8a5b611dbd565b60008a516001811115610d2757fe5b1415610d95576000610d45610d3a610885565b60608d015190611ec3565b9050610d67610d61828d606001516111f490919063ffffffff16565b86611db1565b60608c01526000610d7b8c8c8c8787611f07565b9050610d878186611f26565b985050505050505050610de8565b610da38a6060015184611db1565b60608b01526000610db78b8b8b8686611f32565b9050610dc38186611f45565b9050610ddf610dd8610dd3610885565b611f51565b8290611f77565b97505050505050505b509392505050565b60006105cd338484611537565b60006107e8611fb9565b600080610e1e83610e196008546113bf565b612033565b905061079e81611524565b61040090565b60006060610e3b610bb6565b6001600160a01b031663f94d4668610e51610806565b6040518263ffffffff1660e01b8152600401610e6d9190614993565b60006040518083038186803b158015610e8557600080fd5b505afa158015610e99573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec19190810190614266565b50915050610ece81611b35565b6060610ed861206a565b9050610ee481836120d8565b9250505090565b610ef98442111560d16113cc565b6001600160a01b0387166000908152600560209081526040808320549051909291610f50917f0000000000000000000000000000000000000000000000000000000000000000918c918c918c9188918d91016149bb565b6040516020818303038152906040528051906020012090506000610f738261214a565b9050600060018288888860405160008152602001604052604051610f9a9493929190614a1b565b6020604051602081039080840390855afa158015610fbc573d6000803e3d6000fd5b5050604051601f1901519150610ffe90506001600160a01b03821615801590610ff657508b6001600160a01b0316826001600160a01b0316145b6101f86113cc565b6001600160a01b038b1660009081526005602052604090206001850190556110278b8b8b611246565b5050505050505050505050565b60608088611043610a6a610bb6565b61104e610a90610806565b611056611606565b60006110606105eb565b6110d0576110708b8b8b88612166565b94509050611085620f424082101560cc6113cc565b6110936000620f42406121ef565b6110a289620f424083036121ef565b6110ab84611cab565b604080516002808252606082018352909160208301908036833701905050925061113e565b6110d988611b35565b61110c87896000815181106110ea57fe5b60200260200101518a6001815181106110ff57fe5b6020026020010151611dbd565b61111b8b8b8b8b8b8b8b611c2a565b9095509350905061112c89826121ef565b61113584611cab565b61113e836118ae565b611146611659565b505097509795505050505050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916105cd91859061095790866111c6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606107e861206a565b6201de2090565b600082820161079e84821015836113cc565b600061079e8383605561120a565b600061079e83836056611231565b60006112048383111560016113cc565b50900390565b60006001821b1984168284611220576000611223565b60015b60ff16901b17949350505050565b6001600160401b03811b1992909216911b1790565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906112a1908590614993565b60405180910390a3505050565b60006112c56000356001600160e01b031916610b1b565b90506105e86112d48233612285565b6101916113cc565b80156112fc576112f76112ed611377565b42106101936113cc565b611311565b61131161130761139b565b42106101a96113cc565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be649061134f908390614970565b60405180910390a150565b600061136461139b565b4211806107e857505060065460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006105d182604b612375565b816113da576113da8161237d565b5050565b60006113ef824210156101386113cc565b4282900360006113fe85611a4b565b9050600061140b826123d0565b905061141c600082116101396113cc565b8281116114485780830380611431848a6123dc565b0261143c848a612420565b0194505050505061079e565b600061145387612464565b9050600061146082611a4b565b9050600061146d826123d0565b905061147e600082116101396113cc565b61148d8682111561013a6113cc565b505060008061149c8684612471565b9150915060006114ab836123d0565b6114b4836123d0565b039050801561150c5760006114c9848d612420565b6114d3848e612420565b03905060006114e1856123d0565b8903905082818302816114f057fe5b056114fb868f612420565b01995050505050505050505061079e565b611516838c612420565b97505050505050505061079e565b60006105d1655af3107a40008302612524565b6001600160a01b03831660009081526020819052604090205461155f828210156101966113cc565b6115766001600160a01b03841615156101996113cc565b6001600160a01b038085166000908152602081905260408082208585039055918516815220546115a690836111c6565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906115f8908690614993565b60405180910390a350505050565b6107d761161161135a565b6101926113cc565b60085461162690826111d8565b6008556040517f3e350b41e86a8e10f804ade6d35340d620be35569cc75ac943e8bb14ab80ead19061134f908390614970565b600854611665816117cd565b156105e85761167f611678600954612901565b8290612945565b905061169b61169461168f6105eb565b612901565b8290612952565b60085550565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061170e612960565b306040516020016117239594939291906149ef565b60405160208183030381529060405280519060200120905090565b61175164e8d4a5100082101560cb6113cc565b61176767016345785d8a000082111560ca6113cc565b60085461177490826111e6565b6008556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc9061134f908390614993565b60006105d18282612964565b60006105d1826016612964565b60006105d182602c61298b565b60006105d1826055612995565b60006105d182605661299f565b6113da81831460676113cc565b6000606080606061180361206a565b905061180d61135a565b156118555761182387896000815181106110ea57fe5b600061182f828a6120d8565b90506118408983600954848b6129ac565b925061184f89846111f4612a90565b50611876565b60408051600280825260608201835290916020830190803683370190505091505b611881888287612b22565b909450925061189388846111f4612a90565b61189d81896120d8565b600955509750975097945050505050565b6118d5816000815181106118be57fe5b60200260200101516118d06001611d09565b612b8f565b816000815181106118e257fe5b602002602001018181525050611910816001815181106118fe57fe5b60200260200101516118d06000611d09565b8160018151811061191d57fe5b60200260200101818152505050565b3330146119ea576000306001600160a01b03166000366040516119509291906148b5565b6000604051808303816000865af19150503d806000811461198d576040519150601f19603f3d011682016040523d82523d6000602084013e611992565b606091505b5050905080600081146119a157fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146119cc573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b6119f386611b35565b60006060611a0a8b8b8b8b8b8b8b8b63ffffffff16565b5091509150611a1c818463ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b505050505050505050565b60009081526007602052604090205490565b6000806000806000806000611a7188612baf565b9650611a7c88612bbc565b9550611a8788612bc9565b9450611a9288612bd6565b9350611a9d88612be3565b9250611aa888612bf0565b9150611ab3886123d0565b9050919395979092949650565b600082820261079e841580611add575083858381611ada57fe5b04145b60036113cc565b6000611af382151560046113cc565b82611b00575060006105d1565b670de0b6b3a764000083810290611b2390858381611b1a57fe5b041460056113cc565b828181611b2c57fe5b049150506105d1565b611b5c81600081518110611b4557fe5b6020026020010151611b576001611d09565b611ac0565b81600081518110611b6957fe5b60200260200101818152505061191081600181518110611b8557fe5b6020026020010151611b576000611d09565b6001600160a01b038216600090815260208190526040902054611bbf828210156101966113cc565b6001600160a01b03831660009081526020819052604090208282039055600254611be990836111f4565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906112a1908690614993565b60006060806060611c3961206a565b90506000611c47828a6120d8565b90506060611c5a8a84600954858c6129ac565b9050611c698a826111f4612a90565b60006060611c788c868b612bfd565b91509150611c898c826111c6612a90565b611c93858d6120d8565b600955909e909d50909b509950505050505050505050565b611cd281600081518110611cbb57fe5b6020026020010151611ccd6001611d09565b612c57565b81600081518110611cdf57fe5b60200260200101818152505061191081600181518110611cfb57fe5b6020026020010151611ccd60005b600081611d36577f00000000000000000000000000000000000000000000000000000000000000006105d1565b507f0000000000000000000000000000000000000000000000000000000000000000919050565b600081611d8a577f00000000000000000000000000000000000000000000000000000000000000006105d1565b507f0000000000000000000000000000000000000000000000000000000000000000919050565b600061079e8383611ac0565b600854611dc9816117cd565b8015611dd457508343115b15611ebd576000611e277f0000000000000000000000000000000000000000000000000000000000000000857f000000000000000000000000000000000000000000000000000000000000000086612c8a565b90506000611e5e7f000000000000000000000000000000000000000000000000000000000000000086611e59866117b3565b612cbf565b90506000611e6b846113bf565b90506000611e78856117c0565b90506000611e9182848787611e8c8b6117a7565b612cdb565b9050808314611a4057611ea48682612d32565b9550611eb08642612d40565b6008819055955050505050505b50505050565b6000828202611edd841580611add575083858381611ada57fe5b80611eec5760009150506105d1565b670de0b6b3a764000060001982015b046001019150506105d1565b6000611f1a858486858a60600151612d4e565b90505b95945050505050565b600061079e8383612b8f565b6000611f1a858486858a60600151612dc9565b600061079e8383612c57565b6000670de0b6b3a76400008210611f695760006105d1565b50670de0b6b3a76400000390565b6000611f8682151560046113cc565b82611f93575060006105d1565b670de0b6b3a764000083810290611fad90858381611b1a57fe5b826001820381611efb57fe5b6000611fc3610bb6565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611ffb57600080fd5b505afa15801561200f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e89190614605565b60008061203f83611a4b565b9050612058600061204f836123d0565b116101396113cc565b61206281856123dc565b949350505050565b6040805160028082526060808301845292839291906020830190803683370190505090506120986001611d5d565b816000815181106120a557fe5b6020026020010181815250506120bb6000611d5d565b816001815181106120c857fe5b6020908102919091010152905090565b670de0b6b3a764000060005b835181101561213a576121306121298583815181106120ff57fe5b602002602001015185848151811061211357fe5b6020026020010151612e3f90919063ffffffff16565b8390612e8e565b91506001016120e4565b506105d1600082116101376113cc565b60006121546116a1565b82604051602001610b509291906148c5565b60006060600061217584612eba565b9050612190600082600281111561218857fe5b1460ce6113cc565b606061219b85612ed0565b90506121a9815160026117e7565b6121b281611b35565b60606121bc61206a565b905060006121ca82846120d8565b905060006121d9826002611ac0565b6009929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461221290826111c6565b6001600160a01b03831660009081526020819052604090205560025461223890826111c6565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612279908590614993565b60405180910390a35050565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b6122a4610b92565b6001600160a01b0316141580156122bf57506122bf83612ee6565b156122e7576122cc610b92565b6001600160a01b0316336001600160a01b03161490506105d1565b6122ef611fb9565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b815260040161231e9392919061499c565b60206040518083038186803b15801561233657600080fd5b505afa15801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e91906144c5565b90506105d1565b1c6103ff1690565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006105d1828261298b565b6000808260028111156123eb57fe5b14156123fa5761236e83612baf565b600182600281111561240857fe5b14156124175761236e83612bc9565b61236e83612be3565b60008082600281111561242f57fe5b141561243e5761236e83612bbc565b600182600281111561244c57fe5b141561245b5761236e83612bd6565b61236e83612bf0565b60006105d1826001612f00565b600080806103ff8180805b8385116124e857600285850104612493818a612f00565b935061249e84611a4b565b92506124a9836123d0565b9150898210156124be578060010195506124e2565b898211156124d1576001810394506124e2565b82839750975050505050505061251d565b5061247c565b888110612506576125006124fb84612f11565b611a4b565b82612513565b816125136124fb85612464565b9650965050505050505b9250929050565b6000612553680238fd42c5cf03ffff19831215801561254c575068070c1cc73b00c800008313155b60096113cc565b60008212156125865761256882600003612524565b6a0c097ce7bc90715b34b9f160241b8161257e57fe5b059050610a56565b60006806f05b59d3b200000083126125c657506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec6302628270000000006125fc565b6803782dace9d900000083126125f857506803782dace9d8ffffff19909101906b1425982cf597cd205cef73806125fc565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac62000000841261264c5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412612688576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b1880000084126126c257682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c40000084126126fc576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac6200000841261273557680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d63100000841261276e5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b188000084126127a7576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c4000084126127e05768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b60008061290d83612f1e565b9050655af3107a40006000821361292c57652d79883d20008203612936565b652d79883d200082015b8161293d57fe5b059392505050565b600061079e838383612f7a565b600061079e83836016612f7a565b4690565b600082821c623fffff16621fffff811361297e5780612062565b623fffff19179392505050565b1c637fffffff1690565b1c60019081161490565b1c6001600160401b031690565b604080516002808252606080830184529283929190602083019080368337019050509050826129dc579050611f1d565b612a4f877f000000000000000000000000000000000000000000000000000000000000000081518110612a0b57fe5b6020026020010151877f000000000000000000000000000000000000000000000000000000000000000081518110612a3f57fe5b6020026020010151878787612f91565b817f000000000000000000000000000000000000000000000000000000000000000081518110612a7b57fe5b60209081029190910101529695505050505050565b612ac683600081518110612aa057fe5b602002602001015183600081518110612ab557fe5b60200260200101518363ffffffff16565b83600081518110612ad357fe5b602002602001018181525050612b0483600181518110612aef57fe5b602002602001015183600181518110612ab557fe5b83600181518110612b1157fe5b602002602001018181525050505050565b600060606000612b3184612eba565b90506000816002811115612b4157fe5b1415612b5c57612b52868686613009565b9250925050612b87565b6001816002811115612b6a57fe5b1415612b7a57612b5286856130b9565b612b528686866130eb565b505b935093915050565b6000612b9e82151560046113cc565b818381612ba757fe5b049392505050565b60006105d18260ea612964565b60006105d18260b5613157565b60006105d182609f612964565b60006105d182606a613157565b60006105d1826054612964565b60006105d182601f613157565b600060606000612c0c84612eba565b90506001816002811115612c1c57fe5b1415612c2d57612b5286868661318a565b6002816002811115612c3b57fe5b1415612c4c57612b528686866131e0565b612b8561013661237d565b6000612c6682151560046113cc565b82612c73575060006105d1565b816001840381612c7f57fe5b0460010190506105d1565b600080612caa612c9a8486611f77565b612ca48789611f77565b90611f77565b9050612cb581612901565b9695505050505050565b600080612ccf61168f8587611f77565b92909203949350505050565b600080612cf785858542612cee8b611a4b565b93929190613263565b9050607842889003101580612d0c5786612d15565b612d1587612464565b600081815260076020526040902092909255509695505050505050565b600061079e8383604b6132b5565b600061079e8383602c6132c5565b6000612d70612d6587670429d069189e0000612e8e565b8311156101306113cc565b6000612d7c87846111c6565b90506000612d8a8883611f77565b90506000612d988887611ae4565b90506000612da683836132d7565b9050612dbb612db482611f51565b8990612e8e565b9a9950505050505050505050565b6000612deb612de085670429d069189e0000612e8e565b8311156101316113cc565b6000612e01612dfa86856111f4565b8690611f77565b90506000612e0f8588611f77565b90506000612e1d83836132d7565b90506000612e3382670de0b6b3a76400006111f4565b9050612dbb8a82611ec3565b600080612e4c8484613303565b90506000612e66612e5f83612710611ec3565b60016111c6565b905080821015612e7b576000925050506105d1565b612e8582826111f4565b925050506105d1565b6000828202612ea8841580611add575083858381611ada57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906105d19190614621565b60608180602001905181019061079e91906146e6565b6000612ef8631c74c91760e11b610b1b565b909114919050565b60006104008383015b069392505050565b60006105d1826001613404565b6000612f2e6000831360646113cc565b670c7d713b49da000082138015612f4c5750670f43fc2c04ee000082125b15612f6a57670de0b6b3a7640000612f6383613413565b8161257e57fe5b612f7382613531565b9050610a56565b623fffff828116821b90821b198416179392505050565b6000838311612fa257506000611f1d565b6000612fae8585611f77565b90506000612fc4670de0b6b3a764000088611ae4565b9050612fd8826709b6e64a8ec600006138d0565b91506000612fe683836132d7565b90506000612ffd612ff683611f51565b8b90612e8e565b9050612dbb8187612e8e565b60006060613015611606565b600080613021856138e7565b915091506130336002821060646113cc565b604080516002808252606080830184529260208301908036833701905050905061309488838151811061306257fe5b602002602001015188848151811061307657fe5b6020026020010151856130876105eb565b61308f610885565b613909565b8183815181106130a057fe5b6020908102919091010152919791965090945050505050565b6000606060006130c8846139c0565b905060606130de86836130d96105eb565b6139d6565b9196919550909350505050565b600060606130f7611606565b6060600061310485613a87565b91509150613114825160026117e7565b61311d82611b35565b600061313a88888561312d6105eb565b613135610885565b613a9f565b905061314a8282111560cf6113cc565b9791965090945050505050565b600082821c661fffffffffffff16660fffffffffffff81136131795780612062565b661fffffffffffff19179392505050565b6000606080600061319a85613a87565b915091506131aa825160026117e7565b6131b382611b35565b60006131d08888856131c36105eb565b6131cb610885565b613cca565b905061314a8282101560d06113cc565b600060606000806131f0856138e7565b915091506132026002821060646113cc565b604080516002808252606080830184529260208301908036833701905050905061309488838151811061323157fe5b602002602001015188848151811061324557fe5b6020026020010151856132566105eb565b61325e610885565b613eda565b60008061326f876123d0565b83039050600081870261328189612bbc565b01905060008287026132928a612bd6565b01905060008387026132a38b612bf0565b019050612dbb89848a858b868c613f7c565b6103ff811b1992909216911b1790565b637fffffff811b1992909216911b1790565b6000806132e48484613303565b905060006132f7612e5f83612710611ec3565b9050611f1d82826111c6565b6000816133195750670de0b6b3a76400006105d1565b82613326575060006105d1565b613337600160ff1b841060066113cc565b8261335d770bce5086492111aea88f4bb1ca6bcf584181ea8059f76532841060076113cc565b826000670c7d713b49da00008313801561337e5750670f43fc2c04ee000083125b156133b557600061338e84613413565b9050670de0b6b3a764000080820784020583670de0b6b3a7640000830502019150506133c3565b816133bf84613531565b0290505b670de0b6b3a764000090056133fb680238fd42c5cf03ffff1982128015906133f4575068070c1cc73b00c800008213155b60086113cc565b612cb581612524565b60006104008284038101612f09565b670de0b6b3a7640000026000806a0c097ce7bc90715b34b9f160241b808401906ec097ce7bc90715b34b9f0fffffffff198501028161344e57fe5b05905060006a0c097ce7bc90715b34b9f160241b82800205905081806a0c097ce7bc90715b34b9f160241b81840205915060038205016a0c097ce7bc90715b34b9f160241b82840205915060058205016a0c097ce7bc90715b34b9f160241b82840205915060078205016a0c097ce7bc90715b34b9f160241b82840205915060098205016a0c097ce7bc90715b34b9f160241b828402059150600b8205016a0c097ce7bc90715b34b9f160241b828402059150600d8205016a0c097ce7bc90715b34b9f160241b828402059150600f826002919005919091010295945050505050565b6000670de0b6b3a764000082121561356d57613563826a0c097ce7bc90715b34b9f160241b8161355d57fe5b05613531565b6000039050610a56565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c000000000000083126135be57770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e00000083126135f6576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff0084000831261363e576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a7008312613679576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf85083126136b057693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e283126136e757690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d03831261371c5768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb41746121110831261374757680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d831261377c576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f177578893793783126137b1576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b28660383126137e5576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac8312613819576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d63100000808603028161383c57fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000818310156138e0578161079e565b5090919050565b600080828060200190518101906138fe91906146b0565b909590945092505050565b60008061391a84612ca481886111f4565b90506139336709b6e64a8ec600008210156101326113cc565b600061395161394a670de0b6b3a764000089611ae4565b83906132d7565b9050600061396861396183611f51565b8a90612e8e565b9050600061397589611f51565b905060006139838383611ec3565b9050600061399184836111f4565b90506139b06139a96139a28a611f51565b8490612e8e565b82906111c6565b9c9b505050505050505050505050565b60008180602001905181019061079e9190614683565b606060006139e48484611ae4565b9050606085516001600160401b03811180156139ff57600080fd5b50604051908082528060200260200182016040528015613a29578160200160208202803683370190505b50905060005b8651811015613a7d57613a5e83888381518110613a4857fe5b6020026020010151612e8e90919063ffffffff16565b828281518110613a6a57fe5b6020908102919091010152600101613a2f565b5095945050505050565b60606000828060200190518101906138fe919061463d565b6000606084516001600160401b0381118015613aba57600080fd5b50604051908082528060200260200182016040528015613ae4578160200160208202803683370190505b5090506000805b8851811015613ba957613b44898281518110613b0357fe5b6020026020010151612ca4898481518110613b1a57fe5b60200260200101518c8581518110613b2e57fe5b60200260200101516111f490919063ffffffff16565b838281518110613b5057fe5b602002602001018181525050613b9f613b98898381518110613b6e57fe5b6020026020010151858481518110613b8257fe5b6020026020010151611ec390919063ffffffff16565b83906111c6565b9150600101613aeb565b50670de0b6b3a764000060005b8951811015613ca9576000848281518110613bcd57fe5b6020026020010151841115613c2b576000613bf6613bea86611f51565b8d8581518110613a4857fe5b90506000613c0a828c8681518110613b2e57fe5b9050613c22613b98613c1b8b611f51565b8390611f77565b92505050613c42565b888281518110613c3757fe5b602002602001015190505b6000613c6b8c8481518110613c5357fe5b6020026020010151610985848f8781518110613b2e57fe5b9050613c9d613c968c8581518110613c7f57fe5b602002602001015183612e3f90919063ffffffff16565b8590612e8e565b93505050600101613bb6565b50613cbd613cb682611f51565b8790611ec3565b9998505050505050505050565b6000606084516001600160401b0381118015613ce557600080fd5b50604051908082528060200260200182016040528015613d0f578160200160208202803683370190505b5090506000805b8851811015613db757613d6f898281518110613d2e57fe5b6020026020010151610985898481518110613d4557fe5b60200260200101518c8581518110613d5957fe5b60200260200101516111c690919063ffffffff16565b838281518110613d7b57fe5b602002602001018181525050613dad613b98898381518110613d9957fe5b6020026020010151858481518110613a4857fe5b9150600101613d16565b50670de0b6b3a764000060005b8951811015613e9857600083858381518110613ddc57fe5b60200260200101511115613e38576000613e01613bea86670de0b6b3a76400006111f4565b90506000613e15828c8681518110613b2e57fe5b9050613e2f613b98612129670de0b6b3a76400008c6111f4565b92505050613e4f565b888281518110613e4457fe5b602002602001015190505b6000613e788c8481518110613e6057fe5b6020026020010151610985848f8781518110613d5957fe5b9050613e8c613c968c8581518110613c7f57fe5b93505050600101613dc4565b50670de0b6b3a76400008110613ece57613ec4613ebd82670de0b6b3a76400006111f4565b8790612e8e565b9350505050611f1d565b60009350505050611f1d565b600080613eeb84612ca481886111c6565b9050613f046729a2241af62c00008211156101336113cc565b6000613f1b61394a670de0b6b3a764000089611f77565b90506000613f3b613f3483670de0b6b3a76400006111f4565b8a90611ec3565b90506000613f4889611f51565b90506000613f568383611ec3565b90506000613f6484836111f4565b90506139b06139a9613f758a611f51565b8490611f77565b6000613f888282613fdc565b613f9384601f613fe0565b613f9e866054613ff1565b613fa988606a613fe0565b613fb48a609f613ff1565b613fbf8c60b5613fe0565b613fca8e60ea613ff1565b17171717171798975050505050505050565b1b90565b661fffffffffffff91909116901b90565b623fffff91909116901b90565b6040805160608101909152806000815260200160008152602001600081525090565b604080518082019091526000808252602082015290565b80356105d181614b52565b600082601f830112614052578081fd5b815161406561406082614b33565b614b0d565b81815291506020808301908481018184028601820187101561408657600080fd5b60005b848110156140a557815184529282019290820190600101614089565b505050505092915050565b600082601f8301126140c0578081fd5b81356001600160401b038111156140d5578182fd5b6140e8601f8201601f1916602001614b0d565b91508082528360208285010111156140ff57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106105d157600080fd5b80356105d181614b75565b600060208284031215614143578081fd5b813561079e81614b52565b60008060408385031215614160578081fd5b823561416b81614b52565b9150602083013561417b81614b52565b809150509250929050565b60008060006060848603121561419a578081fd5b83356141a581614b52565b925060208401356141b581614b52565b929592945050506040919091013590565b600080600080600080600060e0888a0312156141e0578485fd5b87356141eb81614b52565b965060208801356141fb81614b52565b95506040880135945060608801359350608088013560ff8116811461421e578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561424d578182fd5b823561425881614b52565b946020939093013593505050565b60008060006060848603121561427a578081fd5b83516001600160401b0380821115614290578283fd5b818601915086601f8301126142a3578283fd5b81516142b161406082614b33565b80828252602080830192508086018b8283870289010111156142d1578788fd5b8796505b848710156142fc5780516142e881614b52565b8452600196909601959281019281016142d5565b508901519097509350505080821115614313578283fd5b5061432086828701614042565b925050604084015190509250925092565b60006020808385031215614343578182fd5b82356001600160401b03811115614358578283fd5b8301601f81018513614368578283fd5b803561437661406082614b33565b818152838101908385016040808502860187018a1015614394578788fd5b8795505b848610156143e15780828b0312156143ae578788fd5b6143b781614b0d565b6143c18b84614127565b815282880135888201528452600195909501949286019290810190614398565b509098975050505050505050565b60006020808385031215614401578182fd5b82356001600160401b03811115614416578283fd5b8301601f81018513614426578283fd5b803561443461406082614b33565b818152838101908385016060808502860187018a1015614452578788fd5b8795505b848610156143e15780828b03121561446c578788fd5b61447581614b0d565b61447f8b84614127565b81528288013588820152604080840135908201528452600195909501949286019290810190614456565b6000602082840312156144ba578081fd5b813561079e81614b67565b6000602082840312156144d6578081fd5b815161079e81614b67565b600080600080600080600060e0888a0312156144fb578081fd5b8735965060208089013561450e81614b52565b9650604089013561451e81614b52565b955060608901356001600160401b0380821115614539578384fd5b818b0191508b601f83011261454c578384fd5b813561455a61406082614b33565b8082825285820191508585018f878886028801011115614578578788fd5b8795505b8386101561459a57803583526001959095019491860191860161457c565b509850505060808b0135955060a08b0135945060c08b01359250808311156145c0578384fd5b50506145ce8a828b016140b0565b91505092959891949750929550565b6000602082840312156145ee578081fd5b81356001600160e01b03198116811461079e578182fd5b600060208284031215614616578081fd5b815161079e81614b52565b600060208284031215614632578081fd5b815161079e81614b75565b600080600060608486031215614651578081fd5b835161465c81614b75565b60208501519093506001600160401b03811115614677578182fd5b61432086828701614042565b60008060408385031215614695578182fd5b82516146a081614b75565b6020939093015192949293505050565b6000806000606084860312156146c4578081fd5b83516146cf81614b75565b602085015160409095015190969495509392505050565b600080604083850312156146f8578182fd5b825161470381614b75565b60208401519092506001600160401b0381111561471e578182fd5b61472a85828601614042565b9150509250929050565b600060208284031215614745578081fd5b813561079e81614b75565b600080600060608486031215614764578081fd5b83356001600160401b038082111561477a578283fd5b8186019150610120808389031215614790578384fd5b61479981614b0d565b90506147a58884614118565b81526147b48860208501614037565b60208201526147c68860408501614037565b6040820152606083013560608201526080830135608082015260a083013560a08201526147f68860c08501614037565b60c08201526148088860e08501614037565b60e08201526101008084013583811115614820578586fd5b61482c8a8287016140b0565b9183019190915250976020870135975060409096013595945050505050565b60006020828403121561485c578081fd5b5035919050565b6000815180845260208085019450808401835b8381101561489257815187529582019590820190600101614876565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b8181101561492c57835183529284019291840191600101614910565b50909695505050505050565b60006020825261079e6020830184614863565b60006040825261495e6040830185614863565b8281036020840152611f1d8185614863565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b9586526020860194909452604085019290925260608401521515608083015260a082015260c00190565b6000602080835283518082850152825b81811015614abf57858101830151858201604001528201614aa3565b81811115614ad05783604083870101525b50601f01601f1916929092016040019392505050565b6000838252604060208301526120626040830184614863565b60ff91909116815260200190565b6040518181016001600160401b0381118282101715614b2b57600080fd5b604052919050565b60006001600160401b03821115614b48578081fd5b5060209081020190565b6001600160a01b03811681146105e857600080fd5b80151581146105e857600080fd5b600381106105e857600080fdfea26469706673582212201dbf8d364d926088a19c5f3f5d0ca0ab72cf3eda8f3f78dda45ab2619de4b6d664736f6c63430007010033a264697066735822122062c63a2c3089490a939fe9f20e0e99ef310f04a393c33a92c66f45a3b2cea18064736f6c63430007010033", + "_disabled": [ { "inputs": [], "name": "getPauseConfiguration", @@ -123,6 +126,5 @@ "stateMutability": "view", "type": "function" } - ], - "bytecode": "0x60c060405234801561001057600080fd5b50604051615fe1380380615fe183398101604081905261002f9161004d565b60601b6001600160601b0319166080526276a700420160a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160601c60a051615f3b6100a660003980610221528061024b5250806102a75250615f3b6000f3fe60806040523480156200001157600080fd5b5060043610620000525760003560e01c80631596019b14620000575780632da47c4014620000865780636634b75314620000a05780638d928af814620000c6575b600080fd5b6200006e6200006836600462000548565b620000d0565b6040516200007d91906200068f565b60405180910390f35b620000906200021b565b6040516200007d929190620007a2565b620000b7620000b136600462000522565b62000287565b6040516200007d9190620006a3565b6200006e620002a5565b6000806000620000df6200021b565b91509150620000ed62000315565b60405180610180016040528062000103620002a5565b6001600160a01b031681526020018c81526020018b81526020018a6000815181106200012b57fe5b60200260200101516001600160a01b031681526020018a6001815181106200014f57fe5b60200260200101516001600160a01b03168152602001896000815181106200017357fe5b60200260200101518152602001896001815181106200018e57fe5b602002602001015181526020018881526020018481526020018381526020018715158152602001866001600160a01b03168152509050600081604051620001d5906200039c565b620001e19190620006ae565b604051809103906000f080158015620001fe573d6000803e3d6000fd5b5090506200020c81620002c9565b9b9a5050505050505050505050565b600080427f00000000000000000000000000000000000000000000000000000000000000008110156200027957807f000000000000000000000000000000000000000000000000000000000000000003925062278d00915062000282565b60009250600091505b509091565b6001600160a01b031660009081526020819052604090205460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b038116600081815260208190526040808220805460ff19166001179055517f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9190a250565b60405180610180016040528060006001600160a01b03168152602001606081526020016060815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681525090565b6156f3806200081383390190565b8035620003b781620007f9565b92915050565b600082601f830112620003ce578081fd5b8135620003e5620003df82620007d8565b620007b0565b8181529150602080830190848101818402860182018710156200040757600080fd5b60005b84811015620004335781356200042081620007f9565b845292820192908201906001016200040a565b505050505092915050565b600082601f8301126200044f578081fd5b813562000460620003df82620007d8565b8181529150602080830190848101818402860182018710156200048257600080fd5b60005b84811015620004335781358452928201929082019060010162000485565b80358015158114620003b757600080fd5b600082601f830112620004c5578081fd5b813567ffffffffffffffff811115620004dc578182fd5b620004f1601f8201601f1916602001620007b0565b91508082528360208285010111156200050957600080fd5b8060208401602084013760009082016020015292915050565b60006020828403121562000534578081fd5b81356200054181620007f9565b9392505050565b600080600080600080600060e0888a03121562000563578283fd5b873567ffffffffffffffff808211156200057b578485fd5b620005898b838c01620004b4565b985060208a01359150808211156200059f578485fd5b620005ad8b838c01620004b4565b975060408a0135915080821115620005c3578485fd5b620005d18b838c01620003bd565b965060608a0135915080821115620005e7578485fd5b50620005f68a828b016200043e565b945050608088013592506200060f8960a08a01620004a3565b9150620006208960c08a01620003aa565b905092959891949750929550565b6001600160a01b03169052565b15159052565b60008151808452815b8181101562000668576020818501810151868301820152016200064a565b818111156200067a5782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b901515815260200190565b600060208252620006c46020830184516200062e565b6020830151610180806040850152620006e26101a085018362000641565b91506040850151601f1985840301606086015262000701838262000641565b92505060608501516200071860808601826200062e565b5060808501516200072d60a08601826200062e565b5060a085015160c085015260c085015160e085015260e085015161010081818701528087015191505061012081818701528087015191505061014081818701528087015191505061016062000785818701836200063b565b860151905062000798858301826200062e565b5090949350505050565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715620007d057600080fd5b604052919050565b600067ffffffffffffffff821115620007ef578081fd5b5060209081020190565b6001600160a01b03811681146200080f57600080fd5b5056fe6102a06040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9610120523480156200003757600080fd5b50604051620056f3380380620056f38339810160408190526200005a916200080c565b61010081810151610120830151602080850151604080870151815180830190925260018252603160f81b8285019081526101608901513360805260601b6001600160601b03191660a052835194840194852060c052915190912060e0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f909552805193949293909291620000f391600391906200069f565b508051620001099060049060208401906200069f565b50620001219150506276a7008311156101946200040a565b6200013562278d008211156101956200040a565b4290910161014081815291016101605281015162000153906200041f565b60e081015162000163906200047b565b80516040516309b2760f60e01b81526000916001600160a01b0316906309b2760f90620001969060029060040162000a12565b602060405180830381600087803b158015620001b157600080fd5b505af1158015620001c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ec9190620007f3565b6040805160028082526060808301845293945090916020830190803683370190505090508260600151816000815181106200022357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508260800151816001815181106200025657fe5b6001600160a01b0392831660209182029290920101528351166366a9c7d283836002604051908082528060200260200182016040528015620002a2578160200160208202803683370190505b506040518463ffffffff1660e01b8152600401620002c39392919062000976565b600060405180830381600087803b158015620002de57600080fd5b505af1158015620002f3573d6000803e3d6000fd5b505084516001600160601b0319606091821b8116610180526101a08690528187018051831b82166101c052608088015190921b166101e052516200033a92509050620004f9565b6102605260808301516200034e90620004f9565b6102805260a08301516200036f90662386f26fc10000111561012e6200040a565b62000391662386f26fc100008460c00151101561012e6200040a60201b60201c565b6000620003b58460c001518560a001516200059b60201b620011c61790919060201c565b9050620003cf670de0b6b3a764000082146101346200040a565b60a0840180516102005260c085018051610220525190511015620003f5576001620003f8565b60005b60ff16610240525062000a6392505050565b816200041b576200041b81620005b8565b5050565b6200043b816008546200060b60201b620011d81790919060201c565b6008556040517f3e350b41e86a8e10f804ade6d35340d620be35569cc75ac943e8bb14ab80ead190620004709083906200096b565b60405180910390a150565b6200049064e8d4a5100082101560cb6200040a565b620004a867016345785d8a000082111560ca6200040a565b620004c4816008546200062a60201b620011e61790919060201c565b6008556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc906200047090839062000a27565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200053657600080fd5b505afa1580156200054b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000571919062000948565b60ff1690506000620005906012836200064960201b620011f41760201c565b600a0a949350505050565b6000828201620005af84821015836200040a565b90505b92915050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b6000620005af826055856200066160201b6200120a179092919060201c565b6000620005af826056856200068a60201b62001231179092919060201c565b60006200065b8383111560016200040a565b50900390565b60006001821b1984168284620006795760006200067c565b60015b60ff16901b17949350505050565b6001600160401b03811b1992909216911b1790565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620006e257805160ff191683800117855562000712565b8280016001018555821562000712579182015b8281111562000712578251825591602001919060010190620006f5565b506200072092915062000724565b5090565b5b8082111562000720576000815560010162000725565b80516001600160a01b0381168114620005b257600080fd5b80518015158114620005b257600080fd5b600082601f83011262000775578081fd5b81516001600160401b038111156200078b578182fd5b6020620007a1601f8301601f1916820162000a30565b92508183528481838601011115620007b857600080fd5b60005b82811015620007d8578481018201518482018301528101620007bb565b82811115620007ea5760008284860101525b50505092915050565b60006020828403121562000805578081fd5b5051919050565b6000602082840312156200081e578081fd5b81516001600160401b038082111562000835578283fd5b81840191506101808083870312156200084c578384fd5b620008578162000a30565b90506200086586846200073b565b815260208301518281111562000879578485fd5b620008878782860162000764565b6020830152506040830151828111156200089f578485fd5b620008ad8782860162000764565b604083015250620008c286606085016200073b565b6060820152620008d686608085016200073b565b608082015260a0838101519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101409150620009228683850162000753565b82820152610160915062000939868385016200073b565b91810191909152949350505050565b6000602082840312156200095a578081fd5b815160ff81168114620005af578182fd5b901515815260200190565b60006060820185835260206060818501528186518084526080860191508288019350845b81811015620009c257620009af855162000a57565b835293830193918301916001016200099a565b505084810360408601528551808252908201925081860190845b8181101562000a0457620009f1835162000a57565b85529383019391830191600101620009dc565b509298975050505050505050565b602081016003831062000a2157fe5b91905290565b90815260200190565b6040518181016001600160401b038111828210171562000a4f57600080fd5b604052919050565b6001600160a01b031690565b60805160a05160601c60c05160e051610100516101205161014051610160516101805160601c6101a0516101c05160601c6101e05160601c6102005161022051610240516102605161028051614bb862000b3b60003980611d12525080611d395250806129e25280612a165280612a52525080611d665280611e02525080611d8d5280611de05280611e3052505080610c6a525080610808525080610bb852508061139d525080611379525080610f205250806116a55250806116e75250806116c6525080610b94525080610b1f5250614bb86000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c806374f3b0091161013b578063aaabadc5116100b8578063d5c096c41161007c578063d5c096c4146104e1578063d73dd623146104f4578063dd62ed3e14610507578063f89f27ed1461051a578063ffd088eb1461052257610248565b8063aaabadc5146104a3578063b10be739146104ab578063b48b5b40146104be578063c0ff1a15146104c6578063d505accf146104ce57610248565b80638d928af8116100ff5780638d928af81461046557806395d89b411461046d5780639b02cdde146104755780639d2c110c1461047d578063a9059cbb1461049057610248565b806374f3b009146103f65780637ecebe0014610417578063851c1bb31461042a57806387ec68171461043d578063893d20e81461045057610248565b806338e9922e116101c957806360d1507c1161018d57806360d1507c1461038257806366188463146103a8578063679aefce146103bb5780636b843239146103c357806370a08231146103e357610248565b806338e9922e1461032457806338fff2d0146103375780634a6b0b151461033f57806355c67628146103595780636028bfd41461036157610248565b80631dccd830116102105780631dccd830146102cc57806323b872dd146102ec578063292c914a146102ff578063313ce567146103075780633644e5151461031c57610248565b806306fdde031461024d578063095ea7b31461026b57806316c38b3c1461028b57806318160ddd146102a05780631c0de051146102b5575b600080fd5b61025561052a565b6040516102629190614a93565b60405180910390f35b61027e61027936600461423b565b6105c0565b6040516102629190614970565b61029e6102993660046144a9565b6105d7565b005b6102a86105eb565b6040516102629190614993565b6102bd6105f1565b6040516102629392919061497b565b6102df6102da3660046143ef565b61061a565b6040516102629190614938565b61027e6102fa366004614186565b610722565b61029e6107a5565b61030f6107d9565b6040516102629190614aff565b6102a86107de565b61029e61033236600461484b565b6107ed565b6102a8610806565b61034761082a565b60405161026296959493929190614a69565b6102a8610885565b61037461036f3660046144e1565b610892565b604051610262929190614ae6565b61039561039036600461484b565b6108c3565b6040516102629796959493929190614a39565b61027e6103b636600461423b565b61090c565b6102a8610966565b6103d66103d1366004614331565b61098b565b60405161026291906148f4565b6102a86103f1366004614132565b610a3c565b6104096104043660046144e1565b610a5b565b60405161026292919061494b565b6102a8610425366004614132565b610b00565b6102a86104383660046145dd565b610b1b565b61037461044b3660046144e1565b610b6d565b610458610b92565b60405161026291906148e0565b610458610bb6565b610255610bda565b6102a8610c3b565b6102a861048b366004614750565b610c41565b61027e61049e36600461423b565b610df0565b610458610dfd565b6102a86104b9366004614734565b610e07565b6102a8610e29565b6102a8610e2f565b61029e6104dc3660046141c6565b610eeb565b6104096104ef3660046144e1565b611034565b61027e61050236600461423b565b611154565b6102a861051536600461414e565b61118a565b6102df6111b5565b6102a86111bf565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105b65780601f1061058b576101008083540402835291602001916105b6565b820191906000526020600020905b81548152906001019060200180831161059957829003601f168201915b5050505050905090565b60006105cd338484611246565b5060015b92915050565b6105df6112ae565b6105e8816112dc565b50565b60025490565b60008060006105fe61135a565b159250610609611377565b915061061361139b565b9050909192565b606081516001600160401b038111801561063357600080fd5b5060405190808252806020026020018201604052801561065d578160200160208202803683370190505b509050600061066d6008546113bf565b9050610677613ffe565b60005b845181101561071a5784818151811061068f57fe5b602002602001015191506106ad82602001516000141561013c6113cc565b60006106c883600001518585602001518660400151016113de565b905060006106df84600001518686604001516113de565b90506106f98460200151838303816106f357fe5b05611524565b86848151811061070557fe5b6020908102919091010152505060010161067a565b505050919050565b6001600160a01b038316600081815260016020908152604080832033808552925282205491926107609114806107585750838210155b6101976113cc565b61076b858585611537565b336001600160a01b0386161480159061078657506000198114155b15610798576107988533858403611246565b60019150505b9392505050565b6107ad611606565b6107b56112ae565b6107bf6001611619565b60006107c96105eb565b11156107d7576107d7611659565b565b601290565b60006107e86116a1565b905090565b6107f56112ae565b6107fd611606565b6105e88161173e565b7f000000000000000000000000000000000000000000000000000000000000000090565b60008060008060008060006008549050610843816117a7565b965061084e816117b3565b9550610859816117c0565b9450610864816113bf565b935061086f816117cd565b925061087a816117da565b915050909192939495565b60006107e86008546117da565b600060606108a2865160026117e7565b6108b7898989898989896117f46118ae61192c565b97509795505050505050565b60008060008060008060006108de610400891061013b6113cc565b60006108e989611a4b565b90506108f481611a5d565b959f949e50929c50909a509850965090945092505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106109485761094333856000611246565b61095c565b61095c338561095784876111f4565b611246565b5060019392505050565b60006107e86109736105eb565b61098561097e610e2f565b6002611ac0565b90611ae4565b606081516001600160401b03811180156109a457600080fd5b506040519080825280602002602001820160405280156109ce578160200160208202803683370190505b50905060006109de6008546113bf565b90506109e8614020565b60005b845181101561071a57848181518110610a0057fe5b60200260200101519150610a1d82600001518484602001516113de565b848281518110610a2957fe5b60209081029190910101526001016109eb565b6001600160a01b0381166000908152602081905260409020545b919050565b60608088610a85610a6a610bb6565b6001600160a01b0316336001600160a01b03161460cd6113cc565b610a9a610a90610806565b82146101f46113cc565b610aa387611b35565b6000606080610ab78d8d8d8d8d8d8d6117f4565b925092509250610ac78c84611b97565b610ad0826118ae565b610ad9816118ae565b610ae161135a565b15610aee57610aee611659565b909c909b509950505050505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f000000000000000000000000000000000000000000000000000000000000000082604051602001610b5092919061489d565b604051602081830303815290604052805190602001209050919050565b60006060610b7d865160026117e7565b6108b789898989898989611c2a611cab61192c565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105b65780601f1061058b576101008083540402835291602001916105b6565b60095490565b6000610c4b611606565b8360800151610c5b610a6a610bb6565b610c66610a90610806565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686602001516001600160a01b03161490506000610cae82611d09565b90506000610cbc8315611d09565b90506000610cc984611d5d565b90506000610cd78515611d5d565b9050610ce38985611db1565b9850610cef8884611db1565b9750610d188a60a0015186610d045789610d06565b8a5b87610d11578b610d13565b8a5b611dbd565b60008a516001811115610d2757fe5b1415610d95576000610d45610d3a610885565b60608d015190611ec3565b9050610d67610d61828d606001516111f490919063ffffffff16565b86611db1565b60608c01526000610d7b8c8c8c8787611f07565b9050610d878186611f26565b985050505050505050610de8565b610da38a6060015184611db1565b60608b01526000610db78b8b8b8686611f32565b9050610dc38186611f45565b9050610ddf610dd8610dd3610885565b611f51565b8290611f77565b97505050505050505b509392505050565b60006105cd338484611537565b60006107e8611fb9565b600080610e1e83610e196008546113bf565b612033565b905061079e81611524565b61040090565b60006060610e3b610bb6565b6001600160a01b031663f94d4668610e51610806565b6040518263ffffffff1660e01b8152600401610e6d9190614993565b60006040518083038186803b158015610e8557600080fd5b505afa158015610e99573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec19190810190614266565b50915050610ece81611b35565b6060610ed861206a565b9050610ee481836120d8565b9250505090565b610ef98442111560d16113cc565b6001600160a01b0387166000908152600560209081526040808320549051909291610f50917f0000000000000000000000000000000000000000000000000000000000000000918c918c918c9188918d91016149bb565b6040516020818303038152906040528051906020012090506000610f738261214a565b9050600060018288888860405160008152602001604052604051610f9a9493929190614a1b565b6020604051602081039080840390855afa158015610fbc573d6000803e3d6000fd5b5050604051601f1901519150610ffe90506001600160a01b03821615801590610ff657508b6001600160a01b0316826001600160a01b0316145b6101f86113cc565b6001600160a01b038b1660009081526005602052604090206001850190556110278b8b8b611246565b5050505050505050505050565b60608088611043610a6a610bb6565b61104e610a90610806565b611056611606565b60006110606105eb565b6110d0576110708b8b8b88612166565b94509050611085620f424082101560cc6113cc565b6110936000620f42406121ef565b6110a289620f424083036121ef565b6110ab84611cab565b604080516002808252606082018352909160208301908036833701905050925061113e565b6110d988611b35565b61110c87896000815181106110ea57fe5b60200260200101518a6001815181106110ff57fe5b6020026020010151611dbd565b61111b8b8b8b8b8b8b8b611c2a565b9095509350905061112c89826121ef565b61113584611cab565b61113e836118ae565b611146611659565b505097509795505050505050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916105cd91859061095790866111c6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606107e861206a565b6201de2090565b600082820161079e84821015836113cc565b600061079e8383605561120a565b600061079e83836056611231565b60006112048383111560016113cc565b50900390565b60006001821b1984168284611220576000611223565b60015b60ff16901b17949350505050565b6001600160401b03811b1992909216911b1790565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906112a1908590614993565b60405180910390a3505050565b60006112c56000356001600160e01b031916610b1b565b90506105e86112d48233612285565b6101916113cc565b80156112fc576112f76112ed611377565b42106101936113cc565b611311565b61131161130761139b565b42106101a96113cc565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be649061134f908390614970565b60405180910390a150565b600061136461139b565b4211806107e857505060065460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006105d182604b612375565b816113da576113da8161237d565b5050565b60006113ef824210156101386113cc565b4282900360006113fe85611a4b565b9050600061140b826123d0565b905061141c600082116101396113cc565b8281116114485780830380611431848a6123dc565b0261143c848a612420565b0194505050505061079e565b600061145387612464565b9050600061146082611a4b565b9050600061146d826123d0565b905061147e600082116101396113cc565b61148d8682111561013a6113cc565b505060008061149c8684612471565b9150915060006114ab836123d0565b6114b4836123d0565b039050801561150c5760006114c9848d612420565b6114d3848e612420565b03905060006114e1856123d0565b8903905082818302816114f057fe5b056114fb868f612420565b01995050505050505050505061079e565b611516838c612420565b97505050505050505061079e565b60006105d1655af3107a40008302612524565b6001600160a01b03831660009081526020819052604090205461155f828210156101966113cc565b6115766001600160a01b03841615156101996113cc565b6001600160a01b038085166000908152602081905260408082208585039055918516815220546115a690836111c6565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906115f8908690614993565b60405180910390a350505050565b6107d761161161135a565b6101926113cc565b60085461162690826111d8565b6008556040517f3e350b41e86a8e10f804ade6d35340d620be35569cc75ac943e8bb14ab80ead19061134f908390614970565b600854611665816117cd565b156105e85761167f611678600954612901565b8290612945565b905061169b61169461168f6105eb565b612901565b8290612952565b60085550565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061170e612960565b306040516020016117239594939291906149ef565b60405160208183030381529060405280519060200120905090565b61175164e8d4a5100082101560cb6113cc565b61176767016345785d8a000082111560ca6113cc565b60085461177490826111e6565b6008556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc9061134f908390614993565b60006105d18282612964565b60006105d1826016612964565b60006105d182602c61298b565b60006105d1826055612995565b60006105d182605661299f565b6113da81831460676113cc565b6000606080606061180361206a565b905061180d61135a565b156118555761182387896000815181106110ea57fe5b600061182f828a6120d8565b90506118408983600954848b6129ac565b925061184f89846111f4612a90565b50611876565b60408051600280825260608201835290916020830190803683370190505091505b611881888287612b22565b909450925061189388846111f4612a90565b61189d81896120d8565b600955509750975097945050505050565b6118d5816000815181106118be57fe5b60200260200101516118d06001611d09565b612b8f565b816000815181106118e257fe5b602002602001018181525050611910816001815181106118fe57fe5b60200260200101516118d06000611d09565b8160018151811061191d57fe5b60200260200101818152505050565b3330146119ea576000306001600160a01b03166000366040516119509291906148b5565b6000604051808303816000865af19150503d806000811461198d576040519150601f19603f3d011682016040523d82523d6000602084013e611992565b606091505b5050905080600081146119a157fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146119cc573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b6119f386611b35565b60006060611a0a8b8b8b8b8b8b8b8b63ffffffff16565b5091509150611a1c818463ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b505050505050505050565b60009081526007602052604090205490565b6000806000806000806000611a7188612baf565b9650611a7c88612bbc565b9550611a8788612bc9565b9450611a9288612bd6565b9350611a9d88612be3565b9250611aa888612bf0565b9150611ab3886123d0565b9050919395979092949650565b600082820261079e841580611add575083858381611ada57fe5b04145b60036113cc565b6000611af382151560046113cc565b82611b00575060006105d1565b670de0b6b3a764000083810290611b2390858381611b1a57fe5b041460056113cc565b828181611b2c57fe5b049150506105d1565b611b5c81600081518110611b4557fe5b6020026020010151611b576001611d09565b611ac0565b81600081518110611b6957fe5b60200260200101818152505061191081600181518110611b8557fe5b6020026020010151611b576000611d09565b6001600160a01b038216600090815260208190526040902054611bbf828210156101966113cc565b6001600160a01b03831660009081526020819052604090208282039055600254611be990836111f4565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906112a1908690614993565b60006060806060611c3961206a565b90506000611c47828a6120d8565b90506060611c5a8a84600954858c6129ac565b9050611c698a826111f4612a90565b60006060611c788c868b612bfd565b91509150611c898c826111c6612a90565b611c93858d6120d8565b600955909e909d50909b509950505050505050505050565b611cd281600081518110611cbb57fe5b6020026020010151611ccd6001611d09565b612c57565b81600081518110611cdf57fe5b60200260200101818152505061191081600181518110611cfb57fe5b6020026020010151611ccd60005b600081611d36577f00000000000000000000000000000000000000000000000000000000000000006105d1565b507f0000000000000000000000000000000000000000000000000000000000000000919050565b600081611d8a577f00000000000000000000000000000000000000000000000000000000000000006105d1565b507f0000000000000000000000000000000000000000000000000000000000000000919050565b600061079e8383611ac0565b600854611dc9816117cd565b8015611dd457508343115b15611ebd576000611e277f0000000000000000000000000000000000000000000000000000000000000000857f000000000000000000000000000000000000000000000000000000000000000086612c8a565b90506000611e5e7f000000000000000000000000000000000000000000000000000000000000000086611e59866117b3565b612cbf565b90506000611e6b846113bf565b90506000611e78856117c0565b90506000611e9182848787611e8c8b6117a7565b612cdb565b9050808314611a4057611ea48682612d32565b9550611eb08642612d40565b6008819055955050505050505b50505050565b6000828202611edd841580611add575083858381611ada57fe5b80611eec5760009150506105d1565b670de0b6b3a764000060001982015b046001019150506105d1565b6000611f1a858486858a60600151612d4e565b90505b95945050505050565b600061079e8383612b8f565b6000611f1a858486858a60600151612dc9565b600061079e8383612c57565b6000670de0b6b3a76400008210611f695760006105d1565b50670de0b6b3a76400000390565b6000611f8682151560046113cc565b82611f93575060006105d1565b670de0b6b3a764000083810290611fad90858381611b1a57fe5b826001820381611efb57fe5b6000611fc3610bb6565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611ffb57600080fd5b505afa15801561200f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e89190614605565b60008061203f83611a4b565b9050612058600061204f836123d0565b116101396113cc565b61206281856123dc565b949350505050565b6040805160028082526060808301845292839291906020830190803683370190505090506120986001611d5d565b816000815181106120a557fe5b6020026020010181815250506120bb6000611d5d565b816001815181106120c857fe5b6020908102919091010152905090565b670de0b6b3a764000060005b835181101561213a576121306121298583815181106120ff57fe5b602002602001015185848151811061211357fe5b6020026020010151612e3f90919063ffffffff16565b8390612e8e565b91506001016120e4565b506105d1600082116101376113cc565b60006121546116a1565b82604051602001610b509291906148c5565b60006060600061217584612eba565b9050612190600082600281111561218857fe5b1460ce6113cc565b606061219b85612ed0565b90506121a9815160026117e7565b6121b281611b35565b60606121bc61206a565b905060006121ca82846120d8565b905060006121d9826002611ac0565b6009929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461221290826111c6565b6001600160a01b03831660009081526020819052604090205560025461223890826111c6565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612279908590614993565b60405180910390a35050565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b6122a4610b92565b6001600160a01b0316141580156122bf57506122bf83612ee6565b156122e7576122cc610b92565b6001600160a01b0316336001600160a01b03161490506105d1565b6122ef611fb9565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b815260040161231e9392919061499c565b60206040518083038186803b15801561233657600080fd5b505afa15801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e91906144c5565b90506105d1565b1c6103ff1690565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006105d1828261298b565b6000808260028111156123eb57fe5b14156123fa5761236e83612baf565b600182600281111561240857fe5b14156124175761236e83612bc9565b61236e83612be3565b60008082600281111561242f57fe5b141561243e5761236e83612bbc565b600182600281111561244c57fe5b141561245b5761236e83612bd6565b61236e83612bf0565b60006105d1826001612f00565b600080806103ff8180805b8385116124e857600285850104612493818a612f00565b935061249e84611a4b565b92506124a9836123d0565b9150898210156124be578060010195506124e2565b898211156124d1576001810394506124e2565b82839750975050505050505061251d565b5061247c565b888110612506576125006124fb84612f11565b611a4b565b82612513565b816125136124fb85612464565b9650965050505050505b9250929050565b6000612553680238fd42c5cf03ffff19831215801561254c575068070c1cc73b00c800008313155b60096113cc565b60008212156125865761256882600003612524565b6a0c097ce7bc90715b34b9f160241b8161257e57fe5b059050610a56565b60006806f05b59d3b200000083126125c657506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec6302628270000000006125fc565b6803782dace9d900000083126125f857506803782dace9d8ffffff19909101906b1425982cf597cd205cef73806125fc565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac62000000841261264c5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412612688576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b1880000084126126c257682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c40000084126126fc576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac6200000841261273557680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d63100000841261276e5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b188000084126127a7576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c4000084126127e05768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b60008061290d83612f1e565b9050655af3107a40006000821361292c57652d79883d20008203612936565b652d79883d200082015b8161293d57fe5b059392505050565b600061079e838383612f7a565b600061079e83836016612f7a565b4690565b600082821c623fffff16621fffff811361297e5780612062565b623fffff19179392505050565b1c637fffffff1690565b1c60019081161490565b1c6001600160401b031690565b604080516002808252606080830184529283929190602083019080368337019050509050826129dc579050611f1d565b612a4f877f000000000000000000000000000000000000000000000000000000000000000081518110612a0b57fe5b6020026020010151877f000000000000000000000000000000000000000000000000000000000000000081518110612a3f57fe5b6020026020010151878787612f91565b817f000000000000000000000000000000000000000000000000000000000000000081518110612a7b57fe5b60209081029190910101529695505050505050565b612ac683600081518110612aa057fe5b602002602001015183600081518110612ab557fe5b60200260200101518363ffffffff16565b83600081518110612ad357fe5b602002602001018181525050612b0483600181518110612aef57fe5b602002602001015183600181518110612ab557fe5b83600181518110612b1157fe5b602002602001018181525050505050565b600060606000612b3184612eba565b90506000816002811115612b4157fe5b1415612b5c57612b52868686613009565b9250925050612b87565b6001816002811115612b6a57fe5b1415612b7a57612b5286856130b9565b612b528686866130eb565b505b935093915050565b6000612b9e82151560046113cc565b818381612ba757fe5b049392505050565b60006105d18260ea612964565b60006105d18260b5613157565b60006105d182609f612964565b60006105d182606a613157565b60006105d1826054612964565b60006105d182601f613157565b600060606000612c0c84612eba565b90506001816002811115612c1c57fe5b1415612c2d57612b5286868661318a565b6002816002811115612c3b57fe5b1415612c4c57612b528686866131e0565b612b8561013661237d565b6000612c6682151560046113cc565b82612c73575060006105d1565b816001840381612c7f57fe5b0460010190506105d1565b600080612caa612c9a8486611f77565b612ca48789611f77565b90611f77565b9050612cb581612901565b9695505050505050565b600080612ccf61168f8587611f77565b92909203949350505050565b600080612cf785858542612cee8b611a4b565b93929190613263565b9050607842889003101580612d0c5786612d15565b612d1587612464565b600081815260076020526040902092909255509695505050505050565b600061079e8383604b6132b5565b600061079e8383602c6132c5565b6000612d70612d6587670429d069189e0000612e8e565b8311156101306113cc565b6000612d7c87846111c6565b90506000612d8a8883611f77565b90506000612d988887611ae4565b90506000612da683836132d7565b9050612dbb612db482611f51565b8990612e8e565b9a9950505050505050505050565b6000612deb612de085670429d069189e0000612e8e565b8311156101316113cc565b6000612e01612dfa86856111f4565b8690611f77565b90506000612e0f8588611f77565b90506000612e1d83836132d7565b90506000612e3382670de0b6b3a76400006111f4565b9050612dbb8a82611ec3565b600080612e4c8484613303565b90506000612e66612e5f83612710611ec3565b60016111c6565b905080821015612e7b576000925050506105d1565b612e8582826111f4565b925050506105d1565b6000828202612ea8841580611add575083858381611ada57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906105d19190614621565b60608180602001905181019061079e91906146e6565b6000612ef8631c74c91760e11b610b1b565b909114919050565b60006104008383015b069392505050565b60006105d1826001613404565b6000612f2e6000831360646113cc565b670c7d713b49da000082138015612f4c5750670f43fc2c04ee000082125b15612f6a57670de0b6b3a7640000612f6383613413565b8161257e57fe5b612f7382613531565b9050610a56565b623fffff828116821b90821b198416179392505050565b6000838311612fa257506000611f1d565b6000612fae8585611f77565b90506000612fc4670de0b6b3a764000088611ae4565b9050612fd8826709b6e64a8ec600006138d0565b91506000612fe683836132d7565b90506000612ffd612ff683611f51565b8b90612e8e565b9050612dbb8187612e8e565b60006060613015611606565b600080613021856138e7565b915091506130336002821060646113cc565b604080516002808252606080830184529260208301908036833701905050905061309488838151811061306257fe5b602002602001015188848151811061307657fe5b6020026020010151856130876105eb565b61308f610885565b613909565b8183815181106130a057fe5b6020908102919091010152919791965090945050505050565b6000606060006130c8846139c0565b905060606130de86836130d96105eb565b6139d6565b9196919550909350505050565b600060606130f7611606565b6060600061310485613a87565b91509150613114825160026117e7565b61311d82611b35565b600061313a88888561312d6105eb565b613135610885565b613a9f565b905061314a8282111560cf6113cc565b9791965090945050505050565b600082821c661fffffffffffff16660fffffffffffff81136131795780612062565b661fffffffffffff19179392505050565b6000606080600061319a85613a87565b915091506131aa825160026117e7565b6131b382611b35565b60006131d08888856131c36105eb565b6131cb610885565b613cca565b905061314a8282101560d06113cc565b600060606000806131f0856138e7565b915091506132026002821060646113cc565b604080516002808252606080830184529260208301908036833701905050905061309488838151811061323157fe5b602002602001015188848151811061324557fe5b6020026020010151856132566105eb565b61325e610885565b613eda565b60008061326f876123d0565b83039050600081870261328189612bbc565b01905060008287026132928a612bd6565b01905060008387026132a38b612bf0565b019050612dbb89848a858b868c613f7c565b6103ff811b1992909216911b1790565b637fffffff811b1992909216911b1790565b6000806132e48484613303565b905060006132f7612e5f83612710611ec3565b9050611f1d82826111c6565b6000816133195750670de0b6b3a76400006105d1565b82613326575060006105d1565b613337600160ff1b841060066113cc565b8261335d770bce5086492111aea88f4bb1ca6bcf584181ea8059f76532841060076113cc565b826000670c7d713b49da00008313801561337e5750670f43fc2c04ee000083125b156133b557600061338e84613413565b9050670de0b6b3a764000080820784020583670de0b6b3a7640000830502019150506133c3565b816133bf84613531565b0290505b670de0b6b3a764000090056133fb680238fd42c5cf03ffff1982128015906133f4575068070c1cc73b00c800008213155b60086113cc565b612cb581612524565b60006104008284038101612f09565b670de0b6b3a7640000026000806a0c097ce7bc90715b34b9f160241b808401906ec097ce7bc90715b34b9f0fffffffff198501028161344e57fe5b05905060006a0c097ce7bc90715b34b9f160241b82800205905081806a0c097ce7bc90715b34b9f160241b81840205915060038205016a0c097ce7bc90715b34b9f160241b82840205915060058205016a0c097ce7bc90715b34b9f160241b82840205915060078205016a0c097ce7bc90715b34b9f160241b82840205915060098205016a0c097ce7bc90715b34b9f160241b828402059150600b8205016a0c097ce7bc90715b34b9f160241b828402059150600d8205016a0c097ce7bc90715b34b9f160241b828402059150600f826002919005919091010295945050505050565b6000670de0b6b3a764000082121561356d57613563826a0c097ce7bc90715b34b9f160241b8161355d57fe5b05613531565b6000039050610a56565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c000000000000083126135be57770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e00000083126135f6576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff0084000831261363e576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a7008312613679576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf85083126136b057693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e283126136e757690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d03831261371c5768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb41746121110831261374757680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d831261377c576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f177578893793783126137b1576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b28660383126137e5576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac8312613819576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d63100000808603028161383c57fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000818310156138e0578161079e565b5090919050565b600080828060200190518101906138fe91906146b0565b909590945092505050565b60008061391a84612ca481886111f4565b90506139336709b6e64a8ec600008210156101326113cc565b600061395161394a670de0b6b3a764000089611ae4565b83906132d7565b9050600061396861396183611f51565b8a90612e8e565b9050600061397589611f51565b905060006139838383611ec3565b9050600061399184836111f4565b90506139b06139a96139a28a611f51565b8490612e8e565b82906111c6565b9c9b505050505050505050505050565b60008180602001905181019061079e9190614683565b606060006139e48484611ae4565b9050606085516001600160401b03811180156139ff57600080fd5b50604051908082528060200260200182016040528015613a29578160200160208202803683370190505b50905060005b8651811015613a7d57613a5e83888381518110613a4857fe5b6020026020010151612e8e90919063ffffffff16565b828281518110613a6a57fe5b6020908102919091010152600101613a2f565b5095945050505050565b60606000828060200190518101906138fe919061463d565b6000606084516001600160401b0381118015613aba57600080fd5b50604051908082528060200260200182016040528015613ae4578160200160208202803683370190505b5090506000805b8851811015613ba957613b44898281518110613b0357fe5b6020026020010151612ca4898481518110613b1a57fe5b60200260200101518c8581518110613b2e57fe5b60200260200101516111f490919063ffffffff16565b838281518110613b5057fe5b602002602001018181525050613b9f613b98898381518110613b6e57fe5b6020026020010151858481518110613b8257fe5b6020026020010151611ec390919063ffffffff16565b83906111c6565b9150600101613aeb565b50670de0b6b3a764000060005b8951811015613ca9576000848281518110613bcd57fe5b6020026020010151841115613c2b576000613bf6613bea86611f51565b8d8581518110613a4857fe5b90506000613c0a828c8681518110613b2e57fe5b9050613c22613b98613c1b8b611f51565b8390611f77565b92505050613c42565b888281518110613c3757fe5b602002602001015190505b6000613c6b8c8481518110613c5357fe5b6020026020010151610985848f8781518110613b2e57fe5b9050613c9d613c968c8581518110613c7f57fe5b602002602001015183612e3f90919063ffffffff16565b8590612e8e565b93505050600101613bb6565b50613cbd613cb682611f51565b8790611ec3565b9998505050505050505050565b6000606084516001600160401b0381118015613ce557600080fd5b50604051908082528060200260200182016040528015613d0f578160200160208202803683370190505b5090506000805b8851811015613db757613d6f898281518110613d2e57fe5b6020026020010151610985898481518110613d4557fe5b60200260200101518c8581518110613d5957fe5b60200260200101516111c690919063ffffffff16565b838281518110613d7b57fe5b602002602001018181525050613dad613b98898381518110613d9957fe5b6020026020010151858481518110613a4857fe5b9150600101613d16565b50670de0b6b3a764000060005b8951811015613e9857600083858381518110613ddc57fe5b60200260200101511115613e38576000613e01613bea86670de0b6b3a76400006111f4565b90506000613e15828c8681518110613b2e57fe5b9050613e2f613b98612129670de0b6b3a76400008c6111f4565b92505050613e4f565b888281518110613e4457fe5b602002602001015190505b6000613e788c8481518110613e6057fe5b6020026020010151610985848f8781518110613d5957fe5b9050613e8c613c968c8581518110613c7f57fe5b93505050600101613dc4565b50670de0b6b3a76400008110613ece57613ec4613ebd82670de0b6b3a76400006111f4565b8790612e8e565b9350505050611f1d565b60009350505050611f1d565b600080613eeb84612ca481886111c6565b9050613f046729a2241af62c00008211156101336113cc565b6000613f1b61394a670de0b6b3a764000089611f77565b90506000613f3b613f3483670de0b6b3a76400006111f4565b8a90611ec3565b90506000613f4889611f51565b90506000613f568383611ec3565b90506000613f6484836111f4565b90506139b06139a9613f758a611f51565b8490611f77565b6000613f888282613fdc565b613f9384601f613fe0565b613f9e866054613ff1565b613fa988606a613fe0565b613fb48a609f613ff1565b613fbf8c60b5613fe0565b613fca8e60ea613ff1565b17171717171798975050505050505050565b1b90565b661fffffffffffff91909116901b90565b623fffff91909116901b90565b6040805160608101909152806000815260200160008152602001600081525090565b604080518082019091526000808252602082015290565b80356105d181614b52565b600082601f830112614052578081fd5b815161406561406082614b33565b614b0d565b81815291506020808301908481018184028601820187101561408657600080fd5b60005b848110156140a557815184529282019290820190600101614089565b505050505092915050565b600082601f8301126140c0578081fd5b81356001600160401b038111156140d5578182fd5b6140e8601f8201601f1916602001614b0d565b91508082528360208285010111156140ff57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106105d157600080fd5b80356105d181614b75565b600060208284031215614143578081fd5b813561079e81614b52565b60008060408385031215614160578081fd5b823561416b81614b52565b9150602083013561417b81614b52565b809150509250929050565b60008060006060848603121561419a578081fd5b83356141a581614b52565b925060208401356141b581614b52565b929592945050506040919091013590565b600080600080600080600060e0888a0312156141e0578485fd5b87356141eb81614b52565b965060208801356141fb81614b52565b95506040880135945060608801359350608088013560ff8116811461421e578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561424d578182fd5b823561425881614b52565b946020939093013593505050565b60008060006060848603121561427a578081fd5b83516001600160401b0380821115614290578283fd5b818601915086601f8301126142a3578283fd5b81516142b161406082614b33565b80828252602080830192508086018b8283870289010111156142d1578788fd5b8796505b848710156142fc5780516142e881614b52565b8452600196909601959281019281016142d5565b508901519097509350505080821115614313578283fd5b5061432086828701614042565b925050604084015190509250925092565b60006020808385031215614343578182fd5b82356001600160401b03811115614358578283fd5b8301601f81018513614368578283fd5b803561437661406082614b33565b818152838101908385016040808502860187018a1015614394578788fd5b8795505b848610156143e15780828b0312156143ae578788fd5b6143b781614b0d565b6143c18b84614127565b815282880135888201528452600195909501949286019290810190614398565b509098975050505050505050565b60006020808385031215614401578182fd5b82356001600160401b03811115614416578283fd5b8301601f81018513614426578283fd5b803561443461406082614b33565b818152838101908385016060808502860187018a1015614452578788fd5b8795505b848610156143e15780828b03121561446c578788fd5b61447581614b0d565b61447f8b84614127565b81528288013588820152604080840135908201528452600195909501949286019290810190614456565b6000602082840312156144ba578081fd5b813561079e81614b67565b6000602082840312156144d6578081fd5b815161079e81614b67565b600080600080600080600060e0888a0312156144fb578081fd5b8735965060208089013561450e81614b52565b9650604089013561451e81614b52565b955060608901356001600160401b0380821115614539578384fd5b818b0191508b601f83011261454c578384fd5b813561455a61406082614b33565b8082825285820191508585018f878886028801011115614578578788fd5b8795505b8386101561459a57803583526001959095019491860191860161457c565b509850505060808b0135955060a08b0135945060c08b01359250808311156145c0578384fd5b50506145ce8a828b016140b0565b91505092959891949750929550565b6000602082840312156145ee578081fd5b81356001600160e01b03198116811461079e578182fd5b600060208284031215614616578081fd5b815161079e81614b52565b600060208284031215614632578081fd5b815161079e81614b75565b600080600060608486031215614651578081fd5b835161465c81614b75565b60208501519093506001600160401b03811115614677578182fd5b61432086828701614042565b60008060408385031215614695578182fd5b82516146a081614b75565b6020939093015192949293505050565b6000806000606084860312156146c4578081fd5b83516146cf81614b75565b602085015160409095015190969495509392505050565b600080604083850312156146f8578182fd5b825161470381614b75565b60208401519092506001600160401b0381111561471e578182fd5b61472a85828601614042565b9150509250929050565b600060208284031215614745578081fd5b813561079e81614b75565b600080600060608486031215614764578081fd5b83356001600160401b038082111561477a578283fd5b8186019150610120808389031215614790578384fd5b61479981614b0d565b90506147a58884614118565b81526147b48860208501614037565b60208201526147c68860408501614037565b6040820152606083013560608201526080830135608082015260a083013560a08201526147f68860c08501614037565b60c08201526148088860e08501614037565b60e08201526101008084013583811115614820578586fd5b61482c8a8287016140b0565b9183019190915250976020870135975060409096013595945050505050565b60006020828403121561485c578081fd5b5035919050565b6000815180845260208085019450808401835b8381101561489257815187529582019590820190600101614876565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b8181101561492c57835183529284019291840191600101614910565b50909695505050505050565b60006020825261079e6020830184614863565b60006040825261495e6040830185614863565b8281036020840152611f1d8185614863565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b9586526020860194909452604085019290925260608401521515608083015260a082015260c00190565b6000602080835283518082850152825b81811015614abf57858101830151858201604001528201614aa3565b81811115614ad05783604083870101525b50601f01601f1916929092016040019392505050565b6000838252604060208301526120626040830184614863565b60ff91909116815260200190565b6040518181016001600160401b0381118282101715614b2b57600080fd5b604052919050565b60006001600160401b03821115614b48578081fd5b5060209081020190565b6001600160a01b03811681146105e857600080fd5b80151581146105e857600080fd5b600381106105e857600080fdfea26469706673582212201dbf8d364d926088a19c5f3f5d0ca0ab72cf3eda8f3f78dda45ab2619de4b6d664736f6c63430007010033a264697066735822122062c63a2c3089490a939fe9f20e0e99ef310f04a393c33a92c66f45a3b2cea18064736f6c63430007010033" + ] } diff --git a/crates/contracts/artifacts/BalancerV2WeightedPoolFactory.json b/contracts/artifacts/BalancerV2WeightedPoolFactory.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2WeightedPoolFactory.json rename to contracts/artifacts/BalancerV2WeightedPoolFactory.json index 2b3a393535..18feaf9fa5 100644 --- a/crates/contracts/artifacts/BalancerV2WeightedPoolFactory.json +++ b/contracts/artifacts/BalancerV2WeightedPoolFactory.json @@ -67,7 +67,10 @@ ], "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "bytecode": "0x60c060405234801561001057600080fd5b5060405161604138038061604183398101604081905261002f9161004d565b60601b6001600160601b0319166080526276a700420160a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160601c60a051615f9c6100a56000398060d6528061010052508061015c5250615f9c6000f3fe60806040523480156200001157600080fd5b5060043610620000525760003560e01c80632da47c4014620000575780636634b753146200007a5780638d928af814620000a0578063fbce039314620000b9575b600080fd5b62000061620000d0565b6040516200007192919062000634565b60405180910390f35b620000916200008b366004620003c0565b6200013c565b60405162000071919062000562565b620000aa6200015a565b6040516200007191906200054e565b620000aa620000ca366004620003e6565b6200017e565b600080427f00000000000000000000000000000000000000000000000000000000000000008110156200012e57807f000000000000000000000000000000000000000000000000000000000000000003925062278d00915062000137565b60009250600091505b509091565b6001600160a01b031660009081526020819052604090205460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000090565b60008060006200018d620000d0565b9150915060006200019d6200015a565b8a8a8a8a8a88888c604051620001b3906200024b565b620001c7999897969594939291906200056d565b604051809103906000f080158015620001e4573d6000803e3d6000fd5b509050620001f281620001ff565b9998505050505050505050565b6001600160a01b038116600081815260208190526040808220805460ff19166001179055517f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9190a250565b6158b680620006b183390190565b8035620002668162000697565b92915050565b600082601f8301126200027d578081fd5b8135620002946200028e826200066a565b62000642565b818152915060208083019084810181840286018201871015620002b657600080fd5b60005b84811015620002e2578135620002cf8162000697565b84529282019290820190600101620002b9565b505050505092915050565b600082601f830112620002fe578081fd5b81356200030f6200028e826200066a565b8181529150602080830190848101818402860182018710156200033157600080fd5b60005b84811015620002e25781358452928201929082019060010162000334565b600082601f83011262000363578081fd5b813567ffffffffffffffff8111156200037a578182fd5b6200038f601f8201601f191660200162000642565b9150808252836020828501011115620003a757600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215620003d2578081fd5b8135620003df8162000697565b9392505050565b60008060008060008060c08789031215620003ff578182fd5b863567ffffffffffffffff8082111562000417578384fd5b620004258a838b0162000352565b975060208901359150808211156200043b578384fd5b620004498a838b0162000352565b965060408901359150808211156200045f578384fd5b6200046d8a838b016200026c565b9550606089013591508082111562000483578384fd5b506200049289828a01620002ed565b93505060808701359150620004ab8860a0890162000259565b90509295509295509295565b6001600160a01b03169052565b6000815180845260208085019450808401835b83811015620004f557815187529582019590820190600101620004d7565b509495945050505050565b60008151808452815b81811015620005275760208185018101518683018201520162000509565b81811115620005395782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b901515815260200190565b60006101206001600160a01b038c16835260208181850152620005938285018d62000500565b91508382036040850152620005a9828c62000500565b84810360608601528a51808252828c01935090820190845b81811015620005e957620005d685516200068b565b83529383019391830191600101620005c1565b50508481036080860152620005ff818b620004c4565b93505050508560a08301528460c08301528360e083015262000626610100830184620004b7565b9a9950505050505050505050565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156200066257600080fd5b604052919050565b600067ffffffffffffffff82111562000681578081fd5b5060209081020190565b6001600160a01b031690565b6001600160a01b0381168114620006ad57600080fd5b5056fe6105006040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9610120523480156200003757600080fd5b50604051620058b6380380620058b68339810160408190526200005a9162000cf2565b88888888878787878785516002146200007557600162000078565b60025b6040805180820190915260018152603160f81b6020808301918252336080526001600160601b0319606087901b1660a0528b51908c0190812060c0529151902060e0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6101005289518a918a918a918a918a918a918a91849184918a918a9162000107916003919062000abb565b5080516200011d90600490602084019062000abb565b50620001359150506276a70083111561019462000865565b6200014962278d0082111561019562000865565b42909101610140819052016101605284516200016b906002111560c862000865565b6200018360088651111560c96200086560201b60201c565b62000199856200087a60201b62000d571760201c565b620001a48462000886565b6040516309b2760f60e01b81526000906001600160a01b038b16906309b2760f90620001d5908c9060040162000eab565b602060405180830381600087803b158015620001f057600080fd5b505af115801562000205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022b919062000cd9565b9050896001600160a01b03166366a9c7d2828889516001600160401b03811180156200025657600080fd5b5060405190808252806020026020018201604052801562000281578160200160208202803683370190505b506040518463ffffffff1660e01b8152600401620002a29392919062000e0f565b600060405180830381600087803b158015620002bd57600080fd5b505af1158015620002d2573d6000803e3d6000fd5b5050506001600160601b031960608c901b1661018052506101a081905285516101c0528551620003045760006200031b565b856000815181106200031257fe5b60200260200101515b60601b6001600160601b0319166101e05285516001106200033e57600062000355565b856001815181106200034c57fe5b60200260200101515b60601b6001600160601b031916610200528551600210620003785760006200038f565b856002815181106200038657fe5b60200260200101515b60601b6001600160601b031916610220528551600310620003b2576000620003c9565b85600381518110620003c057fe5b60200260200101515b60601b6001600160601b031916610240528551600410620003ec57600062000403565b85600481518110620003fa57fe5b60200260200101515b60601b6001600160601b031916610260528551600510620004265760006200043d565b856005815181106200043457fe5b60200260200101515b60601b6001600160601b0319166102805285516006106200046057600062000477565b856006815181106200046e57fe5b60200260200101515b60601b6001600160601b0319166102a05285516007106200049a576000620004b1565b85600781518110620004a857fe5b60200260200101515b60601b6001600160601b0319166102c0528551620004d1576000620004f7565b620004f786600081518110620004e357fe5b6020026020010151620008f560201b60201c565b6102e05285516001106200050d5760006200051f565b6200051f86600181518110620004e357fe5b6103005285516002106200053557600062000547565b6200054786600281518110620004e357fe5b6103205285516003106200055d5760006200056f565b6200056f86600381518110620004e357fe5b6103405285516004106200058557600062000597565b6200059786600481518110620004e357fe5b610360528551600510620005ad576000620005bf565b620005bf86600581518110620004e357fe5b610380528551600610620005d5576000620005e7565b620005e786600681518110620004e357fe5b6103a0528551600710620005fd5760006200060f565b6200060f86600781518110620004e357fe5b6103c08181525050505050505050505050505050505050505050600086519050620006478187516200099760201b62000d651760201c565b6000806000805b848160ff161015620006cd5760008a8260ff16815181106200066c57fe5b6020026020010151905062000694662386f26fc1000082101561012e6200086560201b60201c565b620006ae8186620009a660201b62000d721790919060201c565b945082811115620006c3578160ff1693508092505b506001016200064e565b50620006e6670de0b6b3a7640000841461013462000865565b6103e08290528851620006fb57600062000712565b886000815181106200070957fe5b60200260200101515b610400528851600110620007285760006200073f565b886001815181106200073657fe5b60200260200101515b610420528851600210620007555760006200076c565b886002815181106200076357fe5b60200260200101515b6104405288516003106200078257600062000799565b886003815181106200079057fe5b60200260200101515b610460528851600410620007af576000620007c6565b88600481518110620007bd57fe5b60200260200101515b610480528851600510620007dc576000620007f3565b88600581518110620007ea57fe5b60200260200101515b6104a05288516006106200080957600062000820565b886006815181106200081757fe5b60200260200101515b6104c0528851600710620008365760006200084d565b886007815181106200084457fe5b60200260200101515b6104e0525062000f329b505050505050505050505050565b8162000876576200087681620009c3565b5050565b80620008768162000a16565b6200089b64e8d4a5100082101560cb62000865565b620008b367016345785d8a000082111560ca62000865565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90620008ea90839062000ec0565b60405180910390a150565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200093257600080fd5b505afa15801562000947573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200096d919062000dec565b60ff16905060006200098c60128362000aa360201b62000d841760201c565b600a0a949350505050565b62000876828214606762000865565b6000828201620009ba848210158362000865565b90505b92915050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60028151101562000a275762000aa0565b60008160008151811062000a3757fe5b602002602001015190506000600190505b825181101562000a9d57600083828151811062000a6157fe5b6020026020010151905062000a92816001600160a01b0316846001600160a01b03161060656200086560201b60201c565b915060010162000a48565b50505b50565b600062000ab583831115600162000865565b50900390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1062000afe57805160ff191683800117855562000b2e565b8280016001018555821562000b2e579182015b8281111562000b2e57825182559160200191906001019062000b11565b5062000b3c92915062000b40565b5090565b5b8082111562000b3c576000815560010162000b41565b8051620009bd8162000f1c565b600082601f83011262000b75578081fd5b815162000b8c62000b868262000ef0565b62000ec9565b81815291506020808301908481018184028601820187101562000bae57600080fd5b60005b8481101562000bda57815162000bc78162000f1c565b8452928201929082019060010162000bb1565b505050505092915050565b600082601f83011262000bf6578081fd5b815162000c0762000b868262000ef0565b81815291506020808301908481018184028601820187101562000c2957600080fd5b60005b8481101562000bda5781518452928201929082019060010162000c2c565b600082601f83011262000c5b578081fd5b81516001600160401b0381111562000c71578182fd5b602062000c87601f8301601f1916820162000ec9565b9250818352848183860101111562000c9e57600080fd5b60005b8281101562000cbe57848101820151848201830152810162000ca1565b8281111562000cd05760008284860101525b50505092915050565b60006020828403121562000ceb578081fd5b5051919050565b60008060008060008060008060006101208a8c03121562000d11578485fd5b62000d1d8b8b62000b57565b60208b01519099506001600160401b038082111562000d3a578687fd5b62000d488d838e0162000c4a565b995060408c015191508082111562000d5e578687fd5b62000d6c8d838e0162000c4a565b985060608c015191508082111562000d82578687fd5b62000d908d838e0162000b64565b975060808c015191508082111562000da6578687fd5b5062000db58c828d0162000be5565b95505060a08a0151935060c08a0151925060e08a0151915062000ddd8b6101008c0162000b57565b90509295985092959850929598565b60006020828403121562000dfe578081fd5b815160ff81168114620009ba578182fd5b60006060820185835260206060818501528186518084526080860191508288019350845b8181101562000e5b5762000e48855162000f10565b8352938301939183019160010162000e33565b505084810360408601528551808252908201925081860190845b8181101562000e9d5762000e8a835162000f10565b8552938301939183019160010162000e75565b509298975050505050505050565b602081016003831062000eba57fe5b91905290565b90815260200190565b6040518181016001600160401b038111828210171562000ee857600080fd5b604052919050565b60006001600160401b0382111562000f06578081fd5b5060209081020190565b6001600160a01b031690565b6001600160a01b038116811462000aa057600080fd5b60805160a05160601c60c05160e051610100516101205161014051610160516101805160601c6101a0516101c0516101e05160601c6102005160601c6102205160601c6102405160601c6102605160601c6102805160601c6102a05160601c6102c05160601c6102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a0516104c0516104e05161476e6200114860003980611ec55280612857525080611e8252806127f6525080611e3f5280612795525080611dfc5280612734525080611db952806126d3525080611d765280612672525080611d335280612611525080611cf052806125b05250806122d0528061230452806123405250806116285280611b1e5250806115e55280611abd5250806115a25280611a5c52508061155f52806119fb52508061151c528061199a5250806114d9528061193952508061149652806118d85250806114455280611877525080611ae3528061281c525080611a8252806127bb525080611a21528061275a5250806119c052806126f952508061195f52806126985250806118fe528061263752508061189d52806125d652508061183c52806125755250806111025250806105d7525080610835525080610ef1525080610ecd525080610ab5525080610ff452508061103652508061101552508061081152508061079b525061476e6000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c80637ecebe001161010f578063a9059cbb116100a2578063d5c096c411610071578063d5c096c4146103e6578063d73dd623146103f9578063dd62ed3e1461040c578063f89f27ed1461041f576101f0565b8063a9059cbb146103b0578063aaabadc5146103c3578063c0ff1a15146103cb578063d505accf146103d3576101f0565b80638d928af8116100de5780638d928af81461038557806395d89b411461038d5780639b02cdde146103955780639d2c110c1461039d576101f0565b80637ecebe0014610337578063851c1bb31461034a57806387ec68171461035d578063893d20e814610370576101f0565b806338e9922e11610187578063661884631161015657806366188463146102e8578063679aefce146102fb57806370a082311461030357806374f3b00914610316576101f0565b806338e9922e146102a457806338fff2d0146102b757806355c67628146102bf5780636028bfd4146102c7576101f0565b80631c0de051116101c35780631c0de0511461025d57806323b872dd14610274578063313ce567146102875780633644e5151461029c576101f0565b806306fdde03146101f5578063095ea7b31461021357806316c38b3c1461023357806318160ddd14610248575b600080fd5b6101fd610434565b60405161020a9190614647565b60405180910390f35b61022661022136600461401c565b6104cb565b60405161020a919061457e565b610246610241366004614113565b6104e2565b005b6102506104f6565b60405161020a91906145a1565b6102656104fc565b60405161020a93929190614589565b610226610282366004613f67565b610525565b61028f6105a8565b60405161020a91906146b3565b6102506105ad565b6102466102b236600461449d565b6105bc565b6102506105d5565b6102506105f9565b6102da6102d536600461414b565b6105ff565b60405161020a92919061469a565b6102266102f636600461401c565b610636565b610250610690565b610250610311366004613f13565b6106bb565b61032961032436600461414b565b6106da565b60405161020a929190614559565b610250610345366004613f13565b61077c565b610250610358366004614248565b610797565b6102da61036b36600461414b565b6107e9565b61037861080f565b60405161020a9190614532565b610378610833565b6101fd610857565b6102506108b8565b6102506103ab3660046143a1565b6108be565b6102266103be36600461401c565b6109a5565b6103786109b2565b6102506109bc565b6102466103e1366004613fa7565b610a80565b6103296103f436600461414b565b610bc9565b61022661040736600461401c565b610cec565b61025061041a366004613f2f565b610d22565b610427610d4d565b60405161020a9190614546565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b820191906000526020600020905b8154815290600101906020018083116104a357829003601f168201915b505050505090505b90565b60006104d8338484610d9a565b5060015b92915050565b6104ea610e02565b6104f381610e30565b50565b60025490565b6000806000610509610eae565b159250610514610ecb565b915061051e610eef565b9050909192565b6001600160a01b0383166000818152600160209081526040808320338085529252822054919261056391148061055b5750838210155b610197610f13565b61056e858585610f21565b336001600160a01b0386161480159061058957506000198114155b1561059b5761059b8533858403610d9a565b60019150505b9392505050565b601290565b60006105b7610ff0565b905090565b6105c4610e02565b6105cc61108d565b6104f3816110a2565b7f000000000000000000000000000000000000000000000000000000000000000090565b60075490565b600060606106158651610610611100565b610d65565b61062a898989898989896111246111ec611252565b97509795505050505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106106725761066d33856000610d9a565b610686565b61068633856106818487610d84565b610d9a565b5060019392505050565b60006105b761069d6104f6565b6106b56106a86109bc565b6106b0611100565b611374565b90611398565b6001600160a01b0381166000908152602081905260409020545b919050565b606080886107046106e9610833565b6001600160a01b0316336001600160a01b03161460cd610f13565b61071961070f6105d5565b82146101f4610f13565b60606107236113e9565b905061072f8882611666565b60006060806107438e8e8e8e8e8e8e611124565b9250925092506107538d846116c7565b61075d82856111ec565b61076781856111ec565b909550935050505b5097509795505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016107cc9291906144ef565b604051602081830303815290604052805190602001209050919050565b600060606107fa8651610610611100565b61062a8989898989898961175a6117d7611252565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b60085490565b6000806108ce8560200151611838565b905060006108df8660400151611838565b90506000865160018111156108f057fe5b1415610956576109038660600151611b4d565b60608701526109128583611b71565b945061091e8482611b71565b935061092e866060015183611b71565b60608701526000610940878787611b7d565b905061094c8183611bb8565b93505050506105a1565b6109608583611b71565b945061096c8482611b71565b935061097c866060015182611b71565b6060870152600061098e878787611bc4565b905061099a8184611bf7565b905061094c81611c03565b60006104d8338484610f21565b60006105b7611c1a565b600060606109c8610833565b6001600160a01b031663f94d46686109de6105d5565b6040518263ffffffff1660e01b81526004016109fa91906145a1565b60006040518083038186803b158015610a1257600080fd5b505afa158015610a26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a4e9190810190614047565b50915050610a6381610a5e6113e9565b611666565b6060610a6d611c94565b9050610a798183611ef1565b9250505090565b610a8e8442111560d1610f13565b6001600160a01b0387166000908152600560209081526040808320549051909291610ae5917f0000000000000000000000000000000000000000000000000000000000000000918c918c918c9188918d91016145c9565b6040516020818303038152906040528051906020012090506000610b0882611f63565b9050600060018288888860405160008152602001604052604051610b2f9493929190614629565b6020604051602081039080840390855afa158015610b51573d6000803e3d6000fd5b5050604051601f1901519150610b9390506001600160a01b03821615801590610b8b57508b6001600160a01b0316826001600160a01b0316145b6101f8610f13565b6001600160a01b038b166000908152600560205260409020600185019055610bbc8b8b8b610d9a565b5050505050505050505050565b60608088610bd86106e9610833565b610be361070f6105d5565b6060610bed6113e9565b9050610bf76104f6565b610c9d5760006060610c0b8d8d8d8a611f7f565b91509150610c20620f424083101560cc610f13565b610c2e6000620f424061201a565b610c3d8b620f4240840361201a565b610c4781846117d7565b80610c50611100565b67ffffffffffffffff81118015610c6657600080fd5b50604051908082528060200260200182016040528015610c90578160200160208202803683370190505b509550955050505061076f565b610ca78882611666565b6000606080610cbb8e8e8e8e8e8e8e61175a565b925092509250610ccb8c8461201a565b610cd582856117d7565b610cdf81856111ec565b909550935061076f915050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916104d89185906106819086610d72565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606105b7611c94565b80610d61816120b0565b5050565b610d618183146067610f13565b60008282016105a18482101583610f13565b6000610d94838311156001610f13565b50900390565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610df59085906145a1565b60405180910390a3505050565b6000610e196000356001600160e01b031916610797565b90506104f3610e288233612129565b610191610f13565b8015610e5057610e4b610e41610ecb565b4210610193610f13565b610e65565b610e65610e5b610eef565b42106101a9610f13565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490610ea390839061457e565b60405180910390a150565b6000610eb8610eef565b4211806105b757505060065460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b81610d6157610d6181612219565b6001600160a01b038316600090815260208190526040902054610f4982821015610196610f13565b610f606001600160a01b0384161515610199610f13565b6001600160a01b03808516600090815260208190526040808220858503905591851681522054610f909083610d72565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610fe29086906145a1565b60405180910390a350505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061105d61226c565b306040516020016110729594939291906145fd565b60405160208183030381529060405280519060200120905090565b6110a0611098610eae565b610192610f13565b565b6110b564e8d4a5100082101560cb610f13565b6110cb67016345785d8a000082111560ca610f13565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90610ea39083906145a1565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006060806060611133611c94565b905061113d610eae565b1561117457600061114e828a611ef1565b905061115f8983600854848b612270565b925061116e8984610d84612380565b506111c0565b61117c611100565b67ffffffffffffffff8111801561119257600080fd5b506040519080825280602002602001820160405280156111bc578160200160208202803683370190505b5091505b6111cb8882876123eb565b90945092506111db888483612458565b600855509750975097945050505050565b60005b6111f7611100565b81101561124d5761122e83828151811061120d57fe5b602002602001015183838151811061122157fe5b6020026020010151612471565b83828151811061123a57fe5b60209081029190910101526001016111ef565b505050565b333014611310576000306001600160a01b0316600036604051611276929190614507565b6000604051808303816000865af19150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5050905080600081146112c757fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146112f2573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b606061131a6113e9565b90506113268782611666565b6000606061133d8c8c8c8c8c8c8c8c63ffffffff16565b509150915061135081848663ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b60008282026105a184158061139157508385838161138e57fe5b04145b6003610f13565b60006113a78215156004610f13565b826113b4575060006104dc565b670de0b6b3a7640000838102906113d7908583816113ce57fe5b04146005610f13565b8281816113e057fe5b049150506104dc565b606060006113f5611100565b905060608167ffffffffffffffff8111801561141057600080fd5b5060405190808252806020026020018201604052801561143a578160200160208202803683370190505b5090508115611482577f00000000000000000000000000000000000000000000000000000000000000008160008151811061147157fe5b60200260200101818152505061148b565b91506104c89050565b6001821115611482577f0000000000000000000000000000000000000000000000000000000000000000816001815181106114c257fe5b6020026020010181815250506002821115611482577f00000000000000000000000000000000000000000000000000000000000000008160028151811061150557fe5b6020026020010181815250506003821115611482577f00000000000000000000000000000000000000000000000000000000000000008160038151811061154857fe5b6020026020010181815250506004821115611482577f00000000000000000000000000000000000000000000000000000000000000008160048151811061158b57fe5b6020026020010181815250506005821115611482577f0000000000000000000000000000000000000000000000000000000000000000816005815181106115ce57fe5b6020026020010181815250506006821115611482577f00000000000000000000000000000000000000000000000000000000000000008160068151811061161157fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b60200260200101818152505091505090565b60005b611671611100565b81101561124d576116a883828151811061168757fe5b602002602001015183838151811061169b57fe5b6020026020010151611374565b8382815181106116b457fe5b6020908102919091010152600101611669565b6001600160a01b0382166000908152602081905260409020546116ef82821015610196610f13565b6001600160a01b038316600090815260208190526040902082820390556002546117199083610d84565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610df59086906145a1565b600060608061176761108d565b6060611771611c94565b9050600061177f828a611ef1565b905060606117928a84600854858c612270565b90506117a18a82610d84612380565b600060606117b08c868b612491565b915091506117bf8c82876124eb565b600855909e909d50909b509950505050505050505050565b60005b6117e2611100565b81101561124d576118198382815181106117f857fe5b602002602001015183838151811061180c57fe5b60200260200101516124fa565b83828151811061182557fe5b60209081029190910101526001016117da565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561189b57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156118fc57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561195d57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156119be57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a1f57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a8057507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611ae157507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b6106d5610135612219565b600080611b656007548461252d90919063ffffffff16565b90506105a18382610d84565b60006105a18383611374565b6000611b8761108d565b611bb083611b988660200151612571565b84611ba68860400151612571565b886060015161287b565b949350505050565b60006105a18383612471565b6000611bce61108d565b611bb083611bdf8660200151612571565b84611bed8860400151612571565b88606001516128f6565b60006105a183836124fa565b60006104dc611c1360075461296c565b8390612992565b6000611c24610833565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5c57600080fd5b505afa158015611c70573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b79190614270565b60606000611ca0611100565b905060608167ffffffffffffffff81118015611cbb57600080fd5b50604051908082528060200260200182016040528015611ce5578160200160208202803683370190505b5090508115611482577f000000000000000000000000000000000000000000000000000000000000000081600081518110611d1c57fe5b6020026020010181815250506001821115611482577f000000000000000000000000000000000000000000000000000000000000000081600181518110611d5f57fe5b6020026020010181815250506002821115611482577f000000000000000000000000000000000000000000000000000000000000000081600281518110611da257fe5b6020026020010181815250506003821115611482577f000000000000000000000000000000000000000000000000000000000000000081600381518110611de557fe5b6020026020010181815250506004821115611482577f000000000000000000000000000000000000000000000000000000000000000081600481518110611e2857fe5b6020026020010181815250506005821115611482577f000000000000000000000000000000000000000000000000000000000000000081600581518110611e6b57fe5b6020026020010181815250506006821115611482577f000000000000000000000000000000000000000000000000000000000000000081600681518110611eae57fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b670de0b6b3a764000060005b8351811015611f5357611f49611f42858381518110611f1857fe5b6020026020010151858481518110611f2c57fe5b60200260200101516129d490919063ffffffff16565b8390612a23565b9150600101611efd565b506104dc60008211610137610f13565b6000611f6d610ff0565b826040516020016107cc929190614517565b60006060611f8b61108d565b6000611f9684612a4f565b9050611fb16000826002811115611fa957fe5b1460ce610f13565b6060611fbc85612a65565b9050611fd0611fc9611100565b8251610d65565b611fdc81610a5e6113e9565b6060611fe6611c94565b90506000611ff48284611ef1565b90506000612004826106b0611100565b6008929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461203d9082610d72565b6001600160a01b0383166000908152602081905260409020556002546120639082610d72565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906120a49085906145a1565b60405180910390a35050565b6002815110156120bf576104f3565b6000816000815181106120ce57fe5b602002602001015190506000600190505b825181101561124d5760008382815181106120f657fe5b6020026020010151905061211f816001600160a01b0316846001600160a01b0316106065610f13565b91506001016120df565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b61214861080f565b6001600160a01b031614158015612163575061216383612a7b565b1561218b5761217061080f565b6001600160a01b0316336001600160a01b03161490506104dc565b612193611c1a565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b81526004016121c2939291906145aa565b60206040518083038186803b1580156121da57600080fd5b505afa1580156121ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612212919061412f565b90506104dc565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b4690565b60608061227b611100565b67ffffffffffffffff8111801561229157600080fd5b506040519080825280602002602001820160405280156122bb578160200160208202803683370190505b509050826122ca579050612377565b61233d877f0000000000000000000000000000000000000000000000000000000000000000815181106122f957fe5b6020026020010151877f00000000000000000000000000000000000000000000000000000000000000008151811061232d57fe5b6020026020010151878787612a95565b817f00000000000000000000000000000000000000000000000000000000000000008151811061236957fe5b602090810291909101015290505b95945050505050565b60005b61238b611100565b8110156123e5576123c68482815181106123a157fe5b60200260200101518483815181106123b557fe5b60200260200101518463ffffffff16565b8482815181106123d257fe5b6020908102919091010152600101612383565b50505050565b6000606060006123fa84612a4f565b9050600081600281111561240a57fe5b14156124255761241b868686612b0d565b9250925050612450565b600181600281111561243357fe5b14156124435761241b8685612beb565b61241b868686612c1d565b505b935093915050565b60006124678484610d84612380565b611bb08285611ef1565b60006124808215156004610f13565b81838161248957fe5b049392505050565b6000606060006124a084612a4f565b905060018160028111156124b057fe5b14156124c15761241b868686612c88565b60028160028111156124cf57fe5b14156124e05761241b868686612ce2565b61244e610136612219565b60006124678484610d72612380565b60006125098215156004610f13565b82612516575060006104dc565b81600184038161252257fe5b0460010190506104dc565b600082820261254784158061139157508385838161138e57fe5b806125565760009150506104dc565b670de0b6b3a764000060001982015b046001019150506104dc565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156125d457507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561263557507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561269657507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156126f757507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561275857507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156127b957507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561281a57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b600061289d61289287670429d069189e0000612a23565b831115610130610f13565b60006128a98784610d72565b905060006128b78883612992565b905060006128c58887611398565b905060006128d38383612d8a565b90506128e86128e18261296c565b8990612a23565b9a9950505050505050505050565b600061291861290d85670429d069189e0000612a23565b831115610131610f13565b600061292e6129278685610d84565b8690612992565b9050600061293c8588612992565b9050600061294a8383612d8a565b9050600061296082670de0b6b3a7640000610d84565b90506128e88a8261252d565b6000670de0b6b3a764000082106129845760006104dc565b50670de0b6b3a76400000390565b60006129a18215156004610f13565b826129ae575060006104dc565b670de0b6b3a7640000838102906129c8908583816113ce57fe5b82600182038161256557fe5b6000806129e18484612db6565b905060006129fb6129f48361271061252d565b6001610d72565b905080821015612a10576000925050506104dc565b612a1a8282610d84565b925050506104dc565b6000828202612a3d84158061139157508385838161138e57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906104dc919061428c565b6060818060200190518101906105a19190614352565b6000612a8d631c74c91760e11b610797565b909114919050565b6000838311612aa657506000612377565b6000612ab28585612992565b90506000612ac8670de0b6b3a764000088611398565b9050612adc826709b6e64a8ec60000612ec1565b91506000612aea8383612d8a565b90506000612b01612afa8361296c565b8b90612a23565b90506128e88187612a23565b60006060612b1961108d565b600080612b2585612ed8565b91509150612b3d612b34611100565b82106064610f13565b6060612b47611100565b67ffffffffffffffff81118015612b5d57600080fd5b50604051908082528060200260200182016040528015612b87578160200160208202803683370190505b509050612bc6888381518110612b9957fe5b6020026020010151888481518110612bad57fe5b602002602001015185612bbe6104f6565b600754612efa565b818381518110612bd257fe5b6020908102919091010152919791965090945050505050565b600060606000612bfa84612fb7565b90506060612c108683612c0b6104f6565b612fcd565b9196919550909350505050565b60006060612c2961108d565b60606000612c368561307f565b91509150612c478251610610611100565b612c5382610a5e6113e9565b6000612c6b888885612c636104f6565b600754613097565b9050612c7b8282111560cf610f13565b9791965090945050505050565b60006060806000612c988561307f565b91509150612cae612ca7611100565b8351610d65565b612cba82610a5e6113e9565b6000612cd2888885612cca6104f6565b6007546132bc565b9050612c7b8282101560d0610f13565b60006060600080612cf285612ed8565b91509150612d01612b34611100565b6060612d0b611100565b67ffffffffffffffff81118015612d2157600080fd5b50604051908082528060200260200182016040528015612d4b578160200160208202803683370190505b509050612bc6888381518110612d5d57fe5b6020026020010151888481518110612d7157fe5b602002602001015185612d826104f6565b6007546134cd565b600080612d978484612db6565b90506000612daa6129f48361271061252d565b90506123778282610d72565b600081612dcc5750670de0b6b3a76400006104dc565b82612dd9575060006104dc565b612dea600160ff1b84106006610f13565b82612e10770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007610f13565b826000670c7d713b49da000083138015612e315750670f43fc2c04ee000083125b15612e68576000612e418461356f565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050612e76565b81612e7284613696565b0290505b670de0b6b3a76400009005612eae680238fd42c5cf03ffff198212801590612ea7575068070c1cc73b00c800008213155b6008610f13565b612eb781613a44565b9695505050505050565b600081831015612ed157816105a1565b5090919050565b60008082806020019051810190612eef919061431c565b909590945092505050565b600080612f1184612f0b8188610d84565b90612992565b9050612f2a6709b6e64a8ec60000821015610132610f13565b6000612f48612f41670de0b6b3a764000089611398565b8390612d8a565b90506000612f5f612f588361296c565b8a90612a23565b90506000612f6c8961296c565b90506000612f7a838361252d565b90506000612f888483610d84565b9050612fa7612fa0612f998a61296c565b8490612a23565b8290610d72565b9c9b505050505050505050505050565b6000818060200190518101906105a191906142ef565b60606000612fdb8484611398565b90506060855167ffffffffffffffff81118015612ff757600080fd5b50604051908082528060200260200182016040528015613021578160200160208202803683370190505b50905060005b8651811015613075576130568388838151811061304057fe5b6020026020010151612a2390919063ffffffff16565b82828151811061306257fe5b6020908102919091010152600101613027565b5095945050505050565b6060600082806020019051810190612eef91906142a8565b60006060845167ffffffffffffffff811180156130b357600080fd5b506040519080825280602002602001820160405280156130dd578160200160208202803683370190505b5090506000805b88518110156131a25761313d8982815181106130fc57fe5b6020026020010151612f0b89848151811061311357fe5b60200260200101518c858151811061312757fe5b6020026020010151610d8490919063ffffffff16565b83828151811061314957fe5b60200260200101818152505061319861319189838151811061316757fe5b602002602001015185848151811061317b57fe5b602002602001015161252d90919063ffffffff16565b8390610d72565b91506001016130e4565b50670de0b6b3a764000060005b895181101561329b5760008482815181106131c657fe5b602002602001015184111561321d5760006131ef6131e38661296c565b8d858151811061304057fe5b90506000613203828c868151811061312757fe5b9050613214613191611c138b61296c565b92505050613234565b88828151811061322957fe5b602002602001015190505b600061325d8c848151811061324557fe5b60200260200101516106b5848f878151811061312757fe5b905061328f6132888c858151811061327157fe5b6020026020010151836129d490919063ffffffff16565b8590612a23565b935050506001016131af565b506132af6132a88261296c565b879061252d565b9998505050505050505050565b60006060845167ffffffffffffffff811180156132d857600080fd5b50604051908082528060200260200182016040528015613302578160200160208202803683370190505b5090506000805b88518110156133aa5761336289828151811061332157fe5b60200260200101516106b589848151811061333857fe5b60200260200101518c858151811061334c57fe5b6020026020010151610d7290919063ffffffff16565b83828151811061336e57fe5b6020026020010181815250506133a061319189838151811061338c57fe5b602002602001015185848151811061304057fe5b9150600101613309565b50670de0b6b3a764000060005b895181101561348b576000838583815181106133cf57fe5b6020026020010151111561342b5760006133f46131e386670de0b6b3a7640000610d84565b90506000613408828c868151811061312757fe5b9050613422613191611f42670de0b6b3a76400008c610d84565b92505050613442565b88828151811061343757fe5b602002602001015190505b600061346b8c848151811061345357fe5b60200260200101516106b5848f878151811061334c57fe5b905061347f6132888c858151811061327157fe5b935050506001016133b7565b50670de0b6b3a764000081106134c1576134b76134b082670de0b6b3a7640000610d84565b8790612a23565b9350505050612377565b60009350505050612377565b6000806134de84612f0b8188610d72565b90506134f76729a2241af62c0000821115610133610f13565b600061350e612f41670de0b6b3a764000089612992565b9050600061352e61352783670de0b6b3a7640000610d84565b8a9061252d565b9050600061353b8961296c565b90506000613549838361252d565b905060006135578483610d84565b9050612fa7612fa06135688a61296c565b8490612992565b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401906ec097ce7bc90715b34b9f0fffffffff19850102816135ab57fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f826002919005919091010295945050505050565b60006136a6600083136064610f13565b670de0b6b3a76400008212156136e1576136d7826ec097ce7bc90715b34b9f1000000000816136d157fe5b05613696565b60000390506106d5565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261373257770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261376a576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126137b2576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126137ed576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261382457693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e2831261385b57690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126138905768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb4174612111083126138bb57680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d83126138f0576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312613925576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b2866038312613959576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac831261398d576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d6310000080860302816139b057fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000613a73680238fd42c5cf03ffff198312158015613a6c575068070c1cc73b00c800008313155b6009610f13565b6000821215613aa757613a8882600003613a44565b6ec097ce7bc90715b34b9f100000000081613a9f57fe5b0590506106d5565b60006806f05b59d3b20000008312613ae757506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000613b1d565b6803782dace9d90000008312613b1957506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380613b1d565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412613b6d5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412613ba9576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412613be357682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412613c1d576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412613c5657680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412613c8f5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613cc8576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412613d015768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b80356104dc81614708565b600082601f830112613e3d578081fd5b8151613e50613e4b826146e8565b6146c1565b818152915060208083019084810181840286018201871015613e7157600080fd5b60005b84811015613e9057815184529282019290820190600101613e74565b505050505092915050565b600082601f830112613eab578081fd5b813567ffffffffffffffff811115613ec1578182fd5b613ed4601f8201601f19166020016146c1565b9150808252836020828501011115613eeb57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106104dc57600080fd5b600060208284031215613f24578081fd5b81356105a181614708565b60008060408385031215613f41578081fd5b8235613f4c81614708565b91506020830135613f5c81614708565b809150509250929050565b600080600060608486031215613f7b578081fd5b8335613f8681614708565b92506020840135613f9681614708565b929592945050506040919091013590565b600080600080600080600060e0888a031215613fc1578283fd5b8735613fcc81614708565b96506020880135613fdc81614708565b95506040880135945060608801359350608088013560ff81168114613fff578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561402e578182fd5b823561403981614708565b946020939093013593505050565b60008060006060848603121561405b578081fd5b835167ffffffffffffffff80821115614072578283fd5b818601915086601f830112614085578283fd5b8151614093613e4b826146e8565b80828252602080830192508086018b8283870289010111156140b3578788fd5b8796505b848710156140de5780516140ca81614708565b8452600196909601959281019281016140b7565b5089015190975093505050808211156140f5578283fd5b5061410286828701613e2d565b925050604084015190509250925092565b600060208284031215614124578081fd5b81356105a18161471d565b600060208284031215614140578081fd5b81516105a18161471d565b600080600080600080600060e0888a031215614165578081fd5b8735965060208089013561417881614708565b9650604089013561418881614708565b9550606089013567ffffffffffffffff808211156141a4578384fd5b818b0191508b601f8301126141b7578384fd5b81356141c5613e4b826146e8565b8082825285820191508585018f8788860288010111156141e3578788fd5b8795505b838610156142055780358352600195909501949186019186016141e7565b509850505060808b0135955060a08b0135945060c08b013592508083111561422b578384fd5b50506142398a828b01613e9b565b91505092959891949750929550565b600060208284031215614259578081fd5b81356001600160e01b0319811681146105a1578182fd5b600060208284031215614281578081fd5b81516105a181614708565b60006020828403121561429d578081fd5b81516105a18161472b565b6000806000606084860312156142bc578081fd5b83516142c78161472b565b602085015190935067ffffffffffffffff8111156142e3578182fd5b61410286828701613e2d565b60008060408385031215614301578182fd5b825161430c8161472b565b6020939093015192949293505050565b600080600060608486031215614330578081fd5b835161433b8161472b565b602085015160409095015190969495509392505050565b60008060408385031215614364578182fd5b825161436f8161472b565b602084015190925067ffffffffffffffff81111561438b578182fd5b61439785828601613e2d565b9150509250929050565b6000806000606084860312156143b5578081fd5b833567ffffffffffffffff808211156143cc578283fd5b81860191506101208083890312156143e2578384fd5b6143eb816146c1565b90506143f78884613f04565b81526144068860208501613e22565b60208201526144188860408501613e22565b6040820152606083013560608201526080830135608082015260a083013560a08201526144488860c08501613e22565b60c082015261445a8860e08501613e22565b60e08201526101008084013583811115614472578586fd5b61447e8a828701613e9b565b9183019190915250976020870135975060409096013595945050505050565b6000602082840312156144ae578081fd5b5035919050565b6000815180845260208085019450808401835b838110156144e4578151875295820195908201906001016144c8565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6000602082526105a160208301846144b5565b60006040825261456c60408301856144b5565b828103602084015261237781856144b5565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b6000602080835283518082850152825b8181101561467357858101830151858201604001528201614657565b818111156146845783604083870101525b50601f01601f1916929092016040019392505050565b600083825260406020830152611bb060408301846144b5565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156146e057600080fd5b604052919050565b600067ffffffffffffffff8211156146fe578081fd5b5060209081020190565b6001600160a01b03811681146104f357600080fd5b80151581146104f357600080fd5b600381106104f357600080fdfea2646970667358221220a2c3b62e0bc50507598395387e1557612d7ad59e817ddae4d5279907402fedb464736f6c63430007010033a26469706673582212201bcb3a953b00c5c4dcf4d3cf74f047f69d25320298f41e6f635cb029516f583764736f6c63430007010033", + "_disabled": [ { "inputs": [], "name": "getPauseConfiguration", @@ -118,6 +121,5 @@ "stateMutability": "view", "type": "function" } - ], - "bytecode": "0x60c060405234801561001057600080fd5b5060405161604138038061604183398101604081905261002f9161004d565b60601b6001600160601b0319166080526276a700420160a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160601c60a051615f9c6100a56000398060d6528061010052508061015c5250615f9c6000f3fe60806040523480156200001157600080fd5b5060043610620000525760003560e01c80632da47c4014620000575780636634b753146200007a5780638d928af814620000a0578063fbce039314620000b9575b600080fd5b62000061620000d0565b6040516200007192919062000634565b60405180910390f35b620000916200008b366004620003c0565b6200013c565b60405162000071919062000562565b620000aa6200015a565b6040516200007191906200054e565b620000aa620000ca366004620003e6565b6200017e565b600080427f00000000000000000000000000000000000000000000000000000000000000008110156200012e57807f000000000000000000000000000000000000000000000000000000000000000003925062278d00915062000137565b60009250600091505b509091565b6001600160a01b031660009081526020819052604090205460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000090565b60008060006200018d620000d0565b9150915060006200019d6200015a565b8a8a8a8a8a88888c604051620001b3906200024b565b620001c7999897969594939291906200056d565b604051809103906000f080158015620001e4573d6000803e3d6000fd5b509050620001f281620001ff565b9998505050505050505050565b6001600160a01b038116600081815260208190526040808220805460ff19166001179055517f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9190a250565b6158b680620006b183390190565b8035620002668162000697565b92915050565b600082601f8301126200027d578081fd5b8135620002946200028e826200066a565b62000642565b818152915060208083019084810181840286018201871015620002b657600080fd5b60005b84811015620002e2578135620002cf8162000697565b84529282019290820190600101620002b9565b505050505092915050565b600082601f830112620002fe578081fd5b81356200030f6200028e826200066a565b8181529150602080830190848101818402860182018710156200033157600080fd5b60005b84811015620002e25781358452928201929082019060010162000334565b600082601f83011262000363578081fd5b813567ffffffffffffffff8111156200037a578182fd5b6200038f601f8201601f191660200162000642565b9150808252836020828501011115620003a757600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215620003d2578081fd5b8135620003df8162000697565b9392505050565b60008060008060008060c08789031215620003ff578182fd5b863567ffffffffffffffff8082111562000417578384fd5b620004258a838b0162000352565b975060208901359150808211156200043b578384fd5b620004498a838b0162000352565b965060408901359150808211156200045f578384fd5b6200046d8a838b016200026c565b9550606089013591508082111562000483578384fd5b506200049289828a01620002ed565b93505060808701359150620004ab8860a0890162000259565b90509295509295509295565b6001600160a01b03169052565b6000815180845260208085019450808401835b83811015620004f557815187529582019590820190600101620004d7565b509495945050505050565b60008151808452815b81811015620005275760208185018101518683018201520162000509565b81811115620005395782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b901515815260200190565b60006101206001600160a01b038c16835260208181850152620005938285018d62000500565b91508382036040850152620005a9828c62000500565b84810360608601528a51808252828c01935090820190845b81811015620005e957620005d685516200068b565b83529383019391830191600101620005c1565b50508481036080860152620005ff818b620004c4565b93505050508560a08301528460c08301528360e083015262000626610100830184620004b7565b9a9950505050505050505050565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156200066257600080fd5b604052919050565b600067ffffffffffffffff82111562000681578081fd5b5060209081020190565b6001600160a01b031690565b6001600160a01b0381168114620006ad57600080fd5b5056fe6105006040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9610120523480156200003757600080fd5b50604051620058b6380380620058b68339810160408190526200005a9162000cf2565b88888888878787878785516002146200007557600162000078565b60025b6040805180820190915260018152603160f81b6020808301918252336080526001600160601b0319606087901b1660a0528b51908c0190812060c0529151902060e0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6101005289518a918a918a918a918a918a918a91849184918a918a9162000107916003919062000abb565b5080516200011d90600490602084019062000abb565b50620001359150506276a70083111561019462000865565b6200014962278d0082111561019562000865565b42909101610140819052016101605284516200016b906002111560c862000865565b6200018360088651111560c96200086560201b60201c565b62000199856200087a60201b62000d571760201c565b620001a48462000886565b6040516309b2760f60e01b81526000906001600160a01b038b16906309b2760f90620001d5908c9060040162000eab565b602060405180830381600087803b158015620001f057600080fd5b505af115801562000205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022b919062000cd9565b9050896001600160a01b03166366a9c7d2828889516001600160401b03811180156200025657600080fd5b5060405190808252806020026020018201604052801562000281578160200160208202803683370190505b506040518463ffffffff1660e01b8152600401620002a29392919062000e0f565b600060405180830381600087803b158015620002bd57600080fd5b505af1158015620002d2573d6000803e3d6000fd5b5050506001600160601b031960608c901b1661018052506101a081905285516101c0528551620003045760006200031b565b856000815181106200031257fe5b60200260200101515b60601b6001600160601b0319166101e05285516001106200033e57600062000355565b856001815181106200034c57fe5b60200260200101515b60601b6001600160601b031916610200528551600210620003785760006200038f565b856002815181106200038657fe5b60200260200101515b60601b6001600160601b031916610220528551600310620003b2576000620003c9565b85600381518110620003c057fe5b60200260200101515b60601b6001600160601b031916610240528551600410620003ec57600062000403565b85600481518110620003fa57fe5b60200260200101515b60601b6001600160601b031916610260528551600510620004265760006200043d565b856005815181106200043457fe5b60200260200101515b60601b6001600160601b0319166102805285516006106200046057600062000477565b856006815181106200046e57fe5b60200260200101515b60601b6001600160601b0319166102a05285516007106200049a576000620004b1565b85600781518110620004a857fe5b60200260200101515b60601b6001600160601b0319166102c0528551620004d1576000620004f7565b620004f786600081518110620004e357fe5b6020026020010151620008f560201b60201c565b6102e05285516001106200050d5760006200051f565b6200051f86600181518110620004e357fe5b6103005285516002106200053557600062000547565b6200054786600281518110620004e357fe5b6103205285516003106200055d5760006200056f565b6200056f86600381518110620004e357fe5b6103405285516004106200058557600062000597565b6200059786600481518110620004e357fe5b610360528551600510620005ad576000620005bf565b620005bf86600581518110620004e357fe5b610380528551600610620005d5576000620005e7565b620005e786600681518110620004e357fe5b6103a0528551600710620005fd5760006200060f565b6200060f86600781518110620004e357fe5b6103c08181525050505050505050505050505050505050505050600086519050620006478187516200099760201b62000d651760201c565b6000806000805b848160ff161015620006cd5760008a8260ff16815181106200066c57fe5b6020026020010151905062000694662386f26fc1000082101561012e6200086560201b60201c565b620006ae8186620009a660201b62000d721790919060201c565b945082811115620006c3578160ff1693508092505b506001016200064e565b50620006e6670de0b6b3a7640000841461013462000865565b6103e08290528851620006fb57600062000712565b886000815181106200070957fe5b60200260200101515b610400528851600110620007285760006200073f565b886001815181106200073657fe5b60200260200101515b610420528851600210620007555760006200076c565b886002815181106200076357fe5b60200260200101515b6104405288516003106200078257600062000799565b886003815181106200079057fe5b60200260200101515b610460528851600410620007af576000620007c6565b88600481518110620007bd57fe5b60200260200101515b610480528851600510620007dc576000620007f3565b88600581518110620007ea57fe5b60200260200101515b6104a05288516006106200080957600062000820565b886006815181106200081757fe5b60200260200101515b6104c0528851600710620008365760006200084d565b886007815181106200084457fe5b60200260200101515b6104e0525062000f329b505050505050505050505050565b8162000876576200087681620009c3565b5050565b80620008768162000a16565b6200089b64e8d4a5100082101560cb62000865565b620008b367016345785d8a000082111560ca62000865565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90620008ea90839062000ec0565b60405180910390a150565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200093257600080fd5b505afa15801562000947573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200096d919062000dec565b60ff16905060006200098c60128362000aa360201b62000d841760201c565b600a0a949350505050565b62000876828214606762000865565b6000828201620009ba848210158362000865565b90505b92915050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60028151101562000a275762000aa0565b60008160008151811062000a3757fe5b602002602001015190506000600190505b825181101562000a9d57600083828151811062000a6157fe5b6020026020010151905062000a92816001600160a01b0316846001600160a01b03161060656200086560201b60201c565b915060010162000a48565b50505b50565b600062000ab583831115600162000865565b50900390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1062000afe57805160ff191683800117855562000b2e565b8280016001018555821562000b2e579182015b8281111562000b2e57825182559160200191906001019062000b11565b5062000b3c92915062000b40565b5090565b5b8082111562000b3c576000815560010162000b41565b8051620009bd8162000f1c565b600082601f83011262000b75578081fd5b815162000b8c62000b868262000ef0565b62000ec9565b81815291506020808301908481018184028601820187101562000bae57600080fd5b60005b8481101562000bda57815162000bc78162000f1c565b8452928201929082019060010162000bb1565b505050505092915050565b600082601f83011262000bf6578081fd5b815162000c0762000b868262000ef0565b81815291506020808301908481018184028601820187101562000c2957600080fd5b60005b8481101562000bda5781518452928201929082019060010162000c2c565b600082601f83011262000c5b578081fd5b81516001600160401b0381111562000c71578182fd5b602062000c87601f8301601f1916820162000ec9565b9250818352848183860101111562000c9e57600080fd5b60005b8281101562000cbe57848101820151848201830152810162000ca1565b8281111562000cd05760008284860101525b50505092915050565b60006020828403121562000ceb578081fd5b5051919050565b60008060008060008060008060006101208a8c03121562000d11578485fd5b62000d1d8b8b62000b57565b60208b01519099506001600160401b038082111562000d3a578687fd5b62000d488d838e0162000c4a565b995060408c015191508082111562000d5e578687fd5b62000d6c8d838e0162000c4a565b985060608c015191508082111562000d82578687fd5b62000d908d838e0162000b64565b975060808c015191508082111562000da6578687fd5b5062000db58c828d0162000be5565b95505060a08a0151935060c08a0151925060e08a0151915062000ddd8b6101008c0162000b57565b90509295985092959850929598565b60006020828403121562000dfe578081fd5b815160ff81168114620009ba578182fd5b60006060820185835260206060818501528186518084526080860191508288019350845b8181101562000e5b5762000e48855162000f10565b8352938301939183019160010162000e33565b505084810360408601528551808252908201925081860190845b8181101562000e9d5762000e8a835162000f10565b8552938301939183019160010162000e75565b509298975050505050505050565b602081016003831062000eba57fe5b91905290565b90815260200190565b6040518181016001600160401b038111828210171562000ee857600080fd5b604052919050565b60006001600160401b0382111562000f06578081fd5b5060209081020190565b6001600160a01b031690565b6001600160a01b038116811462000aa057600080fd5b60805160a05160601c60c05160e051610100516101205161014051610160516101805160601c6101a0516101c0516101e05160601c6102005160601c6102205160601c6102405160601c6102605160601c6102805160601c6102a05160601c6102c05160601c6102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a0516104c0516104e05161476e6200114860003980611ec55280612857525080611e8252806127f6525080611e3f5280612795525080611dfc5280612734525080611db952806126d3525080611d765280612672525080611d335280612611525080611cf052806125b05250806122d0528061230452806123405250806116285280611b1e5250806115e55280611abd5250806115a25280611a5c52508061155f52806119fb52508061151c528061199a5250806114d9528061193952508061149652806118d85250806114455280611877525080611ae3528061281c525080611a8252806127bb525080611a21528061275a5250806119c052806126f952508061195f52806126985250806118fe528061263752508061189d52806125d652508061183c52806125755250806111025250806105d7525080610835525080610ef1525080610ecd525080610ab5525080610ff452508061103652508061101552508061081152508061079b525061476e6000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c80637ecebe001161010f578063a9059cbb116100a2578063d5c096c411610071578063d5c096c4146103e6578063d73dd623146103f9578063dd62ed3e1461040c578063f89f27ed1461041f576101f0565b8063a9059cbb146103b0578063aaabadc5146103c3578063c0ff1a15146103cb578063d505accf146103d3576101f0565b80638d928af8116100de5780638d928af81461038557806395d89b411461038d5780639b02cdde146103955780639d2c110c1461039d576101f0565b80637ecebe0014610337578063851c1bb31461034a57806387ec68171461035d578063893d20e814610370576101f0565b806338e9922e11610187578063661884631161015657806366188463146102e8578063679aefce146102fb57806370a082311461030357806374f3b00914610316576101f0565b806338e9922e146102a457806338fff2d0146102b757806355c67628146102bf5780636028bfd4146102c7576101f0565b80631c0de051116101c35780631c0de0511461025d57806323b872dd14610274578063313ce567146102875780633644e5151461029c576101f0565b806306fdde03146101f5578063095ea7b31461021357806316c38b3c1461023357806318160ddd14610248575b600080fd5b6101fd610434565b60405161020a9190614647565b60405180910390f35b61022661022136600461401c565b6104cb565b60405161020a919061457e565b610246610241366004614113565b6104e2565b005b6102506104f6565b60405161020a91906145a1565b6102656104fc565b60405161020a93929190614589565b610226610282366004613f67565b610525565b61028f6105a8565b60405161020a91906146b3565b6102506105ad565b6102466102b236600461449d565b6105bc565b6102506105d5565b6102506105f9565b6102da6102d536600461414b565b6105ff565b60405161020a92919061469a565b6102266102f636600461401c565b610636565b610250610690565b610250610311366004613f13565b6106bb565b61032961032436600461414b565b6106da565b60405161020a929190614559565b610250610345366004613f13565b61077c565b610250610358366004614248565b610797565b6102da61036b36600461414b565b6107e9565b61037861080f565b60405161020a9190614532565b610378610833565b6101fd610857565b6102506108b8565b6102506103ab3660046143a1565b6108be565b6102266103be36600461401c565b6109a5565b6103786109b2565b6102506109bc565b6102466103e1366004613fa7565b610a80565b6103296103f436600461414b565b610bc9565b61022661040736600461401c565b610cec565b61025061041a366004613f2f565b610d22565b610427610d4d565b60405161020a9190614546565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b820191906000526020600020905b8154815290600101906020018083116104a357829003601f168201915b505050505090505b90565b60006104d8338484610d9a565b5060015b92915050565b6104ea610e02565b6104f381610e30565b50565b60025490565b6000806000610509610eae565b159250610514610ecb565b915061051e610eef565b9050909192565b6001600160a01b0383166000818152600160209081526040808320338085529252822054919261056391148061055b5750838210155b610197610f13565b61056e858585610f21565b336001600160a01b0386161480159061058957506000198114155b1561059b5761059b8533858403610d9a565b60019150505b9392505050565b601290565b60006105b7610ff0565b905090565b6105c4610e02565b6105cc61108d565b6104f3816110a2565b7f000000000000000000000000000000000000000000000000000000000000000090565b60075490565b600060606106158651610610611100565b610d65565b61062a898989898989896111246111ec611252565b97509795505050505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106106725761066d33856000610d9a565b610686565b61068633856106818487610d84565b610d9a565b5060019392505050565b60006105b761069d6104f6565b6106b56106a86109bc565b6106b0611100565b611374565b90611398565b6001600160a01b0381166000908152602081905260409020545b919050565b606080886107046106e9610833565b6001600160a01b0316336001600160a01b03161460cd610f13565b61071961070f6105d5565b82146101f4610f13565b60606107236113e9565b905061072f8882611666565b60006060806107438e8e8e8e8e8e8e611124565b9250925092506107538d846116c7565b61075d82856111ec565b61076781856111ec565b909550935050505b5097509795505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016107cc9291906144ef565b604051602081830303815290604052805190602001209050919050565b600060606107fa8651610610611100565b61062a8989898989898961175a6117d7611252565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b60085490565b6000806108ce8560200151611838565b905060006108df8660400151611838565b90506000865160018111156108f057fe5b1415610956576109038660600151611b4d565b60608701526109128583611b71565b945061091e8482611b71565b935061092e866060015183611b71565b60608701526000610940878787611b7d565b905061094c8183611bb8565b93505050506105a1565b6109608583611b71565b945061096c8482611b71565b935061097c866060015182611b71565b6060870152600061098e878787611bc4565b905061099a8184611bf7565b905061094c81611c03565b60006104d8338484610f21565b60006105b7611c1a565b600060606109c8610833565b6001600160a01b031663f94d46686109de6105d5565b6040518263ffffffff1660e01b81526004016109fa91906145a1565b60006040518083038186803b158015610a1257600080fd5b505afa158015610a26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a4e9190810190614047565b50915050610a6381610a5e6113e9565b611666565b6060610a6d611c94565b9050610a798183611ef1565b9250505090565b610a8e8442111560d1610f13565b6001600160a01b0387166000908152600560209081526040808320549051909291610ae5917f0000000000000000000000000000000000000000000000000000000000000000918c918c918c9188918d91016145c9565b6040516020818303038152906040528051906020012090506000610b0882611f63565b9050600060018288888860405160008152602001604052604051610b2f9493929190614629565b6020604051602081039080840390855afa158015610b51573d6000803e3d6000fd5b5050604051601f1901519150610b9390506001600160a01b03821615801590610b8b57508b6001600160a01b0316826001600160a01b0316145b6101f8610f13565b6001600160a01b038b166000908152600560205260409020600185019055610bbc8b8b8b610d9a565b5050505050505050505050565b60608088610bd86106e9610833565b610be361070f6105d5565b6060610bed6113e9565b9050610bf76104f6565b610c9d5760006060610c0b8d8d8d8a611f7f565b91509150610c20620f424083101560cc610f13565b610c2e6000620f424061201a565b610c3d8b620f4240840361201a565b610c4781846117d7565b80610c50611100565b67ffffffffffffffff81118015610c6657600080fd5b50604051908082528060200260200182016040528015610c90578160200160208202803683370190505b509550955050505061076f565b610ca78882611666565b6000606080610cbb8e8e8e8e8e8e8e61175a565b925092509250610ccb8c8461201a565b610cd582856117d7565b610cdf81856111ec565b909550935061076f915050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916104d89185906106819086610d72565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606105b7611c94565b80610d61816120b0565b5050565b610d618183146067610f13565b60008282016105a18482101583610f13565b6000610d94838311156001610f13565b50900390565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610df59085906145a1565b60405180910390a3505050565b6000610e196000356001600160e01b031916610797565b90506104f3610e288233612129565b610191610f13565b8015610e5057610e4b610e41610ecb565b4210610193610f13565b610e65565b610e65610e5b610eef565b42106101a9610f13565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490610ea390839061457e565b60405180910390a150565b6000610eb8610eef565b4211806105b757505060065460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b81610d6157610d6181612219565b6001600160a01b038316600090815260208190526040902054610f4982821015610196610f13565b610f606001600160a01b0384161515610199610f13565b6001600160a01b03808516600090815260208190526040808220858503905591851681522054610f909083610d72565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610fe29086906145a1565b60405180910390a350505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061105d61226c565b306040516020016110729594939291906145fd565b60405160208183030381529060405280519060200120905090565b6110a0611098610eae565b610192610f13565b565b6110b564e8d4a5100082101560cb610f13565b6110cb67016345785d8a000082111560ca610f13565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90610ea39083906145a1565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006060806060611133611c94565b905061113d610eae565b1561117457600061114e828a611ef1565b905061115f8983600854848b612270565b925061116e8984610d84612380565b506111c0565b61117c611100565b67ffffffffffffffff8111801561119257600080fd5b506040519080825280602002602001820160405280156111bc578160200160208202803683370190505b5091505b6111cb8882876123eb565b90945092506111db888483612458565b600855509750975097945050505050565b60005b6111f7611100565b81101561124d5761122e83828151811061120d57fe5b602002602001015183838151811061122157fe5b6020026020010151612471565b83828151811061123a57fe5b60209081029190910101526001016111ef565b505050565b333014611310576000306001600160a01b0316600036604051611276929190614507565b6000604051808303816000865af19150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5050905080600081146112c757fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146112f2573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b606061131a6113e9565b90506113268782611666565b6000606061133d8c8c8c8c8c8c8c8c63ffffffff16565b509150915061135081848663ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b60008282026105a184158061139157508385838161138e57fe5b04145b6003610f13565b60006113a78215156004610f13565b826113b4575060006104dc565b670de0b6b3a7640000838102906113d7908583816113ce57fe5b04146005610f13565b8281816113e057fe5b049150506104dc565b606060006113f5611100565b905060608167ffffffffffffffff8111801561141057600080fd5b5060405190808252806020026020018201604052801561143a578160200160208202803683370190505b5090508115611482577f00000000000000000000000000000000000000000000000000000000000000008160008151811061147157fe5b60200260200101818152505061148b565b91506104c89050565b6001821115611482577f0000000000000000000000000000000000000000000000000000000000000000816001815181106114c257fe5b6020026020010181815250506002821115611482577f00000000000000000000000000000000000000000000000000000000000000008160028151811061150557fe5b6020026020010181815250506003821115611482577f00000000000000000000000000000000000000000000000000000000000000008160038151811061154857fe5b6020026020010181815250506004821115611482577f00000000000000000000000000000000000000000000000000000000000000008160048151811061158b57fe5b6020026020010181815250506005821115611482577f0000000000000000000000000000000000000000000000000000000000000000816005815181106115ce57fe5b6020026020010181815250506006821115611482577f00000000000000000000000000000000000000000000000000000000000000008160068151811061161157fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b60200260200101818152505091505090565b60005b611671611100565b81101561124d576116a883828151811061168757fe5b602002602001015183838151811061169b57fe5b6020026020010151611374565b8382815181106116b457fe5b6020908102919091010152600101611669565b6001600160a01b0382166000908152602081905260409020546116ef82821015610196610f13565b6001600160a01b038316600090815260208190526040902082820390556002546117199083610d84565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610df59086906145a1565b600060608061176761108d565b6060611771611c94565b9050600061177f828a611ef1565b905060606117928a84600854858c612270565b90506117a18a82610d84612380565b600060606117b08c868b612491565b915091506117bf8c82876124eb565b600855909e909d50909b509950505050505050505050565b60005b6117e2611100565b81101561124d576118198382815181106117f857fe5b602002602001015183838151811061180c57fe5b60200260200101516124fa565b83828151811061182557fe5b60209081029190910101526001016117da565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561189b57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156118fc57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561195d57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156119be57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a1f57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a8057507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611ae157507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b6106d5610135612219565b600080611b656007548461252d90919063ffffffff16565b90506105a18382610d84565b60006105a18383611374565b6000611b8761108d565b611bb083611b988660200151612571565b84611ba68860400151612571565b886060015161287b565b949350505050565b60006105a18383612471565b6000611bce61108d565b611bb083611bdf8660200151612571565b84611bed8860400151612571565b88606001516128f6565b60006105a183836124fa565b60006104dc611c1360075461296c565b8390612992565b6000611c24610833565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5c57600080fd5b505afa158015611c70573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b79190614270565b60606000611ca0611100565b905060608167ffffffffffffffff81118015611cbb57600080fd5b50604051908082528060200260200182016040528015611ce5578160200160208202803683370190505b5090508115611482577f000000000000000000000000000000000000000000000000000000000000000081600081518110611d1c57fe5b6020026020010181815250506001821115611482577f000000000000000000000000000000000000000000000000000000000000000081600181518110611d5f57fe5b6020026020010181815250506002821115611482577f000000000000000000000000000000000000000000000000000000000000000081600281518110611da257fe5b6020026020010181815250506003821115611482577f000000000000000000000000000000000000000000000000000000000000000081600381518110611de557fe5b6020026020010181815250506004821115611482577f000000000000000000000000000000000000000000000000000000000000000081600481518110611e2857fe5b6020026020010181815250506005821115611482577f000000000000000000000000000000000000000000000000000000000000000081600581518110611e6b57fe5b6020026020010181815250506006821115611482577f000000000000000000000000000000000000000000000000000000000000000081600681518110611eae57fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b670de0b6b3a764000060005b8351811015611f5357611f49611f42858381518110611f1857fe5b6020026020010151858481518110611f2c57fe5b60200260200101516129d490919063ffffffff16565b8390612a23565b9150600101611efd565b506104dc60008211610137610f13565b6000611f6d610ff0565b826040516020016107cc929190614517565b60006060611f8b61108d565b6000611f9684612a4f565b9050611fb16000826002811115611fa957fe5b1460ce610f13565b6060611fbc85612a65565b9050611fd0611fc9611100565b8251610d65565b611fdc81610a5e6113e9565b6060611fe6611c94565b90506000611ff48284611ef1565b90506000612004826106b0611100565b6008929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461203d9082610d72565b6001600160a01b0383166000908152602081905260409020556002546120639082610d72565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906120a49085906145a1565b60405180910390a35050565b6002815110156120bf576104f3565b6000816000815181106120ce57fe5b602002602001015190506000600190505b825181101561124d5760008382815181106120f657fe5b6020026020010151905061211f816001600160a01b0316846001600160a01b0316106065610f13565b91506001016120df565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b61214861080f565b6001600160a01b031614158015612163575061216383612a7b565b1561218b5761217061080f565b6001600160a01b0316336001600160a01b03161490506104dc565b612193611c1a565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b81526004016121c2939291906145aa565b60206040518083038186803b1580156121da57600080fd5b505afa1580156121ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612212919061412f565b90506104dc565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b4690565b60608061227b611100565b67ffffffffffffffff8111801561229157600080fd5b506040519080825280602002602001820160405280156122bb578160200160208202803683370190505b509050826122ca579050612377565b61233d877f0000000000000000000000000000000000000000000000000000000000000000815181106122f957fe5b6020026020010151877f00000000000000000000000000000000000000000000000000000000000000008151811061232d57fe5b6020026020010151878787612a95565b817f00000000000000000000000000000000000000000000000000000000000000008151811061236957fe5b602090810291909101015290505b95945050505050565b60005b61238b611100565b8110156123e5576123c68482815181106123a157fe5b60200260200101518483815181106123b557fe5b60200260200101518463ffffffff16565b8482815181106123d257fe5b6020908102919091010152600101612383565b50505050565b6000606060006123fa84612a4f565b9050600081600281111561240a57fe5b14156124255761241b868686612b0d565b9250925050612450565b600181600281111561243357fe5b14156124435761241b8685612beb565b61241b868686612c1d565b505b935093915050565b60006124678484610d84612380565b611bb08285611ef1565b60006124808215156004610f13565b81838161248957fe5b049392505050565b6000606060006124a084612a4f565b905060018160028111156124b057fe5b14156124c15761241b868686612c88565b60028160028111156124cf57fe5b14156124e05761241b868686612ce2565b61244e610136612219565b60006124678484610d72612380565b60006125098215156004610f13565b82612516575060006104dc565b81600184038161252257fe5b0460010190506104dc565b600082820261254784158061139157508385838161138e57fe5b806125565760009150506104dc565b670de0b6b3a764000060001982015b046001019150506104dc565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156125d457507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561263557507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561269657507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156126f757507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561275857507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156127b957507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561281a57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b600061289d61289287670429d069189e0000612a23565b831115610130610f13565b60006128a98784610d72565b905060006128b78883612992565b905060006128c58887611398565b905060006128d38383612d8a565b90506128e86128e18261296c565b8990612a23565b9a9950505050505050505050565b600061291861290d85670429d069189e0000612a23565b831115610131610f13565b600061292e6129278685610d84565b8690612992565b9050600061293c8588612992565b9050600061294a8383612d8a565b9050600061296082670de0b6b3a7640000610d84565b90506128e88a8261252d565b6000670de0b6b3a764000082106129845760006104dc565b50670de0b6b3a76400000390565b60006129a18215156004610f13565b826129ae575060006104dc565b670de0b6b3a7640000838102906129c8908583816113ce57fe5b82600182038161256557fe5b6000806129e18484612db6565b905060006129fb6129f48361271061252d565b6001610d72565b905080821015612a10576000925050506104dc565b612a1a8282610d84565b925050506104dc565b6000828202612a3d84158061139157508385838161138e57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906104dc919061428c565b6060818060200190518101906105a19190614352565b6000612a8d631c74c91760e11b610797565b909114919050565b6000838311612aa657506000612377565b6000612ab28585612992565b90506000612ac8670de0b6b3a764000088611398565b9050612adc826709b6e64a8ec60000612ec1565b91506000612aea8383612d8a565b90506000612b01612afa8361296c565b8b90612a23565b90506128e88187612a23565b60006060612b1961108d565b600080612b2585612ed8565b91509150612b3d612b34611100565b82106064610f13565b6060612b47611100565b67ffffffffffffffff81118015612b5d57600080fd5b50604051908082528060200260200182016040528015612b87578160200160208202803683370190505b509050612bc6888381518110612b9957fe5b6020026020010151888481518110612bad57fe5b602002602001015185612bbe6104f6565b600754612efa565b818381518110612bd257fe5b6020908102919091010152919791965090945050505050565b600060606000612bfa84612fb7565b90506060612c108683612c0b6104f6565b612fcd565b9196919550909350505050565b60006060612c2961108d565b60606000612c368561307f565b91509150612c478251610610611100565b612c5382610a5e6113e9565b6000612c6b888885612c636104f6565b600754613097565b9050612c7b8282111560cf610f13565b9791965090945050505050565b60006060806000612c988561307f565b91509150612cae612ca7611100565b8351610d65565b612cba82610a5e6113e9565b6000612cd2888885612cca6104f6565b6007546132bc565b9050612c7b8282101560d0610f13565b60006060600080612cf285612ed8565b91509150612d01612b34611100565b6060612d0b611100565b67ffffffffffffffff81118015612d2157600080fd5b50604051908082528060200260200182016040528015612d4b578160200160208202803683370190505b509050612bc6888381518110612d5d57fe5b6020026020010151888481518110612d7157fe5b602002602001015185612d826104f6565b6007546134cd565b600080612d978484612db6565b90506000612daa6129f48361271061252d565b90506123778282610d72565b600081612dcc5750670de0b6b3a76400006104dc565b82612dd9575060006104dc565b612dea600160ff1b84106006610f13565b82612e10770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007610f13565b826000670c7d713b49da000083138015612e315750670f43fc2c04ee000083125b15612e68576000612e418461356f565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050612e76565b81612e7284613696565b0290505b670de0b6b3a76400009005612eae680238fd42c5cf03ffff198212801590612ea7575068070c1cc73b00c800008213155b6008610f13565b612eb781613a44565b9695505050505050565b600081831015612ed157816105a1565b5090919050565b60008082806020019051810190612eef919061431c565b909590945092505050565b600080612f1184612f0b8188610d84565b90612992565b9050612f2a6709b6e64a8ec60000821015610132610f13565b6000612f48612f41670de0b6b3a764000089611398565b8390612d8a565b90506000612f5f612f588361296c565b8a90612a23565b90506000612f6c8961296c565b90506000612f7a838361252d565b90506000612f888483610d84565b9050612fa7612fa0612f998a61296c565b8490612a23565b8290610d72565b9c9b505050505050505050505050565b6000818060200190518101906105a191906142ef565b60606000612fdb8484611398565b90506060855167ffffffffffffffff81118015612ff757600080fd5b50604051908082528060200260200182016040528015613021578160200160208202803683370190505b50905060005b8651811015613075576130568388838151811061304057fe5b6020026020010151612a2390919063ffffffff16565b82828151811061306257fe5b6020908102919091010152600101613027565b5095945050505050565b6060600082806020019051810190612eef91906142a8565b60006060845167ffffffffffffffff811180156130b357600080fd5b506040519080825280602002602001820160405280156130dd578160200160208202803683370190505b5090506000805b88518110156131a25761313d8982815181106130fc57fe5b6020026020010151612f0b89848151811061311357fe5b60200260200101518c858151811061312757fe5b6020026020010151610d8490919063ffffffff16565b83828151811061314957fe5b60200260200101818152505061319861319189838151811061316757fe5b602002602001015185848151811061317b57fe5b602002602001015161252d90919063ffffffff16565b8390610d72565b91506001016130e4565b50670de0b6b3a764000060005b895181101561329b5760008482815181106131c657fe5b602002602001015184111561321d5760006131ef6131e38661296c565b8d858151811061304057fe5b90506000613203828c868151811061312757fe5b9050613214613191611c138b61296c565b92505050613234565b88828151811061322957fe5b602002602001015190505b600061325d8c848151811061324557fe5b60200260200101516106b5848f878151811061312757fe5b905061328f6132888c858151811061327157fe5b6020026020010151836129d490919063ffffffff16565b8590612a23565b935050506001016131af565b506132af6132a88261296c565b879061252d565b9998505050505050505050565b60006060845167ffffffffffffffff811180156132d857600080fd5b50604051908082528060200260200182016040528015613302578160200160208202803683370190505b5090506000805b88518110156133aa5761336289828151811061332157fe5b60200260200101516106b589848151811061333857fe5b60200260200101518c858151811061334c57fe5b6020026020010151610d7290919063ffffffff16565b83828151811061336e57fe5b6020026020010181815250506133a061319189838151811061338c57fe5b602002602001015185848151811061304057fe5b9150600101613309565b50670de0b6b3a764000060005b895181101561348b576000838583815181106133cf57fe5b6020026020010151111561342b5760006133f46131e386670de0b6b3a7640000610d84565b90506000613408828c868151811061312757fe5b9050613422613191611f42670de0b6b3a76400008c610d84565b92505050613442565b88828151811061343757fe5b602002602001015190505b600061346b8c848151811061345357fe5b60200260200101516106b5848f878151811061334c57fe5b905061347f6132888c858151811061327157fe5b935050506001016133b7565b50670de0b6b3a764000081106134c1576134b76134b082670de0b6b3a7640000610d84565b8790612a23565b9350505050612377565b60009350505050612377565b6000806134de84612f0b8188610d72565b90506134f76729a2241af62c0000821115610133610f13565b600061350e612f41670de0b6b3a764000089612992565b9050600061352e61352783670de0b6b3a7640000610d84565b8a9061252d565b9050600061353b8961296c565b90506000613549838361252d565b905060006135578483610d84565b9050612fa7612fa06135688a61296c565b8490612992565b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401906ec097ce7bc90715b34b9f0fffffffff19850102816135ab57fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f826002919005919091010295945050505050565b60006136a6600083136064610f13565b670de0b6b3a76400008212156136e1576136d7826ec097ce7bc90715b34b9f1000000000816136d157fe5b05613696565b60000390506106d5565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261373257770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261376a576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126137b2576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126137ed576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261382457693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e2831261385b57690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126138905768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb4174612111083126138bb57680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d83126138f0576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312613925576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b2866038312613959576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac831261398d576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d6310000080860302816139b057fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000613a73680238fd42c5cf03ffff198312158015613a6c575068070c1cc73b00c800008313155b6009610f13565b6000821215613aa757613a8882600003613a44565b6ec097ce7bc90715b34b9f100000000081613a9f57fe5b0590506106d5565b60006806f05b59d3b20000008312613ae757506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000613b1d565b6803782dace9d90000008312613b1957506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380613b1d565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412613b6d5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412613ba9576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412613be357682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412613c1d576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412613c5657680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412613c8f5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613cc8576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412613d015768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b80356104dc81614708565b600082601f830112613e3d578081fd5b8151613e50613e4b826146e8565b6146c1565b818152915060208083019084810181840286018201871015613e7157600080fd5b60005b84811015613e9057815184529282019290820190600101613e74565b505050505092915050565b600082601f830112613eab578081fd5b813567ffffffffffffffff811115613ec1578182fd5b613ed4601f8201601f19166020016146c1565b9150808252836020828501011115613eeb57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106104dc57600080fd5b600060208284031215613f24578081fd5b81356105a181614708565b60008060408385031215613f41578081fd5b8235613f4c81614708565b91506020830135613f5c81614708565b809150509250929050565b600080600060608486031215613f7b578081fd5b8335613f8681614708565b92506020840135613f9681614708565b929592945050506040919091013590565b600080600080600080600060e0888a031215613fc1578283fd5b8735613fcc81614708565b96506020880135613fdc81614708565b95506040880135945060608801359350608088013560ff81168114613fff578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561402e578182fd5b823561403981614708565b946020939093013593505050565b60008060006060848603121561405b578081fd5b835167ffffffffffffffff80821115614072578283fd5b818601915086601f830112614085578283fd5b8151614093613e4b826146e8565b80828252602080830192508086018b8283870289010111156140b3578788fd5b8796505b848710156140de5780516140ca81614708565b8452600196909601959281019281016140b7565b5089015190975093505050808211156140f5578283fd5b5061410286828701613e2d565b925050604084015190509250925092565b600060208284031215614124578081fd5b81356105a18161471d565b600060208284031215614140578081fd5b81516105a18161471d565b600080600080600080600060e0888a031215614165578081fd5b8735965060208089013561417881614708565b9650604089013561418881614708565b9550606089013567ffffffffffffffff808211156141a4578384fd5b818b0191508b601f8301126141b7578384fd5b81356141c5613e4b826146e8565b8082825285820191508585018f8788860288010111156141e3578788fd5b8795505b838610156142055780358352600195909501949186019186016141e7565b509850505060808b0135955060a08b0135945060c08b013592508083111561422b578384fd5b50506142398a828b01613e9b565b91505092959891949750929550565b600060208284031215614259578081fd5b81356001600160e01b0319811681146105a1578182fd5b600060208284031215614281578081fd5b81516105a181614708565b60006020828403121561429d578081fd5b81516105a18161472b565b6000806000606084860312156142bc578081fd5b83516142c78161472b565b602085015190935067ffffffffffffffff8111156142e3578182fd5b61410286828701613e2d565b60008060408385031215614301578182fd5b825161430c8161472b565b6020939093015192949293505050565b600080600060608486031215614330578081fd5b835161433b8161472b565b602085015160409095015190969495509392505050565b60008060408385031215614364578182fd5b825161436f8161472b565b602084015190925067ffffffffffffffff81111561438b578182fd5b61439785828601613e2d565b9150509250929050565b6000806000606084860312156143b5578081fd5b833567ffffffffffffffff808211156143cc578283fd5b81860191506101208083890312156143e2578384fd5b6143eb816146c1565b90506143f78884613f04565b81526144068860208501613e22565b60208201526144188860408501613e22565b6040820152606083013560608201526080830135608082015260a083013560a08201526144488860c08501613e22565b60c082015261445a8860e08501613e22565b60e08201526101008084013583811115614472578586fd5b61447e8a828701613e9b565b9183019190915250976020870135975060409096013595945050505050565b6000602082840312156144ae578081fd5b5035919050565b6000815180845260208085019450808401835b838110156144e4578151875295820195908201906001016144c8565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6000602082526105a160208301846144b5565b60006040825261456c60408301856144b5565b828103602084015261237781856144b5565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b6000602080835283518082850152825b8181101561467357858101830151858201604001528201614657565b818111156146845783604083870101525b50601f01601f1916929092016040019392505050565b600083825260406020830152611bb060408301846144b5565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156146e057600080fd5b604052919050565b600067ffffffffffffffff8211156146fe578081fd5b5060209081020190565b6001600160a01b03811681146104f357600080fd5b80151581146104f357600080fd5b600381106104f357600080fdfea2646970667358221220a2c3b62e0bc50507598395387e1557612d7ad59e817ddae4d5279907402fedb464736f6c63430007010033a26469706673582212201bcb3a953b00c5c4dcf4d3cf74f047f69d25320298f41e6f635cb029516f583764736f6c63430007010033" + ] } diff --git a/crates/contracts/artifacts/BalancerV2WeightedPoolFactoryV3.json b/contracts/artifacts/BalancerV2WeightedPoolFactoryV3.json similarity index 99% rename from crates/contracts/artifacts/BalancerV2WeightedPoolFactoryV3.json rename to contracts/artifacts/BalancerV2WeightedPoolFactoryV3.json index 17bfe6a1b4..2ad632b064 100644 --- a/crates/contracts/artifacts/BalancerV2WeightedPoolFactoryV3.json +++ b/contracts/artifacts/BalancerV2WeightedPoolFactoryV3.json @@ -101,6 +101,21 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ { "inputs": [ { @@ -252,19 +267,6 @@ ], "stateMutability": "view", "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" } ] } diff --git a/contracts/artifacts/BalancerV2WeightedPoolFactoryV4.json b/contracts/artifacts/BalancerV2WeightedPoolFactoryV4.json new file mode 100644 index 0000000000..2ad632b064 --- /dev/null +++ b/contracts/artifacts/BalancerV2WeightedPoolFactoryV4.json @@ -0,0 +1,272 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "normalizedWeights", + "type": "uint256[]" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/crates/contracts/artifacts/BalancerV3BatchRouter.json b/contracts/artifacts/BalancerV3BatchRouter.json similarity index 99% rename from crates/contracts/artifacts/BalancerV3BatchRouter.json rename to contracts/artifacts/BalancerV3BatchRouter.json index 645cf4e136..1f6d35c66b 100644 --- a/crates/contracts/artifacts/BalancerV3BatchRouter.json +++ b/contracts/artifacts/BalancerV3BatchRouter.json @@ -129,146 +129,177 @@ "name": "TransientIndexOutOfBounds", "type": "error" }, + { + "stateMutability": "payable", + "type": "receive" + }, { "inputs": [], - "name": "getSender", + "name": "version", "outputs": [ { - "internalType": "address", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { "components": [ { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", + "internalType": "contract IERC20", + "name": "tokenIn", "type": "address" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" }, { "internalType": "uint256", - "name": "nonce", + "name": "exactAmountIn", "type": "uint256" }, { "internalType": "uint256", - "name": "deadline", + "name": "minAmountOut", "type": "uint256" } ], - "internalType": "struct IRouterCommon.PermitApproval[]", - "name": "permitBatch", + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", + "name": "paths", "type": "tuple[]" }, { - "internalType": "bytes[]", - "name": "permitSignatures", - "type": "bytes[]" + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "querySwapExactIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensOut", + "type": "address[]" }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, { "components": [ { "internalType": "address", - "name": "token", + "name": "pool", "type": "address" }, { - "internalType": "uint160", - "name": "amount", - "type": "uint160" - }, - { - "internalType": "uint48", - "name": "expiration", - "type": "uint48" + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" }, { - "internalType": "uint48", - "name": "nonce", - "type": "uint48" + "internalType": "bool", + "name": "isBuffer", + "type": "bool" } ], - "internalType": "struct IAllowanceTransfer.PermitDetails[]", - "name": "details", + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", "type": "tuple[]" }, { - "internalType": "address", - "name": "spender", - "type": "address" + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" }, { "internalType": "uint256", - "name": "sigDeadline", + "name": "exactAmountOut", "type": "uint256" } ], - "internalType": "struct IAllowanceTransfer.PermitBatch", - "name": "permit2Batch", - "type": "tuple" + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "name": "paths", + "type": "tuple[]" }, { - "internalType": "bytes", - "name": "permit2Signature", - "type": "bytes" + "internalType": "address", + "name": "sender", + "type": "address" }, { - "internalType": "bytes[]", - "name": "multicallData", - "type": "bytes[]" + "internalType": "bytes", + "name": "userData", + "type": "bytes" } ], - "name": "permitBatchAndCall", + "name": "querySwapExactOut", "outputs": [ { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" + "internalType": "uint256[]", + "name": "pathAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensIn", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" } ], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -318,9 +349,14 @@ "type": "tuple[]" }, { - "internalType": "address", - "name": "sender", - "type": "address" + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" }, { "internalType": "bytes", @@ -328,7 +364,7 @@ "type": "bytes" } ], - "name": "querySwapExactIn", + "name": "swapExactIn", "outputs": [ { "internalType": "uint256[]", @@ -346,7 +382,7 @@ "type": "uint256[]" } ], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -354,94 +390,120 @@ { "components": [ { - "internalType": "address", - "name": "sender", + "internalType": "contract IERC20", + "name": "tokenIn", "type": "address" }, { "components": [ { - "internalType": "contract IERC20", - "name": "tokenIn", + "internalType": "address", + "name": "pool", "type": "address" }, { - "components": [ - { - "internalType": "address", - "name": "pool", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "tokenOut", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBuffer", - "type": "bool" - } - ], - "internalType": "struct IBatchRouter.SwapPathStep[]", - "name": "steps", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "exactAmountIn", - "type": "uint256" + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" }, { - "internalType": "uint256", - "name": "minAmountOut", - "type": "uint256" + "internalType": "bool", + "name": "isBuffer", + "type": "bool" } ], - "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", - "name": "paths", + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", "type": "tuple[]" }, { "internalType": "uint256", - "name": "deadline", + "name": "maxAmountIn", "type": "uint256" }, { - "internalType": "bool", - "name": "wethIsEth", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" } ], - "internalType": "struct IBatchRouter.SwapExactInHookParams", - "name": "params", - "type": "tuple" + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" } ], - "name": "querySwapExactInHook", + "name": "swapExactOut", "outputs": [ { "internalType": "uint256[]", - "name": "pathAmountsOut", + "name": "pathAmountsIn", "type": "uint256[]" }, { "internalType": "address[]", - "name": "tokensOut", + "name": "tokensIn", "type": "address[]" }, { "internalType": "uint256[]", - "name": "amountsOut", + "name": "amountsIn", "type": "uint256[]" } ], - "stateMutability": "nonpayable", + "stateMutability": "payable", + "type": "function" + } + ], + "bytecode": "0x6101c0604090808252346105c957614bbd803803809161001f82856105e8565b83398101916080828403126105c95781516001600160a01b03939084811681036105c957602093848101519286841684036105c9578482015196871687036105c95760608201516001600160401b03928382116105c9570192601f908282860112156105c95784518481116105b557601f19958851946100a58b898786011601876105e8565b8286528a83830101116105c957815f928b8093018388015e8501015260805281519283116105b5575f54916001928381811c911680156105ab575b8982101461059757828111610554575b50879184116001146104f757839450908392915f946104ec575b50501b915f199060031b1c1916175f555b61014961012661060b565b835190610132826105cd565b600682526539b2b73232b960d11b86830152610669565b60a05261018561015761060b565b835190610163826105cd565b60118252701a5cd4995d1d5c9b915d1a131bd8dad959607a1b86830152610669565b60c05260e0526101009283526101cd815161019f816105cd565b601381527f63757272656e7453776170546f6b656e73496e0000000000000000000000000084820152610633565b9161012092835261021082516101e2816105cd565b601481527f63757272656e7453776170546f6b656e734f757400000000000000000000000083820152610633565b6101409081526102528351610224816105cd565b601981527f63757272656e7453776170546f6b656e496e416d6f756e74730000000000000084820152610633565b906101609182526102d8610298855161026a816105cd565b601a81527f63757272656e7453776170546f6b656e4f7574416d6f756e747300000000000086820152610633565b936101809485527f736574746c6564546f6b656e416d6f756e7473000000000000000000000000008651916102cc836105cd565b60138352820152610633565b936101a094855251946144a1968761071c88396080518781816102460152818161197c01528181611be001528181611e22015281816120790152818161221201528181612323015281816123b10152818161247301528181612aad01528181612c8c01528181612cd401528181612d5201528181612df901528181612f0701528181612f840152818161321901528181613348015281816133e5015281816134ab01528181613b6c01528181613c9101528181613ed0015281816140150152614271015260a0518781816102aa015281816105350152818161181f01526128be015260c0518781816117a901526136ba015260e051878181602201528181613afe01528181613de401528181613f5801526140af0152518681816109f001528181610b0401528181611f6e01528181611ff4015281816130790152613c6d015251858181612569015281816127500152818161295a01526135d8015251848181611c4301528181611e8f01528181612275015281816124d7015281816125ce0152818161272c01528181612b1201526135a8015251838181611d43015281816125950152818161277c0152818161328e01528181613509015261362b015251828181611c6c01528181611ec00152818161250101528181612621015281816127b401528181612b5101526132d001525181818161229f015281816125ff01528181612b8201528181612e5601526136090152f35b015192505f8061010a565b91938316915f805283885f20935f5b8a8883831061053d5750505010610525575b505050811b015f5561011b565b01515f1960f88460031b161c191690555f8080610518565b868601518855909601959485019487935001610506565b5f8052885f208380870160051c8201928b881061058e575b0160051c019084905b8281106105835750506100f0565b5f8155018490610575565b9250819261056c565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100e0565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b604081019081106001600160401b038211176105b557604052565b601f909101601f19168101906001600160401b038211908210176105b557604052565b60405190610618826105cd565b600c82526b2937baba32b921b7b6b6b7b760a11b6020830152565b61066690604051610643816105cd565b60118152702130ba31b42937baba32b921b7b6b6b7b760791b6020820152610669565b90565b906106d6603a60209260405193849181808401977f62616c616e6365722d6c6162732e76332e73746f726167652e000000000000008952805191829101603986015e830190601760f91b60398301528051928391018583015e015f8382015203601a8101845201826105e8565b5190205f198101908111610707576040519060208201908152602082526106fc826105cd565b9051902060ff191690565b634e487b7160e01b5f52601160045260245ffdfe60806040526004361015610072575b3615610018575f80fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361004a57005b7f0540ddf6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f3560e01c806308a465f614610e9d57806319c6989f1461084e578063286f580d146107b75780632950286e146106cc57806354fd4d501461058f5780635a3c3987146105665780635e01eb5a146105215780638a12a08c146104c65780638eb1b65e146103bf578063945ed33f14610344578063ac9650d8146103005763e3b5dff40361000e57346102fc576060806003193601126102fc5767ffffffffffffffff6004358181116102fc5761012d9036906004016112c4565b6101356111a1565b6044359283116102fc57610150610158933690600401610fcd565b9390916128b9565b905f5b835181101561017c57805f8761017360019488611691565b5101520161015b565b506101f06101fe610239946101b65f94886040519361019a8561111a565b30855260208501525f1960408501528660608501523691611381565b60808201526040519283917f8a12a08c0000000000000000000000000000000000000000000000000000000060208401526024830161143e565b03601f198101835282611152565b604051809481927fedfa3568000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39261028e915f916102cf575b50602080825183010191016115d4565b909391926102a7575b60405193849384610f2f565b0390f35b5f7f00000000000000000000000000000000000000000000000000000000000000005d610297565b6102eb91503d805f833e6102e38183611152565b81019061154d565b8461027e565b6040513d5f823e3d90fd5b5f80fd5b60206003193601126102fc5760043567ffffffffffffffff81116102fc576103386103326102a3923690600401610f9c565b9061179b565b60405191829182611020565b346102fc5761035236610eca565b61035a611945565b610362611972565b6103906102a3610371836128fb565b9193909461038a606061038383611344565b9201611358565b90612729565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d60405193849384610f2f565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576103ec9036906004016112c4565b906103f56111b7565b906064359081116102fc576101f061048b6102399461045161041c5f953690600401610fcd565b610425336128b9565b97604051946104338661111a565b33865260208601526024356040860152151560608501523691611381565b60808201526040519283917f945ed33f000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b604051809481927f48c89491000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b346102fc576102a36104ef6104da36610eca565b6104e2611945565b6104ea611972565b611a3b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009492945d60405193849384610f2f565b346102fc575f6003193601126102fc5760207f00000000000000000000000000000000000000000000000000000000000000005c6001600160a01b0360405191168152f35b346102fc576102a36104ef61057a36610eca565b610582611945565b61058a611972565b6128fb565b346102fc575f6003193601126102fc576040515f80549060018260011c91600184169182156106c2575b60209485851084146106955785879486865291825f146106575750506001146105fe575b506105ea92500383611152565b6102a3604051928284938452830190610ffb565b5f808052859250907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061063f5750506105ea9350820101856105dd565b80548389018501528794508693909201918101610628565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858201526105ea95151560051b85010192508791506105dd9050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b92607f16926105b9565b346102fc5760606003193601126102fc5767ffffffffffffffff6004358181116102fc576106fe9036906004016112c4565b906107076111a1565b6044359182116102fc5761072261072a923690600401610fcd565b9290916128b9565b905f5b845181101561075f57806fffffffffffffffffffffffffffffffff604061075660019489611691565b5101520161072d565b506101f06101fe8561077d5f94610239976040519361019a8561111a565b60808201526040519283917f5a3c3987000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576107e49036906004016112c4565b906107ed6111b7565b906064359081116102fc576101f061048b6102399461081461041c5f953690600401610fcd565b60808201526040519283917f08a465f60000000000000000000000000000000000000000000000000000000060208401526024830161143e565b60a06003193601126102fc5767ffffffffffffffff600435116102fc573660236004350112156102fc5767ffffffffffffffff60043560040135116102fc5736602460c060043560040135026004350101116102fc5760243567ffffffffffffffff81116102fc576108c4903690600401610f9c565b67ffffffffffffffff604435116102fc576060600319604435360301126102fc5760643567ffffffffffffffff81116102fc57610905903690600401610fcd565b60843567ffffffffffffffff81116102fc57610925903690600401610f9c565b949093610930611945565b806004356004013503610e75575f5b600435600401358110610bd25750505060443560040135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd6044353603018212156102fc57816044350160048101359067ffffffffffffffff82116102fc5760248260071b36039101136102fc576109e3575b6102a361033886865f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d61179b565b6001600160a01b039492947f0000000000000000000000000000000000000000000000000000000000000000163b156102fc57604051947f2a2d80d10000000000000000000000000000000000000000000000000000000086523360048701526060602487015260c486019260443501602481019367ffffffffffffffff6004830135116102fc57600482013560071b360385136102fc5760606064890152600482013590529192869260e484019291905f905b60048101358210610b5457505050602091601f19601f865f9787956001600160a01b03610ac860246044350161118d565b16608488015260448035013560a48801526003198787030160448801528186528786013787868286010152011601030181836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39361033893610b45575b8294508193506109b3565b610b4e90611106565b84610b3a565b9195945091926001600160a01b03610b6b8761118d565b168152602080870135916001600160a01b0383168093036102fc57600492600192820152610b9b604089016128a6565b65ffffffffffff8091166040830152610bb660608a016128a6565b1660608201526080809101970193019050889495939291610a97565b610be7610be082848661192a565b3691611381565b604051610bf3816110a1565b5f81526020915f838301525f60408301528281015190606060408201519101515f1a91835283830152604082015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc81850260043501360301126102fc5760405190610c60826110ea565b610c73602460c08602600435010161118d565b808352610c89604460c08702600435010161118d565b908185850152610ca2606460c08802600435010161118d565b60408581019190915260043560c08802016084810135606087015260a4810135608087015260c4013560a086015283015183519386015160ff91909116926001600160a01b0383163b156102fc575f6001600160a01b03809460e4948b98849860c460c06040519c8d9b8c9a7fd505accf000000000000000000000000000000000000000000000000000000008c521660048b01523060248b0152608482820260043501013560448b0152026004350101356064880152608487015260a486015260c4850152165af19081610e66575b50610e5c57610d7f612877565b906001600160a01b0381511690836001600160a01b0381830151166044604051809581937fdd62ed3e00000000000000000000000000000000000000000000000000000000835260048301523060248301525afa9182156102f1575f92610e2c575b506060015103610df75750506001905b0161093f565b805115610e045780519101fd5b7fa7285689000000000000000000000000000000000000000000000000000000005f5260045ffd5b9091508381813d8311610e55575b610e448183611152565b810103126102fc5751906060610de1565b503d610e3a565b5050600190610df1565b610e6f90611106565b8a610d72565b7faaad13f7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102fc57610eab36610eca565b610eb3611945565b610ebb611972565b6103906102a361037183611a3b565b600319906020828201126102fc576004359167ffffffffffffffff83116102fc578260a0920301126102fc5760040190565b9081518082526020808093019301915f5b828110610f1b575050505090565b835185529381019392810192600101610f0d565b939290610f4490606086526060860190610efc565b936020948181036020830152602080855192838152019401905f5b818110610f7f57505050610f7c9394506040818403910152610efc565b90565b82516001600160a01b031686529487019491870191600101610f5f565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc576020808501948460051b0101116102fc57565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc57602083818601950101116102fc57565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110555750505050505090565b9091929394958480611091837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51610ffb565b9801930193019194939290611045565b6060810190811067ffffffffffffffff8211176110bd57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd57604052565b60a0810190811067ffffffffffffffff8211176110bd57604052565b60e0810190811067ffffffffffffffff8211176110bd57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd5760051b60200190565b35906001600160a01b03821682036102fc57565b602435906001600160a01b03821682036102fc57565b6044359081151582036102fc57565b9190916080818403126102fc57604090815191608083019467ffffffffffffffff95848110878211176110bd57825283956112008461118d565b8552602090818501359081116102fc57840182601f820112156102fc5780359061122982611175565b9361123686519586611152565b82855283850190846060809502840101928184116102fc578501915b8383106112745750505050508401528181013590830152606090810135910152565b84838303126102fc57875190611289826110a1565b6112928461118d565b825261129f87850161118d565b87830152888401359081151582036102fc578288928b89950152815201920191611252565b81601f820112156102fc578035916020916112de84611175565b936112ec6040519586611152565b808552838086019160051b830101928084116102fc57848301915b8483106113175750505050505090565b823567ffffffffffffffff81116102fc578691611339848480948901016111c6565b815201920191611307565b356001600160a01b03811681036102fc5790565b3580151581036102fc5790565b67ffffffffffffffff81116110bd57601f01601f191660200190565b92919261138d82611365565b9161139b6040519384611152565b8294818452818301116102fc578281602093845f960137010152565b9060808101916001600160a01b03808251168352602093848301519460808186015285518092528060a086019601925f905b83821061140b5750505050506060816040829301516040850152015191015290565b845180518216895280840151821689850152604090810151151590890152606090970196938201936001909101906113e9565b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106114bd5750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b909192939583806114f8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611481565b81601f820112156102fc5780519061151e82611365565b9261152c6040519485611152565b828452602083830101116102fc57815f9260208093018386015e8301015290565b906020828203126102fc57815167ffffffffffffffff81116102fc57610f7c9201611507565b9080601f830112156102fc5781519060209161158e81611175565b9361159c6040519586611152565b81855260208086019260051b8201019283116102fc57602001905b8282106115c5575050505090565b815181529083019083016115b7565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc5784611600918301611573565b936020808301518581116102fc5783019082601f830112156102fc5781519161162883611175565b926116366040519485611152565b808452828085019160051b830101918583116102fc578301905b82821061167257505050509360408301519081116102fc57610f7c9201611573565b81516001600160a01b03811681036102fc578152908301908301611650565b80518210156116a55760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106117515750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b9091929395838061178c837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611715565b91906117a6336128b9565b907f000000000000000000000000000000000000000000000000000000000000000093845c6118b1576001906001865d6117df83611175565b926117ed6040519485611152565b808452601f196117fc82611175565b015f5b8181106118a05750505f5b8181106118575750505050905f61184c92945d7f0000000000000000000000000000000000000000000000000000000000000000805c9161184e575b506136b1565b565b5f905d5f611846565b806118845f8061186c610be08996888a61192a565b602081519101305af461187d612877565b903061415c565b61188e8288611691565b526118998187611691565b500161180a565b8060606020809389010152016117ff565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc576020019181360383136102fc57565b908210156116a5576119419160051b8101906118d9565b9091565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c6118b1576001905d565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633036119a457565b7f089676d5000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906119da82611175565b6119e76040519182611152565b828152601f196119f78294611175565b0190602036910137565b91908201809211611a0e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b604081013542116126c35790611a5e611a5760208401846136f4565b90506119d0565b915f5b611a6e60208301836136f4565b90508110156125c757611a9881611a93611a8b60208601866136f4565b369391613748565b6111c6565b936040850151936001600160a01b038651169060208701518051156116a55760200151604001511515806125be575b1561256357611aec611ad886611344565b8784611ae660608a01611358565b92613add565b5f5b60208801515181101561255357611b03613788565b6020890151515f198101908111611a0e578214806020830152821582525f1461254c576060890151905b611b3b8360208c0151611691565b51604081015190919015611cee57611bd36001600160a01b03835116936001600160a01b03881685145f14611ce7576001945b60405195611b7b8761111a565b5f8752611b87816137be565b6020870152604086015260609485918d838301526080820152604051809381927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611cb0575b50506020015115611c9657816001600160a01b036020611c909360019695611c388c8c611691565b5201611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b5051167f000000000000000000000000000000000000000000000000000000000000000061420a565b01611aee565b602001519097506001600160a01b03169250600190611c90565b60209294509081611cd592903d10611ce0575b611ccd8183611152565b8101906137f5565b91505092905f611c10565b503d611cc3565b5f94611b6e565b888a6001600160a01b038495945116806001600160a01b038a16145f14612132575050815115905061206e57888a80151580612053575b611f4d575b6001600160a01b03939291611ddd82611e15978b5f95897f0000000000000000000000000000000000000000000000000000000000000000921680885282602052604088205c611f3c575b5050505b6001611d9c8983511660208401998b8b51169080158a14611f3657508391614223565b999092511694611db1608091828101906118d9565b93909460405197611dc1896110ea565b8852306020890152604088015260608701528501523691611381565b60a0820152604051809681927f21457897000000000000000000000000000000000000000000000000000000008352600483016139b1565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611f0c575b506020015115611ee95791611ebc826001600160a01b0360019695611e7a611ee49686611691565b51611e858d8d611691565b52611eb3828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b50511692611691565b51907f000000000000000000000000000000000000000000000000000000000000000061420a565b611c90565b98506001929450611f02906001600160a01b0392611691565b5197511692611c90565b6020919450611f2c903d805f833e611f248183611152565b810190613969565b5094919050611e52565b91614223565b611f4592614341565b5f8281611d75565b50611f5a90929192611344565b91611f648b6142fd565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039485166004820152306024820152908416604482015292871660648401525f8380608481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f1578a611ddd8d611e15976001600160a01b03975f95612044575b50975092505091929350611d2a565b61204d90611106565b5f612035565b5061205d82611344565b6001600160a01b0316301415611d25565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916001600160a01b0384511692803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03949094166004850152306024850152604484018c90525f908490606490829084905af180156102f1578a611ddd8d611e15976001600160a01b03975f95612123575b50611d79565b61212c90611106565b5f61211d565b6001600160a01b0360208796949701511690898183145f146123d7576121cd925061220597915060016121735f96956001600160a01b0393848b5116614223565b509282895116956020890151151588146123ae5761219082611344565b945b6121a1608093848101906118d9565b959096604051996121b18b6110ea565b8a52166020890152604088015260608701528501523691611381565b60a0820152604051809581927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f1575f93612384575b5060200151156122c357816001600160a01b036020611ee493600196956122698c8c611691565b526122998383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b60208181015191516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101859052939a50909116945081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612359575b50600190611c90565b602090813d831161237d575b61236f8183611152565b810103126102fc575f612350565b503d612365565b60209193506123a4903d805f833e61239c8183611152565b81019061387c565b5093919050612242565b837f00000000000000000000000000000000000000000000000000000000000000001694612192565b6001600160a01b036124669561242e9394956123f860809b8c8101906118d9565b9390946040519761240889611136565b5f8952602089015216604087015260609a8b978888015286015260a08501523691611381565b60c0820152604051809381927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612525575b50506020015115611c9657816001600160a01b036020611ee493600196956124cb8c8c611691565b526124fb8383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b6020929450908161254192903d10611ce057611ccd8183611152565b91505092905f6124a3565b5f90611b2d565b5091955090935050600101611a61565b61258d827f00000000000000000000000000000000000000000000000000000000000000006141c0565b506125b986837f000000000000000000000000000000000000000000000000000000000000000061420a565b611aec565b50321515611ac7565b50506125f27f0000000000000000000000000000000000000000000000000000000000000000613a71565b916125fd83516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b0380612663838b611691565b51165f528560205261269160405f205c8261267e858d611691565b51165f528860205260405f205c90611a01565b61269b8387611691565b526126a6828a611691565b51165f52856020525f604081205d01612644565b50949391509150565b7fe08b8af0000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f198201918213600116611a0e57565b7f80000000000000000000000000000000000000000000000000000000000000008114611a0e575f190190565b907f000000000000000000000000000000000000000000000000000000000000000090815c7f0000000000000000000000000000000000000000000000000000000000000000612779815c6126eb565b907f0000000000000000000000000000000000000000000000000000000000000000915b5f81121561283a575050506127b1906126eb565b917f0000000000000000000000000000000000000000000000000000000000000000925b5f8112156127ea575050505061184c906136b1565b61283590825f5261282f60205f83828220015c91828252888152886040916128228a8d8587205c906001600160a01b03891690613eb0565b8484525281205d84613e0d565b506126fc565b6127d5565b61287290825f5261282f60205f8a8785848420015c938484528181526128228c6040948587205c906001600160a01b03891690613add565b61279d565b3d156128a1573d9061288882611365565b916128966040519384611152565b82523d5f602084013e565b606090565b359065ffffffffffff821682036102fc57565b905f917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03815c16156128f1575050565b909192505d600190565b90604082013542116126c357612917611a5760208401846136f4565b915f5b61292760208301836136f4565b90508110156135d15761294481611a93611a8b60208601866136f4565b60608101519061297e6001600160a01b038251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506020810151515f198101908111611a0e575b5f8112156129a45750505060010161291a565b6129b2816020840151611691565b516129bb613788565b9082156020830152602084015151805f19810111611a0e575f1901831480835261358f575b6020820151156135545760408401516001600160a01b03855116915b604081015115612c1d5783916001600160a01b036060926020612aa0970151151580612c14575b612bed575b5116906001600160a01b0385168203612be6576001915b60405192612a4c8461111a565b60018452612a59816137be565b6020840152604083015288838301526080820152604051809581927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f95612bbf575b506020015115612bb057612ba69284612b02612bab979694612b7594611691565b52612b366001600160a01b0382167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506001600160a01b03612b4d8460408a01516137b1565b91167f000000000000000000000000000000000000000000000000000000000000000061420a565b6001600160a01b038551167f000000000000000000000000000000000000000000000000000000000000000061420a565b6126fc565b612991565b505050612bab919350926126fc565b6020919550612bdc9060603d606011611ce057611ccd8183611152565b5095919050612ae1565b5f91612a3f565b612c0f612bf98d611344565b8d8b611ae6886040888451169301519301611358565b612a28565b50321515612a23565b906001600160a01b03825116806001600160a01b038516145f14613137575060208401516130495750604051927f967870920000000000000000000000000000000000000000000000000000000084526001600160a01b03831660048501526020846024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9384156102f1575f94613015575b5083916001600160a01b038151166001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015230602482015260448101959095525f8580606481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f157612dec955f92613006575b505b611ddd6001600160a01b03612da88b828551168360208701511690614223565b50925116918c6002612dbf608092838101906118d9565b92909360405196612dcf886110ea565b875230602088015289604088015260608701528501523691611381565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612fe3575b506020015115612ecf57908291612bab9493612e45898d611691565b52612e7a836001600160a01b0384167f000000000000000000000000000000000000000000000000000000000000000061420a565b80831080612eb4575b612e90575b5050506126fc565b612ea6612eac93612ea08b611344565b926137b1565b91614356565b5f8080612e88565b50306001600160a01b03612ec78b611344565b161415612e83565b9450908094808210612ee8575b505050612bab906126fc565b91612ef8602092612f77946137b1565b90612f2d826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683614356565b60405193849283927f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612fb8575b8080612edc565b602090813d8311612fdc575b612fce8183611152565b810103126102fc575f612fb1565b503d612fc4565b6020919450612ffb903d805f833e611f248183611152565b509094919050612e29565b61300f90611106565b5f612d86565b9093506020813d602011613041575b8161303160209383611152565b810103126102fc5751925f612cbc565b3d9150613024565b909261305489611344565b6001600160a01b033091160361306f575b5f612dec94612d88565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936130a38a611344565b6130ac846142fd565b90863b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152306024820152918116604483015285166064820152945f908690608490829084905af19081156102f157612dec955f92613128575b50945050613065565b61313190611106565b5f61311f565b6001600160a01b036020849695940151168a8282145f1461340b5750505061320c61316e5f92846001600160a01b03885116614223565b92906131d48c6001600160a01b03808a5116938951151586146133df576131a361319784611344565b935b60808101906118d9565b929093604051966131b3886110ea565b875216602086015260408501528c6060850152600260808501523691611381565b60a0820152604051809381927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f1575f916133c4575b5060208401518c908a90156133aa5783836001600160a01b03936132836132899461327c8f9c9b9a98996132b29a611691565b5192611691565b52611691565b5191167f000000000000000000000000000000000000000000000000000000000000000061420a565b51156132f457612bab92916001600160a01b036020612ba6930151167f0000000000000000000000000000000000000000000000000000000000000000614341565b516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024810191909152602081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f15761337f575b50612bab906126fc565b602090813d83116133a3575b6133958183611152565b810103126102fc575f613375565b503d61338b565b50509091506133bb92939650611691565b519384916132b2565b6133d891503d805f833e61239c8183611152565b9050613249565b6131a3827f00000000000000000000000000000000000000000000000000000000000000001693613199565b61349e965090613466916060948b61342b608099989993848101906118d9565b9390946040519761343b89611136565b6001895260208901526001600160a01b038b1660408901528888015286015260a08501523691611381565b60c0820152604051809581927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f9561352d575b506020015115612bb057612ba69284613505612bab9796946001600160a01b0394611691565b52167f000000000000000000000000000000000000000000000000000000000000000061420a565b602091955061354a9060603d606011611ce057611ccd8183611152565b50959190506134df565b6fffffffffffffffffffffffffffffffff6001600160a01b0360206135858188015161357f886126eb565b90611691565b51015116916129fc565b6135cc856001600160a01b0360208401611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b6129e0565b50506135fc7f0000000000000000000000000000000000000000000000000000000000000000613a71565b9161360783516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b038061366d838b611691565b51165f528560205261368860405f205c8261267e858d611691565b6136928387611691565b5261369d828a611691565b51165f52856020525f604081205d0161364e565b4780156136f0577f00000000000000000000000000000000000000000000000000000000000000005c6136f0576001600160a01b0361184c92166140e0565b5050565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc57602001918160051b360383136102fc57565b91908110156116a55760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81813603018212156102fc570190565b604051906040820182811067ffffffffffffffff8211176110bd576040525f6020838281520152565b91908203918211611a0e57565b600211156137c857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b908160609103126102fc578051916040602083015192015190565b61010060c0610f7c93602084528051613828816137be565b602085015260208101516001600160a01b0380911660408601528060408301511660608601526060820151166080850152608081015160a085015260a08101518285015201519160e0808201520190610ffb565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc57846138a8918301611573565b9360208201519360408301519081116102fc57610f7c9201611507565b9081518082526020808093019301915f5b8281106138e4575050505090565b8351855293810193928101926001016138d6565b602081526001600160a01b038083511660208301526020830151166040820152613931604083015160c0606084015260e08301906138c5565b9060608301516080820152608083015160058110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b916060838303126102fc5782519260208101519267ffffffffffffffff938481116102fc578161399a918401611573565b9360408301519081116102fc57610f7c9201611507565b602081526001600160a01b038083511660208301526020830151166040820152604082015160608201526139f4606083015160c0608084015260e08301906138c5565b90608083015160048110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b91909160808060a08301948051613a38816137be565b84526020810151613a48816137be565b60208501526001600160a01b036040820151166040850152606081015160608501520151910152565b90815c613a7d81611175565b613a8a6040519182611152565b818152613a9682611175565b601f196020910136602084013781945f5b848110613ab5575050505050565b600190825f5280845f20015c6001600160a01b03613ad38388611691565b9116905201613aa7565b919280613dd8575b15613c51575050804710613c29576001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001691823b156102fc57604051907fd0e30db00000000000000000000000000000000000000000000000000000000082525f915f8160048185895af180156102f157613c12575b506044602092937f00000000000000000000000000000000000000000000000000000000000000001694613b98838783614356565b8460405196879485937f15afd409000000000000000000000000000000000000000000000000000000008552600485015260248401525af1908115613c065750613bdf5750565b602090813d8311613bff575b613bf58183611152565b810103126102fc57565b503d613beb565b604051903d90823e3d90fd5b60209250613c1f90611106565b60445f9250613b63565b7fa01a9df6000000000000000000000000000000000000000000000000000000005f5260045ffd5b90915f9080613c61575b50505050565b6001600160a01b0393847f00000000000000000000000000000000000000000000000000000000000000001694807f00000000000000000000000000000000000000000000000000000000000000001691613cbb846142fd565b96803b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152848316602482015297821660448901529186161660648701525f908690608490829084905af19485156102f157613d8095613dc4575b5082936020936040518097819582947f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1908115613c065750613d99575b808080613c5b565b602090813d8311613dbd575b613daf8183611152565b810103126102fc575f613d91565b503d613da5565b60209350613dd190611106565b5f92613d2f565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690821614613ae5565b6001810191805f5260209183835260405f205c8015155f14613ea7575f1990818101835c8380820191828403613e6a575b5050505050815c81810192818411611a0e575f93815d835284832001015d5f52525f604081205d600190565b613e77613e87938861443a565b865f52885f2001015c918561443a565b835f52808383885f2001015d5f5285855260405f205d5f80808381613e3e565b50505050505f90565b5f949383156140d857806140a3575b15614007576001600160a01b0391827f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03929092166004830152306024830152604482018590525f908290606490829084905af180156102f157613ff4575b5084827f000000000000000000000000000000000000000000000000000000000000000016803b15613ff05781906024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015613fe557613fcd575b5061184c939450166140e0565b613fd78691611106565b613fe15784613fc0565b8480fd5b6040513d88823e3d90fd5b5080fd5b613fff919550611106565b5f935f613f53565b929350906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015293909216602484015260448301525f908290606490829084905af180156102f15761409a5750565b61184c90611106565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690831614613ebf565b505050509050565b814710614130575f8080936001600160a01b038294165af1614100612877565b501561410857565b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcd786059000000000000000000000000000000000000000000000000000000005f523060045260245ffd5b90614171575080511561410857805190602001fd5b815115806141b7575b614182575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561417a565b6001810190825f528160205260405f205c155f1461420357805c815f52838160205f20015d60018101809111611a0e57815d5c915f5260205260405f205d600190565b5050505f90565b905f5260205261421f60405f2091825c611a01565b905d565b916044929391936001600160a01b03604094859282808551998a9586947fc9c1661b0000000000000000000000000000000000000000000000000000000086521660048501521660248301527f0000000000000000000000000000000000000000000000000000000000000000165afa9384156142f3575f935f956142bc575b50506142b96142b285946119d0565b9485611691565b52565b809295508194503d83116142ec575b6142d58183611152565b810103126102fc5760208251920151925f806142a3565b503d6142cb565b83513d5f823e3d90fd5b6001600160a01b0390818111614311571690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f5260a060045260245260445ffd5b905f5260205261421f60405f2091825c6137b1565b6040519260208401907fa9059cbb0000000000000000000000000000000000000000000000000000000082526001600160a01b038094166024860152604485015260448452608084019084821067ffffffffffffffff8311176110bd576143d5935f9384936040521694519082865af16143ce612877565b908361415c565b8051908115159182614416575b50506143eb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126102fc57602001518015908115036102fc575f806143e2565b5c111561444357565b7f0f4ae0e4000000000000000000000000000000000000000000000000000000005f5260045ffdfea2646970667358221220229a5cf89aa7c2d0a4b4d5db20bba6c2b3a74b080303fc6ec00ba582a5dcf75164736f6c634300081a0033", + "deployedBytecode": "0x60806040526004361015610072575b3615610018575f80fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361004a57005b7f0540ddf6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f3560e01c806308a465f614610e9d57806319c6989f1461084e578063286f580d146107b75780632950286e146106cc57806354fd4d501461058f5780635a3c3987146105665780635e01eb5a146105215780638a12a08c146104c65780638eb1b65e146103bf578063945ed33f14610344578063ac9650d8146103005763e3b5dff40361000e57346102fc576060806003193601126102fc5767ffffffffffffffff6004358181116102fc5761012d9036906004016112c4565b6101356111a1565b6044359283116102fc57610150610158933690600401610fcd565b9390916128b9565b905f5b835181101561017c57805f8761017360019488611691565b5101520161015b565b506101f06101fe610239946101b65f94886040519361019a8561111a565b30855260208501525f1960408501528660608501523691611381565b60808201526040519283917f8a12a08c0000000000000000000000000000000000000000000000000000000060208401526024830161143e565b03601f198101835282611152565b604051809481927fedfa3568000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39261028e915f916102cf575b50602080825183010191016115d4565b909391926102a7575b60405193849384610f2f565b0390f35b5f7f00000000000000000000000000000000000000000000000000000000000000005d610297565b6102eb91503d805f833e6102e38183611152565b81019061154d565b8461027e565b6040513d5f823e3d90fd5b5f80fd5b60206003193601126102fc5760043567ffffffffffffffff81116102fc576103386103326102a3923690600401610f9c565b9061179b565b60405191829182611020565b346102fc5761035236610eca565b61035a611945565b610362611972565b6103906102a3610371836128fb565b9193909461038a606061038383611344565b9201611358565b90612729565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d60405193849384610f2f565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576103ec9036906004016112c4565b906103f56111b7565b906064359081116102fc576101f061048b6102399461045161041c5f953690600401610fcd565b610425336128b9565b97604051946104338661111a565b33865260208601526024356040860152151560608501523691611381565b60808201526040519283917f945ed33f000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b604051809481927f48c89491000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b346102fc576102a36104ef6104da36610eca565b6104e2611945565b6104ea611972565b611a3b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009492945d60405193849384610f2f565b346102fc575f6003193601126102fc5760207f00000000000000000000000000000000000000000000000000000000000000005c6001600160a01b0360405191168152f35b346102fc576102a36104ef61057a36610eca565b610582611945565b61058a611972565b6128fb565b346102fc575f6003193601126102fc576040515f80549060018260011c91600184169182156106c2575b60209485851084146106955785879486865291825f146106575750506001146105fe575b506105ea92500383611152565b6102a3604051928284938452830190610ffb565b5f808052859250907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061063f5750506105ea9350820101856105dd565b80548389018501528794508693909201918101610628565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858201526105ea95151560051b85010192508791506105dd9050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b92607f16926105b9565b346102fc5760606003193601126102fc5767ffffffffffffffff6004358181116102fc576106fe9036906004016112c4565b906107076111a1565b6044359182116102fc5761072261072a923690600401610fcd565b9290916128b9565b905f5b845181101561075f57806fffffffffffffffffffffffffffffffff604061075660019489611691565b5101520161072d565b506101f06101fe8561077d5f94610239976040519361019a8561111a565b60808201526040519283917f5a3c3987000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576107e49036906004016112c4565b906107ed6111b7565b906064359081116102fc576101f061048b6102399461081461041c5f953690600401610fcd565b60808201526040519283917f08a465f60000000000000000000000000000000000000000000000000000000060208401526024830161143e565b60a06003193601126102fc5767ffffffffffffffff600435116102fc573660236004350112156102fc5767ffffffffffffffff60043560040135116102fc5736602460c060043560040135026004350101116102fc5760243567ffffffffffffffff81116102fc576108c4903690600401610f9c565b67ffffffffffffffff604435116102fc576060600319604435360301126102fc5760643567ffffffffffffffff81116102fc57610905903690600401610fcd565b60843567ffffffffffffffff81116102fc57610925903690600401610f9c565b949093610930611945565b806004356004013503610e75575f5b600435600401358110610bd25750505060443560040135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd6044353603018212156102fc57816044350160048101359067ffffffffffffffff82116102fc5760248260071b36039101136102fc576109e3575b6102a361033886865f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d61179b565b6001600160a01b039492947f0000000000000000000000000000000000000000000000000000000000000000163b156102fc57604051947f2a2d80d10000000000000000000000000000000000000000000000000000000086523360048701526060602487015260c486019260443501602481019367ffffffffffffffff6004830135116102fc57600482013560071b360385136102fc5760606064890152600482013590529192869260e484019291905f905b60048101358210610b5457505050602091601f19601f865f9787956001600160a01b03610ac860246044350161118d565b16608488015260448035013560a48801526003198787030160448801528186528786013787868286010152011601030181836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39361033893610b45575b8294508193506109b3565b610b4e90611106565b84610b3a565b9195945091926001600160a01b03610b6b8761118d565b168152602080870135916001600160a01b0383168093036102fc57600492600192820152610b9b604089016128a6565b65ffffffffffff8091166040830152610bb660608a016128a6565b1660608201526080809101970193019050889495939291610a97565b610be7610be082848661192a565b3691611381565b604051610bf3816110a1565b5f81526020915f838301525f60408301528281015190606060408201519101515f1a91835283830152604082015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc81850260043501360301126102fc5760405190610c60826110ea565b610c73602460c08602600435010161118d565b808352610c89604460c08702600435010161118d565b908185850152610ca2606460c08802600435010161118d565b60408581019190915260043560c08802016084810135606087015260a4810135608087015260c4013560a086015283015183519386015160ff91909116926001600160a01b0383163b156102fc575f6001600160a01b03809460e4948b98849860c460c06040519c8d9b8c9a7fd505accf000000000000000000000000000000000000000000000000000000008c521660048b01523060248b0152608482820260043501013560448b0152026004350101356064880152608487015260a486015260c4850152165af19081610e66575b50610e5c57610d7f612877565b906001600160a01b0381511690836001600160a01b0381830151166044604051809581937fdd62ed3e00000000000000000000000000000000000000000000000000000000835260048301523060248301525afa9182156102f1575f92610e2c575b506060015103610df75750506001905b0161093f565b805115610e045780519101fd5b7fa7285689000000000000000000000000000000000000000000000000000000005f5260045ffd5b9091508381813d8311610e55575b610e448183611152565b810103126102fc5751906060610de1565b503d610e3a565b5050600190610df1565b610e6f90611106565b8a610d72565b7faaad13f7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102fc57610eab36610eca565b610eb3611945565b610ebb611972565b6103906102a361037183611a3b565b600319906020828201126102fc576004359167ffffffffffffffff83116102fc578260a0920301126102fc5760040190565b9081518082526020808093019301915f5b828110610f1b575050505090565b835185529381019392810192600101610f0d565b939290610f4490606086526060860190610efc565b936020948181036020830152602080855192838152019401905f5b818110610f7f57505050610f7c9394506040818403910152610efc565b90565b82516001600160a01b031686529487019491870191600101610f5f565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc576020808501948460051b0101116102fc57565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc57602083818601950101116102fc57565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110555750505050505090565b9091929394958480611091837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51610ffb565b9801930193019194939290611045565b6060810190811067ffffffffffffffff8211176110bd57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd57604052565b60a0810190811067ffffffffffffffff8211176110bd57604052565b60e0810190811067ffffffffffffffff8211176110bd57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd5760051b60200190565b35906001600160a01b03821682036102fc57565b602435906001600160a01b03821682036102fc57565b6044359081151582036102fc57565b9190916080818403126102fc57604090815191608083019467ffffffffffffffff95848110878211176110bd57825283956112008461118d565b8552602090818501359081116102fc57840182601f820112156102fc5780359061122982611175565b9361123686519586611152565b82855283850190846060809502840101928184116102fc578501915b8383106112745750505050508401528181013590830152606090810135910152565b84838303126102fc57875190611289826110a1565b6112928461118d565b825261129f87850161118d565b87830152888401359081151582036102fc578288928b89950152815201920191611252565b81601f820112156102fc578035916020916112de84611175565b936112ec6040519586611152565b808552838086019160051b830101928084116102fc57848301915b8483106113175750505050505090565b823567ffffffffffffffff81116102fc578691611339848480948901016111c6565b815201920191611307565b356001600160a01b03811681036102fc5790565b3580151581036102fc5790565b67ffffffffffffffff81116110bd57601f01601f191660200190565b92919261138d82611365565b9161139b6040519384611152565b8294818452818301116102fc578281602093845f960137010152565b9060808101916001600160a01b03808251168352602093848301519460808186015285518092528060a086019601925f905b83821061140b5750505050506060816040829301516040850152015191015290565b845180518216895280840151821689850152604090810151151590890152606090970196938201936001909101906113e9565b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106114bd5750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b909192939583806114f8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611481565b81601f820112156102fc5780519061151e82611365565b9261152c6040519485611152565b828452602083830101116102fc57815f9260208093018386015e8301015290565b906020828203126102fc57815167ffffffffffffffff81116102fc57610f7c9201611507565b9080601f830112156102fc5781519060209161158e81611175565b9361159c6040519586611152565b81855260208086019260051b8201019283116102fc57602001905b8282106115c5575050505090565b815181529083019083016115b7565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc5784611600918301611573565b936020808301518581116102fc5783019082601f830112156102fc5781519161162883611175565b926116366040519485611152565b808452828085019160051b830101918583116102fc578301905b82821061167257505050509360408301519081116102fc57610f7c9201611573565b81516001600160a01b03811681036102fc578152908301908301611650565b80518210156116a55760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106117515750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b9091929395838061178c837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611715565b91906117a6336128b9565b907f000000000000000000000000000000000000000000000000000000000000000093845c6118b1576001906001865d6117df83611175565b926117ed6040519485611152565b808452601f196117fc82611175565b015f5b8181106118a05750505f5b8181106118575750505050905f61184c92945d7f0000000000000000000000000000000000000000000000000000000000000000805c9161184e575b506136b1565b565b5f905d5f611846565b806118845f8061186c610be08996888a61192a565b602081519101305af461187d612877565b903061415c565b61188e8288611691565b526118998187611691565b500161180a565b8060606020809389010152016117ff565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc576020019181360383136102fc57565b908210156116a5576119419160051b8101906118d9565b9091565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c6118b1576001905d565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633036119a457565b7f089676d5000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906119da82611175565b6119e76040519182611152565b828152601f196119f78294611175565b0190602036910137565b91908201809211611a0e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b604081013542116126c35790611a5e611a5760208401846136f4565b90506119d0565b915f5b611a6e60208301836136f4565b90508110156125c757611a9881611a93611a8b60208601866136f4565b369391613748565b6111c6565b936040850151936001600160a01b038651169060208701518051156116a55760200151604001511515806125be575b1561256357611aec611ad886611344565b8784611ae660608a01611358565b92613add565b5f5b60208801515181101561255357611b03613788565b6020890151515f198101908111611a0e578214806020830152821582525f1461254c576060890151905b611b3b8360208c0151611691565b51604081015190919015611cee57611bd36001600160a01b03835116936001600160a01b03881685145f14611ce7576001945b60405195611b7b8761111a565b5f8752611b87816137be565b6020870152604086015260609485918d838301526080820152604051809381927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611cb0575b50506020015115611c9657816001600160a01b036020611c909360019695611c388c8c611691565b5201611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b5051167f000000000000000000000000000000000000000000000000000000000000000061420a565b01611aee565b602001519097506001600160a01b03169250600190611c90565b60209294509081611cd592903d10611ce0575b611ccd8183611152565b8101906137f5565b91505092905f611c10565b503d611cc3565b5f94611b6e565b888a6001600160a01b038495945116806001600160a01b038a16145f14612132575050815115905061206e57888a80151580612053575b611f4d575b6001600160a01b03939291611ddd82611e15978b5f95897f0000000000000000000000000000000000000000000000000000000000000000921680885282602052604088205c611f3c575b5050505b6001611d9c8983511660208401998b8b51169080158a14611f3657508391614223565b999092511694611db1608091828101906118d9565b93909460405197611dc1896110ea565b8852306020890152604088015260608701528501523691611381565b60a0820152604051809681927f21457897000000000000000000000000000000000000000000000000000000008352600483016139b1565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611f0c575b506020015115611ee95791611ebc826001600160a01b0360019695611e7a611ee49686611691565b51611e858d8d611691565b52611eb3828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b50511692611691565b51907f000000000000000000000000000000000000000000000000000000000000000061420a565b611c90565b98506001929450611f02906001600160a01b0392611691565b5197511692611c90565b6020919450611f2c903d805f833e611f248183611152565b810190613969565b5094919050611e52565b91614223565b611f4592614341565b5f8281611d75565b50611f5a90929192611344565b91611f648b6142fd565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039485166004820152306024820152908416604482015292871660648401525f8380608481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f1578a611ddd8d611e15976001600160a01b03975f95612044575b50975092505091929350611d2a565b61204d90611106565b5f612035565b5061205d82611344565b6001600160a01b0316301415611d25565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916001600160a01b0384511692803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03949094166004850152306024850152604484018c90525f908490606490829084905af180156102f1578a611ddd8d611e15976001600160a01b03975f95612123575b50611d79565b61212c90611106565b5f61211d565b6001600160a01b0360208796949701511690898183145f146123d7576121cd925061220597915060016121735f96956001600160a01b0393848b5116614223565b509282895116956020890151151588146123ae5761219082611344565b945b6121a1608093848101906118d9565b959096604051996121b18b6110ea565b8a52166020890152604088015260608701528501523691611381565b60a0820152604051809581927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f1575f93612384575b5060200151156122c357816001600160a01b036020611ee493600196956122698c8c611691565b526122998383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b60208181015191516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101859052939a50909116945081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612359575b50600190611c90565b602090813d831161237d575b61236f8183611152565b810103126102fc575f612350565b503d612365565b60209193506123a4903d805f833e61239c8183611152565b81019061387c565b5093919050612242565b837f00000000000000000000000000000000000000000000000000000000000000001694612192565b6001600160a01b036124669561242e9394956123f860809b8c8101906118d9565b9390946040519761240889611136565b5f8952602089015216604087015260609a8b978888015286015260a08501523691611381565b60c0820152604051809381927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612525575b50506020015115611c9657816001600160a01b036020611ee493600196956124cb8c8c611691565b526124fb8383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b6020929450908161254192903d10611ce057611ccd8183611152565b91505092905f6124a3565b5f90611b2d565b5091955090935050600101611a61565b61258d827f00000000000000000000000000000000000000000000000000000000000000006141c0565b506125b986837f000000000000000000000000000000000000000000000000000000000000000061420a565b611aec565b50321515611ac7565b50506125f27f0000000000000000000000000000000000000000000000000000000000000000613a71565b916125fd83516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b0380612663838b611691565b51165f528560205261269160405f205c8261267e858d611691565b51165f528860205260405f205c90611a01565b61269b8387611691565b526126a6828a611691565b51165f52856020525f604081205d01612644565b50949391509150565b7fe08b8af0000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f198201918213600116611a0e57565b7f80000000000000000000000000000000000000000000000000000000000000008114611a0e575f190190565b907f000000000000000000000000000000000000000000000000000000000000000090815c7f0000000000000000000000000000000000000000000000000000000000000000612779815c6126eb565b907f0000000000000000000000000000000000000000000000000000000000000000915b5f81121561283a575050506127b1906126eb565b917f0000000000000000000000000000000000000000000000000000000000000000925b5f8112156127ea575050505061184c906136b1565b61283590825f5261282f60205f83828220015c91828252888152886040916128228a8d8587205c906001600160a01b03891690613eb0565b8484525281205d84613e0d565b506126fc565b6127d5565b61287290825f5261282f60205f8a8785848420015c938484528181526128228c6040948587205c906001600160a01b03891690613add565b61279d565b3d156128a1573d9061288882611365565b916128966040519384611152565b82523d5f602084013e565b606090565b359065ffffffffffff821682036102fc57565b905f917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03815c16156128f1575050565b909192505d600190565b90604082013542116126c357612917611a5760208401846136f4565b915f5b61292760208301836136f4565b90508110156135d15761294481611a93611a8b60208601866136f4565b60608101519061297e6001600160a01b038251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506020810151515f198101908111611a0e575b5f8112156129a45750505060010161291a565b6129b2816020840151611691565b516129bb613788565b9082156020830152602084015151805f19810111611a0e575f1901831480835261358f575b6020820151156135545760408401516001600160a01b03855116915b604081015115612c1d5783916001600160a01b036060926020612aa0970151151580612c14575b612bed575b5116906001600160a01b0385168203612be6576001915b60405192612a4c8461111a565b60018452612a59816137be565b6020840152604083015288838301526080820152604051809581927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f95612bbf575b506020015115612bb057612ba69284612b02612bab979694612b7594611691565b52612b366001600160a01b0382167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506001600160a01b03612b4d8460408a01516137b1565b91167f000000000000000000000000000000000000000000000000000000000000000061420a565b6001600160a01b038551167f000000000000000000000000000000000000000000000000000000000000000061420a565b6126fc565b612991565b505050612bab919350926126fc565b6020919550612bdc9060603d606011611ce057611ccd8183611152565b5095919050612ae1565b5f91612a3f565b612c0f612bf98d611344565b8d8b611ae6886040888451169301519301611358565b612a28565b50321515612a23565b906001600160a01b03825116806001600160a01b038516145f14613137575060208401516130495750604051927f967870920000000000000000000000000000000000000000000000000000000084526001600160a01b03831660048501526020846024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9384156102f1575f94613015575b5083916001600160a01b038151166001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015230602482015260448101959095525f8580606481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f157612dec955f92613006575b505b611ddd6001600160a01b03612da88b828551168360208701511690614223565b50925116918c6002612dbf608092838101906118d9565b92909360405196612dcf886110ea565b875230602088015289604088015260608701528501523691611381565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612fe3575b506020015115612ecf57908291612bab9493612e45898d611691565b52612e7a836001600160a01b0384167f000000000000000000000000000000000000000000000000000000000000000061420a565b80831080612eb4575b612e90575b5050506126fc565b612ea6612eac93612ea08b611344565b926137b1565b91614356565b5f8080612e88565b50306001600160a01b03612ec78b611344565b161415612e83565b9450908094808210612ee8575b505050612bab906126fc565b91612ef8602092612f77946137b1565b90612f2d826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683614356565b60405193849283927f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612fb8575b8080612edc565b602090813d8311612fdc575b612fce8183611152565b810103126102fc575f612fb1565b503d612fc4565b6020919450612ffb903d805f833e611f248183611152565b509094919050612e29565b61300f90611106565b5f612d86565b9093506020813d602011613041575b8161303160209383611152565b810103126102fc5751925f612cbc565b3d9150613024565b909261305489611344565b6001600160a01b033091160361306f575b5f612dec94612d88565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936130a38a611344565b6130ac846142fd565b90863b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152306024820152918116604483015285166064820152945f908690608490829084905af19081156102f157612dec955f92613128575b50945050613065565b61313190611106565b5f61311f565b6001600160a01b036020849695940151168a8282145f1461340b5750505061320c61316e5f92846001600160a01b03885116614223565b92906131d48c6001600160a01b03808a5116938951151586146133df576131a361319784611344565b935b60808101906118d9565b929093604051966131b3886110ea565b875216602086015260408501528c6060850152600260808501523691611381565b60a0820152604051809381927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f1575f916133c4575b5060208401518c908a90156133aa5783836001600160a01b03936132836132899461327c8f9c9b9a98996132b29a611691565b5192611691565b52611691565b5191167f000000000000000000000000000000000000000000000000000000000000000061420a565b51156132f457612bab92916001600160a01b036020612ba6930151167f0000000000000000000000000000000000000000000000000000000000000000614341565b516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024810191909152602081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f15761337f575b50612bab906126fc565b602090813d83116133a3575b6133958183611152565b810103126102fc575f613375565b503d61338b565b50509091506133bb92939650611691565b519384916132b2565b6133d891503d805f833e61239c8183611152565b9050613249565b6131a3827f00000000000000000000000000000000000000000000000000000000000000001693613199565b61349e965090613466916060948b61342b608099989993848101906118d9565b9390946040519761343b89611136565b6001895260208901526001600160a01b038b1660408901528888015286015260a08501523691611381565b60c0820152604051809581927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f9561352d575b506020015115612bb057612ba69284613505612bab9796946001600160a01b0394611691565b52167f000000000000000000000000000000000000000000000000000000000000000061420a565b602091955061354a9060603d606011611ce057611ccd8183611152565b50959190506134df565b6fffffffffffffffffffffffffffffffff6001600160a01b0360206135858188015161357f886126eb565b90611691565b51015116916129fc565b6135cc856001600160a01b0360208401611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b6129e0565b50506135fc7f0000000000000000000000000000000000000000000000000000000000000000613a71565b9161360783516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b038061366d838b611691565b51165f528560205261368860405f205c8261267e858d611691565b6136928387611691565b5261369d828a611691565b51165f52856020525f604081205d0161364e565b4780156136f0577f00000000000000000000000000000000000000000000000000000000000000005c6136f0576001600160a01b0361184c92166140e0565b5050565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc57602001918160051b360383136102fc57565b91908110156116a55760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81813603018212156102fc570190565b604051906040820182811067ffffffffffffffff8211176110bd576040525f6020838281520152565b91908203918211611a0e57565b600211156137c857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b908160609103126102fc578051916040602083015192015190565b61010060c0610f7c93602084528051613828816137be565b602085015260208101516001600160a01b0380911660408601528060408301511660608601526060820151166080850152608081015160a085015260a08101518285015201519160e0808201520190610ffb565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc57846138a8918301611573565b9360208201519360408301519081116102fc57610f7c9201611507565b9081518082526020808093019301915f5b8281106138e4575050505090565b8351855293810193928101926001016138d6565b602081526001600160a01b038083511660208301526020830151166040820152613931604083015160c0606084015260e08301906138c5565b9060608301516080820152608083015160058110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b916060838303126102fc5782519260208101519267ffffffffffffffff938481116102fc578161399a918401611573565b9360408301519081116102fc57610f7c9201611507565b602081526001600160a01b038083511660208301526020830151166040820152604082015160608201526139f4606083015160c0608084015260e08301906138c5565b90608083015160048110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b91909160808060a08301948051613a38816137be565b84526020810151613a48816137be565b60208501526001600160a01b036040820151166040850152606081015160608501520151910152565b90815c613a7d81611175565b613a8a6040519182611152565b818152613a9682611175565b601f196020910136602084013781945f5b848110613ab5575050505050565b600190825f5280845f20015c6001600160a01b03613ad38388611691565b9116905201613aa7565b919280613dd8575b15613c51575050804710613c29576001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001691823b156102fc57604051907fd0e30db00000000000000000000000000000000000000000000000000000000082525f915f8160048185895af180156102f157613c12575b506044602092937f00000000000000000000000000000000000000000000000000000000000000001694613b98838783614356565b8460405196879485937f15afd409000000000000000000000000000000000000000000000000000000008552600485015260248401525af1908115613c065750613bdf5750565b602090813d8311613bff575b613bf58183611152565b810103126102fc57565b503d613beb565b604051903d90823e3d90fd5b60209250613c1f90611106565b60445f9250613b63565b7fa01a9df6000000000000000000000000000000000000000000000000000000005f5260045ffd5b90915f9080613c61575b50505050565b6001600160a01b0393847f00000000000000000000000000000000000000000000000000000000000000001694807f00000000000000000000000000000000000000000000000000000000000000001691613cbb846142fd565b96803b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152848316602482015297821660448901529186161660648701525f908690608490829084905af19485156102f157613d8095613dc4575b5082936020936040518097819582947f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1908115613c065750613d99575b808080613c5b565b602090813d8311613dbd575b613daf8183611152565b810103126102fc575f613d91565b503d613da5565b60209350613dd190611106565b5f92613d2f565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690821614613ae5565b6001810191805f5260209183835260405f205c8015155f14613ea7575f1990818101835c8380820191828403613e6a575b5050505050815c81810192818411611a0e575f93815d835284832001015d5f52525f604081205d600190565b613e77613e87938861443a565b865f52885f2001015c918561443a565b835f52808383885f2001015d5f5285855260405f205d5f80808381613e3e565b50505050505f90565b5f949383156140d857806140a3575b15614007576001600160a01b0391827f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03929092166004830152306024830152604482018590525f908290606490829084905af180156102f157613ff4575b5084827f000000000000000000000000000000000000000000000000000000000000000016803b15613ff05781906024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015613fe557613fcd575b5061184c939450166140e0565b613fd78691611106565b613fe15784613fc0565b8480fd5b6040513d88823e3d90fd5b5080fd5b613fff919550611106565b5f935f613f53565b929350906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015293909216602484015260448301525f908290606490829084905af180156102f15761409a5750565b61184c90611106565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690831614613ebf565b505050509050565b814710614130575f8080936001600160a01b038294165af1614100612877565b501561410857565b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcd786059000000000000000000000000000000000000000000000000000000005f523060045260245ffd5b90614171575080511561410857805190602001fd5b815115806141b7575b614182575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561417a565b6001810190825f528160205260405f205c155f1461420357805c815f52838160205f20015d60018101809111611a0e57815d5c915f5260205260405f205d600190565b5050505f90565b905f5260205261421f60405f2091825c611a01565b905d565b916044929391936001600160a01b03604094859282808551998a9586947fc9c1661b0000000000000000000000000000000000000000000000000000000086521660048501521660248301527f0000000000000000000000000000000000000000000000000000000000000000165afa9384156142f3575f935f956142bc575b50506142b96142b285946119d0565b9485611691565b52565b809295508194503d83116142ec575b6142d58183611152565b810103126102fc5760208251920151925f806142a3565b503d6142cb565b83513d5f823e3d90fd5b6001600160a01b0390818111614311571690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f5260a060045260245260445ffd5b905f5260205261421f60405f2091825c6137b1565b6040519260208401907fa9059cbb0000000000000000000000000000000000000000000000000000000082526001600160a01b038094166024860152604485015260448452608084019084821067ffffffffffffffff8311176110bd576143d5935f9384936040521694519082865af16143ce612877565b908361415c565b8051908115159182614416575b50506143eb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126102fc57602001518015908115036102fc575f806143e2565b5c111561444357565b7f0f4ae0e4000000000000000000000000000000000000000000000000000000005f5260045ffdfea2646970667358221220229a5cf89aa7c2d0a4b4d5db20bba6c2b3a74b080303fc6ec00ba582a5dcf75164736f6c634300081a0033", + "linkReferences": {}, + "deployedLinkReferences": {}, + "_disabled": [ + { + "inputs": [], + "name": "getSender", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", "type": "function" }, { @@ -449,77 +511,109 @@ { "components": [ { - "internalType": "contract IERC20", - "name": "tokenIn", + "internalType": "address", + "name": "token", "type": "address" }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct IRouterCommon.PermitApproval[]", + "name": "permitBatch", + "type": "tuple[]" + }, + { + "internalType": "bytes[]", + "name": "permitSignatures", + "type": "bytes[]" + }, + { + "components": [ { "components": [ { "internalType": "address", - "name": "pool", + "name": "token", "type": "address" }, { - "internalType": "contract IERC20", - "name": "tokenOut", - "type": "address" + "internalType": "uint160", + "name": "amount", + "type": "uint160" }, { - "internalType": "bool", - "name": "isBuffer", - "type": "bool" + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" } ], - "internalType": "struct IBatchRouter.SwapPathStep[]", - "name": "steps", + "internalType": "struct IAllowanceTransfer.PermitDetails[]", + "name": "details", "type": "tuple[]" }, { - "internalType": "uint256", - "name": "maxAmountIn", - "type": "uint256" + "internalType": "address", + "name": "spender", + "type": "address" }, { "internalType": "uint256", - "name": "exactAmountOut", + "name": "sigDeadline", "type": "uint256" } ], - "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", - "name": "paths", - "type": "tuple[]" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" + "internalType": "struct IAllowanceTransfer.PermitBatch", + "name": "permit2Batch", + "type": "tuple" }, { "internalType": "bytes", - "name": "userData", + "name": "permit2Signature", "type": "bytes" + }, + { + "internalType": "bytes[]", + "name": "multicallData", + "type": "bytes[]" } ], - "name": "querySwapExactOut", + "name": "permitBatchAndCall", "outputs": [ { - "internalType": "uint256[]", - "name": "pathAmountsIn", - "type": "uint256[]" - }, - { - "internalType": "address[]", - "name": "tokensIn", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "amountsIn", - "type": "uint256[]" + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" } ], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -562,16 +656,16 @@ }, { "internalType": "uint256", - "name": "maxAmountIn", + "name": "exactAmountIn", "type": "uint256" }, { "internalType": "uint256", - "name": "exactAmountOut", + "name": "minAmountOut", "type": "uint256" } ], - "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", "name": "paths", "type": "tuple[]" }, @@ -591,26 +685,26 @@ "type": "bytes" } ], - "internalType": "struct IBatchRouter.SwapExactOutHookParams", + "internalType": "struct IBatchRouter.SwapExactInHookParams", "name": "params", "type": "tuple" } ], - "name": "querySwapExactOutHook", + "name": "querySwapExactInHook", "outputs": [ { "internalType": "uint256[]", - "name": "pathAmountsIn", + "name": "pathAmountsOut", "type": "uint256[]" }, { "internalType": "address[]", - "name": "tokensIn", + "name": "tokensOut", "type": "address[]" }, { "internalType": "uint256[]", - "name": "amountsIn", + "name": "amountsOut", "type": "uint256[]" } ], @@ -622,82 +716,94 @@ { "components": [ { - "internalType": "contract IERC20", - "name": "tokenIn", + "internalType": "address", + "name": "sender", "type": "address" }, { "components": [ { - "internalType": "address", - "name": "pool", + "internalType": "contract IERC20", + "name": "tokenIn", "type": "address" }, { - "internalType": "contract IERC20", - "name": "tokenOut", - "type": "address" + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" }, { - "internalType": "bool", - "name": "isBuffer", - "type": "bool" + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" } ], - "internalType": "struct IBatchRouter.SwapPathStep[]", - "name": "steps", + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "name": "paths", "type": "tuple[]" }, { "internalType": "uint256", - "name": "exactAmountIn", + "name": "deadline", "type": "uint256" }, { - "internalType": "uint256", - "name": "minAmountOut", - "type": "uint256" + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" } ], - "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", - "name": "paths", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "wethIsEth", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" + "internalType": "struct IBatchRouter.SwapExactOutHookParams", + "name": "params", + "type": "tuple" } ], - "name": "swapExactIn", + "name": "querySwapExactOutHook", "outputs": [ { "internalType": "uint256[]", - "name": "pathAmountsOut", + "name": "pathAmountsIn", "type": "uint256[]" }, { "internalType": "address[]", - "name": "tokensOut", + "name": "tokensIn", "type": "address[]" }, { "internalType": "uint256[]", - "name": "amountsOut", + "name": "amountsIn", "type": "uint256[]" } ], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -795,89 +901,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20", - "name": "tokenIn", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "pool", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "tokenOut", - "type": "address" - }, - { - "internalType": "bool", - "name": "isBuffer", - "type": "bool" - } - ], - "internalType": "struct IBatchRouter.SwapPathStep[]", - "name": "steps", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "maxAmountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exactAmountOut", - "type": "uint256" - } - ], - "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", - "name": "paths", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "wethIsEth", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - } - ], - "name": "swapExactOut", - "outputs": [ - { - "internalType": "uint256[]", - "name": "pathAmountsIn", - "type": "uint256[]" - }, - { - "internalType": "address[]", - "name": "tokensIn", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "amountsIn", - "type": "uint256[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -972,27 +995,6 @@ ], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" } - ], - "bytecode": "0x6101c0604090808252346105c957614bbd803803809161001f82856105e8565b83398101916080828403126105c95781516001600160a01b03939084811681036105c957602093848101519286841684036105c9578482015196871687036105c95760608201516001600160401b03928382116105c9570192601f908282860112156105c95784518481116105b557601f19958851946100a58b898786011601876105e8565b8286528a83830101116105c957815f928b8093018388015e8501015260805281519283116105b5575f54916001928381811c911680156105ab575b8982101461059757828111610554575b50879184116001146104f757839450908392915f946104ec575b50501b915f199060031b1c1916175f555b61014961012661060b565b835190610132826105cd565b600682526539b2b73232b960d11b86830152610669565b60a05261018561015761060b565b835190610163826105cd565b60118252701a5cd4995d1d5c9b915d1a131bd8dad959607a1b86830152610669565b60c05260e0526101009283526101cd815161019f816105cd565b601381527f63757272656e7453776170546f6b656e73496e0000000000000000000000000084820152610633565b9161012092835261021082516101e2816105cd565b601481527f63757272656e7453776170546f6b656e734f757400000000000000000000000083820152610633565b6101409081526102528351610224816105cd565b601981527f63757272656e7453776170546f6b656e496e416d6f756e74730000000000000084820152610633565b906101609182526102d8610298855161026a816105cd565b601a81527f63757272656e7453776170546f6b656e4f7574416d6f756e747300000000000086820152610633565b936101809485527f736574746c6564546f6b656e416d6f756e7473000000000000000000000000008651916102cc836105cd565b60138352820152610633565b936101a094855251946144a1968761071c88396080518781816102460152818161197c01528181611be001528181611e22015281816120790152818161221201528181612323015281816123b10152818161247301528181612aad01528181612c8c01528181612cd401528181612d5201528181612df901528181612f0701528181612f840152818161321901528181613348015281816133e5015281816134ab01528181613b6c01528181613c9101528181613ed0015281816140150152614271015260a0518781816102aa015281816105350152818161181f01526128be015260c0518781816117a901526136ba015260e051878181602201528181613afe01528181613de401528181613f5801526140af0152518681816109f001528181610b0401528181611f6e01528181611ff4015281816130790152613c6d015251858181612569015281816127500152818161295a01526135d8015251848181611c4301528181611e8f01528181612275015281816124d7015281816125ce0152818161272c01528181612b1201526135a8015251838181611d43015281816125950152818161277c0152818161328e01528181613509015261362b015251828181611c6c01528181611ec00152818161250101528181612621015281816127b401528181612b5101526132d001525181818161229f015281816125ff01528181612b8201528181612e5601526136090152f35b015192505f8061010a565b91938316915f805283885f20935f5b8a8883831061053d5750505010610525575b505050811b015f5561011b565b01515f1960f88460031b161c191690555f8080610518565b868601518855909601959485019487935001610506565b5f8052885f208380870160051c8201928b881061058e575b0160051c019084905b8281106105835750506100f0565b5f8155018490610575565b9250819261056c565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100e0565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b604081019081106001600160401b038211176105b557604052565b601f909101601f19168101906001600160401b038211908210176105b557604052565b60405190610618826105cd565b600c82526b2937baba32b921b7b6b6b7b760a11b6020830152565b61066690604051610643816105cd565b60118152702130ba31b42937baba32b921b7b6b6b7b760791b6020820152610669565b90565b906106d6603a60209260405193849181808401977f62616c616e6365722d6c6162732e76332e73746f726167652e000000000000008952805191829101603986015e830190601760f91b60398301528051928391018583015e015f8382015203601a8101845201826105e8565b5190205f198101908111610707576040519060208201908152602082526106fc826105cd565b9051902060ff191690565b634e487b7160e01b5f52601160045260245ffdfe60806040526004361015610072575b3615610018575f80fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361004a57005b7f0540ddf6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f3560e01c806308a465f614610e9d57806319c6989f1461084e578063286f580d146107b75780632950286e146106cc57806354fd4d501461058f5780635a3c3987146105665780635e01eb5a146105215780638a12a08c146104c65780638eb1b65e146103bf578063945ed33f14610344578063ac9650d8146103005763e3b5dff40361000e57346102fc576060806003193601126102fc5767ffffffffffffffff6004358181116102fc5761012d9036906004016112c4565b6101356111a1565b6044359283116102fc57610150610158933690600401610fcd565b9390916128b9565b905f5b835181101561017c57805f8761017360019488611691565b5101520161015b565b506101f06101fe610239946101b65f94886040519361019a8561111a565b30855260208501525f1960408501528660608501523691611381565b60808201526040519283917f8a12a08c0000000000000000000000000000000000000000000000000000000060208401526024830161143e565b03601f198101835282611152565b604051809481927fedfa3568000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39261028e915f916102cf575b50602080825183010191016115d4565b909391926102a7575b60405193849384610f2f565b0390f35b5f7f00000000000000000000000000000000000000000000000000000000000000005d610297565b6102eb91503d805f833e6102e38183611152565b81019061154d565b8461027e565b6040513d5f823e3d90fd5b5f80fd5b60206003193601126102fc5760043567ffffffffffffffff81116102fc576103386103326102a3923690600401610f9c565b9061179b565b60405191829182611020565b346102fc5761035236610eca565b61035a611945565b610362611972565b6103906102a3610371836128fb565b9193909461038a606061038383611344565b9201611358565b90612729565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d60405193849384610f2f565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576103ec9036906004016112c4565b906103f56111b7565b906064359081116102fc576101f061048b6102399461045161041c5f953690600401610fcd565b610425336128b9565b97604051946104338661111a565b33865260208601526024356040860152151560608501523691611381565b60808201526040519283917f945ed33f000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b604051809481927f48c89491000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b346102fc576102a36104ef6104da36610eca565b6104e2611945565b6104ea611972565b611a3b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009492945d60405193849384610f2f565b346102fc575f6003193601126102fc5760207f00000000000000000000000000000000000000000000000000000000000000005c6001600160a01b0360405191168152f35b346102fc576102a36104ef61057a36610eca565b610582611945565b61058a611972565b6128fb565b346102fc575f6003193601126102fc576040515f80549060018260011c91600184169182156106c2575b60209485851084146106955785879486865291825f146106575750506001146105fe575b506105ea92500383611152565b6102a3604051928284938452830190610ffb565b5f808052859250907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061063f5750506105ea9350820101856105dd565b80548389018501528794508693909201918101610628565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858201526105ea95151560051b85010192508791506105dd9050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b92607f16926105b9565b346102fc5760606003193601126102fc5767ffffffffffffffff6004358181116102fc576106fe9036906004016112c4565b906107076111a1565b6044359182116102fc5761072261072a923690600401610fcd565b9290916128b9565b905f5b845181101561075f57806fffffffffffffffffffffffffffffffff604061075660019489611691565b5101520161072d565b506101f06101fe8561077d5f94610239976040519361019a8561111a565b60808201526040519283917f5a3c3987000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576107e49036906004016112c4565b906107ed6111b7565b906064359081116102fc576101f061048b6102399461081461041c5f953690600401610fcd565b60808201526040519283917f08a465f60000000000000000000000000000000000000000000000000000000060208401526024830161143e565b60a06003193601126102fc5767ffffffffffffffff600435116102fc573660236004350112156102fc5767ffffffffffffffff60043560040135116102fc5736602460c060043560040135026004350101116102fc5760243567ffffffffffffffff81116102fc576108c4903690600401610f9c565b67ffffffffffffffff604435116102fc576060600319604435360301126102fc5760643567ffffffffffffffff81116102fc57610905903690600401610fcd565b60843567ffffffffffffffff81116102fc57610925903690600401610f9c565b949093610930611945565b806004356004013503610e75575f5b600435600401358110610bd25750505060443560040135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd6044353603018212156102fc57816044350160048101359067ffffffffffffffff82116102fc5760248260071b36039101136102fc576109e3575b6102a361033886865f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d61179b565b6001600160a01b039492947f0000000000000000000000000000000000000000000000000000000000000000163b156102fc57604051947f2a2d80d10000000000000000000000000000000000000000000000000000000086523360048701526060602487015260c486019260443501602481019367ffffffffffffffff6004830135116102fc57600482013560071b360385136102fc5760606064890152600482013590529192869260e484019291905f905b60048101358210610b5457505050602091601f19601f865f9787956001600160a01b03610ac860246044350161118d565b16608488015260448035013560a48801526003198787030160448801528186528786013787868286010152011601030181836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39361033893610b45575b8294508193506109b3565b610b4e90611106565b84610b3a565b9195945091926001600160a01b03610b6b8761118d565b168152602080870135916001600160a01b0383168093036102fc57600492600192820152610b9b604089016128a6565b65ffffffffffff8091166040830152610bb660608a016128a6565b1660608201526080809101970193019050889495939291610a97565b610be7610be082848661192a565b3691611381565b604051610bf3816110a1565b5f81526020915f838301525f60408301528281015190606060408201519101515f1a91835283830152604082015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc81850260043501360301126102fc5760405190610c60826110ea565b610c73602460c08602600435010161118d565b808352610c89604460c08702600435010161118d565b908185850152610ca2606460c08802600435010161118d565b60408581019190915260043560c08802016084810135606087015260a4810135608087015260c4013560a086015283015183519386015160ff91909116926001600160a01b0383163b156102fc575f6001600160a01b03809460e4948b98849860c460c06040519c8d9b8c9a7fd505accf000000000000000000000000000000000000000000000000000000008c521660048b01523060248b0152608482820260043501013560448b0152026004350101356064880152608487015260a486015260c4850152165af19081610e66575b50610e5c57610d7f612877565b906001600160a01b0381511690836001600160a01b0381830151166044604051809581937fdd62ed3e00000000000000000000000000000000000000000000000000000000835260048301523060248301525afa9182156102f1575f92610e2c575b506060015103610df75750506001905b0161093f565b805115610e045780519101fd5b7fa7285689000000000000000000000000000000000000000000000000000000005f5260045ffd5b9091508381813d8311610e55575b610e448183611152565b810103126102fc5751906060610de1565b503d610e3a565b5050600190610df1565b610e6f90611106565b8a610d72565b7faaad13f7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102fc57610eab36610eca565b610eb3611945565b610ebb611972565b6103906102a361037183611a3b565b600319906020828201126102fc576004359167ffffffffffffffff83116102fc578260a0920301126102fc5760040190565b9081518082526020808093019301915f5b828110610f1b575050505090565b835185529381019392810192600101610f0d565b939290610f4490606086526060860190610efc565b936020948181036020830152602080855192838152019401905f5b818110610f7f57505050610f7c9394506040818403910152610efc565b90565b82516001600160a01b031686529487019491870191600101610f5f565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc576020808501948460051b0101116102fc57565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc57602083818601950101116102fc57565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110555750505050505090565b9091929394958480611091837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51610ffb565b9801930193019194939290611045565b6060810190811067ffffffffffffffff8211176110bd57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd57604052565b60a0810190811067ffffffffffffffff8211176110bd57604052565b60e0810190811067ffffffffffffffff8211176110bd57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd5760051b60200190565b35906001600160a01b03821682036102fc57565b602435906001600160a01b03821682036102fc57565b6044359081151582036102fc57565b9190916080818403126102fc57604090815191608083019467ffffffffffffffff95848110878211176110bd57825283956112008461118d565b8552602090818501359081116102fc57840182601f820112156102fc5780359061122982611175565b9361123686519586611152565b82855283850190846060809502840101928184116102fc578501915b8383106112745750505050508401528181013590830152606090810135910152565b84838303126102fc57875190611289826110a1565b6112928461118d565b825261129f87850161118d565b87830152888401359081151582036102fc578288928b89950152815201920191611252565b81601f820112156102fc578035916020916112de84611175565b936112ec6040519586611152565b808552838086019160051b830101928084116102fc57848301915b8483106113175750505050505090565b823567ffffffffffffffff81116102fc578691611339848480948901016111c6565b815201920191611307565b356001600160a01b03811681036102fc5790565b3580151581036102fc5790565b67ffffffffffffffff81116110bd57601f01601f191660200190565b92919261138d82611365565b9161139b6040519384611152565b8294818452818301116102fc578281602093845f960137010152565b9060808101916001600160a01b03808251168352602093848301519460808186015285518092528060a086019601925f905b83821061140b5750505050506060816040829301516040850152015191015290565b845180518216895280840151821689850152604090810151151590890152606090970196938201936001909101906113e9565b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106114bd5750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b909192939583806114f8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611481565b81601f820112156102fc5780519061151e82611365565b9261152c6040519485611152565b828452602083830101116102fc57815f9260208093018386015e8301015290565b906020828203126102fc57815167ffffffffffffffff81116102fc57610f7c9201611507565b9080601f830112156102fc5781519060209161158e81611175565b9361159c6040519586611152565b81855260208086019260051b8201019283116102fc57602001905b8282106115c5575050505090565b815181529083019083016115b7565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc5784611600918301611573565b936020808301518581116102fc5783019082601f830112156102fc5781519161162883611175565b926116366040519485611152565b808452828085019160051b830101918583116102fc578301905b82821061167257505050509360408301519081116102fc57610f7c9201611573565b81516001600160a01b03811681036102fc578152908301908301611650565b80518210156116a55760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106117515750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b9091929395838061178c837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611715565b91906117a6336128b9565b907f000000000000000000000000000000000000000000000000000000000000000093845c6118b1576001906001865d6117df83611175565b926117ed6040519485611152565b808452601f196117fc82611175565b015f5b8181106118a05750505f5b8181106118575750505050905f61184c92945d7f0000000000000000000000000000000000000000000000000000000000000000805c9161184e575b506136b1565b565b5f905d5f611846565b806118845f8061186c610be08996888a61192a565b602081519101305af461187d612877565b903061415c565b61188e8288611691565b526118998187611691565b500161180a565b8060606020809389010152016117ff565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc576020019181360383136102fc57565b908210156116a5576119419160051b8101906118d9565b9091565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c6118b1576001905d565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633036119a457565b7f089676d5000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906119da82611175565b6119e76040519182611152565b828152601f196119f78294611175565b0190602036910137565b91908201809211611a0e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b604081013542116126c35790611a5e611a5760208401846136f4565b90506119d0565b915f5b611a6e60208301836136f4565b90508110156125c757611a9881611a93611a8b60208601866136f4565b369391613748565b6111c6565b936040850151936001600160a01b038651169060208701518051156116a55760200151604001511515806125be575b1561256357611aec611ad886611344565b8784611ae660608a01611358565b92613add565b5f5b60208801515181101561255357611b03613788565b6020890151515f198101908111611a0e578214806020830152821582525f1461254c576060890151905b611b3b8360208c0151611691565b51604081015190919015611cee57611bd36001600160a01b03835116936001600160a01b03881685145f14611ce7576001945b60405195611b7b8761111a565b5f8752611b87816137be565b6020870152604086015260609485918d838301526080820152604051809381927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611cb0575b50506020015115611c9657816001600160a01b036020611c909360019695611c388c8c611691565b5201611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b5051167f000000000000000000000000000000000000000000000000000000000000000061420a565b01611aee565b602001519097506001600160a01b03169250600190611c90565b60209294509081611cd592903d10611ce0575b611ccd8183611152565b8101906137f5565b91505092905f611c10565b503d611cc3565b5f94611b6e565b888a6001600160a01b038495945116806001600160a01b038a16145f14612132575050815115905061206e57888a80151580612053575b611f4d575b6001600160a01b03939291611ddd82611e15978b5f95897f0000000000000000000000000000000000000000000000000000000000000000921680885282602052604088205c611f3c575b5050505b6001611d9c8983511660208401998b8b51169080158a14611f3657508391614223565b999092511694611db1608091828101906118d9565b93909460405197611dc1896110ea565b8852306020890152604088015260608701528501523691611381565b60a0820152604051809681927f21457897000000000000000000000000000000000000000000000000000000008352600483016139b1565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611f0c575b506020015115611ee95791611ebc826001600160a01b0360019695611e7a611ee49686611691565b51611e858d8d611691565b52611eb3828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b50511692611691565b51907f000000000000000000000000000000000000000000000000000000000000000061420a565b611c90565b98506001929450611f02906001600160a01b0392611691565b5197511692611c90565b6020919450611f2c903d805f833e611f248183611152565b810190613969565b5094919050611e52565b91614223565b611f4592614341565b5f8281611d75565b50611f5a90929192611344565b91611f648b6142fd565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039485166004820152306024820152908416604482015292871660648401525f8380608481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f1578a611ddd8d611e15976001600160a01b03975f95612044575b50975092505091929350611d2a565b61204d90611106565b5f612035565b5061205d82611344565b6001600160a01b0316301415611d25565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916001600160a01b0384511692803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03949094166004850152306024850152604484018c90525f908490606490829084905af180156102f1578a611ddd8d611e15976001600160a01b03975f95612123575b50611d79565b61212c90611106565b5f61211d565b6001600160a01b0360208796949701511690898183145f146123d7576121cd925061220597915060016121735f96956001600160a01b0393848b5116614223565b509282895116956020890151151588146123ae5761219082611344565b945b6121a1608093848101906118d9565b959096604051996121b18b6110ea565b8a52166020890152604088015260608701528501523691611381565b60a0820152604051809581927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f1575f93612384575b5060200151156122c357816001600160a01b036020611ee493600196956122698c8c611691565b526122998383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b60208181015191516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101859052939a50909116945081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612359575b50600190611c90565b602090813d831161237d575b61236f8183611152565b810103126102fc575f612350565b503d612365565b60209193506123a4903d805f833e61239c8183611152565b81019061387c565b5093919050612242565b837f00000000000000000000000000000000000000000000000000000000000000001694612192565b6001600160a01b036124669561242e9394956123f860809b8c8101906118d9565b9390946040519761240889611136565b5f8952602089015216604087015260609a8b978888015286015260a08501523691611381565b60c0820152604051809381927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612525575b50506020015115611c9657816001600160a01b036020611ee493600196956124cb8c8c611691565b526124fb8383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b6020929450908161254192903d10611ce057611ccd8183611152565b91505092905f6124a3565b5f90611b2d565b5091955090935050600101611a61565b61258d827f00000000000000000000000000000000000000000000000000000000000000006141c0565b506125b986837f000000000000000000000000000000000000000000000000000000000000000061420a565b611aec565b50321515611ac7565b50506125f27f0000000000000000000000000000000000000000000000000000000000000000613a71565b916125fd83516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b0380612663838b611691565b51165f528560205261269160405f205c8261267e858d611691565b51165f528860205260405f205c90611a01565b61269b8387611691565b526126a6828a611691565b51165f52856020525f604081205d01612644565b50949391509150565b7fe08b8af0000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f198201918213600116611a0e57565b7f80000000000000000000000000000000000000000000000000000000000000008114611a0e575f190190565b907f000000000000000000000000000000000000000000000000000000000000000090815c7f0000000000000000000000000000000000000000000000000000000000000000612779815c6126eb565b907f0000000000000000000000000000000000000000000000000000000000000000915b5f81121561283a575050506127b1906126eb565b917f0000000000000000000000000000000000000000000000000000000000000000925b5f8112156127ea575050505061184c906136b1565b61283590825f5261282f60205f83828220015c91828252888152886040916128228a8d8587205c906001600160a01b03891690613eb0565b8484525281205d84613e0d565b506126fc565b6127d5565b61287290825f5261282f60205f8a8785848420015c938484528181526128228c6040948587205c906001600160a01b03891690613add565b61279d565b3d156128a1573d9061288882611365565b916128966040519384611152565b82523d5f602084013e565b606090565b359065ffffffffffff821682036102fc57565b905f917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03815c16156128f1575050565b909192505d600190565b90604082013542116126c357612917611a5760208401846136f4565b915f5b61292760208301836136f4565b90508110156135d15761294481611a93611a8b60208601866136f4565b60608101519061297e6001600160a01b038251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506020810151515f198101908111611a0e575b5f8112156129a45750505060010161291a565b6129b2816020840151611691565b516129bb613788565b9082156020830152602084015151805f19810111611a0e575f1901831480835261358f575b6020820151156135545760408401516001600160a01b03855116915b604081015115612c1d5783916001600160a01b036060926020612aa0970151151580612c14575b612bed575b5116906001600160a01b0385168203612be6576001915b60405192612a4c8461111a565b60018452612a59816137be565b6020840152604083015288838301526080820152604051809581927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f95612bbf575b506020015115612bb057612ba69284612b02612bab979694612b7594611691565b52612b366001600160a01b0382167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506001600160a01b03612b4d8460408a01516137b1565b91167f000000000000000000000000000000000000000000000000000000000000000061420a565b6001600160a01b038551167f000000000000000000000000000000000000000000000000000000000000000061420a565b6126fc565b612991565b505050612bab919350926126fc565b6020919550612bdc9060603d606011611ce057611ccd8183611152565b5095919050612ae1565b5f91612a3f565b612c0f612bf98d611344565b8d8b611ae6886040888451169301519301611358565b612a28565b50321515612a23565b906001600160a01b03825116806001600160a01b038516145f14613137575060208401516130495750604051927f967870920000000000000000000000000000000000000000000000000000000084526001600160a01b03831660048501526020846024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9384156102f1575f94613015575b5083916001600160a01b038151166001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015230602482015260448101959095525f8580606481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f157612dec955f92613006575b505b611ddd6001600160a01b03612da88b828551168360208701511690614223565b50925116918c6002612dbf608092838101906118d9565b92909360405196612dcf886110ea565b875230602088015289604088015260608701528501523691611381565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612fe3575b506020015115612ecf57908291612bab9493612e45898d611691565b52612e7a836001600160a01b0384167f000000000000000000000000000000000000000000000000000000000000000061420a565b80831080612eb4575b612e90575b5050506126fc565b612ea6612eac93612ea08b611344565b926137b1565b91614356565b5f8080612e88565b50306001600160a01b03612ec78b611344565b161415612e83565b9450908094808210612ee8575b505050612bab906126fc565b91612ef8602092612f77946137b1565b90612f2d826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683614356565b60405193849283927f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612fb8575b8080612edc565b602090813d8311612fdc575b612fce8183611152565b810103126102fc575f612fb1565b503d612fc4565b6020919450612ffb903d805f833e611f248183611152565b509094919050612e29565b61300f90611106565b5f612d86565b9093506020813d602011613041575b8161303160209383611152565b810103126102fc5751925f612cbc565b3d9150613024565b909261305489611344565b6001600160a01b033091160361306f575b5f612dec94612d88565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936130a38a611344565b6130ac846142fd565b90863b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152306024820152918116604483015285166064820152945f908690608490829084905af19081156102f157612dec955f92613128575b50945050613065565b61313190611106565b5f61311f565b6001600160a01b036020849695940151168a8282145f1461340b5750505061320c61316e5f92846001600160a01b03885116614223565b92906131d48c6001600160a01b03808a5116938951151586146133df576131a361319784611344565b935b60808101906118d9565b929093604051966131b3886110ea565b875216602086015260408501528c6060850152600260808501523691611381565b60a0820152604051809381927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f1575f916133c4575b5060208401518c908a90156133aa5783836001600160a01b03936132836132899461327c8f9c9b9a98996132b29a611691565b5192611691565b52611691565b5191167f000000000000000000000000000000000000000000000000000000000000000061420a565b51156132f457612bab92916001600160a01b036020612ba6930151167f0000000000000000000000000000000000000000000000000000000000000000614341565b516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024810191909152602081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f15761337f575b50612bab906126fc565b602090813d83116133a3575b6133958183611152565b810103126102fc575f613375565b503d61338b565b50509091506133bb92939650611691565b519384916132b2565b6133d891503d805f833e61239c8183611152565b9050613249565b6131a3827f00000000000000000000000000000000000000000000000000000000000000001693613199565b61349e965090613466916060948b61342b608099989993848101906118d9565b9390946040519761343b89611136565b6001895260208901526001600160a01b038b1660408901528888015286015260a08501523691611381565b60c0820152604051809581927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f9561352d575b506020015115612bb057612ba69284613505612bab9796946001600160a01b0394611691565b52167f000000000000000000000000000000000000000000000000000000000000000061420a565b602091955061354a9060603d606011611ce057611ccd8183611152565b50959190506134df565b6fffffffffffffffffffffffffffffffff6001600160a01b0360206135858188015161357f886126eb565b90611691565b51015116916129fc565b6135cc856001600160a01b0360208401611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b6129e0565b50506135fc7f0000000000000000000000000000000000000000000000000000000000000000613a71565b9161360783516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b038061366d838b611691565b51165f528560205261368860405f205c8261267e858d611691565b6136928387611691565b5261369d828a611691565b51165f52856020525f604081205d0161364e565b4780156136f0577f00000000000000000000000000000000000000000000000000000000000000005c6136f0576001600160a01b0361184c92166140e0565b5050565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc57602001918160051b360383136102fc57565b91908110156116a55760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81813603018212156102fc570190565b604051906040820182811067ffffffffffffffff8211176110bd576040525f6020838281520152565b91908203918211611a0e57565b600211156137c857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b908160609103126102fc578051916040602083015192015190565b61010060c0610f7c93602084528051613828816137be565b602085015260208101516001600160a01b0380911660408601528060408301511660608601526060820151166080850152608081015160a085015260a08101518285015201519160e0808201520190610ffb565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc57846138a8918301611573565b9360208201519360408301519081116102fc57610f7c9201611507565b9081518082526020808093019301915f5b8281106138e4575050505090565b8351855293810193928101926001016138d6565b602081526001600160a01b038083511660208301526020830151166040820152613931604083015160c0606084015260e08301906138c5565b9060608301516080820152608083015160058110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b916060838303126102fc5782519260208101519267ffffffffffffffff938481116102fc578161399a918401611573565b9360408301519081116102fc57610f7c9201611507565b602081526001600160a01b038083511660208301526020830151166040820152604082015160608201526139f4606083015160c0608084015260e08301906138c5565b90608083015160048110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b91909160808060a08301948051613a38816137be565b84526020810151613a48816137be565b60208501526001600160a01b036040820151166040850152606081015160608501520151910152565b90815c613a7d81611175565b613a8a6040519182611152565b818152613a9682611175565b601f196020910136602084013781945f5b848110613ab5575050505050565b600190825f5280845f20015c6001600160a01b03613ad38388611691565b9116905201613aa7565b919280613dd8575b15613c51575050804710613c29576001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001691823b156102fc57604051907fd0e30db00000000000000000000000000000000000000000000000000000000082525f915f8160048185895af180156102f157613c12575b506044602092937f00000000000000000000000000000000000000000000000000000000000000001694613b98838783614356565b8460405196879485937f15afd409000000000000000000000000000000000000000000000000000000008552600485015260248401525af1908115613c065750613bdf5750565b602090813d8311613bff575b613bf58183611152565b810103126102fc57565b503d613beb565b604051903d90823e3d90fd5b60209250613c1f90611106565b60445f9250613b63565b7fa01a9df6000000000000000000000000000000000000000000000000000000005f5260045ffd5b90915f9080613c61575b50505050565b6001600160a01b0393847f00000000000000000000000000000000000000000000000000000000000000001694807f00000000000000000000000000000000000000000000000000000000000000001691613cbb846142fd565b96803b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152848316602482015297821660448901529186161660648701525f908690608490829084905af19485156102f157613d8095613dc4575b5082936020936040518097819582947f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1908115613c065750613d99575b808080613c5b565b602090813d8311613dbd575b613daf8183611152565b810103126102fc575f613d91565b503d613da5565b60209350613dd190611106565b5f92613d2f565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690821614613ae5565b6001810191805f5260209183835260405f205c8015155f14613ea7575f1990818101835c8380820191828403613e6a575b5050505050815c81810192818411611a0e575f93815d835284832001015d5f52525f604081205d600190565b613e77613e87938861443a565b865f52885f2001015c918561443a565b835f52808383885f2001015d5f5285855260405f205d5f80808381613e3e565b50505050505f90565b5f949383156140d857806140a3575b15614007576001600160a01b0391827f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03929092166004830152306024830152604482018590525f908290606490829084905af180156102f157613ff4575b5084827f000000000000000000000000000000000000000000000000000000000000000016803b15613ff05781906024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015613fe557613fcd575b5061184c939450166140e0565b613fd78691611106565b613fe15784613fc0565b8480fd5b6040513d88823e3d90fd5b5080fd5b613fff919550611106565b5f935f613f53565b929350906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015293909216602484015260448301525f908290606490829084905af180156102f15761409a5750565b61184c90611106565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690831614613ebf565b505050509050565b814710614130575f8080936001600160a01b038294165af1614100612877565b501561410857565b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcd786059000000000000000000000000000000000000000000000000000000005f523060045260245ffd5b90614171575080511561410857805190602001fd5b815115806141b7575b614182575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561417a565b6001810190825f528160205260405f205c155f1461420357805c815f52838160205f20015d60018101809111611a0e57815d5c915f5260205260405f205d600190565b5050505f90565b905f5260205261421f60405f2091825c611a01565b905d565b916044929391936001600160a01b03604094859282808551998a9586947fc9c1661b0000000000000000000000000000000000000000000000000000000086521660048501521660248301527f0000000000000000000000000000000000000000000000000000000000000000165afa9384156142f3575f935f956142bc575b50506142b96142b285946119d0565b9485611691565b52565b809295508194503d83116142ec575b6142d58183611152565b810103126102fc5760208251920151925f806142a3565b503d6142cb565b83513d5f823e3d90fd5b6001600160a01b0390818111614311571690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f5260a060045260245260445ffd5b905f5260205261421f60405f2091825c6137b1565b6040519260208401907fa9059cbb0000000000000000000000000000000000000000000000000000000082526001600160a01b038094166024860152604485015260448452608084019084821067ffffffffffffffff8311176110bd576143d5935f9384936040521694519082865af16143ce612877565b908361415c565b8051908115159182614416575b50506143eb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126102fc57602001518015908115036102fc575f806143e2565b5c111561444357565b7f0f4ae0e4000000000000000000000000000000000000000000000000000000005f5260045ffdfea2646970667358221220229a5cf89aa7c2d0a4b4d5db20bba6c2b3a74b080303fc6ec00ba582a5dcf75164736f6c634300081a0033", - "deployedBytecode": "0x60806040526004361015610072575b3615610018575f80fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361004a57005b7f0540ddf6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f3560e01c806308a465f614610e9d57806319c6989f1461084e578063286f580d146107b75780632950286e146106cc57806354fd4d501461058f5780635a3c3987146105665780635e01eb5a146105215780638a12a08c146104c65780638eb1b65e146103bf578063945ed33f14610344578063ac9650d8146103005763e3b5dff40361000e57346102fc576060806003193601126102fc5767ffffffffffffffff6004358181116102fc5761012d9036906004016112c4565b6101356111a1565b6044359283116102fc57610150610158933690600401610fcd565b9390916128b9565b905f5b835181101561017c57805f8761017360019488611691565b5101520161015b565b506101f06101fe610239946101b65f94886040519361019a8561111a565b30855260208501525f1960408501528660608501523691611381565b60808201526040519283917f8a12a08c0000000000000000000000000000000000000000000000000000000060208401526024830161143e565b03601f198101835282611152565b604051809481927fedfa3568000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39261028e915f916102cf575b50602080825183010191016115d4565b909391926102a7575b60405193849384610f2f565b0390f35b5f7f00000000000000000000000000000000000000000000000000000000000000005d610297565b6102eb91503d805f833e6102e38183611152565b81019061154d565b8461027e565b6040513d5f823e3d90fd5b5f80fd5b60206003193601126102fc5760043567ffffffffffffffff81116102fc576103386103326102a3923690600401610f9c565b9061179b565b60405191829182611020565b346102fc5761035236610eca565b61035a611945565b610362611972565b6103906102a3610371836128fb565b9193909461038a606061038383611344565b9201611358565b90612729565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d60405193849384610f2f565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576103ec9036906004016112c4565b906103f56111b7565b906064359081116102fc576101f061048b6102399461045161041c5f953690600401610fcd565b610425336128b9565b97604051946104338661111a565b33865260208601526024356040860152151560608501523691611381565b60808201526040519283917f945ed33f000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b604051809481927f48c89491000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b346102fc576102a36104ef6104da36610eca565b6104e2611945565b6104ea611972565b611a3b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009492945d60405193849384610f2f565b346102fc575f6003193601126102fc5760207f00000000000000000000000000000000000000000000000000000000000000005c6001600160a01b0360405191168152f35b346102fc576102a36104ef61057a36610eca565b610582611945565b61058a611972565b6128fb565b346102fc575f6003193601126102fc576040515f80549060018260011c91600184169182156106c2575b60209485851084146106955785879486865291825f146106575750506001146105fe575b506105ea92500383611152565b6102a3604051928284938452830190610ffb565b5f808052859250907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061063f5750506105ea9350820101856105dd565b80548389018501528794508693909201918101610628565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858201526105ea95151560051b85010192508791506105dd9050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b92607f16926105b9565b346102fc5760606003193601126102fc5767ffffffffffffffff6004358181116102fc576106fe9036906004016112c4565b906107076111a1565b6044359182116102fc5761072261072a923690600401610fcd565b9290916128b9565b905f5b845181101561075f57806fffffffffffffffffffffffffffffffff604061075660019489611691565b5101520161072d565b506101f06101fe8561077d5f94610239976040519361019a8561111a565b60808201526040519283917f5a3c3987000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576107e49036906004016112c4565b906107ed6111b7565b906064359081116102fc576101f061048b6102399461081461041c5f953690600401610fcd565b60808201526040519283917f08a465f60000000000000000000000000000000000000000000000000000000060208401526024830161143e565b60a06003193601126102fc5767ffffffffffffffff600435116102fc573660236004350112156102fc5767ffffffffffffffff60043560040135116102fc5736602460c060043560040135026004350101116102fc5760243567ffffffffffffffff81116102fc576108c4903690600401610f9c565b67ffffffffffffffff604435116102fc576060600319604435360301126102fc5760643567ffffffffffffffff81116102fc57610905903690600401610fcd565b60843567ffffffffffffffff81116102fc57610925903690600401610f9c565b949093610930611945565b806004356004013503610e75575f5b600435600401358110610bd25750505060443560040135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd6044353603018212156102fc57816044350160048101359067ffffffffffffffff82116102fc5760248260071b36039101136102fc576109e3575b6102a361033886865f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d61179b565b6001600160a01b039492947f0000000000000000000000000000000000000000000000000000000000000000163b156102fc57604051947f2a2d80d10000000000000000000000000000000000000000000000000000000086523360048701526060602487015260c486019260443501602481019367ffffffffffffffff6004830135116102fc57600482013560071b360385136102fc5760606064890152600482013590529192869260e484019291905f905b60048101358210610b5457505050602091601f19601f865f9787956001600160a01b03610ac860246044350161118d565b16608488015260448035013560a48801526003198787030160448801528186528786013787868286010152011601030181836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39361033893610b45575b8294508193506109b3565b610b4e90611106565b84610b3a565b9195945091926001600160a01b03610b6b8761118d565b168152602080870135916001600160a01b0383168093036102fc57600492600192820152610b9b604089016128a6565b65ffffffffffff8091166040830152610bb660608a016128a6565b1660608201526080809101970193019050889495939291610a97565b610be7610be082848661192a565b3691611381565b604051610bf3816110a1565b5f81526020915f838301525f60408301528281015190606060408201519101515f1a91835283830152604082015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc81850260043501360301126102fc5760405190610c60826110ea565b610c73602460c08602600435010161118d565b808352610c89604460c08702600435010161118d565b908185850152610ca2606460c08802600435010161118d565b60408581019190915260043560c08802016084810135606087015260a4810135608087015260c4013560a086015283015183519386015160ff91909116926001600160a01b0383163b156102fc575f6001600160a01b03809460e4948b98849860c460c06040519c8d9b8c9a7fd505accf000000000000000000000000000000000000000000000000000000008c521660048b01523060248b0152608482820260043501013560448b0152026004350101356064880152608487015260a486015260c4850152165af19081610e66575b50610e5c57610d7f612877565b906001600160a01b0381511690836001600160a01b0381830151166044604051809581937fdd62ed3e00000000000000000000000000000000000000000000000000000000835260048301523060248301525afa9182156102f1575f92610e2c575b506060015103610df75750506001905b0161093f565b805115610e045780519101fd5b7fa7285689000000000000000000000000000000000000000000000000000000005f5260045ffd5b9091508381813d8311610e55575b610e448183611152565b810103126102fc5751906060610de1565b503d610e3a565b5050600190610df1565b610e6f90611106565b8a610d72565b7faaad13f7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102fc57610eab36610eca565b610eb3611945565b610ebb611972565b6103906102a361037183611a3b565b600319906020828201126102fc576004359167ffffffffffffffff83116102fc578260a0920301126102fc5760040190565b9081518082526020808093019301915f5b828110610f1b575050505090565b835185529381019392810192600101610f0d565b939290610f4490606086526060860190610efc565b936020948181036020830152602080855192838152019401905f5b818110610f7f57505050610f7c9394506040818403910152610efc565b90565b82516001600160a01b031686529487019491870191600101610f5f565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc576020808501948460051b0101116102fc57565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc57602083818601950101116102fc57565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110555750505050505090565b9091929394958480611091837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51610ffb565b9801930193019194939290611045565b6060810190811067ffffffffffffffff8211176110bd57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd57604052565b60a0810190811067ffffffffffffffff8211176110bd57604052565b60e0810190811067ffffffffffffffff8211176110bd57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd5760051b60200190565b35906001600160a01b03821682036102fc57565b602435906001600160a01b03821682036102fc57565b6044359081151582036102fc57565b9190916080818403126102fc57604090815191608083019467ffffffffffffffff95848110878211176110bd57825283956112008461118d565b8552602090818501359081116102fc57840182601f820112156102fc5780359061122982611175565b9361123686519586611152565b82855283850190846060809502840101928184116102fc578501915b8383106112745750505050508401528181013590830152606090810135910152565b84838303126102fc57875190611289826110a1565b6112928461118d565b825261129f87850161118d565b87830152888401359081151582036102fc578288928b89950152815201920191611252565b81601f820112156102fc578035916020916112de84611175565b936112ec6040519586611152565b808552838086019160051b830101928084116102fc57848301915b8483106113175750505050505090565b823567ffffffffffffffff81116102fc578691611339848480948901016111c6565b815201920191611307565b356001600160a01b03811681036102fc5790565b3580151581036102fc5790565b67ffffffffffffffff81116110bd57601f01601f191660200190565b92919261138d82611365565b9161139b6040519384611152565b8294818452818301116102fc578281602093845f960137010152565b9060808101916001600160a01b03808251168352602093848301519460808186015285518092528060a086019601925f905b83821061140b5750505050506060816040829301516040850152015191015290565b845180518216895280840151821689850152604090810151151590890152606090970196938201936001909101906113e9565b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106114bd5750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b909192939583806114f8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611481565b81601f820112156102fc5780519061151e82611365565b9261152c6040519485611152565b828452602083830101116102fc57815f9260208093018386015e8301015290565b906020828203126102fc57815167ffffffffffffffff81116102fc57610f7c9201611507565b9080601f830112156102fc5781519060209161158e81611175565b9361159c6040519586611152565b81855260208086019260051b8201019283116102fc57602001905b8282106115c5575050505090565b815181529083019083016115b7565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc5784611600918301611573565b936020808301518581116102fc5783019082601f830112156102fc5781519161162883611175565b926116366040519485611152565b808452828085019160051b830101918583116102fc578301905b82821061167257505050509360408301519081116102fc57610f7c9201611573565b81516001600160a01b03811681036102fc578152908301908301611650565b80518210156116a55760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106117515750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b9091929395838061178c837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611715565b91906117a6336128b9565b907f000000000000000000000000000000000000000000000000000000000000000093845c6118b1576001906001865d6117df83611175565b926117ed6040519485611152565b808452601f196117fc82611175565b015f5b8181106118a05750505f5b8181106118575750505050905f61184c92945d7f0000000000000000000000000000000000000000000000000000000000000000805c9161184e575b506136b1565b565b5f905d5f611846565b806118845f8061186c610be08996888a61192a565b602081519101305af461187d612877565b903061415c565b61188e8288611691565b526118998187611691565b500161180a565b8060606020809389010152016117ff565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc576020019181360383136102fc57565b908210156116a5576119419160051b8101906118d9565b9091565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c6118b1576001905d565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633036119a457565b7f089676d5000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906119da82611175565b6119e76040519182611152565b828152601f196119f78294611175565b0190602036910137565b91908201809211611a0e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b604081013542116126c35790611a5e611a5760208401846136f4565b90506119d0565b915f5b611a6e60208301836136f4565b90508110156125c757611a9881611a93611a8b60208601866136f4565b369391613748565b6111c6565b936040850151936001600160a01b038651169060208701518051156116a55760200151604001511515806125be575b1561256357611aec611ad886611344565b8784611ae660608a01611358565b92613add565b5f5b60208801515181101561255357611b03613788565b6020890151515f198101908111611a0e578214806020830152821582525f1461254c576060890151905b611b3b8360208c0151611691565b51604081015190919015611cee57611bd36001600160a01b03835116936001600160a01b03881685145f14611ce7576001945b60405195611b7b8761111a565b5f8752611b87816137be565b6020870152604086015260609485918d838301526080820152604051809381927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611cb0575b50506020015115611c9657816001600160a01b036020611c909360019695611c388c8c611691565b5201611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b5051167f000000000000000000000000000000000000000000000000000000000000000061420a565b01611aee565b602001519097506001600160a01b03169250600190611c90565b60209294509081611cd592903d10611ce0575b611ccd8183611152565b8101906137f5565b91505092905f611c10565b503d611cc3565b5f94611b6e565b888a6001600160a01b038495945116806001600160a01b038a16145f14612132575050815115905061206e57888a80151580612053575b611f4d575b6001600160a01b03939291611ddd82611e15978b5f95897f0000000000000000000000000000000000000000000000000000000000000000921680885282602052604088205c611f3c575b5050505b6001611d9c8983511660208401998b8b51169080158a14611f3657508391614223565b999092511694611db1608091828101906118d9565b93909460405197611dc1896110ea565b8852306020890152604088015260608701528501523691611381565b60a0820152604051809681927f21457897000000000000000000000000000000000000000000000000000000008352600483016139b1565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611f0c575b506020015115611ee95791611ebc826001600160a01b0360019695611e7a611ee49686611691565b51611e858d8d611691565b52611eb3828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b50511692611691565b51907f000000000000000000000000000000000000000000000000000000000000000061420a565b611c90565b98506001929450611f02906001600160a01b0392611691565b5197511692611c90565b6020919450611f2c903d805f833e611f248183611152565b810190613969565b5094919050611e52565b91614223565b611f4592614341565b5f8281611d75565b50611f5a90929192611344565b91611f648b6142fd565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039485166004820152306024820152908416604482015292871660648401525f8380608481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f1578a611ddd8d611e15976001600160a01b03975f95612044575b50975092505091929350611d2a565b61204d90611106565b5f612035565b5061205d82611344565b6001600160a01b0316301415611d25565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916001600160a01b0384511692803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03949094166004850152306024850152604484018c90525f908490606490829084905af180156102f1578a611ddd8d611e15976001600160a01b03975f95612123575b50611d79565b61212c90611106565b5f61211d565b6001600160a01b0360208796949701511690898183145f146123d7576121cd925061220597915060016121735f96956001600160a01b0393848b5116614223565b509282895116956020890151151588146123ae5761219082611344565b945b6121a1608093848101906118d9565b959096604051996121b18b6110ea565b8a52166020890152604088015260608701528501523691611381565b60a0820152604051809581927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f1575f93612384575b5060200151156122c357816001600160a01b036020611ee493600196956122698c8c611691565b526122998383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b60208181015191516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101859052939a50909116945081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612359575b50600190611c90565b602090813d831161237d575b61236f8183611152565b810103126102fc575f612350565b503d612365565b60209193506123a4903d805f833e61239c8183611152565b81019061387c565b5093919050612242565b837f00000000000000000000000000000000000000000000000000000000000000001694612192565b6001600160a01b036124669561242e9394956123f860809b8c8101906118d9565b9390946040519761240889611136565b5f8952602089015216604087015260609a8b978888015286015260a08501523691611381565b60c0820152604051809381927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612525575b50506020015115611c9657816001600160a01b036020611ee493600196956124cb8c8c611691565b526124fb8383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b6020929450908161254192903d10611ce057611ccd8183611152565b91505092905f6124a3565b5f90611b2d565b5091955090935050600101611a61565b61258d827f00000000000000000000000000000000000000000000000000000000000000006141c0565b506125b986837f000000000000000000000000000000000000000000000000000000000000000061420a565b611aec565b50321515611ac7565b50506125f27f0000000000000000000000000000000000000000000000000000000000000000613a71565b916125fd83516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b0380612663838b611691565b51165f528560205261269160405f205c8261267e858d611691565b51165f528860205260405f205c90611a01565b61269b8387611691565b526126a6828a611691565b51165f52856020525f604081205d01612644565b50949391509150565b7fe08b8af0000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f198201918213600116611a0e57565b7f80000000000000000000000000000000000000000000000000000000000000008114611a0e575f190190565b907f000000000000000000000000000000000000000000000000000000000000000090815c7f0000000000000000000000000000000000000000000000000000000000000000612779815c6126eb565b907f0000000000000000000000000000000000000000000000000000000000000000915b5f81121561283a575050506127b1906126eb565b917f0000000000000000000000000000000000000000000000000000000000000000925b5f8112156127ea575050505061184c906136b1565b61283590825f5261282f60205f83828220015c91828252888152886040916128228a8d8587205c906001600160a01b03891690613eb0565b8484525281205d84613e0d565b506126fc565b6127d5565b61287290825f5261282f60205f8a8785848420015c938484528181526128228c6040948587205c906001600160a01b03891690613add565b61279d565b3d156128a1573d9061288882611365565b916128966040519384611152565b82523d5f602084013e565b606090565b359065ffffffffffff821682036102fc57565b905f917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03815c16156128f1575050565b909192505d600190565b90604082013542116126c357612917611a5760208401846136f4565b915f5b61292760208301836136f4565b90508110156135d15761294481611a93611a8b60208601866136f4565b60608101519061297e6001600160a01b038251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506020810151515f198101908111611a0e575b5f8112156129a45750505060010161291a565b6129b2816020840151611691565b516129bb613788565b9082156020830152602084015151805f19810111611a0e575f1901831480835261358f575b6020820151156135545760408401516001600160a01b03855116915b604081015115612c1d5783916001600160a01b036060926020612aa0970151151580612c14575b612bed575b5116906001600160a01b0385168203612be6576001915b60405192612a4c8461111a565b60018452612a59816137be565b6020840152604083015288838301526080820152604051809581927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f95612bbf575b506020015115612bb057612ba69284612b02612bab979694612b7594611691565b52612b366001600160a01b0382167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506001600160a01b03612b4d8460408a01516137b1565b91167f000000000000000000000000000000000000000000000000000000000000000061420a565b6001600160a01b038551167f000000000000000000000000000000000000000000000000000000000000000061420a565b6126fc565b612991565b505050612bab919350926126fc565b6020919550612bdc9060603d606011611ce057611ccd8183611152565b5095919050612ae1565b5f91612a3f565b612c0f612bf98d611344565b8d8b611ae6886040888451169301519301611358565b612a28565b50321515612a23565b906001600160a01b03825116806001600160a01b038516145f14613137575060208401516130495750604051927f967870920000000000000000000000000000000000000000000000000000000084526001600160a01b03831660048501526020846024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9384156102f1575f94613015575b5083916001600160a01b038151166001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015230602482015260448101959095525f8580606481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f157612dec955f92613006575b505b611ddd6001600160a01b03612da88b828551168360208701511690614223565b50925116918c6002612dbf608092838101906118d9565b92909360405196612dcf886110ea565b875230602088015289604088015260608701528501523691611381565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612fe3575b506020015115612ecf57908291612bab9493612e45898d611691565b52612e7a836001600160a01b0384167f000000000000000000000000000000000000000000000000000000000000000061420a565b80831080612eb4575b612e90575b5050506126fc565b612ea6612eac93612ea08b611344565b926137b1565b91614356565b5f8080612e88565b50306001600160a01b03612ec78b611344565b161415612e83565b9450908094808210612ee8575b505050612bab906126fc565b91612ef8602092612f77946137b1565b90612f2d826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683614356565b60405193849283927f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612fb8575b8080612edc565b602090813d8311612fdc575b612fce8183611152565b810103126102fc575f612fb1565b503d612fc4565b6020919450612ffb903d805f833e611f248183611152565b509094919050612e29565b61300f90611106565b5f612d86565b9093506020813d602011613041575b8161303160209383611152565b810103126102fc5751925f612cbc565b3d9150613024565b909261305489611344565b6001600160a01b033091160361306f575b5f612dec94612d88565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936130a38a611344565b6130ac846142fd565b90863b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152306024820152918116604483015285166064820152945f908690608490829084905af19081156102f157612dec955f92613128575b50945050613065565b61313190611106565b5f61311f565b6001600160a01b036020849695940151168a8282145f1461340b5750505061320c61316e5f92846001600160a01b03885116614223565b92906131d48c6001600160a01b03808a5116938951151586146133df576131a361319784611344565b935b60808101906118d9565b929093604051966131b3886110ea565b875216602086015260408501528c6060850152600260808501523691611381565b60a0820152604051809381927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f1575f916133c4575b5060208401518c908a90156133aa5783836001600160a01b03936132836132899461327c8f9c9b9a98996132b29a611691565b5192611691565b52611691565b5191167f000000000000000000000000000000000000000000000000000000000000000061420a565b51156132f457612bab92916001600160a01b036020612ba6930151167f0000000000000000000000000000000000000000000000000000000000000000614341565b516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024810191909152602081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f15761337f575b50612bab906126fc565b602090813d83116133a3575b6133958183611152565b810103126102fc575f613375565b503d61338b565b50509091506133bb92939650611691565b519384916132b2565b6133d891503d805f833e61239c8183611152565b9050613249565b6131a3827f00000000000000000000000000000000000000000000000000000000000000001693613199565b61349e965090613466916060948b61342b608099989993848101906118d9565b9390946040519761343b89611136565b6001895260208901526001600160a01b038b1660408901528888015286015260a08501523691611381565b60c0820152604051809581927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f9561352d575b506020015115612bb057612ba69284613505612bab9796946001600160a01b0394611691565b52167f000000000000000000000000000000000000000000000000000000000000000061420a565b602091955061354a9060603d606011611ce057611ccd8183611152565b50959190506134df565b6fffffffffffffffffffffffffffffffff6001600160a01b0360206135858188015161357f886126eb565b90611691565b51015116916129fc565b6135cc856001600160a01b0360208401611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b6129e0565b50506135fc7f0000000000000000000000000000000000000000000000000000000000000000613a71565b9161360783516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b038061366d838b611691565b51165f528560205261368860405f205c8261267e858d611691565b6136928387611691565b5261369d828a611691565b51165f52856020525f604081205d0161364e565b4780156136f0577f00000000000000000000000000000000000000000000000000000000000000005c6136f0576001600160a01b0361184c92166140e0565b5050565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc57602001918160051b360383136102fc57565b91908110156116a55760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81813603018212156102fc570190565b604051906040820182811067ffffffffffffffff8211176110bd576040525f6020838281520152565b91908203918211611a0e57565b600211156137c857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b908160609103126102fc578051916040602083015192015190565b61010060c0610f7c93602084528051613828816137be565b602085015260208101516001600160a01b0380911660408601528060408301511660608601526060820151166080850152608081015160a085015260a08101518285015201519160e0808201520190610ffb565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc57846138a8918301611573565b9360208201519360408301519081116102fc57610f7c9201611507565b9081518082526020808093019301915f5b8281106138e4575050505090565b8351855293810193928101926001016138d6565b602081526001600160a01b038083511660208301526020830151166040820152613931604083015160c0606084015260e08301906138c5565b9060608301516080820152608083015160058110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b916060838303126102fc5782519260208101519267ffffffffffffffff938481116102fc578161399a918401611573565b9360408301519081116102fc57610f7c9201611507565b602081526001600160a01b038083511660208301526020830151166040820152604082015160608201526139f4606083015160c0608084015260e08301906138c5565b90608083015160048110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b91909160808060a08301948051613a38816137be565b84526020810151613a48816137be565b60208501526001600160a01b036040820151166040850152606081015160608501520151910152565b90815c613a7d81611175565b613a8a6040519182611152565b818152613a9682611175565b601f196020910136602084013781945f5b848110613ab5575050505050565b600190825f5280845f20015c6001600160a01b03613ad38388611691565b9116905201613aa7565b919280613dd8575b15613c51575050804710613c29576001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001691823b156102fc57604051907fd0e30db00000000000000000000000000000000000000000000000000000000082525f915f8160048185895af180156102f157613c12575b506044602092937f00000000000000000000000000000000000000000000000000000000000000001694613b98838783614356565b8460405196879485937f15afd409000000000000000000000000000000000000000000000000000000008552600485015260248401525af1908115613c065750613bdf5750565b602090813d8311613bff575b613bf58183611152565b810103126102fc57565b503d613beb565b604051903d90823e3d90fd5b60209250613c1f90611106565b60445f9250613b63565b7fa01a9df6000000000000000000000000000000000000000000000000000000005f5260045ffd5b90915f9080613c61575b50505050565b6001600160a01b0393847f00000000000000000000000000000000000000000000000000000000000000001694807f00000000000000000000000000000000000000000000000000000000000000001691613cbb846142fd565b96803b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152848316602482015297821660448901529186161660648701525f908690608490829084905af19485156102f157613d8095613dc4575b5082936020936040518097819582947f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1908115613c065750613d99575b808080613c5b565b602090813d8311613dbd575b613daf8183611152565b810103126102fc575f613d91565b503d613da5565b60209350613dd190611106565b5f92613d2f565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690821614613ae5565b6001810191805f5260209183835260405f205c8015155f14613ea7575f1990818101835c8380820191828403613e6a575b5050505050815c81810192818411611a0e575f93815d835284832001015d5f52525f604081205d600190565b613e77613e87938861443a565b865f52885f2001015c918561443a565b835f52808383885f2001015d5f5285855260405f205d5f80808381613e3e565b50505050505f90565b5f949383156140d857806140a3575b15614007576001600160a01b0391827f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03929092166004830152306024830152604482018590525f908290606490829084905af180156102f157613ff4575b5084827f000000000000000000000000000000000000000000000000000000000000000016803b15613ff05781906024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015613fe557613fcd575b5061184c939450166140e0565b613fd78691611106565b613fe15784613fc0565b8480fd5b6040513d88823e3d90fd5b5080fd5b613fff919550611106565b5f935f613f53565b929350906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015293909216602484015260448301525f908290606490829084905af180156102f15761409a5750565b61184c90611106565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690831614613ebf565b505050509050565b814710614130575f8080936001600160a01b038294165af1614100612877565b501561410857565b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcd786059000000000000000000000000000000000000000000000000000000005f523060045260245ffd5b90614171575080511561410857805190602001fd5b815115806141b7575b614182575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561417a565b6001810190825f528160205260405f205c155f1461420357805c815f52838160205f20015d60018101809111611a0e57815d5c915f5260205260405f205d600190565b5050505f90565b905f5260205261421f60405f2091825c611a01565b905d565b916044929391936001600160a01b03604094859282808551998a9586947fc9c1661b0000000000000000000000000000000000000000000000000000000086521660048501521660248301527f0000000000000000000000000000000000000000000000000000000000000000165afa9384156142f3575f935f956142bc575b50506142b96142b285946119d0565b9485611691565b52565b809295508194503d83116142ec575b6142d58183611152565b810103126102fc5760208251920151925f806142a3565b503d6142cb565b83513d5f823e3d90fd5b6001600160a01b0390818111614311571690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f5260a060045260245260445ffd5b905f5260205261421f60405f2091825c6137b1565b6040519260208401907fa9059cbb0000000000000000000000000000000000000000000000000000000082526001600160a01b038094166024860152604485015260448452608084019084821067ffffffffffffffff8311176110bd576143d5935f9384936040521694519082865af16143ce612877565b908361415c565b8051908115159182614416575b50506143eb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126102fc57602001518015908115036102fc575f806143e2565b5c111561444357565b7f0f4ae0e4000000000000000000000000000000000000000000000000000000005f5260045ffdfea2646970667358221220229a5cf89aa7c2d0a4b4d5db20bba6c2b3a74b080303fc6ec00ba582a5dcf75164736f6c634300081a0033", - "linkReferences": {}, - "deployedLinkReferences": {} + ] } diff --git a/contracts/artifacts/Balances.json b/contracts/artifacts/Balances.json new file mode 100644 index 0000000000..08238348aa --- /dev/null +++ b/contracts/artifacts/Balances.json @@ -0,0 +1,110 @@ +{ + "abi": [ + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISettlement", + "name": "settlement", + "type": "address" + }, + { + "internalType": "contract IVaultRelayer", + "name": "vaultRelayer", + "type": "address" + }, + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + } + ], + "internalType": "struct Balances.Contracts", + "name": "contracts", + "type": "tuple" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "source", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Interaction[]", + "name": "interactions", + "type": "tuple[]" + } + ], + "name": "balance", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "effectiveBalance", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "canTransfer", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "transferRevertReason", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b50610ef28061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063f88cf6db1461002d575b5f5ffd5b61004061003b366004610abe565b61005a565b604051610051959493929190610b83565b60405180910390f35b5f5f5f5f606061006b8c88886107b0565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc988036101c6576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa1580156100fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101209190610c0a565b60208d01516040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e8116600483015291821660248201529196508b169063dd62ed3e906044015b602060405180830381865afa15801561019b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101bf9190610c0a565b9350610604565b7fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328803610389576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa158015610257573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027b9190610c0a565b6040808e015160208f015191517ffec90d7200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8f811660048301529283166024820152929750169063fec90d7290604401602060405180830381865afa1580156102f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061031d9190610c21565b610327575f6101bf565b60408c81015190517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301529182166024820152908b169063dd62ed3e90604401610180565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce880361059d576040805160018082528183019092525f91602080830190803683370190505090508a815f815181106103e4576103e4610c47565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040808f015190517f0f5a6efa000000000000000000000000000000000000000000000000000000008152911690630f5a6efa9061044b908f908590600401610c74565b5f60405180830381865afa158015610465573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104aa9190810190610ced565b5f815181106104bb576104bb610c47565b602002602001015195508c6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728d8f602001516040518363ffffffff1660e01b815260040161052a92919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b602060405180830381865afa158015610545573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105699190610c21565b610573575f610595565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b945050610604565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c696420746f6b656e20736f7572636500000000000000000000000060448201526064015b60405180910390fd5b838511156106125783610614565b845b6040805160018082528183019092529194505f9190816020015b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161062e57905050905060405180608001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b5f036106d157856106d3565b8b5b81526020018a815250815f815181106106ee576106ee610c47565b60200260200101819052508c6020015173ffffffffffffffffffffffffffffffffffffffff16637d10d11f826040518263ffffffff1660e01b81526004016107369190610d99565b5f604051808303815f87803b15801561074d575f5ffd5b505af192505050801561075e575060015b61079b573d80801561078b576040519150601f19603f3d011682016040523d82523d5f602084013e610790565b606091505b505f935091506107a0565b600192505b5097509750975097509792505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e746578740000000000000060448201526064016105fb565b5f5b81811015610997575f83838381811061084d5761084d610c47565b905060200281019061085f9190610e2d565b61086d906020810190610e69565b90505f84848481811061088257610882610c47565b90506020028101906108949190610e2d565b602001359050365f8686868181106108ae576108ae610c47565b90506020028101906108c09190610e2d565b6108ce906040810190610e84565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361096b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e000000000060448201526064016105fb565b604051818382375f5f838387895af1610986573d5f5f3e3d5ffd5b505060019093019250610832915050565b50505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156109ed576109ed61099d565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a3a57610a3a61099d565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610a63575f5ffd5b50565b8035610a7181610a42565b919050565b5f5f83601f840112610a86575f5ffd5b50813567ffffffffffffffff811115610a9d575f5ffd5b6020830191508360208260051b8501011115610ab7575f5ffd5b9250929050565b5f5f5f5f5f5f5f878903610100811215610ad6575f5ffd5b6060811215610ae3575f5ffd5b50610aec6109ca565b8835610af781610a42565b81526020890135610b0781610a42565b60208201526040890135610b1a81610a42565b60408201529650610b2d60608901610a66565b9550610b3b60808901610a66565b945060a0880135935060c0880135925060e088013567ffffffffffffffff811115610b64575f5ffd5b610b708a828b01610a76565b989b979a50959850939692959293505050565b858152846020820152836040820152821515606082015260a060808201525f82518060a08401525f5b81811015610bc957602081860181015160c0868401015201610bac565b505f60c0828501015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509695505050505050565b5f60208284031215610c1a575f5ffd5b5051919050565b5f60208284031215610c31575f5ffd5b81518015158114610c40575f5ffd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040820173ffffffffffffffffffffffffffffffffffffffff85168352604060208401528084518083526060850191506020860192505f5b81811015610ce157835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101610cad565b50909695505050505050565b5f60208284031215610cfd575f5ffd5b815167ffffffffffffffff811115610d13575f5ffd5b8201601f81018413610d23575f5ffd5b805167ffffffffffffffff811115610d3d57610d3d61099d565b8060051b610d4d602082016109f3565b91825260208184018101929081019087841115610d68575f5ffd5b6020850194505b83851015610d8e57845180835260209586019590935090910190610d6f565b979650505050505050565b602080825282518282018190525f918401906040840190835b81811015610e2257835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff6020820151166020850152604081015160408501526060810151606085015250608083019250602084019350600181019050610db2565b509095945050505050565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610e5f575f5ffd5b9190910192915050565b5f60208284031215610e79575f5ffd5b8135610c4081610a42565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610eb7575f5ffd5b83018035915067ffffffffffffffff821115610ed1575f5ffd5b602001915036819003821315610ab7575f5ffdfea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063f88cf6db1461002d575b5f5ffd5b61004061003b366004610abe565b61005a565b604051610051959493929190610b83565b60405180910390f35b5f5f5f5f606061006b8c88886107b0565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc988036101c6576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa1580156100fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101209190610c0a565b60208d01516040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e8116600483015291821660248201529196508b169063dd62ed3e906044015b602060405180830381865afa15801561019b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101bf9190610c0a565b9350610604565b7fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328803610389576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa158015610257573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027b9190610c0a565b6040808e015160208f015191517ffec90d7200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8f811660048301529283166024820152929750169063fec90d7290604401602060405180830381865afa1580156102f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061031d9190610c21565b610327575f6101bf565b60408c81015190517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301529182166024820152908b169063dd62ed3e90604401610180565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce880361059d576040805160018082528183019092525f91602080830190803683370190505090508a815f815181106103e4576103e4610c47565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040808f015190517f0f5a6efa000000000000000000000000000000000000000000000000000000008152911690630f5a6efa9061044b908f908590600401610c74565b5f60405180830381865afa158015610465573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104aa9190810190610ced565b5f815181106104bb576104bb610c47565b602002602001015195508c6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728d8f602001516040518363ffffffff1660e01b815260040161052a92919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b602060405180830381865afa158015610545573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105699190610c21565b610573575f610595565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b945050610604565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c696420746f6b656e20736f7572636500000000000000000000000060448201526064015b60405180910390fd5b838511156106125783610614565b845b6040805160018082528183019092529194505f9190816020015b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161062e57905050905060405180608001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b5f036106d157856106d3565b8b5b81526020018a815250815f815181106106ee576106ee610c47565b60200260200101819052508c6020015173ffffffffffffffffffffffffffffffffffffffff16637d10d11f826040518263ffffffff1660e01b81526004016107369190610d99565b5f604051808303815f87803b15801561074d575f5ffd5b505af192505050801561075e575060015b61079b573d80801561078b576040519150601f19603f3d011682016040523d82523d5f602084013e610790565b606091505b505f935091506107a0565b600192505b5097509750975097509792505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e746578740000000000000060448201526064016105fb565b5f5b81811015610997575f83838381811061084d5761084d610c47565b905060200281019061085f9190610e2d565b61086d906020810190610e69565b90505f84848481811061088257610882610c47565b90506020028101906108949190610e2d565b602001359050365f8686868181106108ae576108ae610c47565b90506020028101906108c09190610e2d565b6108ce906040810190610e84565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361096b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e000000000060448201526064016105fb565b604051818382375f5f838387895af1610986573d5f5f3e3d5ffd5b505060019093019250610832915050565b50505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156109ed576109ed61099d565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a3a57610a3a61099d565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610a63575f5ffd5b50565b8035610a7181610a42565b919050565b5f5f83601f840112610a86575f5ffd5b50813567ffffffffffffffff811115610a9d575f5ffd5b6020830191508360208260051b8501011115610ab7575f5ffd5b9250929050565b5f5f5f5f5f5f5f878903610100811215610ad6575f5ffd5b6060811215610ae3575f5ffd5b50610aec6109ca565b8835610af781610a42565b81526020890135610b0781610a42565b60208201526040890135610b1a81610a42565b60408201529650610b2d60608901610a66565b9550610b3b60808901610a66565b945060a0880135935060c0880135925060e088013567ffffffffffffffff811115610b64575f5ffd5b610b708a828b01610a76565b989b979a50959850939692959293505050565b858152846020820152836040820152821515606082015260a060808201525f82518060a08401525f5b81811015610bc957602081860181015160c0868401015201610bac565b505f60c0828501015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509695505050505050565b5f60208284031215610c1a575f5ffd5b5051919050565b5f60208284031215610c31575f5ffd5b81518015158114610c40575f5ffd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040820173ffffffffffffffffffffffffffffffffffffffff85168352604060208401528084518083526060850191506020860192505f5b81811015610ce157835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101610cad565b50909695505050505050565b5f60208284031215610cfd575f5ffd5b815167ffffffffffffffff811115610d13575f5ffd5b8201601f81018413610d23575f5ffd5b805167ffffffffffffffff811115610d3d57610d3d61099d565b8060051b610d4d602082016109f3565b91825260208184018101929081019087841115610d68575f5ffd5b6020850194505b83851015610d8e57845180835260209586019590935090910190610d6f565b979650505050505050565b602080825282518282018190525f918401906040840190835b81811015610e2257835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff6020820151166020850152604081015160408501526060810151606085015250608083019250602084019350600181019050610db2565b509095945050505050565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610e5f575f5ffd5b9190910192915050565b5f60208284031215610e79575f5ffd5b8135610c4081610a42565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610eb7575f5ffd5b83018035915067ffffffffffffffff821115610ed1575f5ffd5b602001915036819003821315610ab7575f5ffdfea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/contracts/artifacts/BaoswapRouter.json b/contracts/artifacts/BaoswapRouter.json new file mode 100644 index 0000000000..c95b7fd70d --- /dev/null +++ b/contracts/artifacts/BaoswapRouter.json @@ -0,0 +1,957 @@ +{ + "abi": [ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/crates/contracts/artifacts/ChainalysisOracle.json b/contracts/artifacts/ChainalysisOracle.json similarity index 99% rename from crates/contracts/artifacts/ChainalysisOracle.json rename to contracts/artifacts/ChainalysisOracle.json index 7b7318b2b8..066ba42f7a 100644 --- a/crates/contracts/artifacts/ChainalysisOracle.json +++ b/contracts/artifacts/ChainalysisOracle.json @@ -76,19 +76,6 @@ "name": "SanctionedAddressesRemoved", "type": "event" }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "newSanctions", - "type": "address[]" - } - ], - "name": "addToSanctionsList", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -108,25 +95,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - } - ], - "name": "isSanctionedVerbose", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "name", @@ -152,6 +120,40 @@ ], "stateMutability": "view", "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address[]", + "name": "newSanctions", + "type": "address[]" + } + ], + "name": "addToSanctionsList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isSanctionedVerbose", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" }, { "inputs": [ diff --git a/crates/contracts/artifacts/CoWSwapEthFlow.json b/contracts/artifacts/CoWSwapEthFlow.json similarity index 99% rename from crates/contracts/artifacts/CoWSwapEthFlow.json rename to contracts/artifacts/CoWSwapEthFlow.json index 36565487f1..e4fcf8356f 100644 --- a/crates/contracts/artifacts/CoWSwapEthFlow.json +++ b/contracts/artifacts/CoWSwapEthFlow.json @@ -201,17 +201,8 @@ "type": "event" }, { - "inputs": [], - "name": "cowSwapSettlement", - "outputs": [ - { - "internalType": "contract ICoWSwapSettlement", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" + "stateMutability": "payable", + "type": "receive" }, { "inputs": [ @@ -472,6 +463,22 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + } + ], + "bytecode": "0x60e06040523480156200001157600080fd5b5060405162001b2a38038062001b2a83398101604081905262000034916200021e565b816200004b816200015260201b6200089b1760201c565b608052506001600160a01b0380831660a081905290821660c081905260408051634daa966160e11b81529051919263095ea7b3929091639b552cc291600480830192602092919082900301816000875af1158015620000ae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000d491906200025d565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260001960248201526044016020604051808303816000875af115801562000123573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000149919062000284565b505050620002a8565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c918101919091527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf606082015246608082018190526001600160a01b03831660a083015260009160c00160405160208183030381529060405280519060200120915050919050565b6001600160a01b03811681146200021b57600080fd5b50565b600080604083850312156200023257600080fd5b82516200023f8162000205565b6020840151909250620002528162000205565b809150509250929050565b6000602082840312156200027057600080fd5b81516200027d8162000205565b9392505050565b6000602082840312156200029757600080fd5b815180151581146200027d57600080fd5b60805160a05160c0516118216200030960003960008181610129015281816105ff015281816107ad0152818161082501528181610c3301526110310152600081816102ce0152610f4b015260008181610bf70152610cd901526118216000f3fe6080604052600436106100b55760003560e01c80637bc41b9611610069578063de0e9a3e1161004e578063de0e9a3e1461027c578063ea598cb01461029c578063ec30bb88146102bc57600080fd5b80637bc41b96146101c85780639c3f1e90146101e857600080fd5b8063322bba211161009a578063322bba21146101705780634c84c1c8146101915780634cb76498146101a857600080fd5b80631626ba7e146100c157806317fcb39b1461011757600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc36600461126e565b6102f0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010e565b61018361017e36600461132b565b6103de565b60405190815260200161010e565b34801561019d57600080fd5b506101a6610720565b005b3480156101b457600080fd5b506101a66101c3366004611344565b61072b565b3480156101d457600080fd5b506101a66101e336600461132b565b610770565b3480156101f457600080fd5b5061024b6102033660046113ba565b60006020819052908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900463ffffffff1682565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835263ffffffff90911660208301520161010e565b34801561028857600080fd5b506101a66102973660046113ba565b61077e565b3480156102a857600080fd5b506101a66102b73660046113ba565b610821565b3480156102c857600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60008281526020818152604080832081518083019092525473ffffffffffffffffffffffffffffffffffffffff81168083527401000000000000000000000000000000000000000090910463ffffffff1692820192909252901580159061036f5750805173ffffffffffffffffffffffffffffffffffffffff90811614155b8015610385575042816020015163ffffffff1610155b156103b357507f1626ba7e0000000000000000000000000000000000000000000000000000000090506103d8565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b92915050565b60006103f260a08301356040840135611402565b341461042a576040517f8b6ebb4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160400135600003610468576040517feaec5c9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4261047960e0840160c0850161142e565b63ffffffff1610156104b7576040517f89bb260100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152338152600090602081016104db60e0860160c0870161142e565b63ffffffff169052604080518082019091529091506000908082815260200130604051602001610536919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905290529050600061057c61012086016101008701611462565b6020808501516040516105c393920160c09290921b825260e01b7fffffffff00000000000000000000000000000000000000000000000000000000166008820152600c0190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052835190915061063a906106337f000000000000000000000000000000000000000000000000000000000000000061062d368a90038a018a6114b1565b9061095b565b8484610b2a565b60008181526020819052604090205490945073ffffffffffffffffffffffffffffffffffffffff16156106a1576040517f56a1d2b2000000000000000000000000000000000000000000000000000000008152600481018590526024015b60405180910390fd5b505060008281526020818152604090912082518154929093015163ffffffff1674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff90931692909217179055919050565b61072947610821565b565b60005b8181101561076b5761075983838381811061074b5761074b61154b565b905061012002016000610c2c565b806107638161157a565b91505061072e565b505050565b61077b816001610c2c565b50565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561080657600080fd5b505af115801561081a573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461081a576040519150601f19603f3d011682016040523d82523d6000602084013e61081a565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c918101919091527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf6060820152466080820181905273ffffffffffffffffffffffffffffffffffffffff831660a083015260009160c00160405160208183030381529060405280519060200120915050919050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201529083015173ffffffffffffffffffffffffffffffffffffffff16610a0a576040517fefc9ccdf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518061018001604052808373ffffffffffffffffffffffffffffffffffffffff168152602001846000015173ffffffffffffffffffffffffffffffffffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015181526020018460600151815260200163ffffffff80168152602001846080015181526020018460a0015181526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020018460e00151151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9815250905092915050565b60008473ffffffffffffffffffffffffffffffffffffffff167fcf5f9de2984132265203b5c335b25727702ca77262ff622e136baa7362bf1da9858585604051610b7693929190611676565b60405180910390a25050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020919050565b6000610c617f000000000000000000000000000000000000000000000000000000000000000061062d368690038601866114b1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604080517f190100000000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600282015260228101929092526042909120600081815260208181529083902083518085019094525473ffffffffffffffffffffffffffffffffffffffff8082168086527401000000000000000000000000000000000000000090920463ffffffff1692850183905294955091934290911015911480610d8d5750815173ffffffffffffffffffffffffffffffffffffffff16155b80610db75750808015610db75750815173ffffffffffffffffffffffffffffffffffffffff163314155b15610dff578415610df7576040517ff8cc70ce00000000000000000000000000000000000000000000000000000000815260048101849052602401610698565b505050505050565b60008381526020818152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff1790558051603880825260608201909252918201818036833750505060a0860151909150610e7a90829086903090611149565b8115610ebc577fb8bad102ac8bbacfef31ff1c906ec6d951c230b4dce750bb0376b812ad35852a81604051610eaf9190611790565b60405180910390a1610f0b565b3373ffffffffffffffffffffffffffffffffffffffff167f195271068a288191e4b265c641a56b9832919f69e9e7d6c2f31ba40278aeb85a82604051610f029190611790565b60405180910390a25b6040517f2479fb6e00000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690632479fb6e90610f80908590600401611790565b6020604051808303816000875af1158015610f9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc391906117a3565b90506000808760600151838960e001510281610fe157610fe16117bc565b048860e00151039050808389606001510301915050804710156110a4576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247820360048201819052907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561108a57600080fd5b505af115801561109e573d6000803e3d6000fd5b50505050505b845160405160009173ffffffffffffffffffffffffffffffffffffffff169083908381818185875af1925050503d80600081146110fd576040519150601f19603f3d011682016040523d82523d6000602084013e611102565b606091505b505090508061113d576040517f6d963f8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050505050565b60388451146111b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f77000000000000006044820152606401610698565b60388401526034830152602090910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611219576112196111c6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611266576112666111c6565b604052919050565b6000806040838503121561128157600080fd5b8235915060208084013567ffffffffffffffff808211156112a157600080fd5b818601915086601f8301126112b557600080fd5b8135818111156112c7576112c76111c6565b6112f7847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161121f565b9150808252878482850101111561130d57600080fd5b80848401858401376000848284010152508093505050509250929050565b6000610120828403121561133e57600080fd5b50919050565b6000806020838503121561135757600080fd5b823567ffffffffffffffff8082111561136f57600080fd5b818501915085601f83011261138357600080fd5b81358181111561139257600080fd5b866020610120830285010111156113a857600080fd5b60209290920196919550909350505050565b6000602082840312156113cc57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156103d8576103d86113d3565b803563ffffffff8116811461142957600080fd5b919050565b60006020828403121561144057600080fd5b61144982611415565b9392505050565b8035600781900b811461142957600080fd5b60006020828403121561147457600080fd5b61144982611450565b803573ffffffffffffffffffffffffffffffffffffffff8116811461142957600080fd5b8035801515811461142957600080fd5b600061012082840312156114c457600080fd5b6114cc6111f5565b6114d58361147d565b81526114e36020840161147d565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015261151c60c08401611415565b60c082015261152d60e084016114a1565b60e0820152610100611540818501611450565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036115ab576115ab6113d3565b5060010190565b6000815180845260005b818110156115d8576020818501810151868301820152016115bc565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6000815160028110611651577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8084525060208201516040602085015261166e60408501826115b2565b949350505050565b835173ffffffffffffffffffffffffffffffffffffffff16815260006101c060208601516116bc602085018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408601516116e4604085018273ffffffffffffffffffffffffffffffffffffffff169052565b50606086015160608401526080860151608084015260a086015161171060a085018263ffffffff169052565b5060c086015160c084015260e086015160e0840152610100808701518185015250610120808701516117458286018215159052565b505061014086810151908401526101608087015190840152610180830181905261177181840186611616565b90508281036101a084015261178681856115b2565b9695505050505050565b60208152600061144960208301846115b2565b6000602082840312156117b557600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220d3219a243fb3b7683c6c6a0918144885c8551f0fd87b19a0e7355ed3d10e937064736f6c63430008100033", + "_disabled": [ + { + "inputs": [], + "name": "cowSwapSettlement", + "outputs": [ + { + "internalType": "contract ICoWSwapSettlement", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" }, { "inputs": [], @@ -492,11 +499,6 @@ ], "stateMutability": "view", "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" } - ], - "bytecode": "0x60e06040523480156200001157600080fd5b5060405162001b2a38038062001b2a83398101604081905262000034916200021e565b816200004b816200015260201b6200089b1760201c565b608052506001600160a01b0380831660a081905290821660c081905260408051634daa966160e11b81529051919263095ea7b3929091639b552cc291600480830192602092919082900301816000875af1158015620000ae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000d491906200025d565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260001960248201526044016020604051808303816000875af115801562000123573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000149919062000284565b505050620002a8565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c918101919091527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf606082015246608082018190526001600160a01b03831660a083015260009160c00160405160208183030381529060405280519060200120915050919050565b6001600160a01b03811681146200021b57600080fd5b50565b600080604083850312156200023257600080fd5b82516200023f8162000205565b6020840151909250620002528162000205565b809150509250929050565b6000602082840312156200027057600080fd5b81516200027d8162000205565b9392505050565b6000602082840312156200029757600080fd5b815180151581146200027d57600080fd5b60805160a05160c0516118216200030960003960008181610129015281816105ff015281816107ad0152818161082501528181610c3301526110310152600081816102ce0152610f4b015260008181610bf70152610cd901526118216000f3fe6080604052600436106100b55760003560e01c80637bc41b9611610069578063de0e9a3e1161004e578063de0e9a3e1461027c578063ea598cb01461029c578063ec30bb88146102bc57600080fd5b80637bc41b96146101c85780639c3f1e90146101e857600080fd5b8063322bba211161009a578063322bba21146101705780634c84c1c8146101915780634cb76498146101a857600080fd5b80631626ba7e146100c157806317fcb39b1461011757600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc36600461126e565b6102f0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010e565b61018361017e36600461132b565b6103de565b60405190815260200161010e565b34801561019d57600080fd5b506101a6610720565b005b3480156101b457600080fd5b506101a66101c3366004611344565b61072b565b3480156101d457600080fd5b506101a66101e336600461132b565b610770565b3480156101f457600080fd5b5061024b6102033660046113ba565b60006020819052908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900463ffffffff1682565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835263ffffffff90911660208301520161010e565b34801561028857600080fd5b506101a66102973660046113ba565b61077e565b3480156102a857600080fd5b506101a66102b73660046113ba565b610821565b3480156102c857600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60008281526020818152604080832081518083019092525473ffffffffffffffffffffffffffffffffffffffff81168083527401000000000000000000000000000000000000000090910463ffffffff1692820192909252901580159061036f5750805173ffffffffffffffffffffffffffffffffffffffff90811614155b8015610385575042816020015163ffffffff1610155b156103b357507f1626ba7e0000000000000000000000000000000000000000000000000000000090506103d8565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b92915050565b60006103f260a08301356040840135611402565b341461042a576040517f8b6ebb4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160400135600003610468576040517feaec5c9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4261047960e0840160c0850161142e565b63ffffffff1610156104b7576040517f89bb260100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152338152600090602081016104db60e0860160c0870161142e565b63ffffffff169052604080518082019091529091506000908082815260200130604051602001610536919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905290529050600061057c61012086016101008701611462565b6020808501516040516105c393920160c09290921b825260e01b7fffffffff00000000000000000000000000000000000000000000000000000000166008820152600c0190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052835190915061063a906106337f000000000000000000000000000000000000000000000000000000000000000061062d368a90038a018a6114b1565b9061095b565b8484610b2a565b60008181526020819052604090205490945073ffffffffffffffffffffffffffffffffffffffff16156106a1576040517f56a1d2b2000000000000000000000000000000000000000000000000000000008152600481018590526024015b60405180910390fd5b505060008281526020818152604090912082518154929093015163ffffffff1674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff90931692909217179055919050565b61072947610821565b565b60005b8181101561076b5761075983838381811061074b5761074b61154b565b905061012002016000610c2c565b806107638161157a565b91505061072e565b505050565b61077b816001610c2c565b50565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561080657600080fd5b505af115801561081a573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461081a576040519150601f19603f3d011682016040523d82523d6000602084013e61081a565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c918101919091527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf6060820152466080820181905273ffffffffffffffffffffffffffffffffffffffff831660a083015260009160c00160405160208183030381529060405280519060200120915050919050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201529083015173ffffffffffffffffffffffffffffffffffffffff16610a0a576040517fefc9ccdf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518061018001604052808373ffffffffffffffffffffffffffffffffffffffff168152602001846000015173ffffffffffffffffffffffffffffffffffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015181526020018460600151815260200163ffffffff80168152602001846080015181526020018460a0015181526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020018460e00151151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9815250905092915050565b60008473ffffffffffffffffffffffffffffffffffffffff167fcf5f9de2984132265203b5c335b25727702ca77262ff622e136baa7362bf1da9858585604051610b7693929190611676565b60405180910390a25050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020919050565b6000610c617f000000000000000000000000000000000000000000000000000000000000000061062d368690038601866114b1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604080517f190100000000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600282015260228101929092526042909120600081815260208181529083902083518085019094525473ffffffffffffffffffffffffffffffffffffffff8082168086527401000000000000000000000000000000000000000090920463ffffffff1692850183905294955091934290911015911480610d8d5750815173ffffffffffffffffffffffffffffffffffffffff16155b80610db75750808015610db75750815173ffffffffffffffffffffffffffffffffffffffff163314155b15610dff578415610df7576040517ff8cc70ce00000000000000000000000000000000000000000000000000000000815260048101849052602401610698565b505050505050565b60008381526020818152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff1790558051603880825260608201909252918201818036833750505060a0860151909150610e7a90829086903090611149565b8115610ebc577fb8bad102ac8bbacfef31ff1c906ec6d951c230b4dce750bb0376b812ad35852a81604051610eaf9190611790565b60405180910390a1610f0b565b3373ffffffffffffffffffffffffffffffffffffffff167f195271068a288191e4b265c641a56b9832919f69e9e7d6c2f31ba40278aeb85a82604051610f029190611790565b60405180910390a25b6040517f2479fb6e00000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690632479fb6e90610f80908590600401611790565b6020604051808303816000875af1158015610f9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc391906117a3565b90506000808760600151838960e001510281610fe157610fe16117bc565b048860e00151039050808389606001510301915050804710156110a4576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247820360048201819052907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561108a57600080fd5b505af115801561109e573d6000803e3d6000fd5b50505050505b845160405160009173ffffffffffffffffffffffffffffffffffffffff169083908381818185875af1925050503d80600081146110fd576040519150601f19603f3d011682016040523d82523d6000602084013e611102565b606091505b505090508061113d576040517f6d963f8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050505050565b60388451146111b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f77000000000000006044820152606401610698565b60388401526034830152602090910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611219576112196111c6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611266576112666111c6565b604052919050565b6000806040838503121561128157600080fd5b8235915060208084013567ffffffffffffffff808211156112a157600080fd5b818601915086601f8301126112b557600080fd5b8135818111156112c7576112c76111c6565b6112f7847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161121f565b9150808252878482850101111561130d57600080fd5b80848401858401376000848284010152508093505050509250929050565b6000610120828403121561133e57600080fd5b50919050565b6000806020838503121561135757600080fd5b823567ffffffffffffffff8082111561136f57600080fd5b818501915085601f83011261138357600080fd5b81358181111561139257600080fd5b866020610120830285010111156113a857600080fd5b60209290920196919550909350505050565b6000602082840312156113cc57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156103d8576103d86113d3565b803563ffffffff8116811461142957600080fd5b919050565b60006020828403121561144057600080fd5b61144982611415565b9392505050565b8035600781900b811461142957600080fd5b60006020828403121561147457600080fd5b61144982611450565b803573ffffffffffffffffffffffffffffffffffffffff8116811461142957600080fd5b8035801515811461142957600080fd5b600061012082840312156114c457600080fd5b6114cc6111f5565b6114d58361147d565b81526114e36020840161147d565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015261151c60c08401611415565b60c082015261152d60e084016114a1565b60e0820152610100611540818501611450565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036115ab576115ab6113d3565b5060010190565b6000815180845260005b818110156115d8576020818501810151868301820152016115bc565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6000815160028110611651577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8084525060208201516040602085015261166e60408501826115b2565b949350505050565b835173ffffffffffffffffffffffffffffffffffffffff16815260006101c060208601516116bc602085018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408601516116e4604085018273ffffffffffffffffffffffffffffffffffffffff169052565b50606086015160608401526080860151608084015260a086015161171060a085018263ffffffff169052565b5060c086015160c084015260e086015160e0840152610100808701518185015250610120808701516117458286018215159052565b505061014086810151908401526101608087015190840152610180830181905261177181840186611616565b90508281036101a084015261178681856115b2565b9695505050505050565b60208152600061144960208301846115b2565b6000602082840312156117b557600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220d3219a243fb3b7683c6c6a0918144885c8551f0fd87b19a0e7355ed3d10e937064736f6c63430008100033" + ] } diff --git a/crates/contracts/artifacts/CoWSwapOnchainOrders.json b/contracts/artifacts/CoWSwapOnchainOrders.json similarity index 99% rename from crates/contracts/artifacts/CoWSwapOnchainOrders.json rename to contracts/artifacts/CoWSwapOnchainOrders.json index a999dec321..4adfc682bf 100644 --- a/crates/contracts/artifacts/CoWSwapOnchainOrders.json +++ b/contracts/artifacts/CoWSwapOnchainOrders.json @@ -130,4 +130,4 @@ "type": "event" } ] -} +} \ No newline at end of file diff --git a/contracts/artifacts/Counter.json b/contracts/artifacts/Counter.json new file mode 100644 index 0000000000..6a1bbec162 --- /dev/null +++ b/contracts/artifacts/Counter.json @@ -0,0 +1,67 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "name": "counters", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "key", + "type": "string" + } + ], + "name": "incrementCounter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "key", + "type": "string" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "setCounterToBalance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b506103cd8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80630931831e1461004357806357cedf40146100585780639424c8c814610094575b5f5ffd5b6100566100513660046102ab565b6100a7565b005b610082610066366004610305565b80516020818301810180515f8252928201919093012091525481565b60405190815260200160405180910390f35b6100566100a2366004610305565b610159565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301528316906370a0823190602401602060405180830381865afa158015610111573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610135919061033f565b5f846040516101449190610356565b90815260405190819003602001902055505050565b60015f8260405161016a9190610356565b90815260200160405180910390205f8282546101869190610382565b909155505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126101ca575f5ffd5b813567ffffffffffffffff8111156101e4576101e461018e565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156102505761025061018e565b604052818152838201602001851015610267575f5ffd5b816020850160208301375f918101602001919091529392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146102a6575f5ffd5b919050565b5f5f5f606084860312156102bd575f5ffd5b833567ffffffffffffffff8111156102d3575f5ffd5b6102df868287016101bb565b9350506102ee60208501610283565b91506102fc60408501610283565b90509250925092565b5f60208284031215610315575f5ffd5b813567ffffffffffffffff81111561032b575f5ffd5b610337848285016101bb565b949350505050565b5f6020828403121561034f575f5ffd5b5051919050565b5f82515f5b81811015610375576020818601810151858301520161035b565b505f920191825250919050565b808201808211156103ba577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80630931831e1461004357806357cedf40146100585780639424c8c814610094575b5f5ffd5b6100566100513660046102ab565b6100a7565b005b610082610066366004610305565b80516020818301810180515f8252928201919093012091525481565b60405190815260200160405180910390f35b6100566100a2366004610305565b610159565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301528316906370a0823190602401602060405180830381865afa158015610111573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610135919061033f565b5f846040516101449190610356565b90815260405190819003602001902055505050565b60015f8260405161016a9190610356565b90815260200160405180910390205f8282546101869190610382565b909155505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126101ca575f5ffd5b813567ffffffffffffffff8111156101e4576101e461018e565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156102505761025061018e565b604052818152838201602001851015610267575f5ffd5b816020850160208301375f918101602001919091529392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146102a6575f5ffd5b919050565b5f5f5f606084860312156102bd575f5ffd5b833567ffffffffffffffff8111156102d3575f5ffd5b6102df868287016101bb565b9350506102ee60208501610283565b91506102fc60408501610283565b90509250925092565b5f60208284031215610315575f5ffd5b813567ffffffffffffffff81111561032b575f5ffd5b610337848285016101bb565b949350505050565b5f6020828403121561034f575f5ffd5b5051919050565b5f82515f5b81811015610375576020818601810151858301520161035b565b505f920191825250919050565b808201808211156103ba577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/crates/contracts/artifacts/CowAmm.json b/contracts/artifacts/CowAmm.json similarity index 99% rename from crates/contracts/artifacts/CowAmm.json rename to contracts/artifacts/CowAmm.json index 2f9b322da2..eed411938a 100644 --- a/crates/contracts/artifacts/CowAmm.json +++ b/contracts/artifacts/CowAmm.json @@ -22,97 +22,25 @@ "stateMutability": "nonpayable" }, { - "type": "function", - "name": "COMMITMENT_SLOT", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "EMPTY_COMMITMENT", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "MAX_ORDER_DURATION", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint32", - "internalType": "uint32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "NO_TRADING", + "type": "event", + "name": "TradingDisabled", "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" + "anonymous": false }, { - "type": "function", - "name": "commit", + "type": "event", + "name": "TradingEnabled", "inputs": [ { - "name": "orderHash", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "commitment", - "inputs": [], - "outputs": [ - { - "name": "value", + "name": "hash", "type": "bytes32", + "indexed": true, "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "disableTrading", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "enableTrading", - "inputs": [ + }, { - "name": "tradingParams", + "name": "params", "type": "tuple", + "indexed": false, "internalType": "struct ConstantProduct.TradingParams", "components": [ { @@ -138,111 +66,77 @@ ] } ], - "outputs": [], - "stateMutability": "nonpayable" + "anonymous": false }, { - "type": "function", - "name": "getTradeableOrder", + "type": "error", + "name": "CommitOutsideOfSettlement", + "inputs": [] + }, + { + "type": "error", + "name": "OnlyManagerCanCall", + "inputs": [] + }, + { + "type": "error", + "name": "OrderDoesNotMatchCommitmentHash", + "inputs": [] + }, + { + "type": "error", + "name": "OrderDoesNotMatchDefaultTradeableOrder", + "inputs": [] + }, + { + "type": "error", + "name": "OrderDoesNotMatchMessageHash", + "inputs": [] + }, + { + "type": "error", + "name": "OrderNotValid", "inputs": [ { - "name": "tradingParams", - "type": "tuple", - "internalType": "struct ConstantProduct.TradingParams", - "components": [ - { - "name": "minTradedToken0", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "priceOracle", - "type": "address", - "internalType": "contract IPriceOracle" - }, - { - "name": "priceOracleData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "appData", - "type": "bytes32", - "internalType": "bytes32" - } - ] + "name": "", + "type": "string", + "internalType": "string" } - ], - "outputs": [ + ] + }, + { + "type": "error", + "name": "PollTryAtBlock", + "inputs": [ { - "name": "order", - "type": "tuple", - "internalType": "struct GPv2Order.Data", - "components": [ - { - "name": "sellToken", - "type": "address", - "internalType": "contract IERC20" - }, - { - "name": "buyToken", - "type": "address", - "internalType": "contract IERC20" - }, - { - "name": "receiver", - "type": "address", - "internalType": "address" - }, - { - "name": "sellAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "buyAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "validTo", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "appData", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "feeAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "kind", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "partiallyFillable", - "type": "bool", - "internalType": "bool" - }, - { - "name": "sellTokenBalance", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "buyTokenBalance", - "type": "bytes32", - "internalType": "bytes32" - } - ] + "name": "blockNumber", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "message", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "TradingParamsDoNotMatchHash", + "inputs": [] + }, + { + "type": "function", + "name": "commit", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "internalType": "bytes32" } ], - "stateMutability": "view" + "outputs": [], + "stateMutability": "nonpayable" }, { "type": "function", @@ -322,32 +216,6 @@ ], "stateMutability": "view" }, - { - "type": "function", - "name": "solutionSettler", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract ISettlement" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "solutionSettlerDomainSeparator", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "token0", @@ -374,19 +242,6 @@ ], "stateMutability": "view" }, - { - "type": "function", - "name": "tradingParamsHash", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "verify", @@ -481,117 +336,13 @@ { "name": "buyTokenBalance", "type": "bytes32", - "internalType": "bytes32" - } - ] - } - ], - "outputs": [], - "stateMutability": "view" - }, - { - "type": "event", - "name": "TradingDisabled", - "inputs": [], - "anonymous": false - }, - { - "type": "event", - "name": "TradingEnabled", - "inputs": [ - { - "name": "hash", - "type": "bytes32", - "indexed": true, - "internalType": "bytes32" - }, - { - "name": "params", - "type": "tuple", - "indexed": false, - "internalType": "struct ConstantProduct.TradingParams", - "components": [ - { - "name": "minTradedToken0", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "priceOracle", - "type": "address", - "internalType": "contract IPriceOracle" - }, - { - "name": "priceOracleData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "appData", - "type": "bytes32", - "internalType": "bytes32" - } - ] - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "CommitOutsideOfSettlement", - "inputs": [] - }, - { - "type": "error", - "name": "OnlyManagerCanCall", - "inputs": [] - }, - { - "type": "error", - "name": "OrderDoesNotMatchCommitmentHash", - "inputs": [] - }, - { - "type": "error", - "name": "OrderDoesNotMatchDefaultTradeableOrder", - "inputs": [] - }, - { - "type": "error", - "name": "OrderDoesNotMatchMessageHash", - "inputs": [] - }, - { - "type": "error", - "name": "OrderNotValid", - "inputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ] - }, - { - "type": "error", - "name": "PollTryAtBlock", - "inputs": [ - { - "name": "blockNumber", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "message", - "type": "string", - "internalType": "string" - } - ] - }, - { - "type": "error", - "name": "TradingParamsDoNotMatchHash", - "inputs": [] + "internalType": "bytes32" + } + ] + } + ], + "outputs": [], + "stateMutability": "view" } ], "bytecode": "0x610120604052348015610010575f80fd5b5060405161267838038061267883398101604081905261002f9161052f565b6001600160a01b03831660808190526040805163f698da2560e01b8152905163f698da259160048082019260209290919082900301815f875af1158015610078573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061009c9190610579565b610100526100aa823361015f565b6100b4813361015f565b336001600160a01b031660e0816001600160a01b0316815250505f836001600160a01b0316639b552cc26040518163ffffffff1660e01b81526004016020604051808303815f875af115801561010c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101309190610590565b905061013c838261015f565b610146828261015f565b506001600160a01b0391821660a0521660c0525061061c565b6101746001600160a01b038316825f19610178565b5050565b8015806101f05750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156101ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ee9190610579565b155b6102675760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526102bd9185916102c216565b505050565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908201525f9061030e906001600160a01b03851690849061038d565b905080515f148061032e57508080602001905181019061032e91906105b2565b6102bd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161025e565b606061039b84845f856103a3565b949350505050565b6060824710156104045760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161025e565b5f80866001600160a01b0316858760405161041f91906105d1565b5f6040518083038185875af1925050503d805f8114610459576040519150601f19603f3d011682016040523d82523d5f602084013e61045e565b606091505b5090925090506104708783838761047b565b979650505050505050565b606083156104e95782515f036104e2576001600160a01b0385163b6104e25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161025e565b508161039b565b61039b83838151156104fe5781518083602001fd5b8060405162461bcd60e51b815260040161025e91906105e7565b6001600160a01b038116811461052c575f80fd5b50565b5f805f60608486031215610541575f80fd5b835161054c81610518565b602085015190935061055d81610518565b604085015190925061056e81610518565b809150509250925092565b5f60208284031215610589575f80fd5b5051919050565b5f602082840312156105a0575f80fd5b81516105ab81610518565b9392505050565b5f602082840312156105c2575f80fd5b815180151581146105ab575f80fd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b60805160a05160c05160e05161010051611fbd6106bb5f395f81816102db015261042b01525f8181610236015281816104d90152610bf901525f81816102b40152818161059901528181610d5c01528181610ebf01528181610f8e015261100d01525f81816101380152818161057701528181610d3b01528181610e2801528181610f6b015261103001525f818161032201526112140152611fbd5ff3fe608060405234801561000f575f80fd5b506004361061012f575f3560e01c8063b09aaaca116100ad578063e3e6f5b21161007d578063eec50b9711610063578063eec50b9714610344578063f14fcbc81461034c578063ff2dbc9814610203575f80fd5b8063e3e6f5b2146102fd578063e516715b1461031d575f80fd5b8063b09aaaca14610289578063c5f3d2541461029c578063d21220a7146102af578063d25e0cb6146102d6575f80fd5b80631c7de94111610102578063481c6a75116100e8578063481c6a7514610231578063981a160b14610258578063a029a8d414610276575f80fd5b80631c7de941146102035780633e706e321461020a575f80fd5b80630dfe1681146101335780631303a484146101845780631626ba7e146101b557806317700f01146101f9575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c5b60405190815260200161017b565b6101c86101c33660046116bf565b61035f565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161017b565b6102016104d7565b005b6101a75f81565b6101a77f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b59381565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b61026161012c81565b60405163ffffffff909116815260200161017b565b6102016102843660046119ee565b610573565b6101a7610297366004611a3b565b610bc8565b6102016102aa366004611a75565b610bf7565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a77f000000000000000000000000000000000000000000000000000000000000000081565b61031061030b366004611a3b565b610cb7565b60405161017b9190611aac565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a75f5481565b61020161035a366004611b9a565b6111fc565b5f808061036e84860186611bb1565b915091505f5461037d82610bc8565b146103b4576040517ff1a6789000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020868114610494576040517f593fcacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049f818385611291565b6104a98284610573565b507f1626ba7e00000000000000000000000000000000000000000000000000000000925050505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610546576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8080556040517fbcb8b8fbdea8aa6dc4ae41213e4da81e605a3d1a56ed851b9355182321c091909190a1565b80517f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff808416911614610677578073ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff1614610675576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642073656c6c20746f6b656e000000000000000000000000000060448201526064015b60405180910390fd5b905b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156106e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107059190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610772573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107969190611bff565b90508273ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff1614610831576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c69642062757920746f6b656e000000000000000000000000000000604482015260640161066c565b604085015173ffffffffffffffffffffffffffffffffffffffff16156108b3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7265636569766572206d757374206265207a65726f2061646472657373000000604482015260640161066c565b6108bf61012c42611c43565b8560a0015163ffffffff161115610932576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f76616c696469747920746f6f2066617220696e20746865206675747572650000604482015260640161066c565b85606001518560c00151146109a3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420617070446174610000000000000000000000000000000000604482015260640161066c565b60e085015115610a0f576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f66656520616d6f756e74206d757374206265207a65726f000000000000000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610160015114610a9d576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f627579546f6b656e42616c616e6365206d757374206265206572633230000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610140015114610b2b576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656c6c546f6b656e42616c616e6365206d7573742062652065726332300000604482015260640161066c565b6060850151610b3a9082611c56565b60808601516060870151610b4e9085611c6d565b610b589190611c56565b1015610bc0576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f726563656976656420616d6f756e7420746f6f206c6f77000000000000000000604482015260640161066c565b505050505050565b5f81604051602001610bda9190611ccc565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c66576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610c7361029783611d27565b9050805f81905550807f510e4a4f76907c2d6158b343f7c4f2f597df385b727c26e9ef90e75093ace19a83604051610cab9190611d79565b60405180910390a25050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091525f80836020015173ffffffffffffffffffffffffffffffffffffffff1663355efdd97f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087604001516040518463ffffffff1660e01b8152600401610d9e93929190611e3a565b6040805180830381865afa158015610db8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ddc9190611e72565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291935091505f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610e6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e919190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3d9190611bff565b90925090505f80808080610f518888611c56565b90505f610f5e8a88611c56565b90505f8282101561100b577f000000000000000000000000000000000000000000000000000000000000000096507f00000000000000000000000000000000000000000000000000000000000000009550610fd6610fbd60028b611ec1565b610fd184610fcc8e6002611c56565b611346565b61137e565b945061100185610fe6818d611c56565b610ff09085611c43565b610ffa8c8f611c56565b60016113cb565b9350849050611098565b7f000000000000000000000000000000000000000000000000000000000000000096507f0000000000000000000000000000000000000000000000000000000000000000955061106e61105f60028a611ec1565b610fd185610fcc8f6002611c56565b94506110928561107e818e611c56565b6110889086611c43565b610ffa8b8e611c56565b93508390505b8c518110156110df576110df6040518060400160405280601781526020017f74726164656420616d6f756e7420746f6f20736d616c6c000000000000000000815250611426565b6040518061018001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200161115661012c611466565b63ffffffff1681526020018e6060015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98152509b505050505050505050505050919050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461126b576040517fbf84897700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935d50565b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c8381146113405780156112f2576040517fdafbdd1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112fc84610cb7565b90506113088382611487565b61133e576040517fd9ff24c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50505050565b5f82156113735781611359600185611c6d565b6113639190611ec1565b61136e906001611c43565b611375565b5f5b90505b92915050565b5f818310156113c5576113c56040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250611426565b50900390565b5f806113d8868686611599565b905060018360028111156113ee576113ee611ed4565b14801561140a57505f848061140557611405611e94565b868809115b1561141d5761141a600182611c43565b90505b95945050505050565b611431436001611c43565b816040517f1fe8506e00000000000000000000000000000000000000000000000000000000815260040161066c929190611f01565b5f81806114738142611f19565b61147d9190611f3b565b6113789190611f63565b5f80825f015173ffffffffffffffffffffffffffffffffffffffff16845f015173ffffffffffffffffffffffffffffffffffffffff161490505f836020015173ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161490505f846060015186606001511490505f856080015187608001511490505f8660a0015163ffffffff168860a0015163ffffffff161490505f8761010001518961010001511490505f88610120015115158a6101200151151514905086801561155e5750855b80156115675750845b80156115705750835b80156115795750825b80156115825750815b801561158b5750805b9a9950505050505050505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f036115ef578382816115e5576115e5611e94565b04925050506104d0565b808411611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161066c565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f805f604084860312156116d1575f80fd5b83359250602084013567ffffffffffffffff808211156116ef575f80fd5b818601915086601f830112611702575f80fd5b813581811115611710575f80fd5b876020828501011115611721575f80fd5b6020830194508093505050509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561178457611784611734565b60405290565b604051610180810167ffffffffffffffff8111828210171561178457611784611734565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117f5576117f5611734565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461181e575f80fd5b50565b5f60808284031215611831575f80fd5b611839611761565b90508135815260208083013561184e816117fd565b82820152604083013567ffffffffffffffff8082111561186c575f80fd5b818501915085601f83011261187f575f80fd5b81358181111561189157611891611734565b6118c1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016117ae565b915080825286848285010111156118d6575f80fd5b80848401858401375f848284010152508060408501525050506060820135606082015292915050565b803561190a816117fd565b919050565b803563ffffffff8116811461190a575f80fd5b8035801515811461190a575f80fd5b5f6101808284031215611942575f80fd5b61194a61178a565b9050611955826118ff565b8152611963602083016118ff565b6020820152611974604083016118ff565b6040820152606082013560608201526080820135608082015261199960a0830161190f565b60a082015260c082013560c082015260e082013560e08201526101008083013581830152506101206119cc818401611922565b9082015261014082810135908201526101609182013591810191909152919050565b5f806101a08385031215611a00575f80fd5b823567ffffffffffffffff811115611a16575f80fd5b611a2285828601611821565b925050611a328460208501611931565b90509250929050565b5f60208284031215611a4b575f80fd5b813567ffffffffffffffff811115611a61575f80fd5b611a6d84828501611821565b949350505050565b5f60208284031215611a85575f80fd5b813567ffffffffffffffff811115611a9b575f80fd5b8201608081850312156104d0575f80fd5b815173ffffffffffffffffffffffffffffffffffffffff16815261018081016020830151611af2602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151611b1a604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606083015160608301526080830151608083015260a0830151611b4660a084018263ffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b7b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f60208284031215611baa575f80fd5b5035919050565b5f806101a08385031215611bc3575f80fd5b611bcd8484611931565b915061018083013567ffffffffffffffff811115611be9575f80fd5b611bf585828601611821565b9150509250929050565b5f60208284031215611c0f575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561137857611378611c16565b808202811582820484141761137857611378611c16565b8181038181111561137857611378611c16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081528151602082015273ffffffffffffffffffffffffffffffffffffffff60208301511660408201525f604083015160806060840152611d1160a0840182611c80565b9050606084015160808401528091505092915050565b5f6113783683611821565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152813560208201525f6020830135611d93816117fd565b73ffffffffffffffffffffffffffffffffffffffff811660408401525060408301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611de4575f80fd5b830160208101903567ffffffffffffffff811115611e00575f80fd5b803603821315611e0e575f80fd5b60806060850152611e2360a085018284611d32565b915050606084013560808401528091505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff80861683528085166020840152506060604083015261141d6060830184611c80565b5f8060408385031215611e83575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82611ecf57611ecf611e94565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f611a6d6040830184611c80565b5f63ffffffff80841680611f2f57611f2f611e94565b92169190910492915050565b63ffffffff818116838216028082169190828114611f5b57611f5b611c16565b505092915050565b63ffffffff818116838216019080821115611f8057611f80611c16565b509291505056fea2646970667358221220e3fb228b525d90b942c7e58fe2e2034a17bd258c082fd47740e764a7be45bac664736f6c63430008190033", @@ -1496,5 +1247,256 @@ }, "version": 1 }, - "id": 169 + "id": 169, + "_disabled": [ + { + "type": "function", + "name": "COMMITMENT_SLOT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "EMPTY_COMMITMENT", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MAX_ORDER_DURATION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "NO_TRADING", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "commitment", + "inputs": [], + "outputs": [ + { + "name": "value", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "disableTrading", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableTrading", + "inputs": [ + { + "name": "tradingParams", + "type": "tuple", + "internalType": "struct ConstantProduct.TradingParams", + "components": [ + { + "name": "minTradedToken0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceOracle", + "type": "address", + "internalType": "contract IPriceOracle" + }, + { + "name": "priceOracleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getTradeableOrder", + "inputs": [ + { + "name": "tradingParams", + "type": "tuple", + "internalType": "struct ConstantProduct.TradingParams", + "components": [ + { + "name": "minTradedToken0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceOracle", + "type": "address", + "internalType": "contract IPriceOracle" + }, + { + "name": "priceOracleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [ + { + "name": "order", + "type": "tuple", + "internalType": "struct GPv2Order.Data", + "components": [ + { + "name": "sellToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "kind", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sellTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "buyTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "solutionSettler", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISettlement" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "solutionSettlerDomainSeparator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "tradingParamsHash", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + } + ] } diff --git a/crates/contracts/artifacts/CowAmmConstantProductFactory.json b/contracts/artifacts/CowAmmConstantProductFactory.json similarity index 99% rename from crates/contracts/artifacts/CowAmmConstantProductFactory.json rename to contracts/artifacts/CowAmmConstantProductFactory.json index 131f459659..66ecf78cbc 100644 --- a/crates/contracts/artifacts/CowAmmConstantProductFactory.json +++ b/contracts/artifacts/CowAmmConstantProductFactory.json @@ -12,250 +12,125 @@ "stateMutability": "nonpayable" }, { - "type": "function", - "name": "ammDeterministicAddress", + "type": "event", + "name": "ConditionalOrderCreated", "inputs": [ { - "name": "ammOwner", + "name": "owner", "type": "address", + "indexed": true, "internalType": "address" }, { - "name": "token0", - "type": "address", - "internalType": "contract IERC20" - }, - { - "name": "token1", - "type": "address", - "internalType": "contract IERC20" - } - ], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" + "name": "params", + "type": "tuple", + "indexed": false, + "internalType": "struct IConditionalOrder.ConditionalOrderParams", + "components": [ + { + "name": "handler", + "type": "address", + "internalType": "contract IConditionalOrder" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "staticInput", + "type": "bytes", + "internalType": "bytes" + } + ] } ], - "stateMutability": "view" + "anonymous": false }, { - "type": "function", - "name": "create", + "type": "event", + "name": "Deployed", "inputs": [ { - "name": "token0", + "name": "amm", "type": "address", - "internalType": "contract IERC20" + "indexed": true, + "internalType": "contract ConstantProduct" }, { - "name": "amount0", - "type": "uint256", - "internalType": "uint256" + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" }, { - "name": "token1", + "name": "token0", "type": "address", + "indexed": false, "internalType": "contract IERC20" }, { - "name": "amount1", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "minTradedToken0", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "priceOracle", + "name": "token1", "type": "address", - "internalType": "contract IPriceOracle" - }, - { - "name": "priceOracleData", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "appData", - "type": "bytes32", - "internalType": "bytes32" + "indexed": false, + "internalType": "contract IERC20" } ], - "outputs": [ + "anonymous": false + }, + { + "type": "event", + "name": "TradingDisabled", + "inputs": [ { "name": "amm", "type": "address", + "indexed": true, "internalType": "contract ConstantProduct" } ], - "stateMutability": "nonpayable" + "anonymous": false }, { - "type": "function", - "name": "deposit", + "type": "error", + "name": "OnlyOwnerCanCall", "inputs": [ { - "name": "amm", + "name": "owner", "type": "address", - "internalType": "contract ConstantProduct" - }, - { - "name": "amount0", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "amount1", - "type": "uint256", - "internalType": "uint256" + "internalType": "address" } - ], - "outputs": [], - "stateMutability": "nonpayable" + ] }, { - "type": "function", - "name": "disableTrading", + "type": "error", + "name": "OrderNotValid", "inputs": [ { - "name": "amm", - "type": "address", - "internalType": "contract ConstantProduct" + "name": "", + "type": "string", + "internalType": "string" } - ], - "outputs": [], - "stateMutability": "nonpayable" + ] }, { "type": "function", - "name": "getTradeableOrderWithSignature", + "name": "ammDeterministicAddress", "inputs": [ { - "name": "amm", + "name": "ammOwner", "type": "address", - "internalType": "contract ConstantProduct" - }, - { - "name": "params", - "type": "tuple", - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "components": [ - { - "name": "handler", - "type": "address", - "internalType": "contract IConditionalOrder" - }, - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "staticInput", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "", - "type": "bytes", - "internalType": "bytes" + "internalType": "address" }, { - "name": "", - "type": "bytes32[]", - "internalType": "bytes32[]" - } - ], - "outputs": [ - { - "name": "order", - "type": "tuple", - "internalType": "struct GPv2Order.Data", - "components": [ - { - "name": "sellToken", - "type": "address", - "internalType": "contract IERC20" - }, - { - "name": "buyToken", - "type": "address", - "internalType": "contract IERC20" - }, - { - "name": "receiver", - "type": "address", - "internalType": "address" - }, - { - "name": "sellAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "buyAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "validTo", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "appData", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "feeAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "kind", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "partiallyFillable", - "type": "bool", - "internalType": "bool" - }, - { - "name": "sellTokenBalance", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "buyTokenBalance", - "type": "bytes32", - "internalType": "bytes32" - } - ] + "name": "token0", + "type": "address", + "internalType": "contract IERC20" }, { - "name": "signature", - "type": "bytes", - "internalType": "bytes" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "owner", - "inputs": [ - { - "name": "", + "name": "token1", "type": "address", - "internalType": "contract ConstantProduct" + "internalType": "contract IERC20" } ], "outputs": [ @@ -269,25 +144,27 @@ }, { "type": "function", - "name": "settler", - "inputs": [], - "outputs": [ + "name": "create", + "inputs": [ { - "name": "", + "name": "token0", "type": "address", - "internalType": "contract ISettlement" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "updateParameters", - "inputs": [ + "internalType": "contract IERC20" + }, { - "name": "amm", + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "token1", "type": "address", - "internalType": "contract ConstantProduct" + "internalType": "contract IERC20" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" }, { "name": "minTradedToken0", @@ -309,134 +186,80 @@ "type": "bytes32", "internalType": "bytes32" } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "withdraw", - "inputs": [ - { - "name": "amm", - "type": "address", - "internalType": "contract ConstantProduct" - }, - { - "name": "amount0", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "amount1", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "ConditionalOrderCreated", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "params", - "type": "tuple", - "indexed": false, - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "components": [ - { - "name": "handler", - "type": "address", - "internalType": "contract IConditionalOrder" - }, - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "staticInput", - "type": "bytes", - "internalType": "bytes" - } - ] + ], + "outputs": [ + { + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" } ], - "anonymous": false + "stateMutability": "nonpayable" }, { - "type": "event", - "name": "Deployed", + "type": "function", + "name": "deposit", "inputs": [ { "name": "amm", "type": "address", - "indexed": true, "internalType": "contract ConstantProduct" }, { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "token0", - "type": "address", - "indexed": false, - "internalType": "contract IERC20" + "name": "amount0", + "type": "uint256", + "internalType": "uint256" }, { - "name": "token1", - "type": "address", - "indexed": false, - "internalType": "contract IERC20" + "name": "amount1", + "type": "uint256", + "internalType": "uint256" } ], - "anonymous": false + "outputs": [], + "stateMutability": "nonpayable" }, { - "type": "event", - "name": "TradingDisabled", + "type": "function", + "name": "owner", "inputs": [ { - "name": "amm", + "name": "", "type": "address", - "indexed": true, "internalType": "contract ConstantProduct" } ], - "anonymous": false - }, - { - "type": "error", - "name": "OnlyOwnerCanCall", - "inputs": [ + "outputs": [ { - "name": "owner", + "name": "", "type": "address", "internalType": "address" } - ] + ], + "stateMutability": "view" }, { - "type": "error", - "name": "OrderNotValid", + "type": "function", + "name": "withdraw", "inputs": [ { - "name": "", - "type": "string", - "internalType": "string" + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" + }, + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" } - ] + ], + "outputs": [], + "stateMutability": "nonpayable" } ], "bytecode": "0x60a0604052348015600e575f80fd5b506040516141b33803806141b3833981016040819052602b91603b565b6001600160a01b03166080526066565b5f60208284031215604a575f80fd5b81516001600160a01b0381168114605f575f80fd5b9392505050565b60805161412761008c5f395f8181610189015281816102a801526108c401526141275ff3fe608060405234801561000f575f80fd5b506004361061009f575f3560e01c806337ebdf5011610072578063666e1b3911610058578063666e1b391461014f578063ab221a7614610184578063b5c5f672146101ab575f80fd5b806337ebdf50146101295780635b5d9ee61461013c575f80fd5b80630efe6a8b146100a357806322b155c6146100b857806326e0a196146100f55780632791056514610116575b5f80fd5b6100b66100b13660046111ea565b6101be565b005b6100cb6100c6366004611261565b6102a3565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101086101033660046112fb565b61045f565b6040516100ec9291906114fd565b6100b6610124366004611527565b610797565b6100cb610137366004611549565b61082f565b6100b661014a366004611591565b610a01565b6100cb61015d366004611527565b5f6020819052908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6100cb7f000000000000000000000000000000000000000000000000000000000000000081565b6100b66101b93660046111ea565b610b17565b61024f3384848673ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102319190611617565b73ffffffffffffffffffffffffffffffffffffffff16929190610c46565b61029e3384838673ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b505050565b5f33807f00000000000000000000000000000000000000000000000000000000000000008c8b6040516102d5906111b9565b73ffffffffffffffffffffffffffffffffffffffff9384168152918316602083015290911660408201526060018190604051809103905ff590508015801561031f573d5f803e3d5ffd5b506040805173ffffffffffffffffffffffffffffffffffffffff8e811682528c81166020830152929450828416928516917f6707255b2c5ca81220b2f3e408a269cb83baa6aa7e5e37aa1756883a6cdf06f1910160405180910390a373ffffffffffffffffffffffffffffffffffffffff8281165f90815260208190526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790556103d8828b8a6101be565b5f60405180608001604052808981526020018873ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050509082525060200185905290506104508382610cdb565b50509998505050505050505050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526060306104cf6020890189611527565b73ffffffffffffffffffffffffffffffffffffffff1614610551576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e206f6e6c792068616e646c65206f776e206f726465727300000000000060448201526064015b60405180910390fd5b5f61055f6040890189611632565b81019061056c919061175c565b90508873ffffffffffffffffffffffffffffffffffffffff1663eec50b976040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105db919061185a565b6040517fb09aaaca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b169063b09aaaca9061062d9085906004016118c3565b602060405180830381865afa158015610648573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061066c919061185a565b146106d3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f696e76616c69642074726164696e6720706172616d65746572730000000000006044820152606401610548565b6040517fe3e6f5b200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a169063e3e6f5b2906107259084906004016118c3565b61018060405180830381865afa158015610741573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061076591906118f7565b9250828160405160200161077a9291906119b3565b604051602081830303815290604052915050965096945050505050565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526020819052604090205482911633146108225773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b61082b82610e05565b5050565b5f807fff000000000000000000000000000000000000000000000000000000000000003073ffffffffffffffffffffffffffffffffffffffff8716604051610879602082016111b9565b8181037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09081018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166020840152808b169183019190915288166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261093a92916020016119eb565b604051602081830303815290604052805190602001206040516020016109c294939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830152603582015260550190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052805160209091012095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8087165f908152602081905260409020548791163314610a8c5773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b5f60405180608001604052808881526020018773ffffffffffffffffffffffffffffffffffffffff16815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506020018490529050610b0388610e05565b610b0d8882610cdb565b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8084165f908152602081905260409020548491163314610ba25773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b610bf18433858773ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b610c408433848773ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b50505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610c40908590610ea3565b6040517fc5f3d25400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063c5f3d25490610d2d9084906004016118c3565b5f604051808303815f87803b158015610d44575f80fd5b505af1158015610d56573d5f803e3d5ffd5b5050604080516060810182523081525f6020808301829052835191955073ffffffffffffffffffffffffffffffffffffffff881694507f2cceac5555b0ca45a3744ced542f54b56ad2eb45e521962372eef212a2cbf36193830191610dbd918891016118c3565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915251610df891906119ff565b60405180910390a2505050565b8073ffffffffffffffffffffffffffffffffffffffff166317700f016040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610e4a575f80fd5b505af1158015610e5c573d5f803e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff841692507fc75bf4f03c02fab9414a7d7a54048c0486722bc72f33ad924709a0593608ad2791505f90a250565b5f610f04826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610fb09092919063ffffffff16565b905080515f1480610f24575080806020019051810190610f249190611a43565b61029e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610548565b6060610fbe84845f85610fc6565b949350505050565b606082471015611058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610548565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516110809190611a5c565b5f6040518083038185875af1925050503d805f81146110ba576040519150601f19603f3d011682016040523d82523d5f602084013e6110bf565b606091505b50915091506110d0878383876110db565b979650505050505050565b606083156111705782515f036111695773ffffffffffffffffffffffffffffffffffffffff85163b611169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610548565b5081610fbe565b610fbe83838151156111855781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105489190611a67565b61267880611a7a83390190565b73ffffffffffffffffffffffffffffffffffffffff811681146111e7575f80fd5b50565b5f805f606084860312156111fc575f80fd5b8335611207816111c6565b95602085013595506040909401359392505050565b5f8083601f84011261122c575f80fd5b50813567ffffffffffffffff811115611243575f80fd5b60208301915083602082850101111561125a575f80fd5b9250929050565b5f805f805f805f805f6101008a8c03121561127a575f80fd5b8935611285816111c6565b985060208a0135975060408a013561129c816111c6565b965060608a0135955060808a0135945060a08a01356112ba816111c6565b935060c08a013567ffffffffffffffff8111156112d5575f80fd5b6112e18c828d0161121c565b9a9d999c50979a9699959894979660e00135949350505050565b5f805f805f8060808789031215611310575f80fd5b863561131b816111c6565b9550602087013567ffffffffffffffff80821115611337575f80fd5b908801906060828b03121561134a575f80fd5b9095506040880135908082111561135f575f80fd5b61136b8a838b0161121c565b90965094506060890135915080821115611383575f80fd5b818901915089601f830112611396575f80fd5b8135818111156113a4575f80fd5b8a60208260051b85010111156113b8575f80fd5b6020830194508093505050509295509295509295565b805173ffffffffffffffffffffffffffffffffffffffff168252602081015161140f602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151611437604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608301526080810151608083015260a081015161146360a084018263ffffffff169052565b5060c081015160c083015260e081015160e0830152610100808201518184015250610120808201516114988285018215159052565b5050610140818101519083015261016090810151910152565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b5f6101a061150b83866113ce565b8061018084015261151e818401856114b1565b95945050505050565b5f60208284031215611537575f80fd5b8135611542816111c6565b9392505050565b5f805f6060848603121561155b575f80fd5b8335611566816111c6565b92506020840135611576816111c6565b91506040840135611586816111c6565b809150509250925092565b5f805f805f8060a087890312156115a6575f80fd5b86356115b1816111c6565b95506020870135945060408701356115c8816111c6565b9350606087013567ffffffffffffffff8111156115e3575f80fd5b6115ef89828a0161121c565b979a9699509497949695608090950135949350505050565b8051611612816111c6565b919050565b5f60208284031215611627575f80fd5b8151611542816111c6565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611665575f80fd5b83018035915067ffffffffffffffff82111561167f575f80fd5b60200191503681900382131561125a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156116e3576116e3611693565b60405290565b604051610180810167ffffffffffffffff811182821017156116e3576116e3611693565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561175457611754611693565b604052919050565b5f602080838503121561176d575f80fd5b823567ffffffffffffffff80821115611784575f80fd5b9084019060808287031215611797575f80fd5b61179f6116c0565b82358152838301356117b0816111c6565b818501526040830135828111156117c5575f80fd5b8301601f810188136117d5575f80fd5b8035838111156117e7576117e7611693565b611817867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161170d565b9350808452888682840101111561182c575f80fd5b80868301878601375f8682860101525050816040820152606083013560608201528094505050505092915050565b5f6020828403121561186a575f80fd5b5051919050565b8051825273ffffffffffffffffffffffffffffffffffffffff60208201511660208301525f6040820151608060408501526118af60808501826114b1565b606093840151949093019390935250919050565b602081525f6115426020830184611871565b805163ffffffff81168114611612575f80fd5b80518015158114611612575f80fd5b5f6101808284031215611908575f80fd5b6119106116e9565b61191983611607565b815261192760208401611607565b602082015261193860408401611607565b6040820152606083015160608201526080830151608082015261195d60a084016118d5565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206119908185016118e8565b908201526101408381015190820152610160928301519281019290925250919050565b5f6101a06119c183866113ce565b8061018084015261151e81840185611871565b5f81518060208401855e5f93019283525090919050565b5f610fbe6119f983866119d4565b846119d4565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201525f6040830151606080840152610fbe60808401826114b1565b5f60208284031215611a53575f80fd5b611542826118e8565b5f61154282846119d4565b602081525f61154260208301846114b156fe610120604052348015610010575f80fd5b5060405161267838038061267883398101604081905261002f9161052f565b6001600160a01b03831660808190526040805163f698da2560e01b8152905163f698da259160048082019260209290919082900301815f875af1158015610078573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061009c9190610579565b610100526100aa823361015f565b6100b4813361015f565b336001600160a01b031660e0816001600160a01b0316815250505f836001600160a01b0316639b552cc26040518163ffffffff1660e01b81526004016020604051808303815f875af115801561010c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101309190610590565b905061013c838261015f565b610146828261015f565b506001600160a01b0391821660a0521660c0525061061c565b6101746001600160a01b038316825f19610178565b5050565b8015806101f05750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156101ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ee9190610579565b155b6102675760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526102bd9185916102c216565b505050565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908201525f9061030e906001600160a01b03851690849061038d565b905080515f148061032e57508080602001905181019061032e91906105b2565b6102bd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161025e565b606061039b84845f856103a3565b949350505050565b6060824710156104045760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161025e565b5f80866001600160a01b0316858760405161041f91906105d1565b5f6040518083038185875af1925050503d805f8114610459576040519150601f19603f3d011682016040523d82523d5f602084013e61045e565b606091505b5090925090506104708783838761047b565b979650505050505050565b606083156104e95782515f036104e2576001600160a01b0385163b6104e25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161025e565b508161039b565b61039b83838151156104fe5781518083602001fd5b8060405162461bcd60e51b815260040161025e91906105e7565b6001600160a01b038116811461052c575f80fd5b50565b5f805f60608486031215610541575f80fd5b835161054c81610518565b602085015190935061055d81610518565b604085015190925061056e81610518565b809150509250925092565b5f60208284031215610589575f80fd5b5051919050565b5f602082840312156105a0575f80fd5b81516105ab81610518565b9392505050565b5f602082840312156105c2575f80fd5b815180151581146105ab575f80fd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b60805160a05160c05160e05161010051611fbd6106bb5f395f81816102db015261042b01525f8181610236015281816104d90152610bf901525f81816102b40152818161059901528181610d5c01528181610ebf01528181610f8e015261100d01525f81816101380152818161057701528181610d3b01528181610e2801528181610f6b015261103001525f818161032201526112140152611fbd5ff3fe608060405234801561000f575f80fd5b506004361061012f575f3560e01c8063b09aaaca116100ad578063e3e6f5b21161007d578063eec50b9711610063578063eec50b9714610344578063f14fcbc81461034c578063ff2dbc9814610203575f80fd5b8063e3e6f5b2146102fd578063e516715b1461031d575f80fd5b8063b09aaaca14610289578063c5f3d2541461029c578063d21220a7146102af578063d25e0cb6146102d6575f80fd5b80631c7de94111610102578063481c6a75116100e8578063481c6a7514610231578063981a160b14610258578063a029a8d414610276575f80fd5b80631c7de941146102035780633e706e321461020a575f80fd5b80630dfe1681146101335780631303a484146101845780631626ba7e146101b557806317700f01146101f9575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c5b60405190815260200161017b565b6101c86101c33660046116bf565b61035f565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161017b565b6102016104d7565b005b6101a75f81565b6101a77f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b59381565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b61026161012c81565b60405163ffffffff909116815260200161017b565b6102016102843660046119ee565b610573565b6101a7610297366004611a3b565b610bc8565b6102016102aa366004611a75565b610bf7565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a77f000000000000000000000000000000000000000000000000000000000000000081565b61031061030b366004611a3b565b610cb7565b60405161017b9190611aac565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a75f5481565b61020161035a366004611b9a565b6111fc565b5f808061036e84860186611bb1565b915091505f5461037d82610bc8565b146103b4576040517ff1a6789000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020868114610494576040517f593fcacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049f818385611291565b6104a98284610573565b507f1626ba7e00000000000000000000000000000000000000000000000000000000925050505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610546576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8080556040517fbcb8b8fbdea8aa6dc4ae41213e4da81e605a3d1a56ed851b9355182321c091909190a1565b80517f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff808416911614610677578073ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff1614610675576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642073656c6c20746f6b656e000000000000000000000000000060448201526064015b60405180910390fd5b905b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156106e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107059190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610772573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107969190611bff565b90508273ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff1614610831576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c69642062757920746f6b656e000000000000000000000000000000604482015260640161066c565b604085015173ffffffffffffffffffffffffffffffffffffffff16156108b3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7265636569766572206d757374206265207a65726f2061646472657373000000604482015260640161066c565b6108bf61012c42611c43565b8560a0015163ffffffff161115610932576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f76616c696469747920746f6f2066617220696e20746865206675747572650000604482015260640161066c565b85606001518560c00151146109a3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420617070446174610000000000000000000000000000000000604482015260640161066c565b60e085015115610a0f576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f66656520616d6f756e74206d757374206265207a65726f000000000000000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610160015114610a9d576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f627579546f6b656e42616c616e6365206d757374206265206572633230000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610140015114610b2b576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656c6c546f6b656e42616c616e6365206d7573742062652065726332300000604482015260640161066c565b6060850151610b3a9082611c56565b60808601516060870151610b4e9085611c6d565b610b589190611c56565b1015610bc0576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f726563656976656420616d6f756e7420746f6f206c6f77000000000000000000604482015260640161066c565b505050505050565b5f81604051602001610bda9190611ccc565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c66576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610c7361029783611d27565b9050805f81905550807f510e4a4f76907c2d6158b343f7c4f2f597df385b727c26e9ef90e75093ace19a83604051610cab9190611d79565b60405180910390a25050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091525f80836020015173ffffffffffffffffffffffffffffffffffffffff1663355efdd97f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087604001516040518463ffffffff1660e01b8152600401610d9e93929190611e3a565b6040805180830381865afa158015610db8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ddc9190611e72565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291935091505f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610e6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e919190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3d9190611bff565b90925090505f80808080610f518888611c56565b90505f610f5e8a88611c56565b90505f8282101561100b577f000000000000000000000000000000000000000000000000000000000000000096507f00000000000000000000000000000000000000000000000000000000000000009550610fd6610fbd60028b611ec1565b610fd184610fcc8e6002611c56565b611346565b61137e565b945061100185610fe6818d611c56565b610ff09085611c43565b610ffa8c8f611c56565b60016113cb565b9350849050611098565b7f000000000000000000000000000000000000000000000000000000000000000096507f0000000000000000000000000000000000000000000000000000000000000000955061106e61105f60028a611ec1565b610fd185610fcc8f6002611c56565b94506110928561107e818e611c56565b6110889086611c43565b610ffa8b8e611c56565b93508390505b8c518110156110df576110df6040518060400160405280601781526020017f74726164656420616d6f756e7420746f6f20736d616c6c000000000000000000815250611426565b6040518061018001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200161115661012c611466565b63ffffffff1681526020018e6060015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98152509b505050505050505050505050919050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461126b576040517fbf84897700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935d50565b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c8381146113405780156112f2576040517fdafbdd1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112fc84610cb7565b90506113088382611487565b61133e576040517fd9ff24c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50505050565b5f82156113735781611359600185611c6d565b6113639190611ec1565b61136e906001611c43565b611375565b5f5b90505b92915050565b5f818310156113c5576113c56040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250611426565b50900390565b5f806113d8868686611599565b905060018360028111156113ee576113ee611ed4565b14801561140a57505f848061140557611405611e94565b868809115b1561141d5761141a600182611c43565b90505b95945050505050565b611431436001611c43565b816040517f1fe8506e00000000000000000000000000000000000000000000000000000000815260040161066c929190611f01565b5f81806114738142611f19565b61147d9190611f3b565b6113789190611f63565b5f80825f015173ffffffffffffffffffffffffffffffffffffffff16845f015173ffffffffffffffffffffffffffffffffffffffff161490505f836020015173ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161490505f846060015186606001511490505f856080015187608001511490505f8660a0015163ffffffff168860a0015163ffffffff161490505f8761010001518961010001511490505f88610120015115158a6101200151151514905086801561155e5750855b80156115675750845b80156115705750835b80156115795750825b80156115825750815b801561158b5750805b9a9950505050505050505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f036115ef578382816115e5576115e5611e94565b04925050506104d0565b808411611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161066c565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f805f604084860312156116d1575f80fd5b83359250602084013567ffffffffffffffff808211156116ef575f80fd5b818601915086601f830112611702575f80fd5b813581811115611710575f80fd5b876020828501011115611721575f80fd5b6020830194508093505050509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561178457611784611734565b60405290565b604051610180810167ffffffffffffffff8111828210171561178457611784611734565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117f5576117f5611734565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461181e575f80fd5b50565b5f60808284031215611831575f80fd5b611839611761565b90508135815260208083013561184e816117fd565b82820152604083013567ffffffffffffffff8082111561186c575f80fd5b818501915085601f83011261187f575f80fd5b81358181111561189157611891611734565b6118c1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016117ae565b915080825286848285010111156118d6575f80fd5b80848401858401375f848284010152508060408501525050506060820135606082015292915050565b803561190a816117fd565b919050565b803563ffffffff8116811461190a575f80fd5b8035801515811461190a575f80fd5b5f6101808284031215611942575f80fd5b61194a61178a565b9050611955826118ff565b8152611963602083016118ff565b6020820152611974604083016118ff565b6040820152606082013560608201526080820135608082015261199960a0830161190f565b60a082015260c082013560c082015260e082013560e08201526101008083013581830152506101206119cc818401611922565b9082015261014082810135908201526101609182013591810191909152919050565b5f806101a08385031215611a00575f80fd5b823567ffffffffffffffff811115611a16575f80fd5b611a2285828601611821565b925050611a328460208501611931565b90509250929050565b5f60208284031215611a4b575f80fd5b813567ffffffffffffffff811115611a61575f80fd5b611a6d84828501611821565b949350505050565b5f60208284031215611a85575f80fd5b813567ffffffffffffffff811115611a9b575f80fd5b8201608081850312156104d0575f80fd5b815173ffffffffffffffffffffffffffffffffffffffff16815261018081016020830151611af2602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151611b1a604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606083015160608301526080830151608083015260a0830151611b4660a084018263ffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b7b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f60208284031215611baa575f80fd5b5035919050565b5f806101a08385031215611bc3575f80fd5b611bcd8484611931565b915061018083013567ffffffffffffffff811115611be9575f80fd5b611bf585828601611821565b9150509250929050565b5f60208284031215611c0f575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561137857611378611c16565b808202811582820484141761137857611378611c16565b8181038181111561137857611378611c16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081528151602082015273ffffffffffffffffffffffffffffffffffffffff60208301511660408201525f604083015160806060840152611d1160a0840182611c80565b9050606084015160808401528091505092915050565b5f6113783683611821565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152813560208201525f6020830135611d93816117fd565b73ffffffffffffffffffffffffffffffffffffffff811660408401525060408301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611de4575f80fd5b830160208101903567ffffffffffffffff811115611e00575f80fd5b803603821315611e0e575f80fd5b60806060850152611e2360a085018284611d32565b915050606084013560808401528091505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff80861683528085166020840152506060604083015261141d6060830184611c80565b5f8060408385031215611e83575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82611ecf57611ecf611e94565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f611a6d6040830184611c80565b5f63ffffffff80841680611f2f57611f2f611e94565b92169190910492915050565b63ffffffff818116838216028082169190828114611f5b57611f5b611c16565b505092915050565b63ffffffff818116838216019080821115611f8057611f80611c16565b509291505056fea2646970667358221220e3fb228b525d90b942c7e58fe2e2034a17bd258c082fd47740e764a7be45bac664736f6c63430008190033a26469706673582212201190cf42f989cee23f12597c8c1e9daab6d8c816513349c3ce7fd229cae5b0ff64736f6c63430008190033", @@ -1428,5 +1251,184 @@ }, "version": 1 }, - "id": 170 + "id": 170, + "_disabled": [ + { + "type": "function", + "name": "disableTrading", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getTradeableOrderWithSignature", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" + }, + { + "name": "params", + "type": "tuple", + "internalType": "struct IConditionalOrder.ConditionalOrderParams", + "components": [ + { + "name": "handler", + "type": "address", + "internalType": "contract IConditionalOrder" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "staticInput", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "", + "type": "bytes32[]", + "internalType": "bytes32[]" + } + ], + "outputs": [ + { + "name": "order", + "type": "tuple", + "internalType": "struct GPv2Order.Data", + "components": [ + { + "name": "sellToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "kind", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sellTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "buyTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "settler", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ISettlement" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "updateParameters", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" + }, + { + "name": "minTradedToken0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceOracle", + "type": "address", + "internalType": "contract IPriceOracle" + }, + { + "name": "priceOracleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } + ] } diff --git a/crates/contracts/artifacts/CowAmmFactoryGetter.json b/contracts/artifacts/CowAmmFactoryGetter.json similarity index 100% rename from crates/contracts/artifacts/CowAmmFactoryGetter.json rename to contracts/artifacts/CowAmmFactoryGetter.json diff --git a/crates/contracts/artifacts/CowAmmLegacyHelper.json b/contracts/artifacts/CowAmmLegacyHelper.json similarity index 99% rename from crates/contracts/artifacts/CowAmmLegacyHelper.json rename to contracts/artifacts/CowAmmLegacyHelper.json index 391823f88c..892d1e1d16 100644 --- a/crates/contracts/artifacts/CowAmmLegacyHelper.json +++ b/contracts/artifacts/CowAmmLegacyHelper.json @@ -6,73 +6,59 @@ "stateMutability": "nonpayable" }, { - "type": "function", - "name": "factory", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getSnapshot", + "type": "event", + "name": "COWAMMPoolCreated", "inputs": [ { "name": "amm", "type": "address", + "indexed": true, "internalType": "address" } ], - "outputs": [ - { - "name": "", - "type": "bytes", - "internalType": "bytes" - } - ], - "stateMutability": "view" + "anonymous": false }, { - "type": "function", - "name": "isLegacy", - "inputs": [ - { - "name": "amm", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" + "type": "error", + "name": "InvalidArrayLength", + "inputs": [] + }, + { + "type": "error", + "name": "MathOverflowedMulDiv", + "inputs": [] + }, + { + "type": "error", + "name": "NoOrder", + "inputs": [] + }, + { + "type": "error", + "name": "PoolDoesNotExist", + "inputs": [] + }, + { + "type": "error", + "name": "PoolIsClosed", + "inputs": [] + }, + { + "type": "error", + "name": "PoolIsPaused", + "inputs": [] }, { "type": "function", - "name": "isLegacyEnabled", - "inputs": [ + "name": "factory", + "inputs": [], + "outputs": [ { - "name": "amm", + "name": "", "type": "address", "internalType": "address" } ], - "outputs": [ - { - "name": "success", - "type": "bool", - "internalType": "bool" - } - ], "stateMutability": "view" }, { @@ -228,49 +214,6 @@ } ], "stateMutability": "view" - }, - { - "type": "event", - "name": "COWAMMPoolCreated", - "inputs": [ - { - "name": "amm", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "InvalidArrayLength", - "inputs": [] - }, - { - "type": "error", - "name": "MathOverflowedMulDiv", - "inputs": [] - }, - { - "type": "error", - "name": "NoOrder", - "inputs": [] - }, - { - "type": "error", - "name": "PoolDoesNotExist", - "inputs": [] - }, - { - "type": "error", - "name": "PoolIsClosed", - "inputs": [] - }, - { - "type": "error", - "name": "PoolIsPaused", - "inputs": [] } ], "bytecode": "0x608060405234801561000f575f80fd5b5061001861001d565b6102ff565b46600181900361011257610044739941fd7db2003308e7ee17b04400012278f12ac66102c9565b61006173b3bf81714f704720dcb0351ff0d42eca61b069fc6102c9565b61007e73301076c36e034948a747bb61bab9cd03f62672e36102c9565b61009b73027e1cbf2c299cba5eb8a2584910d04f1a8aa4036102c9565b6100b873beef5afe88ef73337e5070ab2855d37dbf5493a46102c9565b6100d573c6b13d5e662fa0458f03995bcb824a1934aa895f6102c9565b6100f273d7cb8cc1b56356bb7b78d02e785ead28e21586606102c9565b61010f73079c868f97aed8e0d03f11e1529c3b056ff21cea6102c9565b50565b8060640361010f5761013773bc6159fd429be18206e60b3bb01d7289f905511b6102c9565b61015473e5d1aa8565f5dbfc06cde20dfd76b4c7c6d43bd56102c9565b610171739d8570ef9a519ca81daec35212f435d9843ba5646102c9565b61018e73d97c31e53f16f495715ce71e12e11b9545eedd8b6102c9565b6101ab73ff1bd3d570e3544c183ba77f5a4d3cc742c8d2b36102c9565b6101c873209d269dfd66b9cec764de7eb6fefc24f75bdd486102c9565b6101e573c37575ad8efe530fd8a79aeb0087e5872a24dabc6102c9565b610202731c7828dadade12a848f36be8e2d3146462abff686102c9565b61021f73aba5294bba7d3635c2a3e44d0e87ea7f58898fb76102c9565b61023c736eb7be972aebb6be2d9acf437cb412c0abee912b6102c9565b61025973c4d09969aad7f252c75dd352bbbd719e34ed06ad6102c9565b61027673a25af86a5dbea45e9fd70c1879489f63d081ad446102c9565b6102937357492cb6c8ee2998e9d83ddc8c713e781ffe548e6102c9565b6102b073c33e3ec14556a8e71be3097fe2dc8c0b9119c8976102c9565b61010f7377472826875953374ed3084c31a483f827987f145b6040516001600160a01b038216907f0d03834d0d86c7f57e877af40e26f176dc31bd637535d4ba153d1ac9de88a7ea905f90a250565b6156848061030c5f395ff3fe608060405234801561000f575f80fd5b506004361061006f575f3560e01c80632aec79a01161004d5780632aec79a0146100de578063c45a0155146100f1578063e48603391461011e575f80fd5b806310029daa14610073578063215702561461009b57806327242c9b146100bb575b5f80fd5b610086610081366004612462565b61013e565b60405190151581526020015b60405180910390f35b6100ae6100a9366004612462565b61050c565b60405161009291906124c9565b6100ce6100c93660046124db565b610cc6565b60405161009294939291906126e9565b6100866100ec366004612462565b61132d565b6100f9611340565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610092565b61013161012c366004612462565b611410565b6040516100929190612734565b6040517f5624b25b0000000000000000000000000000000000000000000000000000000081527f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d56004820152600160248201525f90819073ffffffffffffffffffffffffffffffffffffffff841690635624b25b906044015f60405180830381865afa1580156101d0573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610215919081019061288a565b80602001905181019061022891906128c4565b90505f732f55e8b20d0b9fefa187aa7d00b6cbe563605bf573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161490505f73fdafc9d1902f4e0b84f65f49f244b32b31013b7473ffffffffffffffffffffffffffffffffffffffff16732f55e8b20d0b9fefa187aa7d00b6cbe563605bf573ffffffffffffffffffffffffffffffffffffffff166351cad5ee87739008d19f58aabd9ed0d60971565aa8510560ab4173ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034e91906128df565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401602060405180830381865afa1580156103ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103de91906128c4565b73ffffffffffffffffffffffffffffffffffffffff161490505f6104018661050c565b80602001905181019061041491906128f6565b90505f73fdafc9d1902f4e0b84f65f49f244b32b31013b7473ffffffffffffffffffffffffffffffffffffffff16636108c532888460405160200161045991906129cf565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b81526004016104ad92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b602060405180830381865afa1580156104c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104ec91906129e1565b90508380156104f85750825b80156105015750805b979650505050505050565b60604660018190036107bd5773ffffffffffffffffffffffffffffffffffffffff8316739941fd7db2003308e7ee17b04400012278f12ac60361056c57604051806101e001604052806101c0815260200161482f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673b3bf81714f704720dcb0351ff0d42eca61b069fc036105c057604051806101e001604052806101c081526020016150ef6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673301076c36e034948a747bb61bab9cd03f62672e30361061457604051806101e001604052806101c0815260200161364f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673027e1cbf2c299cba5eb8a2584910d04f1a8aa4030361066857604051806101e001604052806101c08152602001612d2f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673beef5afe88ef73337e5070ab2855d37dbf5493a4036106bc57604051806101e001604052806101c081526020016142ef6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c6b13d5e662fa0458f03995bcb824a1934aa895f0361071057604051806101e001604052806101c0815260200161412f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673d7cb8cc1b56356bb7b78d02e785ead28e21586600361076457604051806101e001604052806101c081526020016139cf6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673079c868f97aed8e0d03f11e1529c3b056ff21cea036107b857604051806101e001604052806101c081526020016149ef6101c091399392505050565b610cb1565b80606403610cb15773ffffffffffffffffffffffffffffffffffffffff831673bc6159fd429be18206e60b3bb01d7289f905511b0361081957604051806101e001604052806101c08152602001612eef6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673e5d1aa8565f5dbfc06cde20dfd76b4c7c6d43bd50361086d57604051806101e001604052806101c0815260200161466f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff8316739d8570ef9a519ca81daec35212f435d9843ba564036108c157604051806101e001604052806101c08152602001614baf6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673d97c31e53f16f495715ce71e12e11b9545eedd8b036109155760405180610240016040528061022081526020016130af61022091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673ff1bd3d570e3544c183ba77f5a4d3cc742c8d2b30361096957604051806101e001604052806101c0815260200161548f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673209d269dfd66b9cec764de7eb6fefc24f75bdd48036109bd57604051806101e001604052806101c08152602001614f2f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c37575ad8efe530fd8a79aeb0087e5872a24dabc03610a1157604051806101e001604052806101c0815260200161348f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff8316731c7828dadade12a848f36be8e2d3146462abff6803610a6557604051806101e001604052806101c08152602001613f6f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673aba5294bba7d3635c2a3e44d0e87ea7f58898fb703610ab957604051806101e001604052806101c08152602001614d6f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff8316736eb7be972aebb6be2d9acf437cb412c0abee912b03610b0d57604051806101e001604052806101c081526020016132cf6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c4d09969aad7f252c75dd352bbbd719e34ed06ad03610b61576040518061024001604052806102208152602001613d4f61022091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673a25af86a5dbea45e9fd70c1879489f63d081ad4403610bb557604051806101e001604052806101c081526020016144af6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff83167357492cb6c8ee2998e9d83ddc8c713e781ffe548e03610c09576040518061020001604052806101e081526020016152af6101e091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c33e3ec14556a8e71be3097fe2dc8c0b9119c89703610c5d57604051806101e001604052806101c0815260200161380f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff83167377472826875953374ed3084c31a483f827987f1403610cb157604051806101e001604052806101c08152602001613b8f6101c091399392505050565b505060408051602081019091525f8152919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526060808060028514610d64576040517f9d89020a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060610d6f8861132d565b6112e957610d7c88611696565b610de7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f506f6f6c206973206e6f74206120436f5720414d4d000000000000000000000060448201526064015b60405180910390fd5b5f8873ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e5591906128c4565b90505f8973ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ec591906128c4565b90508973ffffffffffffffffffffffffffffffffffffffff16634ada218b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f10573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3491906129e1565b15155f03610f6e576040517f21081abf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110816040518060c001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018b8b6001818110610fe357610fe3612a00565b9050602002013581526020018b8b5f81811061100157611001612a00565b9050602002013581526020018c73ffffffffffffffffffffffffffffffffffffffff16636dbc88136040518163ffffffff1660e01b8152600401602060405180830381865afa158015611056573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061107a91906128df565b905261174e565b9650866040516020016110949190612a2d565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815260018084528383019092529450816020015b60408051606080820183525f8083526020830152918101919091528152602001906001900390816110d157905050955060405180606001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020015f815260200161123b739008d19f58aabd9ed0d60971565aa8510560ab4173ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561118e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111b291906128df565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08b0180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60405160240161124d91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff14fcbc8000000000000000000000000000000000000000000000000000000001790529052865187905f906112d7576112d7612a00565b602002602001018190525050506112ff565b6112f4888888611ad6565b929750909550935090505b8781604051602001611312929190612a3c565b60405160208183030381529060405291505093509350935093565b5f806113388361050c565b511192915050565b5f46600181900361136657738deed8ed7c5fcb55884f13f121654bb4bb7c843791505090565b8060640361138957732af6c59fc957d4a45ddbbd927fa30f7c5051f58391505090565b8062aa36a7036113ae5773bd18758055dbe3ed37a2471394559ae97a5da5c091505090565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e737570706f7274656420636861696e0000000000000000000000000000006044820152606401610dde565b60408051600280825260608083018452926020830190803683370190505090506114398261132d565b6115b5578173ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611486573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114aa91906128c4565b815f815181106114bc576114bc612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561153f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061156391906128c4565b8160018151811061157657611576612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050919050565b5f6115bf8361215f565b509050805f815181106115d4576115d4612a00565b6020026020010151825f815181106115ee576115ee612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060018151811061163b5761163b612a00565b60200260200101518260018151811061165657611656612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505050919050565b5f806116a0611340565b6040517f666e1b3900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152919091169063666e1b3990602401602060405180830381865afa15801561170c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061173091906128c4565b73ffffffffffffffffffffffffffffffffffffffff16141592915050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152602082015182516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201525f92839216906370a0823190602401602060405180830381865afa158015611822573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061184691906128df565b604085810151865191517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529116906370a0823190602401602060405180830381865afa1580156118b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118db91906128df565b915091505f805f805f8860800151876118f49190612aae565b90505f8960600151876119079190612aae565b90508181101561196d578960200151955089604001519450611939818b6080015160026119349190612aae565b61227b565b61194460028a612af2565b61194e9190612b05565b9350611966848861195f828c612b05565b60016122cb565b92506119b9565b8960400151955089602001519450611990828b6060015160026119349190612aae565b61199b600289612af2565b6119a59190612b05565b93506119b6848961195f828b612b05565b92505b6040518061018001604052808773ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200185815260200184815260200161012c42611a339190612b18565b63ffffffff1681526020018b60a0015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981525098505050505050505050919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526060806060611b448761013e565b611b7a576040517fefc869b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b858961215f565b915091505f8160400151806020019051810190611ba29190612b3c565b9050611c836040518060c001604052808c73ffffffffffffffffffffffffffffffffffffffff168152602001855f81518110611be057611be0612a00565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16815260200185600181518110611c1657611c16612a00565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018b8b6001818110611c4c57611c4c612a00565b9050602002013581526020018b8b5f818110611c6a57611c6a612a00565b9050602002013581526020018360a0015181525061174e565b96505f739008d19f58aabd9ed0d60971565aa8510560ab4173ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ce3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d0791906128df565b9050807fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48989604051602001611d3c9190612a2d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181525f60608401818152608085018452845260208085018a9052835180820185529182528484019190915291519092611da092909101612bf4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611dde94939291602401612c9d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f5fd7e97d000000000000000000000000000000000000000000000000000000001790528151600180825281840190935292975082015b60408051606080820183525f808352602083015291810191909152815260200190600190039081611e685790505060408051606081018252855173ffffffffffffffffffffffffffffffffffffffff1681525f602082015291985081018c611f558b857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60405173ffffffffffffffffffffffffffffffffffffffff90921660248301526044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30f73c99000000000000000000000000000000000000000000000000000000001790529052875188905f9061200757612007612a00565b602090810291909101015260408051600180825281830190925290816020015b60408051606080820183525f8083526020830152918101919091528152602001906001900390816120275790505095506040518060600160405280845f015173ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020018c5f801b6040516024016120bd92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30f73c99000000000000000000000000000000000000000000000000000000001790529052865187905f9061214757612147612a00565b60200260200101819052505050505093509350935093565b60408051606081810183525f80835260208301529181018290526121828361050c565b80602001905181019061219591906128f6565b90505f81604001518060200190518101906121b09190612b3c565b6040805160028082526060820183529293509190602083019080368337019050509250805f0151835f815181106121e9576121e9612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080602001518360018151811061223b5761223b612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505050915091565b5f815f036122945761228d8284612af2565b90506122c5565b82156122c057816122a6600185612b05565b6122b09190612af2565b6122bb906001612ccd565b6122c2565b5f5b90505b92915050565b5f806122d886868661231a565b90506122e383612412565b80156122fe57505f84806122f9576122f9612ac5565b868809115b156123115761230e600182612ccd565b90505b95945050505050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f0361236d5783828161236357612363612ac5565b049250505061240b565b8084116123a6576040517f227bc15300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b5f600282600381111561242757612427612ce0565b6124319190612d0d565b60ff166001149050919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461245f575f80fd5b50565b5f60208284031215612472575f80fd5b813561240b8161243e565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6122c2602083018461247d565b5f805f604084860312156124ed575f80fd5b83356124f88161243e565b9250602084013567ffffffffffffffff80821115612514575f80fd5b818601915086601f830112612527575f80fd5b813581811115612535575f80fd5b8760208260051b8501011115612549575f80fd5b6020830194508093505050509250925092565b805173ffffffffffffffffffffffffffffffffffffffff168252602081015161259d602084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408101516125c5604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608301526080810151608083015260a08101516125f160a084018263ffffffff169052565b5060c081015160c083015260e081015160e0830152610100808201518184015250610120808201516126268285018215159052565b5050610140818101519083015261016090810151910152565b5f82825180855260208086019550808260051b8401018186015f5b848110156126dc578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00189528151805173ffffffffffffffffffffffffffffffffffffffff16845284810151858501526040908101516060918501829052906126c88186018361247d565b9a86019a945050509083019060010161265a565b5090979650505050505050565b5f6101e06126f7838861255c565b8061018084015261270a8184018761263f565b90508281036101a084015261271f818661263f565b90508281036101c0840152610501818561247d565b602080825282518282018190525f9190848201906040850190845b8181101561278157835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161274f565b50909695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160c0810167ffffffffffffffff811182821017156127dd576127dd61278d565b60405290565b5f82601f8301126127f2575f80fd5b815167ffffffffffffffff8082111561280d5761280d61278d565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156128535761285361278d565b8160405283815286602085880101111561286b575f80fd5b8360208701602083015e5f602085830101528094505050505092915050565b5f6020828403121561289a575f80fd5b815167ffffffffffffffff8111156128b0575f80fd5b6128bc848285016127e3565b949350505050565b5f602082840312156128d4575f80fd5b815161240b8161243e565b5f602082840312156128ef575f80fd5b5051919050565b5f60208284031215612906575f80fd5b815167ffffffffffffffff8082111561291d575f80fd5b9083019060608286031215612930575f80fd5b60405160608101818110838211171561294b5761294b61278d565b60405282516129598161243e565b815260208381015190820152604083015182811115612976575f80fd5b612982878286016127e3565b60408301525095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8151168252602081015160208301525f6040820151606060408501526128bc606085018261247d565b602081525f6122c26020830184612991565b5f602082840312156129f1575f80fd5b8151801515811461240b575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b61018081016122c5828461255c565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008360601b1681525f82518060208501601485015e5f92016014019182525092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820281158282048414176122c5576122c5612a81565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82612b0057612b00612ac5565b500490565b818103818111156122c5576122c5612a81565b63ffffffff818116838216019080821115612b3557612b35612a81565b5092915050565b5f60208284031215612b4c575f80fd5b815167ffffffffffffffff80821115612b63575f80fd5b9083019060c08286031215612b76575f80fd5b612b7e6127ba565b8251612b898161243e565b81526020830151612b998161243e565b6020820152604083810151908201526060830151612bb68161243e565b6060820152608083015182811115612bcc575f80fd5b612bd8878286016127e3565b60808301525060a083015160a082015280935050505092915050565b602080825282516060838301528051608084018190525f9291820190839060a08601905b80831015612c385783518252928401926001929092019190840190612c18565b508387015193507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0925082868203016040870152612c768185612991565b93505050604085015181858403016060860152612c93838261247d565b9695505050505050565b848152836020820152608060408201525f612cbb608083018561247d565b8281036060840152610501818561247d565b808201808211156122c5576122c5612a81565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60ff831680612d1f57612d1f612ac5565b8060ff8416069150509291505056fe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424dac5a0e756ac88c1d3a4c41900d977fe93c2d34fc95a00ca3e84eb4c6b50faf949000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000005afe3855358e112b5647b952709e6165e1c1eeee000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000200000000000000000000000002e7e978da0c53404a8cf66ed4ba2c7706c07b62a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851d85c99996d84d25387bc0d01e50e3ea814f64e7e04a3b949a571789e196c5a910000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006a023ccd1ff6f2045c3309768ead9e68f978f6e1000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000000000000000000000000000000affd9fdeb8e08000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020a99fd9950b5d5dceeaf4939e221dca8ca9b938ab0001000000000000000000250000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85178a729ee3008c7d48832d02267b72e5f34ada8f554a6731a368f01590ed71b34000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cb444e90d8198415266c6a2724b7900fb12fc56e000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d0000000000000000000000000000000000000000000000008156197a5425c0c8000000000000000000000000bd91a72dc3d9b5d9b16ee8638da1fc65311bd90a00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000080000000000000000000000000ab70bcb260073d036d1660201e9d5405f5829b7a000000000000000000000000678df3415fc31947da4324ec63212874be5a82f8000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a8512e31981e34960969eb549f5e826cf77f655e72b03603ad574a79fd015f4de4de0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea6000000000000000000000000af204776c7245bf4147c2612bf6e5972ee483701000000000000000000000000000000000000000000000000000a16c95a4d2e3c000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c0ce9e05c2aee5f22f9941c4cd1f1a1d13194b109779422d5ad9a980157bd0f1640000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f90002000000000000000000630000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851a2029fbb545978d05378b6df19e3754fe5ed2d0ba1e051027503934372f7beb20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb000000000000000000000000177127622c4a00f3d409b75571e12cb3c8973d3c0000000000000000000000000000000000000000000000000052ba9efc38441a000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c89000000000000000000000000000000000000000000000000000000000000002021d4c792ea7e38e0d0819c2011a2b1cb7252bd9900020000000000000000001e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424daca44b6a304baa16d11b6db07066c1276b1273ee3f94590bbd03201a61882af9a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000098cb76000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85159457ac6201da7713efecd84618c7a168e88b9cb7d1c0db128af1efe0a08bbb10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea6000000000000000000000000af204776c7245bf4147c2612bf6e5972ee483701000000000000000000000000000000000000000000000000000a17273fc14b64000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f9000200000000000000000063000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da80ba533f014ef4238ab7ad203c0aeacbf30a71c0346140db77c43ae3121afadd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000aea46a60368a7bd060eec7df8cba43b7ef41ad85000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000336632e53c8ecf04000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000200000000000000000000000004042a04c54ef133ac2a3c93db69d43c6c02a330b0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851d67c9fb87045e07da94c81de035b5c7f435cd46568fca02aa35d709bbc9e21fa0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008e5bbbb09ed1ebde8674cda39a0c169401db4252000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000e089049027b95c2745d1a954bc1d245352d884e900000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000200000000000000000000000008db8870ca4b8ac188c4d1a014f34a381ae27e1c20000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851209c17d9ebe3ac7352795f7f8b3d14d253d92430831d3b2c3965f9a578da7618000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d0000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea60000000000000000000000000000000000000000000000008aa3a52815262f58000000000000000000000000bd91a72dc3d9b5d9b16ee8638da1fc65311bd90a00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000064ac007ff665cf8d0d3af5e0ad1c26a3f853ea000000000000000000000000a767f745331d267c7751297d982b050c93985627000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85105416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f418080000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb000000000000000000000000ce11e14225575945b8e6dc0d4f2dd4c570f79d9f000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000009634ca647474b6b78d3382331a77cd00a8a940da00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da932542294ff270a8bbdbe1fb921de3d09c9749dc35627361fc17c44b9b026b810000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008390a1da07e376ef7add4be859ba74fb83aa02d5000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000aec1c94998000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c89000000000000000000000000000000000000000000000000000000000000002000000000000000000000000069c66beafb06674db41b22cfc50c34a93b8d82a2000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000def1ca1fb7fbcdc777520aa7f396b4e015f497ab000000000000000000000000000000000000000000000000025bf6196bd10000000000000000000000000000ad37fe3ddedf8cdee1022da1b17412cfb649559600000000000000000000000000000000000000000000000000000000000000c0d661a16b0e85eadb705cf5158132b5dd1ebc0a49929ef68097698d15e2a4e3b40000000000000000000000000000000000000000000000000000000000000020de8c195aa41c11a0c4787372defbbddaa31306d20002000000000000000001810000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851560d33bcc26b7f10765f8ae10b1abc4ed265ba0c7a1f9948d06de97c31044aee0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004d18815d14fe5c3304e87b3fa18318baa5c238200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a9b2234773cc6a4f3a34a770c52c931cba5c24b20002000000000000000000870000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851437a72b19b25e8b62fdfb81146ec83c66462138d3d9e08998594853566fa9add000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000177127622c4a00f3d409b75571e12cb3c8973d3c0000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea600000000000000000000000000000000000000000000000146e114355e0f6088000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000204cdabe9e07ca393943acfb9286bbbd0d0a310ff600020000000000000000005c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da559d5fda20be80608e4d5ea1b41e6b9330efca7934beb094281dd4d8f4889374000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000079ef7f110fdfae4000000000000000000000000ad37fe3ddedf8cdee1022da1b17412cfb649559600000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020e99481dc77691d8e2456e5f3f61c1810adfc1503000200000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da56871afb17e444c418900f6db3e1ade07d49eadea1accf03fcebc0a6e7e4b653000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b2617246d0c6c0087f18703d576831899ca94f01000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000048bcb79dba2b56b90000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b36ec83d844c0579ec2493f10b2087e96bb654600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a8511ea56ac96a6369d36ef3fe56ae0ddff8d0cc89e1623095239c5ceed2505aa2810000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb0000000000000000000000006a023ccd1ff6f2045c3309768ead9e68f978f6e1000000000000000000000000000000000000000000000000006b43c27d2e8300000000000000000000000000e089049027b95c2745d1a954bc1d245352d884e900000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c89000000000000000000000000000000000000000000000000000000000000002000000000000000000000000028dbd35fd79f48bfa9444d330d14683e7101d8170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851d1e868d120e326e5581caa39852bb0da9234a511ed76e6f7a9dcceb0d5f154c70000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea6000000000000000000000000af204776c7245bf4147c2612bf6e5972ee48370100000000000000000000000000000000000000000000000000098e46995425ca000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f90002000000000000000000630000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851f0e8ec512b2507dae99175a0a4792d8a53e0863fbb5e735a5c993295bbd17f480000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea60000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb00000000000000000000000000000000000000000000000000094f8d9168e271000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000204683e340a8049261057d5ab1b29c8d840e75695e00020000000000000000005a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424dad003838829115f5d9ff3ed69c8d2b4b26e10eb1a79331206c28fbb4734390a5e000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000808507121b80c02388fad14726482e061b8da827000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000189b23422a9b84d8000000000000000000000000ad37fe3ddedf8cdee1022da1b17412cfb649559600000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020fd1cf6fd41f229ca86ada0584c63c49c3d66bbc90002000000000000000004380000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a8513956efd63537b00bb3b152d3c4961207b6ca14d6f506c66fc0aef4c8e2e176b5000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cb444e90d8198415266c6a2724b7900fb12fc56e0000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb000000000000000000000000000000000000000000000000000000000000004500000000000000000000000015b4c67070d3748b8ec93c8a32f7efe2e8f684c900000000000000000000000000000000000000000000000000000000000000c0056e9806d953dbe2df4352a90ad2c1148c51460e941107f0909fae382b1661cf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000022441d81416430a54336ab28765abd31a792ad37000000000000000000000000ab70bcb260073d036d1660201e9d5405f5829b7a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85133f583d55c4509d5e10ebe3c7c69bce17af4c57419d6c9c90c8f588dd3232c0d000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000af204776c7245bf4147c2612bf6e5972ee4837010000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea600000000000000000000000000000000000000000000000410d586a20a4c0000000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f9000200000000000000000063a2646970667358221220c3b6b701e7d5db53232efcebe1fe1bdd40a35653449ba7cd10551b9e5bf6a94a64736f6c63430008190033", @@ -1079,5 +1022,64 @@ }, "version": 1 }, - "id": 126 + "id": 126, + "_disabled": [ + { + "type": "function", + "name": "getSnapshot", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isLegacy", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isLegacyEnabled", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "success", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + } + ] } diff --git a/crates/contracts/artifacts/CowAmmUniswapV2PriceOracle.json b/contracts/artifacts/CowAmmUniswapV2PriceOracle.json similarity index 99% rename from crates/contracts/artifacts/CowAmmUniswapV2PriceOracle.json rename to contracts/artifacts/CowAmmUniswapV2PriceOracle.json index c232352da2..0016f79051 100644 --- a/crates/contracts/artifacts/CowAmmUniswapV2PriceOracle.json +++ b/contracts/artifacts/CowAmmUniswapV2PriceOracle.json @@ -1,40 +1,5 @@ { - "abi": [ - { - "type": "function", - "name": "getPrice", - "inputs": [ - { - "name": "token0", - "type": "address", - "internalType": "address" - }, - { - "name": "token1", - "type": "address", - "internalType": "address" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ - { - "name": "priceNumerator", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "priceDenominator", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - } - ], + "abi": [], "bytecode": "0x6080604052348015600e575f80fd5b506105468061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063355efdd91461002d575b5f80fd5b61004061003b366004610386565b610059565b6040805192835260208301919091520160405180910390f35b5f808061006884860186610411565b9050805f015173ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156100b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100da91906104a2565b826dffffffffffffffffffffffffffff169250816dffffffffffffffffffffffffffff1691505080935081945050505f815f015173ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610156573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061017a91906104ee565b90505f825f015173ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ed91906104ee565b90508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff160361022757929392905b8173ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff16146102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e300000000000000000000060448201526064015b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e310000000000000000000060448201526064016102b8565b50505094509492505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610383575f80fd5b50565b5f805f8060608587031215610399575f80fd5b84356103a481610362565b935060208501356103b481610362565b9250604085013567ffffffffffffffff808211156103d0575f80fd5b818701915087601f8301126103e3575f80fd5b8135818111156103f1575f80fd5b886020828501011115610402575f80fd5b95989497505060200194505050565b5f60208284031215610421575f80fd5b6040516020810181811067ffffffffffffffff82111715610469577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604052823561047781610362565b81529392505050565b80516dffffffffffffffffffffffffffff8116811461049d575f80fd5b919050565b5f805f606084860312156104b4575f80fd5b6104bd84610480565b92506104cb60208501610480565b9150604084015163ffffffff811681146104e3575f80fd5b809150509250925092565b5f602082840312156104fe575f80fd5b815161050981610362565b939250505056fea26469706673582212201fe6ad4d6b89d204db5394bdedef23d10ed8c7e4f83be4c5fe14dcc09470223464736f6c63430008190033", "deployedBytecode": "0x608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063355efdd91461002d575b5f80fd5b61004061003b366004610386565b610059565b6040805192835260208301919091520160405180910390f35b5f808061006884860186610411565b9050805f015173ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156100b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100da91906104a2565b826dffffffffffffffffffffffffffff169250816dffffffffffffffffffffffffffff1691505080935081945050505f815f015173ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610156573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061017a91906104ee565b90505f825f015173ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ed91906104ee565b90508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff160361022757929392905b8173ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff16146102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e300000000000000000000060448201526064015b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e310000000000000000000060448201526064016102b8565b50505094509492505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610383575f80fd5b50565b5f805f8060608587031215610399575f80fd5b84356103a481610362565b935060208501356103b481610362565b9250604085013567ffffffffffffffff808211156103d0575f80fd5b818701915087601f8301126103e3575f80fd5b8135818111156103f1575f80fd5b886020828501011115610402575f80fd5b95989497505060200194505050565b5f60208284031215610421575f80fd5b6040516020810181811067ffffffffffffffff82111715610469577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604052823561047781610362565b81529392505050565b80516dffffffffffffffffffffffffffff8116811461049d575f80fd5b919050565b5f805f606084860312156104b4575f80fd5b6104bd84610480565b92506104cb60208501610480565b9150604084015163ffffffff811681146104e3575f80fd5b809150509250925092565b5f602082840312156104fe575f80fd5b815161050981610362565b939250505056fea26469706673582212201fe6ad4d6b89d204db5394bdedef23d10ed8c7e4f83be4c5fe14dcc09470223464736f6c63430008190033", "methodIdentifiers": { @@ -171,5 +136,41 @@ }, "version": 1 }, - "id": 178 + "id": 178, + "_disabled": [ + { + "type": "function", + "name": "getPrice", + "inputs": [ + { + "name": "token0", + "type": "address", + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "priceNumerator", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceDenominator", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + ] } diff --git a/crates/contracts/artifacts/CowProtocolToken.json b/contracts/artifacts/CowProtocolToken.json similarity index 99% rename from crates/contracts/artifacts/CowProtocolToken.json rename to contracts/artifacts/CowProtocolToken.json index 11d6f90755..6e7084fb0c 100644 --- a/crates/contracts/artifacts/CowProtocolToken.json +++ b/contracts/artifacts/CowProtocolToken.json @@ -99,32 +99,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "MAX_YEARLY_INFLATION", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "TIME_BETWEEN_MINTINGS", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -192,19 +166,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "cowDao", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "decimals", @@ -218,78 +179,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "subtractedValue", - "type": "uint256" - } - ], - "name": "decreaseAllowance", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "offset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "getStorageAt", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "addedValue", - "type": "uint256" - } - ], - "name": "increaseAllowance", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -407,38 +296,83 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { "internalType": "address", - "name": "targetContract", + "name": "recipient", "type": "address" }, { - "internalType": "bytes", - "name": "calldataPayload", - "type": "bytes" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "simulateDelegatecallInternal", + "name": "transfer", "outputs": [ { - "internalType": "bytes", - "name": "response", - "type": "bytes" + "internalType": "bool", + "name": "", + "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6101806040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c96101405260006006553480156200003c57600080fd5b5060405162002122380380620021228339810160408190526200005f916200035f565b8282826040518060400160405280601281526020017121b7ab90283937ba37b1b7b6102a37b5b2b760711b81525060405180604001604052806003815260200162434f5760e81b8152508180604051806040016040528060018152602001603160f81b81525084848160039080519060200190620000df9291906200029c565b508051620000f59060049060208401906200029c565b5050825160209384012082519284019290922060e08390526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818901819052818301979097526060810194909452608080850193909352308483018190528151808603909301835260c09485019091528151919096012090529290925261012052506200019590508584620001b4565b5050506001600160a01b03166101605250504260065550620004049050565b6001600160a01b0382166200020f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b8060026000828254620002239190620003a0565b90915550506001600160a01b0382166000908152602081905260408120805483929062000252908490620003a0565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b828054620002aa90620003c7565b90600052602060002090601f016020900481019282620002ce576000855562000319565b82601f10620002e957805160ff191683800117855562000319565b8280016001018555821562000319579182015b8281111562000319578251825591602001919060010190620002fc565b50620003279291506200032b565b5090565b5b808211156200032757600081556001016200032c565b80516001600160a01b03811681146200035a57600080fd5b919050565b6000806000606084860312156200037557600080fd5b620003808462000342565b9250620003906020850162000342565b9150604084015190509250925092565b60008219821115620003c257634e487b7160e01b600052601160045260246000fd5b500190565b600181811c90821680620003dc57607f821691505b60208210811415620003fe57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e05161010051610120516101405161016051611cb1620004716000396000818161033a01526105a10152600061096401526000611135015260006111840152600061115f015260006110b8015260006110e20152600061110c0152611cb16000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c806370a08231116100d8578063cd42dcbe1161008c578063e2d5148911610066578063e2d5148914610335578063f84436bd14610381578063fde9e07a1461039457600080fd5b8063cd42dcbe146102d1578063d505accf146102dc578063dd62ed3e146102ef57600080fd5b806395d89b41116100bd57806395d89b41146102a3578063a457c2d7146102ab578063a9059cbb146102be57600080fd5b806370a082311461025a5780637ecebe001461029057600080fd5b80633644e5151161013a57806343218e191161011457806343218e191461022c5780635624b25b1461023f5780635862bf3d1461025257600080fd5b80633644e515146101fc578063395093511461020457806340c10f191461021757600080fd5b806318160ddd1161016b57806318160ddd146101c857806323b872dd146101da578063313ce567146101ed57600080fd5b806306fdde0314610187578063095ea7b3146101a5575b600080fd5b61018f61039d565b60405161019c91906117aa565b60405180910390f35b6101b86101b33660046117ed565b61042f565b604051901515815260200161019c565b6002545b60405190815260200161019c565b6101b86101e8366004611817565b610446565b6040516012815260200161019c565b6101cc610531565b6101b86102123660046117ed565b610540565b61022a6102253660046117ed565b610589565b005b61018f61023a366004611882565b6106af565b61018f61024d366004611962565b610751565b6101cc600381565b6101cc610268366004611984565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101cc61029e366004611984565b6107d7565b61018f610802565b6101b86102b93660046117ed565b610811565b6101b86102cc3660046117ed565b6108e9565b6101cc6301e1338081565b61022a6102ea36600461199f565b6108f6565b6101cc6102fd366004611a12565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b61035c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61018f61038f366004611882565b610ab5565b6101cc60065481565b6060600380546103ac90611a45565b80601f01602080910402602001604051908101604052809291908181526020018280546103d890611a45565b80156104255780601f106103fa57610100808354040283529160200191610425565b820191906000526020600020905b81548152906001019060200180831161040857829003601f168201915b5050505050905090565b600061043c338484610c36565b5060015b92915050565b6000610453848484610de9565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482811015610519576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206160448201527f6c6c6f77616e636500000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6105268533858403610c36565b506001949350505050565b600061053b61109e565b905090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161043c918590610584908690611ac2565b610c36565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105f8576040517ffe72c36e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064600361060560025490565b61060f9190611ada565b6106199190611b17565b811115610652576040517f2c6af20800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426301e133806006546106659190611ac2565b111561069d576040517f7b06471500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426006556106ab82826111d2565b5050565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040516106d89190611b52565b600060405180830381855af49150503d8060008114610713576040519150601f19603f3d011682016040523d82523d6000602084013e610718565b606091505b5060405190935090915061074a906107369084908490602001611b6e565b6040516020818303038152906040526112f2565b5092915050565b60606000610760836020611ada565b67ffffffffffffffff81111561077857610778611853565b6040519080825280601f01601f1916602001820160405280156107a2576020820181803683370190505b50905060005b838110156107cf5784810154602080830284010152806107c781611b96565b9150506107a8565b509392505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260056020526040812054610440565b6060600480546103ac90611a45565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156108d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610510565b6108df3385858403610c36565b5060019392505050565b600061043c338484610de9565b83421115610960576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610510565b60007f000000000000000000000000000000000000000000000000000000000000000088888861098f8c6112fa565b60408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060006109f78261132f565b90506000610a0782878787611398565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610510565b610aa98a8a8a610c36565b50505050505050505050565b606060006343218e1960e01b8484604051602401610ad4929190611bcf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290519091503090610b63908390611b52565b6000604051808303816000865af19150503d8060008114610ba0576040519150601f19603f3d011682016040523d82523d6000602084013e610ba5565b606091505b5090508092505060008260018451610bbd9190611c06565b81518110610bcd57610bcd611c1d565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b149050610c188360018551610c149190611c06565b9052565b8015610c25575050610440565b610c2e836112f2565b505092915050565b73ffffffffffffffffffffffffffffffffffffffff8316610cd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff8216610d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316610e8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff8216610f2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610fe5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220858503905591851681529081208054849290611029908490611ac2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161108f91815260200190565b60405180910390a35b50505050565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801561110457507f000000000000000000000000000000000000000000000000000000000000000046145b1561112e57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b73ffffffffffffffffffffffffffffffffffffffff821661124f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610510565b80600260008282546112619190611ac2565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061129b908490611ac2565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b805160208201fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526005602052604090208054600181018255905b50919050565b600061044061133c61109e565b836040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006113a9878787876113c0565b915091506113b6816114d8565b5095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156113f757506000905060036114cf565b8460ff16601b1415801561140f57508460ff16601c14155b1561142057506000905060046114cf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611474573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166114c8576000600192509250506114cf565b9150600090505b94509492505050565b60008160048111156114ec576114ec611c4c565b14156114f55750565b600181600481111561150957611509611c4c565b1415611571576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610510565b600281600481111561158557611585611c4c565b14156115ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610510565b600381600481111561160157611601611c4c565b141561168f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610510565b60048160048111156116a3576116a3611c4c565b1415611731576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610510565b50565b60005b8381101561174f578181015183820152602001611737565b838111156110985750506000910152565b60008151808452611778816020860160208601611734565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006117bd6020830184611760565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146117e857600080fd5b919050565b6000806040838503121561180057600080fd5b611809836117c4565b946020939093013593505050565b60008060006060848603121561182c57600080fd5b611835846117c4565b9250611843602085016117c4565b9150604084013590509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561189557600080fd5b61189e836117c4565b9150602083013567ffffffffffffffff808211156118bb57600080fd5b818501915085601f8301126118cf57600080fd5b8135818111156118e1576118e1611853565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561192757611927611853565b8160405282815288602084870101111561194057600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000806040838503121561197557600080fd5b50508035926020909101359150565b60006020828403121561199657600080fd5b6117bd826117c4565b600080600080600080600060e0888a0312156119ba57600080fd5b6119c3886117c4565b96506119d1602089016117c4565b95506040880135945060608801359350608088013560ff811681146119f557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611a2557600080fd5b611a2e836117c4565b9150611a3c602084016117c4565b90509250929050565b600181811c90821680611a5957607f821691505b60208210811415611329577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611ad557611ad5611a93565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611b1257611b12611a93565b500290565b600082611b4d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008251611b64818460208701611734565b9190910192915050565b60008351611b80818460208801611734565b92151560f81b9190920190815260010192915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611bc857611bc8611a93565b5060010190565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000611bfe6040830184611760565b949350505050565b600082821015611c1857611c18611a93565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220530954a1b40a0e3c6d45330c16c5bf384a847ba06bf8ebbb9afdfb09ada68c0b64736f6c634300080a0033", + "_disabled": [ { "inputs": [], - "name": "symbol", + "name": "MAX_YEARLY_INFLATION", "outputs": [ { - "internalType": "string", + "internalType": "uint256", "name": "", - "type": "string" + "type": "uint256" } ], "stateMutability": "view", @@ -446,7 +380,7 @@ }, { "inputs": [], - "name": "timestampLastMinting", + "name": "TIME_BETWEEN_MINTINGS", "outputs": [ { "internalType": "uint256", @@ -459,12 +393,12 @@ }, { "inputs": [], - "name": "totalSupply", + "name": "cowDao", "outputs": [ { - "internalType": "uint256", + "internalType": "address", "name": "", - "type": "uint256" + "type": "address" } ], "stateMutability": "view", @@ -474,16 +408,16 @@ "inputs": [ { "internalType": "address", - "name": "recipient", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "subtractedValue", "type": "uint256" } ], - "name": "transfer", + "name": "decreaseAllowance", "outputs": [ { "internalType": "bool", @@ -497,22 +431,41 @@ { "inputs": [ { - "internalType": "address", - "name": "sender", - "type": "address" + "internalType": "uint256", + "name": "offset", + "type": "uint256" }, + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "getStorageAt", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "address", - "name": "recipient", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "addedValue", "type": "uint256" } ], - "name": "transferFrom", + "name": "increaseAllowance", "outputs": [ { "internalType": "bool", @@ -522,7 +475,56 @@ ], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "targetContract", + "type": "address" + }, + { + "internalType": "bytes", + "name": "calldataPayload", + "type": "bytes" + } + ], + "name": "simulateDelegatecallInternal", + "outputs": [ + { + "internalType": "bytes", + "name": "response", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "timestampLastMinting", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" } - ], - "bytecode": "0x6101806040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c96101405260006006553480156200003c57600080fd5b5060405162002122380380620021228339810160408190526200005f916200035f565b8282826040518060400160405280601281526020017121b7ab90283937ba37b1b7b6102a37b5b2b760711b81525060405180604001604052806003815260200162434f5760e81b8152508180604051806040016040528060018152602001603160f81b81525084848160039080519060200190620000df9291906200029c565b508051620000f59060049060208401906200029c565b5050825160209384012082519284019290922060e08390526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818901819052818301979097526060810194909452608080850193909352308483018190528151808603909301835260c09485019091528151919096012090529290925261012052506200019590508584620001b4565b5050506001600160a01b03166101605250504260065550620004049050565b6001600160a01b0382166200020f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b8060026000828254620002239190620003a0565b90915550506001600160a01b0382166000908152602081905260408120805483929062000252908490620003a0565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b828054620002aa90620003c7565b90600052602060002090601f016020900481019282620002ce576000855562000319565b82601f10620002e957805160ff191683800117855562000319565b8280016001018555821562000319579182015b8281111562000319578251825591602001919060010190620002fc565b50620003279291506200032b565b5090565b5b808211156200032757600081556001016200032c565b80516001600160a01b03811681146200035a57600080fd5b919050565b6000806000606084860312156200037557600080fd5b620003808462000342565b9250620003906020850162000342565b9150604084015190509250925092565b60008219821115620003c257634e487b7160e01b600052601160045260246000fd5b500190565b600181811c90821680620003dc57607f821691505b60208210811415620003fe57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e05161010051610120516101405161016051611cb1620004716000396000818161033a01526105a10152600061096401526000611135015260006111840152600061115f015260006110b8015260006110e20152600061110c0152611cb16000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c806370a08231116100d8578063cd42dcbe1161008c578063e2d5148911610066578063e2d5148914610335578063f84436bd14610381578063fde9e07a1461039457600080fd5b8063cd42dcbe146102d1578063d505accf146102dc578063dd62ed3e146102ef57600080fd5b806395d89b41116100bd57806395d89b41146102a3578063a457c2d7146102ab578063a9059cbb146102be57600080fd5b806370a082311461025a5780637ecebe001461029057600080fd5b80633644e5151161013a57806343218e191161011457806343218e191461022c5780635624b25b1461023f5780635862bf3d1461025257600080fd5b80633644e515146101fc578063395093511461020457806340c10f191461021757600080fd5b806318160ddd1161016b57806318160ddd146101c857806323b872dd146101da578063313ce567146101ed57600080fd5b806306fdde0314610187578063095ea7b3146101a5575b600080fd5b61018f61039d565b60405161019c91906117aa565b60405180910390f35b6101b86101b33660046117ed565b61042f565b604051901515815260200161019c565b6002545b60405190815260200161019c565b6101b86101e8366004611817565b610446565b6040516012815260200161019c565b6101cc610531565b6101b86102123660046117ed565b610540565b61022a6102253660046117ed565b610589565b005b61018f61023a366004611882565b6106af565b61018f61024d366004611962565b610751565b6101cc600381565b6101cc610268366004611984565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101cc61029e366004611984565b6107d7565b61018f610802565b6101b86102b93660046117ed565b610811565b6101b86102cc3660046117ed565b6108e9565b6101cc6301e1338081565b61022a6102ea36600461199f565b6108f6565b6101cc6102fd366004611a12565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b61035c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61018f61038f366004611882565b610ab5565b6101cc60065481565b6060600380546103ac90611a45565b80601f01602080910402602001604051908101604052809291908181526020018280546103d890611a45565b80156104255780601f106103fa57610100808354040283529160200191610425565b820191906000526020600020905b81548152906001019060200180831161040857829003601f168201915b5050505050905090565b600061043c338484610c36565b5060015b92915050565b6000610453848484610de9565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482811015610519576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206160448201527f6c6c6f77616e636500000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6105268533858403610c36565b506001949350505050565b600061053b61109e565b905090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161043c918590610584908690611ac2565b610c36565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105f8576040517ffe72c36e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064600361060560025490565b61060f9190611ada565b6106199190611b17565b811115610652576040517f2c6af20800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426301e133806006546106659190611ac2565b111561069d576040517f7b06471500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426006556106ab82826111d2565b5050565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040516106d89190611b52565b600060405180830381855af49150503d8060008114610713576040519150601f19603f3d011682016040523d82523d6000602084013e610718565b606091505b5060405190935090915061074a906107369084908490602001611b6e565b6040516020818303038152906040526112f2565b5092915050565b60606000610760836020611ada565b67ffffffffffffffff81111561077857610778611853565b6040519080825280601f01601f1916602001820160405280156107a2576020820181803683370190505b50905060005b838110156107cf5784810154602080830284010152806107c781611b96565b9150506107a8565b509392505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260056020526040812054610440565b6060600480546103ac90611a45565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156108d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610510565b6108df3385858403610c36565b5060019392505050565b600061043c338484610de9565b83421115610960576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610510565b60007f000000000000000000000000000000000000000000000000000000000000000088888861098f8c6112fa565b60408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060006109f78261132f565b90506000610a0782878787611398565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610510565b610aa98a8a8a610c36565b50505050505050505050565b606060006343218e1960e01b8484604051602401610ad4929190611bcf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290519091503090610b63908390611b52565b6000604051808303816000865af19150503d8060008114610ba0576040519150601f19603f3d011682016040523d82523d6000602084013e610ba5565b606091505b5090508092505060008260018451610bbd9190611c06565b81518110610bcd57610bcd611c1d565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b149050610c188360018551610c149190611c06565b9052565b8015610c25575050610440565b610c2e836112f2565b505092915050565b73ffffffffffffffffffffffffffffffffffffffff8316610cd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff8216610d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316610e8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff8216610f2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610fe5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220858503905591851681529081208054849290611029908490611ac2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161108f91815260200190565b60405180910390a35b50505050565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801561110457507f000000000000000000000000000000000000000000000000000000000000000046145b1561112e57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b73ffffffffffffffffffffffffffffffffffffffff821661124f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610510565b80600260008282546112619190611ac2565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061129b908490611ac2565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b805160208201fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526005602052604090208054600181018255905b50919050565b600061044061133c61109e565b836040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006113a9878787876113c0565b915091506113b6816114d8565b5095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156113f757506000905060036114cf565b8460ff16601b1415801561140f57508460ff16601c14155b1561142057506000905060046114cf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611474573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166114c8576000600192509250506114cf565b9150600090505b94509492505050565b60008160048111156114ec576114ec611c4c565b14156114f55750565b600181600481111561150957611509611c4c565b1415611571576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610510565b600281600481111561158557611585611c4c565b14156115ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610510565b600381600481111561160157611601611c4c565b141561168f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610510565b60048160048111156116a3576116a3611c4c565b1415611731576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610510565b50565b60005b8381101561174f578181015183820152602001611737565b838111156110985750506000910152565b60008151808452611778816020860160208601611734565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006117bd6020830184611760565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146117e857600080fd5b919050565b6000806040838503121561180057600080fd5b611809836117c4565b946020939093013593505050565b60008060006060848603121561182c57600080fd5b611835846117c4565b9250611843602085016117c4565b9150604084013590509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561189557600080fd5b61189e836117c4565b9150602083013567ffffffffffffffff808211156118bb57600080fd5b818501915085601f8301126118cf57600080fd5b8135818111156118e1576118e1611853565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561192757611927611853565b8160405282815288602084870101111561194057600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000806040838503121561197557600080fd5b50508035926020909101359150565b60006020828403121561199657600080fd5b6117bd826117c4565b600080600080600080600060e0888a0312156119ba57600080fd5b6119c3886117c4565b96506119d1602089016117c4565b95506040880135945060608801359350608088013560ff811681146119f557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611a2557600080fd5b611a2e836117c4565b9150611a3c602084016117c4565b90509250929050565b600181811c90821680611a5957607f821691505b60208210811415611329577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611ad557611ad5611a93565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611b1257611b12611a93565b500290565b600082611b4d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008251611b64818460208701611734565b9190910192915050565b60008351611b80818460208801611734565b92151560f81b9190920190815260010192915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611bc857611bc8611a93565b5060010190565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000611bfe6040830184611760565b949350505050565b600082821015611c1857611c18611a93565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220530954a1b40a0e3c6d45330c16c5bf384a847ba06bf8ebbb9afdfb09ada68c0b64736f6c634300080a0033" + ] } diff --git a/crates/contracts/artifacts/ERC1271SignatureValidator.json b/contracts/artifacts/ERC1271SignatureValidator.json similarity index 100% rename from crates/contracts/artifacts/ERC1271SignatureValidator.json rename to contracts/artifacts/ERC1271SignatureValidator.json diff --git a/crates/contracts/artifacts/ERC20.json b/contracts/artifacts/ERC20.json similarity index 99% rename from crates/contracts/artifacts/ERC20.json rename to contracts/artifacts/ERC20.json index fcfdab8026..028a5b1ce0 100644 --- a/crates/contracts/artifacts/ERC20.json +++ b/contracts/artifacts/ERC20.json @@ -147,43 +147,45 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, + "inputs": [], + "name": "name", + "outputs": [ { - "internalType": "uint256", - "name": "subtractedValue", - "type": "uint256" + "internalType": "string", + "name": "", + "type": "string" } ], - "name": "decreaseAllowance", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", "outputs": [ { - "internalType": "bool", + "internalType": "string", "name": "", - "type": "bool" + "type": "string" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", - "name": "spender", + "name": "recipient", "type": "address" }, { "internalType": "uint256", - "name": "addedValue", + "name": "amount", "type": "uint256" } ], - "name": "increaseAllowance", + "name": "transfer", "outputs": [ { "internalType": "bool", @@ -195,58 +197,50 @@ "type": "function" }, { - "inputs": [], - "name": "name", - "outputs": [ + "inputs": [ { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ + "internalType": "address", + "name": "sender", + "type": "address" + }, { - "internalType": "string", - "name": "", - "type": "string" + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", + "name": "transferFrom", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [ { "internalType": "address", - "name": "recipient", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "subtractedValue", "type": "uint256" } ], - "name": "transfer", + "name": "decreaseAllowance", "outputs": [ { "internalType": "bool", @@ -261,21 +255,16 @@ "inputs": [ { "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "addedValue", "type": "uint256" } ], - "name": "transferFrom", + "name": "increaseAllowance", "outputs": [ { "internalType": "bool", @@ -285,6 +274,19 @@ ], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" } ] } diff --git a/crates/contracts/artifacts/ERC20Mintable.json b/contracts/artifacts/ERC20Mintable.json similarity index 99% rename from crates/contracts/artifacts/ERC20Mintable.json rename to contracts/artifacts/ERC20Mintable.json index 2c0b0740c7..bda0b6acda 100644 --- a/crates/contracts/artifacts/ERC20Mintable.json +++ b/contracts/artifacts/ERC20Mintable.json @@ -76,21 +76,6 @@ "name": "Transfer", "type": "event" }, - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "addMinter", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, { "constant": true, "inputs": [ @@ -169,16 +154,16 @@ "inputs": [ { "internalType": "address", - "name": "spender", + "name": "account", "type": "address" }, { "internalType": "uint256", - "name": "subtractedValue", + "name": "amount", "type": "uint256" } ], - "name": "decreaseAllowance", + "name": "mint", "outputs": [ { "internalType": "bool", @@ -195,16 +180,16 @@ "inputs": [ { "internalType": "address", - "name": "spender", + "name": "recipient", "type": "address" }, { "internalType": "uint256", - "name": "addedValue", + "name": "amount", "type": "uint256" } ], - "name": "increaseAllowance", + "name": "transfer", "outputs": [ { "internalType": "bool", @@ -217,32 +202,16 @@ "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "internalType": "address", - "name": "account", + "name": "sender", "type": "address" - } - ], - "name": "isMinter", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ + }, { "internalType": "address", - "name": "account", + "name": "recipient", "type": "address" }, { @@ -251,7 +220,7 @@ "type": "uint256" } ], - "name": "mint", + "name": "transferFrom", "outputs": [ { "internalType": "bool", @@ -262,29 +231,49 @@ "payable": false, "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "bytecode": "0x608060405262000024620000186200002a60201b60201c565b6200003260201b60201c565b62000257565b600033905090565b6200004d8160036200009360201b620012a81790919060201c565b8073ffffffffffffffffffffffffffffffffffffffff167f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f660405160405180910390a250565b620000a582826200017760201b60201c565b1562000119576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650081525060200191505060405180910390fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141562000200576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180620018506022913960400191505060405180910390fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6115e980620002676000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063983b2d5611610071578063983b2d56146102e7578063986502751461032b578063a457c2d714610335578063a9059cbb1461039b578063aa271e1a14610401578063dd62ed3e1461045d576100b4565b8063095ea7b3146100b957806318160ddd1461011f57806323b872dd1461013d57806339509351146101c357806340c10f191461022957806370a082311461028f575b600080fd5b610105600480360360408110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104d5565b604051808215151515815260200191505060405180910390f35b6101276104f3565b6040518082815260200191505060405180910390f35b6101a96004803603606081101561015357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104fd565b604051808215151515815260200191505060405180910390f35b61020f600480360360408110156101d957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105d6565b604051808215151515815260200191505060405180910390f35b6102756004803603604081101561023f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610689565b604051808215151515815260200191505060405180910390f35b6102d1600480360360208110156102a557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610704565b6040518082815260200191505060405180910390f35b610329600480360360208110156102fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061074c565b005b6103336107bd565b005b6103816004803603604081101561034b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506107cf565b604051808215151515815260200191505060405180910390f35b6103e7600480360360408110156103b157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061089c565b604051808215151515815260200191505060405180910390f35b6104436004803603602081101561041757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108ba565b604051808215151515815260200191505060405180910390f35b6104bf6004803603604081101561047357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108d7565b6040518082815260200191505060405180910390f35b60006104e96104e261095e565b8484610966565b6001905092915050565b6000600254905090565b600061050a848484610b5d565b6105cb8461051661095e565b6105c6856040518060600160405280602881526020016114fd60289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061057c61095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b610966565b600190509392505050565b600061067f6105e361095e565b8461067a85600160006105f461095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b610966565b6001905092915050565b600061069b61069661095e565b6108ba565b6106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806114ac6030913960400191505060405180910390fd5b6106fa8383610f5b565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b61075c61075761095e565b6108ba565b6107b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806114ac6030913960400191505060405180910390fd5b6107ba81611116565b50565b6107cd6107c861095e565b611170565b565b60006108926107dc61095e565b8461088d85604051806060016040528060258152602001611590602591396001600061080661095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b610966565b6001905092915050565b60006108b06108a961095e565b8484610b5d565b6001905092915050565b60006108d08260036111ca90919063ffffffff16565b9050919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156109ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602481526020018061156c6024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610a72576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806114646022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610be3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806115476025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610c69576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806114416023913960400191505060405180910390fd5b610cd481604051806060016040528060268152602001611486602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610d67816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610ec0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610e85578082015181840152602081019050610e6a565b50505050905090810190601f168015610eb25780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610f51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610ffe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b61101381600254610ed390919063ffffffff16565b60028190555061106a816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b61112a8160036112a890919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f660405160405180910390a250565b61118481600361138390919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167fe94479a9f7e1952cc78f2d6baab678adc1b772d936c6583def489e524cb6669260405160405180910390a250565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611251576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806115256022913960400191505060405180910390fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6112b282826111ca565b15611325576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650081525060200191505060405180910390fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b61138d82826111ca565b6113e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806114dc6021913960400191505060405180910390fd5b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63654d696e746572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865204d696e74657220726f6c65526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c6545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365526f6c65733a206163636f756e7420697320746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a7231582056e4b738cf76f0838e717d12794ecbbd6278399c81f9192ab9d5f01d5c4c3baf64736f6c63430005100032526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373", + "_disabled": [ { "constant": false, - "inputs": [], - "name": "renounceMinter", + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "addMinter", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, { "internalType": "uint256", - "name": "", + "name": "subtractedValue", "type": "uint256" } ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { @@ -292,16 +281,16 @@ "inputs": [ { "internalType": "address", - "name": "recipient", + "name": "spender", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "addedValue", "type": "uint256" } ], - "name": "transfer", + "name": "increaseAllowance", "outputs": [ { "internalType": "bool", @@ -314,25 +303,15 @@ "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", + "name": "account", "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" } ], - "name": "transferFrom", + "name": "isMinter", "outputs": [ { "internalType": "bool", @@ -341,9 +320,32 @@ } ], "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "renounceMinter", + "outputs": [], + "payable": false, "stateMutability": "nonpayable", "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" } - ], - "bytecode": "0x608060405262000024620000186200002a60201b60201c565b6200003260201b60201c565b62000257565b600033905090565b6200004d8160036200009360201b620012a81790919060201c565b8073ffffffffffffffffffffffffffffffffffffffff167f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f660405160405180910390a250565b620000a582826200017760201b60201c565b1562000119576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650081525060200191505060405180910390fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141562000200576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180620018506022913960400191505060405180910390fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6115e980620002676000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063983b2d5611610071578063983b2d56146102e7578063986502751461032b578063a457c2d714610335578063a9059cbb1461039b578063aa271e1a14610401578063dd62ed3e1461045d576100b4565b8063095ea7b3146100b957806318160ddd1461011f57806323b872dd1461013d57806339509351146101c357806340c10f191461022957806370a082311461028f575b600080fd5b610105600480360360408110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104d5565b604051808215151515815260200191505060405180910390f35b6101276104f3565b6040518082815260200191505060405180910390f35b6101a96004803603606081101561015357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104fd565b604051808215151515815260200191505060405180910390f35b61020f600480360360408110156101d957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105d6565b604051808215151515815260200191505060405180910390f35b6102756004803603604081101561023f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610689565b604051808215151515815260200191505060405180910390f35b6102d1600480360360208110156102a557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610704565b6040518082815260200191505060405180910390f35b610329600480360360208110156102fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061074c565b005b6103336107bd565b005b6103816004803603604081101561034b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506107cf565b604051808215151515815260200191505060405180910390f35b6103e7600480360360408110156103b157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061089c565b604051808215151515815260200191505060405180910390f35b6104436004803603602081101561041757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108ba565b604051808215151515815260200191505060405180910390f35b6104bf6004803603604081101561047357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108d7565b6040518082815260200191505060405180910390f35b60006104e96104e261095e565b8484610966565b6001905092915050565b6000600254905090565b600061050a848484610b5d565b6105cb8461051661095e565b6105c6856040518060600160405280602881526020016114fd60289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061057c61095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b610966565b600190509392505050565b600061067f6105e361095e565b8461067a85600160006105f461095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b610966565b6001905092915050565b600061069b61069661095e565b6108ba565b6106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806114ac6030913960400191505060405180910390fd5b6106fa8383610f5b565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b61075c61075761095e565b6108ba565b6107b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806114ac6030913960400191505060405180910390fd5b6107ba81611116565b50565b6107cd6107c861095e565b611170565b565b60006108926107dc61095e565b8461088d85604051806060016040528060258152602001611590602591396001600061080661095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b610966565b6001905092915050565b60006108b06108a961095e565b8484610b5d565b6001905092915050565b60006108d08260036111ca90919063ffffffff16565b9050919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156109ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602481526020018061156c6024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610a72576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806114646022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610be3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806115476025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610c69576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806114416023913960400191505060405180910390fd5b610cd481604051806060016040528060268152602001611486602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610d67816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610ec0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610e85578082015181840152602081019050610e6a565b50505050905090810190601f168015610eb25780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610f51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610ffe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b61101381600254610ed390919063ffffffff16565b60028190555061106a816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b61112a8160036112a890919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f660405160405180910390a250565b61118481600361138390919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167fe94479a9f7e1952cc78f2d6baab678adc1b772d936c6583def489e524cb6669260405160405180910390a250565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611251576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806115256022913960400191505060405180910390fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6112b282826111ca565b15611325576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650081525060200191505060405180910390fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b61138d82826111ca565b6113e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806114dc6021913960400191505060405180910390fd5b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63654d696e746572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865204d696e74657220726f6c65526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c6545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365526f6c65733a206163636f756e7420697320746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a7231582056e4b738cf76f0838e717d12794ecbbd6278399c81f9192ab9d5f01d5c4c3baf64736f6c63430005100032526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373" + ] } diff --git a/crates/contracts/artifacts/FlashLoanRouter.json b/contracts/artifacts/FlashLoanRouter.json similarity index 99% rename from crates/contracts/artifacts/FlashLoanRouter.json rename to contracts/artifacts/FlashLoanRouter.json index a4349a5917..97c8710b21 100644 --- a/crates/contracts/artifacts/FlashLoanRouter.json +++ b/contracts/artifacts/FlashLoanRouter.json @@ -11,19 +11,6 @@ ], "stateMutability": "nonpayable" }, - { - "type": "function", - "name": "borrowerCallback", - "inputs": [ - { - "name": "encodedLoansWithSettlement", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, { "type": "function", "name": "flashLoanAndSettle", @@ -64,19 +51,6 @@ "outputs": [], "stateMutability": "nonpayable" }, - { - "type": "function", - "name": "settlementAuthentication", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract ICowAuthentication" - } - ], - "stateMutability": "view" - }, { "type": "function", "name": "settlementContract", @@ -291,5 +265,33 @@ }, "version": 1 }, - "id": 27 + "id": 27, + "_disabled": [ + { + "type": "function", + "name": "borrowerCallback", + "inputs": [ + { + "name": "encodedLoansWithSettlement", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settlementAuthentication", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ICowAuthentication" + } + ], + "stateMutability": "view" + } + ] } diff --git a/crates/contracts/artifacts/GPv2AllowListAuthentication.json b/contracts/artifacts/GPv2AllowListAuthentication.json similarity index 99% rename from crates/contracts/artifacts/GPv2AllowListAuthentication.json rename to contracts/artifacts/GPv2AllowListAuthentication.json index 84221396bd..7dfa98f4de 100644 --- a/crates/contracts/artifacts/GPv2AllowListAuthentication.json +++ b/contracts/artifacts/GPv2AllowListAuthentication.json @@ -58,30 +58,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "offset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "getStorageAt", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -140,19 +116,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "manager_", - "type": "address" - } - ], - "name": "setManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -176,30 +139,6 @@ ], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "targetContract", - "type": "address" - }, - { - "internalType": "bytes", - "name": "calldataPayload", - "type": "bytes" - } - ], - "name": "simulateDelegatecallInternal", - "outputs": [ - { - "internalType": "bytes", - "name": "response", - "type": "bytes" - } - ], - "stateMutability": "nonpayable", - "type": "function" } ], "bytecode": "0x608060405234801561001057600080fd5b50610e10806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80637f7120fe11610076578063d0ebdbe71161005b578063d0ebdbe7146102e3578063ec58f4b814610316578063f84436bd14610349576100a3565b80637f7120fe1461027b5780638fd57b92146102b0576100a3565b806302cc250d146100a857806343218e19146100ef578063481c6a75146102275780635624b25b14610258575b600080fd5b6100db600480360360208110156100be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661040c565b604080519115158252519081900360200190f35b6101b26004803603604081101561010557600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561013d57600080fd5b82018360208201111561014f57600080fd5b8035906020019184600183028401116401000000008311171561017157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610437945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101ec5781810151838201526020016101d4565b50505050905090810190601f1680156102195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61022f6105af565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101b26004803603604081101561026e57600080fd5b50803590602001356105d1565b6102ae6004803603602081101561029157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610647565b005b6102ae600480360360208110156102c657600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166107f8565b6102ae600480360360208110156102f957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610907565b6102ae6004803603602081101561032c57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610a47565b6101b26004803603604081101561035f57600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561039757600080fd5b8201836020820111156103a957600080fd5b803590602001918460018302840111640100000000831117156103cb57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610b5a945050505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205460ff1690565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b602083106104a057805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610463565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114610500576040519150601f19603f3d011682016040523d82523d6000602084013e610505565b606091505b5080935081925050506105a882826040516020018083805190602001908083835b6020831061056357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610526565b6001836020036101000a03801982511681845116808217855250505050505090500182151560f81b815260010192505050604051602081830303815290604052610da3565b5092915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008260200267ffffffffffffffff811180156105ef57600080fd5b506040519080825280601f01601f19166020018201604052801561061a576020820181803683370190505b50905060005b8381101561063d5784810154602080830284010152600101610620565b5090505b92915050565b600054610100900460ff16806106605750610660610dab565b8061066e575060005460ff16155b6106d957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f496e697469616c697a61626c653a20696e697469616c697a6564000000000000604482015290519081900360640190fd5b600054610100900460ff1615801561073f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff851690810291909117825560408051918252602082019290925281517f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a4350929181900390910190a180156107f457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461088457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f475076323a2063616c6c6572206e6f74206d616e616765720000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811660008181526001602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055815192835290517f640e18a2587e1d83e4fdabf70257d0a800ca4b2c1aaad1dfc485a4ad8bbbd6c69281900390910190a150565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633148061094f575033610937610db1565b73ffffffffffffffffffffffffffffffffffffffff16145b6109ba57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f475076323a206e6f7420617574686f72697a6564000000000000000000000000604482015290519081900360640190fd5b6000805473ffffffffffffffffffffffffffffffffffffffff838116620100008181027fffffffffffffffffffff0000000000000000000000000000000000000000ffff85161790945560408051918252939092041660208201819052825190927f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a4350928290030190a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610ad357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f475076323a2063616c6c6572206e6f74206d616e616765720000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811660008181526001602081815260409283902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909217909155815192835290517f41f9d09dd5159251f8a8e482bbe097b7c01a5e6f70c5a0ddb494906464fc9dd79281900390910190a150565b606060006343218e1960e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610bc4578181015183820152602001610bac565b50505050905090810190601f168015610bf15780820380516001836020036101000a031916815260200191505b50604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909816979097178752518151919750309688965090945084935091508083835b60208310610cc257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c85565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610d24576040519150601f19603f3d011682016040523d82523d6000602084013e610d29565b606091505b50905080925050600082600184510381518110610d4257fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b149050610d85836001855103610dd6565b8015610d92575050610641565b610d9b83610da3565b505092915050565b805160208201fd5b303b1590565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905256fea26469706673582212207106ba36b2d518d89a5ce88705dd7f52d98f3a8c838b8bb7ad9cdaa5b4254ab164736f6c63430007060033", @@ -291,5 +230,68 @@ "kind": "user", "methods": {}, "version": 1 - } + }, + "_disabled": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "getStorageAt", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "manager_", + "type": "address" + } + ], + "name": "setManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "targetContract", + "type": "address" + }, + { + "internalType": "bytes", + "name": "calldataPayload", + "type": "bytes" + } + ], + "name": "simulateDelegatecallInternal", + "outputs": [ + { + "internalType": "bytes", + "name": "response", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] } diff --git a/crates/contracts/artifacts/GPv2Settlement.json b/contracts/artifacts/GPv2Settlement.json similarity index 99% rename from crates/contracts/artifacts/GPv2Settlement.json rename to contracts/artifacts/GPv2Settlement.json index 8d3a2c65a3..2fbbfb6403 100644 --- a/crates/contracts/artifacts/GPv2Settlement.json +++ b/contracts/artifacts/GPv2Settlement.json @@ -1,5 +1,24 @@ { "abi": [ + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "filledAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -147,6 +166,10 @@ "name": "Trade", "type": "event" }, + { + "stateMutability": "payable", + "type": "receive" + }, { "inputs": [], "name": "authenticator", @@ -173,75 +196,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "filledAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "orderUids", - "type": "bytes[]" - } - ], - "name": "freeFilledAmountStorage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "orderUids", - "type": "bytes[]" - } - ], - "name": "freePreSignatureStorage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "offset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "getStorageAt", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -255,25 +209,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "preSignature", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -418,30 +353,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "targetContract", - "type": "address" - }, - { - "internalType": "bytes", - "name": "calldataPayload", - "type": "bytes" - } - ], - "name": "simulateDelegatecallInternal", - "outputs": [ - { - "internalType": "bytes", - "name": "response", - "type": "bytes" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -574,10 +485,6 @@ ], "stateMutability": "view", "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" } ], "bytecode": "0x6101006040523480156200001257600080fd5b50604051620053eb380380620053eb83398101604081905262000035916200015b565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c828401527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf606080840191909152466080808501919091523060a08086019190915285518086038201815260c09586019687905280519401939093209052600180556001600160601b031986821b811690925284901b16905281906200010a906200014d565b62000116919062000199565b604051809103906000f08015801562000133573d6000803e3d6000fd5b5060601b6001600160601b03191660e05250620001c69050565b61129e806200414d83390190565b600080604083850312156200016e578182fd5b82516200017b81620001ad565b60208401519092506200018e81620001ad565b809150509250929050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114620001c357600080fd5b50565b60805160a05160601c60c05160601c60e05160601c613f2562000228600039806104c55280610d61528061109052806115f0525080610556528061158b52508061039252806106bc528061099d52508061131e52806123df5250613f256000f3fe6080604052600436106100ec5760003560e01c80639b552cc21161008a578063ed9f35ce11610059578063ed9f35ce14610274578063f698da2514610294578063f84436bd146102a9578063fbfa77cf146102c9576100f3565b80639b552cc2146101ff578063a2a7d51b14610214578063d08d33d114610234578063ec6cb13f14610254576100f3565b80632479fb6e116100c65780632479fb6e1461016557806343218e19146101925780635624b25b146101bf578063845a101f146101df576100f3565b806313d79a0b146100f857806315337bc01461011a5780632335c76b1461013a576100f3565b366100f357005b600080fd5b34801561010457600080fd5b5061011861011336600461322e565b6102de565b005b34801561012657600080fd5b50610118610135366004613441565b6105c1565b34801561014657600080fd5b5061014f6106ba565b60405161015c91906136ee565b60405180910390f35b34801561017157600080fd5b506101856101803660046134ca565b6106de565b60405161015c91906137f0565b34801561019e57600080fd5b506101b26101ad3660046131a0565b6106fb565b60405161015c919061380d565b3480156101cb57600080fd5b506101b26101da3660046134fd565b610873565b3480156101eb57600080fd5b506101186101fa36600461338e565b6108e9565b34801561020b57600080fd5b5061014f61108e565b34801561022057600080fd5b5061011861022f3660046131ee565b6110b2565b34801561024057600080fd5b5061018561024f3660046134ca565b6110fb565b34801561026057600080fd5b5061011861026f366004613475565b611118565b34801561028057600080fd5b5061011861028f3660046131ee565b6112d7565b3480156102a057600080fd5b5061018561131c565b3480156102b557600080fd5b506101b26102c43660046131a0565b611340565b3480156102d557600080fd5b5061014f611589565b6002600154141561035057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906302cc250d906103c79033906004016136ee565b60206040518083038186803b1580156103df57600080fd5b505afa1580156103f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104179190613425565b610456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b60405180910390fd5b6104728160005b60200281019061046d9190613d16565b6115ad565b6000806104838989898989896116ea565b6040517f7d10d11f000000000000000000000000000000000000000000000000000000008152919350915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637d10d11f906104fa90859060040161370f565b600060405180830381600087803b15801561051457600080fd5b505af1158015610528573d6000803e3d6000fd5b5050505061053c8360016003811061045d57fe5b61057c73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001682611851565b61058783600261045d565b60405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a250506001805550505050505050565b60006105cd8383611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff81163314610620576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a1b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600284846040516106539291906136c2565b9081526020016040518091039020819055508073ffffffffffffffffffffffffffffffffffffffff167f875b6cb035bbd4ac6500fabc6d1e4ca5bdc58a3e2b424ccb5c24cdbebeb009a984846040516106ad9291906137f9565b60405180910390a2505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b805160208183018101805160028252928201919093012091525481565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b6020831061076457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610727565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146107c4576040519150601f19603f3d011682016040523d82523d6000602084013e6107c9565b606091505b50809350819250505061086c82826040516020018083805190602001908083835b6020831061082757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107ea565b6001836020036101000a03801982511681845116808217855250505050505090500182151560f81b815260010192505050604051602081830303815290604052611bbd565b5092915050565b606060008260200267ffffffffffffffff8111801561089157600080fd5b506040519080825280601f01601f1916602001820160405280156108bc576020820181803683370190505b50905060005b838110156108df57848101546020808302840101526001016108c2565b5090505b92915050565b6002600154141561095b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906302cc250d906109d29033906004016136ee565b60206040518083038186803b1580156109ea57600080fd5b505afa1580156109fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a229190613425565b610a58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b6000610a62611bc5565b8051909150610a7382868686611bf2565b60007ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677582610100015114610aa8576001610aab565b60005b9050610ab5612f90565b60408085015173ffffffffffffffffffffffffffffffffffffffff90811683526101408501517f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce9081146020850152606080880151909216928401929092526101608501519091149082015260008667ffffffffffffffff81118015610b3a57600080fd5b50604051908082528060200260200182016040528015610b64578160200160208202803683370190505b50610100850151909150610120870135907ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467751415610c30578460800151811015610bda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c41565b610be78560600151611c90565b82886000013581518110610bf757fe5b602002602001018181525050610c0c81611c90565b60000382886020013581518110610c1f57fe5b602002602001018181525050610cc0565b8460600151811115610c6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b9c565b610c7781611c90565b82886000013581518110610c8757fe5b602002602001018181525050610ca08560800151611c90565b60000382886020013581518110610cb357fe5b6020026020010181815250505b610cc8612f90565b8660400151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560000151816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560e0015181604001818152505085610140015181606001818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634817a286878f8f8f8f8b8b8f60a001518b6040518a63ffffffff1660e01b8152600401610dcc99989796959493929190613877565b600060405180830381600087803b158015610de657600080fd5b505af1158015610dfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e4091908101906132ed565b90506000886020015190506000610e6d838c6000013581518110610e6057fe5b6020026020010151611d25565b90506000610e94848d6020013581518110610e8457fe5b6020026020010151600003611d25565b9050600283604051610ea691906136d2565b908152602001604051809103902054600014610eee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b7ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467758a61010001511415610f825789606001518214610f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613ac0565b8960600151600284604051610f6d91906136d2565b90815260405190819003602001902055610fe5565b89608001518114610fbf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613af7565b8960800151600284604051610fd491906136d2565b908152604051908190036020019020555b8a6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc178b600001518c6020015185858f60e001518960405161104596959493929190613820565b60405180910390a260405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a25050600180555050505050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b3033146110eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760008383611d96565b5050565b805160208183018101805160008252928201919093012091525481565b60006111248484611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff811633146111ac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f475076323a2063616e6e6f74207072657369676e206f72646572000000000000604482015290519081900360640190fd5b8115611206577ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c60008585604051808383808284378083019250505092505050908152602001604051809103902081905550611232565b600080858560405180838380828437919091019485525050604051928390036020019092209290925550505b8073ffffffffffffffffffffffffffffffffffffffff167f01bf7c8b0ca55deecbea89d7e58295b7ffbf685fd0d96801034ba8c6ffe1c68d858585604051808060200183151581526020018281038252858582818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a250505050565b303314611310576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760028383611d96565b7f000000000000000000000000000000000000000000000000000000000000000081565b606060006343218e1960e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156113aa578181015183820152602001611392565b50505050905090810190601f1680156113d75780820380516001836020036101000a031916815260200191505b50604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909816979097178752518151919750309688965090945084935091508083835b602083106114a857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161146b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461150a576040519150601f19603f3d011682016040523d82523d6000602084013e61150f565b606091505b5090508092505060008260018451038151811061152857fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b14905061156b836001855103611e46565b80156115785750506108e3565b61158183611bbd565b505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60005b818110156116e557368383838181106115c557fe5b90506020028101906115d79190613dde565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001661161d6020830183613184565b73ffffffffffffffffffffffffffffffffffffffff16141561166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613caf565b61167481611e4a565b6116816020820182613184565b73ffffffffffffffffffffffffffffffffffffffff167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356116c684611ea1565b6040516116d4929190613ce6565b60405180910390a2506001016115b0565b505050565b60608060006116f7611bc5565b90508367ffffffffffffffff8111801561171057600080fd5b5060405190808252806020026020018201604052801561174a57816020015b611737612f90565b81526020019060019003908161172f5790505b5092508367ffffffffffffffff8111801561176457600080fd5b5060405190808252806020026020018201604052801561179e57816020015b61178b612f90565b8152602001906001900390816117835790505b50915060005b8481101561184457368686838181106117b957fe5b90506020028101906117cb9190613e11565b90506117d9838c8c84611bf2565b61183b838a8a84358181106117ea57fe5b905060200201358b8b856020013581811061180157fe5b9050602002013584610120013589878151811061181a57fe5b602002602001015189888151811061182e57fe5b6020026020010151611ecb565b506001016117a4565b5050965096945050505050565b6000815167ffffffffffffffff8111801561186b57600080fd5b506040519080825280602002602001820160405280156118a557816020015b611892612fb7565b81526020019060019003908161188a5790505b5090506000805b8351811015611a935760008482815181106118c357fe5b6020026020010151905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1614156119c7577f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce81606001511415611977576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b2e565b8051604080830151905173ffffffffffffffffffffffffffffffffffffffff9092169181156108fc0291906000818181858888f193505050501580156119c1573d6000803e3d6000fd5b50611a8a565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981606001511415611a2657805160408201516020830151611a219273ffffffffffffffffffffffffffffffffffffffff90911691612216565b611a8a565b6000848480600101955081518110611a3a57fe5b602090810291909101810151600081528382015173ffffffffffffffffffffffffffffffffffffffff90811692820192909252604080850151908201523060608201528351909116608090910152505b506001016118ac565b508015611b2957611aa48282611e46565b6040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851690630e8e3e8490611af690859060040161375d565b600060405180830381600087803b158015611b1057600080fd5b505af1158015611b24573d6000803e3d6000fd5b505050505b50505050565b6000808060388414611ba257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f475076323a20696e76616c696420756964000000000000000000000000000000604482015290519081900360640190fd5b5050823593602084013560601c936034013560e01c92509050565b805160208201fd5b611bcd612fe7565b6040805160388082526060820190925290602082018180368337505050602082015290565b83516000611c02838686856122ee565b9050600080611c1f8484611c1a610140890189613d7b565b6123d6565b91509150611c4282828660a001518b60200151612485909392919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff81166040890152611c688482612507565b73ffffffffffffffffffffffffffffffffffffffff1660609098019790975250505050505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f53616665436173743a20696e74323536206f766572666c6f7700000000000000604482015290519081900360640190fd5b5090565b600080821215611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f53616665436173743a206e6f7420706f73697469766500000000000000000000604482015290519081900360640190fd5b60005b81811015611b2957366000848484818110611db057fe5b9050602002810190611dc29190613d7b565b915091506000611dd28383611b2f565b92505050428163ffffffff1610611e15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c0a565b6000878484604051611e289291906136c2565b90815260405190819003602001902055505060019091019050611d99565b9052565b73ffffffffffffffffffffffffffffffffffffffff8135166020820135366000611e776040860186613d7b565b9150915060405181838237600080838387895af1611e99573d6000803e3d6000fd5b505050505050565b60003681611eb26040850185613d7b565b909250905060048110611ec457813592505b5050919050565b8551602087015160a08201514263ffffffff9091161015611f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a52565b6080820151611f279087612539565b6060830151611f369089612539565b1015611f6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a89565b6000806000807ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775866101000151141561206f5785610120015115611fdb57889350611fd48660600151611fce868960e0015161253990919063ffffffff16565b906125c9565b9150611fea565b856060015193508560e0015191505b611ffe8a611ff8868e612539565b9061264a565b925061202a8460028760405161201491906136d2565b90815260405190819003602001902054906126e8565b9050856060015181111561206a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b612116565b856101200151156120a35788925061209c8660800151611fce858960e0015161253990919063ffffffff16565b91506120b2565b856080015192508560e0015191505b6120c08b611fce858d612539565b93506120d68360028760405161201491906136d2565b90508560800151811115612116576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b61212084836126e8565b93508060028660405161213391906136d2565b9081526020016040518091039020819055508b6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc17876000015188602001518787878b6040516121a196959493929190613820565b60405180910390a250506040808b015173ffffffffffffffffffffffffffffffffffffffff9081168852855181166020808a0191909152888301949094526101408601516060988901529a8701518b16865282850151909a169185019190915297830197909752610160015191015250505050565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff84166004830152602482018390529060008060448382895af1612279573d6000803e3d6000fd5b506122838461275c565b611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f475076323a206661696c6564207472616e736665720000000000000000000000604482015290519081900360640190fd5b6000838386358181106122fd57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168452508490849087013581811061233057fe5b73ffffffffffffffffffffffffffffffffffffffff602091820293909301358316908501525060408087013590911690830152606080860135908301526080808601359083015263ffffffff60a080870135919091169083015260c0808601359083015260e080860135908301526123ac610100860135612826565b61016087019190915261014086019190915290151561012085015261010090930152509392505050565b600080612403867f000000000000000000000000000000000000000000000000000000000000000061297b565b9150600085600381111561241357fe5b141561242b57612424828585612a05565b905061247c565b600185600381111561243957fe5b141561244a57612424828585612a1a565b600285600381111561245857fe5b141561246957612424828585612a82565b6124798285858960a00151612c20565b90505b94509492505050565b60388451146124f557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f7700000000000000604482015290519081900360640190fd5b60388401526034830152602090910152565b604082015160009073ffffffffffffffffffffffffffffffffffffffff166125305750806108e3565b50506040015190565b600082612548575060006108e3565b8282028284828161255557fe5b04146125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f536166654d6174683a206d756c206f766572666c6f7700000000000000000000604482015290519081900360640190fd5b9392505050565b600080821161263957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f536166654d6174683a206469766973696f6e2062792030000000000000000000604482015290519081900360640190fd5b81838161264257fe5b049392505050565b60008082116126ba57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f536166654d6174683a206365696c696e67206469766973696f6e206279203000604482015290519081900360640190fd5b8183816126c357fe5b06156126d05760016126d3565b60005b60ff168284816126df57fe5b04019392505050565b6000828201838110156125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600061279a565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452806024528160445260646000fd5b3d80156127d95760208114612813576127d47f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f612763565b612820565b823b61280a5761280a7f475076323a206e6f74206120636f6e74726163740000000000000000000000006014612763565b60019150612820565b3d6000803e600051151591505b50919050565b6000808080806001861661285c577ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467759450612880565b7f6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc94505b6002861615159350600886166128b8577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9925061290c565b600486166128e8577fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632925061290c565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce92505b6010861661293c577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc99150612960565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce91505b600586901c600381111561297057fe5b905091939590929450565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6000612a12848484612de5565b949350505050565b6000808460405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c01828152602001915050604051602081830303815290604052805190602001209050612a79818585612de5565b95945050505050565b813560601c366000612a978460148188613e68565b604080517f1626ba7e00000000000000000000000000000000000000000000000000000000808252600482018b81526024830193845260448301859052949650929450919273ffffffffffffffffffffffffffffffffffffffff871692631626ba7e928b928892889290606401848480828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201965060209550909350505081840390508186803b158015612b5d57600080fd5b505afa158015612b71573d6000803e3d6000fd5b505050506040513d6020811015612b8757600080fd5b50517fffffffff000000000000000000000000000000000000000000000000000000001614612c1757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a20696e76616c69642065697031323731207369676e617475726500604482015290519081900360640190fd5b50509392505050565b600060148314612c9157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f475076323a206d616c666f726d6564207072657369676e617475726500000000604482015290519081900360640190fd5b506040805160388082526060828101909352853590921c9160009190602082018180368337019050509050612cc881878486612485565b7ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c6000826040518082805190602001908083835b60208310612d3c57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612cff565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390205414612ddc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a206f72646572206e6f74207072657369676e656400000000000000604482015290519081900360640190fd5b50949350505050565b600060418214612e5657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a206d616c666f726d6564206563647361207369676e617475726500604482015290519081900360640190fd5b604080516000815260208181018084528790528286013560f81c82840181905286356060840181905282880135608085018190529451909493919260019260a0808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015612ed9573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff8416612f8657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f475076323a20696e76616c6964206563647361207369676e6174757265000000604482015290519081900360640190fd5b5050509392505050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b6040518060800160405280612ffa613014565b815260606020820181905260006040830181905291015290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b60008083601f840112613089578182fd5b50813567ffffffffffffffff8111156130a0578182fd5b60208301915083602080830285010111156130ba57600080fd5b9250929050565b60008083601f8401126130d2578182fd5b50813567ffffffffffffffff8111156130e9578182fd5b6020830191508360208285010111156130ba57600080fd5b600082601f830112613111578081fd5b813567ffffffffffffffff81111561312557fe5b61315660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613e44565b81815284602083860101111561316a578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215613195578081fd5b81356125c281613ebc565b600080604083850312156131b2578081fd5b82356131bd81613ebc565b9150602083013567ffffffffffffffff8111156131d8578182fd5b6131e485828601613101565b9150509250929050565b60008060208385031215613200578182fd5b823567ffffffffffffffff811115613216578283fd5b61322285828601613078565b90969095509350505050565b60008060008060008060006080888a031215613248578283fd5b873567ffffffffffffffff8082111561325f578485fd5b61326b8b838c01613078565b909950975060208a0135915080821115613283578485fd5b61328f8b838c01613078565b909750955060408a01359150808211156132a7578485fd5b6132b38b838c01613078565b909550935060608a01359150808211156132cb578283fd5b508801606081018a10156132dd578182fd5b8091505092959891949750929550565b600060208083850312156132ff578182fd5b825167ffffffffffffffff80821115613316578384fd5b818501915085601f830112613329578384fd5b81518181111561333557fe5b8381029150613345848301613e44565b8181528481019084860184860187018a101561335f578788fd5b8795505b83861015613381578051835260019590950194918601918601613363565b5098975050505050505050565b6000806000806000606086880312156133a5578081fd5b853567ffffffffffffffff808211156133bc578283fd5b6133c889838a01613078565b909750955060208801359150808211156133e0578283fd5b6133ec89838a01613078565b90955093506040880135915080821115613404578283fd5b5086016101608189031215613417578182fd5b809150509295509295909350565b600060208284031215613436578081fd5b81516125c281613ee1565b60008060208385031215613453578182fd5b823567ffffffffffffffff811115613469578283fd5b613222858286016130c1565b600080600060408486031215613489578081fd5b833567ffffffffffffffff81111561349f578182fd5b6134ab868287016130c1565b90945092505060208401356134bf81613ee1565b809150509250925092565b6000602082840312156134db578081fd5b813567ffffffffffffffff8111156134f1578182fd5b612a1284828501613101565b6000806040838503121561350f578182fd5b50508035926020909101359150565b60008284526020808501945082825b8581101561356857813561354081613ebc565b73ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161352d565b509495945050505050565b6000815180845260208085019450808401835b8381101561356857815187529582019590820190600101613586565b600082845282826020860137806020848601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011685010190509392505050565b60008151808452613602816020860160208601613e90565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8082511683528060208301511660208401525060408101516040830152606081015160608301525050565b73ffffffffffffffffffffffffffffffffffffffff808251168352602082015115156020840152806040830151166040840152506060810151151560608301525050565b63ffffffff169052565b6000828483379101908152919050565b600082516136e4818460208701613e90565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252825182820181905260009190848201906040850190845b818110156137515761373e838551613634565b928401926080929092019160010161372b565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156137e357815180516004811061379057fe5b85528087015173ffffffffffffffffffffffffffffffffffffffff908116888701528682015187870152606080830151821690870152608091820151169085015260a0909301929085019060010161377a565b5091979650505050505050565b90815260200190565b600060208252612a126020830184866135a2565b6000602082526125c260208301846135ea565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015283608083015260c060a083015261386b60c08301846135ea565b98975050505050505050565b60006101a0820160028c1061388857fe5b8b835260206101a081850152818b83526101c0850190506101c0828d0286010192508c845b8d8110156139b6577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe408786030183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618f36030182351261390c578586fd5b8e823501803586528481013585870152604081013560408701526060810135606087015260808101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112613964578788fd5b8101803567ffffffffffffffff81111561397c578889fd5b80360383131561398a578889fd5b60a060808901526139a160a08901828985016135a2565b975050509284019250908301906001016138ad565b5050505082810360408401526139cd81898b61351e565b90506139dc6060840188613674565b82810360e08401526139ee8187613573565b9150506139ff6101008301856136b8565b613a0d610120830184613634565b9a9950505050505050505050565b6020808252601f908201527f475076323a2063616c6c657220646f6573206e6f74206f776e206f7264657200604082015260600190565b60208082526013908201527f475076323a206f72646572206578706972656400000000000000000000000000604082015260600190565b6020808252601f908201527f475076323a206c696d6974207072696365206e6f742072657370656374656400604082015260600190565b6020808252601f908201527f475076323a2073656c6c20616d6f756e74206e6f742072657370656374656400604082015260600190565b6020808252601e908201527f475076323a2062757920616d6f756e74206e6f74207265737065637465640000604082015260600190565b6020808252601e908201527f475076323a20756e737570706f7274656420696e7465726e616c204554480000604082015260600190565b60208082526018908201527f475076323a206e6f7420616e20696e746572616374696f6e0000000000000000604082015260600190565b60208082526014908201527f475076323a206c696d697420746f6f2068696768000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206f726465722066696c6c65640000000000000000000000000000604082015260600190565b60208082526017908201527f475076323a206f72646572207374696c6c2076616c6964000000000000000000604082015260600190565b60208082526013908201527f475076323a206c696d697420746f6f206c6f7700000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206e6f74206120736f6c7665720000000000000000000000000000604082015260600190565b6020808252601b908201527f475076323a20666f7262696464656e20696e746572616374696f6e0000000000604082015260600190565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260400190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613d4a578283fd5b83018035915067ffffffffffffffff821115613d64578283fd5b60209081019250810236038213156130ba57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613daf578283fd5b83018035915067ffffffffffffffff821115613dc9578283fd5b6020019150368190038213156130ba57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126136e4578182fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18336030181126136e4578182fd5b60405181810167ffffffffffffffff81118282101715613e6057fe5b604052919050565b60008085851115613e77578182fd5b83861115613e83578182fd5b5050820193919092039150565b60005b83811015613eab578181015183820152602001613e93565b83811115611b295750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114613ede57600080fd5b50565b8015158114613ede57600080fdfea2646970667358221220de5e493c48a3b42da03a5db89085177b8d8ccec6e9bf6e8e48b3809343624c8f64736f6c6343000706003360c060405234801561001057600080fd5b5060405161129e38038061129e83398101604081905261002f9161004b565b33606090811b6080521b6001600160601b03191660a052610079565b60006020828403121561005c578081fd5b81516001600160a01b0381168114610072578182fd5b9392505050565b60805160601c60a05160601c6111ee6100b060003980610130528061020152806102bd5250806093528061024c52506111ee6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80634817a2861461003b5780637d10d11f14610064575b600080fd5b61004e610049366004610cd9565b610079565b60405161005b9190610eb3565b60405180910390f35b610077610072366004610c69565b610234565b005b60603373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea906110e5565b60405180910390fd5b6040517f945bcec900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063945bcec990610171908c908c908c908c908c908c908c90600401610f59565b600060405180830381600087803b15801561018b57600080fd5b505af115801561019f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526101e59190810190610bd9565b905061022873ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683336102e9565b98975050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146102a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea906110e5565b6102e573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016838333610551565b5050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61030e6040840160208501610bb6565b73ffffffffffffffffffffffffffffffffffffffff16141561035c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea9061111c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9826060013514156103d0576103cb6103986020840184610bb6565b82604085018035906103ad9060208801610bb6565b73ffffffffffffffffffffffffffffffffffffffff16929190610816565b61054c565b604080516001808252818301909252600091816020015b6103ef6109cb565b8152602001906001900390816103e757905050905060008160008151811061041357fe5b602002602001015190507fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea063284606001351461044f576002610452565b60035b8190600381111561045f57fe5b9081600381111561046c57fe5b90525061047f6040850160208601610bb6565b73ffffffffffffffffffffffffffffffffffffffff16602080830191909152604080860135908301526104b490850185610bb6565b73ffffffffffffffffffffffffffffffffffffffff908116606083015283811660808301526040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815290861690630e8e3e8490610517908590600401610ec6565b600060405180830381600087803b15801561053157600080fd5b505af1158015610545573d6000803e3d6000fd5b5050505050505b505050565b60008267ffffffffffffffff8111801561056a57600080fd5b506040519080825280602002602001820160405280156105a457816020015b6105916109cb565b8152602001906001900390816105895790505b5090506000805b8481101561077857368686838181106105c057fe5b60800291909101915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90506105f06040830160208401610bb6565b73ffffffffffffffffffffffffffffffffffffffff16141561063e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea9061111c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9816060013514156106945761068f61067a6020830183610bb6565b86604084018035906103ad9060208701610bb6565b61076f565b60008484806001019550815181106106a857fe5b602002602001015190507fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328260600135146106e45760016106e7565b60035b819060038111156106f457fe5b9081600381111561070157fe5b9052506107146040830160208401610bb6565b73ffffffffffffffffffffffffffffffffffffffff166020808301919091526040808401359083015261074990830183610bb6565b73ffffffffffffffffffffffffffffffffffffffff908116606083015286166080909101525b506001016105ab565b50801561080e5761078982826108fd565b6040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690630e8e3e84906107db908590600401610ec6565b600060405180830381600087803b1580156107f557600080fd5b505af1158015610809573d6000803e3d6000fd5b505050505b505050505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff8581166004840152841660248301526044820183905290600080606483828a5af1610881573d6000803e3d6000fd5b5061088b85610901565b6108f657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a206661696c6564207472616e7366657246726f6d00000000000000604482015290519081900360640190fd5b5050505050565b9052565b600061093f565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452806024528160445260646000fd5b3d801561097e57602081146109b8576109797f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f610908565b6109c5565b823b6109af576109af7f475076323a206e6f74206120636f6e74726163740000000000000000000000006014610908565b600191506109c5565b3d6000803e600051151591505b50919050565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b600082601f830112610a0b578081fd5b81356020610a20610a1b83611175565b611151565b8281528181019085830183850287018401881015610a3c578586fd5b855b85811015610a63578135610a5181611193565b84529284019290840190600101610a3e565b5090979650505050505050565b600082601f830112610a80578081fd5b81356020610a90610a1b83611175565b8281528181019085830183850287018401881015610aac578586fd5b855b85811015610a6357813584529284019290840190600101610aae565b60008083601f840112610adb578182fd5b50813567ffffffffffffffff811115610af2578182fd5b6020830191508360208083028501011115610b0c57600080fd5b9250929050565b80358015158114610b2357600080fd5b919050565b6000608082840312156109c5578081fd5b600060808284031215610b4a578081fd5b6040516080810181811067ffffffffffffffff82111715610b6757fe5b6040529050808235610b7881611193565b8152610b8660208401610b13565b60208201526040830135610b9981611193565b6040820152610baa60608401610b13565b60608201525092915050565b600060208284031215610bc7578081fd5b8135610bd281611193565b9392505050565b60006020808385031215610beb578182fd5b825167ffffffffffffffff811115610c01578283fd5b8301601f81018513610c11578283fd5b8051610c1f610a1b82611175565b8181528381019083850185840285018601891015610c3b578687fd5b8694505b83851015610c5d578051835260019490940193918501918501610c3f565b50979650505050505050565b60008060208385031215610c7b578081fd5b823567ffffffffffffffff80821115610c92578283fd5b818501915085601f830112610ca5578283fd5b813581811115610cb3578384fd5b866020608083028501011115610cc7578384fd5b60209290920196919550909350505050565b6000806000806000806000806101a0898b031215610cf5578384fd5b883560028110610d03578485fd5b9750602089013567ffffffffffffffff80821115610d1f578586fd5b610d2b8c838d01610aca565b909950975060408b0135915080821115610d43578586fd5b610d4f8c838d016109fb565b9650610d5e8c60608d01610b39565b955060e08b0135915080821115610d73578485fd5b50610d808b828c01610a70565b9350506101008901359150610d998a6101208b01610b28565b90509295985092959890939650565b6000815180845260208085019450808401835b83811015610ded57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610dbb565b509495945050505050565b6000815180845260208085019450808401835b83811015610ded57815187529582019590820190600101610e0b565b600082845282826020860137806020848601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011685010190509392505050565b73ffffffffffffffffffffffffffffffffffffffff808251168352602082015115156020840152806040830151166040840152506060810151151560608301525050565b600060208252610bd26020830184610df8565b602080825282518282018190526000919060409081850190868401855b82811015610f4c578151805160048110610ef957fe5b85528087015173ffffffffffffffffffffffffffffffffffffffff908116888701528682015187870152606080830151821690870152608091820151169085015260a09093019290850190600101610ee3565b5091979650505050505050565b600061012080830160028b10610f6b57fe5b8a8452602080850192909252889052610140808401918981028501909101908a845b8b811015611098577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec087850301855281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618e3603018112610fed578687fd5b8d01803585528381013584860152604080820135908601526060808201359086015260a0608080830135368490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe101811261104757898afd5b8301803567ffffffffffffffff81111561105f578a8bfd5b80360385131561106d578a8bfd5b83838a0152611081848a01828a8501610e27565b998801999850505093850193505050600101610f8d565b50505083810360408501526110ad8189610da8565b9150506110bd6060840187610e6f565b82810360e08401526110cf8186610df8565b9150508261010083015298975050505050505050565b60208082526011908201527f475076323a206e6f742063726561746f72000000000000000000000000000000604082015260600190565b6020808252818101527f475076323a2063616e6e6f74207472616e73666572206e617469766520455448604082015260600190565b60405181810167ffffffffffffffff8111828210171561116d57fe5b604052919050565b600067ffffffffffffffff82111561118957fe5b5060209081020190565b73ffffffffffffffffffffffffffffffffffffffff811681146111b557600080fd5b5056fea2646970667358221220364a6941bea69620b7dc3a957d0ab4cbf3bfc459c7ad3924d220620aca9202fc64736f6c63430007060033", @@ -686,5 +593,100 @@ "kind": "user", "methods": {}, "version": 1 - } + }, + "_disabled": [ + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "orderUids", + "type": "bytes[]" + } + ], + "name": "freeFilledAmountStorage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "orderUids", + "type": "bytes[]" + } + ], + "name": "freePreSignatureStorage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "getStorageAt", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "preSignature", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "targetContract", + "type": "address" + }, + { + "internalType": "bytes", + "name": "calldataPayload", + "type": "bytes" + } + ], + "name": "simulateDelegatecallInternal", + "outputs": [ + { + "internalType": "bytes", + "name": "response", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] } diff --git a/contracts/artifacts/GasHog.json b/contracts/artifacts/GasHog.json new file mode 100644 index 0000000000..a20d942254 --- /dev/null +++ b/contracts/artifacts/GasHog.json @@ -0,0 +1,59 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract ERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "order", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b506103008061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80631626ba7e14610038578063e1f21c6714610080575b5f5ffd5b61004b6100463660046101c5565b610095565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b61009361008e366004610260565b61013d565b005b5f5f5a90505f6100a78486018661029e565b90507fce7d7369855be79904099402d83db6d6ab8840dcd5c086e062cd1ca0c8111dfc5b815a6100d790856102b5565b1015610106576040805160208101839052016040516020818303038152906040528051906020012090506100cb565b868103610111575f5ffd5b507f1626ba7e000000000000000000000000000000000000000000000000000000009695505050505050565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063095ea7b3906044015f604051808303815f87803b1580156101aa575f5ffd5b505af11580156101bc573d5f5f3e3d5ffd5b50505050505050565b5f5f5f604084860312156101d7575f5ffd5b83359250602084013567ffffffffffffffff8111156101f4575f5ffd5b8401601f81018613610204575f5ffd5b803567ffffffffffffffff81111561021a575f5ffd5b86602082840101111561022b575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461025d575f5ffd5b50565b5f5f5f60608486031215610272575f5ffd5b833561027d8161023c565b9250602084013561028d8161023c565b929592945050506040919091013590565b5f602082840312156102ae575f5ffd5b5035919050565b818103818111156102ed577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80631626ba7e14610038578063e1f21c6714610080575b5f5ffd5b61004b6100463660046101c5565b610095565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b61009361008e366004610260565b61013d565b005b5f5f5a90505f6100a78486018661029e565b90507fce7d7369855be79904099402d83db6d6ab8840dcd5c086e062cd1ca0c8111dfc5b815a6100d790856102b5565b1015610106576040805160208101839052016040516020818303038152906040528051906020012090506100cb565b868103610111575f5ffd5b507f1626ba7e000000000000000000000000000000000000000000000000000000009695505050505050565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063095ea7b3906044015f604051808303815f87803b1580156101aa575f5ffd5b505af11580156101bc573d5f5f3e3d5ffd5b50505050505050565b5f5f5f604084860312156101d7575f5ffd5b83359250602084013567ffffffffffffffff8111156101f4575f5ffd5b8401601f81018613610204575f5ffd5b803567ffffffffffffffff81111561021a575f5ffd5b86602082840101111561022b575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461025d575f5ffd5b50565b5f5f5f60608486031215610272575f5ffd5b833561027d8161023c565b9250602084013561028d8161023c565b929592945050506040919091013590565b5f602082840312156102ae575f5ffd5b5035919050565b818103818111156102ed577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/crates/contracts/artifacts/GnosisSafe.json b/contracts/artifacts/GnosisSafe.json similarity index 99% rename from crates/contracts/artifacts/GnosisSafe.json rename to contracts/artifacts/GnosisSafe.json index 95d2b91459..a356fbec4f 100644 --- a/crates/contracts/artifacts/GnosisSafe.json +++ b/contracts/artifacts/GnosisSafe.json @@ -252,6 +252,10 @@ "stateMutability": "nonpayable", "type": "fallback" }, + { + "stateMutability": "payable", + "type": "receive" + }, { "inputs": [], "name": "VERSION", @@ -265,6 +269,147 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "enum Enum.Operation", + "name": "operation", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "safeTxGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPrice", + "type": "uint256" + }, + { + "internalType": "address", + "name": "gasToken", + "type": "address" + }, + { + "internalType": "address payable", + "name": "refundReceiver", + "type": "address" + }, + { + "internalType": "bytes", + "name": "signatures", + "type": "bytes" + } + ], + "name": "execTransaction", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "nonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_owners", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "_threshold", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "address", + "name": "fallbackHandler", + "type": "address" + }, + { + "internalType": "address", + "name": "paymentToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "payment", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "paymentReceiver", + "type": "address" + } + ], + "name": "setup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b5060016004819055506159ae80620000296000396000f3fe6080604052600436106101dc5760003560e01c8063affed0e011610102578063e19a9dd911610095578063f08a032311610064578063f08a032314611647578063f698da2514611698578063f8dc5dd9146116c3578063ffa1ad741461173e57610231565b8063e19a9dd91461139b578063e318b52b146113ec578063e75235b81461147d578063e86637db146114a857610231565b8063cc2f8452116100d1578063cc2f8452146110e8578063d4d9bdcd146111b5578063d8d11f78146111f0578063e009cfde1461132a57610231565b8063affed0e014610d94578063b4faba0914610dbf578063b63e800d14610ea7578063c4ca3a9c1461101757610231565b80635624b25b1161017a5780636a761202116101495780636a761202146109945780637d83297414610b50578063934f3a1114610bbf578063a0e67e2b14610d2857610231565b80635624b25b146107fb5780635ae6bd37146108b9578063610b592514610908578063694e80c31461095957610231565b80632f54bf6e116101b65780632f54bf6e146104d35780633408e4701461053a578063468721a7146105655780635229073f1461067a57610231565b80630d582f131461029e57806312fb68e0146102f95780632d9ad53d1461046c57610231565b36610231573373ffffffffffffffffffffffffffffffffffffffff167f3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d346040518082815260200191505060405180910390a2005b34801561023d57600080fd5b5060007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b905080548061027257600080f35b36600080373360601b365260008060143601600080855af13d6000803e80610299573d6000fd5b3d6000f35b3480156102aa57600080fd5b506102f7600480360360408110156102c157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506117ce565b005b34801561030557600080fd5b5061046a6004803603608081101561031c57600080fd5b81019080803590602001909291908035906020019064010000000081111561034357600080fd5b82018360208201111561035557600080fd5b8035906020019184600183028401116401000000008311171561037757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156103da57600080fd5b8201836020820111156103ec57600080fd5b8035906020019184600183028401116401000000008311171561040e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190505050611bbe565b005b34801561047857600080fd5b506104bb6004803603602081101561048f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612440565b60405180821515815260200191505060405180910390f35b3480156104df57600080fd5b50610522600480360360208110156104f657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612512565b60405180821515815260200191505060405180910390f35b34801561054657600080fd5b5061054f6125e4565b6040518082815260200191505060405180910390f35b34801561057157600080fd5b506106626004803603608081101561058857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156105cf57600080fd5b8201836020820111156105e157600080fd5b8035906020019184600183028401116401000000008311171561060357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff1690602001909291905050506125f1565b60405180821515815260200191505060405180910390f35b34801561068657600080fd5b506107776004803603608081101561069d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156106e457600080fd5b8201836020820111156106f657600080fd5b8035906020019184600183028401116401000000008311171561071857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff1690602001909291905050506127d7565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156107bf5780820151818401526020810190506107a4565b50505050905090810190601f1680156107ec5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561080757600080fd5b5061083e6004803603604081101561081e57600080fd5b81019080803590602001909291908035906020019092919050505061280d565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561087e578082015181840152602081019050610863565b50505050905090810190601f1680156108ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156108c557600080fd5b506108f2600480360360208110156108dc57600080fd5b8101908080359060200190929190505050612894565b6040518082815260200191505060405180910390f35b34801561091457600080fd5b506109576004803603602081101561092b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506128ac565b005b34801561096557600080fd5b506109926004803603602081101561097c57600080fd5b8101908080359060200190929190505050612c3e565b005b610b3860048036036101408110156109ab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156109f257600080fd5b820183602082011115610a0457600080fd5b80359060200191846001830284011164010000000083111715610a2657600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610ab257600080fd5b820183602082011115610ac457600080fd5b80359060200191846001830284011164010000000083111715610ae657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612d78565b60405180821515815260200191505060405180910390f35b348015610b5c57600080fd5b50610ba960048036036040811015610b7357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506132b5565b6040518082815260200191505060405180910390f35b348015610bcb57600080fd5b50610d2660048036036060811015610be257600080fd5b810190808035906020019092919080359060200190640100000000811115610c0957600080fd5b820183602082011115610c1b57600080fd5b80359060200191846001830284011164010000000083111715610c3d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610ca057600080fd5b820183602082011115610cb257600080fd5b80359060200191846001830284011164010000000083111715610cd457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506132da565b005b348015610d3457600080fd5b50610d3d613369565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d80578082015181840152602081019050610d65565b505050509050019250505060405180910390f35b348015610da057600080fd5b50610da9613512565b6040518082815260200191505060405180910390f35b348015610dcb57600080fd5b50610ea560048036036040811015610de257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610e1f57600080fd5b820183602082011115610e3157600080fd5b80359060200191846001830284011164010000000083111715610e5357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050613518565b005b348015610eb357600080fd5b506110156004803603610100811015610ecb57600080fd5b8101908080359060200190640100000000811115610ee857600080fd5b820183602082011115610efa57600080fd5b80359060200191846020830284011164010000000083111715610f1c57600080fd5b909192939192939080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610f6757600080fd5b820183602082011115610f7957600080fd5b80359060200191846001830284011164010000000083111715610f9b57600080fd5b9091929391929390803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061353a565b005b34801561102357600080fd5b506110d26004803603608081101561103a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561108157600080fd5b82018360208201111561109357600080fd5b803590602001918460018302840111640100000000831117156110b557600080fd5b9091929391929390803560ff1690602001909291905050506136f8565b6040518082815260200191505060405180910390f35b3480156110f457600080fd5b506111416004803603604081101561110b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613820565b60405180806020018373ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b838110156111a0578082015181840152602081019050611185565b50505050905001935050505060405180910390f35b3480156111c157600080fd5b506111ee600480360360208110156111d857600080fd5b8101908080359060200190929190505050613a12565b005b3480156111fc57600080fd5b50611314600480360361014081101561121457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561125b57600080fd5b82018360208201111561126d57600080fd5b8035906020019184600183028401116401000000008311171561128f57600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613bb1565b6040518082815260200191505060405180910390f35b34801561133657600080fd5b506113996004803603604081101561134d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613bde565b005b3480156113a757600080fd5b506113ea600480360360208110156113be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613f6f565b005b3480156113f857600080fd5b5061147b6004803603606081101561140f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613ff3565b005b34801561148957600080fd5b50611492614665565b6040518082815260200191505060405180910390f35b3480156114b457600080fd5b506115cc60048036036101408110156114cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561151357600080fd5b82018360208201111561152557600080fd5b8035906020019184600183028401116401000000008311171561154757600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061466f565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561160c5780820151818401526020810190506115f1565b50505050905090810190601f1680156116395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561165357600080fd5b506116966004803603602081101561166a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614817565b005b3480156116a457600080fd5b506116ad614878565b6040518082815260200191505060405180910390f35b3480156116cf57600080fd5b5061173c600480360360608110156116e657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506148f6565b005b34801561174a57600080fd5b50611753614d29565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611793578082015181840152602081019050611778565b50505050905090810190601f1680156117c05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6117d6614d62565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156118405750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561187857503073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b6118ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146119eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003600081548092919060010191905055507f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2682604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414611bba57611bb981612c3e565b5b5050565b611bd2604182614e0590919063ffffffff16565b82511015611c48576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000808060008060005b8681101561243457611c648882614e3f565b80945081955082965050505060008460ff16141561206d578260001c9450611c96604188614e0590919063ffffffff16565b8260001c1015611d0e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8751611d2760208460001c614e6e90919063ffffffff16565b1115611d9b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006020838a01015190508851611dd182611dc360208760001c614e6e90919063ffffffff16565b614e6e90919063ffffffff16565b1115611e45576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60606020848b010190506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff166320c13b0b8d846040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b83811015611ee7578082015181840152602081019050611ecc565b50505050905090810190601f168015611f145780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b83811015611f4d578082015181840152602081019050611f32565b50505050905090810190601f168015611f7a5780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b158015611f9957600080fd5b505afa158015611fad573d6000803e3d6000fd5b505050506040513d6020811015611fc357600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612066576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b50506122b2565b60018460ff161415612181578260001c94508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061210a57506000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000205414155b61217c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6122b1565b601e8460ff1611156122495760018a60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048603858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015612238573d6000803e3d6000fd5b5050506020604051035194506122b0565b60018a85858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156122a3573d6000803e3d6000fd5b5050506020604051035194505b5b5b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161180156123795750600073ffffffffffffffffffffffffffffffffffffffff16600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b80156123b25750600173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b612424576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323600000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8495508080600101915050611c52565b50505050505050505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff161415801561250b5750600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156125dd5750600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000804690508091505090565b6000600173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156126bc5750600073ffffffffffffffffffffffffffffffffffffffff16600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b61272e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61273b858585855a614e8d565b9050801561278b573373ffffffffffffffffffffffffffffffffffffffff167f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb860405160405180910390a26127cf565b3373ffffffffffffffffffffffffffffffffffffffff167facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd37560405160405180910390a25b949350505050565b600060606127e7868686866125f1565b915060405160203d0181016040523d81523d6000602083013e8091505094509492505050565b606060006020830267ffffffffffffffff8111801561282b57600080fd5b506040519080825280601f01601f19166020018201604052801561285e5781602001600182028036833780820191505090505b50905060005b8381101561288957808501548060208302602085010152508080600101915050612864565b508091505092915050565b60076020528060005260406000206000915090505481565b6128b4614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561291e5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b612990576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612a91576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844081604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b612c46614d62565b600354811115612cbe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001811015612d35576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b806004819055507f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c936004546040518082815260200191505060405180910390a150565b6000806000612d928e8e8e8e8e8e8e8e8e8e60055461466f565b905060056000815480929190600101919050555080805190602001209150612dbb8282866132da565b506000612dc6614ed9565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612fac578073ffffffffffffffffffffffffffffffffffffffff166375f0bb528f8f8f8f8f8f8f8f8f8f8f336040518d63ffffffff1660e01b8152600401808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c8152602001806020018a6001811115612e6957fe5b81526020018981526020018881526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff168152602001806020018473ffffffffffffffffffffffffffffffffffffffff16815260200183810383528d8d82818152602001925080828437600081840152601f19601f820116905080830192505050838103825285818151815260200191508051906020019080838360005b83811015612f3b578082015181840152602081019050612f20565b50505050905090810190601f168015612f685780820380516001836020036101000a031916815260200191505b509e505050505050505050505050505050600060405180830381600087803b158015612f9357600080fd5b505af1158015612fa7573d6000803e3d6000fd5b505050505b6101f4612fd36109c48b01603f60408d0281612fc457fe5b04614f0a90919063ffffffff16565b015a1015613049576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60005a90506130b28f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e60008d146130a7578e6130ad565b6109c45a035b614e8d565b93506130c75a82614f2490919063ffffffff16565b905083806130d6575060008a14155b806130e2575060008814155b613154576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008089111561316e5761316b828b8b8b8b614f44565b90505b84156131b8577f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e8482604051808381526020018281526020019250505060405180910390a16131f8565b7f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d238482604051808381526020018281526020019250505060405180910390a15b5050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146132a4578073ffffffffffffffffffffffffffffffffffffffff16639327136883856040518363ffffffff1660e01b815260040180838152602001821515815260200192505050600060405180830381600087803b15801561328b57600080fd5b505af115801561329f573d6000803e3d6000fd5b505050505b50509b9a5050505050505050505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b6000600454905060008111613357576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61336384848484611bbe565b50505050565b6060600060035467ffffffffffffffff8111801561338657600080fd5b506040519080825280602002602001820160405280156133b55781602001602082028036833780820191505090505b50905060008060026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613509578083838151811061346057fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050818060010192505061341f565b82935050505090565b60055481565b600080825160208401855af4806000523d6020523d600060403e60403d016000fd5b6135858a8a80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508961514a565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146135c3576135c28461564a565b5b6136118787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050615679565b600082111561362b5761362982600060018685614f44565b505b3373ffffffffffffffffffffffffffffffffffffffff167f141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a88b8b8b8b8960405180806020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252878782818152602001925060200280828437600081840152601f19601f820116905080830192505050965050505050505060405180910390a250505050505050505050565b6000805a905061374f878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050865a614e8d565b61375857600080fd5b60005a8203905080604051602001808281526020019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156137e55780820151818401526020810190506137ca565b50505050905090810190601f1680156138125780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b606060008267ffffffffffffffff8111801561383b57600080fd5b5060405190808252806020026020018201604052801561386a5781602001602082028036833780820191505090505b509150600080600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561393d5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561394857508482105b15613a03578084838151811061395a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081806001019250506138d3565b80925081845250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff16600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415613b14576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16817ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c60405160405180910390a350565b6000613bc68c8c8c8c8c8c8c8c8c8c8c61466f565b8051906020012090509b9a5050505050505050505050565b613be6614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015613c505750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b613cc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613dc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427681604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b613f77614d62565b60007f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b90508181557f1151116914515bc0891ff9047a6cb32cf902546f83066499bcf8ba33d2353fa282604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b613ffb614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156140655750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561409d57503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b61410f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614210576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561427a5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b6142ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146143ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a17f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2681604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1505050565b6000600454905090565b606060007fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d860001b8d8d8d8d60405180838380828437808301925050509250505060405180910390208c8c8c8c8c8c8c604051602001808c81526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a815260200189815260200188600181111561470057fe5b81526020018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019b505050505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b61478c614878565b8360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529150509b9a5050505050505050505050565b61481f614d62565b6148288161564a565b7f5ac6c46c93c8d0e53714ba3b53db3e7c046da994313d7ed0d192028bc7c228b081604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b6148a66125e4565b30604051602001808481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405160208183030381529060405280519060200120905090565b6148fe614d62565b806001600354031015614979576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156149e35750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b614a55576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614b55576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360008154809291906001900391905055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414614d2457614d2381612c3e565b5b505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614614e03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b565b600080831415614e185760009050614e39565b6000828402905082848281614e2957fe5b0414614e3457600080fd5b809150505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b600080828401905083811015614e8357600080fd5b8091505092915050565b6000600180811115614e9b57fe5b836001811115614ea757fe5b1415614ec0576000808551602087018986f49050614ed0565b600080855160208701888a87f190505b95945050505050565b6000807f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b9050805491505090565b600081831015614f1a5781614f1c565b825b905092915050565b600082821115614f3357600080fd5b600082840390508091505092915050565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614614f815782614f83565b325b9050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561509b57614fed3a8610614fca573a614fcc565b855b614fdf888a614e6e90919063ffffffff16565b614e0590919063ffffffff16565b91508073ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050615096576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b615140565b6150c0856150b2888a614e6e90919063ffffffff16565b614e0590919063ffffffff16565b91506150cd8482846158b4565b61513f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5095945050505050565b6000600454146151c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8151811115615239576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60018110156152b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006001905060005b83518110156155b65760008482815181106152d057fe5b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156153445750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561537c57503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156153b457508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b615426576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614615527576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508092505080806001019150506152b9565b506001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550825160038190555081600481905550505050565b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b90508181555050565b600073ffffffffffffffffffffffffffffffffffffffff1660016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461577b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001806000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146158b05761583d8260008360015a614e8d565b6158af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5050565b60008063a9059cbb8484604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050602060008251602084016000896127105a03f13d6000811461595b5760208114615963576000935061596e565b81935061596e565b600051158215171593505b505050939250505056fea26469706673582212203874bcf92e1722cc7bfa0cef1a0985cf0dc3485ba0663db3747ccdf1605df53464736f6c63430007060033", + "_disabled": [ { "inputs": [ { @@ -402,19 +547,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "domainSeparator", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -492,70 +624,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "enum Enum.Operation", - "name": "operation", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "safeTxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "baseGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "gasToken", - "type": "address" - }, - { - "internalType": "address payable", - "name": "refundReceiver", - "type": "address" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "name": "execTransaction", - "outputs": [ - { - "internalType": "bool", - "name": "success", - "type": "bool" - } - ], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -823,19 +891,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "nonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -919,54 +974,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_owners", - "type": "address[]" - }, - { - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "address", - "name": "fallbackHandler", - "type": "address" - }, - { - "internalType": "address", - "name": "paymentToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "payment", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "paymentReceiver", - "type": "address" - } - ], - "name": "setup", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1026,11 +1033,6 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" } - ], - "bytecode": "0x608060405234801561001057600080fd5b5060016004819055506159ae80620000296000396000f3fe6080604052600436106101dc5760003560e01c8063affed0e011610102578063e19a9dd911610095578063f08a032311610064578063f08a032314611647578063f698da2514611698578063f8dc5dd9146116c3578063ffa1ad741461173e57610231565b8063e19a9dd91461139b578063e318b52b146113ec578063e75235b81461147d578063e86637db146114a857610231565b8063cc2f8452116100d1578063cc2f8452146110e8578063d4d9bdcd146111b5578063d8d11f78146111f0578063e009cfde1461132a57610231565b8063affed0e014610d94578063b4faba0914610dbf578063b63e800d14610ea7578063c4ca3a9c1461101757610231565b80635624b25b1161017a5780636a761202116101495780636a761202146109945780637d83297414610b50578063934f3a1114610bbf578063a0e67e2b14610d2857610231565b80635624b25b146107fb5780635ae6bd37146108b9578063610b592514610908578063694e80c31461095957610231565b80632f54bf6e116101b65780632f54bf6e146104d35780633408e4701461053a578063468721a7146105655780635229073f1461067a57610231565b80630d582f131461029e57806312fb68e0146102f95780632d9ad53d1461046c57610231565b36610231573373ffffffffffffffffffffffffffffffffffffffff167f3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d346040518082815260200191505060405180910390a2005b34801561023d57600080fd5b5060007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b905080548061027257600080f35b36600080373360601b365260008060143601600080855af13d6000803e80610299573d6000fd5b3d6000f35b3480156102aa57600080fd5b506102f7600480360360408110156102c157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506117ce565b005b34801561030557600080fd5b5061046a6004803603608081101561031c57600080fd5b81019080803590602001909291908035906020019064010000000081111561034357600080fd5b82018360208201111561035557600080fd5b8035906020019184600183028401116401000000008311171561037757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156103da57600080fd5b8201836020820111156103ec57600080fd5b8035906020019184600183028401116401000000008311171561040e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190505050611bbe565b005b34801561047857600080fd5b506104bb6004803603602081101561048f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612440565b60405180821515815260200191505060405180910390f35b3480156104df57600080fd5b50610522600480360360208110156104f657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612512565b60405180821515815260200191505060405180910390f35b34801561054657600080fd5b5061054f6125e4565b6040518082815260200191505060405180910390f35b34801561057157600080fd5b506106626004803603608081101561058857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156105cf57600080fd5b8201836020820111156105e157600080fd5b8035906020019184600183028401116401000000008311171561060357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff1690602001909291905050506125f1565b60405180821515815260200191505060405180910390f35b34801561068657600080fd5b506107776004803603608081101561069d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156106e457600080fd5b8201836020820111156106f657600080fd5b8035906020019184600183028401116401000000008311171561071857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff1690602001909291905050506127d7565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156107bf5780820151818401526020810190506107a4565b50505050905090810190601f1680156107ec5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561080757600080fd5b5061083e6004803603604081101561081e57600080fd5b81019080803590602001909291908035906020019092919050505061280d565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561087e578082015181840152602081019050610863565b50505050905090810190601f1680156108ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156108c557600080fd5b506108f2600480360360208110156108dc57600080fd5b8101908080359060200190929190505050612894565b6040518082815260200191505060405180910390f35b34801561091457600080fd5b506109576004803603602081101561092b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506128ac565b005b34801561096557600080fd5b506109926004803603602081101561097c57600080fd5b8101908080359060200190929190505050612c3e565b005b610b3860048036036101408110156109ab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156109f257600080fd5b820183602082011115610a0457600080fd5b80359060200191846001830284011164010000000083111715610a2657600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610ab257600080fd5b820183602082011115610ac457600080fd5b80359060200191846001830284011164010000000083111715610ae657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612d78565b60405180821515815260200191505060405180910390f35b348015610b5c57600080fd5b50610ba960048036036040811015610b7357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506132b5565b6040518082815260200191505060405180910390f35b348015610bcb57600080fd5b50610d2660048036036060811015610be257600080fd5b810190808035906020019092919080359060200190640100000000811115610c0957600080fd5b820183602082011115610c1b57600080fd5b80359060200191846001830284011164010000000083111715610c3d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610ca057600080fd5b820183602082011115610cb257600080fd5b80359060200191846001830284011164010000000083111715610cd457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506132da565b005b348015610d3457600080fd5b50610d3d613369565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d80578082015181840152602081019050610d65565b505050509050019250505060405180910390f35b348015610da057600080fd5b50610da9613512565b6040518082815260200191505060405180910390f35b348015610dcb57600080fd5b50610ea560048036036040811015610de257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610e1f57600080fd5b820183602082011115610e3157600080fd5b80359060200191846001830284011164010000000083111715610e5357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050613518565b005b348015610eb357600080fd5b506110156004803603610100811015610ecb57600080fd5b8101908080359060200190640100000000811115610ee857600080fd5b820183602082011115610efa57600080fd5b80359060200191846020830284011164010000000083111715610f1c57600080fd5b909192939192939080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610f6757600080fd5b820183602082011115610f7957600080fd5b80359060200191846001830284011164010000000083111715610f9b57600080fd5b9091929391929390803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061353a565b005b34801561102357600080fd5b506110d26004803603608081101561103a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561108157600080fd5b82018360208201111561109357600080fd5b803590602001918460018302840111640100000000831117156110b557600080fd5b9091929391929390803560ff1690602001909291905050506136f8565b6040518082815260200191505060405180910390f35b3480156110f457600080fd5b506111416004803603604081101561110b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613820565b60405180806020018373ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b838110156111a0578082015181840152602081019050611185565b50505050905001935050505060405180910390f35b3480156111c157600080fd5b506111ee600480360360208110156111d857600080fd5b8101908080359060200190929190505050613a12565b005b3480156111fc57600080fd5b50611314600480360361014081101561121457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561125b57600080fd5b82018360208201111561126d57600080fd5b8035906020019184600183028401116401000000008311171561128f57600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613bb1565b6040518082815260200191505060405180910390f35b34801561133657600080fd5b506113996004803603604081101561134d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613bde565b005b3480156113a757600080fd5b506113ea600480360360208110156113be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613f6f565b005b3480156113f857600080fd5b5061147b6004803603606081101561140f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613ff3565b005b34801561148957600080fd5b50611492614665565b6040518082815260200191505060405180910390f35b3480156114b457600080fd5b506115cc60048036036101408110156114cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561151357600080fd5b82018360208201111561152557600080fd5b8035906020019184600183028401116401000000008311171561154757600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061466f565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561160c5780820151818401526020810190506115f1565b50505050905090810190601f1680156116395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561165357600080fd5b506116966004803603602081101561166a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614817565b005b3480156116a457600080fd5b506116ad614878565b6040518082815260200191505060405180910390f35b3480156116cf57600080fd5b5061173c600480360360608110156116e657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506148f6565b005b34801561174a57600080fd5b50611753614d29565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611793578082015181840152602081019050611778565b50505050905090810190601f1680156117c05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6117d6614d62565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156118405750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561187857503073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b6118ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146119eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003600081548092919060010191905055507f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2682604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414611bba57611bb981612c3e565b5b5050565b611bd2604182614e0590919063ffffffff16565b82511015611c48576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000808060008060005b8681101561243457611c648882614e3f565b80945081955082965050505060008460ff16141561206d578260001c9450611c96604188614e0590919063ffffffff16565b8260001c1015611d0e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8751611d2760208460001c614e6e90919063ffffffff16565b1115611d9b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006020838a01015190508851611dd182611dc360208760001c614e6e90919063ffffffff16565b614e6e90919063ffffffff16565b1115611e45576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60606020848b010190506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff166320c13b0b8d846040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b83811015611ee7578082015181840152602081019050611ecc565b50505050905090810190601f168015611f145780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b83811015611f4d578082015181840152602081019050611f32565b50505050905090810190601f168015611f7a5780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b158015611f9957600080fd5b505afa158015611fad573d6000803e3d6000fd5b505050506040513d6020811015611fc357600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612066576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b50506122b2565b60018460ff161415612181578260001c94508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061210a57506000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000205414155b61217c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6122b1565b601e8460ff1611156122495760018a60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048603858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015612238573d6000803e3d6000fd5b5050506020604051035194506122b0565b60018a85858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156122a3573d6000803e3d6000fd5b5050506020604051035194505b5b5b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161180156123795750600073ffffffffffffffffffffffffffffffffffffffff16600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b80156123b25750600173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b612424576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323600000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8495508080600101915050611c52565b50505050505050505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff161415801561250b5750600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156125dd5750600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000804690508091505090565b6000600173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156126bc5750600073ffffffffffffffffffffffffffffffffffffffff16600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b61272e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61273b858585855a614e8d565b9050801561278b573373ffffffffffffffffffffffffffffffffffffffff167f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb860405160405180910390a26127cf565b3373ffffffffffffffffffffffffffffffffffffffff167facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd37560405160405180910390a25b949350505050565b600060606127e7868686866125f1565b915060405160203d0181016040523d81523d6000602083013e8091505094509492505050565b606060006020830267ffffffffffffffff8111801561282b57600080fd5b506040519080825280601f01601f19166020018201604052801561285e5781602001600182028036833780820191505090505b50905060005b8381101561288957808501548060208302602085010152508080600101915050612864565b508091505092915050565b60076020528060005260406000206000915090505481565b6128b4614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561291e5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b612990576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612a91576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844081604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b612c46614d62565b600354811115612cbe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001811015612d35576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b806004819055507f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c936004546040518082815260200191505060405180910390a150565b6000806000612d928e8e8e8e8e8e8e8e8e8e60055461466f565b905060056000815480929190600101919050555080805190602001209150612dbb8282866132da565b506000612dc6614ed9565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612fac578073ffffffffffffffffffffffffffffffffffffffff166375f0bb528f8f8f8f8f8f8f8f8f8f8f336040518d63ffffffff1660e01b8152600401808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c8152602001806020018a6001811115612e6957fe5b81526020018981526020018881526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff168152602001806020018473ffffffffffffffffffffffffffffffffffffffff16815260200183810383528d8d82818152602001925080828437600081840152601f19601f820116905080830192505050838103825285818151815260200191508051906020019080838360005b83811015612f3b578082015181840152602081019050612f20565b50505050905090810190601f168015612f685780820380516001836020036101000a031916815260200191505b509e505050505050505050505050505050600060405180830381600087803b158015612f9357600080fd5b505af1158015612fa7573d6000803e3d6000fd5b505050505b6101f4612fd36109c48b01603f60408d0281612fc457fe5b04614f0a90919063ffffffff16565b015a1015613049576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60005a90506130b28f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e60008d146130a7578e6130ad565b6109c45a035b614e8d565b93506130c75a82614f2490919063ffffffff16565b905083806130d6575060008a14155b806130e2575060008814155b613154576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008089111561316e5761316b828b8b8b8b614f44565b90505b84156131b8577f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e8482604051808381526020018281526020019250505060405180910390a16131f8565b7f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d238482604051808381526020018281526020019250505060405180910390a15b5050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146132a4578073ffffffffffffffffffffffffffffffffffffffff16639327136883856040518363ffffffff1660e01b815260040180838152602001821515815260200192505050600060405180830381600087803b15801561328b57600080fd5b505af115801561329f573d6000803e3d6000fd5b505050505b50509b9a5050505050505050505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b6000600454905060008111613357576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61336384848484611bbe565b50505050565b6060600060035467ffffffffffffffff8111801561338657600080fd5b506040519080825280602002602001820160405280156133b55781602001602082028036833780820191505090505b50905060008060026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613509578083838151811061346057fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050818060010192505061341f565b82935050505090565b60055481565b600080825160208401855af4806000523d6020523d600060403e60403d016000fd5b6135858a8a80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508961514a565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146135c3576135c28461564a565b5b6136118787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050615679565b600082111561362b5761362982600060018685614f44565b505b3373ffffffffffffffffffffffffffffffffffffffff167f141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a88b8b8b8b8960405180806020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252878782818152602001925060200280828437600081840152601f19601f820116905080830192505050965050505050505060405180910390a250505050505050505050565b6000805a905061374f878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050865a614e8d565b61375857600080fd5b60005a8203905080604051602001808281526020019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156137e55780820151818401526020810190506137ca565b50505050905090810190601f1680156138125780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b606060008267ffffffffffffffff8111801561383b57600080fd5b5060405190808252806020026020018201604052801561386a5781602001602082028036833780820191505090505b509150600080600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561393d5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561394857508482105b15613a03578084838151811061395a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081806001019250506138d3565b80925081845250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff16600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415613b14576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16817ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c60405160405180910390a350565b6000613bc68c8c8c8c8c8c8c8c8c8c8c61466f565b8051906020012090509b9a5050505050505050505050565b613be6614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015613c505750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b613cc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613dc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427681604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b613f77614d62565b60007f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b90508181557f1151116914515bc0891ff9047a6cb32cf902546f83066499bcf8ba33d2353fa282604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b613ffb614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156140655750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561409d57503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b61410f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614210576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561427a5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b6142ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146143ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a17f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2681604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1505050565b6000600454905090565b606060007fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d860001b8d8d8d8d60405180838380828437808301925050509250505060405180910390208c8c8c8c8c8c8c604051602001808c81526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a815260200189815260200188600181111561470057fe5b81526020018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019b505050505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b61478c614878565b8360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529150509b9a5050505050505050505050565b61481f614d62565b6148288161564a565b7f5ac6c46c93c8d0e53714ba3b53db3e7c046da994313d7ed0d192028bc7c228b081604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b6148a66125e4565b30604051602001808481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405160208183030381529060405280519060200120905090565b6148fe614d62565b806001600354031015614979576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156149e35750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b614a55576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614b55576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360008154809291906001900391905055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414614d2457614d2381612c3e565b5b505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614614e03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b565b600080831415614e185760009050614e39565b6000828402905082848281614e2957fe5b0414614e3457600080fd5b809150505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b600080828401905083811015614e8357600080fd5b8091505092915050565b6000600180811115614e9b57fe5b836001811115614ea757fe5b1415614ec0576000808551602087018986f49050614ed0565b600080855160208701888a87f190505b95945050505050565b6000807f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b9050805491505090565b600081831015614f1a5781614f1c565b825b905092915050565b600082821115614f3357600080fd5b600082840390508091505092915050565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614614f815782614f83565b325b9050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561509b57614fed3a8610614fca573a614fcc565b855b614fdf888a614e6e90919063ffffffff16565b614e0590919063ffffffff16565b91508073ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050615096576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b615140565b6150c0856150b2888a614e6e90919063ffffffff16565b614e0590919063ffffffff16565b91506150cd8482846158b4565b61513f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5095945050505050565b6000600454146151c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8151811115615239576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60018110156152b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006001905060005b83518110156155b65760008482815181106152d057fe5b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156153445750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561537c57503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156153b457508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b615426576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614615527576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508092505080806001019150506152b9565b506001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550825160038190555081600481905550505050565b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b90508181555050565b600073ffffffffffffffffffffffffffffffffffffffff1660016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461577b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001806000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146158b05761583d8260008360015a614e8d565b6158af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5050565b60008063a9059cbb8484604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050602060008251602084016000896127105a03f13d6000811461595b5760208114615963576000935061596e565b81935061596e565b600051158215171593505b505050939250505056fea26469706673582212203874bcf92e1722cc7bfa0cef1a0985cf0dc3485ba0663db3747ccdf1605df53464736f6c63430007060033" + ] } diff --git a/crates/contracts/artifacts/GnosisSafeCompatibilityFallbackHandler.json b/contracts/artifacts/GnosisSafeCompatibilityFallbackHandler.json similarity index 99% rename from crates/contracts/artifacts/GnosisSafeCompatibilityFallbackHandler.json rename to contracts/artifacts/GnosisSafeCompatibilityFallbackHandler.json index e0372bb975..d539a2309a 100644 --- a/crates/contracts/artifacts/GnosisSafeCompatibilityFallbackHandler.json +++ b/contracts/artifacts/GnosisSafeCompatibilityFallbackHandler.json @@ -28,18 +28,23 @@ }, { "inputs": [ + { + "internalType": "bytes32", + "name": "_dataHash", + "type": "bytes32" + }, { "internalType": "bytes", - "name": "message", + "name": "_signature", "type": "bytes" } ], - "name": "getMessageHash", + "name": "isValidSignature", "outputs": [ { - "internalType": "bytes32", + "internalType": "bytes4", "name": "", - "type": "bytes32" + "type": "bytes4" } ], "stateMutability": "view", @@ -48,59 +53,68 @@ { "inputs": [ { - "internalType": "contract GnosisSafe", - "name": "safe", - "type": "address" + "internalType": "bytes", + "name": "_data", + "type": "bytes" }, { "internalType": "bytes", - "name": "message", + "name": "_signature", "type": "bytes" } ], - "name": "getMessageHashForSafe", + "name": "isValidSignature", "outputs": [ { - "internalType": "bytes32", + "internalType": "bytes4", "name": "", - "type": "bytes32" + "type": "bytes4" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "getModules", + "inputs": [ + { + "internalType": "address", + "name": "targetContract", + "type": "address" + }, + { + "internalType": "bytes", + "name": "calldataPayload", + "type": "bytes" + } + ], + "name": "simulate", "outputs": [ { - "internalType": "address[]", - "name": "", - "type": "address[]" + "internalType": "bytes", + "name": "response", + "type": "bytes" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50611574806100206000396000f3fe608060405234801561001057600080fd5b50600436106100ce5760003560e01c80636ac247841161008c578063bc197c8111610066578063bc197c81146107bb578063bd61951d14610951578063f23a6e6114610a63578063ffa1ad7414610b63576100ce565b80636ac24784146105ea578063a3f4df7e146106d9578063b2494df31461075c576100ce565b806223de29146100d357806301ffc9a71461020b5780630a1028c41461026e578063150b7a021461033d5780631626ba7e1461043357806320c13b0b146104e9575b600080fd5b610209600480360360c08110156100e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561017057600080fd5b82018360208201111561018257600080fd5b803590602001918460018302840111640100000000831117156101a457600080fd5b9091929391929390803590602001906401000000008111156101c557600080fd5b8201836020820111156101d757600080fd5b803590602001918460018302840111640100000000831117156101f957600080fd5b9091929391929390505050610be6565b005b6102566004803603602081101561022157600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169060200190929190505050610bf0565b60405180821515815260200191505060405180910390f35b6103276004803603602081101561028457600080fd5b81019080803590602001906401000000008111156102a157600080fd5b8201836020820111156102b357600080fd5b803590602001918460018302840111640100000000831117156102d557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610d2a565b6040518082815260200191505060405180910390f35b6103fe6004803603608081101561035357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156103ba57600080fd5b8201836020820111156103cc57600080fd5b803590602001918460018302840111640100000000831117156103ee57600080fd5b9091929391929390505050610d3d565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6104b46004803603604081101561044957600080fd5b81019080803590602001909291908035906020019064010000000081111561047057600080fd5b82018360208201111561048257600080fd5b803590602001918460018302840111640100000000831117156104a457600080fd5b9091929391929390505050610d52565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6105b5600480360360408110156104ff57600080fd5b810190808035906020019064010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184600183028401116401000000008311171561055057600080fd5b90919293919293908035906020019064010000000081111561057157600080fd5b82018360208201111561058357600080fd5b803590602001918460018302840111640100000000831117156105a557600080fd5b9091929391929390505050610f0a565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6106c36004803603604081101561060057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561063d57600080fd5b82018360208201111561064f57600080fd5b8035906020019184600183028401116401000000008311171561067157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061115b565b6040518082815260200191505060405180910390f35b6106e16112cd565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610721578082015181840152602081019050610706565b50505050905090810190601f16801561074e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610764611306565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156107a757808201518184015260208101905061078c565b505050509050019250505060405180910390f35b61091c600480360360a08110156107d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561082e57600080fd5b82018360208201111561084057600080fd5b8035906020019184602083028401116401000000008311171561086257600080fd5b90919293919293908035906020019064010000000081111561088357600080fd5b82018360208201111561089557600080fd5b803590602001918460208302840111640100000000831117156108b757600080fd5b9091929391929390803590602001906401000000008111156108d857600080fd5b8201836020820111156108ea57600080fd5b8035906020019184600183028401116401000000008311171561090c57600080fd5b909192939192939050505061146d565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6109e86004803603604081101561096757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156109a457600080fd5b8201836020820111156109b657600080fd5b803590602001918460018302840111640100000000831117156109d857600080fd5b9091929391929390505050611485565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610a28578082015181840152602081019050610a0d565b50505050905090810190601f168015610a555780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610b2e600480360360a0811015610a7957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610aea57600080fd5b820183602082011115610afc57600080fd5b80359060200191846001830284011164010000000083111715610b1e57600080fd5b90919293919293905050506114ef565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b610b6b611505565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610bab578082015181840152602081019050610b90565b50505050905090810190601f168015610bd85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b5050505050505050565b60007f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610cbb57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610d2357507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610d36338361115b565b9050919050565b600063150b7a0260e01b905095945050505050565b60008033905060008173ffffffffffffffffffffffffffffffffffffffff166320c13b0b876040516020018082815260200191505060405160208183030381529060405287876040518463ffffffff1660e01b8152600401808060200180602001838103835286818151815260200191508051906020019080838360005b83811015610deb578082015181840152602081019050610dd0565b50505050905090810190601f168015610e185780820380516001836020036101000a031916815260200191505b508381038252858582818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b158015610e6357600080fd5b505afa158015610e77573d6000803e3d6000fd5b505050506040513d6020811015610e8d57600080fd5b810190808051906020019092919050505090506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610ef657600060e01b610eff565b631626ba7e60e01b5b925050509392505050565b6000803390506000610f608288888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061115b565b905060008585905014156110755760008273ffffffffffffffffffffffffffffffffffffffff16635ae6bd37836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d6020811015610feb57600080fd5b81019080805190602001909291905050501415611070576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f48617368206e6f7420617070726f76656400000000000000000000000000000081525060200191505060405180910390fd5b611147565b8173ffffffffffffffffffffffffffffffffffffffff1663934f3a1182898989896040518663ffffffff1660e01b81526004018086815260200180602001806020018381038352878782818152602001925080828437600081840152601f19601f8201169050808301925050508381038252858582818152602001925080828437600081840152601f19601f82011690508083019250505097505050505050505060006040518083038186803b15801561112e57600080fd5b505afa158015611142573d6000803e3d6000fd5b505050505b6320c13b0b60e01b92505050949350505050565b6000807f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca60001b83805190602001206040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050601960f81b600160f81b8573ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b815260040160206040518083038186803b15801561120957600080fd5b505afa15801561121d573d6000803e3d6000fd5b505050506040513d602081101561123357600080fd5b81019080805190602001909291905050508360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040528051906020012091505092915050565b6040518060400160405280601881526020017f44656661756c742043616c6c6261636b2048616e646c6572000000000000000081525081565b6060600033905060008173ffffffffffffffffffffffffffffffffffffffff1663cc2f84526001600a6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060006040518083038186803b15801561138057600080fd5b505afa158015611394573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060408110156113be57600080fd5b81019080805160405193929190846401000000008211156113de57600080fd5b838201915060208201858111156113f457600080fd5b825186602082028301116401000000008211171561141157600080fd5b8083526020830192505050908051906020019060200280838360005b8381101561144857808201518184015260208101905061142d565b5050505090500160405260200180519060200190929190505050509050809250505090565b600063bc197c8160e01b905098975050505050505050565b60606040517fb4faba09000000000000000000000000000000000000000000000000000000008152600436036004808301376020600036836000335af15060203d036040519250808301604052806020843e6000516114e657825160208401fd5b50509392505050565b600063f23a6e6160e01b90509695505050505050565b6040518060400160405280600581526020017f312e302e300000000000000000000000000000000000000000000000000000008152508156fea26469706673582212204251d58f2a197439239faafa82818b7696d25bb75655794a81cc773a0e39ed2b64736f6c63430007060033", + "_disabled": [ { "inputs": [ - { - "internalType": "bytes32", - "name": "_dataHash", - "type": "bytes32" - }, { "internalType": "bytes", - "name": "_signature", + "name": "message", "type": "bytes" } ], - "name": "isValidSignature", + "name": "getMessageHash", "outputs": [ { - "internalType": "bytes4", + "internalType": "bytes32", "name": "", - "type": "bytes4" + "type": "bytes32" } ], "stateMutability": "view", @@ -109,22 +123,35 @@ { "inputs": [ { - "internalType": "bytes", - "name": "_data", - "type": "bytes" + "internalType": "contract GnosisSafe", + "name": "safe", + "type": "address" }, { "internalType": "bytes", - "name": "_signature", + "name": "message", "type": "bytes" } ], - "name": "isValidSignature", + "name": "getMessageHashForSafe", "outputs": [ { - "internalType": "bytes4", + "internalType": "bytes32", "name": "", - "type": "bytes4" + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getModules", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" } ], "stateMutability": "view", @@ -242,30 +269,6 @@ "stateMutability": "pure", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "targetContract", - "type": "address" - }, - { - "internalType": "bytes", - "name": "calldataPayload", - "type": "bytes" - } - ], - "name": "simulate", - "outputs": [ - { - "internalType": "bytes", - "name": "response", - "type": "bytes" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -323,6 +326,5 @@ "stateMutability": "pure", "type": "function" } - ], - "bytecode": "0x608060405234801561001057600080fd5b50611574806100206000396000f3fe608060405234801561001057600080fd5b50600436106100ce5760003560e01c80636ac247841161008c578063bc197c8111610066578063bc197c81146107bb578063bd61951d14610951578063f23a6e6114610a63578063ffa1ad7414610b63576100ce565b80636ac24784146105ea578063a3f4df7e146106d9578063b2494df31461075c576100ce565b806223de29146100d357806301ffc9a71461020b5780630a1028c41461026e578063150b7a021461033d5780631626ba7e1461043357806320c13b0b146104e9575b600080fd5b610209600480360360c08110156100e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561017057600080fd5b82018360208201111561018257600080fd5b803590602001918460018302840111640100000000831117156101a457600080fd5b9091929391929390803590602001906401000000008111156101c557600080fd5b8201836020820111156101d757600080fd5b803590602001918460018302840111640100000000831117156101f957600080fd5b9091929391929390505050610be6565b005b6102566004803603602081101561022157600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169060200190929190505050610bf0565b60405180821515815260200191505060405180910390f35b6103276004803603602081101561028457600080fd5b81019080803590602001906401000000008111156102a157600080fd5b8201836020820111156102b357600080fd5b803590602001918460018302840111640100000000831117156102d557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610d2a565b6040518082815260200191505060405180910390f35b6103fe6004803603608081101561035357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156103ba57600080fd5b8201836020820111156103cc57600080fd5b803590602001918460018302840111640100000000831117156103ee57600080fd5b9091929391929390505050610d3d565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6104b46004803603604081101561044957600080fd5b81019080803590602001909291908035906020019064010000000081111561047057600080fd5b82018360208201111561048257600080fd5b803590602001918460018302840111640100000000831117156104a457600080fd5b9091929391929390505050610d52565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6105b5600480360360408110156104ff57600080fd5b810190808035906020019064010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184600183028401116401000000008311171561055057600080fd5b90919293919293908035906020019064010000000081111561057157600080fd5b82018360208201111561058357600080fd5b803590602001918460018302840111640100000000831117156105a557600080fd5b9091929391929390505050610f0a565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6106c36004803603604081101561060057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561063d57600080fd5b82018360208201111561064f57600080fd5b8035906020019184600183028401116401000000008311171561067157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061115b565b6040518082815260200191505060405180910390f35b6106e16112cd565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610721578082015181840152602081019050610706565b50505050905090810190601f16801561074e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610764611306565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156107a757808201518184015260208101905061078c565b505050509050019250505060405180910390f35b61091c600480360360a08110156107d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561082e57600080fd5b82018360208201111561084057600080fd5b8035906020019184602083028401116401000000008311171561086257600080fd5b90919293919293908035906020019064010000000081111561088357600080fd5b82018360208201111561089557600080fd5b803590602001918460208302840111640100000000831117156108b757600080fd5b9091929391929390803590602001906401000000008111156108d857600080fd5b8201836020820111156108ea57600080fd5b8035906020019184600183028401116401000000008311171561090c57600080fd5b909192939192939050505061146d565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6109e86004803603604081101561096757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156109a457600080fd5b8201836020820111156109b657600080fd5b803590602001918460018302840111640100000000831117156109d857600080fd5b9091929391929390505050611485565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610a28578082015181840152602081019050610a0d565b50505050905090810190601f168015610a555780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610b2e600480360360a0811015610a7957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610aea57600080fd5b820183602082011115610afc57600080fd5b80359060200191846001830284011164010000000083111715610b1e57600080fd5b90919293919293905050506114ef565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b610b6b611505565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610bab578082015181840152602081019050610b90565b50505050905090810190601f168015610bd85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b5050505050505050565b60007f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610cbb57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610d2357507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610d36338361115b565b9050919050565b600063150b7a0260e01b905095945050505050565b60008033905060008173ffffffffffffffffffffffffffffffffffffffff166320c13b0b876040516020018082815260200191505060405160208183030381529060405287876040518463ffffffff1660e01b8152600401808060200180602001838103835286818151815260200191508051906020019080838360005b83811015610deb578082015181840152602081019050610dd0565b50505050905090810190601f168015610e185780820380516001836020036101000a031916815260200191505b508381038252858582818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b158015610e6357600080fd5b505afa158015610e77573d6000803e3d6000fd5b505050506040513d6020811015610e8d57600080fd5b810190808051906020019092919050505090506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610ef657600060e01b610eff565b631626ba7e60e01b5b925050509392505050565b6000803390506000610f608288888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061115b565b905060008585905014156110755760008273ffffffffffffffffffffffffffffffffffffffff16635ae6bd37836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d6020811015610feb57600080fd5b81019080805190602001909291905050501415611070576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f48617368206e6f7420617070726f76656400000000000000000000000000000081525060200191505060405180910390fd5b611147565b8173ffffffffffffffffffffffffffffffffffffffff1663934f3a1182898989896040518663ffffffff1660e01b81526004018086815260200180602001806020018381038352878782818152602001925080828437600081840152601f19601f8201169050808301925050508381038252858582818152602001925080828437600081840152601f19601f82011690508083019250505097505050505050505060006040518083038186803b15801561112e57600080fd5b505afa158015611142573d6000803e3d6000fd5b505050505b6320c13b0b60e01b92505050949350505050565b6000807f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca60001b83805190602001206040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050601960f81b600160f81b8573ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b815260040160206040518083038186803b15801561120957600080fd5b505afa15801561121d573d6000803e3d6000fd5b505050506040513d602081101561123357600080fd5b81019080805190602001909291905050508360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040528051906020012091505092915050565b6040518060400160405280601881526020017f44656661756c742043616c6c6261636b2048616e646c6572000000000000000081525081565b6060600033905060008173ffffffffffffffffffffffffffffffffffffffff1663cc2f84526001600a6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060006040518083038186803b15801561138057600080fd5b505afa158015611394573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060408110156113be57600080fd5b81019080805160405193929190846401000000008211156113de57600080fd5b838201915060208201858111156113f457600080fd5b825186602082028301116401000000008211171561141157600080fd5b8083526020830192505050908051906020019060200280838360005b8381101561144857808201518184015260208101905061142d565b5050505090500160405260200180519060200190929190505050509050809250505090565b600063bc197c8160e01b905098975050505050505050565b60606040517fb4faba09000000000000000000000000000000000000000000000000000000008152600436036004808301376020600036836000335af15060203d036040519250808301604052806020843e6000516114e657825160208401fd5b50509392505050565b600063f23a6e6160e01b90509695505050505050565b6040518060400160405280600581526020017f312e302e300000000000000000000000000000000000000000000000000000008152508156fea26469706673582212204251d58f2a197439239faafa82818b7696d25bb75655794a81cc773a0e39ed2b64736f6c63430007060033" + ] } diff --git a/crates/contracts/artifacts/GnosisSafeProxy.json b/contracts/artifacts/GnosisSafeProxy.json similarity index 99% rename from crates/contracts/artifacts/GnosisSafeProxy.json rename to contracts/artifacts/GnosisSafeProxy.json index f5c664f184..650084569f 100644 --- a/crates/contracts/artifacts/GnosisSafeProxy.json +++ b/contracts/artifacts/GnosisSafeProxy.json @@ -17,4 +17,4 @@ } ], "bytecode": "0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564" -} +} \ No newline at end of file diff --git a/crates/contracts/artifacts/GnosisSafeProxyFactory.json b/contracts/artifacts/GnosisSafeProxyFactory.json similarity index 99% rename from crates/contracts/artifacts/GnosisSafeProxyFactory.json rename to contracts/artifacts/GnosisSafeProxyFactory.json index 352bef478c..c97bd6cdcb 100644 --- a/crates/contracts/artifacts/GnosisSafeProxyFactory.json +++ b/contracts/artifacts/GnosisSafeProxyFactory.json @@ -23,21 +23,16 @@ "inputs": [ { "internalType": "address", - "name": "_singleton", + "name": "singleton", "type": "address" }, { "internalType": "bytes", - "name": "initializer", + "name": "data", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "saltNonce", - "type": "uint256" } ], - "name": "calculateCreateProxyWithNonceAddress", + "name": "createProxy", "outputs": [ { "internalType": "contract GnosisSafeProxy", @@ -47,21 +42,29 @@ ], "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610ebe806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80631688f0b9146100675780632500510e1461017657806353e5d9351461024357806361b69abd146102c6578063addacc0f146103cb578063d18af54d1461044e575b600080fd5b61014a6004803603606081101561007d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156100ba57600080fd5b8201836020820111156100cc57600080fd5b803590602001918460018302840111640100000000831117156100ee57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919050505061057d565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102176004803603606081101561018c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156101c957600080fd5b8201836020820111156101db57600080fd5b803590602001918460018302840111640100000000831117156101fd57600080fd5b909192939192939080359060200190929190505050610624565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61024b610751565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561028b578082015181840152602081019050610270565b50505050905090810190601f1680156102b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61039f600480360360408110156102dc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561031957600080fd5b82018360208201111561032b57600080fd5b8035906020019184600183028401116401000000008311171561034d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061077c565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103d3610861565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156104135780820151818401526020810190506103f8565b50505050905090810190601f1680156104405780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6105516004803603608081101561046457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156104a157600080fd5b8201836020820111156104b357600080fd5b803590602001918460018302840111640100000000831117156104d557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061088c565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600061058a848484610a3b565b90506000835111156105b25760008060008551602087016000865af114156105b157600080fd5b5b7f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2358185604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a19392505050565b60006106758585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a3b565b905080604051602001808273ffffffffffffffffffffffffffffffffffffffff1660601b81526014019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156107165780820151818401526020810190506106fb565b50505050905090810190601f1680156107435780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60606040518060200161076390610bde565b6020820181038252601f19601f82011660405250905090565b60008260405161078b90610bde565b808273ffffffffffffffffffffffffffffffffffffffff168152602001915050604051809103906000f0801580156107c7573d6000803e3d6000fd5b5090506000825111156107f05760008060008451602086016000865af114156107ef57600080fd5b5b7f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2358184604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a192915050565b60606040518060200161087390610beb565b6020820181038252601f19601f82011660405250905090565b6000808383604051602001808381526020018273ffffffffffffffffffffffffffffffffffffffff1660601b8152601401925050506040516020818303038152906040528051906020012060001c90506108e786868361057d565b9150600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610a32578273ffffffffffffffffffffffffffffffffffffffff16631e52b518838888886040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156109ca5780820151818401526020810190506109af565b50505050905090810190601f1680156109f75780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015610a1957600080fd5b505af1158015610a2d573d6000803e3d6000fd5b505050505b50949350505050565b6000808380519060200120836040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050600060405180602001610a8890610bde565b6020820181038252601f19601f820116604052508673ffffffffffffffffffffffffffffffffffffffff166040516020018083805190602001908083835b60208310610ae95780518252602082019150602081019050602083039250610ac6565b6001836020036101000a038019825116818451168082178552505050505050905001828152602001925050506040516020818303038152906040529050818151826020016000f59250600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610bd5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f437265617465322063616c6c206661696c65640000000000000000000000000081525060200191505060405180910390fd5b50509392505050565b6101e680610bf883390190565b60ab80610dde8339019056fe608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033a26469706673582212200c75fe2196b9f752c82794253f2ebce0d821afef5997e1d5a35ec316ce592f6664736f6c63430007060033", + "_disabled": [ { "inputs": [ { "internalType": "address", - "name": "singleton", + "name": "_singleton", "type": "address" }, { "internalType": "bytes", - "name": "data", + "name": "initializer", "type": "bytes" + }, + { + "internalType": "uint256", + "name": "saltNonce", + "type": "uint256" } ], - "name": "createProxy", + "name": "calculateCreateProxyWithNonceAddress", "outputs": [ { "internalType": "contract GnosisSafeProxy", @@ -161,6 +164,5 @@ "stateMutability": "pure", "type": "function" } - ], - "bytecode": "0x608060405234801561001057600080fd5b50610ebe806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80631688f0b9146100675780632500510e1461017657806353e5d9351461024357806361b69abd146102c6578063addacc0f146103cb578063d18af54d1461044e575b600080fd5b61014a6004803603606081101561007d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156100ba57600080fd5b8201836020820111156100cc57600080fd5b803590602001918460018302840111640100000000831117156100ee57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919050505061057d565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102176004803603606081101561018c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156101c957600080fd5b8201836020820111156101db57600080fd5b803590602001918460018302840111640100000000831117156101fd57600080fd5b909192939192939080359060200190929190505050610624565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61024b610751565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561028b578082015181840152602081019050610270565b50505050905090810190601f1680156102b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61039f600480360360408110156102dc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561031957600080fd5b82018360208201111561032b57600080fd5b8035906020019184600183028401116401000000008311171561034d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061077c565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103d3610861565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156104135780820151818401526020810190506103f8565b50505050905090810190601f1680156104405780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6105516004803603608081101561046457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156104a157600080fd5b8201836020820111156104b357600080fd5b803590602001918460018302840111640100000000831117156104d557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061088c565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600061058a848484610a3b565b90506000835111156105b25760008060008551602087016000865af114156105b157600080fd5b5b7f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2358185604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a19392505050565b60006106758585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a3b565b905080604051602001808273ffffffffffffffffffffffffffffffffffffffff1660601b81526014019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156107165780820151818401526020810190506106fb565b50505050905090810190601f1680156107435780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60606040518060200161076390610bde565b6020820181038252601f19601f82011660405250905090565b60008260405161078b90610bde565b808273ffffffffffffffffffffffffffffffffffffffff168152602001915050604051809103906000f0801580156107c7573d6000803e3d6000fd5b5090506000825111156107f05760008060008451602086016000865af114156107ef57600080fd5b5b7f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2358184604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a192915050565b60606040518060200161087390610beb565b6020820181038252601f19601f82011660405250905090565b6000808383604051602001808381526020018273ffffffffffffffffffffffffffffffffffffffff1660601b8152601401925050506040516020818303038152906040528051906020012060001c90506108e786868361057d565b9150600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610a32578273ffffffffffffffffffffffffffffffffffffffff16631e52b518838888886040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156109ca5780820151818401526020810190506109af565b50505050905090810190601f1680156109f75780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015610a1957600080fd5b505af1158015610a2d573d6000803e3d6000fd5b505050505b50949350505050565b6000808380519060200120836040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050600060405180602001610a8890610bde565b6020820181038252601f19601f820116604052508673ffffffffffffffffffffffffffffffffffffffff166040516020018083805190602001908083835b60208310610ae95780518252602082019150602081019050602083039250610ac6565b6001836020036101000a038019825116818451168082178552505050505050905001828152602001925050506040516020818303038152906040529050818151826020016000f59250600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610bd5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f437265617465322063616c6c206661696c65640000000000000000000000000081525060200191505060405180910390fd5b50509392505050565b6101e680610bf883390190565b60ab80610dde8339019056fe608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033a26469706673582212200c75fe2196b9f752c82794253f2ebce0d821afef5997e1d5a35ec316ce592f6664736f6c63430007060033" + ] } diff --git a/contracts/artifacts/HoneyswapRouter.json b/contracts/artifacts/HoneyswapRouter.json new file mode 100644 index 0000000000..c95b7fd70d --- /dev/null +++ b/contracts/artifacts/HoneyswapRouter.json @@ -0,0 +1,957 @@ +{ + "abi": [ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/crates/contracts/artifacts/HooksTrampoline.json b/contracts/artifacts/HooksTrampoline.json similarity index 100% rename from crates/contracts/artifacts/HooksTrampoline.json rename to contracts/artifacts/HooksTrampoline.json diff --git a/crates/contracts/artifacts/ICowWrapper.json b/contracts/artifacts/ICowWrapper.json similarity index 96% rename from crates/contracts/artifacts/ICowWrapper.json rename to contracts/artifacts/ICowWrapper.json index 4a5d36a0a5..845d9ced8b 100644 --- a/crates/contracts/artifacts/ICowWrapper.json +++ b/contracts/artifacts/ICowWrapper.json @@ -2,40 +2,42 @@ "abi": [ { "type": "function", - "name": "parseWrapperData", + "name": "wrappedSettle", "inputs": [ { - "name": "wrapperData", + "name": "settleData", "type": "bytes", "internalType": "bytes" - } - ], - "outputs": [ + }, { - "name": "remainingWrapperData", + "name": "wrapperData", "type": "bytes", "internalType": "bytes" } ], - "stateMutability": "view" - }, + "outputs": [], + "stateMutability": "nonpayable" + } + ], + "_disabled": [ { "type": "function", - "name": "wrappedSettle", + "name": "parseWrapperData", "inputs": [ { - "name": "settleData", + "name": "wrapperData", "type": "bytes", "internalType": "bytes" - }, + } + ], + "outputs": [ { - "name": "wrapperData", + "name": "remainingWrapperData", "type": "bytes", "internalType": "bytes" } ], - "outputs": [], - "stateMutability": "nonpayable" + "stateMutability": "view" } ] } diff --git a/contracts/artifacts/IERC4626.json b/contracts/artifacts/IERC4626.json new file mode 100644 index 0000000000..2d0eac6929 --- /dev/null +++ b/contracts/artifacts/IERC4626.json @@ -0,0 +1,36 @@ +{ + "abi": [ + { + "type": "function", + "name": "asset", + "inputs": [], + "outputs": [ + { + "name": "assetTokenAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "convertToAssets", + "inputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "assets", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + ] +} diff --git a/crates/contracts/artifacts/ISwaprPair.json b/contracts/artifacts/ISwaprPair.json similarity index 99% rename from crates/contracts/artifacts/ISwaprPair.json rename to contracts/artifacts/ISwaprPair.json index 9d1df4c75a..c14f3336a0 100644 --- a/crates/contracts/artifacts/ISwaprPair.json +++ b/contracts/artifacts/ISwaprPair.json @@ -183,36 +183,6 @@ "stateMutability": "view", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "MINIMUM_LIQUIDITY", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "pure", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "PERMIT_TYPEHASH", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "pure", - "type": "function" - }, { "constant": true, "inputs": [ @@ -387,21 +357,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "kLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": false, "inputs": [ @@ -504,66 +459,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "price0CumulativeLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "price1CumulativeLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "name": "setSwapFee", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "skim", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, { "constant": false, "inputs": [ @@ -663,21 +558,6 @@ "stateMutability": "view", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": false, "inputs": [ @@ -735,5 +615,127 @@ "stateMutability": "nonpayable", "type": "function" } + ], + "_disabled": [ + { + "constant": true, + "inputs": [], + "name": "MINIMUM_LIQUIDITY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "kLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "price0CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "price1CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "name": "setSwapFee", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "skim", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } ] } diff --git a/crates/contracts/artifacts/IUniswapLikePair.json b/contracts/artifacts/IUniswapLikePair.json similarity index 99% rename from crates/contracts/artifacts/IUniswapLikePair.json rename to contracts/artifacts/IUniswapLikePair.json index 7acd690da5..d4ddb0a82a 100644 --- a/crates/contracts/artifacts/IUniswapLikePair.json +++ b/contracts/artifacts/IUniswapLikePair.json @@ -181,32 +181,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "MINIMUM_LIQUIDITY", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "PERMIT_TYPEHASH", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, { "inputs": [ { @@ -365,19 +339,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "kLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -472,45 +433,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "price0CumulativeLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "price1CumulativeLast", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "skim", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -585,19 +507,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -651,5 +560,98 @@ "stateMutability": "nonpayable", "type": "function" } + ], + "_disabled": [ + { + "inputs": [], + "name": "MINIMUM_LIQUIDITY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "PERMIT_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "kLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "price0CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "price1CumulativeLast", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "skim", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } ] } diff --git a/crates/contracts/artifacts/IUniswapLikeRouter.json b/contracts/artifacts/IUniswapLikeRouter.json similarity index 99% rename from crates/contracts/artifacts/IUniswapLikeRouter.json rename to contracts/artifacts/IUniswapLikeRouter.json index 588a76b5d4..c95b7fd70d 100644 --- a/crates/contracts/artifacts/IUniswapLikeRouter.json +++ b/contracts/artifacts/IUniswapLikeRouter.json @@ -77,6 +77,89 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ { "inputs": [ { @@ -131,19 +214,6 @@ "stateMutability": "payable", "type": "function" }, - { - "inputs": [], - "name": "factory", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, { "inputs": [ { @@ -250,35 +320,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveB", - "type": "uint256" - } - ], - "name": "quote", - "outputs": [ - { - "internalType": "uint256", - "name": "amountB", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, { "inputs": [ { @@ -911,45 +952,6 @@ ], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountInMax", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapTokensForExactTokens", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" } ] } diff --git a/crates/contracts/artifacts/IUniswapV3Factory.json b/contracts/artifacts/IUniswapV3Factory.json similarity index 99% rename from crates/contracts/artifacts/IUniswapV3Factory.json rename to contracts/artifacts/IUniswapV3Factory.json index d23387dcc8..077e501648 100644 --- a/crates/contracts/artifacts/IUniswapV3Factory.json +++ b/contracts/artifacts/IUniswapV3Factory.json @@ -93,7 +93,7 @@ "type": "uint24" } ], - "name": "createPool", + "name": "getPool", "outputs": [ { "internalType": "address", @@ -101,46 +101,24 @@ "type": "address" } ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint24", - "name": "fee", - "type": "uint24" - }, - { - "internalType": "int24", - "name": "tickSpacing", - "type": "int24" - } - ], - "name": "enableFeeAmount", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "uint24", - "name": "fee", - "type": "uint24" - } - ], - "name": "feeAmountTickSpacing", + "inputs": [], + "name": "owner", "outputs": [ { - "internalType": "int24", + "internalType": "address", "name": "", - "type": "int24" + "type": "address" } ], "stateMutability": "view", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [ { @@ -159,7 +137,7 @@ "type": "uint24" } ], - "name": "getPool", + "name": "createPool", "outputs": [ { "internalType": "address", @@ -167,17 +145,41 @@ "type": "address" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "owner", + "inputs": [ + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + } + ], + "name": "enableFeeAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + } + ], + "name": "feeAmountTickSpacing", "outputs": [ { - "internalType": "address", + "internalType": "int24", "name": "", - "type": "address" + "type": "int24" } ], "stateMutability": "view", diff --git a/crates/contracts/artifacts/IZeroex.json b/contracts/artifacts/IZeroex.json similarity index 99% rename from crates/contracts/artifacts/IZeroex.json rename to contracts/artifacts/IZeroex.json index 74e5708e40..bb6f9e0225 100644 --- a/crates/contracts/artifacts/IZeroex.json +++ b/contracts/artifacts/IZeroex.json @@ -890,6 +890,24 @@ "name": "TransformerDeployerUpdated", "type": "event" }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "impl", + "type": "address" + } + ], + "name": "extend", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -990,25 +1008,10 @@ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" } ], - "name": "_fillLimitOrder", + "name": "fillOrKillLimitOrder", "outputs": [ - { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - }, { "internalType": "uint128", "name": "makerTokenFilledAmount", @@ -1042,117 +1045,9 @@ "name": "takerAmount", "type": "uint128" }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "txOrigin", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiryAndNonce", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.OtcOrder", - "name": "order", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature", - "name": "makerSignature", - "type": "tuple" - }, - { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "bool", - "name": "useSelfBalance", - "type": "bool" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ], - "name": "_fillOtcOrder", - "outputs": [ - { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, { "internalType": "uint128", - "name": "takerAmount", + "name": "takerTokenFeeAmount", "type": "uint128" }, { @@ -1167,7 +1062,12 @@ }, { "internalType": "address", - "name": "txOrigin", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "feeRecipient", "type": "address" }, { @@ -1186,7 +1086,7 @@ "type": "uint256" } ], - "internalType": "struct LibNativeOrder.RfqOrder", + "internalType": "struct LibNativeOrder.LimitOrder", "name": "order", "type": "tuple" }, @@ -1216,1778 +1116,1112 @@ "internalType": "struct LibSignature.Signature", "name": "signature", "type": "tuple" - }, - { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "bool", - "name": "useSelfBalance", - "type": "bool" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" } ], - "name": "_fillRfqOrder", + "name": "getLimitOrderRelevantState", "outputs": [ { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" + "components": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + }, + { + "internalType": "enum LibNativeOrder.OrderStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNativeOrder.OrderInfo", + "name": "orderInfo", + "type": "tuple" }, { "internalType": "uint128", - "name": "makerTokenFilledAmount", + "name": "actualFillableTakerTokenAmount", "type": "uint128" + }, + { + "internalType": "bool", + "name": "isSignatureValid", + "type": "bool" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "bytes", - "name": "encodedPath", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - }, + "inputs": [], + "name": "owner", + "outputs": [ { "internalType": "address", - "name": "recipient", + "name": "ownerAddress", "type": "address" } ], - "name": "_sellHeldTokenForTokenToUniswapV3", - "outputs": [ - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address payable", - "name": "taker", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "inputToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "outputToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "inputTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minOutputTokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint32", - "name": "deploymentNonce", - "type": "uint32" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct ITransformERC20Feature.Transformation[]", - "name": "transformations", - "type": "tuple[]" - }, - { - "internalType": "bool", - "name": "useSelfBalance", - "type": "bool" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - } - ], - "internalType": "struct ITransformERC20Feature.TransformERC20Args", - "name": "args", - "type": "tuple" - } - ], - "name": "_transformERC20", - "outputs": [ - { - "internalType": "uint256", - "name": "outputTokenAmount", - "type": "uint256" + } + ], + "devdoc": { + "details": "Interface for a fully featured Exchange Proxy.", + "kind": "dev", + "methods": { + "_fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,address)": { + "details": "Fill a limit order. Internal variant. ETH protocol fees can be attached to this call. Any unspent ETH will be refunded to `msg.sender` (not `sender`).", + "params": { + "order": "The limit order.", + "sender": "The order sender.", + "signature": "The order signature.", + "taker": "The order taker.", + "takerTokenFillAmount": "Maximum taker token to fill this order with." + }, + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much maker token was filled." } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" - }, - { - "internalType": "contract IERC1155Token", - "name": "erc1155Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc1155TokenId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc1155TokenProperties", - "type": "tuple[]" - }, - { - "internalType": "uint128", - "name": "erc1155TokenAmount", - "type": "uint128" - } - ], - "internalType": "struct LibNFTOrder.ERC1155Order[]", - "name": "sellOrders", - "type": "tuple[]" + }, + "_fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": { + "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Internal variant.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "recipient": "The recipient of the bought maker tokens.", + "taker": "The address to fill the order in the context of.", + "takerTokenFillAmount": "Maximum taker token amount to fill this order with.", + "useSelfBalance": "Whether to use the Exchange Proxy's balance of input tokens." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "signatures", - "type": "tuple[]" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much taker token was filled." + } + }, + "_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": { + "details": "Fill an RFQ order. Internal variant.", + "params": { + "order": "The RFQ order.", + "recipient": "The recipient of the maker tokens.", + "signature": "The order signature.", + "taker": "The order taker.", + "takerTokenFillAmount": "Maximum taker token to fill this order with.", + "useSelfBalance": "Whether to use the ExchangeProxy's transient balance of taker tokens to fill the order." }, - { - "internalType": "uint128[]", - "name": "erc1155TokenAmounts", - "type": "uint128[]" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much maker token was filled." + } + }, + "_sellHeldTokenForTokenToUniswapV3(bytes,uint256,uint256,address)": { + "details": "Sell a token for another token directly against uniswap v3. Private variant, uses tokens held by `address(this)`.", + "params": { + "encodedPath": "Uniswap-encoded path.", + "minBuyAmount": "Minimum amount of the last token in the path to buy.", + "recipient": "The recipient of the bought tokens. Can be zero for sender.", + "sellAmount": "amount of the first token in the path to sell." }, - { - "internalType": "bytes[]", - "name": "callbackData", - "type": "bytes[]" + "returns": { + "buyAmount": "Amount of the last token in the path bought." + } + }, + "_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))": { + "details": "Internal version of `transformERC20()`. Only callable from within.", + "params": { + "args": "A `TransformERC20Args` struct." }, - { - "internalType": "bool", - "name": "revertIfIncomplete", - "type": "bool" + "returns": { + "outputTokenAmount": "The amount of `outputToken` received by the taker." } - ], - "name": "batchBuyERC1155s", - "outputs": [ - { - "internalType": "bool[]", - "name": "successes", - "type": "bool[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" - }, - { - "internalType": "contract IERC721Token", - "name": "erc721Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc721TokenId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" - } - ], - "internalType": "struct LibNFTOrder.ERC721Order[]", - "name": "sellOrders", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "signatures", - "type": "tuple[]" + }, + "batchBuyERC1155s((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bytes[],bool)": { + "details": "Buys multiple ERC1155 assets by filling the given orders.", + "params": { + "callbackData": "The data (if any) to pass to the taker callback for each order. Refer to the `callbackData` parameter to for `buyERC1155`.", + "erc1155TokenAmounts": "The amounts of the ERC1155 assets to buy for each order.", + "revertIfIncomplete": "If true, reverts if this function fails to fill any individual order.", + "sellOrders": "The ERC1155 sell orders.", + "signatures": "The order signatures." }, - { - "internalType": "bytes[]", - "name": "callbackData", - "type": "bytes[]" + "returns": { + "successes": "An array of booleans corresponding to whether each order in `orders` was successfully filled." + } + }, + "batchBuyERC721s((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[])[],(uint8,uint8,bytes32,bytes32)[],bytes[],bool)": { + "details": "Buys multiple ERC721 assets by filling the given orders.", + "params": { + "callbackData": "The data (if any) to pass to the taker callback for each order. Refer to the `callbackData` parameter to for `buyERC721`.", + "revertIfIncomplete": "If true, reverts if this function fails to fill any individual order.", + "sellOrders": "The ERC721 sell orders.", + "signatures": "The order signatures." }, - { - "internalType": "bool", - "name": "revertIfIncomplete", - "type": "bool" + "returns": { + "successes": "An array of booleans corresponding to whether each order in `orders` was successfully filled." } - ], - "name": "batchBuyERC721s", - "outputs": [ - { - "internalType": "bool[]", - "name": "successes", - "type": "bool[]" + }, + "batchCancelERC1155Orders(uint256[])": { + "details": "Cancel multiple ERC1155 orders by their nonces. The caller should be the maker of the orders. Silently succeeds if an order with the same nonce has already been filled or cancelled.", + "params": { + "orderNonces": "The order nonces." } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "orderNonces", - "type": "uint256[]" + }, + "batchCancelERC721Orders(uint256[])": { + "details": "Cancel multiple ERC721 orders by their nonces. The caller should be the maker of the orders. Silently succeeds if an order with the same nonce has already been filled or cancelled.", + "params": { + "orderNonces": "The order nonces." } - ], - "name": "batchCancelERC1155Orders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "orderNonces", - "type": "uint256[]" + }, + "batchCancelLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[])": { + "details": "Cancel multiple limit orders. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", + "params": { + "orders": "The limit orders." } - ], - "name": "batchCancelERC721Orders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerTokenFeeAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "feeRecipient", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.LimitOrder[]", - "name": "orders", - "type": "tuple[]" + }, + "batchCancelPairLimitOrders(address[],address[],uint256[])": { + "details": "Cancel all limit orders for a given maker and pairs with salts less than the values provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", + "params": { + "makerTokens": "The maker tokens.", + "minValidSalts": "The new minimum valid salts.", + "takerTokens": "The taker tokens." } - ], - "name": "batchCancelLimitOrders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06[]", - "name": "makerTokens", - "type": "address[]" - }, - { - "internalType": "contract IERC20TokenV06[]", - "name": "takerTokens", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "minValidSalts", - "type": "uint256[]" + }, + "batchCancelPairLimitOrdersWithSigner(address,address[],address[],uint256[])": { + "details": "Cancel all limit orders for a given maker and pairs with salts less than the values provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", + "params": { + "maker": "The maker for which to cancel.", + "makerTokens": "The maker tokens.", + "minValidSalts": "The new minimum valid salts.", + "takerTokens": "The taker tokens." } - ], - "name": "batchCancelPairLimitOrders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06[]", - "name": "makerTokens", - "type": "address[]" + }, + "batchCancelPairRfqOrders(address[],address[],uint256[])": { + "details": "Cancel all RFQ orders for a given maker and pairs with salts less than the values provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", + "params": { + "makerTokens": "The maker tokens.", + "minValidSalts": "The new minimum valid salts.", + "takerTokens": "The taker tokens." + } + }, + "batchCancelPairRfqOrdersWithSigner(address,address[],address[],uint256[])": { + "details": "Cancel all RFQ orders for a given maker and pairs with salts less than the values provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", + "params": { + "maker": "The maker for which to cancel.", + "makerTokens": "The maker tokens.", + "minValidSalts": "The new minimum valid salts.", + "takerTokens": "The taker tokens." + } + }, + "batchCancelRfqOrders((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[])": { + "details": "Cancel multiple RFQ orders. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", + "params": { + "orders": "The RFQ orders." + } + }, + "batchExecuteMetaTransactions((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { + "details": "Execute multiple meta-transactions.", + "params": { + "mtxs": "The meta-transactions.", + "signatures": "The signature by each respective `mtx.signer`." }, - { - "internalType": "contract IERC20TokenV06[]", - "name": "takerTokens", - "type": "address[]" + "returns": { + "returnResults": "The ABI-encoded results of the underlying calls." + } + }, + "batchFillLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bool)": { + "details": "Fills multiple limit orders.", + "params": { + "orders": "Array of limit orders.", + "revertIfIncomplete": "If true, reverts if this function fails to fill the full fill amount for any individual order.", + "signatures": "Array of signatures corresponding to each order.", + "takerTokenFillAmounts": "Array of desired amounts to fill each order." }, - { - "internalType": "uint256[]", - "name": "minValidSalts", - "type": "uint256[]" + "returns": { + "makerTokenFilledAmounts": "Array of amounts filled, in maker token.", + "takerTokenFilledAmounts": "Array of amounts filled, in taker token." } - ], - "name": "batchCancelPairLimitOrdersWithSigner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06[]", - "name": "makerTokens", - "type": "address[]" + }, + "batchFillRfqOrders((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bool)": { + "details": "Fills multiple RFQ orders.", + "params": { + "orders": "Array of RFQ orders.", + "revertIfIncomplete": "If true, reverts if this function fails to fill the full fill amount for any individual order.", + "signatures": "Array of signatures corresponding to each order.", + "takerTokenFillAmounts": "Array of desired amounts to fill each order." }, - { - "internalType": "contract IERC20TokenV06[]", - "name": "takerTokens", - "type": "address[]" + "returns": { + "makerTokenFilledAmounts": "Array of amounts filled, in maker token.", + "takerTokenFilledAmounts": "Array of amounts filled, in taker token." + } + }, + "batchFillTakerSignedOtcOrders((address,address,uint128,uint128,address,address,address,uint256)[],(uint8,uint8,bytes32,bytes32)[],(uint8,uint8,bytes32,bytes32)[],bool[])": { + "details": "Fills multiple taker-signed OTC orders.", + "params": { + "makerSignatures": "Array of maker signatures for each order.", + "orders": "Array of OTC orders.", + "takerSignatures": "Array of taker signatures for each order.", + "unwrapWeth": "Array of booleans representing whether or not to unwrap bought WETH into ETH for each order. Should be set to false if the maker token is not WETH." }, - { - "internalType": "uint256[]", - "name": "minValidSalts", - "type": "uint256[]" + "returns": { + "successes": "Array of booleans representing whether or not each order in `orders` was filled successfully." } - ], - "name": "batchCancelPairRfqOrders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "maker", - "type": "address" + }, + "batchGetLimitOrderRelevantStates((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { + "details": "Batch version of `getLimitOrderRelevantState()`, without reverting. Orders that would normally cause `getLimitOrderRelevantState()` to revert will have empty results.", + "params": { + "orders": "The limit orders.", + "signatures": "The order signatures." }, - { - "internalType": "contract IERC20TokenV06[]", - "name": "makerTokens", - "type": "address[]" + "returns": { + "actualFillableTakerTokenAmounts": "How much of each order is fillable based on maker funds, in taker tokens.", + "isSignatureValids": "Whether each signature is valid for the order.", + "orderInfos": "Info about the orders." + } + }, + "batchGetRfqOrderRelevantStates((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { + "details": "Batch version of `getRfqOrderRelevantState()`, without reverting. Orders that would normally cause `getRfqOrderRelevantState()` to revert will have empty results.", + "params": { + "orders": "The RFQ orders.", + "signatures": "The order signatures." }, - { - "internalType": "contract IERC20TokenV06[]", - "name": "takerTokens", - "type": "address[]" + "returns": { + "actualFillableTakerTokenAmounts": "How much of each order is fillable based on maker funds, in taker tokens.", + "isSignatureValids": "Whether each signature is valid for the order.", + "orderInfos": "Info about the orders." + } + }, + "batchMatchERC721Orders((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[])[],(uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[])[],(uint8,uint8,bytes32,bytes32)[],(uint8,uint8,bytes32,bytes32)[])": { + "details": "Matches pairs of complementary orders that have non-negative spreads. Each order is filled at their respective price, and the matcher receives a profit denominated in the ERC20 token.", + "params": { + "buyOrderSignatures": "Signatures for the buy orders.", + "buyOrders": "Orders buying ERC721 assets.", + "sellOrderSignatures": "Signatures for the sell orders.", + "sellOrders": "Orders selling ERC721 assets." }, - { - "internalType": "uint256[]", - "name": "minValidSalts", - "type": "uint256[]" + "returns": { + "profits": "The amount of profit earned by the caller of this function for each pair of matched orders (denominated in the ERC20 token of the order pair).", + "successes": "An array of booleans corresponding to whether each pair of orders was successfully matched." } - ], - "name": "batchCancelPairRfqOrdersWithSigner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "txOrigin", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.RfqOrder[]", - "name": "orders", - "type": "tuple[]" + }, + "buyERC1155((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),(uint8,uint8,bytes32,bytes32),uint128,bytes)": { + "details": "Buys an ERC1155 asset by filling the given order.", + "params": { + "callbackData": "If this parameter is non-zero, invokes `zeroExERC1155OrderCallback` on `msg.sender` after the ERC1155 asset has been transferred to `msg.sender` but before transferring the ERC20 tokens to the seller. Native tokens acquired during the callback can be used to fill the order.", + "erc1155BuyAmount": "The amount of the ERC1155 asset to buy.", + "sellOrder": "The ERC1155 sell order.", + "signature": "The order signature." } - ], - "name": "batchCancelRfqOrders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address payable", - "name": "signer", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minGasPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "feeToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "feeAmount", - "type": "uint256" - } - ], - "internalType": "struct IMetaTransactionsFeature.MetaTransactionData[]", - "name": "mtxs", - "type": "tuple[]" + }, + "buyERC721((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32),bytes)": { + "details": "Buys an ERC721 asset by filling the given order.", + "params": { + "callbackData": "If this parameter is non-zero, invokes `zeroExERC721OrderCallback` on `msg.sender` after the ERC721 asset has been transferred to `msg.sender` but before transferring the ERC20 tokens to the seller. Native tokens acquired during the callback can be used to fill the order.", + "sellOrder": "The ERC721 sell order.", + "signature": "The order signature." + } + }, + "cancelERC1155Order(uint256)": { + "details": "Cancel a single ERC1155 order by its nonce. The caller should be the maker of the order. Silently succeeds if an order with the same nonce has already been filled or cancelled.", + "params": { + "orderNonce": "The order nonce." + } + }, + "cancelERC721Order(uint256)": { + "details": "Cancel a single ERC721 order by its nonce. The caller should be the maker of the order. Silently succeeds if an order with the same nonce has already been filled or cancelled.", + "params": { + "orderNonce": "The order nonce." + } + }, + "cancelLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { + "details": "Cancel a single limit order. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", + "params": { + "order": "The limit order." + } + }, + "cancelPairLimitOrders(address,address,uint256)": { + "details": "Cancel all limit orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", + "params": { + "makerToken": "The maker token.", + "minValidSalt": "The new minimum valid salt.", + "takerToken": "The taker token." + } + }, + "cancelPairLimitOrdersWithSigner(address,address,address,uint256)": { + "details": "Cancel all limit orders for a given maker and pair with a salt less than the value provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", + "params": { + "maker": "The maker for which to cancel.", + "makerToken": "The maker token.", + "minValidSalt": "The new minimum valid salt.", + "takerToken": "The taker token." + } + }, + "cancelPairRfqOrders(address,address,uint256)": { + "details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", + "params": { + "makerToken": "The maker token.", + "minValidSalt": "The new minimum valid salt.", + "takerToken": "The taker token." + } + }, + "cancelPairRfqOrdersWithSigner(address,address,address,uint256)": { + "details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", + "params": { + "maker": "The maker for which to cancel.", + "makerToken": "The maker token.", + "minValidSalt": "The new minimum valid salt.", + "takerToken": "The taker token." + } + }, + "cancelRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": { + "details": "Cancel a single RFQ order. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", + "params": { + "order": "The RFQ order." + } + }, + "createTransformWallet()": { + "details": "Deploy a new flash wallet instance and replace the current one with it. Useful if we somehow break the current wallet instance. Only callable by the owner.", + "returns": { + "wallet": "The new wallet instance." + } + }, + "executeMetaTransaction((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256),(uint8,uint8,bytes32,bytes32))": { + "details": "Execute a single meta-transaction.", + "params": { + "mtx": "The meta-transaction.", + "signature": "The signature by `mtx.signer`." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "signatures", - "type": "tuple[]" + "returns": { + "returnResult": "The ABI-encoded result of the underlying call." } - ], - "name": "batchExecuteMetaTransactions", - "outputs": [ - { - "internalType": "bytes[]", - "name": "returnResults", - "type": "bytes[]" + }, + "extend(bytes4,address)": { + "details": "Register or replace a function.", + "params": { + "impl": "The implementation contract for the function.", + "selector": "The function selector." } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerTokenFeeAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "feeRecipient", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.LimitOrder[]", - "name": "orders", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "signatures", - "type": "tuple[]" - }, - { - "internalType": "uint128[]", - "name": "takerTokenFillAmounts", - "type": "uint128[]" + }, + "fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { + "details": "Fill a limit order. The taker and sender will be the caller.", + "params": { + "order": "The limit order. ETH protocol fees can be attached to this call. Any unspent ETH will be refunded to the caller.", + "signature": "The order signature.", + "takerTokenFillAmount": "Maximum taker token amount to fill this order with." }, - { - "internalType": "bool", - "name": "revertIfIncomplete", - "type": "bool" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much maker token was filled." } - ], - "name": "batchFillLimitOrders", - "outputs": [ - { - "internalType": "uint128[]", - "name": "takerTokenFilledAmounts", - "type": "uint128[]" + }, + "fillOrKillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { + "details": "Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens. The taker will be the caller. ETH protocol fees can be attached to this call. Any unspent ETH will be refunded to the caller.", + "params": { + "order": "The limit order.", + "signature": "The order signature.", + "takerTokenFillAmount": "How much taker token to fill this order with." }, - { - "internalType": "uint128[]", - "name": "makerTokenFilledAmounts", - "type": "uint128[]" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled." } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "txOrigin", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.RfqOrder[]", - "name": "orders", - "type": "tuple[]" + }, + "fillOrKillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { + "details": "Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens. The taker will be the caller.", + "params": { + "order": "The RFQ order.", + "signature": "The order signature.", + "takerTokenFillAmount": "How much taker token to fill this order with." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "signatures", - "type": "tuple[]" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled." + } + }, + "fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { + "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "takerTokenFillAmount": "Maximum taker token amount to fill this order with." }, - { - "internalType": "uint128[]", - "name": "takerTokenFillAmounts", - "type": "uint128[]" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much taker token was filled." + } + }, + "fillOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { + "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Unwraps bought WETH into ETH before sending it to the taker.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "takerTokenFillAmount": "Maximum taker token amount to fill this order with." }, - { - "internalType": "bool", - "name": "revertIfIncomplete", - "type": "bool" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much taker token was filled." } - ], - "name": "batchFillRfqOrders", - "outputs": [ - { - "internalType": "uint128[]", - "name": "takerTokenFilledAmounts", - "type": "uint128[]" + }, + "fillOtcOrderWithEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32))": { + "details": "Fill an OTC order whose taker token is WETH for up to `msg.value`.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order." }, - { - "internalType": "uint128[]", - "name": "makerTokenFilledAmounts", - "type": "uint128[]" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much taker token was filled." } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "txOrigin", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiryAndNonce", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.OtcOrder[]", - "name": "orders", - "type": "tuple[]" + }, + "fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { + "details": "Fill an RFQ order for up to `takerTokenFillAmount` taker tokens. The taker will be the caller.", + "params": { + "order": "The RFQ order.", + "signature": "The order signature.", + "takerTokenFillAmount": "Maximum taker token amount to fill this order with." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "makerSignatures", - "type": "tuple[]" + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much maker token was filled." + } + }, + "fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { + "details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "takerSignature": "The order signature from the taker." + } + }, + "fillTakerSignedOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { + "details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker. Unwraps bought WETH into ETH before sending it to the taker.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "takerSignature": "The order signature from the taker." + } + }, + "getERC1155OrderHash((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128))": { + "details": "Get the EIP-712 hash of an ERC1155 order.", + "params": { + "order": "The ERC1155 order." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "takerSignatures", - "type": "tuple[]" + "returns": { + "orderHash": "The order hash." + } + }, + "getERC1155OrderInfo((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128))": { + "details": "Get the order info for an ERC1155 order.", + "params": { + "order": "The ERC1155 order." }, - { - "internalType": "bool[]", - "name": "unwrapWeth", - "type": "bool[]" + "returns": { + "orderInfo": "Infor about the order." } - ], - "name": "batchFillTakerSignedOtcOrders", - "outputs": [ - { - "internalType": "bool[]", - "name": "successes", - "type": "bool[]" + }, + "getERC721OrderHash((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]))": { + "details": "Get the EIP-712 hash of an ERC721 order.", + "params": { + "order": "The ERC721 order." + }, + "returns": { + "orderHash": "The order hash." } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerTokenFeeAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "feeRecipient", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.LimitOrder[]", - "name": "orders", - "type": "tuple[]" + }, + "getERC721OrderStatus((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]))": { + "details": "Get the current status of an ERC721 order.", + "params": { + "order": "The ERC721 order." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "signatures", - "type": "tuple[]" + "returns": { + "status": "The status of the order." } - ], - "name": "batchGetLimitOrderRelevantStates", - "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - }, - { - "internalType": "enum LibNativeOrder.OrderStatus", - "name": "status", - "type": "uint8" - }, - { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - } - ], - "internalType": "struct LibNativeOrder.OrderInfo[]", - "name": "orderInfos", - "type": "tuple[]" + }, + "getERC721OrderStatusBitVector(address,uint248)": { + "details": "Get the order status bit vector for the given maker address and nonce range.", + "params": { + "maker": "The maker of the order.", + "nonceRange": "Order status bit vectors are indexed by maker address and the upper 248 bits of the order nonce. We define `nonceRange` to be these 248 bits." }, - { - "internalType": "uint128[]", - "name": "actualFillableTakerTokenAmounts", - "type": "uint128[]" + "returns": { + "bitVector": "The order status bit vector for the given maker and nonce range." + } + }, + "getLimitOrderHash((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { + "details": "Get the canonical hash of a limit order.", + "params": { + "order": "The limit order." }, - { - "internalType": "bool[]", - "name": "isSignatureValids", - "type": "bool[]" + "returns": { + "orderHash": "The order hash." } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "address", - "name": "txOrigin", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.RfqOrder[]", - "name": "orders", - "type": "tuple[]" + }, + "getLimitOrderInfo((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { + "details": "Get the order info for a limit order.", + "params": { + "order": "The limit order." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "signatures", - "type": "tuple[]" + "returns": { + "orderInfo": "Info about the order." } - ], - "name": "batchGetRfqOrderRelevantStates", - "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - }, - { - "internalType": "enum LibNativeOrder.OrderStatus", - "name": "status", - "type": "uint8" - }, - { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - } - ], - "internalType": "struct LibNativeOrder.OrderInfo[]", - "name": "orderInfos", - "type": "tuple[]" + }, + "getLimitOrderRelevantState((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32))": { + "details": "Get order info, fillable amount, and signature validity for a limit order. Fillable amount is determined using balances and allowances of the maker.", + "params": { + "order": "The limit order.", + "signature": "The order signature." }, - { - "internalType": "uint128[]", - "name": "actualFillableTakerTokenAmounts", - "type": "uint128[]" + "returns": { + "actualFillableTakerTokenAmount": "How much of the order is fillable based on maker funds, in taker tokens.", + "isSignatureValid": "Whether the signature is valid.", + "orderInfo": "Info about the order." + } + }, + "getMetaTransactionExecutedBlock((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256))": { + "details": "Get the block at which a meta-transaction has been executed.", + "params": { + "mtx": "The meta-transaction." }, - { - "internalType": "bool[]", - "name": "isSignatureValids", - "type": "bool[]" + "returns": { + "blockNumber": "The block height when the meta-transactioin was executed." } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" - }, - { - "internalType": "contract IERC721Token", - "name": "erc721Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc721TokenId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" - } - ], - "internalType": "struct LibNFTOrder.ERC721Order[]", - "name": "sellOrders", - "type": "tuple[]" + }, + "getMetaTransactionHash((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256))": { + "details": "Get the EIP712 hash of a meta-transaction.", + "params": { + "mtx": "The meta-transaction." + }, + "returns": { + "mtxHash": "The EIP712 hash of `mtx`." + } + }, + "getMetaTransactionHashExecutedBlock(bytes32)": { + "details": "Get the block at which a meta-transaction hash has been executed.", + "params": { + "mtxHash": "The meta-transaction hash." + }, + "returns": { + "blockNumber": "The block height when the meta-transactioin was executed." + } + }, + "getOtcOrderHash((address,address,uint128,uint128,address,address,address,uint256))": { + "details": "Get the canonical hash of an OTC order.", + "params": { + "order": "The OTC order." + }, + "returns": { + "orderHash": "The order hash." + } + }, + "getOtcOrderInfo((address,address,uint128,uint128,address,address,address,uint256))": { + "details": "Get the order info for an OTC order.", + "params": { + "order": "The OTC order." + }, + "returns": { + "orderInfo": "Info about the order." + } + }, + "getProtocolFeeMultiplier()": { + "details": "Get the protocol fee multiplier. This should be multiplied by the gas price to arrive at the required protocol fee to fill a native order.", + "returns": { + "multiplier": "The protocol fee multiplier." + } + }, + "getQuoteSigner()": { + "details": "Return the optional signer for `transformERC20()` calldata.", + "returns": { + "signer": "The transform deployer address." + } + }, + "getRfqOrderHash((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": { + "details": "Get the canonical hash of an RFQ order.", + "params": { + "order": "The RFQ order." + }, + "returns": { + "orderHash": "The order hash." + } + }, + "getRfqOrderInfo((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": { + "details": "Get the order info for an RFQ order.", + "params": { + "order": "The RFQ order." + }, + "returns": { + "orderInfo": "Info about the order." + } + }, + "getRfqOrderRelevantState((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32))": { + "details": "Get order info, fillable amount, and signature validity for an RFQ order. Fillable amount is determined using balances and allowances of the maker.", + "params": { + "order": "The RFQ order.", + "signature": "The order signature." + }, + "returns": { + "actualFillableTakerTokenAmount": "How much of the order is fillable based on maker funds, in taker tokens.", + "isSignatureValid": "Whether the signature is valid.", + "orderInfo": "Info about the order." + } + }, + "getRollbackEntryAtIndex(bytes4,uint256)": { + "details": "Retrieve an entry in the rollback history for a function.", + "params": { + "idx": "The index in the rollback history.", + "selector": "The function selector." + }, + "returns": { + "impl": "An implementation address for the function at index `idx`." + } + }, + "getRollbackLength(bytes4)": { + "details": "Retrieve the length of the rollback history for a function.", + "params": { + "selector": "The function selector." + }, + "returns": { + "rollbackLength": "The number of items in the rollback history for the function." + } + }, + "getTransformWallet()": { + "details": "Return the current wallet instance that will serve as the execution context for transformations.", + "returns": { + "wallet": "The wallet instance." + } + }, + "getTransformerDeployer()": { + "details": "Return the allowed deployer for transformers.", + "returns": { + "deployer": "The transform deployer address." + } + }, + "isValidOrderSigner(address,address)": { + "details": "checks if a given address is registered to sign on behalf of a maker address", + "params": { + "maker": "The maker address encoded in an order (can be a contract)", + "signer": "The address that is providing a signature" + } + }, + "lastOtcTxOriginNonce(address,uint64)": { + "details": "Get the last nonce used for a particular tx.origin address and nonce bucket.", + "params": { + "nonceBucket": "The nonce bucket index.", + "txOrigin": "The address." + }, + "returns": { + "lastNonce": "The last nonce value used." + } + }, + "matchERC721Orders((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { + "details": "Matches a pair of complementary orders that have a non-negative spread. Each order is filled at their respective price, and the matcher receives a profit denominated in the ERC20 token.", + "params": { + "buyOrder": "Order buying an ERC721 asset.", + "buyOrderSignature": "Signature for the buy order.", + "sellOrder": "Order selling an ERC721 asset.", + "sellOrderSignature": "Signature for the sell order." + }, + "returns": { + "profit": "The amount of profit earned by the caller of this function (denominated in the ERC20 token of the matched orders)." + } + }, + "migrate(address,bytes,address)": { + "details": "Execute a migration function in the context of the ZeroEx contract. The result of the function being called should be the magic bytes 0x2c64c5ef (`keccack('MIGRATE_SUCCESS')`). Only callable by the owner. The owner will be temporarily set to `address(this)` inside the call. Before returning, the owner will be set to `newOwner`.", + "params": { + "data": "The call data.", + "newOwner": "The address of the new owner.", + "target": "The migrator contract address." + } + }, + "multiplexBatchSellEthForToken(address,(uint8,uint256,bytes)[],uint256)": { + "details": "Sells attached ETH for `outputToken` using the provided calls.", + "params": { + "calls": "The calls to use to sell the attached ETH.", + "minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.", + "outputToken": "The token to buy." + }, + "returns": { + "boughtAmount": "The amount of `outputToken` bought." + } + }, + "multiplexBatchSellTokenForEth(address,(uint8,uint256,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the given `inputToken` for ETH using the provided calls.", + "params": { + "calls": "The calls to use to sell the input tokens.", + "inputToken": "The token to sell.", + "minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.", + "sellAmount": "The amount of `inputToken` to sell." + }, + "returns": { + "boughtAmount": "The amount of ETH bought." + } + }, + "multiplexBatchSellTokenForToken(address,address,(uint8,uint256,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the given `inputToken` for `outputToken` using the provided calls.", + "params": { + "calls": "The calls to use to sell the input tokens.", + "inputToken": "The token to sell.", + "minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.", + "outputToken": "The token to buy.", + "sellAmount": "The amount of `inputToken` to sell." + }, + "returns": { + "boughtAmount": "The amount of `outputToken` bought." + } + }, + "multiplexMultiHopSellEthForToken(address[],(uint8,bytes)[],uint256)": { + "details": "Sells attached ETH via the given sequence of tokens and calls. `tokens[0]` must be WETH. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`", + "params": { + "calls": "The sequence of calls to use for the sell.", + "minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.", + "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + }, + "returns": { + "boughtAmount": "The amount of output tokens bought." + } + }, + "multiplexMultiHopSellTokenForEth(address[],(uint8,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the input token (`tokens[0]`) for ETH via the given sequence of tokens and calls. The last token in `tokens` must be WETH.", + "params": { + "calls": "The sequence of calls to use for the sell.", + "minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.", + "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + }, + "returns": { + "boughtAmount": "The amount of ETH bought." + } + }, + "multiplexMultiHopSellTokenForToken(address[],(uint8,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the input token (`tokens[0]`) via the given sequence of tokens and calls. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`", + "params": { + "calls": "The sequence of calls to use for the sell.", + "minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.", + "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + }, + "returns": { + "boughtAmount": "The amount of output tokens bought." + } + }, + "onERC1155Received(address,address,uint256,uint256,bytes)": { + "details": "Callback for the ERC1155 `safeTransferFrom` function. This callback can be used to sell an ERC1155 asset if a valid ERC1155 order, signature and `unwrapNativeToken` are encoded in `data`. This allows takers to sell their ERC1155 asset without first calling `setApprovalForAll`.", + "params": { + "data": "Additional data with no specified format. If a valid ERC1155 order, signature and `unwrapNativeToken` are encoded in `data`, this function will try to fill the order using the received asset.", + "from": "The address which previously owned the token.", + "operator": "The address which called `safeTransferFrom`.", + "tokenId": "The ID of the asset being transferred.", + "value": "The amount being transferred." + }, + "returns": { + "success": "The selector of this function (0xf23a6e61), indicating that the callback succeeded." + } + }, + "onERC721Received(address,address,uint256,bytes)": { + "details": "Callback for the ERC721 `safeTransferFrom` function. This callback can be used to sell an ERC721 asset if a valid ERC721 order, signature and `unwrapNativeToken` are encoded in `data`. This allows takers to sell their ERC721 asset without first calling `setApprovalForAll`.", + "params": { + "data": "Additional data with no specified format. If a valid ERC721 order, signature and `unwrapNativeToken` are encoded in `data`, this function will try to fill the order using the received asset.", + "from": "The address which previously owned the token.", + "operator": "The address which called `safeTransferFrom`.", + "tokenId": "The ID of the asset being transferred." + }, + "returns": { + "success": "The selector of this function (0x150b7a02), indicating that the callback succeeded." + } + }, + "owner()": { + "details": "The owner of this contract.", + "returns": { + "ownerAddress": "The owner address." + } + }, + "preSignERC1155Order((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128))": { + "details": "Approves an ERC1155 order on-chain. After pre-signing the order, the `PRESIGNED` signature type will become valid for that order and signer.", + "params": { + "order": "An ERC1155 order." + } + }, + "preSignERC721Order((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]))": { + "details": "Approves an ERC721 order on-chain. After pre-signing the order, the `PRESIGNED` signature type will become valid for that order and signer.", + "params": { + "order": "An ERC721 order." + } + }, + "registerAllowedOrderSigner(address,bool)": { + "details": "Register a signer who can sign on behalf of msg.sender This allows one to sign on behalf of a contract that calls this function", + "params": { + "allowed": "True to register, false to unregister.", + "signer": "The address from which you plan to generate signatures" + } + }, + "registerAllowedRfqOrigins(address[],bool)": { + "details": "Mark what tx.origin addresses are allowed to fill an order that specifies the message sender as its txOrigin.", + "params": { + "allowed": "True to register, false to unregister.", + "origins": "An array of origin addresses to update." + } + }, + "rollback(bytes4,address)": { + "details": "Roll back to a prior implementation of a function.", + "params": { + "selector": "The function selector.", + "targetImpl": "The address of an older implementation of the function." + } + }, + "sellERC1155((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),(uint8,uint8,bytes32,bytes32),uint256,uint128,bool,bytes)": { + "details": "Sells an ERC1155 asset to fill the given order.", + "params": { + "buyOrder": "The ERC1155 buy order.", + "callbackData": "If this parameter is non-zero, invokes `zeroExERC1155OrderCallback` on `msg.sender` after the ERC20 tokens have been transferred to `msg.sender` but before transferring the ERC1155 asset to the buyer.", + "erc1155SellAmount": "The amount of the ERC1155 asset to sell.", + "erc1155TokenId": "The ID of the ERC1155 asset being sold. If the given order specifies properties, the asset must satisfy those properties. Otherwise, it must equal the tokenId in the order.", + "signature": "The order signature from the maker.", + "unwrapNativeToken": "If this parameter is true and the ERC20 token of the order is e.g. WETH, unwraps the token before transferring it to the taker." + } + }, + "sellERC721((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32),uint256,bool,bytes)": { + "details": "Sells an ERC721 asset to fill the given order.", + "params": { + "buyOrder": "The ERC721 buy order.", + "callbackData": "If this parameter is non-zero, invokes `zeroExERC721OrderCallback` on `msg.sender` after the ERC20 tokens have been transferred to `msg.sender` but before transferring the ERC721 asset to the buyer.", + "erc721TokenId": "The ID of the ERC721 asset being sold. If the given order specifies properties, the asset must satisfy those properties. Otherwise, it must equal the tokenId in the order.", + "signature": "The order signature from the maker.", + "unwrapNativeToken": "If this parameter is true and the ERC20 token of the order is e.g. WETH, unwraps the token before transferring it to the taker." + } + }, + "sellEthForTokenToUniswapV3(bytes,uint256,address)": { + "details": "Sell attached ETH directly against uniswap v3.", + "params": { + "encodedPath": "Uniswap-encoded path, where the first token is WETH.", + "minBuyAmount": "Minimum amount of the last token in the path to buy.", + "recipient": "The recipient of the bought tokens. Can be zero for sender." + }, + "returns": { + "buyAmount": "Amount of the last token in the path bought." + } + }, + "sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)": { + "details": "Sells `sellAmount` of `inputToken` to the liquidity provider at the given `provider` address.", + "params": { + "auxiliaryData": "Auxiliary data supplied to the `provider` contract.", + "inputToken": "The token being sold.", + "minBuyAmount": "The minimum acceptable amount of `outputToken` to buy. Reverts if this amount is not satisfied.", + "outputToken": "The token being bought.", + "provider": "The address of the on-chain liquidity provider to trade with.", + "recipient": "The recipient of the bought tokens. If equal to address(0), `msg.sender` is assumed to be the recipient.", + "sellAmount": "The amount of `inputToken` to sell." + }, + "returns": { + "boughtAmount": "The amount of `outputToken` bought." + } + }, + "sellToPancakeSwap(address[],uint256,uint256,uint8)": { + "details": "Efficiently sell directly to PancakeSwap (and forks).", + "params": { + "fork": "The protocol fork to use.", + "minBuyAmount": "Minimum amount of `tokens[-1]` to buy.", + "sellAmount": "of `tokens[0]` Amount to sell.", + "tokens": "Sell path." }, - { - "components": [ - { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" - }, - { - "internalType": "contract IERC721Token", - "name": "erc721Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc721TokenId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" - } - ], - "internalType": "struct LibNFTOrder.ERC721Order[]", - "name": "buyOrders", - "type": "tuple[]" + "returns": { + "buyAmount": "Amount of `tokens[-1]` bought." + } + }, + "sellToUniswap(address[],uint256,uint256,bool)": { + "details": "Efficiently sell directly to uniswap/sushiswap.", + "params": { + "isSushi": "Use sushiswap if true.", + "minBuyAmount": "Minimum amount of `tokens[-1]` to buy.", + "sellAmount": "of `tokens[0]` Amount to sell.", + "tokens": "Sell path." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "sellOrderSignatures", - "type": "tuple[]" + "returns": { + "buyAmount": "Amount of `tokens[-1]` bought." + } + }, + "sellTokenForEthToUniswapV3(bytes,uint256,uint256,address)": { + "details": "Sell a token for ETH directly against uniswap v3.", + "params": { + "encodedPath": "Uniswap-encoded path, where the last token is WETH.", + "minBuyAmount": "Minimum amount of ETH to buy.", + "recipient": "The recipient of the bought tokens. Can be zero for sender.", + "sellAmount": "amount of the first token in the path to sell." }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature[]", - "name": "buyOrderSignatures", - "type": "tuple[]" + "returns": { + "buyAmount": "Amount of ETH bought." + } + }, + "sellTokenForTokenToUniswapV3(bytes,uint256,uint256,address)": { + "details": "Sell a token for another token directly against uniswap v3.", + "params": { + "encodedPath": "Uniswap-encoded path.", + "minBuyAmount": "Minimum amount of the last token in the path to buy.", + "recipient": "The recipient of the bought tokens. Can be zero for sender.", + "sellAmount": "amount of the first token in the path to sell." + }, + "returns": { + "buyAmount": "Amount of the last token in the path bought." + } + }, + "setQuoteSigner(address)": { + "details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.", + "params": { + "quoteSigner": "The address of the new calldata signer." + } + }, + "setTransformerDeployer(address)": { + "details": "Replace the allowed deployer for transformers. Only callable by the owner.", + "params": { + "transformerDeployer": "The address of the new trusted deployer for transformers." + } + }, + "supportInterface(bytes4)": { + "details": "Indicates whether the 0x Exchange Proxy implements a particular ERC165 interface. This function should use at most 30,000 gas.", + "params": { + "interfaceId": "The interface identifier, as specified in ERC165." + }, + "returns": { + "isSupported": "Whether the given interface is supported by the 0x Exchange Proxy." + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new address.", + "params": { + "newOwner": "The address that will become the owner." + } + }, + "transferProtocolFeesForPools(bytes32[])": { + "details": "Transfers protocol fees from the `FeeCollector` pools into the staking contract.", + "params": { + "poolIds": "Staking pool IDs" + } + }, + "transferTrappedTokensTo(address,uint256,address)": { + "details": "calledFrom FundRecoveryFeature.transferTrappedTokensTo() This will be delegatecalled in the context of the Exchange Proxy instance being used.", + "params": { + "amountOut": "Amount of tokens to withdraw.", + "erc20": "ERC20 Token Address.", + "recipientWallet": "Recipient wallet address." + } + }, + "transformERC20(address,address,uint256,uint256,(uint32,bytes)[])": { + "details": "Executes a series of transformations to convert an ERC20 `inputToken` to an ERC20 `outputToken`.", + "params": { + "inputToken": "The token being provided by the sender. If `0xeee...`, ETH is implied and should be provided with the call.`", + "inputTokenAmount": "The amount of `inputToken` to take from the sender.", + "minOutputTokenAmount": "The minimum amount of `outputToken` the sender must receive for the entire transformation to succeed.", + "outputToken": "The token to be acquired by the sender. `0xeee...` implies ETH.", + "transformations": "The transformations to execute on the token balance(s) in sequence." + }, + "returns": { + "outputTokenAmount": "The amount of `outputToken` received by the sender." + } + }, + "uniswapV3SwapCallback(int256,int256,bytes)": { + "details": "The UniswapV3 pool swap callback which pays the funds requested by the caller/pool to the pool. Can only be called by a valid UniswapV3 pool.", + "params": { + "amount0Delta": "Token0 amount owed.", + "amount1Delta": "Token1 amount owed.", + "data": "Arbitrary data forwarded from swap() caller. An ABI-encoded struct of: inputToken, outputToken, fee, payer" + } + }, + "validateERC1155OrderProperties((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),uint256)": { + "details": "If the given order is buying an ERC1155 asset, checks whether or not the given token ID satisfies the required properties specified in the order. If the order does not specify any properties, this function instead checks whether the given token ID matches the ID in the order. Reverts if any checks fail, or if the order is selling an ERC1155 asset.", + "params": { + "erc1155TokenId": "The ID of the ERC1155 asset.", + "order": "The ERC1155 order." + } + }, + "validateERC1155OrderSignature((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),(uint8,uint8,bytes32,bytes32))": { + "details": "Checks whether the given signature is valid for the the given ERC1155 order. Reverts if not.", + "params": { + "order": "The ERC1155 order.", + "signature": "The signature to validate." } - ], - "name": "batchMatchERC721Orders", - "outputs": [ - { - "internalType": "uint256[]", - "name": "profits", - "type": "uint256[]" - }, - { - "internalType": "bool[]", - "name": "successes", - "type": "bool[]" + }, + "validateERC721OrderProperties((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),uint256)": { + "details": "If the given order is buying an ERC721 asset, checks whether or not the given token ID satisfies the required properties specified in the order. If the order does not specify any properties, this function instead checks whether the given token ID matches the ID in the order. Reverts if any checks fail, or if the order is selling an ERC721 asset.", + "params": { + "erc721TokenId": "The ID of the ERC721 asset.", + "order": "The ERC721 order." } - ], - "stateMutability": "nonpayable", - "type": "function" + }, + "validateERC721OrderSignature((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32))": { + "details": "Checks whether the given signature is valid for the the given ERC721 order. Reverts if not.", + "params": { + "order": "The ERC721 order.", + "signature": "The signature to validate." + } + } }, + "version": 1 + }, + "_disabled": [ { "inputs": [ { "components": [ { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" }, { - "internalType": "address", - "name": "maker", + "internalType": "contract IERC20TokenV06", + "name": "takerToken", "type": "address" }, { - "internalType": "address", - "name": "taker", - "type": "address" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "internalType": "uint128", + "name": "takerTokenFeeAmount", + "type": "uint128" }, { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", + "internalType": "address", + "name": "maker", "type": "address" }, { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" + "internalType": "address", + "name": "taker", + "type": "address" }, { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" + "internalType": "address", + "name": "sender", + "type": "address" }, { - "internalType": "contract IERC1155Token", - "name": "erc1155Token", + "internalType": "address", + "name": "feeRecipient", "type": "address" }, { - "internalType": "uint256", - "name": "erc1155TokenId", - "type": "uint256" + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" }, { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc1155TokenProperties", - "type": "tuple[]" + "internalType": "uint64", + "name": "expiry", + "type": "uint64" }, { - "internalType": "uint128", - "name": "erc1155TokenAmount", - "type": "uint128" + "internalType": "uint256", + "name": "salt", + "type": "uint256" } ], - "internalType": "struct LibNFTOrder.ERC1155Order", - "name": "sellOrder", + "internalType": "struct LibNativeOrder.LimitOrder", + "name": "order", "type": "tuple" }, { @@ -3019,17 +2253,33 @@ }, { "internalType": "uint128", - "name": "erc1155BuyAmount", + "name": "takerTokenFillAmount", "type": "uint128" }, { - "internalType": "bytes", - "name": "callbackData", - "type": "bytes" + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "_fillLimitOrder", + "outputs": [ + { + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" } ], - "name": "buyERC1155", - "outputs": [], "stateMutability": "payable", "type": "function" }, @@ -3038,92 +2288,48 @@ { "components": [ { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", + "internalType": "contract IERC20TokenV06", + "name": "makerToken", "type": "address" }, { - "internalType": "address", - "name": "taker", + "internalType": "contract IERC20TokenV06", + "name": "takerToken", "type": "address" }, { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" }, { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", + "internalType": "address", + "name": "maker", "type": "address" }, { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" + "internalType": "address", + "name": "taker", + "type": "address" }, { - "internalType": "contract IERC721Token", - "name": "erc721Token", + "internalType": "address", + "name": "txOrigin", "type": "address" }, { "internalType": "uint256", - "name": "erc721TokenId", + "name": "expiryAndNonce", "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" } ], - "internalType": "struct LibNFTOrder.ERC721Order", - "name": "sellOrder", + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", "type": "tuple" }, { @@ -3150,43 +2356,43 @@ } ], "internalType": "struct LibSignature.Signature", - "name": "signature", + "name": "makerSignature", "type": "tuple" }, { - "internalType": "bytes", - "name": "callbackData", - "type": "bytes" - } - ], - "name": "buyERC721", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ + "internalType": "uint128", + "name": "takerTokenFillAmount", + "type": "uint128" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "bool", + "name": "useSelfBalance", + "type": "bool" + }, { - "internalType": "uint256", - "name": "orderNonce", - "type": "uint256" + "internalType": "address", + "name": "recipient", + "type": "address" } ], - "name": "cancelERC1155Order", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "_fillOtcOrder", + "outputs": [ { - "internalType": "uint256", - "name": "orderNonce", - "type": "uint256" + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" } ], - "name": "cancelERC721Order", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -3214,11 +2420,6 @@ "name": "takerAmount", "type": "uint128" }, - { - "internalType": "uint128", - "name": "takerTokenFeeAmount", - "type": "uint128" - }, { "internalType": "address", "name": "maker", @@ -3231,12 +2432,7 @@ }, { "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "feeRecipient", + "name": "txOrigin", "type": "address" }, { @@ -3255,115 +2451,105 @@ "type": "uint256" } ], - "internalType": "struct LibNativeOrder.LimitOrder", + "internalType": "struct LibNativeOrder.RfqOrder", "name": "order", "type": "tuple" - } - ], - "name": "cancelLimitOrder", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" }, { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" }, { - "internalType": "uint256", - "name": "minValidSalt", - "type": "uint256" - } - ], - "name": "cancelPairLimitOrders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "internalType": "uint128", + "name": "takerTokenFillAmount", + "type": "uint128" + }, { "internalType": "address", - "name": "maker", + "name": "taker", "type": "address" }, { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" + "internalType": "bool", + "name": "useSelfBalance", + "type": "bool" }, { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", + "internalType": "address", + "name": "recipient", "type": "address" + } + ], + "name": "_fillRfqOrder", + "outputs": [ + { + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "minValidSalt", - "type": "uint256" + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" } ], - "name": "cancelPairLimitOrdersWithSigner", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" + "internalType": "bytes", + "name": "encodedPath", + "type": "bytes" }, { "internalType": "uint256", - "name": "minValidSalt", + "name": "sellAmount", "type": "uint256" - } - ], - "name": "cancelPairRfqOrders", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "maker", - "type": "address" }, { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" }, { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", + "internalType": "address", + "name": "recipient", "type": "address" - }, + } + ], + "name": "_sellHeldTokenForTokenToUniswapV3", + "outputs": [ { "internalType": "uint256", - "name": "minValidSalt", + "name": "buyAmount", "type": "uint256" } ], - "name": "cancelPairRfqOrdersWithSigner", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -3372,77 +2558,72 @@ { "components": [ { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", + "internalType": "address payable", + "name": "taker", "type": "address" }, { "internalType": "contract IERC20TokenV06", - "name": "takerToken", + "name": "inputToken", "type": "address" }, { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "address", - "name": "maker", + "internalType": "contract IERC20TokenV06", + "name": "outputToken", "type": "address" }, { - "internalType": "address", - "name": "taker", - "type": "address" + "internalType": "uint256", + "name": "inputTokenAmount", + "type": "uint256" }, { - "internalType": "address", - "name": "txOrigin", - "type": "address" + "internalType": "uint256", + "name": "minOutputTokenAmount", + "type": "uint256" }, { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" + "components": [ + { + "internalType": "uint32", + "name": "deploymentNonce", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct ITransformERC20Feature.Transformation[]", + "name": "transformations", + "type": "tuple[]" }, { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" + "internalType": "bool", + "name": "useSelfBalance", + "type": "bool" }, { - "internalType": "uint256", - "name": "salt", - "type": "uint256" + "internalType": "address payable", + "name": "recipient", + "type": "address" } ], - "internalType": "struct LibNativeOrder.RfqOrder", - "name": "order", + "internalType": "struct ITransformERC20Feature.TransformERC20Args", + "name": "args", "type": "tuple" } ], - "name": "cancelRfqOrder", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "createTransformWallet", + "name": "_transformERC20", "outputs": [ { - "internalType": "contract IFlashWallet", - "name": "wallet", - "type": "address" + "internalType": "uint256", + "name": "outputTokenAmount", + "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -3450,59 +2631,98 @@ { "components": [ { - "internalType": "address payable", - "name": "signer", + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", "type": "address" }, { "internalType": "address", - "name": "sender", + "name": "taker", "type": "address" }, { "internalType": "uint256", - "name": "minGasPrice", + "name": "expiry", "type": "uint256" }, { "internalType": "uint256", - "name": "maxGasPrice", + "name": "nonce", "type": "uint256" }, { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" }, { "internalType": "uint256", - "name": "salt", + "name": "erc20TokenAmount", "type": "uint256" }, { - "internalType": "bytes", - "name": "callData", - "type": "bytes" + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC1155Token", + "name": "erc1155Token", + "type": "address" }, { "internalType": "uint256", - "name": "value", + "name": "erc1155TokenId", "type": "uint256" }, { - "internalType": "contract IERC20TokenV06", - "name": "feeToken", - "type": "address" + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc1155TokenProperties", + "type": "tuple[]" }, { - "internalType": "uint256", - "name": "feeAmount", - "type": "uint256" + "internalType": "uint128", + "name": "erc1155TokenAmount", + "type": "uint128" } ], - "internalType": "struct IMetaTransactionsFeature.MetaTransactionData", - "name": "mtx", - "type": "tuple" + "internalType": "struct LibNFTOrder.ERC1155Order[]", + "name": "sellOrders", + "type": "tuple[]" }, { "components": [ @@ -3527,68 +2747,45 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" + "internalType": "struct LibSignature.Signature[]", + "name": "signatures", + "type": "tuple[]" + }, + { + "internalType": "uint128[]", + "name": "erc1155TokenAmounts", + "type": "uint128[]" + }, + { + "internalType": "bytes[]", + "name": "callbackData", + "type": "bytes[]" + }, + { + "internalType": "bool", + "name": "revertIfIncomplete", + "type": "bool" } ], - "name": "executeMetaTransaction", + "name": "batchBuyERC1155s", "outputs": [ { - "internalType": "bytes", - "name": "returnResult", - "type": "bytes" + "internalType": "bool[]", + "name": "successes", + "type": "bool[]" } ], "stateMutability": "payable", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "internalType": "address", - "name": "impl", - "type": "address" - } - ], - "name": "extend", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { "components": [ { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerTokenFeeAmount", - "type": "uint128" + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" }, { "internalType": "address", @@ -3601,34 +2798,78 @@ "type": "address" }, { - "internalType": "address", - "name": "sender", - "type": "address" + "internalType": "uint256", + "name": "expiry", + "type": "uint256" }, { - "internalType": "address", - "name": "feeRecipient", + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", "type": "address" }, { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" }, { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC721Token", + "name": "erc721Token", + "type": "address" }, { "internalType": "uint256", - "name": "salt", + "name": "erc721TokenId", "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc721TokenProperties", + "type": "tuple[]" } ], - "internalType": "struct LibNativeOrder.LimitOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNFTOrder.ERC721Order[]", + "name": "sellOrders", + "type": "tuple[]" }, { "components": [ @@ -3653,32 +2894,58 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" + "internalType": "struct LibSignature.Signature[]", + "name": "signatures", + "type": "tuple[]" + }, + { + "internalType": "bytes[]", + "name": "callbackData", + "type": "bytes[]" }, { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" + "internalType": "bool", + "name": "revertIfIncomplete", + "type": "bool" } ], - "name": "fillLimitOrder", + "name": "batchBuyERC721s", "outputs": [ { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" + "internalType": "bool[]", + "name": "successes", + "type": "bool[]" } ], "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "orderNonces", + "type": "uint256[]" + } + ], + "name": "batchCancelERC1155Orders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "orderNonces", + "type": "uint256[]" + } + ], + "name": "batchCancelERC721Orders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -3744,52 +3011,116 @@ "type": "uint256" } ], - "internalType": "struct LibNativeOrder.LimitOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNativeOrder.LimitOrder[]", + "name": "orders", + "type": "tuple[]" + } + ], + "name": "batchCancelLimitOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06[]", + "name": "makerTokens", + "type": "address[]" }, { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" + "internalType": "contract IERC20TokenV06[]", + "name": "takerTokens", + "type": "address[]" }, { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" + "internalType": "uint256[]", + "name": "minValidSalts", + "type": "uint256[]" } ], - "name": "fillOrKillLimitOrder", - "outputs": [ + "name": "batchCancelPairLimitOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06[]", + "name": "makerTokens", + "type": "address[]" + }, + { + "internalType": "contract IERC20TokenV06[]", + "name": "takerTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "minValidSalts", + "type": "uint256[]" } ], - "stateMutability": "payable", + "name": "batchCancelPairLimitOrdersWithSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06[]", + "name": "makerTokens", + "type": "address[]" + }, + { + "internalType": "contract IERC20TokenV06[]", + "name": "takerTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "minValidSalts", + "type": "uint256[]" + } + ], + "name": "batchCancelPairRfqOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06[]", + "name": "makerTokens", + "type": "address[]" + }, + { + "internalType": "contract IERC20TokenV06[]", + "name": "takerTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "minValidSalts", + "type": "uint256[]" + } + ], + "name": "batchCancelPairRfqOrdersWithSigner", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { @@ -3847,9 +3178,74 @@ "type": "uint256" } ], - "internalType": "struct LibNativeOrder.RfqOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNativeOrder.RfqOrder[]", + "name": "orders", + "type": "tuple[]" + } + ], + "name": "batchCancelRfqOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address payable", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTimeSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "feeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" + } + ], + "internalType": "struct IMetaTransactionsFeature.MetaTransactionData[]", + "name": "mtxs", + "type": "tuple[]" }, { "components": [ @@ -3874,25 +3270,20 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" - }, - { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" + "internalType": "struct LibSignature.Signature[]", + "name": "signatures", + "type": "tuple[]" } ], - "name": "fillOrKillRfqOrder", + "name": "batchExecuteMetaTransactions", "outputs": [ { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" + "internalType": "bytes[]", + "name": "returnResults", + "type": "bytes[]" } ], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -3919,6 +3310,11 @@ "name": "takerAmount", "type": "uint128" }, + { + "internalType": "uint128", + "name": "takerTokenFeeAmount", + "type": "uint128" + }, { "internalType": "address", "name": "maker", @@ -3931,18 +3327,33 @@ }, { "internalType": "address", - "name": "txOrigin", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "feeRecipient", "type": "address" }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, { "internalType": "uint256", - "name": "expiryAndNonce", + "name": "salt", "type": "uint256" } ], - "internalType": "struct LibNativeOrder.OtcOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNativeOrder.LimitOrder[]", + "name": "orders", + "type": "tuple[]" }, { "components": [ @@ -3967,30 +3378,35 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "makerSignature", - "type": "tuple" + "internalType": "struct LibSignature.Signature[]", + "name": "signatures", + "type": "tuple[]" }, { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" + "internalType": "uint128[]", + "name": "takerTokenFillAmounts", + "type": "uint128[]" + }, + { + "internalType": "bool", + "name": "revertIfIncomplete", + "type": "bool" } ], - "name": "fillOtcOrder", + "name": "batchFillLimitOrders", "outputs": [ { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" + "internalType": "uint128[]", + "name": "takerTokenFilledAmounts", + "type": "uint128[]" }, { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" + "internalType": "uint128[]", + "name": "makerTokenFilledAmounts", + "type": "uint128[]" } ], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -4032,15 +3448,25 @@ "name": "txOrigin", "type": "address" }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, { "internalType": "uint256", - "name": "expiryAndNonce", + "name": "salt", "type": "uint256" } ], - "internalType": "struct LibNativeOrder.OtcOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNativeOrder.RfqOrder[]", + "name": "orders", + "type": "tuple[]" }, { "components": [ @@ -4065,27 +3491,32 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "makerSignature", - "type": "tuple" + "internalType": "struct LibSignature.Signature[]", + "name": "signatures", + "type": "tuple[]" }, { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" + "internalType": "uint128[]", + "name": "takerTokenFillAmounts", + "type": "uint128[]" + }, + { + "internalType": "bool", + "name": "revertIfIncomplete", + "type": "bool" } ], - "name": "fillOtcOrderForEth", + "name": "batchFillRfqOrders", "outputs": [ { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" + "internalType": "uint128[]", + "name": "takerTokenFilledAmounts", + "type": "uint128[]" }, { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" + "internalType": "uint128[]", + "name": "makerTokenFilledAmounts", + "type": "uint128[]" } ], "stateMutability": "nonpayable", @@ -4136,9 +3567,9 @@ "type": "uint256" } ], - "internalType": "struct LibNativeOrder.OtcOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNativeOrder.OtcOrder[]", + "name": "orders", + "type": "tuple[]" }, { "components": [ @@ -4163,25 +3594,52 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "makerSignature", - "type": "tuple" + "internalType": "struct LibSignature.Signature[]", + "name": "makerSignatures", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature[]", + "name": "takerSignatures", + "type": "tuple[]" + }, + { + "internalType": "bool[]", + "name": "unwrapWeth", + "type": "bool[]" } ], - "name": "fillOtcOrderWithEth", + "name": "batchFillTakerSignedOtcOrders", "outputs": [ { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" + "internalType": "bool[]", + "name": "successes", + "type": "bool[]" } ], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -4208,6 +3666,11 @@ "name": "takerAmount", "type": "uint128" }, + { + "internalType": "uint128", + "name": "takerTokenFeeAmount", + "type": "uint128" + }, { "internalType": "address", "name": "maker", @@ -4220,7 +3683,12 @@ }, { "internalType": "address", - "name": "txOrigin", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "feeRecipient", "type": "address" }, { @@ -4239,9 +3707,9 @@ "type": "uint256" } ], - "internalType": "struct LibNativeOrder.RfqOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNativeOrder.LimitOrder[]", + "name": "orders", + "type": "tuple[]" }, { "components": [ @@ -4266,30 +3734,47 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" - }, - { - "internalType": "uint128", - "name": "takerTokenFillAmount", - "type": "uint128" + "internalType": "struct LibSignature.Signature[]", + "name": "signatures", + "type": "tuple[]" } ], - "name": "fillRfqOrder", + "name": "batchGetLimitOrderRelevantStates", "outputs": [ { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" + "components": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + }, + { + "internalType": "enum LibNativeOrder.OrderStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNativeOrder.OrderInfo[]", + "name": "orderInfos", + "type": "tuple[]" }, { - "internalType": "uint128", - "name": "makerTokenFilledAmount", - "type": "uint128" + "internalType": "uint128[]", + "name": "actualFillableTakerTokenAmounts", + "type": "uint128[]" + }, + { + "internalType": "bool[]", + "name": "isSignatureValids", + "type": "bool[]" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -4331,15 +3816,25 @@ "name": "txOrigin", "type": "address" }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, { "internalType": "uint256", - "name": "expiryAndNonce", + "name": "salt", "type": "uint256" } ], - "internalType": "struct LibNativeOrder.OtcOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNativeOrder.RfqOrder[]", + "name": "orders", + "type": "tuple[]" }, { "components": [ @@ -4364,41 +3859,47 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "makerSignature", - "type": "tuple" - }, + "internalType": "struct LibSignature.Signature[]", + "name": "signatures", + "type": "tuple[]" + } + ], + "name": "batchGetRfqOrderRelevantStates", + "outputs": [ { "components": [ { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" }, { - "internalType": "uint8", - "name": "v", + "internalType": "enum LibNativeOrder.OrderStatus", + "name": "status", "type": "uint8" }, { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" } ], - "internalType": "struct LibSignature.Signature", - "name": "takerSignature", - "type": "tuple" + "internalType": "struct LibNativeOrder.OrderInfo[]", + "name": "orderInfos", + "type": "tuple[]" + }, + { + "internalType": "uint128[]", + "name": "actualFillableTakerTokenAmounts", + "type": "uint128[]" + }, + { + "internalType": "bool[]", + "name": "isSignatureValids", + "type": "bool[]" } ], - "name": "fillTakerSignedOtcOrder", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -4406,24 +3907,100 @@ { "components": [ { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", "type": "address" }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, { "internalType": "contract IERC20TokenV06", - "name": "takerToken", + "name": "erc20Token", "type": "address" }, { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" }, { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC721Token", + "name": "erc721Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc721TokenProperties", + "type": "tuple[]" + } + ], + "internalType": "struct LibNFTOrder.ERC721Order[]", + "name": "sellOrders", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" }, { "internalType": "address", @@ -4436,19 +4013,78 @@ "type": "address" }, { - "internalType": "address", - "name": "txOrigin", + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", "type": "address" }, { "internalType": "uint256", - "name": "expiryAndNonce", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC721Token", + "name": "erc721Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc721TokenProperties", + "type": "tuple[]" } ], - "internalType": "struct LibNativeOrder.OtcOrder", - "name": "order", - "type": "tuple" + "internalType": "struct LibNFTOrder.ERC721Order[]", + "name": "buyOrders", + "type": "tuple[]" }, { "components": [ @@ -4473,9 +4109,9 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "makerSignature", - "type": "tuple" + "internalType": "struct LibSignature.Signature[]", + "name": "sellOrderSignatures", + "type": "tuple[]" }, { "components": [ @@ -4500,13 +4136,24 @@ "type": "bytes32" } ], - "internalType": "struct LibSignature.Signature", - "name": "takerSignature", - "type": "tuple" + "internalType": "struct LibSignature.Signature[]", + "name": "buyOrderSignatures", + "type": "tuple[]" + } + ], + "name": "batchMatchERC721Orders", + "outputs": [ + { + "internalType": "uint256[]", + "name": "profits", + "type": "uint256[]" + }, + { + "internalType": "bool[]", + "name": "successes", + "type": "bool[]" } ], - "name": "fillTakerSignedOtcOrderForEth", - "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -4605,19 +4252,50 @@ } ], "internalType": "struct LibNFTOrder.ERC1155Order", - "name": "order", + "name": "sellOrder", "type": "tuple" - } - ], - "name": "getERC1155OrderHash", - "outputs": [ + }, { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" + }, + { + "internalType": "uint128", + "name": "erc1155BuyAmount", + "type": "uint128" + }, + { + "internalType": "bytes", + "name": "callbackData", + "type": "bytes" } ], - "stateMutability": "view", + "name": "buyERC1155", + "outputs": [], + "stateMutability": "payable", "type": "function" }, { @@ -4682,13 +4360,13 @@ "type": "tuple[]" }, { - "internalType": "contract IERC1155Token", - "name": "erc1155Token", + "internalType": "contract IERC721Token", + "name": "erc721Token", "type": "address" }, { "internalType": "uint256", - "name": "erc1155TokenId", + "name": "erc721TokenId", "type": "uint256" }, { @@ -4705,61 +4383,278 @@ } ], "internalType": "struct LibNFTOrder.Property[]", - "name": "erc1155TokenProperties", + "name": "erc721TokenProperties", "type": "tuple[]" + } + ], + "internalType": "struct LibNFTOrder.ERC721Order", + "name": "sellOrder", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "callbackData", + "type": "bytes" + } + ], + "name": "buyERC721", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "orderNonce", + "type": "uint256" + } + ], + "name": "cancelERC1155Order", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "orderNonce", + "type": "uint256" + } + ], + "name": "cancelERC721Order", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" }, { "internalType": "uint128", - "name": "erc1155TokenAmount", + "name": "makerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerTokenFeeAmount", "type": "uint128" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "feeRecipient", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" } ], - "internalType": "struct LibNFTOrder.ERC1155Order", + "internalType": "struct LibNativeOrder.LimitOrder", "name": "order", "type": "tuple" } ], - "name": "getERC1155OrderInfo", - "outputs": [ + "name": "cancelLimitOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minValidSalt", + "type": "uint256" + } + ], + "name": "cancelPairLimitOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minValidSalt", + "type": "uint256" + } + ], + "name": "cancelPairLimitOrdersWithSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minValidSalt", + "type": "uint256" + } + ], + "name": "cancelPairRfqOrders", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minValidSalt", + "type": "uint256" + } + ], + "name": "cancelPairRfqOrdersWithSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" }, { - "internalType": "enum LibNFTOrder.OrderStatus", - "name": "status", - "type": "uint8" + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" }, { "internalType": "uint128", - "name": "orderAmount", + "name": "makerAmount", "type": "uint128" }, { "internalType": "uint128", - "name": "remainingAmount", + "name": "takerAmount", "type": "uint128" - } - ], - "internalType": "struct LibNFTOrder.OrderInfo", - "name": "orderInfo", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" }, { "internalType": "address", @@ -4772,89 +4667,47 @@ "type": "address" }, { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", + "internalType": "address", + "name": "txOrigin", "type": "address" }, { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" }, { - "internalType": "contract IERC721Token", - "name": "erc721Token", - "type": "address" + "internalType": "uint64", + "name": "expiry", + "type": "uint64" }, { "internalType": "uint256", - "name": "erc721TokenId", + "name": "salt", "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" } ], - "internalType": "struct LibNFTOrder.ERC721Order", + "internalType": "struct LibNativeOrder.RfqOrder", "name": "order", "type": "tuple" } ], - "name": "getERC721OrderHash", + "name": "cancelRfqOrder", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "createTransformWallet", "outputs": [ { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" + "internalType": "contract IFlashWallet", + "name": "wallet", + "type": "address" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { @@ -4862,128 +4715,97 @@ { "components": [ { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", + "internalType": "address payable", + "name": "signer", "type": "address" }, { "internalType": "address", - "name": "taker", + "name": "sender", "type": "address" }, { "internalType": "uint256", - "name": "expiry", + "name": "minGasPrice", "type": "uint256" }, { "internalType": "uint256", - "name": "nonce", + "name": "maxGasPrice", "type": "uint256" }, { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" + "internalType": "uint256", + "name": "expirationTimeSeconds", + "type": "uint256" }, { "internalType": "uint256", - "name": "erc20TokenAmount", + "name": "salt", "type": "uint256" }, { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" + "internalType": "bytes", + "name": "callData", + "type": "bytes" }, { - "internalType": "contract IERC721Token", - "name": "erc721Token", + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "feeToken", "type": "address" }, { "internalType": "uint256", - "name": "erc721TokenId", + "name": "feeAmount", "type": "uint256" - }, + } + ], + "internalType": "struct IMetaTransactionsFeature.MetaTransactionData", + "name": "mtx", + "type": "tuple" + }, + { + "components": [ { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "internalType": "struct LibNFTOrder.ERC721Order", - "name": "order", + "internalType": "struct LibSignature.Signature", + "name": "signature", "type": "tuple" } ], - "name": "getERC721OrderStatus", - "outputs": [ - { - "internalType": "enum LibNFTOrder.OrderStatus", - "name": "status", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "uint248", - "name": "nonceRange", - "type": "uint248" - } - ], - "name": "getERC721OrderStatusBitVector", + "name": "executeMetaTransaction", "outputs": [ { - "internalType": "uint256", - "name": "bitVector", - "type": "uint256" + "internalType": "bytes", + "name": "returnResult", + "type": "bytes" } ], - "stateMutability": "view", + "stateMutability": "payable", "type": "function" }, { @@ -5054,17 +4876,54 @@ "internalType": "struct LibNativeOrder.LimitOrder", "name": "order", "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" + }, + { + "internalType": "uint128", + "name": "takerTokenFillAmount", + "type": "uint128" } ], - "name": "getLimitOrderHash", + "name": "fillLimitOrder", "outputs": [ { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" } ], - "stateMutability": "view", + "stateMutability": "payable", "type": "function" }, { @@ -5091,11 +4950,6 @@ "name": "takerAmount", "type": "uint128" }, - { - "internalType": "uint128", - "name": "takerTokenFeeAmount", - "type": "uint128" - }, { "internalType": "address", "name": "maker", @@ -5108,12 +4962,7 @@ }, { "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "feeRecipient", + "name": "txOrigin", "type": "address" }, { @@ -5132,37 +4981,52 @@ "type": "uint256" } ], - "internalType": "struct LibNativeOrder.LimitOrder", + "internalType": "struct LibNativeOrder.RfqOrder", "name": "order", "type": "tuple" - } - ], - "name": "getLimitOrderInfo", - "outputs": [ + }, { "components": [ { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" }, { - "internalType": "enum LibNativeOrder.OrderStatus", - "name": "status", + "internalType": "uint8", + "name": "v", "type": "uint8" }, { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "internalType": "struct LibNativeOrder.OrderInfo", - "name": "orderInfo", + "internalType": "struct LibSignature.Signature", + "name": "signature", "type": "tuple" + }, + { + "internalType": "uint128", + "name": "takerTokenFillAmount", + "type": "uint128" } ], - "stateMutability": "view", + "name": "fillOrKillRfqOrder", + "outputs": [ + { + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", "type": "function" }, { @@ -5189,11 +5053,6 @@ "name": "takerAmount", "type": "uint128" }, - { - "internalType": "uint128", - "name": "takerTokenFeeAmount", - "type": "uint128" - }, { "internalType": "address", "name": "maker", @@ -5206,31 +5065,114 @@ }, { "internalType": "address", - "name": "sender", + "name": "txOrigin", "type": "address" }, { - "internalType": "address", - "name": "feeRecipient", - "type": "address" + "internalType": "uint256", + "name": "expiryAndNonce", + "type": "uint256" + } + ], + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" }, { "internalType": "bytes32", - "name": "pool", + "name": "r", "type": "bytes32" }, { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "makerSignature", + "type": "tuple" + }, + { + "internalType": "uint128", + "name": "takerTokenFillAmount", + "type": "uint128" + } + ], + "name": "fillOtcOrder", + "outputs": [ + { + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" + }, + { + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "address", + "name": "txOrigin", + "type": "address" }, { "internalType": "uint256", - "name": "salt", + "name": "expiryAndNonce", "type": "uint256" } ], - "internalType": "struct LibNativeOrder.LimitOrder", + "internalType": "struct LibNativeOrder.OtcOrder", "name": "order", "type": "tuple" }, @@ -5258,46 +5200,29 @@ } ], "internalType": "struct LibSignature.Signature", - "name": "signature", + "name": "makerSignature", "type": "tuple" + }, + { + "internalType": "uint128", + "name": "takerTokenFillAmount", + "type": "uint128" } ], - "name": "getLimitOrderRelevantState", + "name": "fillOtcOrderForEth", "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - }, - { - "internalType": "enum LibNativeOrder.OrderStatus", - "name": "status", - "type": "uint8" - }, - { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - } - ], - "internalType": "struct LibNativeOrder.OrderInfo", - "name": "orderInfo", - "type": "tuple" - }, { "internalType": "uint128", - "name": "actualFillableTakerTokenAmount", + "name": "takerTokenFilledAmount", "type": "uint128" }, { - "internalType": "bool", - "name": "isSignatureValid", - "type": "bool" + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { @@ -5305,160 +5230,92 @@ { "components": [ { - "internalType": "address payable", - "name": "signer", + "internalType": "contract IERC20TokenV06", + "name": "makerToken", "type": "address" }, { - "internalType": "address", - "name": "sender", + "internalType": "contract IERC20TokenV06", + "name": "takerToken", "type": "address" }, { - "internalType": "uint256", - "name": "minGasPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "salt", - "type": "uint256" + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" }, { - "internalType": "bytes", - "name": "callData", - "type": "bytes" + "internalType": "address", + "name": "maker", + "type": "address" }, { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "internalType": "address", + "name": "taker", + "type": "address" }, { - "internalType": "contract IERC20TokenV06", - "name": "feeToken", + "internalType": "address", + "name": "txOrigin", "type": "address" }, { "internalType": "uint256", - "name": "feeAmount", + "name": "expiryAndNonce", "type": "uint256" } ], - "internalType": "struct IMetaTransactionsFeature.MetaTransactionData", - "name": "mtx", + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", "type": "tuple" - } - ], - "name": "getMetaTransactionExecutedBlock", - "outputs": [ - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ + }, { "components": [ { - "internalType": "address payable", - "name": "signer", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minGasPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxGasPrice", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTimeSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "salt", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" }, { - "internalType": "uint256", - "name": "value", - "type": "uint256" + "internalType": "uint8", + "name": "v", + "type": "uint8" }, { - "internalType": "contract IERC20TokenV06", - "name": "feeToken", - "type": "address" + "internalType": "bytes32", + "name": "r", + "type": "bytes32" }, { - "internalType": "uint256", - "name": "feeAmount", - "type": "uint256" + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "internalType": "struct IMetaTransactionsFeature.MetaTransactionData", - "name": "mtx", + "internalType": "struct LibSignature.Signature", + "name": "makerSignature", "type": "tuple" } ], - "name": "getMetaTransactionHash", + "name": "fillOtcOrderWithEth", "outputs": [ { - "internalType": "bytes32", - "name": "mtxHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "mtxHash", - "type": "bytes32" - } - ], - "name": "getMetaTransactionHashExecutedBlock", - "outputs": [ + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + }, { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" } ], - "stateMutability": "view", + "stateMutability": "payable", "type": "function" }, { @@ -5500,26 +5357,73 @@ "name": "txOrigin", "type": "address" }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, { "internalType": "uint256", - "name": "expiryAndNonce", + "name": "salt", "type": "uint256" } ], - "internalType": "struct LibNativeOrder.OtcOrder", + "internalType": "struct LibNativeOrder.RfqOrder", "name": "order", "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" + }, + { + "internalType": "uint128", + "name": "takerTokenFillAmount", + "type": "uint128" } ], - "name": "getOtcOrderHash", + "name": "fillRfqOrder", "outputs": [ { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "makerTokenFilledAmount", + "type": "uint128" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { @@ -5570,55 +5474,65 @@ "internalType": "struct LibNativeOrder.OtcOrder", "name": "order", "type": "tuple" - } - ], - "name": "getOtcOrderInfo", - "outputs": [ + }, { "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, { "internalType": "bytes32", - "name": "orderHash", + "name": "r", "type": "bytes32" }, { - "internalType": "enum LibNativeOrder.OrderStatus", - "name": "status", - "type": "uint8" + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "internalType": "struct LibNativeOrder.OtcOrderInfo", - "name": "orderInfo", + "internalType": "struct LibSignature.Signature", + "name": "makerSignature", "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getProtocolFeeMultiplier", - "outputs": [ - { - "internalType": "uint32", - "name": "multiplier", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getQuoteSigner", - "outputs": [ + }, { - "internalType": "address", - "name": "signer", - "type": "address" + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "takerSignature", + "type": "tuple" } ], - "stateMutability": "view", + "name": "fillTakerSignedOtcOrder", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { @@ -5660,36 +5574,74 @@ "name": "txOrigin", "type": "address" }, + { + "internalType": "uint256", + "name": "expiryAndNonce", + "type": "uint256" + } + ], + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, { "internalType": "bytes32", - "name": "pool", + "name": "r", "type": "bytes32" }, { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "makerSignature", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" }, { - "internalType": "uint256", - "name": "salt", - "type": "uint256" + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" } ], - "internalType": "struct LibNativeOrder.RfqOrder", - "name": "order", + "internalType": "struct LibSignature.Signature", + "name": "takerSignature", "type": "tuple" } ], - "name": "getRfqOrderHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" - } - ], - "stateMutability": "view", + "name": "fillTakerSignedOtcOrderForEth", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { @@ -5697,86 +5649,108 @@ { "components": [ { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" }, { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", + "internalType": "address", + "name": "maker", "type": "address" }, { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" + "internalType": "address", + "name": "taker", + "type": "address" }, { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" + "internalType": "uint256", + "name": "expiry", + "type": "uint256" }, { - "internalType": "address", - "name": "maker", - "type": "address" + "internalType": "uint256", + "name": "nonce", + "type": "uint256" }, { - "internalType": "address", - "name": "taker", + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", "type": "address" }, { - "internalType": "address", - "name": "txOrigin", - "type": "address" + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" }, { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" }, { - "internalType": "uint64", - "name": "expiry", - "type": "uint64" + "internalType": "contract IERC1155Token", + "name": "erc1155Token", + "type": "address" }, { "internalType": "uint256", - "name": "salt", + "name": "erc1155TokenId", "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.RfqOrder", - "name": "order", - "type": "tuple" - } - ], - "name": "getRfqOrderInfo", - "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" }, { - "internalType": "enum LibNativeOrder.OrderStatus", - "name": "status", - "type": "uint8" + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc1155TokenProperties", + "type": "tuple[]" }, { "internalType": "uint128", - "name": "takerTokenFilledAmount", + "name": "erc1155TokenAmount", "type": "uint128" } ], - "internalType": "struct LibNativeOrder.OrderInfo", - "name": "orderInfo", + "internalType": "struct LibNFTOrder.ERC1155Order", + "name": "order", "type": "tuple" } ], + "name": "getERC1155OrderHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], "stateMutability": "view", "type": "function" }, @@ -5785,24 +5759,9 @@ { "components": [ { - "internalType": "contract IERC20TokenV06", - "name": "makerToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "takerToken", - "type": "address" - }, - { - "internalType": "uint128", - "name": "makerAmount", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "takerAmount", - "type": "uint128" + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" }, { "internalType": "address", @@ -5815,208 +5774,113 @@ "type": "address" }, { - "internalType": "address", - "name": "txOrigin", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "pool", - "type": "bytes32" - }, - { - "internalType": "uint64", + "internalType": "uint256", "name": "expiry", - "type": "uint64" + "type": "uint256" }, { "internalType": "uint256", - "name": "salt", + "name": "nonce", "type": "uint256" - } - ], - "internalType": "struct LibNativeOrder.RfqOrder", - "name": "order", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" }, { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" - } - ], - "name": "getRfqOrderRelevantState", - "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "orderHash", - "type": "bytes32" + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" }, { - "internalType": "enum LibNativeOrder.OrderStatus", - "name": "status", - "type": "uint8" + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" }, { - "internalType": "uint128", - "name": "takerTokenFilledAmount", - "type": "uint128" - } - ], - "internalType": "struct LibNativeOrder.OrderInfo", - "name": "orderInfo", - "type": "tuple" - }, - { - "internalType": "uint128", - "name": "actualFillableTakerTokenAmount", - "type": "uint128" - }, - { - "internalType": "bool", - "name": "isSignatureValid", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "internalType": "uint256", - "name": "idx", - "type": "uint256" - } - ], - "name": "getRollbackEntryAtIndex", - "outputs": [ - { - "internalType": "address", - "name": "impl", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "getRollbackLength", - "outputs": [ - { - "internalType": "uint256", - "name": "rollbackLength", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getTransformWallet", - "outputs": [ - { - "internalType": "contract IFlashWallet", - "name": "wallet", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getTransformerDeployer", - "outputs": [ - { - "internalType": "address", - "name": "deployer", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "signer", - "type": "address" - } - ], - "name": "isValidOrderSigner", - "outputs": [ - { - "internalType": "bool", - "name": "isAllowed", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "txOrigin", - "type": "address" - }, - { - "internalType": "uint64", - "name": "nonceBucket", - "type": "uint64" + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC1155Token", + "name": "erc1155Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc1155TokenProperties", + "type": "tuple[]" + }, + { + "internalType": "uint128", + "name": "erc1155TokenAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNFTOrder.ERC1155Order", + "name": "order", + "type": "tuple" } ], - "name": "lastOtcTxOriginNonce", + "name": "getERC1155OrderInfo", "outputs": [ { - "internalType": "uint128", - "name": "lastNonce", - "type": "uint128" + "components": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + }, + { + "internalType": "enum LibNFTOrder.OrderStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "orderAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "remainingAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNFTOrder.OrderInfo", + "name": "orderInfo", + "type": "tuple" } ], "stateMutability": "view", @@ -6112,9 +5976,23 @@ } ], "internalType": "struct LibNFTOrder.ERC721Order", - "name": "sellOrder", + "name": "order", "type": "tuple" - }, + } + ], + "name": "getERC721OrderHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "components": [ { @@ -6203,465 +6081,380 @@ } ], "internalType": "struct LibNFTOrder.ERC721Order", - "name": "buyOrder", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature", - "name": "sellOrderSignature", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature", - "name": "buyOrderSignature", + "name": "order", "type": "tuple" } ], - "name": "matchERC721Orders", - "outputs": [ - { - "internalType": "uint256", - "name": "profit", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "migrate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06", - "name": "outputToken", - "type": "address" - }, - { - "components": [ - { - "internalType": "enum IMultiplexFeature.MultiplexSubcall", - "name": "id", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", - "name": "calls", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - } - ], - "name": "multiplexBatchSellEthForToken", + "name": "getERC721OrderStatus", "outputs": [ { - "internalType": "uint256", - "name": "boughtAmount", - "type": "uint256" + "internalType": "enum LibNFTOrder.OrderStatus", + "name": "status", + "type": "uint8" } ], - "stateMutability": "payable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "contract IERC20TokenV06", - "name": "inputToken", - "type": "address" - }, - { - "components": [ - { - "internalType": "enum IMultiplexFeature.MultiplexSubcall", - "name": "id", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", - "name": "calls", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" + "internalType": "address", + "name": "maker", + "type": "address" }, { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" + "internalType": "uint248", + "name": "nonceRange", + "type": "uint248" } ], - "name": "multiplexBatchSellTokenForEth", + "name": "getERC721OrderStatusBitVector", "outputs": [ { "internalType": "uint256", - "name": "boughtAmount", + "name": "bitVector", "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ - { - "internalType": "contract IERC20TokenV06", - "name": "inputToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "outputToken", - "type": "address" - }, { "components": [ { - "internalType": "enum IMultiplexFeature.MultiplexSubcall", - "name": "id", - "type": "uint8" + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" }, { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" }, { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerTokenFeeAmount", + "type": "uint128" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "feeRecipient", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" } ], - "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", - "name": "calls", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" + "internalType": "struct LibNativeOrder.LimitOrder", + "name": "order", + "type": "tuple" } ], - "name": "multiplexBatchSellTokenForToken", + "name": "getLimitOrderHash", "outputs": [ { - "internalType": "uint256", - "name": "boughtAmount", - "type": "uint256" + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ - { - "internalType": "address[]", - "name": "tokens", - "type": "address[]" - }, { "components": [ { - "internalType": "enum IMultiplexFeature.MultiplexSubcall", - "name": "id", - "type": "uint8" + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" }, { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" + }, + { + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerTokenFeeAmount", + "type": "uint128" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "feeRecipient", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" } ], - "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", - "name": "calls", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" + "internalType": "struct LibNativeOrder.LimitOrder", + "name": "order", + "type": "tuple" } ], - "name": "multiplexMultiHopSellEthForToken", + "name": "getLimitOrderInfo", "outputs": [ { - "internalType": "uint256", - "name": "boughtAmount", - "type": "uint256" + "components": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + }, + { + "internalType": "enum LibNativeOrder.OrderStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNativeOrder.OrderInfo", + "name": "orderInfo", + "type": "tuple" } ], - "stateMutability": "payable", + "stateMutability": "view", "type": "function" }, { "inputs": [ - { - "internalType": "address[]", - "name": "tokens", - "type": "address[]" - }, { "components": [ { - "internalType": "enum IMultiplexFeature.MultiplexSubcall", - "name": "id", - "type": "uint8" + "internalType": "address payable", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTimeSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" }, { "internalType": "bytes", - "name": "data", + "name": "callData", "type": "bytes" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "feeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" } ], - "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", - "name": "calls", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" + "internalType": "struct IMetaTransactionsFeature.MetaTransactionData", + "name": "mtx", + "type": "tuple" } ], - "name": "multiplexMultiHopSellTokenForEth", + "name": "getMetaTransactionExecutedBlock", "outputs": [ { "internalType": "uint256", - "name": "boughtAmount", + "name": "blockNumber", "type": "uint256" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ - { - "internalType": "address[]", - "name": "tokens", - "type": "address[]" - }, { "components": [ { - "internalType": "enum IMultiplexFeature.MultiplexSubcall", - "name": "id", - "type": "uint8" + "internalType": "address payable", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expirationTimeSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" }, { "internalType": "bytes", - "name": "data", + "name": "callData", "type": "bytes" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "feeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" } ], - "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", - "name": "calls", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" + "internalType": "struct IMetaTransactionsFeature.MetaTransactionData", + "name": "mtx", + "type": "tuple" } ], - "name": "multiplexMultiHopSellTokenForToken", + "name": "getMetaTransactionHash", "outputs": [ { - "internalType": "uint256", - "name": "boughtAmount", - "type": "uint256" + "internalType": "bytes32", + "name": "mtxHash", + "type": "bytes32" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "internalType": "bytes32", + "name": "mtxHash", + "type": "bytes32" } ], - "name": "onERC1155Received", + "name": "getMetaTransactionHashExecutedBlock", "outputs": [ - { - "internalType": "bytes4", - "name": "success", - "type": "bytes4" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, { "internalType": "uint256", - "name": "tokenId", + "name": "blockNumber", "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "onERC721Received", - "outputs": [ - { - "internalType": "bytes4", - "name": "success", - "type": "bytes4" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "ownerAddress", - "type": "address" } ], "stateMutability": "view", @@ -6671,104 +6464,61 @@ "inputs": [ { "components": [ - { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, { "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" - }, - { - "internalType": "contract IERC1155Token", - "name": "erc1155Token", + "name": "makerToken", "type": "address" }, { - "internalType": "uint256", - "name": "erc1155TokenId", - "type": "uint256" + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" }, { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc1155TokenProperties", - "type": "tuple[]" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" }, { "internalType": "uint128", - "name": "erc1155TokenAmount", + "name": "takerAmount", "type": "uint128" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "address", + "name": "txOrigin", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiryAndNonce", + "type": "uint256" } ], - "internalType": "struct LibNFTOrder.ERC1155Order", + "internalType": "struct LibNativeOrder.OtcOrder", "name": "order", "type": "tuple" } ], - "name": "preSignERC1155Order", - "outputs": [], - "stateMutability": "nonpayable", + "name": "getOtcOrderHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + } + ], + "stateMutability": "view", "type": "function" }, { @@ -6776,152 +6526,169 @@ { "components": [ { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", + "internalType": "contract IERC20TokenV06", + "name": "makerToken", "type": "address" }, { - "internalType": "address", - "name": "taker", + "internalType": "contract IERC20TokenV06", + "name": "takerToken", "type": "address" }, { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" }, { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", + "internalType": "address", + "name": "maker", "type": "address" }, { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" + "internalType": "address", + "name": "taker", + "type": "address" }, { - "internalType": "contract IERC721Token", - "name": "erc721Token", + "internalType": "address", + "name": "txOrigin", "type": "address" }, { "internalType": "uint256", - "name": "erc721TokenId", + "name": "expiryAndNonce", "type": "uint256" + } + ], + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", + "type": "tuple" + } + ], + "name": "getOtcOrderInfo", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" }, { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" + "internalType": "enum LibNativeOrder.OrderStatus", + "name": "status", + "type": "uint8" } ], - "internalType": "struct LibNFTOrder.ERC721Order", - "name": "order", + "internalType": "struct LibNativeOrder.OtcOrderInfo", + "name": "orderInfo", "type": "tuple" } ], - "name": "preSignERC721Order", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address", - "name": "signer", - "type": "address" - }, + "inputs": [], + "name": "getProtocolFeeMultiplier", + "outputs": [ { - "internalType": "bool", - "name": "allowed", - "type": "bool" + "internalType": "uint32", + "name": "multiplier", + "type": "uint32" } ], - "name": "registerAllowedOrderSigner", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "address[]", - "name": "origins", - "type": "address[]" - }, + "inputs": [], + "name": "getQuoteSigner", + "outputs": [ { - "internalType": "bool", - "name": "allowed", - "type": "bool" + "internalType": "address", + "name": "signer", + "type": "address" } ], - "name": "registerAllowedRfqOrigins", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, + "components": [ + { + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "takerToken", + "type": "address" + }, + { + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "address", + "name": "txOrigin", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiry", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "salt", + "type": "uint256" + } + ], + "internalType": "struct LibNativeOrder.RfqOrder", + "name": "order", + "type": "tuple" + } + ], + "name": "getRfqOrderHash", + "outputs": [ { - "internalType": "address", - "name": "targetImpl", - "type": "address" + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" } ], - "name": "rollback", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -6929,150 +6696,87 @@ { "components": [ { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", + "internalType": "contract IERC20TokenV06", + "name": "makerToken", "type": "address" }, { - "internalType": "address", - "name": "taker", + "internalType": "contract IERC20TokenV06", + "name": "takerToken", "type": "address" }, { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" }, { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", + "internalType": "address", + "name": "maker", "type": "address" }, { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" + "internalType": "address", + "name": "taker", + "type": "address" }, { - "internalType": "contract IERC1155Token", - "name": "erc1155Token", + "internalType": "address", + "name": "txOrigin", "type": "address" }, { - "internalType": "uint256", - "name": "erc1155TokenId", - "type": "uint256" + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" }, { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc1155TokenProperties", - "type": "tuple[]" + "internalType": "uint64", + "name": "expiry", + "type": "uint64" }, { - "internalType": "uint128", - "name": "erc1155TokenAmount", - "type": "uint128" + "internalType": "uint256", + "name": "salt", + "type": "uint256" } ], - "internalType": "struct LibNFTOrder.ERC1155Order", - "name": "buyOrder", + "internalType": "struct LibNativeOrder.RfqOrder", + "name": "order", "type": "tuple" - }, + } + ], + "name": "getRfqOrderInfo", + "outputs": [ { "components": [ { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" }, { - "internalType": "uint8", - "name": "v", + "internalType": "enum LibNativeOrder.OrderStatus", + "name": "status", "type": "uint8" }, { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" } ], - "internalType": "struct LibSignature.Signature", - "name": "signature", + "internalType": "struct LibNativeOrder.OrderInfo", + "name": "orderInfo", "type": "tuple" - }, - { - "internalType": "uint256", - "name": "erc1155TokenId", - "type": "uint256" - }, - { - "internalType": "uint128", - "name": "erc1155SellAmount", - "type": "uint128" - }, - { - "internalType": "bool", - "name": "unwrapNativeToken", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "callbackData", - "type": "bytes" } ], - "name": "sellERC1155", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -7080,92 +6784,58 @@ { "components": [ { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" + "internalType": "contract IERC20TokenV06", + "name": "makerToken", + "type": "address" }, { - "internalType": "address", - "name": "maker", + "internalType": "contract IERC20TokenV06", + "name": "takerToken", "type": "address" }, { - "internalType": "address", - "name": "taker", - "type": "address" + "internalType": "uint128", + "name": "makerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" + "internalType": "uint128", + "name": "takerAmount", + "type": "uint128" }, { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "internalType": "address", + "name": "maker", + "type": "address" }, { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", + "internalType": "address", + "name": "taker", "type": "address" }, { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" + "internalType": "address", + "name": "txOrigin", + "type": "address" }, { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" + "internalType": "bytes32", + "name": "pool", + "type": "bytes32" }, { - "internalType": "contract IERC721Token", - "name": "erc721Token", - "type": "address" + "internalType": "uint64", + "name": "expiry", + "type": "uint64" }, { "internalType": "uint256", - "name": "erc721TokenId", + "name": "salt", "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" } ], - "internalType": "struct LibNFTOrder.ERC721Order", - "name": "buyOrder", + "internalType": "struct LibNativeOrder.RfqOrder", + "name": "order", "type": "tuple" }, { @@ -7194,516 +6864,160 @@ "internalType": "struct LibSignature.Signature", "name": "signature", "type": "tuple" - }, - { - "internalType": "uint256", - "name": "erc721TokenId", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "unwrapNativeToken", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "callbackData", - "type": "bytes" - } - ], - "name": "sellERC721", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "encodedPath", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ], - "name": "sellEthForTokenToUniswapV3", - "outputs": [ - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06", - "name": "inputToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "outputToken", - "type": "address" - }, - { - "internalType": "contract ILiquidityProvider", - "name": "provider", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "auxiliaryData", - "type": "bytes" - } - ], - "name": "sellToLiquidityProvider", - "outputs": [ - { - "internalType": "uint256", - "name": "boughtAmount", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06[]", - "name": "tokens", - "type": "address[]" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - }, - { - "internalType": "enum IPancakeSwapFeature.ProtocolFork", - "name": "fork", - "type": "uint8" - } - ], - "name": "sellToPancakeSwap", - "outputs": [ - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06[]", - "name": "tokens", - "type": "address[]" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "isSushi", - "type": "bool" - } - ], - "name": "sellToUniswap", - "outputs": [ - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "encodedPath", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - } - ], - "name": "sellTokenForEthToUniswapV3", - "outputs": [ - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "encodedPath", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minBuyAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" } ], - "name": "sellTokenForTokenToUniswapV3", + "name": "getRfqOrderRelevantState", "outputs": [ { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "components": [ + { + "internalType": "bytes32", + "name": "orderHash", + "type": "bytes32" + }, + { + "internalType": "enum LibNativeOrder.OrderStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "takerTokenFilledAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNativeOrder.OrderInfo", + "name": "orderInfo", + "type": "tuple" + }, { - "internalType": "address", - "name": "quoteSigner", - "type": "address" - } - ], - "name": "setQuoteSigner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "internalType": "uint128", + "name": "actualFillableTakerTokenAmount", + "type": "uint128" + }, { - "internalType": "address", - "name": "transformerDeployer", - "type": "address" + "internalType": "bool", + "name": "isSignatureValid", + "type": "bool" } ], - "name": "setTransformerDeployer", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "bytes4", - "name": "interfaceId", + "name": "selector", "type": "bytes4" - } - ], - "name": "supportInterface", - "outputs": [ + }, { - "internalType": "bool", - "name": "isSupported", - "type": "bool" + "internalType": "uint256", + "name": "idx", + "type": "uint256" } ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ + "name": "getRollbackEntryAtIndex", + "outputs": [ { "internalType": "address", - "name": "newOwner", + "name": "impl", "type": "address" } ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "bytes32[]", - "name": "poolIds", - "type": "bytes32[]" + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" } ], - "name": "transferProtocolFeesForPools", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC20TokenV06", - "name": "erc20", - "type": "address" - }, + "name": "getRollbackLength", + "outputs": [ { "internalType": "uint256", - "name": "amountOut", + "name": "rollbackLength", "type": "uint256" - }, - { - "internalType": "address payable", - "name": "recipientWallet", - "type": "address" } ], - "name": "transferTrappedTokensTo", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "contract IERC20TokenV06", - "name": "inputToken", - "type": "address" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "outputToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "inputTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minOutputTokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint32", - "name": "deploymentNonce", - "type": "uint32" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct ITransformERC20Feature.Transformation[]", - "name": "transformations", - "type": "tuple[]" - } - ], - "name": "transformERC20", + "inputs": [], + "name": "getTransformWallet", "outputs": [ { - "internalType": "uint256", - "name": "outputTokenAmount", - "type": "uint256" + "internalType": "contract IFlashWallet", + "name": "wallet", + "type": "address" } ], - "stateMutability": "payable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "int256", - "name": "amount0Delta", - "type": "int256" - }, - { - "internalType": "int256", - "name": "amount1Delta", - "type": "int256" - }, + "inputs": [], + "name": "getTransformerDeployer", + "outputs": [ { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "internalType": "address", + "name": "deployer", + "type": "address" } ], - "name": "uniswapV3SwapCallback", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [ { - "components": [ - { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", - "type": "uint8" - }, - { - "internalType": "address", - "name": "maker", - "type": "address" - }, - { - "internalType": "address", - "name": "taker", - "type": "address" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" - }, - { - "internalType": "contract IERC1155Token", - "name": "erc1155Token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "erc1155TokenId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc1155TokenProperties", - "type": "tuple[]" - }, - { - "internalType": "uint128", - "name": "erc1155TokenAmount", - "type": "uint128" - } - ], - "internalType": "struct LibNFTOrder.ERC1155Order", - "name": "order", - "type": "tuple" + "internalType": "address", + "name": "maker", + "type": "address" }, { - "internalType": "uint256", - "name": "erc1155TokenId", - "type": "uint256" + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "isValidOrderSigner", + "outputs": [ + { + "internalType": "bool", + "name": "isAllowed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "txOrigin", + "type": "address" + }, + { + "internalType": "uint64", + "name": "nonceBucket", + "type": "uint64" + } + ], + "name": "lastOtcTxOriginNonce", + "outputs": [ + { + "internalType": "uint128", + "name": "lastNonce", + "type": "uint128" } ], - "name": "validateERC1155OrderProperties", - "outputs": [], "stateMutability": "view", "type": "function" }, @@ -7769,13 +7083,13 @@ "type": "tuple[]" }, { - "internalType": "contract IERC1155Token", - "name": "erc1155Token", + "internalType": "contract IERC721Token", + "name": "erc721Token", "type": "address" }, { "internalType": "uint256", - "name": "erc1155TokenId", + "name": "erc721TokenId", "type": "uint256" }, { @@ -7792,54 +7106,14 @@ } ], "internalType": "struct LibNFTOrder.Property[]", - "name": "erc1155TokenProperties", + "name": "erc721TokenProperties", "type": "tuple[]" - }, - { - "internalType": "uint128", - "name": "erc1155TokenAmount", - "type": "uint128" } ], - "internalType": "struct LibNFTOrder.ERC1155Order", - "name": "order", + "internalType": "struct LibNFTOrder.ERC721Order", + "name": "sellOrder", "type": "tuple" }, - { - "components": [ - { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" - } - ], - "name": "validateERC1155OrderSignature", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ { "components": [ { @@ -7928,1129 +7202,1857 @@ } ], "internalType": "struct LibNFTOrder.ERC721Order", - "name": "order", + "name": "buyOrder", "type": "tuple" }, - { - "internalType": "uint256", - "name": "erc721TokenId", - "type": "uint256" - } - ], - "name": "validateERC721OrderProperties", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ { "components": [ { - "internalType": "enum LibNFTOrder.TradeDirection", - "name": "direction", + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", "type": "uint8" }, { - "internalType": "address", - "name": "maker", - "type": "address" + "internalType": "uint8", + "name": "v", + "type": "uint8" }, { - "internalType": "address", - "name": "taker", - "type": "address" + "internalType": "bytes32", + "name": "r", + "type": "bytes32" }, { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "sellOrderSignature", + "type": "tuple" + }, + { + "components": [ { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" }, { - "internalType": "contract IERC20TokenV06", - "name": "erc20Token", - "type": "address" + "internalType": "uint8", + "name": "v", + "type": "uint8" }, { - "internalType": "uint256", - "name": "erc20TokenAmount", - "type": "uint256" + "internalType": "bytes32", + "name": "r", + "type": "bytes32" }, { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "feeData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Fee[]", - "name": "fees", - "type": "tuple[]" - }, + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "buyOrderSignature", + "type": "tuple" + } + ], + "name": "matchERC721Orders", + "outputs": [ + { + "internalType": "uint256", + "name": "profit", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "migrate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "outputToken", + "type": "address" + }, + { + "components": [ { - "internalType": "contract IERC721Token", - "name": "erc721Token", - "type": "address" + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" }, { "internalType": "uint256", - "name": "erc721TokenId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "contract IPropertyValidator", - "name": "propertyValidator", - "type": "address" - }, - { - "internalType": "bytes", - "name": "propertyData", - "type": "bytes" - } - ], - "internalType": "struct LibNFTOrder.Property[]", - "name": "erc721TokenProperties", - "type": "tuple[]" + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" } ], - "internalType": "struct LibNFTOrder.ERC721Order", - "name": "order", - "type": "tuple" + "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" + } + ], + "name": "multiplexBatchSellEthForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "boughtAmount", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "inputToken", + "type": "address" }, { "components": [ { - "internalType": "enum LibSignature.SignatureType", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "v", + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", "type": "uint8" }, { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" }, { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" + "internalType": "bytes", + "name": "data", + "type": "bytes" } ], - "internalType": "struct LibSignature.Signature", - "name": "signature", - "type": "tuple" - } - ], - "name": "validateERC721OrderSignature", - "outputs": [], - "stateMutability": "view", - "type": "function" - } - ], - "devdoc": { - "details": "Interface for a fully featured Exchange Proxy.", - "kind": "dev", - "methods": { - "_fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,address)": { - "details": "Fill a limit order. Internal variant. ETH protocol fees can be attached to this call. Any unspent ETH will be refunded to `msg.sender` (not `sender`).", - "params": { - "order": "The limit order.", - "sender": "The order sender.", - "signature": "The order signature.", - "taker": "The order taker.", - "takerTokenFillAmount": "Maximum taker token to fill this order with." - }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much maker token was filled." - } - }, - "_fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": { - "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Internal variant.", - "params": { - "makerSignature": "The order signature from the maker.", - "order": "The OTC order.", - "recipient": "The recipient of the bought maker tokens.", - "taker": "The address to fill the order in the context of.", - "takerTokenFillAmount": "Maximum taker token amount to fill this order with.", - "useSelfBalance": "Whether to use the Exchange Proxy's balance of input tokens." - }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much taker token was filled." - } - }, - "_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": { - "details": "Fill an RFQ order. Internal variant.", - "params": { - "order": "The RFQ order.", - "recipient": "The recipient of the maker tokens.", - "signature": "The order signature.", - "taker": "The order taker.", - "takerTokenFillAmount": "Maximum taker token to fill this order with.", - "useSelfBalance": "Whether to use the ExchangeProxy's transient balance of taker tokens to fill the order." - }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much maker token was filled." - } - }, - "_sellHeldTokenForTokenToUniswapV3(bytes,uint256,uint256,address)": { - "details": "Sell a token for another token directly against uniswap v3. Private variant, uses tokens held by `address(this)`.", - "params": { - "encodedPath": "Uniswap-encoded path.", - "minBuyAmount": "Minimum amount of the last token in the path to buy.", - "recipient": "The recipient of the bought tokens. Can be zero for sender.", - "sellAmount": "amount of the first token in the path to sell." - }, - "returns": { - "buyAmount": "Amount of the last token in the path bought." - } - }, - "_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))": { - "details": "Internal version of `transformERC20()`. Only callable from within.", - "params": { - "args": "A `TransformERC20Args` struct." - }, - "returns": { - "outputTokenAmount": "The amount of `outputToken` received by the taker." - } - }, - "batchBuyERC1155s((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bytes[],bool)": { - "details": "Buys multiple ERC1155 assets by filling the given orders.", - "params": { - "callbackData": "The data (if any) to pass to the taker callback for each order. Refer to the `callbackData` parameter to for `buyERC1155`.", - "erc1155TokenAmounts": "The amounts of the ERC1155 assets to buy for each order.", - "revertIfIncomplete": "If true, reverts if this function fails to fill any individual order.", - "sellOrders": "The ERC1155 sell orders.", - "signatures": "The order signatures." - }, - "returns": { - "successes": "An array of booleans corresponding to whether each order in `orders` was successfully filled." - } - }, - "batchBuyERC721s((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[])[],(uint8,uint8,bytes32,bytes32)[],bytes[],bool)": { - "details": "Buys multiple ERC721 assets by filling the given orders.", - "params": { - "callbackData": "The data (if any) to pass to the taker callback for each order. Refer to the `callbackData` parameter to for `buyERC721`.", - "revertIfIncomplete": "If true, reverts if this function fails to fill any individual order.", - "sellOrders": "The ERC721 sell orders.", - "signatures": "The order signatures." - }, - "returns": { - "successes": "An array of booleans corresponding to whether each order in `orders` was successfully filled." - } - }, - "batchCancelERC1155Orders(uint256[])": { - "details": "Cancel multiple ERC1155 orders by their nonces. The caller should be the maker of the orders. Silently succeeds if an order with the same nonce has already been filled or cancelled.", - "params": { - "orderNonces": "The order nonces." - } - }, - "batchCancelERC721Orders(uint256[])": { - "details": "Cancel multiple ERC721 orders by their nonces. The caller should be the maker of the orders. Silently succeeds if an order with the same nonce has already been filled or cancelled.", - "params": { - "orderNonces": "The order nonces." - } - }, - "batchCancelLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[])": { - "details": "Cancel multiple limit orders. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", - "params": { - "orders": "The limit orders." - } - }, - "batchCancelPairLimitOrders(address[],address[],uint256[])": { - "details": "Cancel all limit orders for a given maker and pairs with salts less than the values provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", - "params": { - "makerTokens": "The maker tokens.", - "minValidSalts": "The new minimum valid salts.", - "takerTokens": "The taker tokens." - } - }, - "batchCancelPairLimitOrdersWithSigner(address,address[],address[],uint256[])": { - "details": "Cancel all limit orders for a given maker and pairs with salts less than the values provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", - "params": { - "maker": "The maker for which to cancel.", - "makerTokens": "The maker tokens.", - "minValidSalts": "The new minimum valid salts.", - "takerTokens": "The taker tokens." - } - }, - "batchCancelPairRfqOrders(address[],address[],uint256[])": { - "details": "Cancel all RFQ orders for a given maker and pairs with salts less than the values provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", - "params": { - "makerTokens": "The maker tokens.", - "minValidSalts": "The new minimum valid salts.", - "takerTokens": "The taker tokens." - } - }, - "batchCancelPairRfqOrdersWithSigner(address,address[],address[],uint256[])": { - "details": "Cancel all RFQ orders for a given maker and pairs with salts less than the values provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", - "params": { - "maker": "The maker for which to cancel.", - "makerTokens": "The maker tokens.", - "minValidSalts": "The new minimum valid salts.", - "takerTokens": "The taker tokens." - } - }, - "batchCancelRfqOrders((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[])": { - "details": "Cancel multiple RFQ orders. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", - "params": { - "orders": "The RFQ orders." - } - }, - "batchExecuteMetaTransactions((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { - "details": "Execute multiple meta-transactions.", - "params": { - "mtxs": "The meta-transactions.", - "signatures": "The signature by each respective `mtx.signer`." - }, - "returns": { - "returnResults": "The ABI-encoded results of the underlying calls." - } - }, - "batchFillLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bool)": { - "details": "Fills multiple limit orders.", - "params": { - "orders": "Array of limit orders.", - "revertIfIncomplete": "If true, reverts if this function fails to fill the full fill amount for any individual order.", - "signatures": "Array of signatures corresponding to each order.", - "takerTokenFillAmounts": "Array of desired amounts to fill each order." + "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", + "name": "calls", + "type": "tuple[]" }, - "returns": { - "makerTokenFilledAmounts": "Array of amounts filled, in maker token.", - "takerTokenFilledAmounts": "Array of amounts filled, in taker token." - } - }, - "batchFillRfqOrders((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bool)": { - "details": "Fills multiple RFQ orders.", - "params": { - "orders": "Array of RFQ orders.", - "revertIfIncomplete": "If true, reverts if this function fails to fill the full fill amount for any individual order.", - "signatures": "Array of signatures corresponding to each order.", - "takerTokenFillAmounts": "Array of desired amounts to fill each order." + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" }, - "returns": { - "makerTokenFilledAmounts": "Array of amounts filled, in maker token.", - "takerTokenFilledAmounts": "Array of amounts filled, in taker token." + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" } - }, - "batchFillTakerSignedOtcOrders((address,address,uint128,uint128,address,address,address,uint256)[],(uint8,uint8,bytes32,bytes32)[],(uint8,uint8,bytes32,bytes32)[],bool[])": { - "details": "Fills multiple taker-signed OTC orders.", - "params": { - "makerSignatures": "Array of maker signatures for each order.", - "orders": "Array of OTC orders.", - "takerSignatures": "Array of taker signatures for each order.", - "unwrapWeth": "Array of booleans representing whether or not to unwrap bought WETH into ETH for each order. Should be set to false if the maker token is not WETH." - }, - "returns": { - "successes": "Array of booleans representing whether or not each order in `orders` was filled successfully." + ], + "name": "multiplexBatchSellTokenForEth", + "outputs": [ + { + "internalType": "uint256", + "name": "boughtAmount", + "type": "uint256" } - }, - "batchGetLimitOrderRelevantStates((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { - "details": "Batch version of `getLimitOrderRelevantState()`, without reverting. Orders that would normally cause `getLimitOrderRelevantState()` to revert will have empty results.", - "params": { - "orders": "The limit orders.", - "signatures": "The order signatures." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "inputToken", + "type": "address" }, - "returns": { - "actualFillableTakerTokenAmounts": "How much of each order is fillable based on maker funds, in taker tokens.", - "isSignatureValids": "Whether each signature is valid for the order.", - "orderInfos": "Info about the orders." - } - }, - "batchGetRfqOrderRelevantStates((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { - "details": "Batch version of `getRfqOrderRelevantState()`, without reverting. Orders that would normally cause `getRfqOrderRelevantState()` to revert will have empty results.", - "params": { - "orders": "The RFQ orders.", - "signatures": "The order signatures." + { + "internalType": "contract IERC20TokenV06", + "name": "outputToken", + "type": "address" }, - "returns": { - "actualFillableTakerTokenAmounts": "How much of each order is fillable based on maker funds, in taker tokens.", - "isSignatureValids": "Whether each signature is valid for the order.", - "orderInfos": "Info about the orders." - } - }, - "batchMatchERC721Orders((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[])[],(uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[])[],(uint8,uint8,bytes32,bytes32)[],(uint8,uint8,bytes32,bytes32)[])": { - "details": "Matches pairs of complementary orders that have non-negative spreads. Each order is filled at their respective price, and the matcher receives a profit denominated in the ERC20 token.", - "params": { - "buyOrderSignatures": "Signatures for the buy orders.", - "buyOrders": "Orders buying ERC721 assets.", - "sellOrderSignatures": "Signatures for the sell orders.", - "sellOrders": "Orders selling ERC721 assets." + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", + "name": "calls", + "type": "tuple[]" }, - "returns": { - "profits": "The amount of profit earned by the caller of this function for each pair of matched orders (denominated in the ERC20 token of the order pair).", - "successes": "An array of booleans corresponding to whether each pair of orders was successfully matched." - } - }, - "buyERC1155((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),(uint8,uint8,bytes32,bytes32),uint128,bytes)": { - "details": "Buys an ERC1155 asset by filling the given order.", - "params": { - "callbackData": "If this parameter is non-zero, invokes `zeroExERC1155OrderCallback` on `msg.sender` after the ERC1155 asset has been transferred to `msg.sender` but before transferring the ERC20 tokens to the seller. Native tokens acquired during the callback can be used to fill the order.", - "erc1155BuyAmount": "The amount of the ERC1155 asset to buy.", - "sellOrder": "The ERC1155 sell order.", - "signature": "The order signature." - } - }, - "buyERC721((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32),bytes)": { - "details": "Buys an ERC721 asset by filling the given order.", - "params": { - "callbackData": "If this parameter is non-zero, invokes `zeroExERC721OrderCallback` on `msg.sender` after the ERC721 asset has been transferred to `msg.sender` but before transferring the ERC20 tokens to the seller. Native tokens acquired during the callback can be used to fill the order.", - "sellOrder": "The ERC721 sell order.", - "signature": "The order signature." - } - }, - "cancelERC1155Order(uint256)": { - "details": "Cancel a single ERC1155 order by its nonce. The caller should be the maker of the order. Silently succeeds if an order with the same nonce has already been filled or cancelled.", - "params": { - "orderNonce": "The order nonce." - } - }, - "cancelERC721Order(uint256)": { - "details": "Cancel a single ERC721 order by its nonce. The caller should be the maker of the order. Silently succeeds if an order with the same nonce has already been filled or cancelled.", - "params": { - "orderNonce": "The order nonce." + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" } - }, - "cancelLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { - "details": "Cancel a single limit order. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", - "params": { - "order": "The limit order." + ], + "name": "multiplexBatchSellTokenForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "boughtAmount", + "type": "uint256" } - }, - "cancelPairLimitOrders(address,address,uint256)": { - "details": "Cancel all limit orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", - "params": { - "makerToken": "The maker token.", - "minValidSalt": "The new minimum valid salt.", - "takerToken": "The taker token." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" } - }, - "cancelPairLimitOrdersWithSigner(address,address,address,uint256)": { - "details": "Cancel all limit orders for a given maker and pair with a salt less than the value provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", - "params": { - "maker": "The maker for which to cancel.", - "makerToken": "The maker token.", - "minValidSalt": "The new minimum valid salt.", - "takerToken": "The taker token." + ], + "name": "multiplexMultiHopSellEthForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "boughtAmount", + "type": "uint256" } - }, - "cancelPairRfqOrders(address,address,uint256)": { - "details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", - "params": { - "makerToken": "The maker token.", - "minValidSalt": "The new minimum valid salt.", - "takerToken": "The taker token." + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" } - }, - "cancelPairRfqOrdersWithSigner(address,address,address,uint256)": { - "details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.", - "params": { - "maker": "The maker for which to cancel.", - "makerToken": "The maker token.", - "minValidSalt": "The new minimum valid salt.", - "takerToken": "The taker token." + ], + "name": "multiplexMultiHopSellTokenForEth", + "outputs": [ + { + "internalType": "uint256", + "name": "boughtAmount", + "type": "uint256" } - }, - "cancelRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": { - "details": "Cancel a single RFQ order. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.", - "params": { - "order": "The RFQ order." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" } - }, - "createTransformWallet()": { - "details": "Deploy a new flash wallet instance and replace the current one with it. Useful if we somehow break the current wallet instance. Only callable by the owner.", - "returns": { - "wallet": "The new wallet instance." + ], + "name": "multiplexMultiHopSellTokenForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "boughtAmount", + "type": "uint256" } - }, - "executeMetaTransaction((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256),(uint8,uint8,bytes32,bytes32))": { - "details": "Execute a single meta-transaction.", - "params": { - "mtx": "The meta-transaction.", - "signature": "The signature by `mtx.signer`." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" }, - "returns": { - "returnResult": "The ABI-encoded result of the underlying call." + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" } - }, - "extend(bytes4,address)": { - "details": "Register or replace a function.", - "params": { - "impl": "The implementation contract for the function.", - "selector": "The function selector." + ], + "name": "onERC1155Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "success", + "type": "bytes4" } - }, - "fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { - "details": "Fill a limit order. The taker and sender will be the caller.", - "params": { - "order": "The limit order. ETH protocol fees can be attached to this call. Any unspent ETH will be refunded to the caller.", - "signature": "The order signature.", - "takerTokenFillAmount": "Maximum taker token amount to fill this order with." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much maker token was filled." - } - }, - "fillOrKillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { - "details": "Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens. The taker will be the caller. ETH protocol fees can be attached to this call. Any unspent ETH will be refunded to the caller.", - "params": { - "order": "The limit order.", - "signature": "The order signature.", - "takerTokenFillAmount": "How much taker token to fill this order with." + { + "internalType": "address", + "name": "from", + "type": "address" }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled." - } - }, - "fillOrKillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { - "details": "Fill an RFQ order for exactly `takerTokenFillAmount` taker tokens. The taker will be the caller.", - "params": { - "order": "The RFQ order.", - "signature": "The order signature.", - "takerTokenFillAmount": "How much taker token to fill this order with." + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled." + { + "internalType": "bytes", + "name": "data", + "type": "bytes" } - }, - "fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { - "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens.", - "params": { - "makerSignature": "The order signature from the maker.", - "order": "The OTC order.", - "takerTokenFillAmount": "Maximum taker token amount to fill this order with." - }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much taker token was filled." + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "success", + "type": "bytes4" } - }, - "fillOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { - "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Unwraps bought WETH into ETH before sending it to the taker.", - "params": { - "makerSignature": "The order signature from the maker.", - "order": "The OTC order.", - "takerTokenFillAmount": "Maximum taker token amount to fill this order with." - }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much taker token was filled." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC1155Token", + "name": "erc1155Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc1155TokenProperties", + "type": "tuple[]" + }, + { + "internalType": "uint128", + "name": "erc1155TokenAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNFTOrder.ERC1155Order", + "name": "order", + "type": "tuple" } - }, - "fillOtcOrderWithEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32))": { - "details": "Fill an OTC order whose taker token is WETH for up to `msg.value`.", - "params": { - "makerSignature": "The order signature from the maker.", - "order": "The OTC order." - }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much taker token was filled." + ], + "name": "preSignERC1155Order", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC721Token", + "name": "erc721Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc721TokenProperties", + "type": "tuple[]" + } + ], + "internalType": "struct LibNFTOrder.ERC721Order", + "name": "order", + "type": "tuple" } - }, - "fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { - "details": "Fill an RFQ order for up to `takerTokenFillAmount` taker tokens. The taker will be the caller.", - "params": { - "order": "The RFQ order.", - "signature": "The order signature.", - "takerTokenFillAmount": "Maximum taker token amount to fill this order with." + ], + "name": "preSignERC721Order", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much maker token was filled." - } - }, - "fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { - "details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker.", - "params": { - "makerSignature": "The order signature from the maker.", - "order": "The OTC order.", - "takerSignature": "The order signature from the taker." - } - }, - "fillTakerSignedOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { - "details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker. Unwraps bought WETH into ETH before sending it to the taker.", - "params": { - "makerSignature": "The order signature from the maker.", - "order": "The OTC order.", - "takerSignature": "The order signature from the taker." + { + "internalType": "bool", + "name": "allowed", + "type": "bool" } - }, - "getERC1155OrderHash((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128))": { - "details": "Get the EIP-712 hash of an ERC1155 order.", - "params": { - "order": "The ERC1155 order." + ], + "name": "registerAllowedOrderSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "origins", + "type": "address[]" }, - "returns": { - "orderHash": "The order hash." + { + "internalType": "bool", + "name": "allowed", + "type": "bool" } - }, - "getERC1155OrderInfo((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128))": { - "details": "Get the order info for an ERC1155 order.", - "params": { - "order": "The ERC1155 order." + ], + "name": "registerAllowedRfqOrigins", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" }, - "returns": { - "orderInfo": "Infor about the order." + { + "internalType": "address", + "name": "targetImpl", + "type": "address" } - }, - "getERC721OrderHash((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]))": { - "details": "Get the EIP-712 hash of an ERC721 order.", - "params": { - "order": "The ERC721 order." + ], + "name": "rollback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC1155Token", + "name": "erc1155Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc1155TokenProperties", + "type": "tuple[]" + }, + { + "internalType": "uint128", + "name": "erc1155TokenAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNFTOrder.ERC1155Order", + "name": "buyOrder", + "type": "tuple" }, - "returns": { - "orderHash": "The order hash." - } - }, - "getERC721OrderStatus((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]))": { - "details": "Get the current status of an ERC721 order.", - "params": { - "order": "The ERC721 order." + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" }, - "returns": { - "status": "The status of the order." - } - }, - "getERC721OrderStatusBitVector(address,uint248)": { - "details": "Get the order status bit vector for the given maker address and nonce range.", - "params": { - "maker": "The maker of the order.", - "nonceRange": "Order status bit vectors are indexed by maker address and the upper 248 bits of the order nonce. We define `nonceRange` to be these 248 bits." + { + "internalType": "uint256", + "name": "erc1155TokenId", + "type": "uint256" }, - "returns": { - "bitVector": "The order status bit vector for the given maker and nonce range." - } - }, - "getLimitOrderHash((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { - "details": "Get the canonical hash of a limit order.", - "params": { - "order": "The limit order." + { + "internalType": "uint128", + "name": "erc1155SellAmount", + "type": "uint128" }, - "returns": { - "orderHash": "The order hash." - } - }, - "getLimitOrderInfo((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { - "details": "Get the order info for a limit order.", - "params": { - "order": "The limit order." + { + "internalType": "bool", + "name": "unwrapNativeToken", + "type": "bool" }, - "returns": { - "orderInfo": "Info about the order." + { + "internalType": "bytes", + "name": "callbackData", + "type": "bytes" } - }, - "getLimitOrderRelevantState((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32))": { - "details": "Get order info, fillable amount, and signature validity for a limit order. Fillable amount is determined using balances and allowances of the maker.", - "params": { - "order": "The limit order.", - "signature": "The order signature." + ], + "name": "sellERC1155", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC721Token", + "name": "erc721Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc721TokenProperties", + "type": "tuple[]" + } + ], + "internalType": "struct LibNFTOrder.ERC721Order", + "name": "buyOrder", + "type": "tuple" }, - "returns": { - "actualFillableTakerTokenAmount": "How much of the order is fillable based on maker funds, in taker tokens.", - "isSignatureValid": "Whether the signature is valid.", - "orderInfo": "Info about the order." - } - }, - "getMetaTransactionExecutedBlock((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256))": { - "details": "Get the block at which a meta-transaction has been executed.", - "params": { - "mtx": "The meta-transaction." + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" }, - "returns": { - "blockNumber": "The block height when the meta-transactioin was executed." - } - }, - "getMetaTransactionHash((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256))": { - "details": "Get the EIP712 hash of a meta-transaction.", - "params": { - "mtx": "The meta-transaction." + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" }, - "returns": { - "mtxHash": "The EIP712 hash of `mtx`." - } - }, - "getMetaTransactionHashExecutedBlock(bytes32)": { - "details": "Get the block at which a meta-transaction hash has been executed.", - "params": { - "mtxHash": "The meta-transaction hash." + { + "internalType": "bool", + "name": "unwrapNativeToken", + "type": "bool" }, - "returns": { - "blockNumber": "The block height when the meta-transactioin was executed." + { + "internalType": "bytes", + "name": "callbackData", + "type": "bytes" } - }, - "getOtcOrderHash((address,address,uint128,uint128,address,address,address,uint256))": { - "details": "Get the canonical hash of an OTC order.", - "params": { - "order": "The OTC order." + ], + "name": "sellERC721", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "encodedPath", + "type": "bytes" }, - "returns": { - "orderHash": "The order hash." - } - }, - "getOtcOrderInfo((address,address,uint128,uint128,address,address,address,uint256))": { - "details": "Get the order info for an OTC order.", - "params": { - "order": "The OTC order." + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" }, - "returns": { - "orderInfo": "Info about the order." - } - }, - "getProtocolFeeMultiplier()": { - "details": "Get the protocol fee multiplier. This should be multiplied by the gas price to arrive at the required protocol fee to fill a native order.", - "returns": { - "multiplier": "The protocol fee multiplier." + { + "internalType": "address", + "name": "recipient", + "type": "address" } - }, - "getQuoteSigner()": { - "details": "Return the optional signer for `transformERC20()` calldata.", - "returns": { - "signer": "The transform deployer address." + ], + "name": "sellEthForTokenToUniswapV3", + "outputs": [ + { + "internalType": "uint256", + "name": "buyAmount", + "type": "uint256" } - }, - "getRfqOrderHash((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": { - "details": "Get the canonical hash of an RFQ order.", - "params": { - "order": "The RFQ order." + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "inputToken", + "type": "address" }, - "returns": { - "orderHash": "The order hash." - } - }, - "getRfqOrderInfo((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": { - "details": "Get the order info for an RFQ order.", - "params": { - "order": "The RFQ order." + { + "internalType": "contract IERC20TokenV06", + "name": "outputToken", + "type": "address" }, - "returns": { - "orderInfo": "Info about the order." - } - }, - "getRfqOrderRelevantState((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32))": { - "details": "Get order info, fillable amount, and signature validity for an RFQ order. Fillable amount is determined using balances and allowances of the maker.", - "params": { - "order": "The RFQ order.", - "signature": "The order signature." + { + "internalType": "contract ILiquidityProvider", + "name": "provider", + "type": "address" }, - "returns": { - "actualFillableTakerTokenAmount": "How much of the order is fillable based on maker funds, in taker tokens.", - "isSignatureValid": "Whether the signature is valid.", - "orderInfo": "Info about the order." - } - }, - "getRollbackEntryAtIndex(bytes4,uint256)": { - "details": "Retrieve an entry in the rollback history for a function.", - "params": { - "idx": "The index in the rollback history.", - "selector": "The function selector." + { + "internalType": "address", + "name": "recipient", + "type": "address" }, - "returns": { - "impl": "An implementation address for the function at index `idx`." - } - }, - "getRollbackLength(bytes4)": { - "details": "Retrieve the length of the rollback history for a function.", - "params": { - "selector": "The function selector." + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" }, - "returns": { - "rollbackLength": "The number of items in the rollback history for the function." - } - }, - "getTransformWallet()": { - "details": "Return the current wallet instance that will serve as the execution context for transformations.", - "returns": { - "wallet": "The wallet instance." - } - }, - "getTransformerDeployer()": { - "details": "Return the allowed deployer for transformers.", - "returns": { - "deployer": "The transform deployer address." + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "auxiliaryData", + "type": "bytes" } - }, - "isValidOrderSigner(address,address)": { - "details": "checks if a given address is registered to sign on behalf of a maker address", - "params": { - "maker": "The maker address encoded in an order (can be a contract)", - "signer": "The address that is providing a signature" + ], + "name": "sellToLiquidityProvider", + "outputs": [ + { + "internalType": "uint256", + "name": "boughtAmount", + "type": "uint256" } - }, - "lastOtcTxOriginNonce(address,uint64)": { - "details": "Get the last nonce used for a particular tx.origin address and nonce bucket.", - "params": { - "nonceBucket": "The nonce bucket index.", - "txOrigin": "The address." + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06[]", + "name": "tokens", + "type": "address[]" }, - "returns": { - "lastNonce": "The last nonce value used." - } - }, - "matchERC721Orders((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { - "details": "Matches a pair of complementary orders that have a non-negative spread. Each order is filled at their respective price, and the matcher receives a profit denominated in the ERC20 token.", - "params": { - "buyOrder": "Order buying an ERC721 asset.", - "buyOrderSignature": "Signature for the buy order.", - "sellOrder": "Order selling an ERC721 asset.", - "sellOrderSignature": "Signature for the sell order." + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" }, - "returns": { - "profit": "The amount of profit earned by the caller of this function (denominated in the ERC20 token of the matched orders)." + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" + }, + { + "internalType": "enum IPancakeSwapFeature.ProtocolFork", + "name": "fork", + "type": "uint8" } - }, - "migrate(address,bytes,address)": { - "details": "Execute a migration function in the context of the ZeroEx contract. The result of the function being called should be the magic bytes 0x2c64c5ef (`keccack('MIGRATE_SUCCESS')`). Only callable by the owner. The owner will be temporarily set to `address(this)` inside the call. Before returning, the owner will be set to `newOwner`.", - "params": { - "data": "The call data.", - "newOwner": "The address of the new owner.", - "target": "The migrator contract address." + ], + "name": "sellToPancakeSwap", + "outputs": [ + { + "internalType": "uint256", + "name": "buyAmount", + "type": "uint256" } - }, - "multiplexBatchSellEthForToken(address,(uint8,uint256,bytes)[],uint256)": { - "details": "Sells attached ETH for `outputToken` using the provided calls.", - "params": { - "calls": "The calls to use to sell the attached ETH.", - "minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.", - "outputToken": "The token to buy." + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06[]", + "name": "tokens", + "type": "address[]" }, - "returns": { - "boughtAmount": "The amount of `outputToken` bought." - } - }, - "multiplexBatchSellTokenForEth(address,(uint8,uint256,bytes)[],uint256,uint256)": { - "details": "Sells `sellAmount` of the given `inputToken` for ETH using the provided calls.", - "params": { - "calls": "The calls to use to sell the input tokens.", - "inputToken": "The token to sell.", - "minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.", - "sellAmount": "The amount of `inputToken` to sell." + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" }, - "returns": { - "boughtAmount": "The amount of ETH bought." - } - }, - "multiplexBatchSellTokenForToken(address,address,(uint8,uint256,bytes)[],uint256,uint256)": { - "details": "Sells `sellAmount` of the given `inputToken` for `outputToken` using the provided calls.", - "params": { - "calls": "The calls to use to sell the input tokens.", - "inputToken": "The token to sell.", - "minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.", - "outputToken": "The token to buy.", - "sellAmount": "The amount of `inputToken` to sell." + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" }, - "returns": { - "boughtAmount": "The amount of `outputToken` bought." + { + "internalType": "bool", + "name": "isSushi", + "type": "bool" } - }, - "multiplexMultiHopSellEthForToken(address[],(uint8,bytes)[],uint256)": { - "details": "Sells attached ETH via the given sequence of tokens and calls. `tokens[0]` must be WETH. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`", - "params": { - "calls": "The sequence of calls to use for the sell.", - "minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.", - "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." - }, - "returns": { - "boughtAmount": "The amount of output tokens bought." + ], + "name": "sellToUniswap", + "outputs": [ + { + "internalType": "uint256", + "name": "buyAmount", + "type": "uint256" } - }, - "multiplexMultiHopSellTokenForEth(address[],(uint8,bytes)[],uint256,uint256)": { - "details": "Sells `sellAmount` of the input token (`tokens[0]`) for ETH via the given sequence of tokens and calls. The last token in `tokens` must be WETH.", - "params": { - "calls": "The sequence of calls to use for the sell.", - "minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.", - "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "encodedPath", + "type": "bytes" }, - "returns": { - "boughtAmount": "The amount of ETH bought." - } - }, - "multiplexMultiHopSellTokenForToken(address[],(uint8,bytes)[],uint256,uint256)": { - "details": "Sells `sellAmount` of the input token (`tokens[0]`) via the given sequence of tokens and calls. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`", - "params": { - "calls": "The sequence of calls to use for the sell.", - "minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.", - "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" }, - "returns": { - "boughtAmount": "The amount of output tokens bought." - } - }, - "onERC1155Received(address,address,uint256,uint256,bytes)": { - "details": "Callback for the ERC1155 `safeTransferFrom` function. This callback can be used to sell an ERC1155 asset if a valid ERC1155 order, signature and `unwrapNativeToken` are encoded in `data`. This allows takers to sell their ERC1155 asset without first calling `setApprovalForAll`.", - "params": { - "data": "Additional data with no specified format. If a valid ERC1155 order, signature and `unwrapNativeToken` are encoded in `data`, this function will try to fill the order using the received asset.", - "from": "The address which previously owned the token.", - "operator": "The address which called `safeTransferFrom`.", - "tokenId": "The ID of the asset being transferred.", - "value": "The amount being transferred." + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" }, - "returns": { - "success": "The selector of this function (0xf23a6e61), indicating that the callback succeeded." + { + "internalType": "address payable", + "name": "recipient", + "type": "address" } - }, - "onERC721Received(address,address,uint256,bytes)": { - "details": "Callback for the ERC721 `safeTransferFrom` function. This callback can be used to sell an ERC721 asset if a valid ERC721 order, signature and `unwrapNativeToken` are encoded in `data`. This allows takers to sell their ERC721 asset without first calling `setApprovalForAll`.", - "params": { - "data": "Additional data with no specified format. If a valid ERC721 order, signature and `unwrapNativeToken` are encoded in `data`, this function will try to fill the order using the received asset.", - "from": "The address which previously owned the token.", - "operator": "The address which called `safeTransferFrom`.", - "tokenId": "The ID of the asset being transferred." - }, - "returns": { - "success": "The selector of this function (0x150b7a02), indicating that the callback succeeded." + ], + "name": "sellTokenForEthToUniswapV3", + "outputs": [ + { + "internalType": "uint256", + "name": "buyAmount", + "type": "uint256" } - }, - "owner()": { - "details": "The owner of this contract.", - "returns": { - "ownerAddress": "The owner address." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "encodedPath", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minBuyAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" } - }, - "preSignERC1155Order((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128))": { - "details": "Approves an ERC1155 order on-chain. After pre-signing the order, the `PRESIGNED` signature type will become valid for that order and signer.", - "params": { - "order": "An ERC1155 order." + ], + "name": "sellTokenForTokenToUniswapV3", + "outputs": [ + { + "internalType": "uint256", + "name": "buyAmount", + "type": "uint256" } - }, - "preSignERC721Order((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]))": { - "details": "Approves an ERC721 order on-chain. After pre-signing the order, the `PRESIGNED` signature type will become valid for that order and signer.", - "params": { - "order": "An ERC721 order." + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "quoteSigner", + "type": "address" } - }, - "registerAllowedOrderSigner(address,bool)": { - "details": "Register a signer who can sign on behalf of msg.sender This allows one to sign on behalf of a contract that calls this function", - "params": { - "allowed": "True to register, false to unregister.", - "signer": "The address from which you plan to generate signatures" + ], + "name": "setQuoteSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "transformerDeployer", + "type": "address" } - }, - "registerAllowedRfqOrigins(address[],bool)": { - "details": "Mark what tx.origin addresses are allowed to fill an order that specifies the message sender as its txOrigin.", - "params": { - "allowed": "True to register, false to unregister.", - "origins": "An array of origin addresses to update." + ], + "name": "setTransformerDeployer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" } - }, - "rollback(bytes4,address)": { - "details": "Roll back to a prior implementation of a function.", - "params": { - "selector": "The function selector.", - "targetImpl": "The address of an older implementation of the function." + ], + "name": "supportInterface", + "outputs": [ + { + "internalType": "bool", + "name": "isSupported", + "type": "bool" } - }, - "sellERC1155((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),(uint8,uint8,bytes32,bytes32),uint256,uint128,bool,bytes)": { - "details": "Sells an ERC1155 asset to fill the given order.", - "params": { - "buyOrder": "The ERC1155 buy order.", - "callbackData": "If this parameter is non-zero, invokes `zeroExERC1155OrderCallback` on `msg.sender` after the ERC20 tokens have been transferred to `msg.sender` but before transferring the ERC1155 asset to the buyer.", - "erc1155SellAmount": "The amount of the ERC1155 asset to sell.", - "erc1155TokenId": "The ID of the ERC1155 asset being sold. If the given order specifies properties, the asset must satisfy those properties. Otherwise, it must equal the tokenId in the order.", - "signature": "The order signature from the maker.", - "unwrapNativeToken": "If this parameter is true and the ERC20 token of the order is e.g. WETH, unwraps the token before transferring it to the taker." + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" } - }, - "sellERC721((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32),uint256,bool,bytes)": { - "details": "Sells an ERC721 asset to fill the given order.", - "params": { - "buyOrder": "The ERC721 buy order.", - "callbackData": "If this parameter is non-zero, invokes `zeroExERC721OrderCallback` on `msg.sender` after the ERC20 tokens have been transferred to `msg.sender` but before transferring the ERC721 asset to the buyer.", - "erc721TokenId": "The ID of the ERC721 asset being sold. If the given order specifies properties, the asset must satisfy those properties. Otherwise, it must equal the tokenId in the order.", - "signature": "The order signature from the maker.", - "unwrapNativeToken": "If this parameter is true and the ERC20 token of the order is e.g. WETH, unwraps the token before transferring it to the taker." + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "poolIds", + "type": "bytes32[]" } - }, - "sellEthForTokenToUniswapV3(bytes,uint256,address)": { - "details": "Sell attached ETH directly against uniswap v3.", - "params": { - "encodedPath": "Uniswap-encoded path, where the first token is WETH.", - "minBuyAmount": "Minimum amount of the last token in the path to buy.", - "recipient": "The recipient of the bought tokens. Can be zero for sender." + ], + "name": "transferProtocolFeesForPools", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "erc20", + "type": "address" }, - "returns": { - "buyAmount": "Amount of the last token in the path bought." - } - }, - "sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)": { - "details": "Sells `sellAmount` of `inputToken` to the liquidity provider at the given `provider` address.", - "params": { - "auxiliaryData": "Auxiliary data supplied to the `provider` contract.", - "inputToken": "The token being sold.", - "minBuyAmount": "The minimum acceptable amount of `outputToken` to buy. Reverts if this amount is not satisfied.", - "outputToken": "The token being bought.", - "provider": "The address of the on-chain liquidity provider to trade with.", - "recipient": "The recipient of the bought tokens. If equal to address(0), `msg.sender` is assumed to be the recipient.", - "sellAmount": "The amount of `inputToken` to sell." + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" }, - "returns": { - "boughtAmount": "The amount of `outputToken` bought." + { + "internalType": "address payable", + "name": "recipientWallet", + "type": "address" } - }, - "sellToPancakeSwap(address[],uint256,uint256,uint8)": { - "details": "Efficiently sell directly to PancakeSwap (and forks).", - "params": { - "fork": "The protocol fork to use.", - "minBuyAmount": "Minimum amount of `tokens[-1]` to buy.", - "sellAmount": "of `tokens[0]` Amount to sell.", - "tokens": "Sell path." + ], + "name": "transferTrappedTokensTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20TokenV06", + "name": "inputToken", + "type": "address" }, - "returns": { - "buyAmount": "Amount of `tokens[-1]` bought." + { + "internalType": "contract IERC20TokenV06", + "name": "outputToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "inputTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minOutputTokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "deploymentNonce", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct ITransformERC20Feature.Transformation[]", + "name": "transformations", + "type": "tuple[]" } - }, - "sellToUniswap(address[],uint256,uint256,bool)": { - "details": "Efficiently sell directly to uniswap/sushiswap.", - "params": { - "isSushi": "Use sushiswap if true.", - "minBuyAmount": "Minimum amount of `tokens[-1]` to buy.", - "sellAmount": "of `tokens[0]` Amount to sell.", - "tokens": "Sell path." + ], + "name": "transformERC20", + "outputs": [ + { + "internalType": "uint256", + "name": "outputTokenAmount", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int256", + "name": "amount0Delta", + "type": "int256" }, - "returns": { - "buyAmount": "Amount of `tokens[-1]` bought." + { + "internalType": "int256", + "name": "amount1Delta", + "type": "int256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" } - }, - "sellTokenForEthToUniswapV3(bytes,uint256,uint256,address)": { - "details": "Sell a token for ETH directly against uniswap v3.", - "params": { - "encodedPath": "Uniswap-encoded path, where the last token is WETH.", - "minBuyAmount": "Minimum amount of ETH to buy.", - "recipient": "The recipient of the bought tokens. Can be zero for sender.", - "sellAmount": "amount of the first token in the path to sell." + ], + "name": "uniswapV3SwapCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC1155Token", + "name": "erc1155Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc1155TokenProperties", + "type": "tuple[]" + }, + { + "internalType": "uint128", + "name": "erc1155TokenAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNFTOrder.ERC1155Order", + "name": "order", + "type": "tuple" }, - "returns": { - "buyAmount": "Amount of ETH bought." + { + "internalType": "uint256", + "name": "erc1155TokenId", + "type": "uint256" } - }, - "sellTokenForTokenToUniswapV3(bytes,uint256,uint256,address)": { - "details": "Sell a token for another token directly against uniswap v3.", - "params": { - "encodedPath": "Uniswap-encoded path.", - "minBuyAmount": "Minimum amount of the last token in the path to buy.", - "recipient": "The recipient of the bought tokens. Can be zero for sender.", - "sellAmount": "amount of the first token in the path to sell." + ], + "name": "validateERC1155OrderProperties", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC1155Token", + "name": "erc1155Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc1155TokenProperties", + "type": "tuple[]" + }, + { + "internalType": "uint128", + "name": "erc1155TokenAmount", + "type": "uint128" + } + ], + "internalType": "struct LibNFTOrder.ERC1155Order", + "name": "order", + "type": "tuple" }, - "returns": { - "buyAmount": "Amount of the last token in the path bought." - } - }, - "setQuoteSigner(address)": { - "details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.", - "params": { - "quoteSigner": "The address of the new calldata signer." - } - }, - "setTransformerDeployer(address)": { - "details": "Replace the allowed deployer for transformers. Only callable by the owner.", - "params": { - "transformerDeployer": "The address of the new trusted deployer for transformers." + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" } - }, - "supportInterface(bytes4)": { - "details": "Indicates whether the 0x Exchange Proxy implements a particular ERC165 interface. This function should use at most 30,000 gas.", - "params": { - "interfaceId": "The interface identifier, as specified in ERC165." + ], + "name": "validateERC1155OrderSignature", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC721Token", + "name": "erc721Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc721TokenProperties", + "type": "tuple[]" + } + ], + "internalType": "struct LibNFTOrder.ERC721Order", + "name": "order", + "type": "tuple" }, - "returns": { - "isSupported": "Whether the given interface is supported by the 0x Exchange Proxy." - } - }, - "transferOwnership(address)": { - "details": "Transfers ownership of the contract to a new address.", - "params": { - "newOwner": "The address that will become the owner." - } - }, - "transferProtocolFeesForPools(bytes32[])": { - "details": "Transfers protocol fees from the `FeeCollector` pools into the staking contract.", - "params": { - "poolIds": "Staking pool IDs" - } - }, - "transferTrappedTokensTo(address,uint256,address)": { - "details": "calledFrom FundRecoveryFeature.transferTrappedTokensTo() This will be delegatecalled in the context of the Exchange Proxy instance being used.", - "params": { - "amountOut": "Amount of tokens to withdraw.", - "erc20": "ERC20 Token Address.", - "recipientWallet": "Recipient wallet address." + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" } - }, - "transformERC20(address,address,uint256,uint256,(uint32,bytes)[])": { - "details": "Executes a series of transformations to convert an ERC20 `inputToken` to an ERC20 `outputToken`.", - "params": { - "inputToken": "The token being provided by the sender. If `0xeee...`, ETH is implied and should be provided with the call.`", - "inputTokenAmount": "The amount of `inputToken` to take from the sender.", - "minOutputTokenAmount": "The minimum amount of `outputToken` the sender must receive for the entire transformation to succeed.", - "outputToken": "The token to be acquired by the sender. `0xeee...` implies ETH.", - "transformations": "The transformations to execute on the token balance(s) in sequence." + ], + "name": "validateERC721OrderProperties", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum LibNFTOrder.TradeDirection", + "name": "direction", + "type": "uint8" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "contract IERC20TokenV06", + "name": "erc20Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc20TokenAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "feeData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Fee[]", + "name": "fees", + "type": "tuple[]" + }, + { + "internalType": "contract IERC721Token", + "name": "erc721Token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IPropertyValidator", + "name": "propertyValidator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "propertyData", + "type": "bytes" + } + ], + "internalType": "struct LibNFTOrder.Property[]", + "name": "erc721TokenProperties", + "type": "tuple[]" + } + ], + "internalType": "struct LibNFTOrder.ERC721Order", + "name": "order", + "type": "tuple" }, - "returns": { - "outputTokenAmount": "The amount of `outputToken` received by the sender." - } - }, - "uniswapV3SwapCallback(int256,int256,bytes)": { - "details": "The UniswapV3 pool swap callback which pays the funds requested by the caller/pool to the pool. Can only be called by a valid UniswapV3 pool.", - "params": { - "amount0Delta": "Token0 amount owed.", - "amount1Delta": "Token1 amount owed.", - "data": "Arbitrary data forwarded from swap() caller. An ABI-encoded struct of: inputToken, outputToken, fee, payer" - } - }, - "validateERC1155OrderProperties((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),uint256)": { - "details": "If the given order is buying an ERC1155 asset, checks whether or not the given token ID satisfies the required properties specified in the order. If the order does not specify any properties, this function instead checks whether the given token ID matches the ID in the order. Reverts if any checks fail, or if the order is selling an ERC1155 asset.", - "params": { - "erc1155TokenId": "The ID of the ERC1155 asset.", - "order": "The ERC1155 order." - } - }, - "validateERC1155OrderSignature((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128),(uint8,uint8,bytes32,bytes32))": { - "details": "Checks whether the given signature is valid for the the given ERC1155 order. Reverts if not.", - "params": { - "order": "The ERC1155 order.", - "signature": "The signature to validate." - } - }, - "validateERC721OrderProperties((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),uint256)": { - "details": "If the given order is buying an ERC721 asset, checks whether or not the given token ID satisfies the required properties specified in the order. If the order does not specify any properties, this function instead checks whether the given token ID matches the ID in the order. Reverts if any checks fail, or if the order is selling an ERC721 asset.", - "params": { - "erc721TokenId": "The ID of the ERC721 asset.", - "order": "The ERC721 order." - } - }, - "validateERC721OrderSignature((uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[]),(uint8,uint8,bytes32,bytes32))": { - "details": "Checks whether the given signature is valid for the the given ERC721 order. Reverts if not.", - "params": { - "order": "The ERC721 order.", - "signature": "The signature to validate." + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct LibSignature.Signature", + "name": "signature", + "type": "tuple" } - } - }, - "version": 1 - } + ], + "name": "validateERC721OrderSignature", + "outputs": [], + "stateMutability": "view", + "type": "function" + } + ] } diff --git a/contracts/artifacts/LiquoriceSettlement.json b/contracts/artifacts/LiquoriceSettlement.json new file mode 100644 index 0000000000..a0c1e0a46f --- /dev/null +++ b/contracts/artifacts/LiquoriceSettlement.json @@ -0,0 +1,4193 @@ +{ + "abi": [ + { + "type": "constructor", + "inputs": [ + { + "name": "authenticator_", + "type": "address", + "internalType": "contract IAllowListAuthentication" + }, + { + "name": "repository_", + "type": "address", + "internalType": "contract IRepository" + }, + { + "name": "permit2_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "event", + "name": "Interaction", + "inputs": [ + { + "name": "target", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "selector", + "type": "bytes4", + "indexed": false, + "internalType": "bytes4" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TradeOrder", + "inputs": [ + { + "name": "rfqId", + "type": "string", + "indexed": true, + "internalType": "string" + }, + { + "name": "trader", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "baseToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "quoteToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "baseTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "quoteTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "ECDSAInvalidSignature", + "inputs": [] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureS", + "inputs": [ + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidAmount", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidBaseTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidDestination", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEIP1271Signature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEIP712Signature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidETHSignSignature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidFillAmount", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidHooksTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInteractionsBaseTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInteractionsQuoteTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidLendingPoolInteraction", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidQuoteTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSignatureType", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSigner", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSource", + "inputs": [] + }, + { + "type": "error", + "name": "NonceInvalid", + "inputs": [] + }, + { + "type": "error", + "name": "NotMaker", + "inputs": [] + }, + { + "type": "error", + "name": "NotSolver", + "inputs": [] + }, + { + "type": "error", + "name": "OrderExpired", + "inputs": [] + }, + { + "type": "error", + "name": "PartialFillNotSupported", + "inputs": [] + }, + { + "type": "error", + "name": "ReceiverNotManager", + "inputs": [] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "SafeERC20FailedOperation", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignatureIsExpired", + "inputs": [] + }, + { + "type": "error", + "name": "SignatureIsNotEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "UpdatedMakerAmountsTooLow", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroMakerAmount", + "inputs": [] + }, + { + "type": "function", + "name": "AUTHENTICATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IAllowListAuthentication" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "BALANCE_MANAGER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IBalanceManager" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hashSingleOrder", + "inputs": [ + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Single", + "components": [ + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "baseToken", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteToken", + "type": "address", + "internalType": "address" + }, + { + "name": "baseTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "_hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "settle", + "inputs": [ + { + "name": "_signer", + "type": "address", + "internalType": "address" + }, + { + "name": "_filledTakerAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Order", + "components": [ + { + "name": "market", + "type": "address", + "internalType": "address" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "baseTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRecipient", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRepay", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toSupply", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "quoteTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toTrader", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toBorrow", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + }, + { + "name": "_interactions", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_hooks", + "type": "tuple", + "internalType": "struct GPv2Interaction.Hooks", + "components": [ + { + "name": "beforeSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "afterSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "_makerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_takerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settleSingle", + "inputs": [ + { + "name": "_signer", + "type": "address", + "internalType": "address" + }, + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Single", + "components": [ + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "baseToken", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteToken", + "type": "address", + "internalType": "address" + }, + { + "name": "baseTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "_makerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_filledTakerAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_takerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "payable" + } + ], + "bytecode": { + "object": "0x61012060405234801562000011575f80fd5b5060405162004ef638038062004ef6833981016040819052620000349162000175565b4660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201526080810192909252309082015260c00160408051601f19818403018152908290528051602090910120608052600180556001600160a01b03841660c05230908290620000fe906200014f565b6001600160a01b03928316815291166020820152604001604051809103905ff0801580156200012f573d5f803e3d5ffd5b506001600160a01b0390811660e052919091166101005250620001c69050565b610963806200459383390190565b6001600160a01b038116811462000172575f80fd5b50565b5f805f6060848603121562000188575f80fd5b835162000195816200015d565b6020850151909350620001a8816200015d565b6040850151909250620001bb816200015d565b809150509250925092565b60805160a05160c05160e0516101005161432d620002665f395f81816102570152818161078401526116dc01525f8181610197015281816107ba0152818161188c01528181611e2c01528181611f1e0152818161202c0152818161230b01528181612427015261303c01525f818161033801528181610412015281816106a70152818161152001526115ff01525f6104da01525f6105a4015261432d5ff3fe608060405260043610610126575f3560e01c8063a5cdc8fc116100a1578063c618618111610071578063db58772811610057578063db58772814610379578063e242924e1461038c578063fa5cd56c146103ab575f80fd5b8063c618618114610327578063cba673a71461035a575f80fd5b8063a5cdc8fc146102ab578063a7ab49bc146102ca578063ae80c584146102e9578063b11f126214610308575f80fd5b806351d46815116100f65780636f35d2d2116100dc5780636f35d2d214610246578063875530ff146102795780639935c86814610298575f80fd5b806351d46815146102125780635aa0e95d14610227575f80fd5b80631626ba7e1461013157806329bcdc95146101865780633644e515146101d15780634c9e03d3146101f3575f80fd5b3661012d57005b5f80fd5b34801561013c575f80fd5b5061015061014b366004613595565b6103ca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610191575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161017d565b3480156101dc575f80fd5b506101e56104d7565b60405190815260200161017d565b3480156101fe575f80fd5b506101e561020d366004613620565b6105c6565b6102256102203660046136d7565b610667565b005b348015610232575f80fd5b506102256102413660046137e1565b6109e8565b348015610251575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610284575f80fd5b506101e5610293366004613620565b610c30565b6102256102a636600461383f565b610c5f565b3480156102b6575f80fd5b506102256102c53660046138dd565b610c7f565b3480156102d5575f80fd5b506102256102e4366004613901565b610c8c565b3480156102f4575f80fd5b5061022561030336600461399d565b611067565b348015610313575f80fd5b506101e56103223660046139f2565b6112eb565b348015610332575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610365575f80fd5b50610225610374366004613a24565b6114ea565b610225610387366004613b0b565b611878565b348015610397575f80fd5b506101e56103a6366004613bc9565b61194c565b3480156103b6575f80fd5b506102256103c5366004613bc9565b611a8e565b5f806103d7858585611b50565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063e75600c390602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190613bfb565b156104ab577f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150506104d0565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b9392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000046146105a157604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f7f68b8e94dc077458241d6c8d89f0a7665c7cda2cfe70c9eb4437efee1663c66fe6105f56020840184613c16565b836020013584604001358560600135866080013560405160200161064a969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b61066f611bdb565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa1580156106ec573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107109190613bfb565b610746576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610200870135881580159061076057506101608801358911155b1561077f5761077c896102008a01356101608b01356001611c1e565b90505b6107b07f00000000000000000000000000000000000000000000000000000000000000008b838b8b8b8b8b8b611c69565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66107ef60c08b0160a08c01613c16565b6108016101408c016101208d01613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108449291906101608e0135908890600401613c8d565b5f604051808303815f87803b15801561085b575f80fd5b505af115801561086d573d5f803e3d5ffd5b505050506108b4888b838c5f148061088957506101608c01358d115b610893578c61089a565b6101608c01355b898c8c60026108af60408e0160208f01613d61565b611e01565b6108c16040890189613d7f565b6040516108cf929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661090960a08b0160808c01613c16565b61091960c08c0160a08d01613c16565b61092b6101408d016101208e01613c16565b61093d6101e08e016101c08f01613c16565b8e158061094e57506101608e01358f115b610958578e61095f565b6101408e01355b6102008f013588146109715787610978565b6101e08f01355b8f60e001602081019061098b9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a2506109dd60018055565b505050505050505050565b5f5b6109f48280613def565b9050811015610b065736610a088380613def565b83818110610a1857610a18613e53565b9050602002810190610a2a9190613e80565b90506001600160a01b03841663a8c4bc95610a486020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610aa2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac69190613bfb565b15610afd576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016109ea565b505f5b610b166020830183613def565b9050811015610c2b5736610b2d6020840184613def565b83818110610b3d57610b3d613e53565b9050602002810190610b4f9190613e80565b90506001600160a01b03841663a8c4bc95610b6d6020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610bc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610beb9190613bfb565b15610c22576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101610b09565b505050565b5f7fae676bf6913ac2689b7331293c989fe7723124faf8b5d275f06fbcebc77950096105f56020840184613c16565b610c698482612212565b610c78858585856001806122c9565b5050505050565b610c89338261261e565b50565b610cbf6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f5b828110156110535736848483818110610cdc57610cdc613e53565b9050602002810190610cee9190613e80565b9050365f610cff6040840184613d7f565b90925090506001600160a01b038b1663a8c4bc95610d206020860186613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9e9190613bfb565b15611045575f8915610ddc576040517f7d617bb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048210610de8575081355b7fc03a9de9000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610e5657610e3d83838d8c6126c4565b86602001818151610e4e9190613ebc565b905250611043565b7f243a4b7f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610ebc57610eab83838d8c6127da565b86606001818151610e4e9190613ebc565b7f7dc4f458000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f4757610f1183838d8c61294e565b60a088015260808701819052606087018051610f2e908390613ebc565b90525060a0860151602087018051610e4e908390613ebc565b7f68931b6b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610fab57610f9c83838d8c612bb6565b86518790610e4e908390613ebc565b7f0c9be7e4000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016110115761100083838d8c612cc0565b86604001818151610e4e9190613ebc565b6040517f0561d8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050806001019050610cc1565b5061105e8482612e29565b50505050505050565b60036110766020830183613f21565b600381111561108757611087613ef4565b036110ec576001600160a01b0383166110ac836110a76040850185613d7f565b611b50565b6001600160a01b031614610c2b576040517fb81d58e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016110fb6020830183613f21565b600381111561110c5761110c613ef4565b036111a0577f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c839052603c90206001600160a01b03841661115a826110a76040860186613d7f565b6001600160a01b03161461119a576040517f644ae6c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60026111af6020830183613f21565b60038111156111c0576111c0613ef4565b036112b9577f1626ba7e000000000000000000000000000000000000000000000000000000006001600160a01b038416631626ba7e846112036040860186613d7f565b6040518463ffffffff1660e01b815260040161122193929190613f3f565b602060405180830381865afa15801561123c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112609190613f58565b7fffffffff000000000000000000000000000000000000000000000000000000001614610c2b576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f60cd402d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112f46104d7565b7fd28e809b708f5ee38be8347d6d869d8232493c094ab2dde98369e4102369a99d61131f8480613d7f565b604051602001611330929190613f97565b60405160208183030381529060405280519060200120846020013585604001602081019061135e9190613c16565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526113c46080850160608601613c16565b6113d460a0860160808701613c16565b6113e460c0870160a08801613c16565b60c087013560e08801356101008901356101208a013561140c6101608c016101408d01613c16565b604080516001600160a01b03998a166020820152978916908801529487166060870152608086019390935260a085019190915260c084015260e083015290911661010082015261012001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526114929291602001613fd7565b6040516020818303038152906040528051906020012060405160200161064a9291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6114f2611bdb565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906302cc250d90602401602060405180830381865afa15801561156d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115919190613bfb565b6115c7576040517fc139eabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa158015611644573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116689190613bfb565b61169e576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61020086013587158015906116b857506101608701358811155b156116d7576116d4886102008901356101608a01356001611c1e565b90505b6117087f00000000000000000000000000000000000000000000000000000000000000008a838a8a8a8a8a8a611c69565b611745878a838b158061171f57506101608b01358c115b611729578b611730565b6101608b01355b888b8b60016108af60408d0160208e01613d61565b6117526040880188613d7f565b604051611760929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661179a60a08a0160808b01613c16565b6117aa60c08b0160a08c01613c16565b6117bc6101408c016101208d01613c16565b6117ce6101e08d016101c08e01613c16565b8d15806117df57506101608d01358e115b6117e9578d6117f0565b6101408d01355b6102008e013588146118025787611809565b6101e08e01355b8e60e001602081019061181c9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a25061186e60018055565b5050505050505050565b6118828583612212565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66118c16080880160608901613c16565b6118d160a0890160808a01613c16565b8860c00135856040518563ffffffff1660e01b81526004016118f69493929190613c8d565b5f604051808303815f87803b15801561190d575f80fd5b505af115801561191f573d5f803e3d5ffd5b5050505061194486868686600289602001602081019061193f9190613d61565b6122c9565b505050505050565b5f6119556104d7565b7fc994d2ca0375d6d473785e0ce0b1d203f069121bac1314f72c5c0fe601eb39106119836040850185613d7f565b604051602001611994929190613f97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060608501356119df60a0870160808801613c16565b6119ef60c0880160a08901613c16565b60c0880135611a056101008a0160e08b01613c16565b60408051602081019890985287019590955260608601939093526001600160a01b039182166080860152811660a085015260c08401919091521660e0820152610100808501359082015261012001604051602081830303815290604052611a6f8461012001610c30565b611a7c856101c0016105c6565b60405160200161149293929190613feb565b6101a0810135611aa8610180830135610160840135613ebc565b611ab29190613ebc565b61014082013514611aef576040517fc04377d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610240810135611b09610220830135610200840135613ebc565b611b139190613ebc565b6101e082013514610c89576040517f877630be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ed692505050565b90506001600160a01b038116611bd3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b600260015403611c17576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600155565b5f611c4b611c2b83612f00565b8015611c4657505f8480611c4157611c41614008565b868809115b151590565b611c56868686612f2c565b611c609190613ebc565b95945050505050565b5f611c738761194c565b9050611c80898285611067565b611c9060c0880160a08901613c16565b6001600160a01b0316336001600160a01b031614611cc757611cc2611cbb60c0890160a08a01613c16565b8284611067565b611d0e565b611cd46040830183613d7f565b90505f03611d0e576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d2b611d2160c0890160a08a01613c16565b886060013561261e565b8660c00135421115611d69576040517f133df02900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f88118015611d7c575086610100013588105b15611db3576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dbc87611a8e565b611dc68a856109e8565b611de78a8a5f8b118015611ddf57506102008a01358b14155b8a8a8a610c8c565b611df589886060013561261e565b50505050505050505050565b611e13611e0e8680613def565b613001565b5f611e286101808b01356101a08c0135613ebc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611e779190613c16565b6001600160a01b03168152602001306001600160a01b031681526020018d610120015f016020810190611eaa9190613c16565b6001600160a01b03168152602001848152602001866002811115611ed057611ed0613ef4565b8152506040518263ffffffff1660e01b8152600401611eef9190614035565b5f604051808303815f87803b158015611f06575f80fd5b505af1158015611f18573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611f699190613c16565b6001600160a01b031681526020018d60e0016020810190611f8a9190613c16565b6001600160a01b031681526020018d610120015f016020810190611fae9190613c16565b6001600160a01b031681526020018a8152602001866002811115611fd457611fd4613ef4565b8152506040518263ffffffff1660e01b8152600401611ff39190614035565b5f604051808303815f87803b15801561200a575f80fd5b505af115801561201c573d5f803e3d5ffd5b5050505061202a8585613001565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808c6001600160a01b031681526020018d60800160208101906120869190613c16565b6001600160a01b031681526020018d6101c0015f0160208101906120aa9190613c16565b6001600160a01b031681526020018b81526020018560028111156120d0576120d0613ef4565b8152506040518263ffffffff1660e01b81526004016120ef9190614035565b5f604051808303815f87803b158015612106575f80fd5b505af1158015612118573d5f803e3d5ffd5b5061212e9250611e0e9150506020880188613def565b5f6121416101408c016101208d01613c16565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561219e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c291906140b4565b90508015612205576122056121de6101008d0160e08e01613c16565b828d610120015f0160208101906121f59190613c16565b6001600160a01b03169190613139565b5050505050505050505050565b6122226080830160608401613c16565b6001600160a01b0316336001600160a01b0316146122615761225c61224d6080840160608501613c16565b612256846112eb565b83611067565b6122a8565b61226e6040820182613d7f565b90505f036122a8576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122c56122bb6080840160608501613c16565b836020013561261e565b5050565b60e085013583158015906122e057508560c0013584105b156122fd576122fa848760e001358860c001356001611c1e565b90505b612309878288886131b9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808960600160208101906123569190613c16565b6001600160a01b031681526020016123766101608b016101408c01613c16565b6001600160a01b0316815260200161239460a08b0160808c01613c16565b6001600160a01b031681526020018715806123b257508960c0013588115b6123bc57876123c2565b8960c001355b81526020018660028111156123d9576123d9613ef4565b8152506040518263ffffffff1660e01b81526004016123f89190614035565b5f604051808303815f87803b15801561240f575f80fd5b505af1158015612421573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808a6001600160a01b031681526020018960400160208101906124819190613c16565b6001600160a01b0316815260200161249f60c08b0160a08c01613c16565b6001600160a01b031681526020018481526020018560028111156124c5576124c5613ef4565b8152506040518263ffffffff1660e01b81526004016124e49190614035565b5f604051808303815f87803b1580156124fb575f80fd5b505af115801561250d573d5f803e3d5ffd5b5061251e9250889150819050613d7f565b60405161252c929190613de0565b60405180910390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b68760400160208101906125689190613c16565b61257860808a0160608b01613c16565b61258860a08b0160808c01613c16565b61259860c08c0160a08d01613c16565b8915806125a857508b60c001358a115b6125b257896125b8565b8b60c001355b878d6101400160208101906125cd9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a250505050505050565b6001600160a01b0382165f9081526020818152604080832084845290915290205460ff1615612679576040517fbc0da7d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b039091165f908152602081815260408083209383529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f8080806126d5876004818b6140cb565b8101906126e291906140f2565b50919450925090506126fc61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612746576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612791576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b979650505050505050565b5f808080806127ec886004818c6140cb565b8101906127f99190614142565b929650909450925090506128156101e087016101c08801613c16565b6001600160a01b0316846001600160a01b03161461285f576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b0316146128aa576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128ba60a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612904576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b98975050505050505050565b5f805f805f805f805f8c8c600490809261296a939291906140cb565b8101906129779190614190565b959c50939a50919850965094509250905061299a6101e08b016101c08c01613c16565b6001600160a01b0316876001600160a01b0316146129e4576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856001600160a01b03168b6001600160a01b031614612a2f576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385163014612a71576040517f8154374b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612a8160a08b0160808c01613c16565b6001600160a01b0316846001600160a01b031614612acb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408a01358314612b09576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b1b6101408b016101208c01613c16565b6001600160a01b0316826001600160a01b031614612b65576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a08a01358114612ba3576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919c919b50909950505050505050505050565b5f808080612bc7876004818b6140cb565b810190612bd4919061420f565b91945092509050612bed61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612c37576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612c82576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61018085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808080612cd2886004818c6140cb565b810190612cdf919061424d565b5092965090945092509050612cfc6101e087016101c08801613c16565b6001600160a01b0316846001600160a01b031614612d46576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614612d91576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612da160a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612deb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102208601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051610180830135141580612e47575060208101516101a083013514155b15612e7e576040517f4a55da2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610220830135141580612e9f5750606081015161024083013514155b156122c5576040517f77a5920300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f80612ee4868661325c565b925092509250612ef482826132a5565b50909150505b92915050565b5f6002826003811115612f1557612f15613ef4565b612f1f91906142b1565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03612f7f57838281612f7557612f75614008565b04925050506104d0565b808411612f9657612f9660038515026011186133ad565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f5b81811015610c2b573683838381811061301e5761301e613e53565b90506020028101906130309190613e80565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130696020830183613c16565b6001600160a01b0316036130a9576040517f79a1bff000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130b2816133be565b6130bf6020820182613c16565b6001600160a01b03167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356130f784613401565b604080519283527fffffffff0000000000000000000000000000000000000000000000000000000090911660208301520160405180910390a250600101613003565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610c2b90849061342a565b5f831180156131cc575081610100013583105b15613203576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61321084612256846112eb565b61321e84836020013561261e565b428261012001351161119a576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f8351604103613293576020840151604085015160608601515f1a613285888285856134af565b95509550955050505061329e565b505081515f91506002905b9250925092565b5f8260038111156132b8576132b8613ef4565b036132c1575050565b60018260038111156132d5576132d5613ef4565b0361330c576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561332057613320613ef4565b0361335f576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600382600381111561337357613373613ef4565b036122c5576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401613356565b634e487b715f52806020526024601cfd5b5f6133cc6020830183613c16565b90506020820135365f6133e26040860186613d7f565b91509150604051818382375f80838387895af1611944573d5f803e3d5ffd5b5f36816134116040850185613d7f565b90925090506004811061342357813592505b5050919050565b5f8060205f8451602086015f885af180613449576040513d5f823e3d81fd5b50505f513d9150811561346057806001141561346d565b6001600160a01b0384163b155b1561119a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613356565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156134e857505f9150600390508261358b565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613539573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811661358257505f92506001915082905061358b565b92505f91508190505b9450945094915050565b5f805f604084860312156135a7575f80fd5b83359250602084013567ffffffffffffffff808211156135c5575f80fd5b818601915086601f8301126135d8575f80fd5b8135818111156135e6575f80fd5b8760208285010111156135f7575f80fd5b6020830194508093505050509250925092565b5f60a0828403121561361a575f80fd5b50919050565b5f60a08284031215613630575f80fd5b6104d0838361360a565b6001600160a01b0381168114610c89575f80fd5b80356136598161363a565b919050565b5f610260828403121561361a575f80fd5b5f8083601f84011261367f575f80fd5b50813567ffffffffffffffff811115613696575f80fd5b6020830191508360208260051b85010111156136b0575f80fd5b9250929050565b5f6040828403121561361a575f80fd5b5f6060828403121561361a575f80fd5b5f805f805f805f805f6101008a8c0312156136f0575f80fd5b6136f98a61364e565b985060208a0135975060408a013567ffffffffffffffff8082111561371c575f80fd5b6137288d838e0161365e565b985060608c013591508082111561373d575f80fd5b6137498d838e0161366f565b909850965060808c0135915080821115613761575f80fd5b61376d8d838e016136b7565b955060a08c0135915080821115613782575f80fd5b61378e8d838e016136c7565b945060c08c01359150808211156137a3575f80fd5b6137af8d838e016136c7565b935060e08c01359150808211156137c4575f80fd5b506137d18c828d016136c7565b9150509295985092959850929598565b5f80604083850312156137f2575f80fd5b82356137fd8161363a565b9150602083013567ffffffffffffffff811115613818575f80fd5b613824858286016136b7565b9150509250929050565b5f610160828403121561361a575f80fd5b5f805f805f60a08688031215613853575f80fd5b853561385e8161363a565b9450602086013567ffffffffffffffff8082111561387a575f80fd5b61388689838a0161382e565b9550604088013591508082111561389b575f80fd5b6138a789838a016136c7565b94506060880135935060808801359150808211156138c3575f80fd5b506138d0888289016136c7565b9150509295509295909350565b5f602082840312156138ed575f80fd5b5035919050565b8015158114610c89575f80fd5b5f805f805f8060a08789031215613916575f80fd5b86356139218161363a565b955060208701356139318161363a565b94506040870135613941816138f4565b9350606087013567ffffffffffffffff8082111561395d575f80fd5b6139698a838b0161365e565b9450608089013591508082111561397e575f80fd5b5061398b89828a0161366f565b979a9699509497509295939492505050565b5f805f606084860312156139af575f80fd5b83356139ba8161363a565b925060208401359150604084013567ffffffffffffffff8111156139dc575f80fd5b6139e8868287016136c7565b9150509250925092565b5f60208284031215613a02575f80fd5b813567ffffffffffffffff811115613a18575f80fd5b611bd38482850161382e565b5f805f805f805f8060e0898b031215613a3b575f80fd5b613a448961364e565b975060208901359650604089013567ffffffffffffffff80821115613a67575f80fd5b613a738c838d0161365e565b975060608b0135915080821115613a88575f80fd5b613a948c838d0161366f565b909750955060808b0135915080821115613aac575f80fd5b613ab88c838d016136b7565b945060a08b0135915080821115613acd575f80fd5b613ad98c838d016136c7565b935060c08b0135915080821115613aee575f80fd5b50613afb8b828c016136c7565b9150509295985092959890939650565b5f805f805f8060c08789031215613b20575f80fd5b613b298761364e565b9550602087013567ffffffffffffffff80821115613b45575f80fd5b613b518a838b0161382e565b96506040890135915080821115613b66575f80fd5b613b728a838b016136c7565b9550606089013594506080890135915080821115613b8e575f80fd5b613b9a8a838b016136c7565b935060a0890135915080821115613baf575f80fd5b50613bbc89828a016136c7565b9150509295509295509295565b5f60208284031215613bd9575f80fd5b813567ffffffffffffffff811115613bef575f80fd5b611bd38482850161365e565b5f60208284031215613c0b575f80fd5b81516104d0816138f4565b5f60208284031215613c26575f80fd5b81356104d08161363a565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b803565ffffffffffff81168114613659575f80fd5b5f6001600160a01b0380871683528086166020840152508360408301526080606083015282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ce2575f80fd5b830160208101903567ffffffffffffffff811115613cfe575f80fd5b803603821315613d0c575f80fd5b60606080850152613d2160e085018284613c31565b915050613d3060208501613c78565b65ffffffffffff80821660a086015280613d4c60408801613c78565b1660c086015250508091505095945050505050565b5f60208284031215613d71575f80fd5b8135600381106104d0575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db2575f80fd5b83018035915067ffffffffffffffff821115613dcc575f80fd5b6020019150368190038213156136b0575f80fd5b818382375f9101908152919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e22575f80fd5b83018035915067ffffffffffffffff821115613e3c575f80fd5b6020019150600581901b36038213156136b0575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112613eb2575f80fd5b9190910192915050565b80820180821115612efa577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613f31575f80fd5b8135600481106104d0575f80fd5b838152604060208201525f611c60604083018486613c31565b5f60208284031215613f68575f80fd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146104d0575f80fd5b602081525f611bd3602083018486613c31565b5f81515f5b81811015613fc95760208185018101518683015201613faf565b505f93019283525090919050565b5f611bd3613fe58386613faa565b84613faa565b5f613ff68286613faa565b93845250506020820152604001919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60a0820190506001600160a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151600381106140a7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8060808401525092915050565b5f602082840312156140c4575f80fd5b5051919050565b5f80858511156140d9575f80fd5b838611156140e5575f80fd5b5050820193919092039150565b5f805f8060808587031215614105575f80fd5b84356141108161363a565b935060208501356141208161363a565b9250604085013591506060850135614137816138f4565b939692955090935050565b5f805f8060808587031215614155575f80fd5b84356141608161363a565b935060208501356141708161363a565b925060408501356141808161363a565b9396929550929360600135925050565b5f805f805f805f60e0888a0312156141a6575f80fd5b87356141b18161363a565b965060208801356141c18161363a565b955060408801356141d18161363a565b945060608801356141e18161363a565b93506080880135925060a08801356141f88161363a565b8092505060c0880135905092959891949750929550565b5f805f60608486031215614221575f80fd5b833561422c8161363a565b9250602084013561423c8161363a565b929592945050506040919091013590565b5f805f805f60a08688031215614261575f80fd5b853561426c8161363a565b9450602086013561427c8161363a565b9350604086013561428c8161363a565b92506060860135915060808601356142a3816138f4565b809150509295509295909350565b5f60ff8316806142e8577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff8416069150509291505056fea26469706673582212209be58acada353061a2a202cc7011f3c91393e0f2e305e9202445b042fc4a4ce664736f6c6343000817003360c060405234801561000f575f80fd5b5060405161096338038061096383398101604081905261002e91610060565b6001600160a01b039182166080521660a052610091565b80516001600160a01b038116811461005b575f80fd5b919050565b5f8060408385031215610071575f80fd5b61007a83610045565b915061008860208401610045565b90509250929050565b60805160a05161089e6100c55f395f81816048015281816101f2015261038101525f818160d30152610327015261089e5ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c80636afdd85014610043578063b519d36914610093578063bc1178e6146100a8575b5f80fd5b61006a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100a66100a136600461060a565b6100bb565b005b6100a66100b6366004610648565b61030f565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016811461012b576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820135156101af57600161014760a08401608085016106dd565b6002811115610158576101586106b0565b036101b3576101af61016d6020840184610702565b61017d6040850160208601610702565b606085018035906101919060408801610702565b73ffffffffffffffffffffffffffffffffffffffff169291906104cc565b5050565b60026101c560a08401608085016106dd565b60028111156101d6576101d66106b0565b036102dd5773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166336c785166102246020850185610702565b6102346040860160208701610702565b606086018035906102489060408901610702565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152908316604483015290911660648201526084015f604051808303815f87803b1580156102c3575f80fd5b505af11580156102d5573d5f803e3d5ffd5b505050505050565b6040517fc79aaa4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016811461037f576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632b67b57086604051806060016040528060405180608001604052808a73ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff16815260200188604001602081019061041d919061071b565b65ffffffffffff16815260200188602001602081019061043d919061071b565b65ffffffffffff1690528152306020820152604090810190610465906060890190890161071b565b65ffffffffffff1690526104798680610740565b6040518563ffffffff1660e01b815260040161049894939291906107a8565b5f604051808303815f87803b1580156104af575f80fd5b505af11580156104c1573d5f803e3d5ffd5b505050505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610561908590610567565b50505050565b5f8060205f8451602086015f885af180610586576040513d5f823e3d81fd5b50505f513d9150811561059d5780600114156105b7565b73ffffffffffffffffffffffffffffffffffffffff84163b155b15610561576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240160405180910390fd5b5f60a0828403121561061a575f80fd5b50919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610643575f80fd5b919050565b5f805f806080858703121561065b575f80fd5b61066485610620565b935061067260208601610620565b925060408501359150606085013567ffffffffffffffff811115610694575f80fd5b8501606081880312156106a5575f80fd5b939692955090935050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f602082840312156106ed575f80fd5b8135600381106106fb575f80fd5b9392505050565b5f60208284031215610712575f80fd5b6106fb82610620565b5f6020828403121561072b575f80fd5b813565ffffffffffff811681146106fb575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610773575f80fd5b83018035915067ffffffffffffffff82111561078d575f80fd5b6020019150368190038213156107a1575f80fd5b9250929050565b5f61010073ffffffffffffffffffffffffffffffffffffffff80881684528651818151166020860152816020820151166040860152604081015165ffffffffffff80821660608801528060608401511660808801525050508060208801511660a085015250604086015160c08401528060e08401528381840152506101208385828501375f838501820152601f9093017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910190910194935050505056fea2646970667358221220f3565f6589500276fcbb6fb33d3ee3b534d9566c5b2732fe10a6039b753c3a0764736f6c63430008170033", + "sourceMap": "975:10890:90:-:0;;;2483:234;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3749:13:91;3730:32;;;;3811:93;;;1026:66;3811:93;;;1092:25:169;879:32:91;1133:18:169;;;1126:34;;;;957:14:91;1176:18:169;;;1169:34;1219:18;;;1212:34;;;;3898:4:91;1262:19:169;;;1255:61;1064:19;;3811:93:91;;;-1:-1:-1;;3811:93:91;;;;;;;;;;3801:104;;3811:93;3801:104;;;;3768:137;;1857:1:44;2061:21;;-1:-1:-1;;;;;2585:30:90;;;;2666:4;;2673:8;;2639:43;;;:::i;:::-;-1:-1:-1;;;;;1557:15:169;;;1539:34;;1609:15;;1604:2;1589:18;;1582:43;1489:2;1474:18;2639:43:90;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2621:61:90;;;;;2688:24;;;;;;-1:-1:-1;975:10890:90;;-1:-1:-1;975:10890:90;;;;;;;;;:::o;14:157:169:-;-1:-1:-1;;;;;115:31:169;;105:42;;95:70;;161:1;158;151:12;95:70;14:157;:::o;176:652::-;319:6;327;335;388:2;376:9;367:7;363:23;359:32;356:52;;;404:1;401;394:12;356:52;436:9;430:16;455:57;506:5;455:57;:::i;:::-;581:2;566:18;;560:25;531:5;;-1:-1:-1;594:59:169;560:25;594:59;:::i;:::-;724:2;709:18;;703:25;672:7;;-1:-1:-1;737:59:169;703:25;737:59;:::i;:::-;815:7;805:17;;;176:652;;;;;:::o;1327:304::-;975:10890:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405260043610610126575f3560e01c8063a5cdc8fc116100a1578063c618618111610071578063db58772811610057578063db58772814610379578063e242924e1461038c578063fa5cd56c146103ab575f80fd5b8063c618618114610327578063cba673a71461035a575f80fd5b8063a5cdc8fc146102ab578063a7ab49bc146102ca578063ae80c584146102e9578063b11f126214610308575f80fd5b806351d46815116100f65780636f35d2d2116100dc5780636f35d2d214610246578063875530ff146102795780639935c86814610298575f80fd5b806351d46815146102125780635aa0e95d14610227575f80fd5b80631626ba7e1461013157806329bcdc95146101865780633644e515146101d15780634c9e03d3146101f3575f80fd5b3661012d57005b5f80fd5b34801561013c575f80fd5b5061015061014b366004613595565b6103ca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610191575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161017d565b3480156101dc575f80fd5b506101e56104d7565b60405190815260200161017d565b3480156101fe575f80fd5b506101e561020d366004613620565b6105c6565b6102256102203660046136d7565b610667565b005b348015610232575f80fd5b506102256102413660046137e1565b6109e8565b348015610251575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610284575f80fd5b506101e5610293366004613620565b610c30565b6102256102a636600461383f565b610c5f565b3480156102b6575f80fd5b506102256102c53660046138dd565b610c7f565b3480156102d5575f80fd5b506102256102e4366004613901565b610c8c565b3480156102f4575f80fd5b5061022561030336600461399d565b611067565b348015610313575f80fd5b506101e56103223660046139f2565b6112eb565b348015610332575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610365575f80fd5b50610225610374366004613a24565b6114ea565b610225610387366004613b0b565b611878565b348015610397575f80fd5b506101e56103a6366004613bc9565b61194c565b3480156103b6575f80fd5b506102256103c5366004613bc9565b611a8e565b5f806103d7858585611b50565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063e75600c390602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190613bfb565b156104ab577f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150506104d0565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b9392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000046146105a157604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f7f68b8e94dc077458241d6c8d89f0a7665c7cda2cfe70c9eb4437efee1663c66fe6105f56020840184613c16565b836020013584604001358560600135866080013560405160200161064a969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b61066f611bdb565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa1580156106ec573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107109190613bfb565b610746576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610200870135881580159061076057506101608801358911155b1561077f5761077c896102008a01356101608b01356001611c1e565b90505b6107b07f00000000000000000000000000000000000000000000000000000000000000008b838b8b8b8b8b8b611c69565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66107ef60c08b0160a08c01613c16565b6108016101408c016101208d01613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108449291906101608e0135908890600401613c8d565b5f604051808303815f87803b15801561085b575f80fd5b505af115801561086d573d5f803e3d5ffd5b505050506108b4888b838c5f148061088957506101608c01358d115b610893578c61089a565b6101608c01355b898c8c60026108af60408e0160208f01613d61565b611e01565b6108c16040890189613d7f565b6040516108cf929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661090960a08b0160808c01613c16565b61091960c08c0160a08d01613c16565b61092b6101408d016101208e01613c16565b61093d6101e08e016101c08f01613c16565b8e158061094e57506101608e01358f115b610958578e61095f565b6101408e01355b6102008f013588146109715787610978565b6101e08f01355b8f60e001602081019061098b9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a2506109dd60018055565b505050505050505050565b5f5b6109f48280613def565b9050811015610b065736610a088380613def565b83818110610a1857610a18613e53565b9050602002810190610a2a9190613e80565b90506001600160a01b03841663a8c4bc95610a486020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610aa2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac69190613bfb565b15610afd576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016109ea565b505f5b610b166020830183613def565b9050811015610c2b5736610b2d6020840184613def565b83818110610b3d57610b3d613e53565b9050602002810190610b4f9190613e80565b90506001600160a01b03841663a8c4bc95610b6d6020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610bc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610beb9190613bfb565b15610c22576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101610b09565b505050565b5f7fae676bf6913ac2689b7331293c989fe7723124faf8b5d275f06fbcebc77950096105f56020840184613c16565b610c698482612212565b610c78858585856001806122c9565b5050505050565b610c89338261261e565b50565b610cbf6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f5b828110156110535736848483818110610cdc57610cdc613e53565b9050602002810190610cee9190613e80565b9050365f610cff6040840184613d7f565b90925090506001600160a01b038b1663a8c4bc95610d206020860186613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9e9190613bfb565b15611045575f8915610ddc576040517f7d617bb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048210610de8575081355b7fc03a9de9000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610e5657610e3d83838d8c6126c4565b86602001818151610e4e9190613ebc565b905250611043565b7f243a4b7f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610ebc57610eab83838d8c6127da565b86606001818151610e4e9190613ebc565b7f7dc4f458000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f4757610f1183838d8c61294e565b60a088015260808701819052606087018051610f2e908390613ebc565b90525060a0860151602087018051610e4e908390613ebc565b7f68931b6b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610fab57610f9c83838d8c612bb6565b86518790610e4e908390613ebc565b7f0c9be7e4000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016110115761100083838d8c612cc0565b86604001818151610e4e9190613ebc565b6040517f0561d8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050806001019050610cc1565b5061105e8482612e29565b50505050505050565b60036110766020830183613f21565b600381111561108757611087613ef4565b036110ec576001600160a01b0383166110ac836110a76040850185613d7f565b611b50565b6001600160a01b031614610c2b576040517fb81d58e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016110fb6020830183613f21565b600381111561110c5761110c613ef4565b036111a0577f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c839052603c90206001600160a01b03841661115a826110a76040860186613d7f565b6001600160a01b03161461119a576040517f644ae6c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60026111af6020830183613f21565b60038111156111c0576111c0613ef4565b036112b9577f1626ba7e000000000000000000000000000000000000000000000000000000006001600160a01b038416631626ba7e846112036040860186613d7f565b6040518463ffffffff1660e01b815260040161122193929190613f3f565b602060405180830381865afa15801561123c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112609190613f58565b7fffffffff000000000000000000000000000000000000000000000000000000001614610c2b576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f60cd402d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112f46104d7565b7fd28e809b708f5ee38be8347d6d869d8232493c094ab2dde98369e4102369a99d61131f8480613d7f565b604051602001611330929190613f97565b60405160208183030381529060405280519060200120846020013585604001602081019061135e9190613c16565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526113c46080850160608601613c16565b6113d460a0860160808701613c16565b6113e460c0870160a08801613c16565b60c087013560e08801356101008901356101208a013561140c6101608c016101408d01613c16565b604080516001600160a01b03998a166020820152978916908801529487166060870152608086019390935260a085019190915260c084015260e083015290911661010082015261012001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526114929291602001613fd7565b6040516020818303038152906040528051906020012060405160200161064a9291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6114f2611bdb565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906302cc250d90602401602060405180830381865afa15801561156d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115919190613bfb565b6115c7576040517fc139eabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa158015611644573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116689190613bfb565b61169e576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61020086013587158015906116b857506101608701358811155b156116d7576116d4886102008901356101608a01356001611c1e565b90505b6117087f00000000000000000000000000000000000000000000000000000000000000008a838a8a8a8a8a8a611c69565b611745878a838b158061171f57506101608b01358c115b611729578b611730565b6101608b01355b888b8b60016108af60408d0160208e01613d61565b6117526040880188613d7f565b604051611760929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661179a60a08a0160808b01613c16565b6117aa60c08b0160a08c01613c16565b6117bc6101408c016101208d01613c16565b6117ce6101e08d016101c08e01613c16565b8d15806117df57506101608d01358e115b6117e9578d6117f0565b6101408d01355b6102008e013588146118025787611809565b6101e08e01355b8e60e001602081019061181c9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a25061186e60018055565b5050505050505050565b6118828583612212565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66118c16080880160608901613c16565b6118d160a0890160808a01613c16565b8860c00135856040518563ffffffff1660e01b81526004016118f69493929190613c8d565b5f604051808303815f87803b15801561190d575f80fd5b505af115801561191f573d5f803e3d5ffd5b5050505061194486868686600289602001602081019061193f9190613d61565b6122c9565b505050505050565b5f6119556104d7565b7fc994d2ca0375d6d473785e0ce0b1d203f069121bac1314f72c5c0fe601eb39106119836040850185613d7f565b604051602001611994929190613f97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060608501356119df60a0870160808801613c16565b6119ef60c0880160a08901613c16565b60c0880135611a056101008a0160e08b01613c16565b60408051602081019890985287019590955260608601939093526001600160a01b039182166080860152811660a085015260c08401919091521660e0820152610100808501359082015261012001604051602081830303815290604052611a6f8461012001610c30565b611a7c856101c0016105c6565b60405160200161149293929190613feb565b6101a0810135611aa8610180830135610160840135613ebc565b611ab29190613ebc565b61014082013514611aef576040517fc04377d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610240810135611b09610220830135610200840135613ebc565b611b139190613ebc565b6101e082013514610c89576040517f877630be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ed692505050565b90506001600160a01b038116611bd3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b600260015403611c17576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600155565b5f611c4b611c2b83612f00565b8015611c4657505f8480611c4157611c41614008565b868809115b151590565b611c56868686612f2c565b611c609190613ebc565b95945050505050565b5f611c738761194c565b9050611c80898285611067565b611c9060c0880160a08901613c16565b6001600160a01b0316336001600160a01b031614611cc757611cc2611cbb60c0890160a08a01613c16565b8284611067565b611d0e565b611cd46040830183613d7f565b90505f03611d0e576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d2b611d2160c0890160a08a01613c16565b886060013561261e565b8660c00135421115611d69576040517f133df02900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f88118015611d7c575086610100013588105b15611db3576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dbc87611a8e565b611dc68a856109e8565b611de78a8a5f8b118015611ddf57506102008a01358b14155b8a8a8a610c8c565b611df589886060013561261e565b50505050505050505050565b611e13611e0e8680613def565b613001565b5f611e286101808b01356101a08c0135613ebc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611e779190613c16565b6001600160a01b03168152602001306001600160a01b031681526020018d610120015f016020810190611eaa9190613c16565b6001600160a01b03168152602001848152602001866002811115611ed057611ed0613ef4565b8152506040518263ffffffff1660e01b8152600401611eef9190614035565b5f604051808303815f87803b158015611f06575f80fd5b505af1158015611f18573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611f699190613c16565b6001600160a01b031681526020018d60e0016020810190611f8a9190613c16565b6001600160a01b031681526020018d610120015f016020810190611fae9190613c16565b6001600160a01b031681526020018a8152602001866002811115611fd457611fd4613ef4565b8152506040518263ffffffff1660e01b8152600401611ff39190614035565b5f604051808303815f87803b15801561200a575f80fd5b505af115801561201c573d5f803e3d5ffd5b5050505061202a8585613001565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808c6001600160a01b031681526020018d60800160208101906120869190613c16565b6001600160a01b031681526020018d6101c0015f0160208101906120aa9190613c16565b6001600160a01b031681526020018b81526020018560028111156120d0576120d0613ef4565b8152506040518263ffffffff1660e01b81526004016120ef9190614035565b5f604051808303815f87803b158015612106575f80fd5b505af1158015612118573d5f803e3d5ffd5b5061212e9250611e0e9150506020880188613def565b5f6121416101408c016101208d01613c16565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561219e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c291906140b4565b90508015612205576122056121de6101008d0160e08e01613c16565b828d610120015f0160208101906121f59190613c16565b6001600160a01b03169190613139565b5050505050505050505050565b6122226080830160608401613c16565b6001600160a01b0316336001600160a01b0316146122615761225c61224d6080840160608501613c16565b612256846112eb565b83611067565b6122a8565b61226e6040820182613d7f565b90505f036122a8576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122c56122bb6080840160608501613c16565b836020013561261e565b5050565b60e085013583158015906122e057508560c0013584105b156122fd576122fa848760e001358860c001356001611c1e565b90505b612309878288886131b9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808960600160208101906123569190613c16565b6001600160a01b031681526020016123766101608b016101408c01613c16565b6001600160a01b0316815260200161239460a08b0160808c01613c16565b6001600160a01b031681526020018715806123b257508960c0013588115b6123bc57876123c2565b8960c001355b81526020018660028111156123d9576123d9613ef4565b8152506040518263ffffffff1660e01b81526004016123f89190614035565b5f604051808303815f87803b15801561240f575f80fd5b505af1158015612421573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808a6001600160a01b031681526020018960400160208101906124819190613c16565b6001600160a01b0316815260200161249f60c08b0160a08c01613c16565b6001600160a01b031681526020018481526020018560028111156124c5576124c5613ef4565b8152506040518263ffffffff1660e01b81526004016124e49190614035565b5f604051808303815f87803b1580156124fb575f80fd5b505af115801561250d573d5f803e3d5ffd5b5061251e9250889150819050613d7f565b60405161252c929190613de0565b60405180910390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b68760400160208101906125689190613c16565b61257860808a0160608b01613c16565b61258860a08b0160808c01613c16565b61259860c08c0160a08d01613c16565b8915806125a857508b60c001358a115b6125b257896125b8565b8b60c001355b878d6101400160208101906125cd9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a250505050505050565b6001600160a01b0382165f9081526020818152604080832084845290915290205460ff1615612679576040517fbc0da7d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b039091165f908152602081815260408083209383529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f8080806126d5876004818b6140cb565b8101906126e291906140f2565b50919450925090506126fc61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612746576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612791576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b979650505050505050565b5f808080806127ec886004818c6140cb565b8101906127f99190614142565b929650909450925090506128156101e087016101c08801613c16565b6001600160a01b0316846001600160a01b03161461285f576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b0316146128aa576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128ba60a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612904576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b98975050505050505050565b5f805f805f805f805f8c8c600490809261296a939291906140cb565b8101906129779190614190565b959c50939a50919850965094509250905061299a6101e08b016101c08c01613c16565b6001600160a01b0316876001600160a01b0316146129e4576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856001600160a01b03168b6001600160a01b031614612a2f576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385163014612a71576040517f8154374b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612a8160a08b0160808c01613c16565b6001600160a01b0316846001600160a01b031614612acb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408a01358314612b09576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b1b6101408b016101208c01613c16565b6001600160a01b0316826001600160a01b031614612b65576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a08a01358114612ba3576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919c919b50909950505050505050505050565b5f808080612bc7876004818b6140cb565b810190612bd4919061420f565b91945092509050612bed61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612c37576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612c82576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61018085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808080612cd2886004818c6140cb565b810190612cdf919061424d565b5092965090945092509050612cfc6101e087016101c08801613c16565b6001600160a01b0316846001600160a01b031614612d46576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614612d91576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612da160a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612deb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102208601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051610180830135141580612e47575060208101516101a083013514155b15612e7e576040517f4a55da2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610220830135141580612e9f5750606081015161024083013514155b156122c5576040517f77a5920300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f80612ee4868661325c565b925092509250612ef482826132a5565b50909150505b92915050565b5f6002826003811115612f1557612f15613ef4565b612f1f91906142b1565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03612f7f57838281612f7557612f75614008565b04925050506104d0565b808411612f9657612f9660038515026011186133ad565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f5b81811015610c2b573683838381811061301e5761301e613e53565b90506020028101906130309190613e80565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130696020830183613c16565b6001600160a01b0316036130a9576040517f79a1bff000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130b2816133be565b6130bf6020820182613c16565b6001600160a01b03167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356130f784613401565b604080519283527fffffffff0000000000000000000000000000000000000000000000000000000090911660208301520160405180910390a250600101613003565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610c2b90849061342a565b5f831180156131cc575081610100013583105b15613203576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61321084612256846112eb565b61321e84836020013561261e565b428261012001351161119a576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f8351604103613293576020840151604085015160608601515f1a613285888285856134af565b95509550955050505061329e565b505081515f91506002905b9250925092565b5f8260038111156132b8576132b8613ef4565b036132c1575050565b60018260038111156132d5576132d5613ef4565b0361330c576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561332057613320613ef4565b0361335f576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600382600381111561337357613373613ef4565b036122c5576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401613356565b634e487b715f52806020526024601cfd5b5f6133cc6020830183613c16565b90506020820135365f6133e26040860186613d7f565b91509150604051818382375f80838387895af1611944573d5f803e3d5ffd5b5f36816134116040850185613d7f565b90925090506004811061342357813592505b5050919050565b5f8060205f8451602086015f885af180613449576040513d5f823e3d81fd5b50505f513d9150811561346057806001141561346d565b6001600160a01b0384163b155b1561119a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613356565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156134e857505f9150600390508261358b565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613539573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811661358257505f92506001915082905061358b565b92505f91508190505b9450945094915050565b5f805f604084860312156135a7575f80fd5b83359250602084013567ffffffffffffffff808211156135c5575f80fd5b818601915086601f8301126135d8575f80fd5b8135818111156135e6575f80fd5b8760208285010111156135f7575f80fd5b6020830194508093505050509250925092565b5f60a0828403121561361a575f80fd5b50919050565b5f60a08284031215613630575f80fd5b6104d0838361360a565b6001600160a01b0381168114610c89575f80fd5b80356136598161363a565b919050565b5f610260828403121561361a575f80fd5b5f8083601f84011261367f575f80fd5b50813567ffffffffffffffff811115613696575f80fd5b6020830191508360208260051b85010111156136b0575f80fd5b9250929050565b5f6040828403121561361a575f80fd5b5f6060828403121561361a575f80fd5b5f805f805f805f805f6101008a8c0312156136f0575f80fd5b6136f98a61364e565b985060208a0135975060408a013567ffffffffffffffff8082111561371c575f80fd5b6137288d838e0161365e565b985060608c013591508082111561373d575f80fd5b6137498d838e0161366f565b909850965060808c0135915080821115613761575f80fd5b61376d8d838e016136b7565b955060a08c0135915080821115613782575f80fd5b61378e8d838e016136c7565b945060c08c01359150808211156137a3575f80fd5b6137af8d838e016136c7565b935060e08c01359150808211156137c4575f80fd5b506137d18c828d016136c7565b9150509295985092959850929598565b5f80604083850312156137f2575f80fd5b82356137fd8161363a565b9150602083013567ffffffffffffffff811115613818575f80fd5b613824858286016136b7565b9150509250929050565b5f610160828403121561361a575f80fd5b5f805f805f60a08688031215613853575f80fd5b853561385e8161363a565b9450602086013567ffffffffffffffff8082111561387a575f80fd5b61388689838a0161382e565b9550604088013591508082111561389b575f80fd5b6138a789838a016136c7565b94506060880135935060808801359150808211156138c3575f80fd5b506138d0888289016136c7565b9150509295509295909350565b5f602082840312156138ed575f80fd5b5035919050565b8015158114610c89575f80fd5b5f805f805f8060a08789031215613916575f80fd5b86356139218161363a565b955060208701356139318161363a565b94506040870135613941816138f4565b9350606087013567ffffffffffffffff8082111561395d575f80fd5b6139698a838b0161365e565b9450608089013591508082111561397e575f80fd5b5061398b89828a0161366f565b979a9699509497509295939492505050565b5f805f606084860312156139af575f80fd5b83356139ba8161363a565b925060208401359150604084013567ffffffffffffffff8111156139dc575f80fd5b6139e8868287016136c7565b9150509250925092565b5f60208284031215613a02575f80fd5b813567ffffffffffffffff811115613a18575f80fd5b611bd38482850161382e565b5f805f805f805f8060e0898b031215613a3b575f80fd5b613a448961364e565b975060208901359650604089013567ffffffffffffffff80821115613a67575f80fd5b613a738c838d0161365e565b975060608b0135915080821115613a88575f80fd5b613a948c838d0161366f565b909750955060808b0135915080821115613aac575f80fd5b613ab88c838d016136b7565b945060a08b0135915080821115613acd575f80fd5b613ad98c838d016136c7565b935060c08b0135915080821115613aee575f80fd5b50613afb8b828c016136c7565b9150509295985092959890939650565b5f805f805f8060c08789031215613b20575f80fd5b613b298761364e565b9550602087013567ffffffffffffffff80821115613b45575f80fd5b613b518a838b0161382e565b96506040890135915080821115613b66575f80fd5b613b728a838b016136c7565b9550606089013594506080890135915080821115613b8e575f80fd5b613b9a8a838b016136c7565b935060a0890135915080821115613baf575f80fd5b50613bbc89828a016136c7565b9150509295509295509295565b5f60208284031215613bd9575f80fd5b813567ffffffffffffffff811115613bef575f80fd5b611bd38482850161365e565b5f60208284031215613c0b575f80fd5b81516104d0816138f4565b5f60208284031215613c26575f80fd5b81356104d08161363a565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b803565ffffffffffff81168114613659575f80fd5b5f6001600160a01b0380871683528086166020840152508360408301526080606083015282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ce2575f80fd5b830160208101903567ffffffffffffffff811115613cfe575f80fd5b803603821315613d0c575f80fd5b60606080850152613d2160e085018284613c31565b915050613d3060208501613c78565b65ffffffffffff80821660a086015280613d4c60408801613c78565b1660c086015250508091505095945050505050565b5f60208284031215613d71575f80fd5b8135600381106104d0575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db2575f80fd5b83018035915067ffffffffffffffff821115613dcc575f80fd5b6020019150368190038213156136b0575f80fd5b818382375f9101908152919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e22575f80fd5b83018035915067ffffffffffffffff821115613e3c575f80fd5b6020019150600581901b36038213156136b0575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112613eb2575f80fd5b9190910192915050565b80820180821115612efa577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613f31575f80fd5b8135600481106104d0575f80fd5b838152604060208201525f611c60604083018486613c31565b5f60208284031215613f68575f80fd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146104d0575f80fd5b602081525f611bd3602083018486613c31565b5f81515f5b81811015613fc95760208185018101518683015201613faf565b505f93019283525090919050565b5f611bd3613fe58386613faa565b84613faa565b5f613ff68286613faa565b93845250506020820152604001919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60a0820190506001600160a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151600381106140a7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8060808401525092915050565b5f602082840312156140c4575f80fd5b5051919050565b5f80858511156140d9575f80fd5b838611156140e5575f80fd5b5050820193919092039150565b5f805f8060808587031215614105575f80fd5b84356141108161363a565b935060208501356141208161363a565b9250604085013591506060850135614137816138f4565b939692955090935050565b5f805f8060808587031215614155575f80fd5b84356141608161363a565b935060208501356141708161363a565b925060408501356141808161363a565b9396929550929360600135925050565b5f805f805f805f60e0888a0312156141a6575f80fd5b87356141b18161363a565b965060208801356141c18161363a565b955060408801356141d18161363a565b945060608801356141e18161363a565b93506080880135925060a08801356141f88161363a565b8092505060c0880135905092959891949750929550565b5f805f60608486031215614221575f80fd5b833561422c8161363a565b9250602084013561423c8161363a565b929592945050506040919091013590565b5f805f805f60a08688031215614261575f80fd5b853561426c8161363a565b9450602086013561427c8161363a565b9350604086013561428c8161363a565b92506060860135915060808601356142a3816138f4565b809150509295509295909350565b5f60ff8316806142e8577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff8416069150509291505056fea26469706673582212209be58acada353061a2a202cc7011f3c91393e0f2e305e9202445b042fc4a4ce664736f6c63430008170033", + "sourceMap": "975:10890:90:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7809:308;;;;;;;;;;-1:-1:-1;7809:308:90;;;;;:::i;:::-;;:::i;:::-;;;852:66:169;840:79;;;822:98;;810:2;795:18;7809:308:90;;;;;;;;1318:57;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;1102:74;;1090:2;1075:18;1318:57:90;931:251:169;6790:255:91;;;;;;;;;;;;;:::i;:::-;;;1333:25:169;;;1321:2;1306:18;6790:255:91;1187:177:169;5478:391:91;;;;;;;;;;-1:-1:-1;5478:391:91;;;;;:::i;:::-;;:::i;5859:1907:90:-;;;;;;:::i;:::-;;:::i;:::-;;14436:563:91;;;;;;;;;;-1:-1:-1;14436:563:91;;;;;:::i;:::-;;:::i;1440:48:90:-;;;;;;;;;;;;;;;5092:382:91;;;;;;;;;;-1:-1:-1;5092:382:91;;;;;:::i;:::-;;:::i;4627:523:90:-;;;;;;:::i;:::-;;:::i;4091:109:91:-;;;;;;;;;;-1:-1:-1;4091:109:91;;;;;:::i;:::-;;:::i;7272:1606::-;;;;;;;;;;-1:-1:-1;7272:1606:91;;;;;:::i;:::-;;:::i;15182:1005::-;;;;;;;;;;-1:-1:-1;15182:1005:91;;;;;:::i;:::-;;:::i;6025:761::-;;;;;;;;;;-1:-1:-1;6025:761:91;;;;;:::i;:::-;;:::i;1196:64:90:-;;;;;;;;;;;;;;;2894:1690;;;;;;;;;;-1:-1:-1;2894:1690:90;;;;;:::i;:::-;;:::i;5154:701::-;;;;;;:::i;:::-;;:::i;4336:752:91:-;;;;;;;;;;-1:-1:-1;4336:752:91;;;;;:::i;:::-;;:::i;13818:485::-;;;;;;;;;;-1:-1:-1;13818:485:91;;;;;:::i;:::-;;:::i;7809:308:90:-;7909:6;7923:23;7949:35;7966:5;7973:10;;7949:16;:35::i;:::-;7994:38;;;;;-1:-1:-1;;;;;1120:55:169;;;7994:38:90;;;1102:74:169;7923:61:90;;-1:-1:-1;7994:13:90;:21;;;;;;1075:18:169;;7994:38:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7990:123;;;1905:44:91;8042:26:90;;;;;7990:123;-1:-1:-1;8089:17:90;;-1:-1:-1;7809:308:90;;;;;;:::o;6790:255:91:-;6839:7;6878:16;6861:13;:33;:179;;6946:93;;;1026:66;6946:93;;;13746:25:169;879:32:91;13787:18:169;;;13780:34;;;;957:14:91;13830:18:169;;;13823:34;7010:13:91;13873:18:169;;;13866:34;7033:4:91;13916:19:169;;;13909:84;13718:19;;6946:93:91;;;;;;;;;;;;6936:104;;;;;;6854:186;;6790:255;:::o;6861:179::-;-1:-1:-1;6903:24:91;;6790:255::o;5478:391::-;5597:7;2314:68;5694:20;;;;:15;:20;:::i;:::-;5724:15;:22;;;5756:15;:24;;;5790:15;:26;;;5826:15;:24;;;5636:222;;;;;;;;;;;;14543:25:169;;;-1:-1:-1;;;;;14604:55:169;;;;14599:2;14584:18;;14577:83;14691:2;14676:18;;14669:34;;;;14734:2;14719:18;;14712:34;14777:3;14762:19;;14755:35;14821:3;14806:19;;14799:35;14530:3;14515:19;;14256:584;5636:222:91;;;;;;;;;;;;;5619:245;;;;;;5612:252;;5478:391;;;:::o;5859:1907:90:-;2500:21:44;:19;:21::i;:::-;6282:30:90::1;::::0;;;;-1:-1:-1;;;;;1120:55:169;;;6282:30:90::1;::::0;::::1;1102:74:169::0;6282:13:90::1;:21;::::0;::::1;::::0;1075:18:169;;6282:30:90::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6277:54;;6321:10;;;;;;;;;;;;;;6277:54;6366:30:::0;;;::::1;6406:22:::0;;;;;:80:::1;;-1:-1:-1::0;6454:32:90;;;::::1;6432:54:::0;::::1;;6406:80;6402:254;;;6516:133;6537:18:::0;6557:30;;;::::1;6589:32:::0;;;::::1;6623:18;6516:11;:133::i;:::-;6496:153;;6402:254;6662:130;6683:10;6695:7;6704:17;6723:6;6731:13;;6746:6;6754:15;6771;6662:13;:130::i;:::-;-1:-1:-1::0;;;;;6799:15:90::1;:28;;6835:22;::::0;;;::::1;::::0;::::1;;:::i;:::-;6859:25;::::0;;;:20:::1;::::0;::::1;:25;:::i;:::-;6886:32;6799:143:::0;;::::1;::::0;;;;;;::::1;::::0;;;6886:32;;;::::1;::::0;6920:16;;6799:143:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;6949:357;6970:6;6984:7;6999:17;7024:18;7046:1;7024:23;:80;;;-1:-1:-1::0;7072:32:90;;;::::1;7051:53:::0;::::1;7024:80;:152;;7158:18;7024:152;;;7115:32:::0;;;::::1;7024:152;7184:6:::0;7198:13;;7219:42:::1;7269:31;::::0;;;::::1;::::0;::::1;;:::i;:::-;6949:13;:357::i;:::-;7336:12;;::::0;::::1;:6:::0;:12:::1;:::i;:::-;7318:443;;;;;;;:::i;:::-;;::::0;;;;::::1;::::0;;::::1;7356:13;::::0;;;::::1;::::0;::::1;;:::i;:::-;7377:22;::::0;;;::::1;::::0;::::1;;:::i;:::-;7407:25;::::0;;;:20:::1;::::0;::::1;:25;:::i;:::-;7440:26;::::0;;;:21:::1;::::0;::::1;:26;:::i;:::-;7474:23:::0;;;:80:::1;;-1:-1:-1::0;7522:32:90;;;::::1;7501:53:::0;::::1;7474:80;:147;;7603:18;7474:147;;;7565:27:::0;;;::::1;7474:147;7650:30:::0;;;::::1;7629:51:::0;::::1;:102;;7714:17;7629:102;;;7683:28:::0;;;::::1;7629:102;7739:6;:16;;;;;;;;;;:::i;:::-;7318:443;::::0;;-1:-1:-1;;;;;18257:15:169;;;18239:34;;18309:15;;;18304:2;18289:18;;18282:43;18361:15;;;18341:18;;;18334:43;;;;18413:15;;;18408:2;18393:18;;18386:43;18460:3;18445:19;;18438:35;18504:3;18489:19;;18482:35;18554:15;;;18548:3;18533:19;;18526:44;18165:3;18150:19;7318:443:90::1;;;;;;;6271:1495;2542:20:44::0;1857:1;3068:21;;2888:208;2542:20;5859:1907:90;;;;;;;;;:::o;14436:563:91:-;14546:9;14541:225;14561:19;:6;;:19;:::i;:::-;:26;;14557:1;:30;14541:225;;;14602:34;14639:19;:6;;:19;:::i;:::-;14659:1;14639:22;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;14602:59;-1:-1:-1;;;;;;14674:25:91;;;14700:11;;;;14602:59;14700:11;:::i;:::-;14674:38;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;14674:38:91;;;1102:74:169;1075:18;;14674:38:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14670:90;;;14731:20;;;;;;;;;;;;;;14670:90;-1:-1:-1;14589:3:91;;14541:225;;;;14777:9;14772:223;14792:18;;;;:6;:18;:::i;:::-;:25;;14788:1;:29;14772:223;;;14832:34;14869:18;;;;:6;:18;:::i;:::-;14888:1;14869:21;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;14832:58;-1:-1:-1;;;;;;14903:25:91;;;14929:11;;;;14832:58;14929:11;:::i;:::-;14903:38;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;14903:38:91;;;1102:74:169;1075:18;;14903:38:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14899:90;;;14960:20;;;;;;;;;;;;;;14899:90;-1:-1:-1;14819:3:91;;14772:223;;;;14436:563;;:::o;5092:382::-;5208:7;2182:67;5304:19;;;;:14;:19;:::i;4627:523:90:-;4876:62;4914:6;4922:15;4876:37;:62::i;:::-;4944:201;4971:7;4986:6;5000:15;5023:18;5049:41;5098;4944:19;:201::i;:::-;4627:523;;;;;:::o;4091:109:91:-;4155:40;4177:10;4189:5;4155:21;:40::i;:::-;4091:109;:::o;7272:1606::-;7498:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7498:27:91;7537:9;7532:1297;7548:24;;;7532:1297;;;7587:41;7631:13;;7645:1;7631:16;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;7587:60;-1:-1:-1;7655:23:91;;7681:20;;;;7587:60;7681:20;:::i;:::-;7655:46;;-1:-1:-1;7655:46:91;-1:-1:-1;;;;;;7714:25:91;;;7740:18;;;;:11;:18;:::i;:::-;7714:45;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;7714:45:91;;;1102:74:169;1075:18;;7714:45:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7710:1113;;;7771:10;7796:14;7792:52;;;7819:25;;;;;;;;;;;;;;7792:52;7878:1;7859:20;;7855:119;;-1:-1:-1;7923:29:91;;7855:119;7988:33;;;;;7984:831;;8049:45;8068:8;;8078:7;8087:6;8049:18;:45::i;:::-;8035:1;:10;;:59;;;;;;;:::i;:::-;;;-1:-1:-1;7984:831:91;;;8115:33;;;;;8111:704;;8176:45;8195:8;;8205:7;8214:6;8176:18;:45::i;:::-;8162:1;:10;;:59;;;;;;;:::i;8111:704::-;8242:39;;;;;8238:577;;8340:50;8364:8;;8374:7;8383:6;8340:23;:50::i;:::-;8317:19;;;8295:95;8296:19;;;8295:95;;;8402:10;;;:33;;;;8295:95;;8402:33;:::i;:::-;;;-1:-1:-1;8461:19:91;;;;8447:10;;;:33;;;;8461:19;;8447:33;:::i;8238:577::-;8501:32;;;;;8497:318;;8560:44;8578:8;;8588:7;8597:6;8560:17;:44::i;:::-;8547:57;;:1;;:57;;;;;:::i;8497:318::-;8625:35;;;;;8621:194;;8690:47;8711:8;;8721:7;8730:6;8690:20;:47::i;:::-;8674:1;:12;;:63;;;;;;;:::i;8621:194::-;8773:31;;;;;;;;;;;;;;8621:194;7761:1062;7710:1113;7579:1250;;;7574:3;;;;;7532:1297;;;;8835:38;8863:6;8871:1;8835:27;:38::i;:::-;7492:1386;7272:1606;;;;;;:::o;15182:1005::-;15364:21;15336:24;;;;:10;:24;:::i;:::-;:49;;;;;;;;:::i;:::-;;15332:851;;-1:-1:-1;;;;;15399:72:91;;:50;15416:5;15423:25;;;;:10;:25;:::i;:::-;15399:16;:50::i;:::-;-1:-1:-1;;;;;15399:72:91;;15395:128;;15490:24;;;;;;;;;;;;;;15332:851;15567:22;15539:24;;;;:10;:24;:::i;:::-;:50;;;;;;;;:::i;:::-;;15535:648;;15655:20;15599:19;15645:31;;;15692:2;15685:17;;;15739:2;15726:16;;-1:-1:-1;;;;;15761:78:91;;:56;15726:16;15791:25;;;;:10;:25;:::i;15761:56::-;-1:-1:-1;;;;;15761:78:91;;15757:135;;15858:25;;;;;;;;;;;;;;15757:135;15591:307;14772:223;14436:563;;:::o;15535:648::-;15936:22;15908:24;;;;:10;:24;:::i;:::-;:50;;;;;;;;:::i;:::-;;15904:279;;15972:102;-1:-1:-1;;;;;15972:45:91;;;16018:5;16025:25;;;;:10;:25;:::i;:::-;15972:79;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:102;;;15968:159;;16093:25;;;;;;;;;;;;;;15904:279;16154:22;;;;;;;;;;;;;;6025:761;6124:7;6209:18;:16;:18::i;:::-;2011:107;6381:12;:6;;:12;:::i;:::-;6370:24;;;;;;;;;:::i;:::-;;;;;;;;;;;;;6360:35;;;;;;6397:6;:12;;;6411:6;:13;;;;;;;;;;:::i;:::-;6323:102;;;;;;22262:25:169;;;;22303:18;;22296:34;;;;22346:18;;;22339:34;-1:-1:-1;;;;;22409:55:169;22389:18;;;22382:83;22234:19;;6323:102:91;;;;;;;;;;;;;6465:22;;;;;;;;:::i;:::-;6503:16;;;;;;;;:::i;:::-;6535:17;;;;;;;;:::i;:::-;6568:22;;;;6606:23;;;;6645:20;;;;6681:18;;;;6715:16;;;;;;;;:::i;:::-;6439:306;;;-1:-1:-1;;;;;22898:15:169;;;6439:306:91;;;22880:34:169;22950:15;;;22930:18;;;22923:43;23002:15;;;22982:18;;;22975:43;23034:18;;;23027:34;;;;23077:19;;;23070:35;;;;23121:19;;;23114:35;23165:19;;;23158:35;23230:15;;;23209:19;;;23202:44;22791:19;;6439:306:91;;;;;;;;;;;;;;6258:499;;;6439:306;6258:499;;:::i;:::-;;;;;;;;;;;;;6237:530;;;;;;6163:612;;;;;;;;24120:66:169;24108:79;;24212:1;24203:11;;24196:27;;;;24248:2;24239:12;;24232:28;24285:2;24276:12;;23850:444;2894:1690:90;2500:21:44;:19;:21::i;:::-;2266:34:90::1;::::0;;;;2289:10:::1;2266:34;::::0;::::1;1102:74:169::0;2266:13:90::1;-1:-1:-1::0;;;;;2266:22:90::1;::::0;::::1;::::0;1075:18:169;;2266:34:90::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2261:59;;2309:11;;;;;;;;;;;;;;2261:59;3251:30:::2;::::0;;;;-1:-1:-1;;;;;1120:55:169;;;3251:30:90::2;::::0;::::2;1102:74:169::0;3251:13:90::2;:21;::::0;::::2;::::0;1075:18:169;;3251:30:90::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3246:54;;3290:10;;;;;;;;;;;;;;3246:54;3335:30:::0;;;::::2;3375:22:::0;;;;;:80:::2;;-1:-1:-1::0;3423:32:90;;;::::2;3401:54:::0;::::2;;3375:80;3371:254;;;3485:133;3506:18:::0;3526:30;;;::::2;3558:32:::0;;;::::2;3592:18;3485:11;:133::i;:::-;3465:153;;3371:254;3631:130;3652:10;3664:7;3673:17;3692:6;3700:13;;3715:6;3723:15;3740;3631:13;:130::i;:::-;3768:356;3789:6:::0;3803:7;3818:17;3843:23;;;:80:::2;;-1:-1:-1::0;3891:32:90;;;::::2;3870:53:::0;::::2;3843:80;:152;;3977:18;3843:152;;;3934:32:::0;;;::::2;3843:152;4003:6:::0;4017:13;;4038:41:::2;4087:31;::::0;;;::::2;::::0;::::2;;:::i;3768:356::-;4154:12;;::::0;::::2;:6:::0;:12:::2;:::i;:::-;4136:443;;;;;;;:::i;:::-;;::::0;;;;::::2;::::0;;::::2;4174:13;::::0;;;::::2;::::0;::::2;;:::i;:::-;4195:22;::::0;;;::::2;::::0;::::2;;:::i;:::-;4225:25;::::0;;;:20:::2;::::0;::::2;:25;:::i;:::-;4258:26;::::0;;;:21:::2;::::0;::::2;:26;:::i;:::-;4292:23:::0;;;:80:::2;;-1:-1:-1::0;4340:32:90;;;::::2;4319:53:::0;::::2;4292:80;:147;;4421:18;4292:147;;;4383:27:::0;;;::::2;4292:147;4468:30:::0;;;::::2;4447:51:::0;::::2;:102;;4532:17;4447:102;;;4501:28:::0;;;::::2;4447:102;4557:6;:16;;;;;;;;;;:::i;:::-;4136:443;::::0;;-1:-1:-1;;;;;18257:15:169;;;18239:34;;18309:15;;;18304:2;18289:18;;18282:43;18361:15;;;18341:18;;;18334:43;;;;18413:15;;;18408:2;18393:18;;18386:43;18460:3;18445:19;;18438:35;18504:3;18489:19;;18482:35;18554:15;;;18548:3;18533:19;;18526:44;18165:3;18150:19;4136:443:90::2;;;;;;;3240:1344;2542:20:44::0;1857:1;3068:21;;2888:208;2542:20;2894:1690:90;;;;;;;;:::o;5154:701::-;5472:62;5510:6;5518:15;5472:37;:62::i;:::-;-1:-1:-1;;;;;5540:15:90;:28;;5569:22;;;;;;;;:::i;:::-;5593:16;;;;;;;;:::i;:::-;5611:6;:22;;;5635:16;5540:112;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5658:192;5685:7;5700:6;5714:15;5737:18;5763:42;5813:15;:31;;;;;;;;;;:::i;:::-;5658:19;:192::i;:::-;5154:701;;;;;;:::o;4336:752:91:-;4428:7;4513:18;:16;:18::i;:::-;2439:220;4714:12;;;;:6;:12;:::i;:::-;4703:24;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;4693:35;;4703:24;4693:35;;;;4744:12;;;;4772:13;;;;;;;;:::i;:::-;4801:22;;;;;;;;:::i;:::-;4839:18;;;;4873:16;;;;;;;;:::i;:::-;4627:312;;;;;;24642:25:169;;;;24683:18;;24676:34;;;;24726:18;;;24719:34;;;;-1:-1:-1;;;;;24850:15:169;;;24830:18;;;24823:43;24903:15;;24882:19;;;24875:44;24935:19;;;24928:35;;;;25000:15;24979:19;;;24972:44;4905:20:91;;;;;25032:19:169;;;25025:35;24614:19;;4627:312:91;;;;;;;;;;;;4953:39;4971:6;:20;;4953:17;:39::i;:::-;5006:41;5025:6;:21;;5006:18;:41::i;:::-;4562:497;;;;;;;;;;:::i;13818:485::-;14034:29;;;;13968:63;14003:28;;;;13968:32;;;;:63;:::i;:::-;:95;;;;:::i;:::-;13929:27;;;;:134;13918:184;;14077:25;;;;;;;;;;;;;;13918:184;14228:30;;;;14160:65;14193:32;;;;14160:30;;;;:65;:::i;:::-;:98;;;;:::i;:::-;14120:28;;;;:138;14109:189;;14272:26;;;;;;;;;;;;;;16423:233;16514:7;16529:14;16546:32;16560:5;16567:10;;16546:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16546:13:91;;-1:-1:-1;;;16546:32:91:i;:::-;16529:49;-1:-1:-1;;;;;;16588:20:91;;16584:48;;16617:15;;;;;;;;;;;;;;16584:48;16645:6;16423:233;-1:-1:-1;;;;16423:233:91:o;2575:307:44:-;1899:1;2702:7;;:18;2698:86;;2743:30;;;;;;;;;;;;;;2698:86;1899:1;2858:7;:17;2575:307::o;9351:238:48:-;9452:7;9506:76;9522:26;9539:8;9522:16;:26::i;:::-;:59;;;;;9580:1;9565:11;9552:25;;;;;:::i;:::-;9562:1;9559;9552:25;:29;9522:59;34914:9:49;34907:17;;34795:145;9506:76:48;9478:25;9485:1;9488;9491:11;9478:6;:25::i;:::-;:104;;;;:::i;:::-;9471:111;9351:238;-1:-1:-1;;;;;9351:238:48:o;17073:1250:91:-;17445:17;17465;17475:6;17465:9;:17::i;:::-;17445:37;;17488:54;17506:7;17515:9;17526:15;17488:17;:54::i;:::-;17567:22;;;;;;;;:::i;:::-;-1:-1:-1;;;;;17553:36:91;:10;-1:-1:-1;;;;;17553:36:91;;17549:223;;17599:69;17617:22;;;;;;;;:::i;:::-;17641:9;17652:15;17599:17;:69::i;:::-;17549:223;;;17693:30;;;;:15;:30;:::i;:::-;:37;;17734:1;17693:42;17689:76;;17744:21;;;;;;;;;;;;;;17689:76;17777:59;17799:22;;;;;;;;:::i;:::-;17823:6;:12;;;17777:21;:59::i;:::-;17865:6;:18;;;17847:15;:36;17843:69;;;17892:20;;;;;;;;;;;;;;17843:69;17939:1;17922:14;:18;:61;;;;;17962:6;:20;;;17945:14;:37;17922:61;17918:93;;;17992:19;;;;;;;;;;;;;;17918:93;18018:28;18039:6;18018:20;:28::i;:::-;18053:34;18067:11;18080:6;18053:13;:34::i;:::-;18094:173;18122:11;18141:7;18173:1;18156:14;:18;:70;;;;-1:-1:-1;18196:30:91;;;;18178:48;;;18156:70;18234:6;18248:13;;18094:20;:173::i;:::-;18274:44;18296:7;18305:6;:12;;;18274:21;:44::i;:::-;17439:884;17073:1250;;;;;;;;;:::o;8812:1368:90:-;9164:40;9184:19;:6;;:19;:::i;:::-;9164;:40::i;:::-;9211:23;9237:60;9269:28;;;;9237:29;;;;:60;:::i;:::-;9211:86;;9304:15;-1:-1:-1;;;;;9304:30:90;;9342:150;;;;;;;;9380:6;:22;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9342:150:90;;;;;9412:4;-1:-1:-1;;;;;9342:150:90;;;;;9419:6;:20;;:25;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9342:150:90;;;;;9446:15;9342:150;;;;9463:21;9342:150;;;;;;;;:::i;:::-;;;;9304:194;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9505:15;-1:-1:-1;;;;;9505:30:90;;9543:155;;;;;;;;9581:6;:22;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9543:155:90;;;;;9605:6;:16;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9543:155:90;;;;;9623:6;:20;;:25;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9543:155:90;;;;;9650:17;9543:155;;;;9669:21;9543:155;;;;;;;;:::i;:::-;;;;9505:199;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9711:34;9731:13;;9711:19;:34::i;:::-;9752:15;-1:-1:-1;;;;;9752:30:90;;9790:138;;;;;;;;9828:7;-1:-1:-1;;;;;9790:138:90;;;;;9837:6;:13;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9790:138:90;;;;;9852:6;:21;;:26;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9790:138:90;;;;;9880:17;9790:138;;;;9899:21;9790:138;;;;;;;;:::i;:::-;;;;9752:182;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9941:39:90;;-1:-1:-1;9961:18:90;;-1:-1:-1;;9961:18:90;;;:6;:18;:::i;9941:39::-;9987:15;10012:25;;;;:20;;;:25;:::i;:::-;10005:58;;;;;10057:4;10005:58;;;1102:74:169;-1:-1:-1;;;;;10005:43:90;;;;;;;1075:18:169;;10005:58:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9987:76;-1:-1:-1;10074:12:90;;10070:106;;10096:73;10143:16;;;;;;;;:::i;:::-;10161:7;10103:6;:20;;:25;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;10096:46:90;;:73;:46;:73::i;:::-;9158:1022;;8812:1368;;;;;;;;;:::o;18485:482:91:-;18673:22;;;;;;;;:::i;:::-;-1:-1:-1;;;;;18659:36:91;:10;-1:-1:-1;;;;;18659:36:91;;18655:237;;18705:83;18723:22;;;;;;;;:::i;:::-;18747:23;18763:6;18747:15;:23::i;:::-;18772:15;18705:17;:83::i;:::-;18655:237;;;18813:30;;;;:15;:30;:::i;:::-;:37;;18854:1;18813:42;18809:76;;18864:21;;;;;;;;;;;;;;18809:76;18897:65;18925:22;;;;;;;;:::i;:::-;18949:6;:12;;;18897:27;:65::i;:::-;18485:482;;:::o;10379:1484:90:-;10694:23;;;;10727;;;;;:70;;;10775:6;:22;;;10754:18;:43;10727:70;10723:216;;;10832:100;10844:18;10864:6;:23;;;10889:6;:22;;;10913:18;10832:11;:100::i;:::-;10807:125;;10723:216;10945:70;10966:7;10975:14;10991:6;10999:15;10945:20;:70::i;:::-;11022:15;-1:-1:-1;;;;;11022:30:90;;11060:297;;;;;;;;11098:6;:22;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11060:297:90;;;;;11130:16;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11060:297:90;;;;;11156:16;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11060:297:90;;;;;11182:23;;;:70;;;11230:6;:22;;;11209:18;:43;11182:70;:136;;11300:18;11182:136;;;11265:6;:22;;;11182:136;11060:297;;;;11328:21;11060:297;;;;;;;;:::i;:::-;;;;11022:341;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11370:15;-1:-1:-1;;;;;11370:30:90;;11408:110;;;;;;;;11437:7;-1:-1:-1;;;;;11408:110:90;;;;;11446:6;:13;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11408:110:90;;;;;11461:17;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11408:110:90;;;;;11480:14;11408:110;;;;11496:21;11408:110;;;;;;;;:::i;:::-;;;;11370:154;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11554:12:90;;-1:-1:-1;11554:6:90;;-1:-1:-1;11554:6:90;;-1:-1:-1;11554:12:90;:::i;:::-;11536:322;;;;;;;:::i;:::-;;;;;;;;;11574:6;:13;;;;;;;;;;:::i;:::-;11595:22;;;;;;;;:::i;:::-;11625:16;;;;;;;;:::i;:::-;11649:17;;;;;;;;:::i;:::-;11674:23;;;:70;;;11722:6;:22;;;11701:18;:43;11674:70;:132;;11788:18;11674:132;;;11755:6;:22;;;11674:132;11814:14;11836:6;:16;;;;;;;;;;:::i;:::-;11536:322;;;-1:-1:-1;;;;;18257:15:169;;;18239:34;;18309:15;;;18304:2;18289:18;;18282:43;18361:15;;;18341:18;;;18334:43;;;;18413:15;;;18408:2;18393:18;;18386:43;18460:3;18445:19;;18438:35;18504:3;18489:19;;18482:35;18554:15;;;18548:3;18533:19;;18526:44;18165:3;18150:19;11536:322:90;;;;;;;10663:1200;10379:1484;;;;;;:::o;20053:172:91:-;-1:-1:-1;;;;;20136:16:91;;:7;:16;;;;;;;;;;;:24;;;;;;;;;;;20132:51;;;20169:14;;;;;;;;;;;;;;20132:51;-1:-1:-1;;;;;20189:16:91;;;:7;:16;;;;;;;;;;;:24;;;;;;;:31;;;;20216:4;20189:31;;;20053:172::o;9090:497::-;9242:7;;;;9321:12;:8;9330:1;9321:8;;:12;:::i;:::-;9310:59;;;;;;;:::i;:::-;-1:-1:-1;9257:112:91;;-1:-1:-1;9257:112:91;-1:-1:-1;9257:112:91;-1:-1:-1;9388:25:91;;;;:20;;;:25;:::i;:::-;-1:-1:-1;;;;;9379:34:91;:5;-1:-1:-1;;;;;9379:34:91;;9375:61;;9422:14;;;;;;;;;;;;;;9375:61;9457:8;-1:-1:-1;;;;;9446:19:91;:7;-1:-1:-1;;;;;9446:19:91;;9442:47;;9474:15;;;;;;;;;;;;;;9442:47;9509:29;;;;9499:39;;9495:67;;9547:15;;;;;;;;;;;;;;9495:67;9576:6;9090:497;-1:-1:-1;;;;;;;9090:497:91:o;9799:589::-;9951:7;;;;;10053:12;:8;10062:1;10053:8;;:12;:::i;:::-;10042:62;;;;;;;:::i;:::-;9966:138;;-1:-1:-1;9966:138:91;;-1:-1:-1;9966:138:91;-1:-1:-1;9966:138:91;-1:-1:-1;10123:26:91;;;;:21;;;:26;:::i;:::-;-1:-1:-1;;;;;10114:35:91;:5;-1:-1:-1;;;;;10114:35:91;;10110:62;;10158:14;;;;;;;;;;;;;;10110:62;10193:8;-1:-1:-1;;;;;10182:19:91;:7;-1:-1:-1;;;;;10182:19:91;;10178:47;;10210:15;;;;;;;;;;;;;;10178:47;10247:13;;;;;;;;:::i;:::-;-1:-1:-1;;;;;10235:25:91;:8;-1:-1:-1;;;;;10235:25:91;;10231:58;;10269:20;;;;;;;;;;;;;;10231:58;10309:30;;;;10299:40;;10295:68;;10348:15;;;;;;;;;;;;;;10295:68;10377:6;9799:589;-1:-1:-1;;;;;;;;9799:589:91:o;10633:953::-;10790:7;10799;10822:13;10843:16;10867:14;10889:17;10914:14;10936:18;10962:19;11001:8;;11010:1;11001:12;;;;;;;;;:::i;:::-;10990:89;;;;;;;:::i;:::-;10814:265;;-1:-1:-1;10814:265:91;;-1:-1:-1;10814:265:91;;-1:-1:-1;10814:265:91;-1:-1:-1;10814:265:91;-1:-1:-1;10814:265:91;-1:-1:-1;10814:265:91;-1:-1:-1;11098:26:91;;;;:21;;;:26;:::i;:::-;-1:-1:-1;;;;;11089:35:91;:5;-1:-1:-1;;;;;11089:35:91;;11085:62;;11133:14;;;;;;;;;;;;;;11085:62;11168:8;-1:-1:-1;;;;;11157:19:91;:7;-1:-1:-1;;;;;11157:19:91;;11153:47;;11185:15;;;;;;;;;;;;;;11153:47;-1:-1:-1;;;;;11210:23:91;;11228:4;11210:23;11206:51;;11242:15;;;;;;;;;;;;;;11206:51;11280:13;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11267:26:91;:9;-1:-1:-1;;;;;11267:26:91;;11263:59;;11302:20;;;;;;;;;;;;;;11263:59;11342:30;;;;11332:40;;11328:68;;11381:15;;;;;;;;;;;;;;11328:68;11420:25;;;;:20;;;:25;:::i;:::-;-1:-1:-1;;;;;11406:39:91;:10;-1:-1:-1;;;;;11406:39:91;;11402:66;;11454:14;;;;;;;;;;;;;;11402:66;11493:29;;;;11478:44;;11474:72;;11531:15;;;;;;;;;;;;;;11474:72;11561:6;;;;-1:-1:-1;10633:953:91;;-1:-1:-1;;;;;;;;;;10633:953:91:o;11796:488::-;11947:7;;;;12025:12;:8;12034:1;12025:8;;:12;:::i;:::-;12014:53;;;;;;;:::i;:::-;11962:105;;-1:-1:-1;11962:105:91;-1:-1:-1;11962:105:91;-1:-1:-1;12086:25:91;;;;:20;;;:25;:::i;:::-;-1:-1:-1;;;;;12077:34:91;:5;-1:-1:-1;;;;;12077:34:91;;12073:61;;12120:14;;;;;;;;;;;;;;12073:61;12155:8;-1:-1:-1;;;;;12144:19:91;:7;-1:-1:-1;;;;;12144:19:91;;12140:47;;12172:15;;;;;;;;;;;;;;12140:47;12207:28;;;;12197:38;;12193:66;;12244:15;;;;;;;;;;;;;;12500:602;12654:7;;;;;12758:12;:8;12767:1;12758:8;;:12;:::i;:::-;12747:68;;;;;;;:::i;:::-;-1:-1:-1;12669:146:91;;-1:-1:-1;12669:146:91;;-1:-1:-1;12669:146:91;-1:-1:-1;12669:146:91;-1:-1:-1;12834:26:91;;;;:21;;;:26;:::i;:::-;-1:-1:-1;;;;;12825:35:91;:5;-1:-1:-1;;;;;12825:35:91;;12821:62;;12869:14;;;;;;;;;;;;;;12821:62;12904:9;-1:-1:-1;;;;;12893:20:91;:7;-1:-1:-1;;;;;12893:20:91;;12889:48;;12922:15;;;;;;;;;;;;;;12889:48;12959:13;;;;;;;;:::i;:::-;-1:-1:-1;;;;;12947:25:91;:8;-1:-1:-1;;;;;12947:25:91;;12943:58;;12981:20;;;;;;;;;;;;;;12943:58;13021:32;;;;13011:42;;13007:70;;13062:15;;;;;;;;;;;;;;13259:466;13404:9;;13417:28;;;;13404:41;;;:88;;-1:-1:-1;13449:10:91;;;;13463:29;;;;13449:43;;13404:88;13400:153;;;13509:37;;;;;;;;;;;;;;13400:153;13563:12;;;;13579:32;;;;13563:48;;;:96;;-1:-1:-1;13615:10:91;;;;13629:30;;;;13615:44;;13563:96;13559:162;;;13676:38;;;;;;;;;;;;;;3714:255:45;3792:7;3812:17;3831:18;3851:16;3871:27;3882:4;3888:9;3871:10;:27::i;:::-;3811:87;;;;;;3908:28;3920:5;3927:8;3908:11;:28::i;:::-;-1:-1:-1;3953:9:45;;-1:-1:-1;;3714:255:45;;;;;:::o;29533:122:48:-;29601:4;29642:1;29630:8;29624:15;;;;;;;;:::i;:::-;:19;;;;:::i;:::-;:24;;29647:1;29624:24;29617:31;;29533:122;;;:::o;4996:4226::-;5078:14;5449:5;;;5078:14;5634:6;5453:1;5449;5621:20;5694:5;5690:2;5687:13;5679:5;5675:2;5671:14;5667:34;5658:43;;;5796:5;5805:1;5796:10;5792:368;;6134:11;6126:5;:19;;;;;:::i;:::-;;6119:26;;;;;;5792:368;6285:5;6270:11;:20;6266:143;;6310:84;3066:5;6330:16;;3065:36;940:4:43;3060:42:48;6310:11;:84::i;:::-;6664:17;6799:11;6796:1;6793;6786:25;7199:12;7229:15;;;7214:31;;7348:22;;;;;8094:1;8075;:15;;8074:21;;8327;;;8323:25;;8312:36;8397:21;;;8393:25;;8382:36;8469:21;;;8465:25;;8454:36;8540:21;;;8536:25;;8525:36;8613:21;;;8609:25;;8598:36;8687:21;;;8683:25;;;8672:36;7597:12;;;;7593:23;;;7618:1;7589:31;6913:20;;;6902:32;;;7709:12;;;;6960:21;;;;7446:16;;;;7700:21;;;;9163:15;;;;;-1:-1:-1;;4996:4226:48;;;;;:::o;8348:460:90:-;8452:9;8447:357;8463:24;;;8447:357;;;8502:41;8546:13;;8560:1;8546:16;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;8502:60;-1:-1:-1;;;;;;8605:15:90;8575:46;:18;;;;8502:60;8575:18;:::i;:::-;-1:-1:-1;;;;;8575:46:90;;8571:79;;8630:20;;;;;;;;;;;;;;8571:79;8658:36;8682:11;8658:23;:36::i;:::-;8720:18;;;;:11;:18;:::i;:::-;-1:-1:-1;;;;;8708:89:90;;8740:11;:17;;;8759:37;8784:11;8759:24;:37::i;:::-;8708:89;;;30953:25:169;;;31026:66;31014:79;;;31009:2;30994:18;;30987:107;30926:18;8708:89:90;;;;;;;-1:-1:-1;8489:3:90;;8447:357;;1219:160:39;1328:43;;;-1:-1:-1;;;;;31297:55:169;;1328:43:39;;;31279:74:169;31369:18;;;;31362:34;;;1328:43:39;;;;;;;;;;31252:18:169;;;;1328:43:39;;;;;;;;;;;;;;1301:71;;1321:5;;1301:19;:71::i;19109:500:91:-;19332:1;19315:14;:18;:61;;;;;19355:6;:20;;;19338:14;:37;19315:61;19311:93;;;19385:19;;;;;;;;;;;;;;19311:93;19410:68;19428:7;19437:23;19453:6;19437:15;:23::i;19410:68::-;19484:50;19512:7;19521:6;:12;;;19484:27;:50::i;:::-;19566:15;19544:6;:18;;;:37;19540:64;;19590:14;;;;;;;;;;;;;;2129:778:45;2232:17;2251:16;2269:14;2299:9;:16;2319:2;2299:22;2295:606;;2604:4;2589:20;;2583:27;2653:4;2638:20;;2632:27;2710:4;2695:20;;2689:27;2337:9;2681:36;2751:25;2762:4;2681:36;2583:27;2632;2751:10;:25::i;:::-;2744:32;;;;;;;;;;;2295:606;-1:-1:-1;;2872:16:45;;2823:1;;-1:-1:-1;2827:35:45;;2295:606;2129:778;;;;;:::o;7280:532::-;7375:20;7366:5;:29;;;;;;;;:::i;:::-;;7362:444;;7280:532;;:::o;7362:444::-;7471:29;7462:5;:38;;;;;;;;:::i;:::-;;7458:348;;7523:23;;;;;;;;;;;;;;7458:348;7576:35;7567:5;:44;;;;;;;;:::i;:::-;;7563:243;;7634:46;;;;;;;;1333:25:169;;;1306:18;;7634:46:45;;;;;;;;7563:243;7710:30;7701:5;:39;;;;;;;;:::i;:::-;;7697:109;;7763:32;;;;;;;;1333:25:169;;;1306:18;;7763:32:45;1187:177:169;1776:194:43;1881:10;1875:4;1868:24;1918:4;1912;1905:18;1949:4;1943;1936:18;582:989:72;649:14;666:18;;;;:11;:18;:::i;:::-;649:35;-1:-1:-1;706:17:72;;;;729:23;690:13;755:20;;;;706:11;755:20;:::i;:::-;729:46;;;;1305:4;1299:11;1366:15;1349;1330:17;1317:65;1465:1;1462;1445:15;1426:17;1419:5;1411:6;1404:5;1399:68;1389:172;;1500:16;1497:1;1494;1479:38;1536:16;1533:1;1526:27;1798:809;1874:13;1895:23;1874:13;1921:20;;;;:11;:20;:::i;:::-;1895:46;;-1:-1:-1;1895:46:72;-1:-1:-1;1970:1:72;1951:20;;1947:656;;2573:15;2560:29;2550:39;;1947:656;1889:718;;1798:809;;;:::o;8370:720:39:-;8450:18;8478:19;8616:4;8613:1;8606:4;8600:11;8593:4;8587;8583:15;8580:1;8573:5;8566;8561:60;8673:7;8663:176;;8717:4;8711:11;8762:16;8759:1;8754:3;8739:40;8808:16;8803:3;8796:29;8663:176;-1:-1:-1;;8916:1:39;8910:8;8866:16;;-1:-1:-1;8942:15:39;;:68;;8994:11;9009:1;8994:16;;8942:68;;;-1:-1:-1;;;;;8960:26:39;;;:31;8942:68;8938:146;;;9033:40;;;;;-1:-1:-1;;;;;1120:55:169;;9033:40:39;;;1102:74:169;1075:18;;9033:40:39;931:251:169;5203:1551:45;5329:17;;;6283:66;6270:79;;6266:164;;;-1:-1:-1;6381:1:45;;-1:-1:-1;6385:30:45;;-1:-1:-1;6417:1:45;6365:54;;6266:164;6541:24;;;6524:14;6541:24;;;;;;;;;31816:25:169;;;31889:4;31877:17;;31857:18;;;31850:45;;;;31911:18;;;31904:34;;;31954:18;;;31947:34;;;6541:24:45;;31788:19:169;;6541:24:45;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6541:24:45;;;;;;-1:-1:-1;;;;;;;6579:20:45;;6575:113;;-1:-1:-1;6631:1:45;;-1:-1:-1;6635:29:45;;-1:-1:-1;6631:1:45;;-1:-1:-1;6615:62:45;;6575:113;6706:6;-1:-1:-1;6714:20:45;;-1:-1:-1;6714:20:45;;-1:-1:-1;5203:1551:45;;;;;;;;;:::o;14:659:169:-;93:6;101;109;162:2;150:9;141:7;137:23;133:32;130:52;;;178:1;175;168:12;130:52;214:9;201:23;191:33;;275:2;264:9;260:18;247:32;298:18;339:2;331:6;328:14;325:34;;;355:1;352;345:12;325:34;393:6;382:9;378:22;368:32;;438:7;431:4;427:2;423:13;419:27;409:55;;460:1;457;450:12;409:55;500:2;487:16;526:2;518:6;515:14;512:34;;;542:1;539;532:12;512:34;587:7;582:2;573:6;569:2;565:15;561:24;558:37;555:57;;;608:1;605;598:12;555:57;639:2;635;631:11;621:21;;661:6;651:16;;;;;14:659;;;;;:::o;1369:163::-;1436:5;1481:3;1472:6;1467:3;1463:16;1459:26;1456:46;;;1498:1;1495;1488:12;1456:46;-1:-1:-1;1520:6:169;1369:163;-1:-1:-1;1369:163:169:o;1537:254::-;1631:6;1684:3;1672:9;1663:7;1659:23;1655:33;1652:53;;;1701:1;1698;1691:12;1652:53;1724:61;1777:7;1766:9;1724:61;:::i;1796:154::-;-1:-1:-1;;;;;1875:5:169;1871:54;1864:5;1861:65;1851:93;;1940:1;1937;1930:12;1955:134;2023:20;;2052:31;2023:20;2052:31;:::i;:::-;1955:134;;;:::o;2094:154::-;2152:5;2197:3;2188:6;2183:3;2179:16;2175:26;2172:46;;;2214:1;2211;2204:12;2253:380;2329:8;2339:6;2393:3;2386:4;2378:6;2374:17;2370:27;2360:55;;2411:1;2408;2401:12;2360:55;-1:-1:-1;2434:20:169;;2477:18;2466:30;;2463:50;;;2509:1;2506;2499:12;2463:50;2546:4;2538:6;2534:17;2522:29;;2606:3;2599:4;2589:6;2586:1;2582:14;2574:6;2570:27;2566:38;2563:47;2560:67;;;2623:1;2620;2613:12;2560:67;2253:380;;;;;:::o;2638:153::-;2696:5;2741:2;2732:6;2727:3;2723:16;2719:25;2716:45;;;2757:1;2754;2747:12;2796:162;2863:5;2908:2;2899:6;2894:3;2890:16;2886:25;2883:45;;;2924:1;2921;2914:12;2963:1853;3295:6;3303;3311;3319;3327;3335;3343;3351;3359;3412:3;3400:9;3391:7;3387:23;3383:33;3380:53;;;3429:1;3426;3419:12;3380:53;3452:29;3471:9;3452:29;:::i;:::-;3442:39;;3528:2;3517:9;3513:18;3500:32;3490:42;;3583:2;3572:9;3568:18;3555:32;3606:18;3647:2;3639:6;3636:14;3633:34;;;3663:1;3660;3653:12;3633:34;3686:65;3743:7;3734:6;3723:9;3719:22;3686:65;:::i;:::-;3676:75;;3804:2;3793:9;3789:18;3776:32;3760:48;;3833:2;3823:8;3820:16;3817:36;;;3849:1;3846;3839:12;3817:36;3888:85;3965:7;3954:8;3943:9;3939:24;3888:85;:::i;:::-;3992:8;;-1:-1:-1;3862:111:169;-1:-1:-1;4080:3:169;4065:19;;4052:33;;-1:-1:-1;4097:16:169;;;4094:36;;;4126:1;4123;4116:12;4094:36;4149:67;4208:7;4197:8;4186:9;4182:24;4149:67;:::i;:::-;4139:77;;4269:3;4258:9;4254:19;4241:33;4225:49;;4299:2;4289:8;4286:16;4283:36;;;4315:1;4312;4305:12;4283:36;4338:76;4406:7;4395:8;4384:9;4380:24;4338:76;:::i;:::-;4328:86;;4467:3;4456:9;4452:19;4439:33;4423:49;;4497:2;4487:8;4484:16;4481:36;;;4513:1;4510;4503:12;4481:36;4536:76;4604:7;4593:8;4582:9;4578:24;4536:76;:::i;:::-;4526:86;;4665:3;4654:9;4650:19;4637:33;4621:49;;4695:2;4685:8;4682:16;4679:36;;;4711:1;4708;4701:12;4679:36;;4734:76;4802:7;4791:8;4780:9;4776:24;4734:76;:::i;:::-;4724:86;;;2963:1853;;;;;;;;;;;:::o;4821:509::-;4936:6;4944;4997:2;4985:9;4976:7;4972:23;4968:32;4965:52;;;5013:1;5010;5003:12;4965:52;5052:9;5039:23;5071:31;5096:5;5071:31;:::i;:::-;5121:5;-1:-1:-1;5177:2:169;5162:18;;5149:32;5204:18;5193:30;;5190:50;;;5236:1;5233;5226:12;5190:50;5259:65;5316:7;5307:6;5296:9;5292:22;5259:65;:::i;:::-;5249:75;;;4821:509;;;;;:::o;5845:155::-;5904:5;5949:3;5940:6;5935:3;5931:16;5927:26;5924:46;;;5966:1;5963;5956:12;6005:1079;6197:6;6205;6213;6221;6229;6282:3;6270:9;6261:7;6257:23;6253:33;6250:53;;;6299:1;6296;6289:12;6250:53;6338:9;6325:23;6357:31;6382:5;6357:31;:::i;:::-;6407:5;-1:-1:-1;6463:2:169;6448:18;;6435:32;6486:18;6516:14;;;6513:34;;;6543:1;6540;6533:12;6513:34;6566:66;6624:7;6615:6;6604:9;6600:22;6566:66;:::i;:::-;6556:76;;6685:2;6674:9;6670:18;6657:32;6641:48;;6714:2;6704:8;6701:16;6698:36;;;6730:1;6727;6720:12;6698:36;6753:76;6821:7;6810:8;6799:9;6795:24;6753:76;:::i;:::-;6743:86;;6876:2;6865:9;6861:18;6848:32;6838:42;;6933:3;6922:9;6918:19;6905:33;6889:49;;6963:2;6953:8;6950:16;6947:36;;;6979:1;6976;6969:12;6947:36;;7002:76;7070:7;7059:8;7048:9;7044:24;7002:76;:::i;:::-;6992:86;;;6005:1079;;;;;;;;:::o;7089:180::-;7148:6;7201:2;7189:9;7180:7;7176:23;7172:32;7169:52;;;7217:1;7214;7207:12;7169:52;-1:-1:-1;7240:23:169;;7089:180;-1:-1:-1;7089:180:169:o;7274:118::-;7360:5;7353:13;7346:21;7339:5;7336:32;7326:60;;7382:1;7379;7372:12;7397:1161;7588:6;7596;7604;7612;7620;7628;7681:3;7669:9;7660:7;7656:23;7652:33;7649:53;;;7698:1;7695;7688:12;7649:53;7737:9;7724:23;7756:31;7781:5;7756:31;:::i;:::-;7806:5;-1:-1:-1;7863:2:169;7848:18;;7835:32;7876:33;7835:32;7876:33;:::i;:::-;7928:7;-1:-1:-1;7987:2:169;7972:18;;7959:32;8000:30;7959:32;8000:30;:::i;:::-;8049:7;-1:-1:-1;8107:2:169;8092:18;;8079:32;8130:18;8160:14;;;8157:34;;;8187:1;8184;8177:12;8157:34;8210:65;8267:7;8258:6;8247:9;8243:22;8210:65;:::i;:::-;8200:75;;8328:3;8317:9;8313:19;8300:33;8284:49;;8358:2;8348:8;8345:16;8342:36;;;8374:1;8371;8364:12;8342:36;;8413:85;8490:7;8479:8;8468:9;8464:24;8413:85;:::i;:::-;7397:1161;;;;-1:-1:-1;7397:1161:169;;-1:-1:-1;7397:1161:169;;8517:8;;7397:1161;-1:-1:-1;;;7397:1161:169:o;8563:574::-;8675:6;8683;8691;8744:2;8732:9;8723:7;8719:23;8715:32;8712:52;;;8760:1;8757;8750:12;8712:52;8799:9;8786:23;8818:31;8843:5;8818:31;:::i;:::-;8868:5;-1:-1:-1;8920:2:169;8905:18;;8892:32;;-1:-1:-1;8975:2:169;8960:18;;8947:32;9002:18;8991:30;;8988:50;;;9034:1;9031;9024:12;8988:50;9057:74;9123:7;9114:6;9103:9;9099:22;9057:74;:::i;:::-;9047:84;;;8563:574;;;;;:::o;9142:355::-;9228:6;9281:2;9269:9;9260:7;9256:23;9252:32;9249:52;;;9297:1;9294;9287:12;9249:52;9337:9;9324:23;9370:18;9362:6;9359:30;9356:50;;;9402:1;9399;9392:12;9356:50;9425:66;9483:7;9474:6;9463:9;9459:22;9425:66;:::i;9767:1602::-;10054:6;10062;10070;10078;10086;10094;10102;10110;10163:3;10151:9;10142:7;10138:23;10134:33;10131:53;;;10180:1;10177;10170:12;10131:53;10203:29;10222:9;10203:29;:::i;:::-;10193:39;;10279:2;10268:9;10264:18;10251:32;10241:42;;10334:2;10323:9;10319:18;10306:32;10357:18;10398:2;10390:6;10387:14;10384:34;;;10414:1;10411;10404:12;10384:34;10437:65;10494:7;10485:6;10474:9;10470:22;10437:65;:::i;:::-;10427:75;;10555:2;10544:9;10540:18;10527:32;10511:48;;10584:2;10574:8;10571:16;10568:36;;;10600:1;10597;10590:12;10568:36;10639:85;10716:7;10705:8;10694:9;10690:24;10639:85;:::i;:::-;10743:8;;-1:-1:-1;10613:111:169;-1:-1:-1;10831:3:169;10816:19;;10803:33;;-1:-1:-1;10848:16:169;;;10845:36;;;10877:1;10874;10867:12;10845:36;10900:67;10959:7;10948:8;10937:9;10933:24;10900:67;:::i;:::-;10890:77;;11020:3;11009:9;11005:19;10992:33;10976:49;;11050:2;11040:8;11037:16;11034:36;;;11066:1;11063;11056:12;11034:36;11089:76;11157:7;11146:8;11135:9;11131:24;11089:76;:::i;:::-;11079:86;;11218:3;11207:9;11203:19;11190:33;11174:49;;11248:2;11238:8;11235:16;11232:36;;;11264:1;11261;11254:12;11232:36;;11287:76;11355:7;11344:8;11333:9;11329:24;11287:76;:::i;:::-;11277:86;;;9767:1602;;;;;;;;;;;:::o;11374:1269::-;11611:6;11619;11627;11635;11643;11651;11704:3;11692:9;11683:7;11679:23;11675:33;11672:53;;;11721:1;11718;11711:12;11672:53;11744:29;11763:9;11744:29;:::i;:::-;11734:39;;11824:2;11813:9;11809:18;11796:32;11847:18;11888:2;11880:6;11877:14;11874:34;;;11904:1;11901;11894:12;11874:34;11927:66;11985:7;11976:6;11965:9;11961:22;11927:66;:::i;:::-;11917:76;;12046:2;12035:9;12031:18;12018:32;12002:48;;12075:2;12065:8;12062:16;12059:36;;;12091:1;12088;12081:12;12059:36;12114:76;12182:7;12171:8;12160:9;12156:24;12114:76;:::i;:::-;12104:86;;12237:2;12226:9;12222:18;12209:32;12199:42;;12294:3;12283:9;12279:19;12266:33;12250:49;;12324:2;12314:8;12311:16;12308:36;;;12340:1;12337;12330:12;12308:36;12363:76;12431:7;12420:8;12409:9;12405:24;12363:76;:::i;:::-;12353:86;;12492:3;12481:9;12477:19;12464:33;12448:49;;12522:2;12512:8;12509:16;12506:36;;;12538:1;12535;12528:12;12506:36;;12561:76;12629:7;12618:8;12607:9;12603:24;12561:76;:::i;:::-;12551:86;;;11374:1269;;;;;;;;:::o;12648:353::-;12733:6;12786:2;12774:9;12765:7;12761:23;12757:32;12754:52;;;12802:1;12799;12792:12;12754:52;12842:9;12829:23;12875:18;12867:6;12864:30;12861:50;;;12907:1;12904;12897:12;12861:50;12930:65;12987:7;12978:6;12967:9;12963:22;12930:65;:::i;13237:245::-;13304:6;13357:2;13345:9;13336:7;13332:23;13328:32;13325:52;;;13373:1;13370;13363:12;13325:52;13405:9;13399:16;13424:28;13446:5;13424:28;:::i;14004:247::-;14063:6;14116:2;14104:9;14095:7;14091:23;14087:32;14084:52;;;14132:1;14129;14122:12;14084:52;14171:9;14158:23;14190:31;14215:5;14190:31;:::i;14845:325::-;14933:6;14928:3;14921:19;14985:6;14978:5;14971:4;14966:3;14962:14;14949:43;;15037:1;15030:4;15021:6;15016:3;15012:16;15008:27;15001:38;14903:3;15159:4;15089:66;15084:2;15076:6;15072:15;15068:88;15063:3;15059:98;15055:109;15048:116;;14845:325;;;;:::o;15175:167::-;15242:20;;15302:14;15291:26;;15281:37;;15271:65;;15332:1;15329;15322:12;15347:1365;15593:4;-1:-1:-1;;;;;15703:2:169;15695:6;15691:15;15680:9;15673:34;15755:2;15747:6;15743:15;15738:2;15727:9;15723:18;15716:43;;15795:6;15790:2;15779:9;15775:18;15768:34;15838:3;15833:2;15822:9;15818:18;15811:31;15890:6;15877:20;15973:66;15964:6;15948:14;15944:27;15940:100;15920:18;15916:125;15906:153;;16055:1;16052;16045:12;15906:153;16081:31;;16189:2;16178:14;;;16135:19;16215:18;16204:30;;16201:50;;;16247:1;16244;16237:12;16201:50;16296:6;16280:14;16276:27;16267:7;16263:41;16260:61;;;16317:1;16314;16307:12;16260:61;16358:2;16352:3;16341:9;16337:19;16330:31;16384:63;16442:3;16431:9;16427:19;16419:6;16410:7;16384:63;:::i;:::-;16370:77;;;16476:34;16506:2;16498:6;16494:15;16476:34;:::i;:::-;16529:14;16598:2;16584:12;16580:21;16574:3;16563:9;16559:19;16552:50;16679:2;16643:34;16673:2;16665:6;16661:15;16643:34;:::i;:::-;16639:43;16633:3;16622:9;16618:19;16611:72;;;16700:6;16692:14;;;15347:1365;;;;;;;:::o;16717:277::-;16797:6;16850:2;16838:9;16829:7;16825:23;16821:32;16818:52;;;16866:1;16863;16856:12;16818:52;16905:9;16892:23;16944:1;16937:5;16934:12;16924:40;;16960:1;16957;16950:12;16999:581;17077:4;17083:6;17143:11;17130:25;17233:66;17222:8;17206:14;17202:29;17198:102;17178:18;17174:127;17164:155;;17315:1;17312;17305:12;17164:155;17342:33;;17394:20;;;-1:-1:-1;17437:18:169;17426:30;;17423:50;;;17469:1;17466;17459:12;17423:50;17502:4;17490:17;;-1:-1:-1;17533:14:169;17529:27;;;17519:38;;17516:58;;;17570:1;17567;17560:12;17585:273;17770:6;17762;17757:3;17744:33;17726:3;17796:16;;17821:13;;;17796:16;17585:273;-1:-1:-1;17585:273:169:o;18581:629::-;18699:4;18705:6;18765:11;18752:25;18855:66;18844:8;18828:14;18824:29;18820:102;18800:18;18796:127;18786:155;;18937:1;18934;18927:12;18786:155;18964:33;;19016:20;;;-1:-1:-1;19059:18:169;19048:30;;19045:50;;;19091:1;19088;19081:12;19045:50;19124:4;19112:17;;-1:-1:-1;19175:1:169;19171:14;;;19155;19151:35;19141:46;;19138:66;;;19200:1;19197;19190:12;19215:184;19267:77;19264:1;19257:88;19364:4;19361:1;19354:15;19388:4;19385:1;19378:15;19404:381;19495:4;19553:11;19540:25;19643:66;19632:8;19616:14;19612:29;19608:102;19588:18;19584:127;19574:155;;19725:1;19722;19715:12;19574:155;19746:33;;;;;19404:381;-1:-1:-1;;19404:381:169:o;20375:279::-;20440:9;;;20461:10;;;20458:190;;;20504:77;20501:1;20494:88;20605:4;20602:1;20595:15;20633:4;20630:1;20623:15;20659:184;20711:77;20708:1;20701:88;20808:4;20805:1;20798:15;20832:4;20829:1;20822:15;20848:266;20917:6;20970:2;20958:9;20949:7;20945:23;20941:32;20938:52;;;20986:1;20983;20976:12;20938:52;21025:9;21012:23;21064:1;21057:5;21054:12;21044:40;;21080:1;21077;21070:12;21119:315;21304:6;21293:9;21286:25;21347:2;21342;21331:9;21327:18;21320:30;21267:4;21367:61;21424:2;21413:9;21409:18;21401:6;21393;21367:61;:::i;21439:336::-;21508:6;21561:2;21549:9;21540:7;21536:23;21532:32;21529:52;;;21577:1;21574;21567:12;21529:52;21609:9;21603:16;21659:66;21652:5;21648:78;21641:5;21638:89;21628:117;;21741:1;21738;21731:12;21780:246;21939:2;21928:9;21921:21;21902:4;21959:61;22016:2;22005:9;22001:18;21993:6;21985;21959:61;:::i;23257:322::-;23298:3;23336:5;23330:12;23360:1;23370:128;23384:6;23381:1;23378:13;23370:128;;;23481:4;23466:13;;;23462:24;;23456:31;23443:11;;;23436:52;23399:12;23370:128;;;-1:-1:-1;23553:1:169;23517:16;;23542:13;;;-1:-1:-1;23517:16:169;;23257:322;-1:-1:-1;23257:322:169:o;23584:261::-;23759:3;23784:55;23809:29;23834:3;23826:6;23809:29;:::i;:::-;23801:6;23784:55;:::i;25071:350::-;25256:3;25287:29;25312:3;25304:6;25287:29;:::i;:::-;25325:21;;;-1:-1:-1;;25373:2:169;25362:14;;25355:30;25412:2;25401:14;;25071:350;-1:-1:-1;25071:350:169:o;25426:184::-;25478:77;25475:1;25468:88;25575:4;25572:1;25565:15;25599:4;25596:1;25589:15;25615:844;25769:4;25811:3;25800:9;25796:19;25788:27;;-1:-1:-1;;;;;25922:2:169;25913:6;25907:13;25903:22;25892:9;25885:41;25994:2;25986:4;25978:6;25974:17;25968:24;25964:33;25957:4;25946:9;25942:20;25935:63;26066:2;26058:4;26050:6;26046:17;26040:24;26036:33;26029:4;26018:9;26014:20;26007:63;;26126:4;26118:6;26114:17;26108:24;26101:4;26090:9;26086:20;26079:54;26180:4;26172:6;26168:17;26162:24;26222:1;26208:12;26205:19;26195:207;;26258:77;26255:1;26248:88;26359:4;26356:1;26349:15;26387:4;26384:1;26377:15;26195:207;26440:12;26433:4;26422:9;26418:20;26411:42;;25615:844;;;;:::o;26464:184::-;26534:6;26587:2;26575:9;26566:7;26562:23;26558:32;26555:52;;;26603:1;26600;26593:12;26555:52;-1:-1:-1;26626:16:169;;26464:184;-1:-1:-1;26464:184:169:o;26653:331::-;26758:9;26769;26811:8;26799:10;26796:24;26793:44;;;26833:1;26830;26823:12;26793:44;26862:6;26852:8;26849:20;26846:40;;;26882:1;26879;26872:12;26846:40;-1:-1:-1;;26908:23:169;;;26953:25;;;;;-1:-1:-1;26653:331:169:o;26989:608::-;27088:6;27096;27104;27112;27165:3;27153:9;27144:7;27140:23;27136:33;27133:53;;;27182:1;27179;27172:12;27133:53;27221:9;27208:23;27240:31;27265:5;27240:31;:::i;:::-;27290:5;-1:-1:-1;27347:2:169;27332:18;;27319:32;27360:33;27319:32;27360:33;:::i;:::-;27412:7;-1:-1:-1;27466:2:169;27451:18;;27438:32;;-1:-1:-1;27522:2:169;27507:18;;27494:32;27535:30;27494:32;27535:30;:::i;:::-;26989:608;;;;-1:-1:-1;26989:608:169;;-1:-1:-1;;26989:608:169:o;27602:622::-;27712:6;27720;27728;27736;27789:3;27777:9;27768:7;27764:23;27760:33;27757:53;;;27806:1;27803;27796:12;27757:53;27845:9;27832:23;27864:31;27889:5;27864:31;:::i;:::-;27914:5;-1:-1:-1;27971:2:169;27956:18;;27943:32;27984:33;27943:32;27984:33;:::i;:::-;28036:7;-1:-1:-1;28095:2:169;28080:18;;28067:32;28108:33;28067:32;28108:33;:::i;:::-;27602:622;;;;-1:-1:-1;28160:7:169;;28214:2;28199:18;28186:32;;-1:-1:-1;;27602:622:169:o;28229:991::-;28382:6;28390;28398;28406;28414;28422;28430;28483:3;28471:9;28462:7;28458:23;28454:33;28451:53;;;28500:1;28497;28490:12;28451:53;28539:9;28526:23;28558:31;28583:5;28558:31;:::i;:::-;28608:5;-1:-1:-1;28665:2:169;28650:18;;28637:32;28678:33;28637:32;28678:33;:::i;:::-;28730:7;-1:-1:-1;28789:2:169;28774:18;;28761:32;28802:33;28761:32;28802:33;:::i;:::-;28854:7;-1:-1:-1;28913:2:169;28898:18;;28885:32;28926:33;28885:32;28926:33;:::i;:::-;28978:7;-1:-1:-1;29032:3:169;29017:19;;29004:33;;-1:-1:-1;29089:3:169;29074:19;;29061:33;29103;29061;29103;:::i;:::-;29155:7;29145:17;;;29209:3;29198:9;29194:19;29181:33;29171:43;;28229:991;;;;;;;;;;:::o;29225:472::-;29318:6;29326;29334;29387:2;29375:9;29366:7;29362:23;29358:32;29355:52;;;29403:1;29400;29393:12;29355:52;29442:9;29429:23;29461:31;29486:5;29461:31;:::i;:::-;29511:5;-1:-1:-1;29568:2:169;29553:18;;29540:32;29581:33;29540:32;29581:33;:::i;:::-;29225:472;;29633:7;;-1:-1:-1;;;29687:2:169;29672:18;;;;29659:32;;29225:472::o;29702:758::-;29818:6;29826;29834;29842;29850;29903:3;29891:9;29882:7;29878:23;29874:33;29871:53;;;29920:1;29917;29910:12;29871:53;29959:9;29946:23;29978:31;30003:5;29978:31;:::i;:::-;30028:5;-1:-1:-1;30085:2:169;30070:18;;30057:32;30098:33;30057:32;30098:33;:::i;:::-;30150:7;-1:-1:-1;30209:2:169;30194:18;;30181:32;30222:33;30181:32;30222:33;:::i;:::-;30274:7;-1:-1:-1;30328:2:169;30313:18;;30300:32;;-1:-1:-1;30384:3:169;30369:19;;30356:33;30398:30;30356:33;30398:30;:::i;:::-;30447:7;30437:17;;;29702:758;;;;;;;;:::o;30465:311::-;30495:1;30529:4;30526:1;30522:12;30553:3;30543:191;;30590:77;30587:1;30580:88;30691:4;30688:1;30681:15;30719:4;30716:1;30709:15;30543:191;30766:3;30759:4;30756:1;30752:12;30748:22;30743:27;;;30465:311;;;;:::o", + "linkReferences": {}, + "immutableReferences": { + "65518": [ + { + "start": 824, + "length": 32 + }, + { + "start": 1042, + "length": 32 + }, + { + "start": 1703, + "length": 32 + }, + { + "start": 5408, + "length": 32 + }, + { + "start": 5631, + "length": 32 + } + ], + "65523": [ + { + "start": 407, + "length": 32 + }, + { + "start": 1978, + "length": 32 + }, + { + "start": 6284, + "length": 32 + }, + { + "start": 7724, + "length": 32 + }, + { + "start": 7966, + "length": 32 + }, + { + "start": 8236, + "length": 32 + }, + { + "start": 8971, + "length": 32 + }, + { + "start": 9255, + "length": 32 + }, + { + "start": 12348, + "length": 32 + } + ], + "65528": [ + { + "start": 599, + "length": 32 + }, + { + "start": 1924, + "length": 32 + }, + { + "start": 5852, + "length": 32 + } + ], + "66488": [ + { + "start": 1444, + "length": 32 + } + ], + "66490": [ + { + "start": 1242, + "length": 32 + } + ] + } + }, + "methodIdentifiers": { + "AUTHENTICATOR()": "c6186181", + "BALANCE_MANAGER()": "29bcdc95", + "DOMAIN_SEPARATOR()": "3644e515", + "REPOSITORY()": "6f35d2d2", + "cancelLimitOrder(uint256)": "a5cdc8fc", + "hashBaseTokenData((address,uint256,uint256,uint256,uint256))": "875530ff", + "hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": "e242924e", + "hashQuoteTokenData((address,uint256,uint256,uint256,uint256))": "4c9e03d3", + "hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))": "b11f1262", + "isValidSignature(bytes32,bytes)": "1626ba7e", + "settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))": "cba673a7", + "settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))": "9935c868", + "settleSingleWithPermitsSignatures(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes),(bytes,uint48,uint48))": "db587728", + "settleWithPermitsSignatures(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes),(bytes,uint48,uint48))": "51d46815", + "validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))": "5aa0e95d", + "validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])": "a7ab49bc", + "validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": "fa5cd56c", + "validateSignature(address,bytes32,(uint8,uint8,bytes))": "ae80c584" + }, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.23+commit.f704f362\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IAllowListAuthentication\",\"name\":\"authenticator_\",\"type\":\"address\"},{\"internalType\":\"contract IRepository\",\"name\":\"repository_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"permit2_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ECDSAInvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"ECDSAInvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"ECDSAInvalidSignatureS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAsset\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidBaseTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDestination\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidEIP1271Signature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidEIP712Signature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidETHSignSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFillAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidHooksTarget\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInteractionsBaseTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInteractionsQuoteTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidLendingPoolInteraction\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuoteTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignatureType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSource\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonceInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotMaker\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSolver\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OrderExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PartialFillNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReceiverNotManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrancyGuardReentrantCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignatureIsExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignatureIsNotEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpdatedMakerAmountsTooLow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroMakerAmount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"selector\",\"type\":\"bytes4\"}],\"name\":\"Interaction\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"TradeOrder\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"AUTHENTICATOR\",\"outputs\":[{\"internalType\":\"contract IAllowListAuthentication\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BALANCE_MANAGER\",\"outputs\":[{\"internalType\":\"contract IBalanceManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REPOSITORY\",\"outputs\":[{\"internalType\":\"contract IRepository\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"cancelLimitOrder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"_baseTokenData\",\"type\":\"tuple\"}],\"name\":\"hashBaseTokenData\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"}],\"name\":\"hashOrder\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"_quoteTokenData\",\"type\":\"tuple\"}],\"name\":\"hashQuoteTokenData\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"internalType\":\"struct ILiquoriceSettlement.Single\",\"name\":\"_order\",\"type\":\"tuple\"}],\"name\":\"hashSingleOrder\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_hash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"isValidSignature\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"_interactions\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"beforeSettle\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"afterSettle\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GPv2Interaction.Hooks\",\"name\":\"_hooks\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"}],\"name\":\"settle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"internalType\":\"struct ILiquoriceSettlement.Single\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"}],\"name\":\"settleSingle\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"internalType\":\"struct ILiquoriceSettlement.Single\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint48\",\"name\":\"nonce\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"deadline\",\"type\":\"uint48\"}],\"internalType\":\"struct Signature.TakerPermitInfo\",\"name\":\"_takerPermitInfo\",\"type\":\"tuple\"}],\"name\":\"settleSingleWithPermitsSignatures\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"_interactions\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"beforeSettle\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"afterSettle\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GPv2Interaction.Hooks\",\"name\":\"_hooks\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint48\",\"name\":\"nonce\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"deadline\",\"type\":\"uint48\"}],\"internalType\":\"struct Signature.TakerPermitInfo\",\"name\":\"_takerPermitInfo\",\"type\":\"tuple\"}],\"name\":\"settleWithPermitsSignatures\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IRepository\",\"name\":\"_repository\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"beforeSettle\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"afterSettle\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GPv2Interaction.Hooks\",\"name\":\"_hooks\",\"type\":\"tuple\"}],\"name\":\"validateHooks\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IRepository\",\"name\":\"_repository\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_isPartialFill\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"_interactions\",\"type\":\"tuple[]\"}],\"name\":\"validateInteractions\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"}],\"name\":\"validateOrderAmounts\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_validationAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"_hash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_signature\",\"type\":\"tuple\"}],\"name\":\"validateSignature\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"errors\":{\"ECDSAInvalidSignature()\":[{\"details\":\"The signature derives the `address(0)`.\"}],\"ECDSAInvalidSignatureLength(uint256)\":[{\"details\":\"The signature has an invalid length.\"}],\"ECDSAInvalidSignatureS(bytes32)\":[{\"details\":\"The signature has an S value that is in the upper half order.\"}],\"ReentrancyGuardReentrantCall()\":[{\"details\":\"Unauthorized reentrant call.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC-20 token failed.\"}]},\"events\":{\"Interaction(address,uint256,bytes4)\":{\"params\":{\"selector\":\"Selector of the interaction function\",\"target\":\"Address of the interaction target\",\"value\":\"Value associated with the interaction\"}}},\"kind\":\"dev\",\"methods\":{\"cancelLimitOrder(uint256)\":{\"params\":{\"nonce\":\"Nonce of the order to be canceled\"}},\"hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"params\":{\"_order\":\"Order data to hash\"},\"returns\":{\"_0\":\"bytes32 Hash of the order\"}},\"hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))\":{\"params\":{\"_order\":\"Single order data to hash\"},\"returns\":{\"_0\":\"bytes32 Hash of the single order\"}},\"isValidSignature(bytes32,bytes)\":{\"params\":{\"_hash\":\"Hash of the data\",\"_signature\":\"Signature to validate\"},\"returns\":{\"_0\":\"Magic value if signature is valid, otherwise 0xffffffff\"}},\"settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))\":{\"params\":{\"_filledTakerAmount\":\"Amount filled by the taker\",\"_hooks\":\"Hooks to be called before and after settlement\",\"_interactions\":\"Array of interaction data to be executed during settlement\",\"_makerSignature\":\"Typed signature of the maker\",\"_order\":\"Order data\",\"_signer\":\"Address that signed the order\",\"_takerSignature\":\"Typed signature of the taker\"}},\"settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))\":{\"params\":{\"_filledTakerAmount\":\"Amount filled by the taker\",\"_makerSignature\":\"Signature of the maker\",\"_order\":\"Single order data\",\"_signer\":\"Address that signed the order\",\"_takerSignature\":\"Signature of the taker\"}},\"validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))\":{\"params\":{\"_hooks\":\"Hooks data\",\"_repository\":\"Repository interface\"}},\"validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])\":{\"params\":{\"_interactions\":\"Array of interaction data\",\"_order\":\"Order data\",\"_repository\":\"Repository interface\",\"_signer\":\"Signer address\"}},\"validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"params\":{\"_order\":\"Order data\"}},\"validateSignature(address,bytes32,(uint8,uint8,bytes))\":{\"params\":{\"_hash\":\"Hash of the data\",\"_signature\":\"Signature data\",\"_validationAddress\":\"Address to validate against\"}}},\"title\":\"Liquorice Settlement Contract\",\"version\":1},\"userdoc\":{\"events\":{\"Interaction(address,uint256,bytes4)\":{\"notice\":\"Emitted when an interaction is executed\"}},\"kind\":\"user\",\"methods\":{\"AUTHENTICATOR()\":{\"notice\":\"Authenticator for verifying solvers and makers\"},\"BALANCE_MANAGER()\":{\"notice\":\"Manager for handling balance transfers\"},\"REPOSITORY()\":{\"notice\":\"Repository that stores data for Lending Pools\"},\"cancelLimitOrder(uint256)\":{\"notice\":\"Cancels a limit order by invalidating its nonce\"},\"hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"notice\":\"Computes the hash of an order\"},\"hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))\":{\"notice\":\"Computes the hash of a single order\"},\"isValidSignature(bytes32,bytes)\":{\"notice\":\"Validates a signature\"},\"settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))\":{\"notice\":\"Settles a signed order with the given interactions and hooks\"},\"settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))\":{\"notice\":\"Settles a single order\"},\"validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))\":{\"notice\":\"Validates hooks for an order\"},\"validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])\":{\"notice\":\"Validates interactions for an order\"},\"validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"notice\":\"Validates the amounts in an order\"},\"validateSignature(address,bytes32,(uint8,uint8,bytes))\":{\"notice\":\"Validates a signature\"}},\"notice\":\"Handles settlement of orders and interactions\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/settlement/LiquoriceSettlement.sol\":\"LiquoriceSettlement\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[\":@chainlink/=lib/chainlink/contracts/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/\",\":chainlink/=lib/chainlink/\",\":contracts/=src/contracts/\",\":ds-test/=node_modules/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/\",\":interfaces/=src/interfaces/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/\",\":openzeppelin-upgrades/=lib/openzeppelin-upgrades/\",\":solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/\"]},\"sources\":{\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol\":{\"keccak256\":\"0xc92e946b954f185c3ca5ee56f9721aa73d64464456a46459384cb0ccf3c3856e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ae178b4e7b259557d8b93f3dd4f6f909ac72f914a9e92676e59b8d737f0423e2\",\"dweb:/ipfs/QmXeqyUJYzn6w8wyivQAtSzmwwFQnHaFYPvGad66RW1sPf\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol\":{\"keccak256\":\"0x9b6b3e7803bc5f2f8cd7ad57db8ac1def61a9930a5a3107df4882e028a9605d7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://da62d6be1f5c6edf577f0cb45666a8aa9c2086a4bac87d95d65f02e2f4c36a4b\",\"dweb:/ipfs/QmNkpvBpoCMvX8JwAFNSc5XxJ2q5BXJpL5L1txb4QkqVFF\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol\":{\"keccak256\":\"0xde7e9fd9aee8d4f40772f96bb3b58836cbc6dfc0227014a061947f8821ea9724\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://11fea9f8bc98949ac6709f0c1699db7430d2948137aa94d5a9e95a91f61a710a\",\"dweb:/ipfs/QmQdfRXxQjwP6yn3DVo1GHPpriKNcFghSPi94Z1oKEFUNS\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol\":{\"keccak256\":\"0xce41876e78d1badc0512229b4d14e4daf83bc1003d7f83978d18e0e56f965b9c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a2608291cb038b388d80b79a06b6118a42f7894ff67b7da10ec0dbbf5b2973ba\",\"dweb:/ipfs/QmWohqcBLbcxmA4eGPhZDXe5RYMMEEpFq22nfkaUMvTfw1\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://df6f0c459663c9858b6cba2cda1d14a7d05a985bed6d2de72bd8e78c25ee79db\",\"dweb:/ipfs/QmeTTxZ7qVk9rjEv2R4CpCwdf8UMCcRqDNMvzNxHc3Fnn9\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol\":{\"keccak256\":\"0x6dd0cb67846da3fa1241c520faaa215d6bec8226e37beac6056c51e8af44d24e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://650e533e62b30dcc6edea2b6c91358d5659da3bde42e56adf7316c493b916a15\",\"dweb:/ipfs/QmYkmK2vPE6FjdAoQVpZSJxamTLGno9wzGS495TcMNFViV\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Panic.sol\":{\"keccak256\":\"0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a\",\"dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol\":{\"keccak256\":\"0x11a5a79827df29e915a12740caf62fe21ebe27c08c9ae3e09abe9ee3ba3866d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3cf0c69ab827e3251db9ee6a50647d62c90ba580a4d7bbff21f2bea39e7b2f4a\",\"dweb:/ipfs/QmZiKwtKU1SBX4RGfQtY7PZfiapbbu6SZ9vizGQD9UHjRA\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9\",\"dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x79796192ec90263f21b464d5bc90b777a525971d3de8232be80d9c4f9fb353b8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f6fda447a62815e8064f47eff0dd1cf58d9207ad69b5d32280f8d7ed1d1e4621\",\"dweb:/ipfs/QmfDRc7pxfaXB2Dh9np5Uf29Na3pQ7tafRS684wd3GLjVL\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0x6f61a65c733690afafb4cf528b5677e704828c8350b60b948dbc1d3bb6d7689c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://00265b985b303af62ee243e10db819fa8cf890d9f122f82f4f03f55b02f62654\",\"dweb:/ipfs/QmNneFqZn2uKK6dECxatH6aENk1EMCTETi58dGaz5NCWQe\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol\":{\"keccak256\":\"0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8\",\"dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy\"]},\"src/contracts/lib/GPv2Interaction.sol\":{\"keccak256\":\"0x55968a83f6ae3d8d806b8faf02360abc676fb7476d05f33c0c9d324e6336fd0f\",\"license\":\"LGPL-3.0-or-later\",\"urls\":[\"bzz-raw://2d813e60c3fa006d02c8fd1aed73d2d47f9f153ac3c410d408384f3084e46de3\",\"dweb:/ipfs/QmdNyQMmyscMH6CVUkhQQfGdKdxgqhqDEe5K4iwrvcWDsk\"]},\"src/contracts/lib/Signature.sol\":{\"keccak256\":\"0xc084fe793244e2e7b0f4a51440df7dbf97d39b4ad6450a2b8a082cb6d86993b5\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://9bff9732e68149a83f2e044c7f1700432997750166cd15f4a54f73bd68a475aa\",\"dweb:/ipfs/QmZJMNppHQ3nUDcJhAkrMYa4QWhGLDr4Tzah6LndgrDCib\"]},\"src/contracts/settlement/BalanceManager.sol\":{\"keccak256\":\"0x82d5d0de5cf88ff8882f1f7a2d05b98ed32bb3f2a6b9eab728ce55ae943e67c3\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://ebcbe822ad5c68896a12ecd60e17ba6a2ed0ba8e0544c7ad54d88d1c25206b5c\",\"dweb:/ipfs/QmYEZeKUEz7Nw6MW9uZHnXvkeRTmmcS1WZhx77s9kUWSWw\"]},\"src/contracts/settlement/LiquoriceSettlement.sol\":{\"keccak256\":\"0xcac528919829fc8e021cec4325b38835866a7d0630b61349deae6ecfbe0ddaef\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://6d6dafbba3885b42cb97be6d190ac1f611548ceb2116e9b6ed7da9bf422c8b58\",\"dweb:/ipfs/QmZQk6WQNgYqsu9Z85tPF2VQGXgaYzvpEqc7VEmJ4zEEJU\"]},\"src/contracts/settlement/Signing.sol\":{\"keccak256\":\"0xad9e59ae740627e5b71fa1ebde019999084480664d06d18f0a01e4d31fa32ef6\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://ea0e0021cd0074292b04f9921f6ca3cc77a6799c86cacabb9dc6ff7dadbd7933\",\"dweb:/ipfs/QmPjY69PntfUGW5eNrNe98DCTemq6daRqUiLFkcYvVWuvh\"]},\"src/interfaces/IACLManager.sol\":{\"keccak256\":\"0xeee5cbedcfaff01733979b8f439a817aa67b09d9e330d21e11f180dceebed024\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://814431cd9df23d0d7cc0f9761927e2aa18fc7fa599f34422f332ee6352580d69\",\"dweb:/ipfs/QmXLdGsdMyeX5j64rAaByz35SwEMPMQ7usXwruWjEPo6Cz\"]},\"src/interfaces/IAllowListAuthentication.sol\":{\"keccak256\":\"0xbabb9eda80757d9355ab9863fccb3fdb1f15c1cbce458c3236d792d007077a9e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f6fa97e90b315ffc3cae3998adda6810c856ea96be015e797723e13b436d1a10\",\"dweb:/ipfs/Qme1dzXXcMDQpeqyqfuSbZDY6GKWjyrRBQrNDjitPeXQEF\"]},\"src/interfaces/IBalanceManager.sol\":{\"keccak256\":\"0xc4cff6f33170df6d91a866ee69263c9b90091e94027bea04038558c315e6e127\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://867164a381fb78da320c89db6b15978becd49be61e2349abc805362904bffb4e\",\"dweb:/ipfs/QmPY9UYCi9YVdCC8A1UxmTPcnV5BmMj93Gq1nqxBv4fMJ7\"]},\"src/interfaces/IInterestRateModel.sol\":{\"keccak256\":\"0xccd4c1dea98176c392de07cb8f5a2ac969405090d42d831310fa53464c0d9264\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a22b5b87be29e616142b6c4677e109e9246157c4b7e6378334fbc7ba403d82de\",\"dweb:/ipfs/QmXmSF34VsktTfqSCJU8Mz9sTaXGVk7xdYQwr9NcsR3k43\"]},\"src/interfaces/ILiquoriceSettlement.sol\":{\"keccak256\":\"0xa4a36d51f174d9994c39287f89e63bbea57ff5adcd2a9bc649c67bb5cae75272\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8562fe9fc033c3e3320c5d95ad10e49f5e23ea50a5e9eaf186cbf53d9f1ce7a6\",\"dweb:/ipfs/QmXKSjRi8oxmS5xd5V95HofYtFzYfehbL6s8t2MKoXR7y1\"]},\"src/interfaces/IPriceProvider.sol\":{\"keccak256\":\"0x75812be8d692287010f5ee9ce13556df1bd8299faa64b42c49cd08cf7cc53847\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://623d4faa57b078a33a2afe0d13fc426c4a750ae7f07f9d826000047dab54148e\",\"dweb:/ipfs/QmYmFpZnLug6FBG9C8s1mxPBjZHwiCk7cRBC7A9WXtyGKE\"]},\"src/interfaces/IRepository.sol\":{\"keccak256\":\"0xf08a5812ce10042564d518994db487c49d9f35d511da07a5103b9b886b6e2607\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b602c9f5a61c9796f711330ee56d4f0287adc656c686acf391d4e8c45453e6d0\",\"dweb:/ipfs/QmQ7XJ1qERgRxWurpkS3t1XDtuBUTpQEz14h4eXBc8vp9t\"]},\"src/interfaces/external/permit/IAllowanceTransfer.sol\":{\"keccak256\":\"0x23986b17f0c10296cb8afadb43014cd7901f56dac5ba85067d18ca7db7d3e37e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5f6ec55ce038e045b15a89a7f19fa45aa09d42a52517dd1846968d16777d3a9b\",\"dweb:/ipfs/QmZXthQLUtRFgqGv3bFbijmNk5Vviacrf7VnRDbXEQjdBQ\"]},\"src/interfaces/external/permit/IEIP712.sol\":{\"keccak256\":\"0x07e44e64248ed6316fe1db6f44c80468b950e6d1ab4bfdf21a65cbbd27718f77\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://58487548bc5289e7f5a4d4c278e5c7e9a7829d8a5be024a42938943f8c8fb63b\",\"dweb:/ipfs/QmYg63mq3SgXH6H4Wyvznb1E5fEjw6W7NeLASUcRjMuKYa\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.23+commit.f704f362" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [ + { + "internalType": "contract IAllowListAuthentication", + "name": "authenticator_", + "type": "address" + }, + { + "internalType": "contract IRepository", + "name": "repository_", + "type": "address" + }, + { + "internalType": "address", + "name": "permit2_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "type": "error", + "name": "ECDSAInvalidSignature" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "type": "error", + "name": "ECDSAInvalidSignatureLength" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "type": "error", + "name": "ECDSAInvalidSignatureS" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidAmount" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidAsset" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidBaseTokenAmounts" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidDestination" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidEIP1271Signature" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidEIP712Signature" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidETHSignSignature" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidFillAmount" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidHooksTarget" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidInteractionsBaseTokenAmounts" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidInteractionsQuoteTokenAmounts" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidLendingPoolInteraction" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidQuoteTokenAmounts" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidSignatureType" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidSigner" + }, + { + "inputs": [], + "type": "error", + "name": "InvalidSource" + }, + { + "inputs": [], + "type": "error", + "name": "NonceInvalid" + }, + { + "inputs": [], + "type": "error", + "name": "NotMaker" + }, + { + "inputs": [], + "type": "error", + "name": "NotSolver" + }, + { + "inputs": [], + "type": "error", + "name": "OrderExpired" + }, + { + "inputs": [], + "type": "error", + "name": "PartialFillNotSupported" + }, + { + "inputs": [], + "type": "error", + "name": "ReceiverNotManager" + }, + { + "inputs": [], + "type": "error", + "name": "ReentrancyGuardReentrantCall" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "type": "error", + "name": "SafeERC20FailedOperation" + }, + { + "inputs": [], + "type": "error", + "name": "SignatureIsExpired" + }, + { + "inputs": [], + "type": "error", + "name": "SignatureIsNotEmpty" + }, + { + "inputs": [], + "type": "error", + "name": "UpdatedMakerAmountsTooLow" + }, + { + "inputs": [], + "type": "error", + "name": "ZeroMakerAmount" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address", + "indexed": true + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256", + "indexed": false + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4", + "indexed": false + } + ], + "type": "event", + "name": "Interaction", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "string", + "name": "rfqId", + "type": "string", + "indexed": true + }, + { + "internalType": "address", + "name": "trader", + "type": "address", + "indexed": false + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address", + "indexed": false + }, + { + "internalType": "address", + "name": "baseToken", + "type": "address", + "indexed": false + }, + { + "internalType": "address", + "name": "quoteToken", + "type": "address", + "indexed": false + }, + { + "internalType": "uint256", + "name": "baseTokenAmount", + "type": "uint256", + "indexed": false + }, + { + "internalType": "uint256", + "name": "quoteTokenAmount", + "type": "uint256", + "indexed": false + }, + { + "internalType": "address", + "name": "recipient", + "type": "address", + "indexed": false + } + ], + "type": "event", + "name": "TradeOrder", + "anonymous": false + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "AUTHENTICATOR", + "outputs": [ + { + "internalType": "contract IAllowListAuthentication", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "BALANCE_MANAGER", + "outputs": [ + { + "internalType": "contract IBalanceManager", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "REPOSITORY", + "outputs": [ + { + "internalType": "contract IRepository", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "cancelLimitOrder" + }, + { + "inputs": [ + { + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "name": "_baseTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRecipient", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRepay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toSupply", + "type": "uint256" + } + ] + } + ], + "stateMutability": "pure", + "type": "function", + "name": "hashBaseTokenData", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "struct ILiquoriceSettlement.Order", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "name": "baseTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRecipient", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRepay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toSupply", + "type": "uint256" + } + ] + }, + { + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "name": "quoteTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toTrader", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toWithdraw", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toBorrow", + "type": "uint256" + } + ] + } + ] + } + ], + "stateMutability": "view", + "type": "function", + "name": "hashOrder", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "name": "_quoteTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toTrader", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toWithdraw", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toBorrow", + "type": "uint256" + } + ] + } + ], + "stateMutability": "pure", + "type": "function", + "name": "hashQuoteTokenData", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "struct ILiquoriceSettlement.Single", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "address", + "name": "baseToken", + "type": "address" + }, + { + "internalType": "address", + "name": "quoteToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "baseTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quoteTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ] + } + ], + "stateMutability": "view", + "type": "function", + "name": "hashSingleOrder", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_hash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function", + "name": "isValidSignature", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_signer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_filledTakerAmount", + "type": "uint256" + }, + { + "internalType": "struct ILiquoriceSettlement.Order", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "name": "baseTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRecipient", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRepay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toSupply", + "type": "uint256" + } + ] + }, + { + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "name": "quoteTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toTrader", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toWithdraw", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toBorrow", + "type": "uint256" + } + ] + } + ] + }, + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "_interactions", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + }, + { + "internalType": "struct GPv2Interaction.Hooks", + "name": "_hooks", + "type": "tuple", + "components": [ + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "beforeSettle", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + }, + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "afterSettle", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + } + ] + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_makerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_takerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "settle" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_signer", + "type": "address" + }, + { + "internalType": "struct ILiquoriceSettlement.Single", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "address", + "name": "baseToken", + "type": "address" + }, + { + "internalType": "address", + "name": "quoteToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "baseTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quoteTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ] + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_makerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + }, + { + "internalType": "uint256", + "name": "_filledTakerAmount", + "type": "uint256" + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_takerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + } + ], + "stateMutability": "payable", + "type": "function", + "name": "settleSingle" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_signer", + "type": "address" + }, + { + "internalType": "struct ILiquoriceSettlement.Single", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "address", + "name": "baseToken", + "type": "address" + }, + { + "internalType": "address", + "name": "quoteToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "baseTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quoteTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ] + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_makerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + }, + { + "internalType": "uint256", + "name": "_filledTakerAmount", + "type": "uint256" + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_takerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + }, + { + "internalType": "struct Signature.TakerPermitInfo", + "name": "_takerPermitInfo", + "type": "tuple", + "components": [ + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + } + ] + } + ], + "stateMutability": "payable", + "type": "function", + "name": "settleSingleWithPermitsSignatures" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_signer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_filledTakerAmount", + "type": "uint256" + }, + { + "internalType": "struct ILiquoriceSettlement.Order", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "name": "baseTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRecipient", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRepay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toSupply", + "type": "uint256" + } + ] + }, + { + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "name": "quoteTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toTrader", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toWithdraw", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toBorrow", + "type": "uint256" + } + ] + } + ] + }, + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "_interactions", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + }, + { + "internalType": "struct GPv2Interaction.Hooks", + "name": "_hooks", + "type": "tuple", + "components": [ + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "beforeSettle", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + }, + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "afterSettle", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + } + ] + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_makerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_takerSignature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + }, + { + "internalType": "struct Signature.TakerPermitInfo", + "name": "_takerPermitInfo", + "type": "tuple", + "components": [ + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "deadline", + "type": "uint48" + } + ] + } + ], + "stateMutability": "payable", + "type": "function", + "name": "settleWithPermitsSignatures" + }, + { + "inputs": [ + { + "internalType": "contract IRepository", + "name": "_repository", + "type": "address" + }, + { + "internalType": "struct GPv2Interaction.Hooks", + "name": "_hooks", + "type": "tuple", + "components": [ + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "beforeSettle", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + }, + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "afterSettle", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + } + ] + } + ], + "stateMutability": "view", + "type": "function", + "name": "validateHooks" + }, + { + "inputs": [ + { + "internalType": "contract IRepository", + "name": "_repository", + "type": "address" + }, + { + "internalType": "address", + "name": "_signer", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isPartialFill", + "type": "bool" + }, + { + "internalType": "struct ILiquoriceSettlement.Order", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "name": "baseTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRecipient", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRepay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toSupply", + "type": "uint256" + } + ] + }, + { + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "name": "quoteTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toTrader", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toWithdraw", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toBorrow", + "type": "uint256" + } + ] + } + ] + }, + { + "internalType": "struct GPv2Interaction.Data[]", + "name": "_interactions", + "type": "tuple[]", + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ] + } + ], + "stateMutability": "view", + "type": "function", + "name": "validateInteractions" + }, + { + "inputs": [ + { + "internalType": "struct ILiquoriceSettlement.Order", + "name": "_order", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "rfqId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "effectiveTrader", + "type": "address" + }, + { + "internalType": "uint256", + "name": "quoteExpiry", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minFillAmount", + "type": "uint256" + }, + { + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "name": "baseTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRecipient", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toRepay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toSupply", + "type": "uint256" + } + ] + }, + { + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "name": "quoteTokenData", + "type": "tuple", + "components": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toTrader", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toWithdraw", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toBorrow", + "type": "uint256" + } + ] + } + ] + } + ], + "stateMutability": "pure", + "type": "function", + "name": "validateOrderAmounts" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_validationAddress", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_hash", + "type": "bytes32" + }, + { + "internalType": "struct Signature.TypedSignature", + "name": "_signature", + "type": "tuple", + "components": [ + { + "internalType": "enum Signature.Type", + "name": "signatureType", + "type": "uint8" + }, + { + "internalType": "enum Signature.TransferCommand", + "name": "transferCommand", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "signatureBytes", + "type": "bytes" + } + ] + } + ], + "stateMutability": "view", + "type": "function", + "name": "validateSignature" + }, + { + "inputs": [], + "stateMutability": "payable", + "type": "receive" + } + ], + "devdoc": { + "kind": "dev", + "methods": { + "cancelLimitOrder(uint256)": { + "params": { + "nonce": "Nonce of the order to be canceled" + } + }, + "hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { + "params": { + "_order": "Order data to hash" + }, + "returns": { + "_0": "bytes32 Hash of the order" + } + }, + "hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))": { + "params": { + "_order": "Single order data to hash" + }, + "returns": { + "_0": "bytes32 Hash of the single order" + } + }, + "isValidSignature(bytes32,bytes)": { + "params": { + "_hash": "Hash of the data", + "_signature": "Signature to validate" + }, + "returns": { + "_0": "Magic value if signature is valid, otherwise 0xffffffff" + } + }, + "settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))": { + "params": { + "_filledTakerAmount": "Amount filled by the taker", + "_hooks": "Hooks to be called before and after settlement", + "_interactions": "Array of interaction data to be executed during settlement", + "_makerSignature": "Typed signature of the maker", + "_order": "Order data", + "_signer": "Address that signed the order", + "_takerSignature": "Typed signature of the taker" + } + }, + "settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))": { + "params": { + "_filledTakerAmount": "Amount filled by the taker", + "_makerSignature": "Signature of the maker", + "_order": "Single order data", + "_signer": "Address that signed the order", + "_takerSignature": "Signature of the taker" + } + }, + "validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))": { + "params": { + "_hooks": "Hooks data", + "_repository": "Repository interface" + } + }, + "validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])": { + "params": { + "_interactions": "Array of interaction data", + "_order": "Order data", + "_repository": "Repository interface", + "_signer": "Signer address" + } + }, + "validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { + "params": { + "_order": "Order data" + } + }, + "validateSignature(address,bytes32,(uint8,uint8,bytes))": { + "params": { + "_hash": "Hash of the data", + "_signature": "Signature data", + "_validationAddress": "Address to validate against" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "AUTHENTICATOR()": { + "notice": "Authenticator for verifying solvers and makers" + }, + "BALANCE_MANAGER()": { + "notice": "Manager for handling balance transfers" + }, + "REPOSITORY()": { + "notice": "Repository that stores data for Lending Pools" + }, + "cancelLimitOrder(uint256)": { + "notice": "Cancels a limit order by invalidating its nonce" + }, + "hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { + "notice": "Computes the hash of an order" + }, + "hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))": { + "notice": "Computes the hash of a single order" + }, + "isValidSignature(bytes32,bytes)": { + "notice": "Validates a signature" + }, + "settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))": { + "notice": "Settles a signed order with the given interactions and hooks" + }, + "settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))": { + "notice": "Settles a single order" + }, + "validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))": { + "notice": "Validates hooks for an order" + }, + "validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])": { + "notice": "Validates interactions for an order" + }, + "validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { + "notice": "Validates the amounts in an order" + }, + "validateSignature(address,bytes32,(uint8,uint8,bytes))": { + "notice": "Validates a signature" + } + }, + "version": 1 + } + }, + "settings": { + "remappings": [ + "@chainlink/=lib/chainlink/contracts/", + "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", + "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/", + "chainlink/=lib/chainlink/", + "contracts/=src/contracts/", + "ds-test/=node_modules/ds-test/src/", + "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", + "forge-std/=lib/forge-std/src/", + "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/", + "interfaces/=src/interfaces/", + "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", + "openzeppelin-contracts/=lib/openzeppelin-contracts/", + "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", + "openzeppelin-upgrades/=lib/openzeppelin-upgrades/", + "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/" + ], + "optimizer": { + "enabled": true, + "runs": 10000 + }, + "metadata": { + "bytecodeHash": "ipfs" + }, + "compilationTarget": { + "src/contracts/settlement/LiquoriceSettlement.sol": "LiquoriceSettlement" + }, + "evmVersion": "shanghai", + "libraries": {} + }, + "sources": { + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol": { + "keccak256": "0xc92e946b954f185c3ca5ee56f9721aa73d64464456a46459384cb0ccf3c3856e", + "urls": [ + "bzz-raw://ae178b4e7b259557d8b93f3dd4f6f909ac72f914a9e92676e59b8d737f0423e2", + "dweb:/ipfs/QmXeqyUJYzn6w8wyivQAtSzmwwFQnHaFYPvGad66RW1sPf" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol": { + "keccak256": "0x9b6b3e7803bc5f2f8cd7ad57db8ac1def61a9930a5a3107df4882e028a9605d7", + "urls": [ + "bzz-raw://da62d6be1f5c6edf577f0cb45666a8aa9c2086a4bac87d95d65f02e2f4c36a4b", + "dweb:/ipfs/QmNkpvBpoCMvX8JwAFNSc5XxJ2q5BXJpL5L1txb4QkqVFF" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol": { + "keccak256": "0xde7e9fd9aee8d4f40772f96bb3b58836cbc6dfc0227014a061947f8821ea9724", + "urls": [ + "bzz-raw://11fea9f8bc98949ac6709f0c1699db7430d2948137aa94d5a9e95a91f61a710a", + "dweb:/ipfs/QmQdfRXxQjwP6yn3DVo1GHPpriKNcFghSPi94Z1oKEFUNS" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol": { + "keccak256": "0xce41876e78d1badc0512229b4d14e4daf83bc1003d7f83978d18e0e56f965b9c", + "urls": [ + "bzz-raw://a2608291cb038b388d80b79a06b6118a42f7894ff67b7da10ec0dbbf5b2973ba", + "dweb:/ipfs/QmWohqcBLbcxmA4eGPhZDXe5RYMMEEpFq22nfkaUMvTfw1" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": { + "keccak256": "0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7", + "urls": [ + "bzz-raw://df6f0c459663c9858b6cba2cda1d14a7d05a985bed6d2de72bd8e78c25ee79db", + "dweb:/ipfs/QmeTTxZ7qVk9rjEv2R4CpCwdf8UMCcRqDNMvzNxHc3Fnn9" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": { + "keccak256": "0x6dd0cb67846da3fa1241c520faaa215d6bec8226e37beac6056c51e8af44d24e", + "urls": [ + "bzz-raw://650e533e62b30dcc6edea2b6c91358d5659da3bde42e56adf7316c493b916a15", + "dweb:/ipfs/QmYkmK2vPE6FjdAoQVpZSJxamTLGno9wzGS495TcMNFViV" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Panic.sol": { + "keccak256": "0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a", + "urls": [ + "bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a", + "dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol": { + "keccak256": "0x11a5a79827df29e915a12740caf62fe21ebe27c08c9ae3e09abe9ee3ba3866d3", + "urls": [ + "bzz-raw://3cf0c69ab827e3251db9ee6a50647d62c90ba580a4d7bbff21f2bea39e7b2f4a", + "dweb:/ipfs/QmZiKwtKU1SBX4RGfQtY7PZfiapbbu6SZ9vizGQD9UHjRA" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": { + "keccak256": "0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84", + "urls": [ + "bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9", + "dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": { + "keccak256": "0x79796192ec90263f21b464d5bc90b777a525971d3de8232be80d9c4f9fb353b8", + "urls": [ + "bzz-raw://f6fda447a62815e8064f47eff0dd1cf58d9207ad69b5d32280f8d7ed1d1e4621", + "dweb:/ipfs/QmfDRc7pxfaXB2Dh9np5Uf29Na3pQ7tafRS684wd3GLjVL" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/Math.sol": { + "keccak256": "0x6f61a65c733690afafb4cf528b5677e704828c8350b60b948dbc1d3bb6d7689c", + "urls": [ + "bzz-raw://00265b985b303af62ee243e10db819fa8cf890d9f122f82f4f03f55b02f62654", + "dweb:/ipfs/QmNneFqZn2uKK6dECxatH6aENk1EMCTETi58dGaz5NCWQe" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol": { + "keccak256": "0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54", + "urls": [ + "bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8", + "dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy" + ], + "license": "MIT" + }, + "src/contracts/lib/GPv2Interaction.sol": { + "keccak256": "0x55968a83f6ae3d8d806b8faf02360abc676fb7476d05f33c0c9d324e6336fd0f", + "urls": [ + "bzz-raw://2d813e60c3fa006d02c8fd1aed73d2d47f9f153ac3c410d408384f3084e46de3", + "dweb:/ipfs/QmdNyQMmyscMH6CVUkhQQfGdKdxgqhqDEe5K4iwrvcWDsk" + ], + "license": "LGPL-3.0-or-later" + }, + "src/contracts/lib/Signature.sol": { + "keccak256": "0xc084fe793244e2e7b0f4a51440df7dbf97d39b4ad6450a2b8a082cb6d86993b5", + "urls": [ + "bzz-raw://9bff9732e68149a83f2e044c7f1700432997750166cd15f4a54f73bd68a475aa", + "dweb:/ipfs/QmZJMNppHQ3nUDcJhAkrMYa4QWhGLDr4Tzah6LndgrDCib" + ], + "license": "BUSL-1.1" + }, + "src/contracts/settlement/BalanceManager.sol": { + "keccak256": "0x82d5d0de5cf88ff8882f1f7a2d05b98ed32bb3f2a6b9eab728ce55ae943e67c3", + "urls": [ + "bzz-raw://ebcbe822ad5c68896a12ecd60e17ba6a2ed0ba8e0544c7ad54d88d1c25206b5c", + "dweb:/ipfs/QmYEZeKUEz7Nw6MW9uZHnXvkeRTmmcS1WZhx77s9kUWSWw" + ], + "license": "BUSL-1.1" + }, + "src/contracts/settlement/LiquoriceSettlement.sol": { + "keccak256": "0xcac528919829fc8e021cec4325b38835866a7d0630b61349deae6ecfbe0ddaef", + "urls": [ + "bzz-raw://6d6dafbba3885b42cb97be6d190ac1f611548ceb2116e9b6ed7da9bf422c8b58", + "dweb:/ipfs/QmZQk6WQNgYqsu9Z85tPF2VQGXgaYzvpEqc7VEmJ4zEEJU" + ], + "license": "BUSL-1.1" + }, + "src/contracts/settlement/Signing.sol": { + "keccak256": "0xad9e59ae740627e5b71fa1ebde019999084480664d06d18f0a01e4d31fa32ef6", + "urls": [ + "bzz-raw://ea0e0021cd0074292b04f9921f6ca3cc77a6799c86cacabb9dc6ff7dadbd7933", + "dweb:/ipfs/QmPjY69PntfUGW5eNrNe98DCTemq6daRqUiLFkcYvVWuvh" + ], + "license": "BUSL-1.1" + }, + "src/interfaces/IACLManager.sol": { + "keccak256": "0xeee5cbedcfaff01733979b8f439a817aa67b09d9e330d21e11f180dceebed024", + "urls": [ + "bzz-raw://814431cd9df23d0d7cc0f9761927e2aa18fc7fa599f34422f332ee6352580d69", + "dweb:/ipfs/QmXLdGsdMyeX5j64rAaByz35SwEMPMQ7usXwruWjEPo6Cz" + ], + "license": "MIT" + }, + "src/interfaces/IAllowListAuthentication.sol": { + "keccak256": "0xbabb9eda80757d9355ab9863fccb3fdb1f15c1cbce458c3236d792d007077a9e", + "urls": [ + "bzz-raw://f6fa97e90b315ffc3cae3998adda6810c856ea96be015e797723e13b436d1a10", + "dweb:/ipfs/Qme1dzXXcMDQpeqyqfuSbZDY6GKWjyrRBQrNDjitPeXQEF" + ], + "license": "MIT" + }, + "src/interfaces/IBalanceManager.sol": { + "keccak256": "0xc4cff6f33170df6d91a866ee69263c9b90091e94027bea04038558c315e6e127", + "urls": [ + "bzz-raw://867164a381fb78da320c89db6b15978becd49be61e2349abc805362904bffb4e", + "dweb:/ipfs/QmPY9UYCi9YVdCC8A1UxmTPcnV5BmMj93Gq1nqxBv4fMJ7" + ], + "license": "MIT" + }, + "src/interfaces/IInterestRateModel.sol": { + "keccak256": "0xccd4c1dea98176c392de07cb8f5a2ac969405090d42d831310fa53464c0d9264", + "urls": [ + "bzz-raw://a22b5b87be29e616142b6c4677e109e9246157c4b7e6378334fbc7ba403d82de", + "dweb:/ipfs/QmXmSF34VsktTfqSCJU8Mz9sTaXGVk7xdYQwr9NcsR3k43" + ], + "license": "MIT" + }, + "src/interfaces/ILiquoriceSettlement.sol": { + "keccak256": "0xa4a36d51f174d9994c39287f89e63bbea57ff5adcd2a9bc649c67bb5cae75272", + "urls": [ + "bzz-raw://8562fe9fc033c3e3320c5d95ad10e49f5e23ea50a5e9eaf186cbf53d9f1ce7a6", + "dweb:/ipfs/QmXKSjRi8oxmS5xd5V95HofYtFzYfehbL6s8t2MKoXR7y1" + ], + "license": "MIT" + }, + "src/interfaces/IPriceProvider.sol": { + "keccak256": "0x75812be8d692287010f5ee9ce13556df1bd8299faa64b42c49cd08cf7cc53847", + "urls": [ + "bzz-raw://623d4faa57b078a33a2afe0d13fc426c4a750ae7f07f9d826000047dab54148e", + "dweb:/ipfs/QmYmFpZnLug6FBG9C8s1mxPBjZHwiCk7cRBC7A9WXtyGKE" + ], + "license": "MIT" + }, + "src/interfaces/IRepository.sol": { + "keccak256": "0xf08a5812ce10042564d518994db487c49d9f35d511da07a5103b9b886b6e2607", + "urls": [ + "bzz-raw://b602c9f5a61c9796f711330ee56d4f0287adc656c686acf391d4e8c45453e6d0", + "dweb:/ipfs/QmQ7XJ1qERgRxWurpkS3t1XDtuBUTpQEz14h4eXBc8vp9t" + ], + "license": "MIT" + }, + "src/interfaces/external/permit/IAllowanceTransfer.sol": { + "keccak256": "0x23986b17f0c10296cb8afadb43014cd7901f56dac5ba85067d18ca7db7d3e37e", + "urls": [ + "bzz-raw://5f6ec55ce038e045b15a89a7f19fa45aa09d42a52517dd1846968d16777d3a9b", + "dweb:/ipfs/QmZXthQLUtRFgqGv3bFbijmNk5Vviacrf7VnRDbXEQjdBQ" + ], + "license": "MIT" + }, + "src/interfaces/external/permit/IEIP712.sol": { + "keccak256": "0x07e44e64248ed6316fe1db6f44c80468b950e6d1ab4bfdf21a65cbbd27718f77", + "urls": [ + "bzz-raw://58487548bc5289e7f5a4d4c278e5c7e9a7829d8a5be024a42938943f8c8fb63b", + "dweb:/ipfs/QmYg63mq3SgXH6H4Wyvznb1E5fEjw6W7NeLASUcRjMuKYa" + ], + "license": "MIT" + } + }, + "version": 1 + }, + "id": 90, + "_disabled": [ + { + "type": "function", + "name": "REPOSITORY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IRepository" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "cancelLimitOrder", + "inputs": [ + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hashBaseTokenData", + "inputs": [ + { + "name": "_baseTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRecipient", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRepay", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toSupply", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "hashOrder", + "inputs": [ + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Order", + "components": [ + { + "name": "market", + "type": "address", + "internalType": "address" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "baseTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRecipient", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRepay", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toSupply", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "quoteTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toTrader", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toBorrow", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hashQuoteTokenData", + "inputs": [ + { + "name": "_quoteTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toTrader", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toBorrow", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "settleSingleWithPermitsSignatures", + "inputs": [ + { + "name": "_signer", + "type": "address", + "internalType": "address" + }, + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Single", + "components": [ + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "baseToken", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteToken", + "type": "address", + "internalType": "address" + }, + { + "name": "baseTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "_makerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_filledTakerAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_takerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_takerPermitInfo", + "type": "tuple", + "internalType": "struct Signature.TakerPermitInfo", + "components": [ + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "nonce", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "settleWithPermitsSignatures", + "inputs": [ + { + "name": "_signer", + "type": "address", + "internalType": "address" + }, + { + "name": "_filledTakerAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Order", + "components": [ + { + "name": "market", + "type": "address", + "internalType": "address" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "baseTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRecipient", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRepay", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toSupply", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "quoteTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toTrader", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toBorrow", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + }, + { + "name": "_interactions", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_hooks", + "type": "tuple", + "internalType": "struct GPv2Interaction.Hooks", + "components": [ + { + "name": "beforeSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "afterSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "_makerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_takerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_takerPermitInfo", + "type": "tuple", + "internalType": "struct Signature.TakerPermitInfo", + "components": [ + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "nonce", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "deadline", + "type": "uint48", + "internalType": "uint48" + } + ] + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "validateHooks", + "inputs": [ + { + "name": "_repository", + "type": "address", + "internalType": "contract IRepository" + }, + { + "name": "_hooks", + "type": "tuple", + "internalType": "struct GPv2Interaction.Hooks", + "components": [ + { + "name": "beforeSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "afterSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "validateInteractions", + "inputs": [ + { + "name": "_repository", + "type": "address", + "internalType": "contract IRepository" + }, + { + "name": "_signer", + "type": "address", + "internalType": "address" + }, + { + "name": "_isPartialFill", + "type": "bool", + "internalType": "bool" + }, + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Order", + "components": [ + { + "name": "market", + "type": "address", + "internalType": "address" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "baseTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRecipient", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRepay", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toSupply", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "quoteTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toTrader", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toBorrow", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + }, + { + "name": "_interactions", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "validateOrderAmounts", + "inputs": [ + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Order", + "components": [ + { + "name": "market", + "type": "address", + "internalType": "address" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "baseTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRecipient", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRepay", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toSupply", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "quoteTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toTrader", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toBorrow", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "validateSignature", + "inputs": [ + { + "name": "_validationAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "_hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_signature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "view" + } + ] +} diff --git a/contracts/artifacts/MockERC4626Wrapper.json b/contracts/artifacts/MockERC4626Wrapper.json new file mode 100644 index 0000000000..4bbe02465e --- /dev/null +++ b/contracts/artifacts/MockERC4626Wrapper.json @@ -0,0 +1,240 @@ +{ + "abi": [ + { + "type": "constructor", + "inputs": [ + { + "name": "_asset", + "type": "address", + "internalType": "address" + }, + { + "name": "_decimals", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "_rateNumerator", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_rateDenominator", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "asset", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "convertToAssets", + "inputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rateDenominator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "rateNumerator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + } + ], + "bytecode": "0x610100604052348015610010575f5ffd5b50604051610c17380380610c1783398181016040528101906100329190610154565b8373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508260ff1660a08160ff16815250508160c081815250508060e08181525050505050506101b8565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100ba82610091565b9050919050565b6100ca816100b0565b81146100d4575f5ffd5b50565b5f815190506100e5816100c1565b92915050565b5f60ff82169050919050565b610100816100eb565b811461010a575f5ffd5b50565b5f8151905061011b816100f7565b92915050565b5f819050919050565b61013381610121565b811461013d575f5ffd5b50565b5f8151905061014e8161012a565b92915050565b5f5f5f5f6080858703121561016c5761016b61008d565b5b5f610179878288016100d7565b945050602061018a8782880161010d565b935050604061019b87828801610140565b92505060606101ac87828801610140565b91505092959194509250565b60805160a05160c05160e051610a1e6101f95f395f8181610262015261055c01525f8181610283015261034801525f6104aa01525f6104ce0152610a1e5ff3fe608060405234801561000f575f5ffd5b50600436106100a7575f3560e01c806338d52e0f1161006f57806338d52e0f1461017757806340c10f191461019557806370a08231146101b1578063865192f7146101e1578063a9059cbb146101ff578063dd62ed3e1461022f576100a7565b806307a2d13a146100ab578063095ea7b3146100db5780630b36b8db1461010b57806323b872dd14610129578063313ce56714610159575b5f5ffd5b6100c560048036038101906100c09190610684565b61025f565b6040516100d291906106be565b60405180910390f35b6100f560048036038101906100f09190610731565b6102be565b6040516101029190610789565b60405180910390f35b610113610346565b60405161012091906106be565b60405180910390f35b610143600480360381019061013e91906107a2565b61036a565b6040516101509190610789565b60405180910390f35b6101616104a8565b60405161016e919061080d565b60405180910390f35b61017f6104cc565b60405161018c9190610835565b60405180910390f35b6101af60048036038101906101aa9190610731565b6104f0565b005b6101cb60048036038101906101c6919061084e565b610546565b6040516101d891906106be565b60405180910390f35b6101e961055a565b6040516101f691906106be565b60405180910390f35b61021960048036038101906102149190610731565b61057e565b6040516102269190610789565b60405180910390f35b61024960048036038101906102449190610879565b61062d565b60405161025691906106be565b60405180910390f35b5f7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836102ad91906108e4565b6102b79190610952565b9050919050565b5f8160015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055506001905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546103f29190610982565b92505081905550815f5f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546104449190610982565b92505081905550815f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461049691906109b5565b92505081905550600190509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461053b91906109b5565b925050819055505050565b5f602052805f5260405f205f915090505481565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f815f5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ca9190610982565b92505081905550815f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461061c91906109b5565b925050819055506001905092915050565b6001602052815f5260405f20602052805f5260405f205f91509150505481565b5f5ffd5b5f819050919050565b61066381610651565b811461066d575f5ffd5b50565b5f8135905061067e8161065a565b92915050565b5f602082840312156106995761069861064d565b5b5f6106a684828501610670565b91505092915050565b6106b881610651565b82525050565b5f6020820190506106d15f8301846106af565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610700826106d7565b9050919050565b610710816106f6565b811461071a575f5ffd5b50565b5f8135905061072b81610707565b92915050565b5f5f604083850312156107475761074661064d565b5b5f6107548582860161071d565b925050602061076585828601610670565b9150509250929050565b5f8115159050919050565b6107838161076f565b82525050565b5f60208201905061079c5f83018461077a565b92915050565b5f5f5f606084860312156107b9576107b861064d565b5b5f6107c68682870161071d565b93505060206107d78682870161071d565b92505060406107e886828701610670565b9150509250925092565b5f60ff82169050919050565b610807816107f2565b82525050565b5f6020820190506108205f8301846107fe565b92915050565b61082f816106f6565b82525050565b5f6020820190506108485f830184610826565b92915050565b5f602082840312156108635761086261064d565b5b5f6108708482850161071d565b91505092915050565b5f5f6040838503121561088f5761088e61064d565b5b5f61089c8582860161071d565b92505060206108ad8582860161071d565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6108ee82610651565b91506108f983610651565b925082820261090781610651565b9150828204841483151761091e5761091d6108b7565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61095c82610651565b915061096783610651565b92508261097757610976610925565b5b828204905092915050565b5f61098c82610651565b915061099783610651565b92508282039050818111156109af576109ae6108b7565b5b92915050565b5f6109bf82610651565b91506109ca83610651565b92508282019050808211156109e2576109e16108b7565b5b9291505056fea2646970667358221220b5ebafab2270a2c41eb9cd473eb8aca958511fe12b7302559d197e2a8704c94b64736f6c634300081e0033" +} diff --git a/contracts/artifacts/NonStandardERC20Balances.json b/contracts/artifacts/NonStandardERC20Balances.json new file mode 100644 index 0000000000..93353094ff --- /dev/null +++ b/contracts/artifacts/NonStandardERC20Balances.json @@ -0,0 +1,132 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b5061050e8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061006f575f3560e01c806370a082311161004d57806370a082311461010b578063a9059cbb14610155578063dd62ed3e14610168575f5ffd5b8063095ea7b31461007357806323b872dd146100bb57806340c10f19146100ce575b5f5ffd5b6100b96100813660046103c4565b335f9081526020818152604080832073ffffffffffffffffffffffffffffffffffffffff959095168352600190940190529190912055565b005b6100b96100c93660046103ec565b61017b565b6100b96100dc3660046103c4565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526020819052604090206001815560020155565b610143610119366004610426565b73ffffffffffffffffffffffffffffffffffffffff165f9081526020819052604090206002015490565b60405190815260200160405180910390f35b6100b96101633660046103c4565b6102a7565b610143610176366004610446565b610361565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260208181526040808320338452600101909152812080548392906101bb9084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812060020180548392906101f79084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812080549161022c836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906102689084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812080549161029d836104b7565b9190505550505050565b335f90815260208190526040812060020180548392906102c89084906104a4565b9091555050335f9081526020819052604081208054916102e7836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906103239084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f908152602081905260408120805491610358836104b7565b91905055505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683526001909301905220545b92915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146103bf575f5ffd5b919050565b5f5f604083850312156103d5575f5ffd5b6103de8361039c565b946020939093013593505050565b5f5f5f606084860312156103fe575f5ffd5b6104078461039c565b92506104156020850161039c565b929592945050506040919091013590565b5f60208284031215610436575f5ffd5b61043f8261039c565b9392505050565b5f5f60408385031215610457575f5ffd5b6104608361039c565b915061046e6020840161039c565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561039657610396610477565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036104e7576104e7610477565b5060010190565b808201808211156103965761039661047756fea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b506004361061006f575f3560e01c806370a082311161004d57806370a082311461010b578063a9059cbb14610155578063dd62ed3e14610168575f5ffd5b8063095ea7b31461007357806323b872dd146100bb57806340c10f19146100ce575b5f5ffd5b6100b96100813660046103c4565b335f9081526020818152604080832073ffffffffffffffffffffffffffffffffffffffff959095168352600190940190529190912055565b005b6100b96100c93660046103ec565b61017b565b6100b96100dc3660046103c4565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526020819052604090206001815560020155565b610143610119366004610426565b73ffffffffffffffffffffffffffffffffffffffff165f9081526020819052604090206002015490565b60405190815260200160405180910390f35b6100b96101633660046103c4565b6102a7565b610143610176366004610446565b610361565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260208181526040808320338452600101909152812080548392906101bb9084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812060020180548392906101f79084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812080549161022c836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906102689084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812080549161029d836104b7565b9190505550505050565b335f90815260208190526040812060020180548392906102c89084906104a4565b9091555050335f9081526020819052604081208054916102e7836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906103239084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f908152602081905260408120805491610358836104b7565b91905055505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683526001909301905220545b92915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146103bf575f5ffd5b919050565b5f5f604083850312156103d5575f5ffd5b6103de8361039c565b946020939093013593505050565b5f5f5f606084860312156103fe575f5ffd5b6104078461039c565b92506104156020850161039c565b929592945050506040919091013590565b5f60208284031215610436575f5ffd5b61043f8261039c565b9392505050565b5f5f60408385031215610457575f5ffd5b6104608361039c565b915061046e6020840161039c565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561039657610396610477565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036104e7576104e7610477565b5060010190565b808201808211156103965761039661047756fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/contracts/artifacts/PancakeRouter.json b/contracts/artifacts/PancakeRouter.json new file mode 100644 index 0000000000..c95b7fd70d --- /dev/null +++ b/contracts/artifacts/PancakeRouter.json @@ -0,0 +1,957 @@ +{ + "abi": [ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/crates/contracts/artifacts/Permit2.json b/contracts/artifacts/Permit2.json similarity index 99% rename from crates/contracts/artifacts/Permit2.json rename to contracts/artifacts/Permit2.json index 00537570e6..60c0727632 100644 --- a/crates/contracts/artifacts/Permit2.json +++ b/contracts/artifacts/Permit2.json @@ -326,6 +326,106 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails", + "name": "details", + "type": "tuple" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitSingle", + "name": "permitSingle", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x", + "deployedBytecode": "0x", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + }, + "_disabled": [ { "inputs": [ { @@ -416,68 +516,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "components": [ - { - "components": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint160", - "name": "amount", - "type": "uint160" - }, - { - "internalType": "uint48", - "name": "expiration", - "type": "uint48" - }, - { - "internalType": "uint48", - "name": "nonce", - "type": "uint48" - } - ], - "internalType": "struct IAllowanceTransfer.PermitDetails", - "name": "details", - "type": "tuple" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sigDeadline", - "type": "uint256" - } - ], - "internalType": "struct IAllowanceTransfer.PermitSingle", - "name": "permitSingle", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -625,42 +663,6 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint160", - "name": "amount", - "type": "uint160" - }, - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" } - ], - "bytecode": "0x", - "deployedBytecode": "0x", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } + ] } diff --git a/contracts/artifacts/RemoteERC20Balances.json b/contracts/artifacts/RemoteERC20Balances.json new file mode 100644 index 0000000000..740892456f --- /dev/null +++ b/contracts/artifacts/RemoteERC20Balances.json @@ -0,0 +1,161 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract NonStandardERC20Balances", + "name": "_target", + "type": "address" + }, + { + "internalType": "bool", + "name": "_balanceFromHere", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "target", + "outputs": [ + { + "internalType": "contract NonStandardERC20Balances", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60c060405234801561000f575f5ffd5b5060405161071338038061071383398101604081905261002e91610044565b15156080526001600160a01b031660a05261008b565b5f5f60408385031215610055575f5ffd5b82516001600160a01b038116811461006b575f5ffd5b60208401519092508015158114610080575f5ffd5b809150509250929050565b60805160a0516106606100b35f395f8181610154015261032301525f61039001526106605ff3fe608060405234801561000f575f5ffd5b506004361061007a575f3560e01c806370a082311161005857806370a0823114610116578063a9059cbb1461013c578063d4b839921461014f578063dd62ed3e1461019b575f5ffd5b8063095ea7b31461007e57806323b872dd146100c657806340c10f19146100d9575b5f5ffd5b6100c461008c366004610506565b335f9081526020818152604080832073ffffffffffffffffffffffffffffffffffffffff959095168352600190940190529190912055565b005b6100c46100d436600461052e565b6101ae565b6100c46100e7366004610506565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526020819052604090206001815560020155565b610129610124366004610568565b6102da565b6040519081526020015b60405180910390f35b6100c461014a366004610506565b6103e9565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610133565b6101296101a9366004610581565b6104a3565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260208181526040808320338452600101909152812080548392906101ee9084906105df565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f908152602081905260408120600201805483929061022a9084906105df565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812080549161025f836105f2565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f908152602081905260408120600201805483929061029b908490610629565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f9081526020819052604081208054916102d0836105f2565b9190505550505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f9182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038c919061063c565b90507f00000000000000000000000000000000000000000000000000000000000000006103b957806103e2565b73ffffffffffffffffffffffffffffffffffffffff83165f908152602081905260409020600201545b9392505050565b335f908152602081905260408120600201805483929061040a9084906105df565b9091555050335f908152602081905260408120805491610429836105f2565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f9081526020819052604081206002018054839290610465908490610629565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812080549161049a836105f2565b91905055505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683526001909301905220545b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610501575f5ffd5b919050565b5f5f60408385031215610517575f5ffd5b610520836104de565b946020939093013593505050565b5f5f5f60608486031215610540575f5ffd5b610549846104de565b9250610557602085016104de565b929592945050506040919091013590565b5f60208284031215610578575f5ffd5b6103e2826104de565b5f5f60408385031215610592575f5ffd5b61059b836104de565b91506105a9602084016104de565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156104d8576104d86105b2565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610622576106226105b2565b5060010190565b808201808211156104d8576104d86105b2565b5f6020828403121561064c575f5ffd5b505191905056fea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b506004361061007a575f3560e01c806370a082311161005857806370a0823114610116578063a9059cbb1461013c578063d4b839921461014f578063dd62ed3e1461019b575f5ffd5b8063095ea7b31461007e57806323b872dd146100c657806340c10f19146100d9575b5f5ffd5b6100c461008c366004610506565b335f9081526020818152604080832073ffffffffffffffffffffffffffffffffffffffff959095168352600190940190529190912055565b005b6100c46100d436600461052e565b6101ae565b6100c46100e7366004610506565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526020819052604090206001815560020155565b610129610124366004610568565b6102da565b6040519081526020015b60405180910390f35b6100c461014a366004610506565b6103e9565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610133565b6101296101a9366004610581565b6104a3565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260208181526040808320338452600101909152812080548392906101ee9084906105df565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f908152602081905260408120600201805483929061022a9084906105df565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812080549161025f836105f2565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f908152602081905260408120600201805483929061029b908490610629565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f9081526020819052604081208054916102d0836105f2565b9190505550505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f9182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038c919061063c565b90507f00000000000000000000000000000000000000000000000000000000000000006103b957806103e2565b73ffffffffffffffffffffffffffffffffffffffff83165f908152602081905260409020600201545b9392505050565b335f908152602081905260408120600201805483929061040a9084906105df565b9091555050335f908152602081905260408120805491610429836105f2565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f9081526020819052604081206002018054839290610465908490610629565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812080549161049a836105f2565b91905055505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683526001909301905220545b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610501575f5ffd5b919050565b5f5f60408385031215610517575f5ffd5b610520836104de565b946020939093013593505050565b5f5f5f60608486031215610540575f5ffd5b610549846104de565b9250610557602085016104de565b929592945050506040919091013590565b5f60208284031215610578575f5ffd5b6103e2826104de565b5f5f60408385031215610592575f5ffd5b61059b836104de565b91506105a9602084016104de565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156104d8576104d86105b2565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610622576106226105b2565b5060010190565b808201808211156104d8576104d86105b2565b5f6020828403121561064c575f5ffd5b505191905056fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/contracts/artifacts/Signatures.json b/contracts/artifacts/Signatures.json new file mode 100644 index 0000000000..23a3b07243 --- /dev/null +++ b/contracts/artifacts/Signatures.json @@ -0,0 +1,80 @@ +{ + "abi": [ + { + "inputs": [ + { + "components": [ + { + "internalType": "contract ISettlement", + "name": "settlement", + "type": "address" + }, + { + "internalType": "contract IVaultRelayer", + "name": "vaultRelayer", + "type": "address" + } + ], + "internalType": "struct Signatures.Contracts", + "name": "contracts", + "type": "tuple" + }, + { + "internalType": "contract IERC1271", + "name": "signer", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "order", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Interaction[]", + "name": "interactions", + "type": "tuple[]" + } + ], + "name": "validate", + "outputs": [ + { + "internalType": "uint256", + "name": "gasUsed", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b506107238061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b46054151461002d575b5f5ffd5b61004061003b366004610450565b610052565b60405190815260200160405180910390f35b5f61005e8884846101a9565b5a90505f8773ffffffffffffffffffffffffffffffffffffffff16631626ba7e8888886040518463ffffffff1660e01b815260040161009f9392919061055a565b602060405180830381865afa1580156100ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100de91906105ad565b90505a6100eb90836105f3565b91507fffffffff0000000000000000000000000000000000000000000000000000000081167f1626ba7e000000000000000000000000000000000000000000000000000000001461019d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6469646e27742073617920746865206d6167696320776f72640000000000000060448201526064015b60405180910390fd5b50979650505050505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e74657874000000000000006044820152606401610194565b5f5b81811015610390575f83838381811061024657610246610631565b9050602002810190610258919061065e565b61026690602081019061069a565b90505f84848481811061027b5761027b610631565b905060200281019061028d919061065e565b602001359050365f8686868181106102a7576102a7610631565b90506020028101906102b9919061065e565b6102c79060408101906106b5565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e00000000006044820152606401610194565b604051818382375f5f838387895af161037f573d5f5f3e3d5ffd5b50506001909301925061022b915050565b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146103b7575f5ffd5b50565b80356103c581610396565b919050565b5f5f83601f8401126103da575f5ffd5b50813567ffffffffffffffff8111156103f1575f5ffd5b602083019150836020828501011115610408575f5ffd5b9250929050565b5f5f83601f84011261041f575f5ffd5b50813567ffffffffffffffff811115610436575f5ffd5b6020830191508360208260051b8501011115610408575f5ffd5b5f5f5f5f5f5f5f87890360c0811215610467575f5ffd5b6040811215610474575f5ffd5b506040516040810181811067ffffffffffffffff821117156104bd577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405288356104cb81610396565b815260208901356104db81610396565b602082015296506104ee604089016103ba565b955060608801359450608088013567ffffffffffffffff811115610510575f5ffd5b61051c8a828b016103ca565b90955093505060a088013567ffffffffffffffff81111561053b575f5ffd5b6105478a828b0161040f565b989b979a50959850939692959293505050565b83815260406020820152816040820152818360608301375f818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b5f602082840312156105bd575f5ffd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146105ec575f5ffd5b9392505050565b8181038181111561062b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610690575f5ffd5b9190910192915050565b5f602082840312156106aa575f5ffd5b81356105ec81610396565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126106e8575f5ffd5b83018035915067ffffffffffffffff821115610702575f5ffd5b602001915036819003821315610408575f5ffdfea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b46054151461002d575b5f5ffd5b61004061003b366004610450565b610052565b60405190815260200160405180910390f35b5f61005e8884846101a9565b5a90505f8773ffffffffffffffffffffffffffffffffffffffff16631626ba7e8888886040518463ffffffff1660e01b815260040161009f9392919061055a565b602060405180830381865afa1580156100ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100de91906105ad565b90505a6100eb90836105f3565b91507fffffffff0000000000000000000000000000000000000000000000000000000081167f1626ba7e000000000000000000000000000000000000000000000000000000001461019d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6469646e27742073617920746865206d6167696320776f72640000000000000060448201526064015b60405180910390fd5b50979650505050505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e74657874000000000000006044820152606401610194565b5f5b81811015610390575f83838381811061024657610246610631565b9050602002810190610258919061065e565b61026690602081019061069a565b90505f84848481811061027b5761027b610631565b905060200281019061028d919061065e565b602001359050365f8686868181106102a7576102a7610631565b90506020028101906102b9919061065e565b6102c79060408101906106b5565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e00000000006044820152606401610194565b604051818382375f5f838387895af161037f573d5f5f3e3d5ffd5b50506001909301925061022b915050565b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146103b7575f5ffd5b50565b80356103c581610396565b919050565b5f5f83601f8401126103da575f5ffd5b50813567ffffffffffffffff8111156103f1575f5ffd5b602083019150836020828501011115610408575f5ffd5b9250929050565b5f5f83601f84011261041f575f5ffd5b50813567ffffffffffffffff811115610436575f5ffd5b6020830191508360208260051b8501011115610408575f5ffd5b5f5f5f5f5f5f5f87890360c0811215610467575f5ffd5b6040811215610474575f5ffd5b506040516040810181811067ffffffffffffffff821117156104bd577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405288356104cb81610396565b815260208901356104db81610396565b602082015296506104ee604089016103ba565b955060608801359450608088013567ffffffffffffffff811115610510575f5ffd5b61051c8a828b016103ca565b90955093505060a088013567ffffffffffffffff81111561053b575f5ffd5b6105478a828b0161040f565b989b979a50959850939692959293505050565b83815260406020820152816040820152818360608301375f818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b5f602082840312156105bd575f5ffd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146105ec575f5ffd5b9392505050565b8181038181111561062b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610690575f5ffd5b9190910192915050565b5f602082840312156106aa575f5ffd5b81356105ec81610396565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126106e8575f5ffd5b83018035915067ffffffffffffffff821115610702575f5ffd5b602001915036819003821315610408575f5ffdfea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/contracts/artifacts/Solver.json b/contracts/artifacts/Solver.json new file mode 100644 index 0000000000..4bbb87b4c3 --- /dev/null +++ b/contracts/artifacts/Solver.json @@ -0,0 +1,94 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bool", + "name": "countGas", + "type": "bool" + } + ], + "name": "storeBalance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ISettlement", + "name": "settlementContract", + "type": "address" + }, + { + "internalType": "address[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "address payable", + "name": "receiver", + "type": "address" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "address", + "name": "sellToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sellAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "settleCallTarget", + "type": "address" + }, + { + "internalType": "bytes", + "name": "settlementCall", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "uint256", + "name": "gasUsed", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "queriedBalances", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b50610acb8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80633bbb2e1d146100385780638581192b1461004d575b5f5ffd5b61004b610046366004610805565b610077565b005b61006061005b366004610896565b6101e6565b60405161006e929190610997565b60405180910390f35b5f5a90507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff861614610160576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528616906370a0823190602401602060405180830381865afa158015610137573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061015b91906109e4565b610179565b8373ffffffffffffffffffffffffffffffffffffffff16315b81546001810183555f92835260209092209091015581156101e0575a61019f9082610a28565b6101ab9061116c610a41565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f8282546101da9190610a41565b90915550505b50505050565b5f60606101f58c8989896102f7565b5f8973ffffffffffffffffffffffffffffffffffffffff165f6040515f6040518083038185875af1925050503d805f811461024b576040519150601f19603f3d011682016040523d82523d5f602084013e610250565b606091505b50509050506102608b8b8e61066f565b61026b858585610739565b91506102788b8b8e61066f565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c8054806020026020016040519081016040528092919081815260200182805480156102e157602002820191905f5260205f20905b8154815260200190600101908083116102cd575b505050505090509a509a98505050505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610341573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103659190610a54565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015280831660248301529192505f9185169063dd62ed3e90604401602060405180830381865afa1580156103dc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040091906109e4565b905082811015610497576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f74726164657220646964206e6f7420676976652074686520726571756972656460448201527f20617070726f76616c730000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301525f91908616906370a0823190602401602060405180830381865afa158015610504573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052891906109e4565b90508381101561066657731111111111111111111111111111111111111111636a52902687876105588589610a28565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064015f604051808303815f87803b1580156105c9575f5ffd5b505af19250505080156105da575060015b610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f74726164657220646f6573206e6f74206861766520656e6f7567682073656c6c60448201527f20746f6b656e0000000000000000000000000000000000000000000000000000606482015260840161048e565b50505050505050565b5f5b828110156101e05730633bbb2e1d85858481811061069157610691610a76565b90506020020160208101906106a69190610aa3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff918216600482015290851660248201525f60448201526064015f604051808303815f87803b158015610717575f5ffd5b505af1158015610729573d5f5f3e3d5ffd5b5050600190920191506106719050565b5f5f5a90505f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525084519495509384935091505060208401828a5af1610790573d5f5f3e3d5ffd5b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b545a6107bd9084610a28565b6107c79190610a28565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107f2575f5ffd5b50565b8035610800816107d1565b919050565b5f5f5f60608486031215610817575f5ffd5b8335610822816107d1565b92506020840135610832816107d1565b915060408401358015158114610846575f5ffd5b809150509250925092565b5f5f83601f840112610861575f5ffd5b50813567ffffffffffffffff811115610878575f5ffd5b60208301915083602082850101111561088f575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f5f5f6101008b8d0312156108b0575f5ffd5b8a356108bb816107d1565b995060208b013567ffffffffffffffff8111156108d6575f5ffd5b8b01601f81018d136108e6575f5ffd5b803567ffffffffffffffff8111156108fc575f5ffd5b8d60208260051b8401011115610910575f5ffd5b6020919091019950975061092660408c016107f5565b965061093460608c016107f5565b955061094260808c016107f5565b945060a08b0135935061095760c08c016107f5565b925060e08b013567ffffffffffffffff811115610972575f5ffd5b61097e8d828e01610851565b915080935050809150509295989b9194979a5092959850565b5f60408201848352604060208401528084518083526060850191506020860192505f5b818110156109d85783518352602093840193909201916001016109ba565b50909695505050505050565b5f602082840312156109f4575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610a3b57610a3b6109fb565b92915050565b80820180821115610a3b57610a3b6109fb565b5f60208284031215610a64575f5ffd5b8151610a6f816107d1565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215610ab3575f5ffd5b8135610a6f816107d156fea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80633bbb2e1d146100385780638581192b1461004d575b5f5ffd5b61004b610046366004610805565b610077565b005b61006061005b366004610896565b6101e6565b60405161006e929190610997565b60405180910390f35b5f5a90507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff861614610160576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528616906370a0823190602401602060405180830381865afa158015610137573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061015b91906109e4565b610179565b8373ffffffffffffffffffffffffffffffffffffffff16315b81546001810183555f92835260209092209091015581156101e0575a61019f9082610a28565b6101ab9061116c610a41565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f8282546101da9190610a41565b90915550505b50505050565b5f60606101f58c8989896102f7565b5f8973ffffffffffffffffffffffffffffffffffffffff165f6040515f6040518083038185875af1925050503d805f811461024b576040519150601f19603f3d011682016040523d82523d5f602084013e610250565b606091505b50509050506102608b8b8e61066f565b61026b858585610739565b91506102788b8b8e61066f565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c8054806020026020016040519081016040528092919081815260200182805480156102e157602002820191905f5260205f20905b8154815260200190600101908083116102cd575b505050505090509a509a98505050505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610341573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103659190610a54565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015280831660248301529192505f9185169063dd62ed3e90604401602060405180830381865afa1580156103dc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040091906109e4565b905082811015610497576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f74726164657220646964206e6f7420676976652074686520726571756972656460448201527f20617070726f76616c730000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301525f91908616906370a0823190602401602060405180830381865afa158015610504573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052891906109e4565b90508381101561066657731111111111111111111111111111111111111111636a52902687876105588589610a28565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064015f604051808303815f87803b1580156105c9575f5ffd5b505af19250505080156105da575060015b610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f74726164657220646f6573206e6f74206861766520656e6f7567682073656c6c60448201527f20746f6b656e0000000000000000000000000000000000000000000000000000606482015260840161048e565b50505050505050565b5f5b828110156101e05730633bbb2e1d85858481811061069157610691610a76565b90506020020160208101906106a69190610aa3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff918216600482015290851660248201525f60448201526064015f604051808303815f87803b158015610717575f5ffd5b505af1158015610729573d5f5f3e3d5ffd5b5050600190920191506106719050565b5f5f5a90505f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525084519495509384935091505060208401828a5af1610790573d5f5f3e3d5ffd5b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b545a6107bd9084610a28565b6107c79190610a28565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107f2575f5ffd5b50565b8035610800816107d1565b919050565b5f5f5f60608486031215610817575f5ffd5b8335610822816107d1565b92506020840135610832816107d1565b915060408401358015158114610846575f5ffd5b809150509250925092565b5f5f83601f840112610861575f5ffd5b50813567ffffffffffffffff811115610878575f5ffd5b60208301915083602082850101111561088f575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f5f5f6101008b8d0312156108b0575f5ffd5b8a356108bb816107d1565b995060208b013567ffffffffffffffff8111156108d6575f5ffd5b8b01601f81018d136108e6575f5ffd5b803567ffffffffffffffff8111156108fc575f5ffd5b8d60208260051b8401011115610910575f5ffd5b6020919091019950975061092660408c016107f5565b965061093460608c016107f5565b955061094260808c016107f5565b945060a08b0135935061095760c08c016107f5565b925060e08b013567ffffffffffffffff811115610972575f5ffd5b61097e8d828e01610851565b915080935050809150509295989b9194979a5092959850565b5f60408201848352604060208401528084518083526060850191506020860192505f5b818110156109d85783518352602093840193909201916001016109ba565b50909695505050505050565b5f602082840312156109f4575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610a3b57610a3b6109fb565b92915050565b80820180821115610a3b57610a3b6109fb565b5f60208284031215610a64575f5ffd5b8151610a6f816107d1565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215610ab3575f5ffd5b8135610a6f816107d156fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/contracts/artifacts/Solver7702Delegate.json b/contracts/artifacts/Solver7702Delegate.json new file mode 100644 index 0000000000..161b76beca --- /dev/null +++ b/contracts/artifacts/Solver7702Delegate.json @@ -0,0 +1,35 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address[5]", + "name": "approvedCallers", + "type": "address[5]" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "Unauthorized", + "type": "error" + } + ], + "bytecode": { + "linkReferences": {}, + "object": "0x610120604052348015610010575f5ffd5b506040516103fd3803806103fd83398101604081905261002f9161009c565b80516001600160a01b0390811660809081526020830151821660a0526040830151821660c0526060830151821660e05290910151166101005261011c565b634e487b7160e01b5f52604160045260245ffd5b80516001600160a01b0381168114610097575f5ffd5b919050565b5f60a082840312156100ac575f5ffd5b82601f8301126100ba575f5ffd5b60405160a081016001600160401b03811182821017156100dc576100dc61006d565b6040528060a08401858111156100f0575f5ffd5b845b818110156101115761010381610081565b8352602092830192016100f2565b509195945050505050565b60805160a05160c05160e051610100516102a86101555f395f61011b01525f60db01525f609b01525f605b01525f601c01526102a85ff3fe60806040523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148061007d57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b806100bd57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b806100fd57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b8061013d57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b1561014c5761014a610198565b005b5f34118061015957503330145b1561016057005b6040517f8e4a23d600000000000000000000000000000000000000000000000000000000815233600482015260240160405180910390fd5b60143610156101a357565b5f6101b160148236816101e5565b6101ba9161020c565b60601c90506014360360145f375f5f601436035f34855af13d5f5f3e8080156101e1573d5ff35b3d5ffd5b5f5f858511156101f3575f5ffd5b838611156101ff575f5ffd5b5050820193919092039150565b80357fffffffffffffffffffffffffffffffffffffffff000000000000000000000000811690601484101561026b577fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808560140360031b1b82161691505b509291505056fea2646970667358221220ef31ba5be14f09268bdfe684e4f9d33c71640e3412fc60118872f20167113f6964736f6c63430008220033", + "sourceMap": "184:3445:19:-:0;;;967:294;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1044:18;;-1:-1:-1;;;;;1024:38:19;;;;;;;1044:18;1092;;;1072:38;;;;1140:18;;;;1120:38;;;;1188:18;;;;1168:38;;;;1236:18;;;;1216:38;;;184:3445;;14:127:23;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:177;225:13;;-1:-1:-1;;;;;267:31:23;;257:42;;247:70;;313:1;310;303:12;247:70;146:177;;;:::o;328:789::-;421:6;474:3;462:9;453:7;449:23;445:33;442:53;;;491:1;488;481:12;442:53;540:7;533:4;522:9;518:20;514:34;504:62;;562:1;559;552:12;504:62;595:2;589:9;637:3;625:16;;-1:-1:-1;;;;;656:34:23;;692:22;;;653:62;650:88;;;718:18;;:::i;:::-;754:2;747:22;789:6;833:3;818:19;;849;;;846:39;;;881:1;878;871:12;846:39;905:9;923:163;939:6;934:3;931:15;923:163;;;1007:34;1037:3;1007:34;:::i;:::-;995:47;;1071:4;1062:14;;;;956;923:163;;;-1:-1:-1;1105:6:23;;328:789;-1:-1:-1;;;;;328:789:23:o;1122:127::-;184:3445:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" + } +} \ No newline at end of file diff --git a/contracts/artifacts/Spardose.json b/contracts/artifacts/Spardose.json new file mode 100644 index 0000000000..78dc5e44c8 --- /dev/null +++ b/contracts/artifacts/Spardose.json @@ -0,0 +1,35 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "requestFunds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b506102ea8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80636a5290261461002d575b5f5ffd5b61004061003b366004610259565b610042565b005b61006373ffffffffffffffffffffffffffffffffffffffff83168483610068565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052905f906100fa90861683610176565b90506101058161018a565b61016f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a207472616e73666572206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b6060610183835f846101af565b9392505050565b5f81515f14806101a95750818060200190518101906101a99190610292565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516101d891906102b1565b5f6040518083038185875af1925050503d805f8114610212576040519150601f19603f3d011682016040523d82523d5f602084013e610217565b606091505b50925090508061022957815160208301fd5b509392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610254575f5ffd5b919050565b5f5f5f6060848603121561026b575f5ffd5b61027484610231565b925061028260208501610231565b9150604084013590509250925092565b5f602082840312156102a2575f5ffd5b81518015158114610183575f5ffd5b5f82515f5b818110156102d057602081860181015185830152016102b6565b505f92019182525091905056fea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80636a5290261461002d575b5f5ffd5b61004061003b366004610259565b610042565b005b61006373ffffffffffffffffffffffffffffffffffffffff83168483610068565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052905f906100fa90861683610176565b90506101058161018a565b61016f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a207472616e73666572206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b6060610183835f846101af565b9392505050565b5f81515f14806101a95750818060200190518101906101a99190610292565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516101d891906102b1565b5f6040518083038185875af1925050503d805f8114610212576040519150601f19603f3d011682016040523d82523d5f602084013e610217565b606091505b50925090508061022957815160208301fd5b509392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610254575f5ffd5b919050565b5f5f5f6060848603121561026b575f5ffd5b61027484610231565b925061028260208501610231565b9150604084013590509250925092565b5f602082840312156102a2575f5ffd5b81518015158114610183575f5ffd5b5f82515f5b818110156102d057602081860181015185830152016102b6565b505f92019182525091905056fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/contracts/artifacts/SushiSwapRouter.json b/contracts/artifacts/SushiSwapRouter.json new file mode 100644 index 0000000000..c95b7fd70d --- /dev/null +++ b/contracts/artifacts/SushiSwapRouter.json @@ -0,0 +1,957 @@ +{ + "abi": [ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/contracts/artifacts/Swapper.json b/contracts/artifacts/Swapper.json new file mode 100644 index 0000000000..35c1e95819 --- /dev/null +++ b/contracts/artifacts/Swapper.json @@ -0,0 +1,128 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ISettlement", + "name": "settlement", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Asset", + "name": "sell", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Asset", + "name": "buy", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct Allowance", + "name": "allowance", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Interaction[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "uint256", + "name": "gasUsed", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052348015600e575f5ffd5b506111ea8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80631626ba7e14610038578063e8333e0d146100a4575b5f5ffd5b61006e610046366004610a63565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b6100b76100b2366004610b14565b6100c5565b60405190815260200161009b565b5f602086018035906100d79088610bcc565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa158015610141573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101659190610be7565b101561017257505f61082e565b61020d8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101be573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101e29190610bfe565b5f6101f060208a018a610bcc565b73ffffffffffffffffffffffffffffffffffffffff169190610838565b61028e8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610259573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027d9190610bfe565b602088018035906101f0908a610bcc565b6040805160028082526060820183525f926020830190803683370190505090506102bb6020880188610bcc565b815f815181106102cd576102cd610c46565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526102fd90870187610bcc565b8160018151811061031057610310610c46565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160028082526060820183525f9391929091830190803683370190505090508660200135815f8151811061036e5761036e610c46565b60200260200101818152505087602001358160018151811061039257610392610c46565b60209081029190910101526040805160018082528183019092525f91816020015b6104226040518061016001604052805f81526020015f81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020015f81526020015f63ffffffff1681526020015f81526020015f81526020015f81526020015f8152602001606081525090565b8152602001906001900390816103b35790505090506040518061016001604052805f8152602001600181526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020018a6020013581526020018960200135815260200163ffffffff801681526020015f5f1b81526020015f8152602001604081526020015f8152602001306040516020016104e3919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604051602081830303815290604052815250815f8151811061050757610507610c46565b602002602001018190525061051a610a3c565b6020808901359061052d908c018c610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8d61055660208d018d610bcc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa1580156105c4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e89190610be7565b10156107625760408051600180825281830190925290816020015b60408051606080820183525f808352602083015291810191909152815260200190600190039081610603575050815261063f60208b018b610bcc565b815180515f9061065157610651610c46565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff909216909152610684908b018b610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b36106ac60208b018b610bcc565b60405173ffffffffffffffffffffffffffffffffffffffff909116602482015260208b01356044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b929092179091529050815f60200201515f8151811061075257610752610c46565b6020026020010151604001819052505b61076c8688610ceb565b60208201526040516108279073ffffffffffffffffffffffffffffffffffffffff8d16906313d79a0b906107aa9088908890889088906024016110a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b9290921790915273ffffffffffffffffffffffffffffffffffffffff8e169150610946565b9450505050505b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052905f906108ca90861683610959565b90506108d581610966565b61093f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b5f610952835f8461098b565b9392505050565b6060610952835f846109ba565b5f81515f1480610985575081806020019051810190610985919061116b565b92915050565b5f5a90505f5f83516020850186885af16109a7573d5f5f3e3d5ffd5b5a6109b2908261118a565b949350505050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516109e391906111c2565b5f6040518083038185875af1925050503d805f8114610a1d576040519150601f19603f3d011682016040523d82523d5f602084013e610a22565b606091505b509250905080610a3457815160208301fd5b509392505050565b60405180606001604052806003905b6060815260200190600190039081610a4b5790505090565b5f5f5f60408486031215610a75575f5ffd5b83359250602084013567ffffffffffffffff811115610a92575f5ffd5b8401601f81018613610aa2575f5ffd5b803567ffffffffffffffff811115610ab8575f5ffd5b866020828401011115610ac9575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610afb575f5ffd5b50565b5f60408284031215610b0e575f5ffd5b50919050565b5f5f5f5f5f5f6101008789031215610b2a575f5ffd5b8635610b3581610ada565b9550610b448860208901610afe565b9450610b538860608901610afe565b9350610b628860a08901610afe565b925060e087013567ffffffffffffffff811115610b7d575f5ffd5b8701601f81018913610b8d575f5ffd5b803567ffffffffffffffff811115610ba3575f5ffd5b8960208260051b8401011115610bb7575f5ffd5b60208201935080925050509295509295509295565b5f60208284031215610bdc575f5ffd5b813561095281610ada565b5f60208284031215610bf7575f5ffd5b5051919050565b5f60208284031215610c0e575f5ffd5b815161095281610ada565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040516060810167ffffffffffffffff81118282101715610c9657610c96610c19565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ce357610ce3610c19565b604052919050565b5f67ffffffffffffffff831115610d0457610d04610c19565b8260051b610d1460208201610c9c565b84815290830190602081019036831115610d2c575f5ffd5b845b83811015610e3857803567ffffffffffffffff811115610d4c575f5ffd5b86016060368290031215610d5e575f5ffd5b610d66610c73565b8135610d7181610ada565b815260208281013590820152604082013567ffffffffffffffff811115610d96575f5ffd5b919091019036601f830112610da9575f5ffd5b813567ffffffffffffffff811115610dc357610dc3610c19565b610df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610c9c565b818152366020838601011115610e08575f5ffd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050610d2e565b5095945050505050565b5f5b83811015610e5c578181015183820152602001610e44565b50505f910152565b5f8151808452610e7b816020860160208601610e42565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f82825180855260208501945060208160051b830101602085015f5b83811015610fbe577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0858403018852815180518452602081015160208501526040810151610f2f604086018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608501526080810151608085015260a0810151610f5b60a086018263ffffffff169052565b5060c081015160c085015260e081015160e08501526101008101516101008501526101208101516101208501526101408101519050610160610140850152610fa7610160850182610e64565b6020998a0199909450929092019150600101610ec9565b50909695505050505050565b5f8260608101835f5b600381101561109d578383038752815180518085526020918201918086019190600582901b8701015f5b82811015611083577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0888303018452845173ffffffffffffffffffffffffffffffffffffffff815116835260208101516020840152604081015190506060604084015261106d6060840182610e64565b6020968701969590950194925050600101610ffd565b5060209a8b019a9096509490940193505050600101610fd3565b509095945050505050565b608080825285519082018190525f90602087019060a0840190835b818110156110f757835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016110c3565b505083810360208501528091505f87518083526020830193506020890192505f5b81811015611136578351855260209485019490930192600101611118565b50505050828103604084015261114c8186610ead565b905082810360608401526111608185610fca565b979650505050505050565b5f6020828403121561117b575f5ffd5b81518015158114610952575f5ffd5b81810381811115610985577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f82516111d3818460208701610e42565b919091019291505056fea164736f6c634300081e000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80631626ba7e14610038578063e8333e0d146100a4575b5f5ffd5b61006e610046366004610a63565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b6100b76100b2366004610b14565b6100c5565b60405190815260200161009b565b5f602086018035906100d79088610bcc565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa158015610141573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101659190610be7565b101561017257505f61082e565b61020d8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101be573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101e29190610bfe565b5f6101f060208a018a610bcc565b73ffffffffffffffffffffffffffffffffffffffff169190610838565b61028e8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610259573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027d9190610bfe565b602088018035906101f0908a610bcc565b6040805160028082526060820183525f926020830190803683370190505090506102bb6020880188610bcc565b815f815181106102cd576102cd610c46565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526102fd90870187610bcc565b8160018151811061031057610310610c46565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160028082526060820183525f9391929091830190803683370190505090508660200135815f8151811061036e5761036e610c46565b60200260200101818152505087602001358160018151811061039257610392610c46565b60209081029190910101526040805160018082528183019092525f91816020015b6104226040518061016001604052805f81526020015f81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020015f81526020015f63ffffffff1681526020015f81526020015f81526020015f81526020015f8152602001606081525090565b8152602001906001900390816103b35790505090506040518061016001604052805f8152602001600181526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020018a6020013581526020018960200135815260200163ffffffff801681526020015f5f1b81526020015f8152602001604081526020015f8152602001306040516020016104e3919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604051602081830303815290604052815250815f8151811061050757610507610c46565b602002602001018190525061051a610a3c565b6020808901359061052d908c018c610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8d61055660208d018d610bcc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa1580156105c4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e89190610be7565b10156107625760408051600180825281830190925290816020015b60408051606080820183525f808352602083015291810191909152815260200190600190039081610603575050815261063f60208b018b610bcc565b815180515f9061065157610651610c46565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff909216909152610684908b018b610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b36106ac60208b018b610bcc565b60405173ffffffffffffffffffffffffffffffffffffffff909116602482015260208b01356044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b929092179091529050815f60200201515f8151811061075257610752610c46565b6020026020010151604001819052505b61076c8688610ceb565b60208201526040516108279073ffffffffffffffffffffffffffffffffffffffff8d16906313d79a0b906107aa9088908890889088906024016110a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b9290921790915273ffffffffffffffffffffffffffffffffffffffff8e169150610946565b9450505050505b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052905f906108ca90861683610959565b90506108d581610966565b61093f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b5f610952835f8461098b565b9392505050565b6060610952835f846109ba565b5f81515f1480610985575081806020019051810190610985919061116b565b92915050565b5f5a90505f5f83516020850186885af16109a7573d5f5f3e3d5ffd5b5a6109b2908261118a565b949350505050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516109e391906111c2565b5f6040518083038185875af1925050503d805f8114610a1d576040519150601f19603f3d011682016040523d82523d5f602084013e610a22565b606091505b509250905080610a3457815160208301fd5b509392505050565b60405180606001604052806003905b6060815260200190600190039081610a4b5790505090565b5f5f5f60408486031215610a75575f5ffd5b83359250602084013567ffffffffffffffff811115610a92575f5ffd5b8401601f81018613610aa2575f5ffd5b803567ffffffffffffffff811115610ab8575f5ffd5b866020828401011115610ac9575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610afb575f5ffd5b50565b5f60408284031215610b0e575f5ffd5b50919050565b5f5f5f5f5f5f6101008789031215610b2a575f5ffd5b8635610b3581610ada565b9550610b448860208901610afe565b9450610b538860608901610afe565b9350610b628860a08901610afe565b925060e087013567ffffffffffffffff811115610b7d575f5ffd5b8701601f81018913610b8d575f5ffd5b803567ffffffffffffffff811115610ba3575f5ffd5b8960208260051b8401011115610bb7575f5ffd5b60208201935080925050509295509295509295565b5f60208284031215610bdc575f5ffd5b813561095281610ada565b5f60208284031215610bf7575f5ffd5b5051919050565b5f60208284031215610c0e575f5ffd5b815161095281610ada565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040516060810167ffffffffffffffff81118282101715610c9657610c96610c19565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ce357610ce3610c19565b604052919050565b5f67ffffffffffffffff831115610d0457610d04610c19565b8260051b610d1460208201610c9c565b84815290830190602081019036831115610d2c575f5ffd5b845b83811015610e3857803567ffffffffffffffff811115610d4c575f5ffd5b86016060368290031215610d5e575f5ffd5b610d66610c73565b8135610d7181610ada565b815260208281013590820152604082013567ffffffffffffffff811115610d96575f5ffd5b919091019036601f830112610da9575f5ffd5b813567ffffffffffffffff811115610dc357610dc3610c19565b610df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610c9c565b818152366020838601011115610e08575f5ffd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050610d2e565b5095945050505050565b5f5b83811015610e5c578181015183820152602001610e44565b50505f910152565b5f8151808452610e7b816020860160208601610e42565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f82825180855260208501945060208160051b830101602085015f5b83811015610fbe577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0858403018852815180518452602081015160208501526040810151610f2f604086018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608501526080810151608085015260a0810151610f5b60a086018263ffffffff169052565b5060c081015160c085015260e081015160e08501526101008101516101008501526101208101516101208501526101408101519050610160610140850152610fa7610160850182610e64565b6020998a0199909450929092019150600101610ec9565b50909695505050505050565b5f8260608101835f5b600381101561109d578383038752815180518085526020918201918086019190600582901b8701015f5b82811015611083577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0888303018452845173ffffffffffffffffffffffffffffffffffffffff815116835260208101516020840152604081015190506060604084015261106d6060840182610e64565b6020968701969590950194925050600101610ffd565b5060209a8b019a9096509490940193505050600101610fd3565b509095945050505050565b608080825285519082018190525f90602087019060a0840190835b818110156110f757835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016110c3565b505083810360208501528091505f87518083526020830193506020890192505f5b81811015611136578351855260209485019490930192600101611118565b50505050828103604084015261114c8186610ead565b905082810360608401526111608185610fca565b979650505050505050565b5f6020828403121561117b575f5ffd5b81518015158114610952575f5ffd5b81810381811115610985577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f82516111d3818460208701610e42565b919091019291505056fea164736f6c634300081e000a", + "devdoc": { + "methods": {} + }, + "userdoc": { + "methods": {} + } +} diff --git a/contracts/artifacts/SwaprRouter.json b/contracts/artifacts/SwaprRouter.json new file mode 100644 index 0000000000..c95b7fd70d --- /dev/null +++ b/contracts/artifacts/SwaprRouter.json @@ -0,0 +1,957 @@ +{ + "abi": [ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/contracts/artifacts/TestnetUniswapV2Router02.json b/contracts/artifacts/TestnetUniswapV2Router02.json new file mode 100644 index 0000000000..c95b7fd70d --- /dev/null +++ b/contracts/artifacts/TestnetUniswapV2Router02.json @@ -0,0 +1,957 @@ +{ + "abi": [ + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountADesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountTokenDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "addLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveOut", + "type": "uint256" + } + ], + "name": "getAmountOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + } + ], + "name": "getAmountsOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETH", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityETHSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountETHMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountETH", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountAMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountBMin", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "approveMax", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "removeLiquidityWithPermit", + "outputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapETHForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactETH", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/crates/contracts/artifacts/UniswapV2Factory.json b/contracts/artifacts/UniswapV2Factory.json similarity index 99% rename from crates/contracts/artifacts/UniswapV2Factory.json rename to contracts/artifacts/UniswapV2Factory.json index c7cc7a97b7..043c56a2c9 100644 --- a/crates/contracts/artifacts/UniswapV2Factory.json +++ b/contracts/artifacts/UniswapV2Factory.json @@ -44,71 +44,70 @@ "type": "event" }, { - "constant": true, + "constant": false, "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "allPairs", - "outputs": [ + "internalType": "address", + "name": "tokenA", + "type": "address" + }, { "internalType": "address", - "name": "", + "name": "tokenB", "type": "address" } ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "allPairsLength", + "name": "createPair", "outputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "address", + "name": "pair", + "type": "address" } ], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { "internalType": "address", - "name": "tokenA", + "name": "", "type": "address" }, { "internalType": "address", - "name": "tokenB", + "name": "", "type": "address" } ], - "name": "createPair", + "name": "getPair", "outputs": [ { "internalType": "address", - "name": "pair", + "name": "", "type": "address" } ], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" - }, + } + ], + "bytecode": "608060405234801561001057600080fd5b506040516136863803806136868339818101604052602081101561003357600080fd5b5051600180546001600160a01b0319166001600160a01b03909216919091179055613623806100636000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063a2e74af61161005b578063a2e74af6146100fd578063c9c6539614610132578063e6a439051461016d578063f46901ed146101a857610088565b8063017e7e581461008d578063094b7415146100be5780631e3dd18b146100c6578063574f2ba3146100e3575b600080fd5b6100956101db565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100956101f7565b610095600480360360208110156100dc57600080fd5b5035610213565b6100eb610247565b60408051918252519081900360200190f35b6101306004803603602081101561011357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661024d565b005b6100956004803603604081101561014857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661031a565b6100956004803603604081101561018357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661076d565b610130600480360360208110156101be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166107a0565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6003818154811061022057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60035490565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156103b757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056323a204944454e544943414c5f4144445245535345530000604482015290519081900360640190fd5b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16106103f45783856103f7565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff821661047e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f556e697377617056323a205a45524f5f41444452455353000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526002602090815260408083208585168452909152902054161561051f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e697377617056323a20504149525f45584953545300000000000000000000604482015290519081900360640190fd5b6060604051806020016105319061086d565b6020820181038252601f19601f82011660405250905060008383604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140192505050604051602081830303815290604052805190602001209050808251602084016000f5604080517f485cc95500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152868116602483015291519297509087169163485cc9559160448082019260009290919082900301818387803b15801561065e57600080fd5b505af1158015610672573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff84811660008181526002602081815260408084208987168086529083528185208054978d167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90950180549097168417909655925483519283529082015281517f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9929181900390910190a35050505092915050565b600260209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff16331461082657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b612d748061087b8339019056fe60806040526001600c5534801561001557600080fd5b506040514690806052612d228239604080519182900360520182208282018252600a8352692ab734b9bbb0b8102b1960b11b6020938401528151808301835260018152603160f81b908401528151808401919091527fbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c09094019052825192019190912060035550600580546001600160a01b03191633179055612c1d806101056000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a265627a7a723158202760f92d7fa1db6f5aa16307bad65df4ebcc8550c4b1f03755ab8dfd830c178f64736f6c63430005100032", + "_disabled": [ { "constant": true, - "inputs": [], - "name": "feeTo", + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allPairs", "outputs": [ { "internalType": "address", @@ -123,12 +122,12 @@ { "constant": true, "inputs": [], - "name": "feeToSetter", + "name": "allPairsLength", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "payable": false, @@ -137,19 +136,23 @@ }, { "constant": true, - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, + "inputs": [], + "name": "feeTo", + "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], - "name": "getPair", + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "feeToSetter", "outputs": [ { "internalType": "address", @@ -191,6 +194,5 @@ "stateMutability": "nonpayable", "type": "function" } - ], - "bytecode": "608060405234801561001057600080fd5b506040516136863803806136868339818101604052602081101561003357600080fd5b5051600180546001600160a01b0319166001600160a01b03909216919091179055613623806100636000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063a2e74af61161005b578063a2e74af6146100fd578063c9c6539614610132578063e6a439051461016d578063f46901ed146101a857610088565b8063017e7e581461008d578063094b7415146100be5780631e3dd18b146100c6578063574f2ba3146100e3575b600080fd5b6100956101db565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100956101f7565b610095600480360360208110156100dc57600080fd5b5035610213565b6100eb610247565b60408051918252519081900360200190f35b6101306004803603602081101561011357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661024d565b005b6100956004803603604081101561014857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661031a565b6100956004803603604081101561018357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661076d565b610130600480360360208110156101be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166107a0565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6003818154811061022057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60035490565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156103b757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056323a204944454e544943414c5f4144445245535345530000604482015290519081900360640190fd5b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16106103f45783856103f7565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff821661047e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f556e697377617056323a205a45524f5f41444452455353000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526002602090815260408083208585168452909152902054161561051f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e697377617056323a20504149525f45584953545300000000000000000000604482015290519081900360640190fd5b6060604051806020016105319061086d565b6020820181038252601f19601f82011660405250905060008383604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140192505050604051602081830303815290604052805190602001209050808251602084016000f5604080517f485cc95500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152868116602483015291519297509087169163485cc9559160448082019260009290919082900301818387803b15801561065e57600080fd5b505af1158015610672573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff84811660008181526002602081815260408084208987168086529083528185208054978d167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90950180549097168417909655925483519283529082015281517f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9929181900390910190a35050505092915050565b600260209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff16331461082657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b612d748061087b8339019056fe60806040526001600c5534801561001557600080fd5b506040514690806052612d228239604080519182900360520182208282018252600a8352692ab734b9bbb0b8102b1960b11b6020938401528151808301835260018152603160f81b908401528151808401919091527fbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c09094019052825192019190912060035550600580546001600160a01b03191633179055612c1d806101056000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a265627a7a723158202760f92d7fa1db6f5aa16307bad65df4ebcc8550c4b1f03755ab8dfd830c178f64736f6c63430005100032" + ] } diff --git a/crates/contracts/artifacts/UniswapV2Router02.json b/contracts/artifacts/UniswapV2Router02.json similarity index 99% rename from crates/contracts/artifacts/UniswapV2Router02.json rename to contracts/artifacts/UniswapV2Router02.json index bb735ec84e..93f965d0d8 100644 --- a/crates/contracts/artifacts/UniswapV2Router02.json +++ b/contracts/artifacts/UniswapV2Router02.json @@ -16,6 +16,10 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "stateMutability": "payable", + "type": "receive" + }, { "inputs": [], "name": "WETH", @@ -93,6 +97,90 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveB", + "type": "uint256" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "uint256", + "name": "amountB", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "path", + "type": "address[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "60c06040523480156200001157600080fd5b506040516200573e3803806200573e833981810160405260408110156200003757600080fd5b5080516020909101516001600160601b0319606092831b8116608052911b1660a05260805160601c60a05160601c6155b762000187600039806101ac5280610e5d5280610e985280610fd5528061129852806116f252806118d65280611e1e5280611fa252806120725280612179528061232c52806123c15280612673528061271a52806127ef52806128f452806129dc5280612a5d52806130ec5280613422528061347852806134ac528061352d528061374752806138f7528061398c5250806110c752806111c5528061136b52806113a4528061154f52806117e452806118b45280611aa1528061225f528061240052806125a95280612a9c5280612ddf5280613071528061309a52806130ca52806132a75280613456528061382d52806139cb528061444a528061448d52806147ed52806149ce5280614f49528061502a52806150aa52506155b76000f3fe60806040526004361061018f5760003560e01c80638803dbee116100d6578063c45a01551161007f578063e8e3370011610059578063e8e3370014610c71578063f305d71914610cfe578063fb3bdb4114610d51576101d5565b8063c45a015514610b25578063d06ca61f14610b3a578063ded9382a14610bf1576101d5565b8063af2979eb116100b0578063af2979eb146109c8578063b6f9de9514610a28578063baa2abde14610abb576101d5565b80638803dbee146108af578063ad5c464814610954578063ad615dec14610992576101d5565b80634a25d94a11610138578063791ac94711610112578063791ac947146107415780637ff36ab5146107e657806385f8c25914610879576101d5565b80634a25d94a146105775780635b0d59841461061c5780635c11d7951461069c576101d5565b80631f00ca74116101695780631f00ca74146103905780632195995c1461044757806338ed1739146104d2576101d5565b806302751cec146101da578063054d50d41461025357806318cbafe51461029b576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061023a600480360360c08110156101fd57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a00135610de4565b6040805192835260208301919091528051918290030190f35b34801561025f57600080fd5b506102896004803603606081101561027657600080fd5b5080359060208101359060400135610f37565b60408051918252519081900360200190f35b3480156102a757600080fd5b50610340600480360360a08110156102be57600080fd5b8135916020810135918101906060810160408201356401000000008111156102e557600080fd5b8201836020820111156102f757600080fd5b8035906020019184602083028401116401000000008311171561031957600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f4c565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561037c578181015183820152602001610364565b505050509050019250505060405180910390f35b34801561039c57600080fd5b50610340600480360360408110156103b357600080fd5b813591908101906040810160208201356401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611364945050505050565b34801561045357600080fd5b5061023a600480360361016081101561046b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff610100820135169061012081013590610140013561139a565b3480156104de57600080fd5b50610340600480360360a08110156104f557600080fd5b81359160208101359181019060608101604082013564010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184602083028401116401000000008311171561055057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356114d8565b34801561058357600080fd5b50610340600480360360a081101561059a57600080fd5b8135916020810135918101906060810160408201356401000000008111156105c157600080fd5b8201836020820111156105d357600080fd5b803590602001918460208302840111640100000000831117156105f557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611669565b34801561062857600080fd5b50610289600480360361014081101561064057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356118ac565b3480156106a857600080fd5b506101d3600480360360a08110156106bf57600080fd5b8135916020810135918101906060810160408201356401000000008111156106e657600080fd5b8201836020820111156106f857600080fd5b8035906020019184602083028401116401000000008311171561071a57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356119fe565b34801561074d57600080fd5b506101d3600480360360a081101561076457600080fd5b81359160208101359181019060608101604082013564010000000081111561078b57600080fd5b82018360208201111561079d57600080fd5b803590602001918460208302840111640100000000831117156107bf57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d97565b610340600480360360808110156107fc57600080fd5b8135919081019060408101602082013564010000000081111561081e57600080fd5b82018360208201111561083057600080fd5b8035906020019184602083028401116401000000008311171561085257600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612105565b34801561088557600080fd5b506102896004803603606081101561089c57600080fd5b5080359060208101359060400135612525565b3480156108bb57600080fd5b50610340600480360360a08110156108d257600080fd5b8135916020810135918101906060810160408201356401000000008111156108f957600080fd5b82018360208201111561090b57600080fd5b8035906020019184602083028401116401000000008311171561092d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612532565b34801561096057600080fd5b50610969612671565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561099e57600080fd5b50610289600480360360608110156109b557600080fd5b5080359060208101359060400135612695565b3480156109d457600080fd5b50610289600480360360c08110156109eb57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356126a2565b6101d360048036036080811015610a3e57600080fd5b81359190810190604081016020820135640100000000811115610a6057600080fd5b820183602082011115610a7257600080fd5b80359060200191846020830284011164010000000083111715610a9457600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612882565b348015610ac757600080fd5b5061023a600480360360e0811015610ade57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135612d65565b348015610b3157600080fd5b5061096961306f565b348015610b4657600080fd5b5061034060048036036040811015610b5d57600080fd5b81359190810190604081016020820135640100000000811115610b7f57600080fd5b820183602082011115610b9157600080fd5b80359060200191846020830284011164010000000083111715610bb357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613093945050505050565b348015610bfd57600080fd5b5061023a6004803603610140811015610c1557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356130c0565b348015610c7d57600080fd5b50610ce06004803603610100811015610c9557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135613218565b60408051938452602084019290925282820152519081900360600190f35b610ce0600480360360c0811015610d1457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356133a7565b61034060048036036080811015610d6757600080fd5b81359190810190604081016020820135640100000000811115610d8957600080fd5b820183602082011115610d9b57600080fd5b80359060200191846020830284011164010000000083111715610dbd57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356136d3565b6000808242811015610e5757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b610e86897f00000000000000000000000000000000000000000000000000000000000000008a8a8a308a612d65565b9093509150610e96898685613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050610f2b8583613cff565b50965096945050505050565b6000610f44848484613e3c565b949350505050565b60608142811015610fbe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061102357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146110c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6111207f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b9150868260018451038151811061113357fe5b60200260200101511015611192576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b611257868660008181106111a257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff163361123d7f00000000000000000000000000000000000000000000000000000000000000008a8a60008181106111f157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b8b600181811061121b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166140c6565b8560008151811061124a57fe5b60200260200101516141b1565b61129682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614381915050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836001855103815181106112e257fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b50505050611359848360018551038151811061134c57fe5b6020026020010151613cff565b509695505050505050565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484614608565b90505b92915050565b60008060006113ca7f00000000000000000000000000000000000000000000000000000000000000008f8f6140c6565b90506000876113d9578c6113fb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506114be8f8f8f8f8f8f8f612d65565b809450819550505050509b509b9950505050505050505050565b6060814281101561154a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6115a87f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106115bb57fe5b6020026020010151101561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b61162a868660008181106111a257fe5b61135982878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b606081428110156116db57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061174057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146117df57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b61183d7f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061184d57fe5b60200260200101511115611192576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b6000806118fa7f00000000000000000000000000000000000000000000000000000000000000008d7f00000000000000000000000000000000000000000000000000000000000000006140c6565b9050600086611909578b61192b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506119ed8d8d8d8d8d8d6126a2565b9d9c50505050505050505050505050565b8042811015611a6e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b611afd85856000818110611a7e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1633611af77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168a8a600181811061121b57fe5b8a6141b1565b600085857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611b2d57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611bc657600080fd5b505afa158015611bda573d6000803e3d6000fd5b505050506040513d6020811015611bf057600080fd5b50516040805160208881028281018201909352888252929350611c32929091899189918291850190849080828437600092019190915250889250614796915050565b86611d368288887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611c6557fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b50519063ffffffff614b2916565b1015611d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b5050505050505050565b8042811015611e0757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611e6c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b611f1b85856000818110611a7e57fe5b611f59858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614796915050565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b5051905086811015612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b50505050611d8d8482613cff565b6060814281101561217757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16868660008181106121bb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461225a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6122b87f000000000000000000000000000000000000000000000000000000000000000034888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106122cb57fe5b6020026020010151101561232a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061237357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61242c7f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b8460008151811061243957fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505050506040513d60208110156124d457600080fd5b50516124dc57fe5b61251b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b5095945050505050565b6000610f44848484614b9b565b606081428110156125a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6126027f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061261257fe5b6020026020010151111561161a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610f44848484614cbf565b6000814281101561271457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b612743887f00000000000000000000000000000000000000000000000000000000000000008989893089612d65565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519194506127ed92508a91879173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b1580156127bc57600080fd5b505afa1580156127d0573d6000803e3d6000fd5b505050506040513d60208110156127e657600080fd5b5051613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561286057600080fd5b505af1158015612874573d6000803e3d6000fd5b505050506113598483613cff565b80428110156128f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168585600081811061293657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146129d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b60003490507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4257600080fd5b505af1158015612a56573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb612ac87f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b3257600080fd5b505af1158015612b46573d6000803e3d6000fd5b505050506040513d6020811015612b5c57600080fd5b5051612b6457fe5b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612b9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c2d57600080fd5b505afa158015612c41573d6000803e3d6000fd5b505050506040513d6020811015612c5757600080fd5b50516040805160208981028281018201909352898252929350612c999290918a918a918291850190849080828437600092019190915250899250614796915050565b87611d368289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612ccc57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b6000808242811015612dd857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6000612e057f00000000000000000000000000000000000000000000000000000000000000008c8c6140c6565b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b158015612e8657600080fd5b505af1158015612e9a573d6000803e3d6000fd5b505050506040513d6020811015612eb057600080fd5b5050604080517f89afcb4400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b158015612f2357600080fd5b505af1158015612f37573d6000803e3d6000fd5b505050506040513d6040811015612f4d57600080fd5b50805160209091015190925090506000612f678e8e614d9f565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614612fa4578183612fa7565b82825b90975095508a871015613005576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b8986101561305e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b505050505097509795505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484613f60565b60008060006131107f00000000000000000000000000000000000000000000000000000000000000008e7f00000000000000000000000000000000000000000000000000000000000000006140c6565b905060008761311f578c613141565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156131dd57600080fd5b505af11580156131f1573d6000803e3d6000fd5b505050506132038e8e8e8e8e8e610de4565b909f909e509c50505050505050505050505050565b6000806000834281101561328d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61329b8c8c8c8c8c8c614ef2565b909450925060006132cd7f00000000000000000000000000000000000000000000000000000000000000008e8e6140c6565b90506132db8d3383886141b1565b6132e78c3383876141b1565b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561336657600080fd5b505af115801561337a573d6000803e3d6000fd5b505050506040513d602081101561339057600080fd5b5051949d939c50939a509198505050505050505050565b6000806000834281101561341c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61344a8a7f00000000000000000000000000000000000000000000000000000000000000008b348c8c614ef2565b9094509250600061349c7f00000000000000000000000000000000000000000000000000000000000000008c7f00000000000000000000000000000000000000000000000000000000000000006140c6565b90506134aa8b3383886141b1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561351257600080fd5b505af1158015613526573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb82866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b505050506040513d60208110156135fc57600080fd5b505161360457fe5b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561368357600080fd5b505af1158015613697573d6000803e3d6000fd5b505050506040513d60208110156136ad57600080fd5b50519250348410156136c5576136c533853403613cff565b505096509650969350505050565b6060814281101561374557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168686600081811061378957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461382857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6138867f00000000000000000000000000000000000000000000000000000000000000008888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150348260008151811061389657fe5b602002602001015111156138f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061393e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397157600080fd5b505af1158015613985573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6139f77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b84600081518110613a0457fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015613a7557600080fd5b505af1158015613a89573d6000803e3d6000fd5b505050506040513d6020811015613a9f57600080fd5b5051613aa757fe5b613ae682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b81600081518110613af357fe5b602002602001015134111561251b5761251b3383600081518110613b1357fe5b60200260200101513403613cff565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613bf857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613bbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c5a576040519150601f19603f3d011682016040523d82523d6000602084013e613c5f565b606091505b5091509150818015613c8d575080511580613c8d5750808060200190516020811015613c8a57600080fd5b50515b613cf857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b5050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310613d7657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613d39565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613dd8576040519150601f19603f3d011682016040523d82523d6000602084013e613ddd565b606091505b5050905080613e37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806154e56023913960400191505060405180910390fd5b505050565b6000808411613e96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615557602b913960400191505060405180910390fd5b600083118015613ea65750600082115b613efb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000613f0f856103e563ffffffff6151f316565b90506000613f23828563ffffffff6151f316565b90506000613f4983613f3d886103e863ffffffff6151f316565b9063ffffffff61527916565b9050808281613f5457fe5b04979650505050505050565b6060600282511015613fd357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff81118015613feb57600080fd5b50604051908082528060200260200182016040528015614015578160200160208202803683370190505b509050828160008151811061402657fe5b60200260200101818152505060005b60018351038110156140be576000806140788786858151811061405457fe5b602002602001015187866001018151811061406b57fe5b60200260200101516152eb565b9150915061409a84848151811061408b57fe5b60200260200101518383613e3c565b8484600101815181106140a957fe5b60209081029190910101525050600101614035565b509392505050565b60008060006140d58585614d9f565b604080517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017815292518251600094606094938a169392918291908083835b6020831061428f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614252565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146142f1576040519150601f19603f3d011682016040523d82523d6000602084013e6142f6565b606091505b5091509150818015614324575080511580614324575080806020019051602081101561432157600080fd5b50515b614379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806155336024913960400191505060405180910390fd5b505050505050565b60005b60018351038110156146025760008084838151811061439f57fe5b60200260200101518584600101815181106143b657fe5b60200260200101519150915060006143ce8383614d9f565b50905060008785600101815181106143e257fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461442a5782600061442e565b6000835b91509150600060028a510388106144455788614486565b6144867f0000000000000000000000000000000000000000000000000000000000000000878c8b6002018151811061447957fe5b60200260200101516140c6565b90506144b37f000000000000000000000000000000000000000000000000000000000000000088886140c6565b73ffffffffffffffffffffffffffffffffffffffff1663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156144fd576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614588578181015183820152602001614570565b50505050905090810190601f1680156145b55780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156145d757600080fd5b505af11580156145eb573d6000803e3d6000fd5b505060019099019850614384975050505050505050565b50505050565b606060028251101561467b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561469357600080fd5b506040519080825280602002602001820160405280156146bd578160200160208202803683370190505b50905082816001835103815181106146d157fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b80156140be576000806147318786600186038151811061471d57fe5b602002602001015187868151811061406b57fe5b9150915061475384848151811061474457fe5b60200260200101518383614b9b565b84600185038151811061476257fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614701565b60005b6001835103811015613e37576000808483815181106147b457fe5b60200260200101518584600101815181106147cb57fe5b60200260200101519150915060006147e38383614d9f565b50905060006148137f000000000000000000000000000000000000000000000000000000000000000085856140c6565b90506000806000808473ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561486157600080fd5b505afa158015614875573d6000803e3d6000fd5b505050506040513d606081101561488b57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905060008073ffffffffffffffffffffffffffffffffffffffff8a8116908916146148d55782846148d8565b83835b9150915061495d828b73ffffffffffffffffffffffffffffffffffffffff166370a082318a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b955061496a868383613e3c565b9450505050506000808573ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146149ae578260006149b2565b6000835b91509150600060028c51038a106149c9578a6149fd565b6149fd7f0000000000000000000000000000000000000000000000000000000000000000898e8d6002018151811061447957fe5b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614aad578181015183820152602001614a95565b50505050905090810190601f168015614ada5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614afc57600080fd5b505af1158015614b10573d6000803e3d6000fd5b50506001909b019a506147999950505050505050505050565b8082038281111561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6000808411614bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806153d4602c913960400191505060405180910390fd5b600083118015614c055750600082115b614c5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000614c7e6103e8614c72868863ffffffff6151f316565b9063ffffffff6151f316565b90506000614c986103e5614c72868963ffffffff614b2916565b9050614cb56001828481614ca857fe5b049063ffffffff61527916565b9695505050505050565b6000808411614d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154736025913960400191505060405180910390fd5b600083118015614d295750600082115b614d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b82614d8f858463ffffffff6151f316565b81614d9657fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415614e27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154006025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610614e61578284614e64565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216614eeb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529151600092839283927f00000000000000000000000000000000000000000000000000000000000000009092169163e6a4390591604480820192602092909190829003018186803b158015614f9257600080fd5b505afa158015614fa6573d6000803e3d6000fd5b505050506040513d6020811015614fbc57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614156150a257604080517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152898116602483015291517f00000000000000000000000000000000000000000000000000000000000000009092169163c9c65396916044808201926020929091908290030181600087803b15801561507557600080fd5b505af1158015615089573d6000803e3d6000fd5b505050506040513d602081101561509f57600080fd5b50505b6000806150d07f00000000000000000000000000000000000000000000000000000000000000008b8b6152eb565b915091508160001480156150e2575080155b156150f2578793508692506151e6565b60006150ff898484614cbf565b905087811161516c5785811015615161576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b8894509250826151e4565b6000615179898486614cbf565b90508981111561518557fe5b878110156151de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061520e5750508082028282828161520b57fe5b04145b61139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b8082018281101561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008060006152fa8585614d9f565b50905060008061530b8888886140c6565b73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561535057600080fd5b505afa158015615364573d6000803e3d6000fd5b505050506040513d606081101561537a57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905073ffffffffffffffffffffffffffffffffffffffff878116908416146153c15780826153c4565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a26469706673582212206dd6e03c4b2c0a8e55214926227ae9e2d6f9fec2ce74a6446d615afa355c84f364736f6c63430006060033", + "_disabled": [ { "inputs": [ { @@ -147,19 +235,6 @@ "stateMutability": "payable", "type": "function" }, - { - "inputs": [], - "name": "factory", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -266,35 +341,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveA", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "reserveB", - "type": "uint256" - } - ], - "name": "quote", - "outputs": [ - { - "internalType": "uint256", - "name": "amountB", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - }, { "inputs": [ { @@ -927,50 +973,6 @@ ], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountInMax", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "path", - "type": "address[]" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "swapTokensForExactTokens", - "outputs": [ - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" } - ], - "bytecode": "60c06040523480156200001157600080fd5b506040516200573e3803806200573e833981810160405260408110156200003757600080fd5b5080516020909101516001600160601b0319606092831b8116608052911b1660a05260805160601c60a05160601c6155b762000187600039806101ac5280610e5d5280610e985280610fd5528061129852806116f252806118d65280611e1e5280611fa252806120725280612179528061232c52806123c15280612673528061271a52806127ef52806128f452806129dc5280612a5d52806130ec5280613422528061347852806134ac528061352d528061374752806138f7528061398c5250806110c752806111c5528061136b52806113a4528061154f52806117e452806118b45280611aa1528061225f528061240052806125a95280612a9c5280612ddf5280613071528061309a52806130ca52806132a75280613456528061382d52806139cb528061444a528061448d52806147ed52806149ce5280614f49528061502a52806150aa52506155b76000f3fe60806040526004361061018f5760003560e01c80638803dbee116100d6578063c45a01551161007f578063e8e3370011610059578063e8e3370014610c71578063f305d71914610cfe578063fb3bdb4114610d51576101d5565b8063c45a015514610b25578063d06ca61f14610b3a578063ded9382a14610bf1576101d5565b8063af2979eb116100b0578063af2979eb146109c8578063b6f9de9514610a28578063baa2abde14610abb576101d5565b80638803dbee146108af578063ad5c464814610954578063ad615dec14610992576101d5565b80634a25d94a11610138578063791ac94711610112578063791ac947146107415780637ff36ab5146107e657806385f8c25914610879576101d5565b80634a25d94a146105775780635b0d59841461061c5780635c11d7951461069c576101d5565b80631f00ca74116101695780631f00ca74146103905780632195995c1461044757806338ed1739146104d2576101d5565b806302751cec146101da578063054d50d41461025357806318cbafe51461029b576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061023a600480360360c08110156101fd57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a00135610de4565b6040805192835260208301919091528051918290030190f35b34801561025f57600080fd5b506102896004803603606081101561027657600080fd5b5080359060208101359060400135610f37565b60408051918252519081900360200190f35b3480156102a757600080fd5b50610340600480360360a08110156102be57600080fd5b8135916020810135918101906060810160408201356401000000008111156102e557600080fd5b8201836020820111156102f757600080fd5b8035906020019184602083028401116401000000008311171561031957600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f4c565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561037c578181015183820152602001610364565b505050509050019250505060405180910390f35b34801561039c57600080fd5b50610340600480360360408110156103b357600080fd5b813591908101906040810160208201356401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611364945050505050565b34801561045357600080fd5b5061023a600480360361016081101561046b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff610100820135169061012081013590610140013561139a565b3480156104de57600080fd5b50610340600480360360a08110156104f557600080fd5b81359160208101359181019060608101604082013564010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184602083028401116401000000008311171561055057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356114d8565b34801561058357600080fd5b50610340600480360360a081101561059a57600080fd5b8135916020810135918101906060810160408201356401000000008111156105c157600080fd5b8201836020820111156105d357600080fd5b803590602001918460208302840111640100000000831117156105f557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611669565b34801561062857600080fd5b50610289600480360361014081101561064057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356118ac565b3480156106a857600080fd5b506101d3600480360360a08110156106bf57600080fd5b8135916020810135918101906060810160408201356401000000008111156106e657600080fd5b8201836020820111156106f857600080fd5b8035906020019184602083028401116401000000008311171561071a57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356119fe565b34801561074d57600080fd5b506101d3600480360360a081101561076457600080fd5b81359160208101359181019060608101604082013564010000000081111561078b57600080fd5b82018360208201111561079d57600080fd5b803590602001918460208302840111640100000000831117156107bf57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d97565b610340600480360360808110156107fc57600080fd5b8135919081019060408101602082013564010000000081111561081e57600080fd5b82018360208201111561083057600080fd5b8035906020019184602083028401116401000000008311171561085257600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612105565b34801561088557600080fd5b506102896004803603606081101561089c57600080fd5b5080359060208101359060400135612525565b3480156108bb57600080fd5b50610340600480360360a08110156108d257600080fd5b8135916020810135918101906060810160408201356401000000008111156108f957600080fd5b82018360208201111561090b57600080fd5b8035906020019184602083028401116401000000008311171561092d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612532565b34801561096057600080fd5b50610969612671565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561099e57600080fd5b50610289600480360360608110156109b557600080fd5b5080359060208101359060400135612695565b3480156109d457600080fd5b50610289600480360360c08110156109eb57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356126a2565b6101d360048036036080811015610a3e57600080fd5b81359190810190604081016020820135640100000000811115610a6057600080fd5b820183602082011115610a7257600080fd5b80359060200191846020830284011164010000000083111715610a9457600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612882565b348015610ac757600080fd5b5061023a600480360360e0811015610ade57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135612d65565b348015610b3157600080fd5b5061096961306f565b348015610b4657600080fd5b5061034060048036036040811015610b5d57600080fd5b81359190810190604081016020820135640100000000811115610b7f57600080fd5b820183602082011115610b9157600080fd5b80359060200191846020830284011164010000000083111715610bb357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613093945050505050565b348015610bfd57600080fd5b5061023a6004803603610140811015610c1557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356130c0565b348015610c7d57600080fd5b50610ce06004803603610100811015610c9557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135613218565b60408051938452602084019290925282820152519081900360600190f35b610ce0600480360360c0811015610d1457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356133a7565b61034060048036036080811015610d6757600080fd5b81359190810190604081016020820135640100000000811115610d8957600080fd5b820183602082011115610d9b57600080fd5b80359060200191846020830284011164010000000083111715610dbd57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356136d3565b6000808242811015610e5757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b610e86897f00000000000000000000000000000000000000000000000000000000000000008a8a8a308a612d65565b9093509150610e96898685613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050610f2b8583613cff565b50965096945050505050565b6000610f44848484613e3c565b949350505050565b60608142811015610fbe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061102357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146110c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6111207f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b9150868260018451038151811061113357fe5b60200260200101511015611192576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b611257868660008181106111a257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff163361123d7f00000000000000000000000000000000000000000000000000000000000000008a8a60008181106111f157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b8b600181811061121b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166140c6565b8560008151811061124a57fe5b60200260200101516141b1565b61129682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614381915050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836001855103815181106112e257fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b50505050611359848360018551038151811061134c57fe5b6020026020010151613cff565b509695505050505050565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484614608565b90505b92915050565b60008060006113ca7f00000000000000000000000000000000000000000000000000000000000000008f8f6140c6565b90506000876113d9578c6113fb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506114be8f8f8f8f8f8f8f612d65565b809450819550505050509b509b9950505050505050505050565b6060814281101561154a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6115a87f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106115bb57fe5b6020026020010151101561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b61162a868660008181106111a257fe5b61135982878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b606081428110156116db57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061174057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146117df57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b61183d7f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061184d57fe5b60200260200101511115611192576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b6000806118fa7f00000000000000000000000000000000000000000000000000000000000000008d7f00000000000000000000000000000000000000000000000000000000000000006140c6565b9050600086611909578b61192b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506119ed8d8d8d8d8d8d6126a2565b9d9c50505050505050505050505050565b8042811015611a6e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b611afd85856000818110611a7e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1633611af77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168a8a600181811061121b57fe5b8a6141b1565b600085857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611b2d57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611bc657600080fd5b505afa158015611bda573d6000803e3d6000fd5b505050506040513d6020811015611bf057600080fd5b50516040805160208881028281018201909352888252929350611c32929091899189918291850190849080828437600092019190915250889250614796915050565b86611d368288887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611c6557fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b50519063ffffffff614b2916565b1015611d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b5050505050505050565b8042811015611e0757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611e6c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b611f1b85856000818110611a7e57fe5b611f59858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614796915050565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b5051905086811015612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b50505050611d8d8482613cff565b6060814281101561217757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16868660008181106121bb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461225a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6122b87f000000000000000000000000000000000000000000000000000000000000000034888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106122cb57fe5b6020026020010151101561232a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061237357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61242c7f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b8460008151811061243957fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505050506040513d60208110156124d457600080fd5b50516124dc57fe5b61251b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b5095945050505050565b6000610f44848484614b9b565b606081428110156125a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6126027f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061261257fe5b6020026020010151111561161a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610f44848484614cbf565b6000814281101561271457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b612743887f00000000000000000000000000000000000000000000000000000000000000008989893089612d65565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519194506127ed92508a91879173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b1580156127bc57600080fd5b505afa1580156127d0573d6000803e3d6000fd5b505050506040513d60208110156127e657600080fd5b5051613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561286057600080fd5b505af1158015612874573d6000803e3d6000fd5b505050506113598483613cff565b80428110156128f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168585600081811061293657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146129d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b60003490507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4257600080fd5b505af1158015612a56573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb612ac87f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b3257600080fd5b505af1158015612b46573d6000803e3d6000fd5b505050506040513d6020811015612b5c57600080fd5b5051612b6457fe5b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612b9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c2d57600080fd5b505afa158015612c41573d6000803e3d6000fd5b505050506040513d6020811015612c5757600080fd5b50516040805160208981028281018201909352898252929350612c999290918a918a918291850190849080828437600092019190915250899250614796915050565b87611d368289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612ccc57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b6000808242811015612dd857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6000612e057f00000000000000000000000000000000000000000000000000000000000000008c8c6140c6565b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b158015612e8657600080fd5b505af1158015612e9a573d6000803e3d6000fd5b505050506040513d6020811015612eb057600080fd5b5050604080517f89afcb4400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b158015612f2357600080fd5b505af1158015612f37573d6000803e3d6000fd5b505050506040513d6040811015612f4d57600080fd5b50805160209091015190925090506000612f678e8e614d9f565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614612fa4578183612fa7565b82825b90975095508a871015613005576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b8986101561305e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b505050505097509795505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484613f60565b60008060006131107f00000000000000000000000000000000000000000000000000000000000000008e7f00000000000000000000000000000000000000000000000000000000000000006140c6565b905060008761311f578c613141565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156131dd57600080fd5b505af11580156131f1573d6000803e3d6000fd5b505050506132038e8e8e8e8e8e610de4565b909f909e509c50505050505050505050505050565b6000806000834281101561328d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61329b8c8c8c8c8c8c614ef2565b909450925060006132cd7f00000000000000000000000000000000000000000000000000000000000000008e8e6140c6565b90506132db8d3383886141b1565b6132e78c3383876141b1565b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561336657600080fd5b505af115801561337a573d6000803e3d6000fd5b505050506040513d602081101561339057600080fd5b5051949d939c50939a509198505050505050505050565b6000806000834281101561341c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61344a8a7f00000000000000000000000000000000000000000000000000000000000000008b348c8c614ef2565b9094509250600061349c7f00000000000000000000000000000000000000000000000000000000000000008c7f00000000000000000000000000000000000000000000000000000000000000006140c6565b90506134aa8b3383886141b1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561351257600080fd5b505af1158015613526573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb82866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b505050506040513d60208110156135fc57600080fd5b505161360457fe5b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561368357600080fd5b505af1158015613697573d6000803e3d6000fd5b505050506040513d60208110156136ad57600080fd5b50519250348410156136c5576136c533853403613cff565b505096509650969350505050565b6060814281101561374557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168686600081811061378957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461382857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6138867f00000000000000000000000000000000000000000000000000000000000000008888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150348260008151811061389657fe5b602002602001015111156138f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061393e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397157600080fd5b505af1158015613985573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6139f77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b84600081518110613a0457fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015613a7557600080fd5b505af1158015613a89573d6000803e3d6000fd5b505050506040513d6020811015613a9f57600080fd5b5051613aa757fe5b613ae682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b81600081518110613af357fe5b602002602001015134111561251b5761251b3383600081518110613b1357fe5b60200260200101513403613cff565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613bf857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613bbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c5a576040519150601f19603f3d011682016040523d82523d6000602084013e613c5f565b606091505b5091509150818015613c8d575080511580613c8d5750808060200190516020811015613c8a57600080fd5b50515b613cf857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b5050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310613d7657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613d39565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613dd8576040519150601f19603f3d011682016040523d82523d6000602084013e613ddd565b606091505b5050905080613e37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806154e56023913960400191505060405180910390fd5b505050565b6000808411613e96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615557602b913960400191505060405180910390fd5b600083118015613ea65750600082115b613efb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000613f0f856103e563ffffffff6151f316565b90506000613f23828563ffffffff6151f316565b90506000613f4983613f3d886103e863ffffffff6151f316565b9063ffffffff61527916565b9050808281613f5457fe5b04979650505050505050565b6060600282511015613fd357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff81118015613feb57600080fd5b50604051908082528060200260200182016040528015614015578160200160208202803683370190505b509050828160008151811061402657fe5b60200260200101818152505060005b60018351038110156140be576000806140788786858151811061405457fe5b602002602001015187866001018151811061406b57fe5b60200260200101516152eb565b9150915061409a84848151811061408b57fe5b60200260200101518383613e3c565b8484600101815181106140a957fe5b60209081029190910101525050600101614035565b509392505050565b60008060006140d58585614d9f565b604080517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017815292518251600094606094938a169392918291908083835b6020831061428f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614252565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146142f1576040519150601f19603f3d011682016040523d82523d6000602084013e6142f6565b606091505b5091509150818015614324575080511580614324575080806020019051602081101561432157600080fd5b50515b614379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806155336024913960400191505060405180910390fd5b505050505050565b60005b60018351038110156146025760008084838151811061439f57fe5b60200260200101518584600101815181106143b657fe5b60200260200101519150915060006143ce8383614d9f565b50905060008785600101815181106143e257fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461442a5782600061442e565b6000835b91509150600060028a510388106144455788614486565b6144867f0000000000000000000000000000000000000000000000000000000000000000878c8b6002018151811061447957fe5b60200260200101516140c6565b90506144b37f000000000000000000000000000000000000000000000000000000000000000088886140c6565b73ffffffffffffffffffffffffffffffffffffffff1663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156144fd576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614588578181015183820152602001614570565b50505050905090810190601f1680156145b55780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156145d757600080fd5b505af11580156145eb573d6000803e3d6000fd5b505060019099019850614384975050505050505050565b50505050565b606060028251101561467b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561469357600080fd5b506040519080825280602002602001820160405280156146bd578160200160208202803683370190505b50905082816001835103815181106146d157fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b80156140be576000806147318786600186038151811061471d57fe5b602002602001015187868151811061406b57fe5b9150915061475384848151811061474457fe5b60200260200101518383614b9b565b84600185038151811061476257fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614701565b60005b6001835103811015613e37576000808483815181106147b457fe5b60200260200101518584600101815181106147cb57fe5b60200260200101519150915060006147e38383614d9f565b50905060006148137f000000000000000000000000000000000000000000000000000000000000000085856140c6565b90506000806000808473ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561486157600080fd5b505afa158015614875573d6000803e3d6000fd5b505050506040513d606081101561488b57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905060008073ffffffffffffffffffffffffffffffffffffffff8a8116908916146148d55782846148d8565b83835b9150915061495d828b73ffffffffffffffffffffffffffffffffffffffff166370a082318a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b955061496a868383613e3c565b9450505050506000808573ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146149ae578260006149b2565b6000835b91509150600060028c51038a106149c9578a6149fd565b6149fd7f0000000000000000000000000000000000000000000000000000000000000000898e8d6002018151811061447957fe5b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614aad578181015183820152602001614a95565b50505050905090810190601f168015614ada5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614afc57600080fd5b505af1158015614b10573d6000803e3d6000fd5b50506001909b019a506147999950505050505050505050565b8082038281111561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6000808411614bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806153d4602c913960400191505060405180910390fd5b600083118015614c055750600082115b614c5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000614c7e6103e8614c72868863ffffffff6151f316565b9063ffffffff6151f316565b90506000614c986103e5614c72868963ffffffff614b2916565b9050614cb56001828481614ca857fe5b049063ffffffff61527916565b9695505050505050565b6000808411614d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154736025913960400191505060405180910390fd5b600083118015614d295750600082115b614d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b82614d8f858463ffffffff6151f316565b81614d9657fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415614e27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154006025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610614e61578284614e64565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216614eeb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529151600092839283927f00000000000000000000000000000000000000000000000000000000000000009092169163e6a4390591604480820192602092909190829003018186803b158015614f9257600080fd5b505afa158015614fa6573d6000803e3d6000fd5b505050506040513d6020811015614fbc57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614156150a257604080517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152898116602483015291517f00000000000000000000000000000000000000000000000000000000000000009092169163c9c65396916044808201926020929091908290030181600087803b15801561507557600080fd5b505af1158015615089573d6000803e3d6000fd5b505050506040513d602081101561509f57600080fd5b50505b6000806150d07f00000000000000000000000000000000000000000000000000000000000000008b8b6152eb565b915091508160001480156150e2575080155b156150f2578793508692506151e6565b60006150ff898484614cbf565b905087811161516c5785811015615161576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b8894509250826151e4565b6000615179898486614cbf565b90508981111561518557fe5b878110156151de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061520e5750508082028282828161520b57fe5b04145b61139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b8082018281101561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008060006152fa8585614d9f565b50905060008061530b8888886140c6565b73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561535057600080fd5b505afa158015615364573d6000803e3d6000fd5b505050506040513d606081101561537a57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905073ffffffffffffffffffffffffffffffffffffffff878116908416146153c15780826153c4565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a26469706673582212206dd6e03c4b2c0a8e55214926227ae9e2d6f9fec2ce74a6446d615afa355c84f364736f6c63430006060033" + ] } diff --git a/crates/contracts/artifacts/UniswapV3Pool.json b/contracts/artifacts/UniswapV3Pool.json similarity index 99% rename from crates/contracts/artifacts/UniswapV3Pool.json rename to contracts/artifacts/UniswapV3Pool.json index 87969854f7..8e04b0b6b5 100644 --- a/crates/contracts/artifacts/UniswapV3Pool.json +++ b/contracts/artifacts/UniswapV3Pool.json @@ -410,40 +410,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint128", - "name": "amount0Requested", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "amount1Requested", - "type": "uint128" - } - ], - "name": "collectProtocol", - "outputs": [ - { - "internalType": "uint128", - "name": "amount0", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "amount1", - "type": "uint128" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "factory", @@ -470,32 +436,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "feeGrowthGlobal0X128", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeGrowthGlobal1X128", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -524,19 +464,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "observationCardinalityNext", - "type": "uint16" - } - ], - "name": "increaseObservationCardinalityNext", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -563,19 +490,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "maxLiquidityPerTick", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -738,151 +652,179 @@ { "inputs": [ { - "internalType": "uint8", - "name": "feeProtocol0", - "type": "uint8" - }, - { - "internalType": "uint8", - "name": "feeProtocol1", - "type": "uint8" - } - ], - "name": "setFeeProtocol", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "slot0", - "outputs": [ - { - "internalType": "uint160", - "name": "sqrtPriceX96", - "type": "uint160" + "internalType": "address", + "name": "recipient", + "type": "address" }, { - "internalType": "int24", - "name": "tick", - "type": "int24" + "internalType": "bool", + "name": "zeroForOne", + "type": "bool" }, { - "internalType": "uint16", - "name": "observationIndex", - "type": "uint16" + "internalType": "int256", + "name": "amountSpecified", + "type": "int256" }, { - "internalType": "uint16", - "name": "observationCardinality", - "type": "uint16" + "internalType": "uint160", + "name": "sqrtPriceLimitX96", + "type": "uint160" }, { - "internalType": "uint16", - "name": "observationCardinalityNext", - "type": "uint16" - }, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "swap", + "outputs": [ { - "internalType": "uint8", - "name": "feeProtocol", - "type": "uint8" + "internalType": "int256", + "name": "amount0", + "type": "int256" }, { - "internalType": "bool", - "name": "unlocked", - "type": "bool" + "internalType": "int256", + "name": "amount1", + "type": "int256" } ], - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "int24", - "name": "tickLower", - "type": "int24" - }, - { - "internalType": "int24", - "name": "tickUpper", + "name": "", "type": "int24" } ], - "name": "snapshotCumulativesInside", + "name": "ticks", "outputs": [ + { + "internalType": "uint128", + "name": "liquidityGross", + "type": "uint128" + }, + { + "internalType": "int128", + "name": "liquidityNet", + "type": "int128" + }, + { + "internalType": "uint256", + "name": "feeGrowthOutside0X128", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "feeGrowthOutside1X128", + "type": "uint256" + }, { "internalType": "int56", - "name": "tickCumulativeInside", + "name": "tickCumulativeOutside", "type": "int56" }, { "internalType": "uint160", - "name": "secondsPerLiquidityInsideX128", + "name": "secondsPerLiquidityOutsideX128", "type": "uint160" }, { "internalType": "uint32", - "name": "secondsInside", + "name": "secondsOutside", "type": "uint32" + }, + { + "internalType": "bool", + "name": "initialized", + "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "token0", + "outputs": [ { "internalType": "address", - "name": "recipient", + "name": "", "type": "address" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1", + "outputs": [ { - "internalType": "bool", - "name": "zeroForOne", - "type": "bool" - }, + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "_disabled": [ + { + "inputs": [ { - "internalType": "int256", - "name": "amountSpecified", - "type": "int256" + "internalType": "address", + "name": "recipient", + "type": "address" }, { - "internalType": "uint160", - "name": "sqrtPriceLimitX96", - "type": "uint160" + "internalType": "uint128", + "name": "amount0Requested", + "type": "uint128" }, { - "internalType": "bytes", - "name": "data", - "type": "bytes" + "internalType": "uint128", + "name": "amount1Requested", + "type": "uint128" } ], - "name": "swap", + "name": "collectProtocol", "outputs": [ { - "internalType": "int256", + "internalType": "uint128", "name": "amount0", - "type": "int256" + "type": "uint128" }, { - "internalType": "int256", + "internalType": "uint128", "name": "amount1", - "type": "int256" + "type": "uint128" } ], "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [ + "inputs": [], + "name": "feeGrowthGlobal0X128", + "outputs": [ { - "internalType": "int16", + "internalType": "uint256", "name": "", - "type": "int16" + "type": "uint256" } ], - "name": "tickBitmap", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGrowthGlobal1X128", "outputs": [ { "internalType": "uint256", @@ -893,14 +835,27 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "observationCardinalityNext", + "type": "uint16" + } + ], + "name": "increaseObservationCardinalityNext", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], - "name": "tickSpacing", + "name": "maxLiquidityPerTick", "outputs": [ { - "internalType": "int24", + "internalType": "uint128", "name": "", - "type": "int24" + "type": "uint128" } ], "stateMutability": "view", @@ -909,65 +864,112 @@ { "inputs": [ { - "internalType": "int24", - "name": "", - "type": "int24" + "internalType": "uint8", + "name": "feeProtocol0", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "feeProtocol1", + "type": "uint8" } ], - "name": "ticks", + "name": "setFeeProtocol", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slot0", "outputs": [ { - "internalType": "uint128", - "name": "liquidityGross", - "type": "uint128" + "internalType": "uint160", + "name": "sqrtPriceX96", + "type": "uint160" }, { - "internalType": "int128", - "name": "liquidityNet", - "type": "int128" + "internalType": "int24", + "name": "tick", + "type": "int24" }, { - "internalType": "uint256", - "name": "feeGrowthOutside0X128", - "type": "uint256" + "internalType": "uint16", + "name": "observationIndex", + "type": "uint16" }, { - "internalType": "uint256", - "name": "feeGrowthOutside1X128", - "type": "uint256" + "internalType": "uint16", + "name": "observationCardinality", + "type": "uint16" }, + { + "internalType": "uint16", + "name": "observationCardinalityNext", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "feeProtocol", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "unlocked", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int24", + "name": "tickLower", + "type": "int24" + }, + { + "internalType": "int24", + "name": "tickUpper", + "type": "int24" + } + ], + "name": "snapshotCumulativesInside", + "outputs": [ { "internalType": "int56", - "name": "tickCumulativeOutside", + "name": "tickCumulativeInside", "type": "int56" }, { "internalType": "uint160", - "name": "secondsPerLiquidityOutsideX128", + "name": "secondsPerLiquidityInsideX128", "type": "uint160" }, { "internalType": "uint32", - "name": "secondsOutside", + "name": "secondsInside", "type": "uint32" - }, - { - "internalType": "bool", - "name": "initialized", - "type": "bool" } ], "stateMutability": "view", "type": "function" }, { - "inputs": [], - "name": "token0", + "inputs": [ + { + "internalType": "int16", + "name": "", + "type": "int16" + } + ], + "name": "tickBitmap", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -975,12 +977,12 @@ }, { "inputs": [], - "name": "token1", + "name": "tickSpacing", "outputs": [ { - "internalType": "address", + "internalType": "int24", "name": "", - "type": "address" + "type": "int24" } ], "stateMutability": "view", diff --git a/crates/contracts/artifacts/UniswapV3QuoterV2.json b/contracts/artifacts/UniswapV3QuoterV2.json similarity index 99% rename from crates/contracts/artifacts/UniswapV3QuoterV2.json rename to contracts/artifacts/UniswapV3QuoterV2.json index 7d72b79934..ffb210fdc1 100644 --- a/crates/contracts/artifacts/UniswapV3QuoterV2.json +++ b/contracts/artifacts/UniswapV3QuoterV2.json @@ -241,7 +241,9 @@ ], "stateMutability": "nonpayable", "type": "function" - }, + } + ], + "_disabled": [ { "inputs": [ { diff --git a/crates/contracts/artifacts/UniswapV3SwapRouterV2.json b/contracts/artifacts/UniswapV3SwapRouterV2.json similarity index 100% rename from crates/contracts/artifacts/UniswapV3SwapRouterV2.json rename to contracts/artifacts/UniswapV3SwapRouterV2.json diff --git a/crates/contracts/artifacts/WETH9.json b/contracts/artifacts/WETH9.json similarity index 99% rename from crates/contracts/artifacts/WETH9.json rename to contracts/artifacts/WETH9.json index 6e4607ddbb..9abe58a0af 100644 --- a/crates/contracts/artifacts/WETH9.json +++ b/contracts/artifacts/WETH9.json @@ -1,89 +1,5 @@ { "abi": [ - { - "constant": true, - "inputs": [], - "name": "name", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "decimals", - "outputs": [ - { - "name": "", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "symbol", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "payable": true, "stateMutability": "payable", @@ -168,32 +84,79 @@ "type": "event" }, { - "constant": false, + "constant": true, "inputs": [], - "name": "deposit", - "outputs": [], - "payable": true, - "stateMutability": "payable", + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", "type": "function" }, { - "constant": false, + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, "inputs": [ { - "name": "wad", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", "type": "uint256" } ], - "name": "withdraw", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], - "name": "totalSupply", + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + } + ], + "name": "allowance", "outputs": [ { "name": "", @@ -204,6 +167,29 @@ "stateMutability": "view", "type": "function" }, + { + "constant": false, + "inputs": [], + "name": "deposit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "wad", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { "constant": false, "inputs": [ @@ -284,5 +270,21 @@ }, "userdoc": { "methods": {} - } + }, + "_disabled": [ + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] } diff --git a/crates/contracts/foundry.toml b/contracts/foundry.toml similarity index 100% rename from crates/contracts/foundry.toml rename to contracts/foundry.toml diff --git a/contracts/generated/.gitignore b/contracts/generated/.gitignore new file mode 100644 index 0000000000..05923927ff --- /dev/null +++ b/contracts/generated/.gitignore @@ -0,0 +1,2 @@ +/target +.DS_Store diff --git a/contracts/generated/Cargo.lock b/contracts/generated/Cargo.lock new file mode 100644 index 0000000000..55b402ca78 --- /dev/null +++ b/contracts/generated/Cargo.lock @@ -0,0 +1,4519 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy-chains" +version = "0.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f374d3c6d729268bbe2d0e0ff992bb97898b2df756691a62ee1d5f0506bc39" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c0dc44157867da82c469c13186015b86abef209bf0e41625e4b68bac61d728" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-trie", + "alloy-tx-macros", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "k256", + "once_cell", + "rand 0.8.5", + "secp256k1", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-consensus-any" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4cdb42df3871cd6b346d6a938ec2ba69a9a0f49d1f82714bc5c48349268434" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca63b7125a981415898ffe2a2a696c83696c9c6bdb1671c8a912946bbd8e49e7" +dependencies = [ + "alloy-consensus", + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "futures", + "futures-util", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-dyn-abi" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2db5c583aaef0255aa63a4fe827f826090142528bba48d1bf4119b62780cad" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "crc", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip2930" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9441120fa82df73e8959ae0e4ab8ade03de2aaae61be313fbf5746277847ce25" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip7928" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3231de68d5d6e75332b7489cfcc7f4dfabeba94d990a10e4b923af0e6623540" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f7ef09f21bd1e9cb8a686f168cb4a206646804567f0889eadb8dcc4c9288c8" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-eip7928", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "serde", + "serde_with", + "sha2", + "thiserror", +] + +[[package]] +name = "alloy-json-abi" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dbe713da0c737d9e5e387b0ba790eb98b14dd207fe53eef50e19a5a8ec3dac" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff42cd777eea61f370c0b10f2648a1c81e0b783066cd7269228aa993afd487f7" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "http", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cbca04f9b410fdc51aaaf88433cbac761213905a65fe832058bcf6690585762" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-any", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "derive_more", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-network-primitives" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d6d15e069a8b11f56bef2eccbad2a873c6dd4d4c81d04dda29710f5ea52f04" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3b431b4e72cd8bd0ec7a50b4be18e73dab74de0dba180eef171055e5d5926e" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "foldhash 0.2.0", + "hashbrown 0.16.1", + "indexmap 2.13.0", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand 0.9.2", + "rapidhash", + "ruint", + "rustc-hash", + "serde", + "sha3", +] + +[[package]] +name = "alloy-provider" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d181c8cc7cf4805d7e589bf4074d56d55064fa1a979f005a45a62b047616d870" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-signer", + "alloy-sol-types", + "alloy-transport", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "either", + "futures", + "futures-utils-wasm", + "lru", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "wasmtimer", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e93e50f64a77ad9c5470bf2ad0ca02f228da70c792a8f06634801e202579f35e" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8849c74c9ca0f5a03da1c865e3eb6f768df816e67dd3721a398a8a7e398011" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "alloy-rpc-client" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2792758a93ae32a32e9047c843d536e1448044f78422d71bf7d7c05149e103f" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "futures", + "pin-project", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-types-any" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd720b63f82b457610f2eaaf1f32edf44efffe03ae25d537632e7d23e7929e1a" +dependencies = [ + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2dc411f13092f237d2bf6918caf80977fc2f51485f9b90cb2a2f956912c8c9" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "itertools 0.14.0", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-serde" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ce1e0dbf7720eee747700e300c99aac01b1a95bb93f493a01e78ee28bb1a37" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2425c6f314522c78e8198979c8cbf6769362be4da381d4152ea8eefce383535d" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "either", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab81bab693da9bb79f7a95b64b394718259fdd7e41dceeced4cad57cb71c4f6a" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.13.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "sha3", + "syn 2.0.117", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" +dependencies = [ + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "syn 2.0.117", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64612d29379782a5dde6f4b6570d9c756d734d760c0c94c254d361e678a6591f" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa186e560d523d196580c48bf00f1bf62e63041f28ecf276acc22f8b27bb9f53" +dependencies = [ + "alloy-json-rpc", + "auto_impl", + "base64", + "derive_more", + "futures", + "futures-utils-wasm", + "parking_lot", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-trie" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d7fd448ab0a017de542de1dcca7a58e7019fe0e7a34ed3f9543ebddf6aceffa" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arrayvec", + "derive_more", + "nybbles", + "serde", + "smallvec", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-tx-macros" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa0c53e8c1e1ef4d01066b01c737fb62fc9397ab52c6e7bb5669f97d281b9bc" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitcoin-io" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f582957c24870b7bfd12bf562c40b4734b533cafbaf8ded31d6d85f462c01" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "const-hex" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9a108e542ddf1de36743a6126e94d6659dccda38fc8a77e80b915102ac784a" +dependencies = [ + "cfg-if", + "cpufeatures", + "proptest", + "serde_core", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "contracts" +version = "0.1.0" +dependencies = [ + "cow-contract-anyoneauthenticator", + "cow-contract-balancerqueries", + "cow-contract-balancerv2authorizer", + "cow-contract-balancerv2basepool", + "cow-contract-balancerv2basepoolfactory", + "cow-contract-balancerv2composablestablepool", + "cow-contract-balancerv2composablestablepoolfactory", + "cow-contract-balancerv2composablestablepoolfactoryv3", + "cow-contract-balancerv2composablestablepoolfactoryv4", + "cow-contract-balancerv2composablestablepoolfactoryv5", + "cow-contract-balancerv2composablestablepoolfactoryv6", + "cow-contract-balancerv2liquiditybootstrappingpool", + "cow-contract-balancerv2liquiditybootstrappingpoolfactory", + "cow-contract-balancerv2noprotocolfeeliquiditybootstrappingpoolfactory", + "cow-contract-balancerv2stablepool", + "cow-contract-balancerv2stablepoolfactoryv2", + "cow-contract-balancerv2vault", + "cow-contract-balancerv2weightedpool", + "cow-contract-balancerv2weightedpool2tokensfactory", + "cow-contract-balancerv2weightedpoolfactory", + "cow-contract-balancerv2weightedpoolfactoryv3", + "cow-contract-balancerv2weightedpoolfactoryv4", + "cow-contract-balancerv3batchrouter", + "cow-contract-balances", + "cow-contract-baoswaprouter", + "cow-contract-chainalysisoracle", + "cow-contract-counter", + "cow-contract-cowamm", + "cow-contract-cowammconstantproductfactory", + "cow-contract-cowammfactorygetter", + "cow-contract-cowammlegacyhelper", + "cow-contract-cowammuniswapv2priceoracle", + "cow-contract-cowprotocoltoken", + "cow-contract-cowswapethflow", + "cow-contract-cowswaponchainorders", + "cow-contract-erc1271signaturevalidator", + "cow-contract-erc20", + "cow-contract-erc20mintable", + "cow-contract-flashloanrouter", + "cow-contract-gashog", + "cow-contract-gnosissafe", + "cow-contract-gnosissafecompatibilityfallbackhandler", + "cow-contract-gnosissafeproxy", + "cow-contract-gnosissafeproxyfactory", + "cow-contract-gpv2allowlistauthentication", + "cow-contract-gpv2settlement", + "cow-contract-honeyswaprouter", + "cow-contract-hookstrampoline", + "cow-contract-icowwrapper", + "cow-contract-ierc4626", + "cow-contract-iswaprpair", + "cow-contract-iuniswaplikepair", + "cow-contract-iuniswaplikerouter", + "cow-contract-iuniswapv3factory", + "cow-contract-izeroex", + "cow-contract-liquoricesettlement", + "cow-contract-mockerc4626wrapper", + "cow-contract-nonstandarderc20balances", + "cow-contract-pancakerouter", + "cow-contract-permit2", + "cow-contract-remoteerc20balances", + "cow-contract-signatures", + "cow-contract-solver", + "cow-contract-solver7702delegate", + "cow-contract-spardose", + "cow-contract-sushiswaprouter", + "cow-contract-swapper", + "cow-contract-swaprrouter", + "cow-contract-testnetuniswapv2router02", + "cow-contract-uniswapv2factory", + "cow-contract-uniswapv2router02", + "cow-contract-uniswapv3pool", + "cow-contract-uniswapv3quoterv2", + "cow-contract-uniswapv3swaprouterv2", + "cow-contract-weth9", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cow-contract-anyoneauthenticator" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerqueries" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2authorizer" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2basepool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2basepoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv3" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv4" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv5" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2composablestablepoolfactoryv6" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2liquiditybootstrappingpool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2liquiditybootstrappingpoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2noprotocolfeeliquiditybootstrappingpoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2stablepool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2stablepoolfactoryv2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2vault" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpool2tokensfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpoolfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpoolfactoryv3" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv2weightedpoolfactoryv4" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balancerv3batchrouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-balances" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-baoswaprouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-chainalysisoracle" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-counter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowamm" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammconstantproductfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammfactorygetter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammlegacyhelper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowammuniswapv2priceoracle" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowprotocoltoken" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowswapethflow" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-cowswaponchainorders" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-erc1271signaturevalidator" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-erc20" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-erc20mintable" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-flashloanrouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gashog" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafe" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafecompatibilityfallbackhandler" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafeproxy" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gnosissafeproxyfactory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gpv2allowlistauthentication" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-gpv2settlement" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-honeyswaprouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-hookstrampoline" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-icowwrapper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-ierc4626" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iswaprpair" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iuniswaplikepair" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iuniswaplikerouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-iuniswapv3factory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-izeroex" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-liquoricesettlement" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-mockerc4626wrapper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-nonstandarderc20balances" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-pancakerouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-permit2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-remoteerc20balances" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-signatures" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-solver" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-solver7702delegate" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-spardose" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-sushiswaprouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-swapper" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-swaprrouter" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-testnetuniswapv2router02" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv2factory" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv2router02" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv3pool" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv3quoterv2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-uniswapv3swaprouterv2" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cow-contract-weth9" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "alloy-sol-types", + "anyhow", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "serde", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.117", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "serde", + "serde_core", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b646a74e746cd25045aa0fd42f4f7f78aa6d119380182c7e63a5593c4ab8df6f" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "nybbles" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" +dependencies = [ + "alloy-rlp", + "cfg-if", + "proptest", + "ruint", + "serde", + "smallvec", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", + "serde", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" +dependencies = [ + "rustversion", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "ark-ff 0.5.0", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rand 0.9.2", + "rlp", + "ruint-macro", + "serde_core", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.27", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_with" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b31139435f327c93c6038ed350ae4588e2c70a13d50599509fee6349967ba35a" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom 0.4.1", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver 1.0.27", +] + +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver 1.0.27", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/contracts/generated/Cargo.toml b/contracts/generated/Cargo.toml new file mode 100644 index 0000000000..05040e2ae0 --- /dev/null +++ b/contracts/generated/Cargo.toml @@ -0,0 +1,17 @@ +# Auto-generated by contracts-generate. Do not edit. +[workspace] +resolver = "3" +members = [ + "contracts-facade", + "contracts-generated/*", +] + +[workspace.dependencies] +alloy-contract = { version = "1.7.3" } +alloy-primitives = { version = "1.5.7", default-features = false } +alloy-provider = { version = "1.7.3", default-features = false } +alloy-sol-types = { version = "1.5.7", default-features = false } +anyhow = "1.0.100" + +[workspace.lints.clippy] +all = "warn" diff --git a/contracts/generated/contracts-facade/Cargo.toml b/contracts/generated/contracts-facade/Cargo.toml new file mode 100644 index 0000000000..55c0ed9a08 --- /dev/null +++ b/contracts/generated/contracts-facade/Cargo.toml @@ -0,0 +1,109 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "contracts" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +cow-contract-anyoneauthenticator = { path = "../contracts-generated/anyoneauthenticator" } +cow-contract-balancerqueries = { path = "../contracts-generated/balancerqueries" } +cow-contract-balancerv2authorizer = { path = "../contracts-generated/balancerv2authorizer" } +cow-contract-balancerv2basepool = { path = "../contracts-generated/balancerv2basepool" } +cow-contract-balancerv2basepoolfactory = { path = "../contracts-generated/balancerv2basepoolfactory" } +cow-contract-balancerv2composablestablepool = { path = "../contracts-generated/balancerv2composablestablepool" } +cow-contract-balancerv2composablestablepoolfactory = { + path = "../contracts-generated/balancerv2composablestablepoolfactory" +} +cow-contract-balancerv2composablestablepoolfactoryv3 = { + path = "../contracts-generated/balancerv2composablestablepoolfactoryv3" +} +cow-contract-balancerv2composablestablepoolfactoryv4 = { + path = "../contracts-generated/balancerv2composablestablepoolfactoryv4" +} +cow-contract-balancerv2composablestablepoolfactoryv5 = { + path = "../contracts-generated/balancerv2composablestablepoolfactoryv5" +} +cow-contract-balancerv2composablestablepoolfactoryv6 = { + path = "../contracts-generated/balancerv2composablestablepoolfactoryv6" +} +cow-contract-balancerv2liquiditybootstrappingpool = { + path = "../contracts-generated/balancerv2liquiditybootstrappingpool" +} +cow-contract-balancerv2liquiditybootstrappingpoolfactory = { + path = "../contracts-generated/balancerv2liquiditybootstrappingpoolfactory" +} +cow-contract-balancerv2noprotocolfeeliquiditybootstrappingpoolfactory = { + path = "../contracts-generated/balancerv2noprotocolfeeliquiditybootstrappingpoolfactory" +} +cow-contract-balancerv2stablepool = { path = "../contracts-generated/balancerv2stablepool" } +cow-contract-balancerv2stablepoolfactoryv2 = { path = "../contracts-generated/balancerv2stablepoolfactoryv2" } +cow-contract-balancerv2vault = { path = "../contracts-generated/balancerv2vault" } +cow-contract-balancerv2weightedpool = { path = "../contracts-generated/balancerv2weightedpool" } +cow-contract-balancerv2weightedpool2tokensfactory = { + path = "../contracts-generated/balancerv2weightedpool2tokensfactory" +} +cow-contract-balancerv2weightedpoolfactory = { path = "../contracts-generated/balancerv2weightedpoolfactory" } +cow-contract-balancerv2weightedpoolfactoryv3 = { path = "../contracts-generated/balancerv2weightedpoolfactoryv3" } +cow-contract-balancerv2weightedpoolfactoryv4 = { path = "../contracts-generated/balancerv2weightedpoolfactoryv4" } +cow-contract-balancerv3batchrouter = { path = "../contracts-generated/balancerv3batchrouter" } +cow-contract-balances = { path = "../contracts-generated/balances" } +cow-contract-baoswaprouter = { path = "../contracts-generated/baoswaprouter" } +cow-contract-chainalysisoracle = { path = "../contracts-generated/chainalysisoracle" } +cow-contract-counter = { path = "../contracts-generated/counter" } +cow-contract-cowamm = { path = "../contracts-generated/cowamm" } +cow-contract-cowammconstantproductfactory = { path = "../contracts-generated/cowammconstantproductfactory" } +cow-contract-cowammfactorygetter = { path = "../contracts-generated/cowammfactorygetter" } +cow-contract-cowammlegacyhelper = { path = "../contracts-generated/cowammlegacyhelper" } +cow-contract-cowammuniswapv2priceoracle = { path = "../contracts-generated/cowammuniswapv2priceoracle" } +cow-contract-cowprotocoltoken = { path = "../contracts-generated/cowprotocoltoken" } +cow-contract-cowswapethflow = { path = "../contracts-generated/cowswapethflow" } +cow-contract-cowswaponchainorders = { path = "../contracts-generated/cowswaponchainorders" } +cow-contract-erc20 = { path = "../contracts-generated/erc20" } +cow-contract-erc20mintable = { path = "../contracts-generated/erc20mintable" } +cow-contract-erc1271signaturevalidator = { path = "../contracts-generated/erc1271signaturevalidator" } +cow-contract-flashloanrouter = { path = "../contracts-generated/flashloanrouter" } +cow-contract-gashog = { path = "../contracts-generated/gashog" } +cow-contract-gnosissafe = { path = "../contracts-generated/gnosissafe" } +cow-contract-gnosissafecompatibilityfallbackhandler = { + path = "../contracts-generated/gnosissafecompatibilityfallbackhandler" +} +cow-contract-gnosissafeproxy = { path = "../contracts-generated/gnosissafeproxy" } +cow-contract-gnosissafeproxyfactory = { path = "../contracts-generated/gnosissafeproxyfactory" } +cow-contract-gpv2allowlistauthentication = { path = "../contracts-generated/gpv2allowlistauthentication" } +cow-contract-gpv2settlement = { path = "../contracts-generated/gpv2settlement" } +cow-contract-honeyswaprouter = { path = "../contracts-generated/honeyswaprouter" } +cow-contract-hookstrampoline = { path = "../contracts-generated/hookstrampoline" } +cow-contract-icowwrapper = { path = "../contracts-generated/icowwrapper" } +cow-contract-ierc4626 = { path = "../contracts-generated/ierc4626" } +cow-contract-iswaprpair = { path = "../contracts-generated/iswaprpair" } +cow-contract-iuniswaplikepair = { path = "../contracts-generated/iuniswaplikepair" } +cow-contract-iuniswaplikerouter = { path = "../contracts-generated/iuniswaplikerouter" } +cow-contract-iuniswapv3factory = { path = "../contracts-generated/iuniswapv3factory" } +cow-contract-izeroex = { path = "../contracts-generated/izeroex" } +cow-contract-liquoricesettlement = { path = "../contracts-generated/liquoricesettlement" } +cow-contract-mockerc4626wrapper = { path = "../contracts-generated/mockerc4626wrapper" } +cow-contract-nonstandarderc20balances = { path = "../contracts-generated/nonstandarderc20balances" } +cow-contract-pancakerouter = { path = "../contracts-generated/pancakerouter" } +cow-contract-permit2 = { path = "../contracts-generated/permit2" } +cow-contract-remoteerc20balances = { path = "../contracts-generated/remoteerc20balances" } +cow-contract-signatures = { path = "../contracts-generated/signatures" } +cow-contract-solver = { path = "../contracts-generated/solver" } +cow-contract-solver7702delegate = { path = "../contracts-generated/solver7702delegate" } +cow-contract-spardose = { path = "../contracts-generated/spardose" } +cow-contract-sushiswaprouter = { path = "../contracts-generated/sushiswaprouter" } +cow-contract-swapper = { path = "../contracts-generated/swapper" } +cow-contract-swaprrouter = { path = "../contracts-generated/swaprrouter" } +cow-contract-testnetuniswapv2router02 = { path = "../contracts-generated/testnetuniswapv2router02" } +cow-contract-uniswapv2factory = { path = "../contracts-generated/uniswapv2factory" } +cow-contract-uniswapv2router02 = { path = "../contracts-generated/uniswapv2router02" } +cow-contract-uniswapv3pool = { path = "../contracts-generated/uniswapv3pool" } +cow-contract-uniswapv3quoterv2 = { path = "../contracts-generated/uniswapv3quoterv2" } +cow-contract-uniswapv3swaprouterv2 = { path = "../contracts-generated/uniswapv3swaprouterv2" } +cow-contract-weth9 = { path = "../contracts-generated/weth9" } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-facade/src/lib.rs b/contracts/generated/contracts-facade/src/lib.rs new file mode 100644 index 0000000000..1117260f9e --- /dev/null +++ b/contracts/generated/contracts-facade/src/lib.rs @@ -0,0 +1,98 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! This crate re-exports per-contract crate bindings. +//! Auto-generated by contracts-generate. Do not edit. +pub use { + cow_contract_balancerqueries as BalancerQueries, + cow_contract_balancerv2authorizer as BalancerV2Authorizer, + cow_contract_balancerv2basepool as BalancerV2BasePool, + cow_contract_balancerv2basepoolfactory as BalancerV2BasePoolFactory, + cow_contract_balancerv2composablestablepool as BalancerV2ComposableStablePool, + cow_contract_balancerv2composablestablepoolfactory as BalancerV2ComposableStablePoolFactory, + cow_contract_balancerv2composablestablepoolfactoryv3 as BalancerV2ComposableStablePoolFactoryV3, + cow_contract_balancerv2composablestablepoolfactoryv4 as BalancerV2ComposableStablePoolFactoryV4, + cow_contract_balancerv2composablestablepoolfactoryv5 as BalancerV2ComposableStablePoolFactoryV5, + cow_contract_balancerv2composablestablepoolfactoryv6 as BalancerV2ComposableStablePoolFactoryV6, + cow_contract_balancerv2liquiditybootstrappingpool as BalancerV2LiquidityBootstrappingPool, + cow_contract_balancerv2liquiditybootstrappingpoolfactory as BalancerV2LiquidityBootstrappingPoolFactory, + cow_contract_balancerv2noprotocolfeeliquiditybootstrappingpoolfactory as BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory, + cow_contract_balancerv2stablepool as BalancerV2StablePool, + cow_contract_balancerv2stablepoolfactoryv2 as BalancerV2StablePoolFactoryV2, + cow_contract_balancerv2vault as BalancerV2Vault, + cow_contract_balancerv2weightedpool as BalancerV2WeightedPool, + cow_contract_balancerv2weightedpool2tokensfactory as BalancerV2WeightedPool2TokensFactory, + cow_contract_balancerv2weightedpoolfactory as BalancerV2WeightedPoolFactory, + cow_contract_balancerv2weightedpoolfactoryv3 as BalancerV2WeightedPoolFactoryV3, + cow_contract_balancerv2weightedpoolfactoryv4 as BalancerV2WeightedPoolFactoryV4, + cow_contract_balancerv3batchrouter as BalancerV3BatchRouter, + cow_contract_baoswaprouter as BaoswapRouter, + cow_contract_chainalysisoracle as ChainalysisOracle, + cow_contract_cowswapethflow as CoWSwapEthFlow, + cow_contract_cowswaponchainorders as CoWSwapOnchainOrders, + cow_contract_erc20 as ERC20, + cow_contract_erc20mintable as ERC20Mintable, + cow_contract_erc1271signaturevalidator as ERC1271SignatureValidator, + cow_contract_flashloanrouter as FlashLoanRouter, + cow_contract_gnosissafe as GnosisSafe, + cow_contract_gnosissafecompatibilityfallbackhandler as GnosisSafeCompatibilityFallbackHandler, + cow_contract_gnosissafeproxy as GnosisSafeProxy, + cow_contract_gnosissafeproxyfactory as GnosisSafeProxyFactory, + cow_contract_gpv2allowlistauthentication as GPv2AllowListAuthentication, + cow_contract_gpv2settlement as GPv2Settlement, + cow_contract_honeyswaprouter as HoneyswapRouter, + cow_contract_hookstrampoline as HooksTrampoline, + cow_contract_icowwrapper as ICowWrapper, + cow_contract_ierc4626 as IERC4626, + cow_contract_iswaprpair as ISwaprPair, + cow_contract_iuniswaplikepair as IUniswapLikePair, + cow_contract_iuniswaplikerouter as IUniswapLikeRouter, + cow_contract_iuniswapv3factory as IUniswapV3Factory, + cow_contract_izeroex as IZeroex, + cow_contract_liquoricesettlement as LiquoriceSettlement, + cow_contract_pancakerouter as PancakeRouter, + cow_contract_permit2 as Permit2, + cow_contract_solver7702delegate as Solver7702Delegate, + cow_contract_sushiswaprouter as SushiSwapRouter, + cow_contract_swaprrouter as SwaprRouter, + cow_contract_testnetuniswapv2router02 as TestnetUniswapV2Router02, + cow_contract_uniswapv2factory as UniswapV2Factory, + cow_contract_uniswapv2router02 as UniswapV2Router02, + cow_contract_uniswapv3pool as UniswapV3Pool, + cow_contract_uniswapv3quoterv2 as UniswapV3QuoterV2, + cow_contract_uniswapv3swaprouterv2 as UniswapV3SwapRouterV2, + cow_contract_weth9 as WETH9, +}; +pub mod support { + pub use { + cow_contract_anyoneauthenticator as AnyoneAuthenticator, + cow_contract_balances as Balances, + cow_contract_signatures as Signatures, + cow_contract_solver as Solver, + cow_contract_spardose as Spardose, + cow_contract_swapper as Swapper, + }; +} +pub mod test { + pub use { + cow_contract_counter as Counter, + cow_contract_cowprotocoltoken as CowProtocolToken, + cow_contract_gashog as GasHog, + cow_contract_mockerc4626wrapper as MockERC4626Wrapper, + cow_contract_nonstandarderc20balances as NonStandardERC20Balances, + cow_contract_remoteerc20balances as RemoteERC20Balances, + }; +} +pub mod cow_amm { + pub use { + cow_contract_cowamm as CowAmm, + cow_contract_cowammconstantproductfactory as CowAmmConstantProductFactory, + cow_contract_cowammfactorygetter as CowAmmFactoryGetter, + cow_contract_cowammlegacyhelper as CowAmmLegacyHelper, + cow_contract_cowammuniswapv2priceoracle as CowAmmUniswapV2PriceOracle, + }; +} diff --git a/contracts/generated/contracts-generated/anyoneauthenticator/Cargo.toml b/contracts/generated/contracts-generated/anyoneauthenticator/Cargo.toml new file mode 100644 index 0000000000..e537b8086d --- /dev/null +++ b/contracts/generated/contracts-generated/anyoneauthenticator/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-anyoneauthenticator" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/anyoneauthenticator/src/lib.rs b/contracts/generated/contracts-generated/anyoneauthenticator/src/lib.rs new file mode 100644 index 0000000000..c4f71c03f3 --- /dev/null +++ b/contracts/generated/contracts-generated/anyoneauthenticator/src/lib.rs @@ -0,0 +1,527 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface AnyoneAuthenticator { + function isSolver(address) external pure returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "isSolver", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "pure" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod AnyoneAuthenticator { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b50609480601a5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c806302cc250d14602a575b5f5ffd5b603b6035366004604f565b50600190565b604051901515815260200160405180910390f35b5f60208284031215605e575f5ffd5b813573ffffffffffffffffffffffffffffffffffffffff811681146080575f5ffd5b939250505056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[P`\x94\x80`\x1A_9_\xF3\xFE`\x80`@R4\x80\x15`\x0EW__\xFD[P`\x046\x10`&W_5`\xE0\x1C\x80c\x02\xCC%\r\x14`*W[__\xFD[`;`56`\x04`OV[P`\x01\x90V[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[_` \x82\x84\x03\x12\x15`^W__\xFD[\x815s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14`\x80W__\xFD[\x93\x92PPPV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c806302cc250d14602a575b5f5ffd5b603b6035366004604f565b50600190565b604051901515815260200160405180910390f35b5f60208284031215605e575f5ffd5b813573ffffffffffffffffffffffffffffffffffffffff811681146080575f5ffd5b939250505056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[P`\x046\x10`&W_5`\xE0\x1C\x80c\x02\xCC%\r\x14`*W[__\xFD[`;`56`\x04`OV[P`\x01\x90V[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[_` \x82\x84\x03\x12\x15`^W__\xFD[\x815s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14`\x80W__\xFD[\x93\x92PPPV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isSolver(address)` and selector `0x02cc250d`. + ```solidity + function isSolver(address) external pure returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isSolverCall(pub alloy_sol_types::private::Address); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isSolver(address)`](isSolverCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isSolverReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isSolverCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isSolverCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isSolverReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isSolverReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isSolverCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [2u8, 204u8, 37u8, 13u8]; + const SIGNATURE: &'static str = "isSolver(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isSolverReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isSolverReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`AnyoneAuthenticator`](self) function calls. + #[derive(Clone)] + pub enum AnyoneAuthenticatorCalls { + #[allow(missing_docs)] + isSolver(isSolverCall), + } + impl AnyoneAuthenticatorCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[2u8, 204u8, 37u8, 13u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(isSolver)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for AnyoneAuthenticatorCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 32usize; + const NAME: &'static str = "AnyoneAuthenticatorCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::isSolver(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[{ + fn isSolver(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(AnyoneAuthenticatorCalls::isSolver) + } + isSolver + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + AnyoneAuthenticatorCalls, + >] = &[{ + fn isSolver(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(AnyoneAuthenticatorCalls::isSolver) + } + isSolver + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::isSolver(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::isSolver(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`AnyoneAuthenticator`](self) contract instance. + + See the [wrapper's documentation](`AnyoneAuthenticatorInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> AnyoneAuthenticatorInstance { + AnyoneAuthenticatorInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> + { + AnyoneAuthenticatorInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + AnyoneAuthenticatorInstance::::deploy_builder(__provider) + } + /**A [`AnyoneAuthenticator`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`AnyoneAuthenticator`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct AnyoneAuthenticatorInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for AnyoneAuthenticatorInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("AnyoneAuthenticatorInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + AnyoneAuthenticatorInstance + { + /**Creates a new wrapper around an on-chain [`AnyoneAuthenticator`](self) contract instance. + + See the [wrapper's documentation](`AnyoneAuthenticatorInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl AnyoneAuthenticatorInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> AnyoneAuthenticatorInstance { + AnyoneAuthenticatorInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + AnyoneAuthenticatorInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`isSolver`] function. + pub fn isSolver( + &self, + _0: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, isSolverCall, N> { + self.call_builder(&isSolverCall(_0)) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + AnyoneAuthenticatorInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = AnyoneAuthenticator::AnyoneAuthenticatorInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/balancerqueries/Cargo.toml b/contracts/generated/contracts-generated/balancerqueries/Cargo.toml new file mode 100644 index 0000000000..c253060b73 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerqueries/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerqueries" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerqueries/src/lib.rs b/contracts/generated/contracts-generated/balancerqueries/src/lib.rs new file mode 100644 index 0000000000..0830247e8e --- /dev/null +++ b/contracts/generated/contracts-generated/balancerqueries/src/lib.rs @@ -0,0 +1,1749 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library IVault { + type SwapKind is uint8; + struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } + struct FundManagement { address sender; bool fromInternalBalance; address recipient; bool toInternalBalance; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IVault { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SwapKind(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl SwapKind { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for SwapKind { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: SwapKind) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for SwapKind { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for SwapKind { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct BatchSwapStep { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub assetInIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub assetOutIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: BatchSwapStep) -> Self { + ( + value.poolId, + value.assetInIndex, + value.assetOutIndex, + value.amount, + value.userData, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for BatchSwapStep { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + poolId: tuple.0, + assetInIndex: tuple.1, + assetOutIndex: tuple.2, + amount: tuple.3, + userData: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for BatchSwapStep { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for BatchSwapStep { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.poolId), + as alloy_sol_types::SolType>::tokenize(&self.assetInIndex), + as alloy_sol_types::SolType>::tokenize(&self.assetOutIndex), + as alloy_sol_types::SolType>::tokenize(&self.amount), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for BatchSwapStep { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for BatchSwapStep { + const NAME: &'static str = "BatchSwapStep"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "BatchSwapStep(bytes32 poolId,uint256 assetInIndex,uint256 \ + assetOutIndex,uint256 amount,bytes userData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word(&self.poolId) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.assetInIndex) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.assetOutIndex) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ::eip712_data_word( + &self.userData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for BatchSwapStep { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.poolId, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.assetInIndex, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.assetOutIndex, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + ::topic_preimage_length( + &rust.userData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.poolId, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.assetInIndex, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.assetOutIndex, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + ::encode_topic_preimage( + &rust.userData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct FundManagement { address sender; bool fromInternalBalance; address recipient; bool toInternalBalance; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct FundManagement { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub fromInternalBalance: bool, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub toInternalBalance: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + bool, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: FundManagement) -> Self { + ( + value.sender, + value.fromInternalBalance, + value.recipient, + value.toInternalBalance, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for FundManagement { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + fromInternalBalance: tuple.1, + recipient: tuple.2, + toInternalBalance: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for FundManagement { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for FundManagement { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.fromInternalBalance, + ), + ::tokenize( + &self.recipient, + ), + ::tokenize( + &self.toInternalBalance, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for FundManagement { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for FundManagement { + const NAME: &'static str = "FundManagement"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "FundManagement(address sender,bool fromInternalBalance,address \ + recipient,bool toInternalBalance)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.sender, + ) + .0, + ::eip712_data_word( + &self.fromInternalBalance, + ) + .0, + ::eip712_data_word( + &self.recipient, + ) + .0, + ::eip712_data_word( + &self.toInternalBalance, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for FundManagement { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.sender, + ) + + ::topic_preimage_length( + &rust.fromInternalBalance, + ) + + ::topic_preimage_length( + &rust.recipient, + ) + + ::topic_preimage_length( + &rust.toInternalBalance, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.sender, + out, + ); + ::encode_topic_preimage( + &rust.fromInternalBalance, + out, + ); + ::encode_topic_preimage( + &rust.recipient, + out, + ); + ::encode_topic_preimage( + &rust.toInternalBalance, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IVault`](self) contract instance. + + See the [wrapper's documentation](`IVaultInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IVaultInstance { + IVaultInstance::::new(address, __provider) + } + /**A [`IVault`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IVault`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IVaultInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IVaultInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IVaultInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /**Creates a new wrapper around an on-chain [`IVault`](self) contract instance. + + See the [wrapper's documentation](`IVaultInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IVaultInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IVaultInstance { + IVaultInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library IVault { + type SwapKind is uint8; + struct BatchSwapStep { + bytes32 poolId; + uint256 assetInIndex; + uint256 assetOutIndex; + uint256 amount; + bytes userData; + } + struct FundManagement { + address sender; + bool fromInternalBalance; + address payable recipient; + bool toInternalBalance; + } +} + +interface BalancerQueries { + constructor(address _vault); + + function queryBatchSwap(IVault.SwapKind kind, IVault.BatchSwapStep[] memory swaps, address[] memory assets, IVault.FundManagement memory funds) external returns (int256[] memory assetDeltas); + function vault() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_vault", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "queryBatchSwap", + "inputs": [ + { + "name": "kind", + "type": "uint8", + "internalType": "enum IVault.SwapKind" + }, + { + "name": "swaps", + "type": "tuple[]", + "internalType": "struct IVault.BatchSwapStep[]", + "components": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "assetInIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assetOutIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "assets", + "type": "address[]", + "internalType": "contract IAsset[]" + }, + { + "name": "funds", + "type": "tuple", + "internalType": "struct IVault.FundManagement", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "fromInternalBalance", + "type": "bool", + "internalType": "bool" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address payable" + }, + { + "name": "toInternalBalance", + "type": "bool", + "internalType": "bool" + } + ] + } + ], + "outputs": [ + { + "name": "assetDeltas", + "type": "int256[]", + "internalType": "int256[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "vault", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "view" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerQueries { + use {super::*, alloy_sol_types}; + /**Constructor`. + ```solidity + constructor(address _vault); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _vault: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._vault,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _vault: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._vault, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `queryBatchSwap(uint8,(bytes32,uint256,uint256,uint256,bytes)[],address[],(address,bool,address,bool))` and selector `0xf84d066e`. + ```solidity + function queryBatchSwap(IVault.SwapKind kind, IVault.BatchSwapStep[] memory swaps, address[] memory assets, IVault.FundManagement memory funds) external returns (int256[] memory assetDeltas); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct queryBatchSwapCall { + #[allow(missing_docs)] + pub kind: ::RustType, + #[allow(missing_docs)] + pub swaps: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub assets: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub funds: ::RustType, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`queryBatchSwap(uint8,(bytes32,uint256,uint256,uint256,bytes)[], + /// address[],(address,bool,address,bool))`](queryBatchSwapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct queryBatchSwapReturn { + #[allow(missing_docs)] + pub assetDeltas: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + IVault::SwapKind, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + IVault::FundManagement, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Vec, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: queryBatchSwapCall) -> Self { + (value.kind, value.swaps, value.assets, value.funds) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for queryBatchSwapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + kind: tuple.0, + swaps: tuple.1, + assets: tuple.2, + funds: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: queryBatchSwapReturn) -> Self { + (value.assetDeltas,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for queryBatchSwapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + assetDeltas: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for queryBatchSwapCall { + type Parameters<'a> = ( + IVault::SwapKind, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + IVault::FundManagement, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 77u8, 6u8, 110u8]; + const SIGNATURE: &'static str = "queryBatchSwap(uint8,(bytes32,uint256,uint256,\ + uint256,bytes)[],address[],(address,bool,address,\ + bool))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize(&self.kind), + as alloy_sol_types::SolType>::tokenize(&self.swaps), + as alloy_sol_types::SolType>::tokenize(&self.assets), + ::tokenize( + &self.funds, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: queryBatchSwapReturn = r.into(); + r.assetDeltas + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: queryBatchSwapReturn = r.into(); + r.assetDeltas + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `vault()` and selector `0xfbfa77cf`. + ```solidity + function vault() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct vaultCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`vault()`](vaultCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct vaultReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: vaultCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for vaultCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: vaultReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for vaultReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for vaultCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [251u8, 250u8, 119u8, 207u8]; + const SIGNATURE: &'static str = "vault()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: vaultReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: vaultReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerQueries`](self) function calls. + #[derive(Clone)] + pub enum BalancerQueriesCalls { + #[allow(missing_docs)] + queryBatchSwap(queryBatchSwapCall), + #[allow(missing_docs)] + vault(vaultCall), + } + impl BalancerQueriesCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[248u8, 77u8, 6u8, 110u8], [251u8, 250u8, 119u8, 207u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(queryBatchSwap), + ::core::stringify!(vault), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerQueriesCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerQueriesCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::queryBatchSwap(_) => { + ::SELECTOR + } + Self::vault(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn queryBatchSwap( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerQueriesCalls::queryBatchSwap) + } + queryBatchSwap + }, + { + fn vault(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerQueriesCalls::vault) + } + vault + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn queryBatchSwap( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerQueriesCalls::queryBatchSwap) + } + queryBatchSwap + }, + { + fn vault(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerQueriesCalls::vault) + } + vault + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::queryBatchSwap(inner) => { + ::abi_encoded_size(inner) + } + Self::vault(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::queryBatchSwap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::vault(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerQueries`](self) contract instance. + + See the [wrapper's documentation](`BalancerQueriesInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerQueriesInstance { + BalancerQueriesInstance::::new(address, __provider) + } + /**A [`BalancerQueries`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerQueries`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerQueriesInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerQueriesInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerQueriesInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerQueriesInstance + { + /**Creates a new wrapper around an on-chain [`BalancerQueries`](self) contract instance. + + See the [wrapper's documentation](`BalancerQueriesInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerQueriesInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerQueriesInstance { + BalancerQueriesInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerQueriesInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`queryBatchSwap`] function. + pub fn queryBatchSwap( + &self, + kind: ::RustType, + swaps: alloy_sol_types::private::Vec< + ::RustType, + >, + assets: alloy_sol_types::private::Vec, + funds: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, queryBatchSwapCall, N> { + self.call_builder(&queryBatchSwapCall { + kind, + swaps, + assets, + funds, + }) + } + + ///Creates a new call builder for the [`vault`] function. + pub fn vault(&self) -> alloy_contract::SolCallBuilder<&P, vaultCall, N> { + self.call_builder(&vaultCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerQueriesInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = BalancerQueries::BalancerQueriesInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), + Some(15188261u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), + Some(15288107u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), + Some(24821845u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), + Some(30988035u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x300Ab2038EAc391f26D9F895dc61F8F66a548833"), + Some(1205869u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), + Some(18238624u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), + Some(26387068u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2authorizer/Cargo.toml b/contracts/generated/contracts-generated/balancerv2authorizer/Cargo.toml new file mode 100644 index 0000000000..39bf9bc97b --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2authorizer/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2authorizer" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2authorizer/src/lib.rs b/contracts/generated/contracts-generated/balancerv2authorizer/src/lib.rs new file mode 100644 index 0000000000..e8c3ca7910 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2authorizer/src/lib.rs @@ -0,0 +1,1455 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2Authorizer { + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + constructor(address admin); + + function grantRole(bytes32 role, address account) external; + function grantRoles(bytes32[] memory roles, address account) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "admin", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "grantRoles", + "inputs": [ + { + "name": "roles", + "type": "bytes32[]", + "internalType": "bytes32[]" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2Authorizer { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561001057600080fd5b50604051610e1d380380610e1d8339818101604052602081101561003357600080fd5b5051610040600082610046565b5061013d565b6100508282610054565b5050565b6000828152602081815260409091206100769183906108946100b7821b17901c565b156100505760405133906001600160a01b0383169084907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d90600090a45050565b60006100c3838361011c565b61011257508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155610116565b5060005b92915050565b6001600160a01b031660009081526001919091016020526040902054151590565b610cd18061014c6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c8063988360a31161008c578063a73cb2ab11610066578063a73cb2ab1461044b578063ca15c87314610572578063d547741f1461058f578063fcd7627e146105c8576100df565b8063988360a3146103475780639be2a88414610402578063a217fddf14610443576100df565b806336568abe116100bd57806336568abe146102755780639010d07c146102ae57806391d14854146102fa576100df565b806318b2cde9146100e4578063248a9ca31461020d5780632f2ff15d1461023c575b600080fd5b61020b600480360360408110156100fa57600080fd5b81019060208101813564010000000081111561011557600080fd5b82018360208201111561012757600080fd5b8035906020019184602083028401116401000000008311171561014957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561019957600080fd5b8201836020820111156101ab57600080fd5b803590602001918460208302840111640100000000831117156101cd57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610683945050505050565b005b61022a6004803603602081101561022357600080fd5b50356106d8565b60408051918252519081900360200190f35b61020b6004803603604081101561025257600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff166106ed565b61020b6004803603604081101561028b57600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16610723565b6102d1600480360360408110156102c457600080fd5b5080359060200135610751565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6103336004803603604081101561031057600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16610772565b604080519115158252519081900360200190f35b61020b6004803603604081101561035d57600080fd5b81019060208101813564010000000081111561037857600080fd5b82018360208201111561038a57600080fd5b803590602001918460208302840111640100000000831117156103ac57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050903573ffffffffffffffffffffffffffffffffffffffff16915061078a9050565b6103336004803603606081101561041857600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff602082013581169160400135166107bb565b61022a6107cf565b61020b6004803603604081101561046157600080fd5b81019060208101813564010000000081111561047c57600080fd5b82018360208201111561048e57600080fd5b803590602001918460208302840111640100000000831117156104b057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561050057600080fd5b82018360208201111561051257600080fd5b8035906020019184602083028401116401000000008311171561053457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107d4945050505050565b61022a6004803603602081101561058857600080fd5b5035610824565b61020b600480360360408110156105a557600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff1661083b565b61020b600480360360408110156105de57600080fd5b8101906020810181356401000000008111156105f957600080fd5b82018360208201111561060b57600080fd5b8035906020019184602083028401116401000000008311171561062d57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505050903573ffffffffffffffffffffffffffffffffffffffff1691506108639050565b61068f8251825161091c565b60005b82518110156106d3576106cb8382815181106106aa57fe5b60200260200101518383815181106106be57fe5b602002602001015161083b565b600101610692565b505050565b60009081526020819052604090206002015490565b6000828152602081905260409020600201546107159061070d9033610772565b6101a6610925565b61071f8282610933565b5050565b61074773ffffffffffffffffffffffffffffffffffffffff821633146101a8610925565b61071f8282610999565b600082815260208190526040812061076990836109ff565b90505b92915050565b60008281526020819052604081206107699083610a1b565b60005b82518110156106d3576107b38382815181106107a557fe5b60200260200101518361083b565b60010161078d565b60006107c78484610772565b949350505050565b600081565b6107e08251825161091c565b60005b82518110156106d35761081c8382815181106107fb57fe5b602002602001015183838151811061080f57fe5b60200260200101516106ed565b6001016107e3565b600081815260208190526040812061076c90610a49565b6000828152602081905260409020600201546107479061085b9033610772565b6101a7610925565b60005b82518110156106d35761088c83828151811061087e57fe5b6020026020010151836106ed565b600101610866565b60006108a08383610a1b565b61091457508154600180820184556000848152602080822090930180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558554908252828601909352604090209190915561076c565b50600061076c565b61071f81831460675b8161071f5761071f81610a4d565b600082815260208190526040902061094b9082610894565b1561071f57604051339073ffffffffffffffffffffffffffffffffffffffff83169084907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d90600090a45050565b60008281526020819052604090206109b19082610aba565b1561071f57604051339073ffffffffffffffffffffffffffffffffffffffff83169084907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b90600090a45050565b8154600090610a119083106064610925565b6107698383610c61565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001919091016020526040902054151590565b5490565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120548015610c575783547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8083019190810190600090879083908110610b2257fe5b600091825260209091200154875473ffffffffffffffffffffffffffffffffffffffff90911691508190889085908110610b5857fe5b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918316815260018981019092526040902090840190558654879080610bc657fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff8816825260018981019091526040822091909155945061076c9350505050565b600091505061076c565b6000826000018281548110610c7257fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16939250505056fea2646970667358221220dfe715d2cd44c733089f2c396b8ba6a91ca4ec5b907632f366d4d8a9814a53d364736f6c63430007010033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x0E\x1D8\x03\x80a\x0E\x1D\x839\x81\x81\x01`@R` \x81\x10\x15a\x003W`\0\x80\xFD[PQa\0@`\0\x82a\0FV[Pa\x01=V[a\0P\x82\x82a\0TV[PPV[`\0\x82\x81R` \x81\x81R`@\x90\x91 a\0v\x91\x83\x90a\x08\x94a\0\xB7\x82\x1B\x17\x90\x1CV[\x15a\0PW`@Q3\x90`\x01`\x01`\xA0\x1B\x03\x83\x16\x90\x84\x90\x7F/\x87\x88\x11~~\xFF\x1D\x82\xE9&\xECyI\x01\xD1|x\x02JP'\t@0E@\xA73eo\r\x90`\0\x90\xA4PPV[`\0a\0\xC3\x83\x83a\x01\x1CV[a\x01\x12WP\x81T`\x01\x80\x82\x01\x84U`\0\x84\x81R` \x80\x82 \x90\x93\x01\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16`\x01`\x01`\xA0\x1B\x03\x86\x16\x90\x81\x17\x90\x91U\x85T\x90\x82R\x82\x86\x01\x90\x93R`@\x90 \x91\x90\x91Ua\x01\x16V[P`\0[\x92\x91PPV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R`\x01\x91\x90\x91\x01` R`@\x90 T\x15\x15\x90V[a\x0C\xD1\x80a\x01L`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\xDFW`\x005`\xE0\x1C\x80c\x98\x83`\xA3\x11a\0\x8CW\x80c\xA7<\xB2\xAB\x11a\0fW\x80c\xA7<\xB2\xAB\x14a\x04KW\x80c\xCA\x15\xC8s\x14a\x05rW\x80c\xD5Gt\x1F\x14a\x05\x8FW\x80c\xFC\xD7b~\x14a\x05\xC8Wa\0\xDFV[\x80c\x98\x83`\xA3\x14a\x03GW\x80c\x9B\xE2\xA8\x84\x14a\x04\x02W\x80c\xA2\x17\xFD\xDF\x14a\x04CWa\0\xDFV[\x80c6V\x8A\xBE\x11a\0\xBDW\x80c6V\x8A\xBE\x14a\x02uW\x80c\x90\x10\xD0|\x14a\x02\xAEW\x80c\x91\xD1HT\x14a\x02\xFAWa\0\xDFV[\x80c\x18\xB2\xCD\xE9\x14a\0\xE4W\x80c$\x8A\x9C\xA3\x14a\x02\rW\x80c//\xF1]\x14a\x02, + #[allow(missing_docs)] + pub previousAdminRole: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub newAdminRole: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RoleAdminChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "RoleAdminChanged(bytes32,bytes32,bytes32)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 189u8, 121u8, 184u8, 111u8, 254u8, 10u8, 184u8, 232u8, 119u8, 97u8, 81u8, 81u8, + 66u8, 23u8, 205u8, 124u8, 172u8, 213u8, 44u8, 144u8, 159u8, 102u8, 71u8, 92u8, + 58u8, 244u8, 78u8, 18u8, 159u8, 11u8, 0u8, 255u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + role: topics.1, + previousAdminRole: topics.2, + newAdminRole: topics.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.role.clone(), + self.previousAdminRole.clone(), + self.newAdminRole.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.role); + out[2usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.previousAdminRole); + out[3usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.newAdminRole); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RoleAdminChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RoleAdminChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RoleAdminChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `RoleGranted(bytes32,address,address)` and selector `0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d`. + ```solidity + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct RoleGranted { + #[allow(missing_docs)] + pub role: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RoleGranted { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "RoleGranted(bytes32,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 47u8, 135u8, 136u8, 17u8, 126u8, 126u8, 255u8, 29u8, 130u8, 233u8, 38u8, 236u8, + 121u8, 73u8, 1u8, 209u8, 124u8, 120u8, 2u8, 74u8, 80u8, 39u8, 9u8, 64u8, 48u8, + 69u8, 64u8, 167u8, 51u8, 101u8, 111u8, 13u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + role: topics.1, + account: topics.2, + sender: topics.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.role.clone(), + self.account.clone(), + self.sender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.role); + out[2usize] = ::encode_topic( + &self.account, + ); + out[3usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RoleGranted { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RoleGranted> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RoleGranted) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `RoleRevoked(bytes32,address,address)` and selector `0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b`. + ```solidity + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct RoleRevoked { + #[allow(missing_docs)] + pub role: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RoleRevoked { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "RoleRevoked(bytes32,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 246u8, 57u8, 31u8, 92u8, 50u8, 217u8, 198u8, 157u8, 42u8, 71u8, 234u8, 103u8, + 11u8, 68u8, 41u8, 116u8, 181u8, 57u8, 53u8, 209u8, 237u8, 199u8, 253u8, 100u8, + 235u8, 33u8, 224u8, 71u8, 168u8, 57u8, 23u8, 27u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + role: topics.1, + account: topics.2, + sender: topics.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.role.clone(), + self.account.clone(), + self.sender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.role); + out[2usize] = ::encode_topic( + &self.account, + ); + out[3usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RoleRevoked { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RoleRevoked> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RoleRevoked) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address admin); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub admin: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.admin,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { admin: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.admin, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `grantRole(bytes32,address)` and selector `0x2f2ff15d`. + ```solidity + function grantRole(bytes32 role, address account) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct grantRoleCall { + #[allow(missing_docs)] + pub role: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`grantRole(bytes32,address)`](grantRoleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct grantRoleReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: grantRoleCall) -> Self { + (value.role, value.account) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for grantRoleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + role: tuple.0, + account: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: grantRoleReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for grantRoleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl grantRoleReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for grantRoleCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + type Return = grantRoleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 47u8, 241u8, 93u8]; + const SIGNATURE: &'static str = "grantRole(bytes32,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.role), + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + grantRoleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `grantRoles(bytes32[],address)` and selector `0xfcd7627e`. + ```solidity + function grantRoles(bytes32[] memory roles, address account) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct grantRolesCall { + #[allow(missing_docs)] + pub roles: alloy_sol_types::private::Vec>, + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`grantRoles(bytes32[],address)`](grantRolesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct grantRolesReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec>, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: grantRolesCall) -> Self { + (value.roles, value.account) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for grantRolesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + roles: tuple.0, + account: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: grantRolesReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for grantRolesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl grantRolesReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for grantRolesCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Address, + ); + type Return = grantRolesReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [252u8, 215u8, 98u8, 126u8]; + const SIGNATURE: &'static str = "grantRoles(bytes32[],address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + , + > as alloy_sol_types::SolType>::tokenize(&self.roles), + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + grantRolesReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`BalancerV2Authorizer`](self) function calls. + #[derive(Clone)] + pub enum BalancerV2AuthorizerCalls { + #[allow(missing_docs)] + grantRole(grantRoleCall), + #[allow(missing_docs)] + grantRoles(grantRolesCall), + } + impl BalancerV2AuthorizerCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[47u8, 47u8, 241u8, 93u8], [252u8, 215u8, 98u8, 126u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(grantRole), + ::core::stringify!(grantRoles), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2AuthorizerCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 64usize; + const NAME: &'static str = "BalancerV2AuthorizerCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::grantRole(_) => ::SELECTOR, + Self::grantRoles(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn grantRole( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2AuthorizerCalls::grantRole) + } + grantRole + }, + { + fn grantRoles( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2AuthorizerCalls::grantRoles) + } + grantRoles + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2AuthorizerCalls, + >] = &[ + { + fn grantRole( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2AuthorizerCalls::grantRole) + } + grantRole + }, + { + fn grantRoles( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2AuthorizerCalls::grantRoles) + } + grantRoles + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::grantRole(inner) => { + ::abi_encoded_size(inner) + } + Self::grantRoles(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::grantRole(inner) => { + ::abi_encode_raw(inner, out) + } + Self::grantRoles(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2Authorizer`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2AuthorizerEvents { + #[allow(missing_docs)] + RoleAdminChanged(RoleAdminChanged), + #[allow(missing_docs)] + RoleGranted(RoleGranted), + #[allow(missing_docs)] + RoleRevoked(RoleRevoked), + } + impl BalancerV2AuthorizerEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 47u8, 135u8, 136u8, 17u8, 126u8, 126u8, 255u8, 29u8, 130u8, 233u8, 38u8, 236u8, + 121u8, 73u8, 1u8, 209u8, 124u8, 120u8, 2u8, 74u8, 80u8, 39u8, 9u8, 64u8, 48u8, + 69u8, 64u8, 167u8, 51u8, 101u8, 111u8, 13u8, + ], + [ + 189u8, 121u8, 184u8, 111u8, 254u8, 10u8, 184u8, 232u8, 119u8, 97u8, 81u8, 81u8, + 66u8, 23u8, 205u8, 124u8, 172u8, 213u8, 44u8, 144u8, 159u8, 102u8, 71u8, 92u8, + 58u8, 244u8, 78u8, 18u8, 159u8, 11u8, 0u8, 255u8, + ], + [ + 246u8, 57u8, 31u8, 92u8, 50u8, 217u8, 198u8, 157u8, 42u8, 71u8, 234u8, 103u8, 11u8, + 68u8, 41u8, 116u8, 181u8, 57u8, 53u8, 209u8, 237u8, 199u8, 253u8, 100u8, 235u8, + 33u8, 224u8, 71u8, 168u8, 57u8, 23u8, 27u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(RoleGranted), + ::core::stringify!(RoleAdminChanged), + ::core::stringify!(RoleRevoked), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2AuthorizerEvents { + const COUNT: usize = 3usize; + const NAME: &'static str = "BalancerV2AuthorizerEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::RoleAdminChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::RoleGranted) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::RoleRevoked) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2AuthorizerEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::RoleAdminChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::RoleGranted(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::RoleRevoked(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::RoleAdminChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::RoleGranted(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::RoleRevoked(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2Authorizer`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2AuthorizerInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2AuthorizerInstance { + BalancerV2AuthorizerInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + admin: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + BalancerV2AuthorizerInstance::::deploy(__provider, admin) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + admin: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + BalancerV2AuthorizerInstance::::deploy_builder(__provider, admin) + } + /**A [`BalancerV2Authorizer`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2Authorizer`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2AuthorizerInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2AuthorizerInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2AuthorizerInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2AuthorizerInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2Authorizer`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2AuthorizerInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + admin: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, admin); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + admin: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { admin })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2AuthorizerInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2AuthorizerInstance { + BalancerV2AuthorizerInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2AuthorizerInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`grantRole`] function. + pub fn grantRole( + &self, + role: alloy_sol_types::private::FixedBytes<32>, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, grantRoleCall, N> { + self.call_builder(&grantRoleCall { role, account }) + } + + ///Creates a new call builder for the [`grantRoles`] function. + pub fn grantRoles( + &self, + roles: alloy_sol_types::private::Vec>, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, grantRolesCall, N> { + self.call_builder(&grantRolesCall { roles, account }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2AuthorizerInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`RoleAdminChanged`] event. + pub fn RoleAdminChanged_filter(&self) -> alloy_contract::Event<&P, RoleAdminChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`RoleGranted`] event. + pub fn RoleGranted_filter(&self) -> alloy_contract::Event<&P, RoleGranted, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`RoleRevoked`] event. + pub fn RoleRevoked_filter(&self) -> alloy_contract::Event<&P, RoleRevoked, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2Authorizer::BalancerV2AuthorizerInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/balancerv2basepool/Cargo.toml b/contracts/generated/contracts-generated/balancerv2basepool/Cargo.toml new file mode 100644 index 0000000000..747e10839f --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2basepool/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2basepool" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2basepool/src/lib.rs b/contracts/generated/contracts-generated/balancerv2basepool/src/lib.rs new file mode 100644 index 0000000000..fa557b1b9f --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2basepool/src/lib.rs @@ -0,0 +1,3947 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2BasePool { + event Approval(address indexed owner, address indexed spender, uint256 value); + event PausedStateChanged(bool paused); + event SwapFeePercentageChanged(uint256 swapFeePercentage); + event Transfer(address indexed from, address indexed to, uint256 value); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external pure returns (uint8); + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + function getPoolId() external view returns (bytes32); + function getSwapFeePercentage() external view returns (uint256); + function name() external view returns (string memory); + function nonces(address owner) external view returns (uint256); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function symbol() external view returns (string memory); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getPausedState", + "inputs": [], + "outputs": [ + { + "name": "paused", + "type": "bool", + "internalType": "bool" + }, + { + "name": "pauseWindowEndTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodEndTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSwapFeePercentage", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PausedStateChanged", + "inputs": [ + { + "name": "paused", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SwapFeePercentageChanged", + "inputs": [ + { + "name": "swapFeePercentage", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2BasePool { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PausedStateChanged(bool)` and selector `0x9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be64`. + ```solidity + event PausedStateChanged(bool paused); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PausedStateChanged { + #[allow(missing_docs)] + pub paused: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PausedStateChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PausedStateChanged(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { paused: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.paused, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PausedStateChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PausedStateChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PausedStateChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SwapFeePercentageChanged(uint256)` and selector `0xa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc`. + ```solidity + event SwapFeePercentageChanged(uint256 swapFeePercentage); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SwapFeePercentageChanged { + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SwapFeePercentageChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SwapFeePercentageChanged(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, + 118u8, 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + swapFeePercentage: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.swapFeePercentage, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SwapFeePercentageChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SwapFeePercentageChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SwapFeePercentageChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external pure returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPausedState()` and selector `0x1c0de051`. + ```solidity + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPausedState()`](getPausedStateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateReturn { + #[allow(missing_docs)] + pub paused: bool, + #[allow(missing_docs)] + pub pauseWindowEndTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodEndTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + bool, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateReturn) -> Self { + ( + value.paused, + value.pauseWindowEndTime, + value.bufferPeriodEndTime, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paused: tuple.0, + pauseWindowEndTime: tuple.1, + bufferPeriodEndTime: tuple.2, + } + } + } + } + impl getPausedStateReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self.paused, + ), + as alloy_sol_types::SolType>::tokenize( + &self.pauseWindowEndTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.bufferPeriodEndTime, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPausedStateCall { + type Parameters<'a> = (); + type Return = getPausedStateReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [28u8, 13u8, 224u8, 81u8]; + const SIGNATURE: &'static str = "getPausedState()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPausedStateReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPoolId()` and selector `0x38fff2d0`. + ```solidity + function getPoolId() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPoolId()`](getPoolIdCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolIdCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [56u8, 255u8, 242u8, 208u8]; + const SIGNATURE: &'static str = "getPoolId()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getPoolIdReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getPoolIdReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getSwapFeePercentage()` and selector `0x55c67628`. + ```solidity + function getSwapFeePercentage() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getSwapFeePercentage()`](getSwapFeePercentageCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getSwapFeePercentageCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [85u8, 198u8, 118u8, 40u8]; + const SIGNATURE: &'static str = "getSwapFeePercentage()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2BasePool`](self) function calls. + #[derive(Clone)] + pub enum BalancerV2BasePoolCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + getPausedState(getPausedStateCall), + #[allow(missing_docs)] + getPoolId(getPoolIdCall), + #[allow(missing_docs)] + getSwapFeePercentage(getSwapFeePercentageCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl BalancerV2BasePoolCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [28u8, 13u8, 224u8, 81u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [56u8, 255u8, 242u8, 208u8], + [85u8, 198u8, 118u8, 40u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(getPausedState), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(getPoolId), + ::core::stringify!(getSwapFeePercentage), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2BasePoolCalls { + const COUNT: usize = 14usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2BasePoolCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::getPausedState(_) => { + ::SELECTOR + } + Self::getPoolId(_) => ::SELECTOR, + Self::getSwapFeePercentage(_) => { + ::SELECTOR + } + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::getPausedState) + } + getPausedState + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2BasePoolCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2BasePoolCalls, + >] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2BasePoolCalls::getPausedState) + } + getPausedState + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2BasePoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2BasePoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2BasePoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2BasePoolCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::getPausedState(inner) => { + ::abi_encoded_size(inner) + } + Self::getPoolId(inner) => { + ::abi_encoded_size(inner) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPausedState(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPoolId(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2BasePool`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2BasePoolEvents { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + PausedStateChanged(PausedStateChanged), + #[allow(missing_docs)] + SwapFeePercentageChanged(SwapFeePercentageChanged), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl BalancerV2BasePoolEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ], + [ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, 118u8, + 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(Approval), + ::core::stringify!(PausedStateChanged), + ::core::stringify!(SwapFeePercentageChanged), + ::core::stringify!(Transfer), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2BasePoolEvents { + const COUNT: usize = 4usize; + const NAME: &'static str = "BalancerV2BasePoolEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PausedStateChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::SwapFeePercentageChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2BasePoolEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2BasePool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2BasePoolInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2BasePoolInstance { + BalancerV2BasePoolInstance::::new(address, __provider) + } + /**A [`BalancerV2BasePool`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2BasePool`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2BasePoolInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2BasePoolInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2BasePoolInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2BasePoolInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2BasePool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2BasePoolInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2BasePoolInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2BasePoolInstance { + BalancerV2BasePoolInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2BasePoolInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`getPausedState`] function. + pub fn getPausedState(&self) -> alloy_contract::SolCallBuilder<&P, getPausedStateCall, N> { + self.call_builder(&getPausedStateCall) + } + + ///Creates a new call builder for the [`getPoolId`] function. + pub fn getPoolId(&self) -> alloy_contract::SolCallBuilder<&P, getPoolIdCall, N> { + self.call_builder(&getPoolIdCall) + } + + ///Creates a new call builder for the [`getSwapFeePercentage`] + /// function. + pub fn getSwapFeePercentage( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getSwapFeePercentageCall, N> { + self.call_builder(&getSwapFeePercentageCall) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2BasePoolInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PausedStateChanged`] event. + pub fn PausedStateChanged_filter( + &self, + ) -> alloy_contract::Event<&P, PausedStateChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SwapFeePercentageChanged`] + /// event. + pub fn SwapFeePercentageChanged_filter( + &self, + ) -> alloy_contract::Event<&P, SwapFeePercentageChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2BasePool::BalancerV2BasePoolInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/balancerv2basepoolfactory/Cargo.toml b/contracts/generated/contracts-generated/balancerv2basepoolfactory/Cargo.toml new file mode 100644 index 0000000000..c1dae90168 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2basepoolfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2basepoolfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2basepoolfactory/src/lib.rs b/contracts/generated/contracts-generated/balancerv2basepoolfactory/src/lib.rs new file mode 100644 index 0000000000..4b71d5171c --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2basepoolfactory/src/lib.rs @@ -0,0 +1,374 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2BasePoolFactory { + event PoolCreated(address indexed pool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2BasePoolFactory { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + ///Container for all the [`BalancerV2BasePoolFactory`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2BasePoolFactoryEvents { + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2BasePoolFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, 73u8, + 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, 188u8, + 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(PoolCreated)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2BasePoolFactoryEvents { + const COUNT: usize = 1usize; + const NAME: &'static str = "BalancerV2BasePoolFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2BasePoolFactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2BasePoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2BasePoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2BasePoolFactoryInstance { + BalancerV2BasePoolFactoryInstance::::new(address, __provider) + } + /**A [`BalancerV2BasePoolFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2BasePoolFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2BasePoolFactoryInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2BasePoolFactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2BasePoolFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2BasePoolFactoryInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2BasePoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2BasePoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2BasePoolFactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2BasePoolFactoryInstance { + BalancerV2BasePoolFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2BasePoolFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2BasePoolFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2BasePoolFactory::BalancerV2BasePoolFactoryInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepool/Cargo.toml b/contracts/generated/contracts-generated/balancerv2composablestablepool/Cargo.toml new file mode 100644 index 0000000000..199d8fe5ba --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepool/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2composablestablepool" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepool/src/lib.rs b/contracts/generated/contracts-generated/balancerv2composablestablepool/src/lib.rs new file mode 100644 index 0000000000..7a22688432 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepool/src/lib.rs @@ -0,0 +1,6664 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library ComposableStablePool { + struct NewPoolParams { address vault; address protocolFeeProvider; string name; string symbol; address[] tokens; address[] rateProviders; uint256[] tokenRateCacheDurations; bool[] exemptFromYieldProtocolFeeFlags; uint256 amplificationParameter; uint256 swapFeePercentage; uint256 pauseWindowDuration; uint256 bufferPeriodDuration; address owner; string version; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ComposableStablePool { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct NewPoolParams { address vault; address protocolFeeProvider; string name; string symbol; address[] tokens; address[] rateProviders; uint256[] tokenRateCacheDurations; bool[] exemptFromYieldProtocolFeeFlags; uint256 amplificationParameter; uint256 swapFeePercentage; uint256 pauseWindowDuration; uint256 bufferPeriodDuration; address owner; string version; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NewPoolParams { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokenRateCacheDurations: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub version: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NewPoolParams) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.name, + value.symbol, + value.tokens, + value.rateProviders, + value.tokenRateCacheDurations, + value.exemptFromYieldProtocolFeeFlags, + value.amplificationParameter, + value.swapFeePercentage, + value.pauseWindowDuration, + value.bufferPeriodDuration, + value.owner, + value.version, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NewPoolParams { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + name: tuple.2, + symbol: tuple.3, + tokens: tuple.4, + rateProviders: tuple.5, + tokenRateCacheDurations: tuple.6, + exemptFromYieldProtocolFeeFlags: tuple.7, + amplificationParameter: tuple.8, + swapFeePercentage: tuple.9, + pauseWindowDuration: tuple.10, + bufferPeriodDuration: tuple.11, + owner: tuple.12, + version: tuple.13, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for NewPoolParams { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for NewPoolParams { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + , + > as alloy_sol_types::SolType>::tokenize( + &self.tokenRateCacheDurations, + ), + as alloy_sol_types::SolType>::tokenize( + &self.exemptFromYieldProtocolFeeFlags, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + as alloy_sol_types::SolType>::tokenize(&self.pauseWindowDuration), + as alloy_sol_types::SolType>::tokenize(&self.bufferPeriodDuration), + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.version, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for NewPoolParams { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for NewPoolParams { + const NAME: &'static str = "NewPoolParams"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "NewPoolParams(address vault,address protocolFeeProvider,string name,string \ + symbol,address[] tokens,address[] rateProviders,uint256[] \ + tokenRateCacheDurations,bool[] exemptFromYieldProtocolFeeFlags,uint256 \ + amplificationParameter,uint256 swapFeePercentage,uint256 \ + pauseWindowDuration,uint256 bufferPeriodDuration,address owner,string \ + version)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.vault, + ) + .0, + ::eip712_data_word( + &self.protocolFeeProvider, + ) + .0, + ::eip712_data_word( + &self.name, + ) + .0, + ::eip712_data_word( + &self.symbol, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.tokens) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.rateProviders) + .0, + , + > as alloy_sol_types::SolType>::eip712_data_word( + &self.tokenRateCacheDurations, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.exemptFromYieldProtocolFeeFlags, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.amplificationParameter, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.swapFeePercentage, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.pauseWindowDuration, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.bufferPeriodDuration, + ) + .0, + ::eip712_data_word( + &self.owner, + ) + .0, + ::eip712_data_word( + &self.version, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for NewPoolParams { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.vault, + ) + + ::topic_preimage_length( + &rust.protocolFeeProvider, + ) + + ::topic_preimage_length( + &rust.name, + ) + + ::topic_preimage_length( + &rust.symbol, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.tokens, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.rateProviders, + ) + + , + > as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.tokenRateCacheDurations, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.exemptFromYieldProtocolFeeFlags, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amplificationParameter, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.swapFeePercentage, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.pauseWindowDuration, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.bufferPeriodDuration, + ) + + ::topic_preimage_length( + &rust.owner, + ) + + ::topic_preimage_length( + &rust.version, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.vault, + out, + ); + ::encode_topic_preimage( + &rust.protocolFeeProvider, + out, + ); + ::encode_topic_preimage( + &rust.name, + out, + ); + ::encode_topic_preimage( + &rust.symbol, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.tokens, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.rateProviders, + out, + ); + , + > as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.tokenRateCacheDurations, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.exemptFromYieldProtocolFeeFlags, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amplificationParameter, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.swapFeePercentage, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.pauseWindowDuration, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.bufferPeriodDuration, + out, + ); + ::encode_topic_preimage( + &rust.owner, + out, + ); + ::encode_topic_preimage( + &rust.version, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ComposableStablePool`](self) contract instance. + + See the [wrapper's documentation](`ComposableStablePoolInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ComposableStablePoolInstance { + ComposableStablePoolInstance::::new(address, __provider) + } + /**A [`ComposableStablePool`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ComposableStablePool`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ComposableStablePoolInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ComposableStablePoolInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ComposableStablePoolInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ComposableStablePoolInstance + { + /**Creates a new wrapper around an on-chain [`ComposableStablePool`](self) contract instance. + + See the [wrapper's documentation](`ComposableStablePoolInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ComposableStablePoolInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ComposableStablePoolInstance { + ComposableStablePoolInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ComposableStablePoolInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ComposableStablePoolInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library ComposableStablePool { + struct NewPoolParams { + address vault; + address protocolFeeProvider; + string name; + string symbol; + address[] tokens; + address[] rateProviders; + uint256[] tokenRateCacheDurations; + bool[] exemptFromYieldProtocolFeeFlags; + uint256 amplificationParameter; + uint256 swapFeePercentage; + uint256 pauseWindowDuration; + uint256 bufferPeriodDuration; + address owner; + string version; + } +} + +interface BalancerV2ComposableStablePool { + event AmpUpdateStarted(uint256 startValue, uint256 endValue, uint256 startTime, uint256 endTime); + event AmpUpdateStopped(uint256 currentValue); + event Approval(address indexed owner, address indexed spender, uint256 value); + event PausedStateChanged(bool paused); + event ProtocolFeePercentageCacheUpdated(uint256 indexed feeType, uint256 protocolFeePercentage); + event RecoveryModeStateChanged(bool enabled); + event SwapFeePercentageChanged(uint256 swapFeePercentage); + event TokenRateCacheUpdated(uint256 indexed tokenIndex, uint256 rate); + event TokenRateProviderSet(uint256 indexed tokenIndex, address indexed provider, uint256 cacheDuration); + event Transfer(address indexed from, address indexed to, uint256 value); + + constructor(ComposableStablePool.NewPoolParams params); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external view returns (uint8); + function getAmplificationParameter() external view returns (uint256 value, bool isUpdating, uint256 precision); + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + function getPoolId() external view returns (bytes32); + function getScalingFactors() external view returns (uint256[] memory); + function getSwapFeePercentage() external view returns (uint256); + function name() external view returns (string memory); + function nonces(address owner) external view returns (uint256); + function pause() external; + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function symbol() external view returns (string memory); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "params", + "type": "tuple", + "internalType": "struct ComposableStablePool.NewPoolParams", + "components": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "tokenRateCacheDurations", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]", + "internalType": "bool[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pauseWindowDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "version", + "type": "string", + "internalType": "string" + } + ] + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAmplificationParameter", + "inputs": [], + "outputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "isUpdating", + "type": "bool", + "internalType": "bool" + }, + { + "name": "precision", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPausedState", + "inputs": [], + "outputs": [ + { + "name": "paused", + "type": "bool", + "internalType": "bool" + }, + { + "name": "pauseWindowEndTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodEndTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getScalingFactors", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSwapFeePercentage", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "AmpUpdateStarted", + "inputs": [ + { + "name": "startValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "endValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "startTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "endTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AmpUpdateStopped", + "inputs": [ + { + "name": "currentValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PausedStateChanged", + "inputs": [ + { + "name": "paused", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProtocolFeePercentageCacheUpdated", + "inputs": [ + { + "name": "feeType", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "protocolFeePercentage", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RecoveryModeStateChanged", + "inputs": [ + { + "name": "enabled", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SwapFeePercentageChanged", + "inputs": [ + { + "name": "swapFeePercentage", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenRateCacheUpdated", + "inputs": [ + { + "name": "tokenIndex", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "rate", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenRateProviderSet", + "inputs": [ + { + "name": "tokenIndex", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "contract IRateProvider" + }, + { + "name": "cacheDuration", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2ComposableStablePool { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `AmpUpdateStarted(uint256,uint256,uint256,uint256)` and selector `0x1835882ee7a34ac194f717a35e09bb1d24c82a3b9d854ab6c9749525b714cdf2`. + ```solidity + event AmpUpdateStarted(uint256 startValue, uint256 endValue, uint256 startTime, uint256 endTime); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct AmpUpdateStarted { + #[allow(missing_docs)] + pub startValue: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub endValue: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub startTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub endTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for AmpUpdateStarted { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "AmpUpdateStarted(uint256,uint256,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 24u8, 53u8, 136u8, 46u8, 231u8, 163u8, 74u8, 193u8, 148u8, 247u8, 23u8, 163u8, + 94u8, 9u8, 187u8, 29u8, 36u8, 200u8, 42u8, 59u8, 157u8, 133u8, 74u8, 182u8, + 201u8, 116u8, 149u8, 37u8, 183u8, 20u8, 205u8, 242u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + startValue: data.0, + endValue: data.1, + startTime: data.2, + endTime: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.startValue, + ), + as alloy_sol_types::SolType>::tokenize( + &self.endValue, + ), + as alloy_sol_types::SolType>::tokenize( + &self.startTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.endTime, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for AmpUpdateStarted { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&AmpUpdateStarted> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &AmpUpdateStarted) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `AmpUpdateStopped(uint256)` and selector `0xa0d01593e47e69d07e0ccd87bece09411e07dd1ed40ca8f2e7af2976542a0233`. + ```solidity + event AmpUpdateStopped(uint256 currentValue); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct AmpUpdateStopped { + #[allow(missing_docs)] + pub currentValue: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for AmpUpdateStopped { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "AmpUpdateStopped(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 160u8, 208u8, 21u8, 147u8, 228u8, 126u8, 105u8, 208u8, 126u8, 12u8, 205u8, + 135u8, 190u8, 206u8, 9u8, 65u8, 30u8, 7u8, 221u8, 30u8, 212u8, 12u8, 168u8, + 242u8, 231u8, 175u8, 41u8, 118u8, 84u8, 42u8, 2u8, 51u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + currentValue: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.currentValue, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for AmpUpdateStopped { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&AmpUpdateStopped> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &AmpUpdateStopped) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PausedStateChanged(bool)` and selector `0x9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be64`. + ```solidity + event PausedStateChanged(bool paused); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PausedStateChanged { + #[allow(missing_docs)] + pub paused: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PausedStateChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PausedStateChanged(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { paused: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.paused, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PausedStateChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PausedStateChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PausedStateChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ProtocolFeePercentageCacheUpdated(uint256,uint256)` and selector `0x6bfb689528fa96ec1ad670ad6d6064be1ae96bfd5d2ee35c837fd0fe0c11959a`. + ```solidity + event ProtocolFeePercentageCacheUpdated(uint256 indexed feeType, uint256 protocolFeePercentage); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ProtocolFeePercentageCacheUpdated { + #[allow(missing_docs)] + pub feeType: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub protocolFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ProtocolFeePercentageCacheUpdated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ProtocolFeePercentageCacheUpdated(uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 107u8, 251u8, 104u8, 149u8, 40u8, 250u8, 150u8, 236u8, 26u8, 214u8, 112u8, + 173u8, 109u8, 96u8, 100u8, 190u8, 26u8, 233u8, 107u8, 253u8, 93u8, 46u8, 227u8, + 92u8, 131u8, 127u8, 208u8, 254u8, 12u8, 17u8, 149u8, 154u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + feeType: topics.1, + protocolFeePercentage: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.protocolFeePercentage, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.feeType.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.feeType); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ProtocolFeePercentageCacheUpdated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ProtocolFeePercentageCacheUpdated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ProtocolFeePercentageCacheUpdated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `RecoveryModeStateChanged(bool)` and selector `0xeff3d4d215b42bf0960be9c6d5e05c22cba4df6627a3a523e2acee733b5854c8`. + ```solidity + event RecoveryModeStateChanged(bool enabled); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct RecoveryModeStateChanged { + #[allow(missing_docs)] + pub enabled: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RecoveryModeStateChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "RecoveryModeStateChanged(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 239u8, 243u8, 212u8, 210u8, 21u8, 180u8, 43u8, 240u8, 150u8, 11u8, 233u8, + 198u8, 213u8, 224u8, 92u8, 34u8, 203u8, 164u8, 223u8, 102u8, 39u8, 163u8, + 165u8, 35u8, 226u8, 172u8, 238u8, 115u8, 59u8, 88u8, 84u8, 200u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { enabled: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.enabled, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RecoveryModeStateChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RecoveryModeStateChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RecoveryModeStateChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SwapFeePercentageChanged(uint256)` and selector `0xa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc`. + ```solidity + event SwapFeePercentageChanged(uint256 swapFeePercentage); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SwapFeePercentageChanged { + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SwapFeePercentageChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SwapFeePercentageChanged(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, + 118u8, 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + swapFeePercentage: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.swapFeePercentage, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SwapFeePercentageChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SwapFeePercentageChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SwapFeePercentageChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TokenRateCacheUpdated(uint256,uint256)` and selector `0xb77a83204ca282e08dc3a65b0a1ca32ea4e6875c38ef0bf5bf75e52a67354fac`. + ```solidity + event TokenRateCacheUpdated(uint256 indexed tokenIndex, uint256 rate); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TokenRateCacheUpdated { + #[allow(missing_docs)] + pub tokenIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub rate: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TokenRateCacheUpdated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "TokenRateCacheUpdated(uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 183u8, 122u8, 131u8, 32u8, 76u8, 162u8, 130u8, 224u8, 141u8, 195u8, 166u8, + 91u8, 10u8, 28u8, 163u8, 46u8, 164u8, 230u8, 135u8, 92u8, 56u8, 239u8, 11u8, + 245u8, 191u8, 117u8, 229u8, 42u8, 103u8, 53u8, 79u8, 172u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + tokenIndex: topics.1, + rate: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.rate, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.tokenIndex.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tokenIndex); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TokenRateCacheUpdated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TokenRateCacheUpdated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TokenRateCacheUpdated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TokenRateProviderSet(uint256,address,uint256)` and selector `0xdd6d1c9badb346de6925b358a472c937b41698d2632696759e43fd6527feeec4`. + ```solidity + event TokenRateProviderSet(uint256 indexed tokenIndex, address indexed provider, uint256 cacheDuration); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TokenRateProviderSet { + #[allow(missing_docs)] + pub tokenIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub provider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub cacheDuration: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TokenRateProviderSet { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "TokenRateProviderSet(uint256,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 109u8, 28u8, 155u8, 173u8, 179u8, 70u8, 222u8, 105u8, 37u8, 179u8, 88u8, + 164u8, 114u8, 201u8, 55u8, 180u8, 22u8, 152u8, 210u8, 99u8, 38u8, 150u8, 117u8, + 158u8, 67u8, 253u8, 101u8, 39u8, 254u8, 238u8, 196u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + tokenIndex: topics.1, + provider: topics.2, + cacheDuration: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.cacheDuration, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.tokenIndex.clone(), + self.provider.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tokenIndex); + out[2usize] = ::encode_topic( + &self.provider, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TokenRateProviderSet { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TokenRateProviderSet> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TokenRateProviderSet) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(ComposableStablePool.NewPoolParams params); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub params: ::RustType, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (ComposableStablePool::NewPoolParams,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.params,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { params: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (ComposableStablePool::NewPoolParams,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.params, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external view returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getAmplificationParameter()` and selector `0x6daccffa`. + ```solidity + function getAmplificationParameter() external view returns (uint256 value, bool isUpdating, uint256 precision); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getAmplificationParameterCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getAmplificationParameter()`](getAmplificationParameterCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getAmplificationParameterReturn { + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub isUpdating: bool, + #[allow(missing_docs)] + pub precision: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getAmplificationParameterCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getAmplificationParameterCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + bool, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getAmplificationParameterReturn) -> Self { + (value.value, value.isUpdating, value.precision) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getAmplificationParameterReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + value: tuple.0, + isUpdating: tuple.1, + precision: tuple.2, + } + } + } + } + impl getAmplificationParameterReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> + { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.isUpdating, + ), + as alloy_sol_types::SolType>::tokenize( + &self.precision, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getAmplificationParameterCall { + type Parameters<'a> = (); + type Return = getAmplificationParameterReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [109u8, 172u8, 207u8, 250u8]; + const SIGNATURE: &'static str = "getAmplificationParameter()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getAmplificationParameterReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPausedState()` and selector `0x1c0de051`. + ```solidity + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPausedState()`](getPausedStateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateReturn { + #[allow(missing_docs)] + pub paused: bool, + #[allow(missing_docs)] + pub pauseWindowEndTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodEndTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + bool, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateReturn) -> Self { + ( + value.paused, + value.pauseWindowEndTime, + value.bufferPeriodEndTime, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paused: tuple.0, + pauseWindowEndTime: tuple.1, + bufferPeriodEndTime: tuple.2, + } + } + } + } + impl getPausedStateReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self.paused, + ), + as alloy_sol_types::SolType>::tokenize( + &self.pauseWindowEndTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.bufferPeriodEndTime, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPausedStateCall { + type Parameters<'a> = (); + type Return = getPausedStateReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [28u8, 13u8, 224u8, 81u8]; + const SIGNATURE: &'static str = "getPausedState()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPausedStateReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPoolId()` and selector `0x38fff2d0`. + ```solidity + function getPoolId() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPoolId()`](getPoolIdCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolIdCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [56u8, 255u8, 242u8, 208u8]; + const SIGNATURE: &'static str = "getPoolId()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getPoolIdReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getPoolIdReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getScalingFactors()` and selector `0x1dd746ea`. + ```solidity + function getScalingFactors() external view returns (uint256[] memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getScalingFactorsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getScalingFactors()`](getScalingFactorsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getScalingFactorsReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getScalingFactorsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getScalingFactorsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getScalingFactorsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getScalingFactorsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getScalingFactorsCall { + type Parameters<'a> = (); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [29u8, 215u8, 70u8, 234u8]; + const SIGNATURE: &'static str = "getScalingFactors()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getScalingFactorsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getScalingFactorsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getSwapFeePercentage()` and selector `0x55c67628`. + ```solidity + function getSwapFeePercentage() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getSwapFeePercentage()`](getSwapFeePercentageCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getSwapFeePercentageCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [85u8, 198u8, 118u8, 40u8]; + const SIGNATURE: &'static str = "getSwapFeePercentage()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `pause()` and selector `0x8456cb59`. + ```solidity + function pause() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct pauseCall; + ///Container type for the return parameters of the [`pause()`](pauseCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct pauseReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: pauseCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for pauseCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: pauseReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for pauseReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl pauseReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for pauseCall { + type Parameters<'a> = (); + type Return = pauseReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [132u8, 86u8, 203u8, 89u8]; + const SIGNATURE: &'static str = "pause()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + pauseReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2ComposableStablePool`](self) function + /// calls. + #[derive(Clone)] + pub enum BalancerV2ComposableStablePoolCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + getAmplificationParameter(getAmplificationParameterCall), + #[allow(missing_docs)] + getPausedState(getPausedStateCall), + #[allow(missing_docs)] + getPoolId(getPoolIdCall), + #[allow(missing_docs)] + getScalingFactors(getScalingFactorsCall), + #[allow(missing_docs)] + getSwapFeePercentage(getSwapFeePercentageCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + pause(pauseCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2ComposableStablePoolCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [28u8, 13u8, 224u8, 81u8], + [29u8, 215u8, 70u8, 234u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [56u8, 255u8, 242u8, 208u8], + [84u8, 253u8, 77u8, 80u8], + [85u8, 198u8, 118u8, 40u8], + [109u8, 172u8, 207u8, 250u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [132u8, 86u8, 203u8, 89u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(getPausedState), + ::core::stringify!(getScalingFactors), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(getPoolId), + ::core::stringify!(version), + ::core::stringify!(getSwapFeePercentage), + ::core::stringify!(getAmplificationParameter), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(pause), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2ComposableStablePoolCalls { + const COUNT: usize = 18usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::getAmplificationParameter(_) => { + ::SELECTOR + } + Self::getPausedState(_) => { + ::SELECTOR + } + Self::getPoolId(_) => ::SELECTOR, + Self::getScalingFactors(_) => { + ::SELECTOR + } + Self::getSwapFeePercentage(_) => { + ::SELECTOR + } + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::pause(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolCalls, + >] = &[ + { + fn name( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::name) + } + name + }, + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::getPausedState) + } + getPausedState + }, + { + fn getScalingFactors( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::getScalingFactors) + } + getScalingFactors + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::getPoolId) + } + getPoolId + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::version) + } + version + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn getAmplificationParameter( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw( + data, + ) + .map(BalancerV2ComposableStablePoolCalls::getAmplificationParameter) + } + getAmplificationParameter + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::nonces) + } + nonces + }, + { + fn pause( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::pause) + } + pause + }, + { + fn symbol( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::symbol) + } + symbol + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::transfer) + } + transfer + }, + { + fn permit( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolCalls, + >] = &[ + { + fn name( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::name) + } + name + }, + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2ComposableStablePoolCalls::getPausedState) + } + getPausedState + }, + { + fn getScalingFactors( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2ComposableStablePoolCalls::getScalingFactors) + } + getScalingFactors + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2ComposableStablePoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2ComposableStablePoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::getPoolId) + } + getPoolId + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::version) + } + version + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + BalancerV2ComposableStablePoolCalls::getSwapFeePercentage, + ) + } + getSwapFeePercentage + }, + { + fn getAmplificationParameter( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + BalancerV2ComposableStablePoolCalls::getAmplificationParameter, + ) + } + getAmplificationParameter + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::nonces) + } + nonces + }, + { + fn pause( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::pause) + } + pause + }, + { + fn symbol( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::symbol) + } + symbol + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::transfer) + } + transfer + }, + { + fn permit( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::getAmplificationParameter(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::getPausedState(inner) => { + ::abi_encoded_size(inner) + } + Self::getPoolId(inner) => { + ::abi_encoded_size(inner) + } + Self::getScalingFactors(inner) => { + ::abi_encoded_size(inner) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::pause(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getAmplificationParameter(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::getPausedState(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPoolId(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getScalingFactors(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::pause(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2ComposableStablePool`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2ComposableStablePoolEvents { + #[allow(missing_docs)] + AmpUpdateStarted(AmpUpdateStarted), + #[allow(missing_docs)] + AmpUpdateStopped(AmpUpdateStopped), + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + PausedStateChanged(PausedStateChanged), + #[allow(missing_docs)] + ProtocolFeePercentageCacheUpdated(ProtocolFeePercentageCacheUpdated), + #[allow(missing_docs)] + RecoveryModeStateChanged(RecoveryModeStateChanged), + #[allow(missing_docs)] + SwapFeePercentageChanged(SwapFeePercentageChanged), + #[allow(missing_docs)] + TokenRateCacheUpdated(TokenRateCacheUpdated), + #[allow(missing_docs)] + TokenRateProviderSet(TokenRateProviderSet), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl BalancerV2ComposableStablePoolEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 24u8, 53u8, 136u8, 46u8, 231u8, 163u8, 74u8, 193u8, 148u8, 247u8, 23u8, 163u8, + 94u8, 9u8, 187u8, 29u8, 36u8, 200u8, 42u8, 59u8, 157u8, 133u8, 74u8, 182u8, 201u8, + 116u8, 149u8, 37u8, 183u8, 20u8, 205u8, 242u8, + ], + [ + 107u8, 251u8, 104u8, 149u8, 40u8, 250u8, 150u8, 236u8, 26u8, 214u8, 112u8, 173u8, + 109u8, 96u8, 100u8, 190u8, 26u8, 233u8, 107u8, 253u8, 93u8, 46u8, 227u8, 92u8, + 131u8, 127u8, 208u8, 254u8, 12u8, 17u8, 149u8, 154u8, + ], + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ], + [ + 160u8, 208u8, 21u8, 147u8, 228u8, 126u8, 105u8, 208u8, 126u8, 12u8, 205u8, 135u8, + 190u8, 206u8, 9u8, 65u8, 30u8, 7u8, 221u8, 30u8, 212u8, 12u8, 168u8, 242u8, 231u8, + 175u8, 41u8, 118u8, 84u8, 42u8, 2u8, 51u8, + ], + [ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, 118u8, + 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ], + [ + 183u8, 122u8, 131u8, 32u8, 76u8, 162u8, 130u8, 224u8, 141u8, 195u8, 166u8, 91u8, + 10u8, 28u8, 163u8, 46u8, 164u8, 230u8, 135u8, 92u8, 56u8, 239u8, 11u8, 245u8, + 191u8, 117u8, 229u8, 42u8, 103u8, 53u8, 79u8, 172u8, + ], + [ + 221u8, 109u8, 28u8, 155u8, 173u8, 179u8, 70u8, 222u8, 105u8, 37u8, 179u8, 88u8, + 164u8, 114u8, 201u8, 55u8, 180u8, 22u8, 152u8, 210u8, 99u8, 38u8, 150u8, 117u8, + 158u8, 67u8, 253u8, 101u8, 39u8, 254u8, 238u8, 196u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + [ + 239u8, 243u8, 212u8, 210u8, 21u8, 180u8, 43u8, 240u8, 150u8, 11u8, 233u8, 198u8, + 213u8, 224u8, 92u8, 34u8, 203u8, 164u8, 223u8, 102u8, 39u8, 163u8, 165u8, 35u8, + 226u8, 172u8, 238u8, 115u8, 59u8, 88u8, 84u8, 200u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(AmpUpdateStarted), + ::core::stringify!(ProtocolFeePercentageCacheUpdated), + ::core::stringify!(Approval), + ::core::stringify!(PausedStateChanged), + ::core::stringify!(AmpUpdateStopped), + ::core::stringify!(SwapFeePercentageChanged), + ::core::stringify!(TokenRateCacheUpdated), + ::core::stringify!(TokenRateProviderSet), + ::core::stringify!(Transfer), + ::core::stringify!(RecoveryModeStateChanged), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2ComposableStablePoolEvents { + const COUNT: usize = 10usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::AmpUpdateStarted) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::AmpUpdateStopped) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some( + ::SIGNATURE_HASH, + ) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::PausedStateChanged) + } + Some( + ::SIGNATURE_HASH, + ) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::ProtocolFeePercentageCacheUpdated) + } + Some( + ::SIGNATURE_HASH, + ) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::RecoveryModeStateChanged) + } + Some( + ::SIGNATURE_HASH, + ) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::SwapFeePercentageChanged) + } + Some( + ::SIGNATURE_HASH, + ) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::TokenRateCacheUpdated) + } + Some( + ::SIGNATURE_HASH, + ) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::TokenRateProviderSet) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => { + alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }) + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2ComposableStablePoolEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::AmpUpdateStarted(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::AmpUpdateStopped(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ProtocolFeePercentageCacheUpdated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::RecoveryModeStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::TokenRateCacheUpdated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::TokenRateProviderSet(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::AmpUpdateStarted(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::AmpUpdateStopped(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ProtocolFeePercentageCacheUpdated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::RecoveryModeStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TokenRateCacheUpdated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TokenRateProviderSet(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2ComposableStablePoolInstance { + BalancerV2ComposableStablePoolInstance::::new(address, __provider) + } + /**A [`BalancerV2ComposableStablePool`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2ComposableStablePool`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2ComposableStablePoolInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2ComposableStablePoolInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2ComposableStablePoolInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2ComposableStablePoolInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2ComposableStablePoolInstance { + BalancerV2ComposableStablePoolInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`getAmplificationParameter`] + /// function. + pub fn getAmplificationParameter( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getAmplificationParameterCall, N> { + self.call_builder(&getAmplificationParameterCall) + } + + ///Creates a new call builder for the [`getPausedState`] function. + pub fn getPausedState(&self) -> alloy_contract::SolCallBuilder<&P, getPausedStateCall, N> { + self.call_builder(&getPausedStateCall) + } + + ///Creates a new call builder for the [`getPoolId`] function. + pub fn getPoolId(&self) -> alloy_contract::SolCallBuilder<&P, getPoolIdCall, N> { + self.call_builder(&getPoolIdCall) + } + + ///Creates a new call builder for the [`getScalingFactors`] function. + pub fn getScalingFactors( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getScalingFactorsCall, N> { + self.call_builder(&getScalingFactorsCall) + } + + ///Creates a new call builder for the [`getSwapFeePercentage`] + /// function. + pub fn getSwapFeePercentage( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getSwapFeePercentageCall, N> { + self.call_builder(&getSwapFeePercentageCall) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`pause`] function. + pub fn pause(&self) -> alloy_contract::SolCallBuilder<&P, pauseCall, N> { + self.call_builder(&pauseCall) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`AmpUpdateStarted`] event. + pub fn AmpUpdateStarted_filter(&self) -> alloy_contract::Event<&P, AmpUpdateStarted, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`AmpUpdateStopped`] event. + pub fn AmpUpdateStopped_filter(&self) -> alloy_contract::Event<&P, AmpUpdateStopped, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PausedStateChanged`] event. + pub fn PausedStateChanged_filter( + &self, + ) -> alloy_contract::Event<&P, PausedStateChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the + /// [`ProtocolFeePercentageCacheUpdated`] event. + pub fn ProtocolFeePercentageCacheUpdated_filter( + &self, + ) -> alloy_contract::Event<&P, ProtocolFeePercentageCacheUpdated, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`RecoveryModeStateChanged`] + /// event. + pub fn RecoveryModeStateChanged_filter( + &self, + ) -> alloy_contract::Event<&P, RecoveryModeStateChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SwapFeePercentageChanged`] + /// event. + pub fn SwapFeePercentageChanged_filter( + &self, + ) -> alloy_contract::Event<&P, SwapFeePercentageChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TokenRateCacheUpdated`] event. + pub fn TokenRateCacheUpdated_filter( + &self, + ) -> alloy_contract::Event<&P, TokenRateCacheUpdated, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TokenRateProviderSet`] event. + pub fn TokenRateProviderSet_filter( + &self, + ) -> alloy_contract::Event<&P, TokenRateProviderSet, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2ComposableStablePool::BalancerV2ComposableStablePoolInstance< + ::alloy_provider::DynProvider, +>; diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactory/Cargo.toml b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactory/Cargo.toml new file mode 100644 index 0000000000..144fe8647d --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2composablestablepoolfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactory/src/lib.rs b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactory/src/lib.rs new file mode 100644 index 0000000000..37993f652e --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactory/src/lib.rs @@ -0,0 +1,1540 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2ComposableStablePoolFactory { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "factoryVersion", + "type": "string", + "internalType": "string" + }, + { + "name": "poolVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "tokenRateCacheDurations", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]", + "internalType": "bool[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ComposableStablePool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2ComposableStablePoolFactory { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub factoryVersion: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub poolVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.factoryVersion, + value.poolVersion, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + factoryVersion: tuple.2, + poolVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.factoryVersion, + ), + ::tokenize( + &self.poolVersion, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256,address[],uint256[],bool[],uint256,address)` and selector `0x66b59f6c`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokenRateCacheDurations: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256,address[],uint256[],bool[], + /// uint256,address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.amplificationParameter, + value.rateProviders, + value.tokenRateCacheDurations, + value.exemptFromYieldProtocolFeeFlags, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + amplificationParameter: tuple.3, + rateProviders: tuple.4, + tokenRateCacheDurations: tuple.5, + exemptFromYieldProtocolFeeFlags: tuple.6, + swapFeePercentage: tuple.7, + owner: tuple.8, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [102u8, 181u8, 159u8, 108u8]; + const SIGNATURE: &'static str = "create(string,string,address[],uint256,address[],\ + uint256[],bool[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + , + > as alloy_sol_types::SolType>::tokenize( + &self.tokenRateCacheDurations, + ), + as alloy_sol_types::SolType>::tokenize( + &self.exemptFromYieldProtocolFeeFlags, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2ComposableStablePoolFactory`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2ComposableStablePoolFactoryCalls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2ComposableStablePoolFactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 39u8, 112u8, 219u8], + [84u8, 253u8, 77u8, 80u8], + [102u8, 181u8, 159u8, 108u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(disable), + ::core::stringify!(version), + ::core::stringify!(create), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2ComposableStablePoolFactoryCalls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryCalls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryCalls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryCalls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryCalls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryCalls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryCalls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryCalls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryCalls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2ComposableStablePoolFactory`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2ComposableStablePoolFactoryEvents { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2ComposableStablePoolFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2ComposableStablePoolFactoryEvents { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2ComposableStablePoolFactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2ComposableStablePoolFactoryInstance { + BalancerV2ComposableStablePoolFactoryInstance::::new(address, __provider) + } + /**A [`BalancerV2ComposableStablePoolFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2ComposableStablePoolFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2ComposableStablePoolFactoryInstance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2ComposableStablePoolFactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2ComposableStablePoolFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2ComposableStablePoolFactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2ComposableStablePoolFactoryInstance { + BalancerV2ComposableStablePoolFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + rateProviders: alloy_sol_types::private::Vec, + tokenRateCacheDurations: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + amplificationParameter, + rateProviders, + tokenRateCacheDurations, + exemptFromYieldProtocolFeeFlags, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2ComposableStablePoolFactory::BalancerV2ComposableStablePoolFactoryInstance< + ::alloy_provider::DynProvider, + >; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F"), + Some(15485885u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xf145caFB67081895EE80eB7c04A30Cf87f07b745"), + Some(22182522u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xf302f9F50958c5593770FDf4d4812309fF77414f"), + Some(22691193u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x136FD06Fa01eCF624C7F2B3CB15742c1339dC2c4"), + Some(32774224u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xaEb406b0E430BF5Ea2Dc0B9Fe62E4E53f74B3a33"), + Some(23227044u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv3/Cargo.toml b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv3/Cargo.toml new file mode 100644 index 0000000000..f205ae2f71 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv3/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2composablestablepoolfactoryv3" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv3/src/lib.rs b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv3/src/lib.rs new file mode 100644 index 0000000000..7d75717db0 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv3/src/lib.rs @@ -0,0 +1,1544 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2ComposableStablePoolFactoryV3 { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "factoryVersion", + "type": "string", + "internalType": "string" + }, + { + "name": "poolVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "tokenRateCacheDurations", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]", + "internalType": "bool[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ComposableStablePool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2ComposableStablePoolFactoryV3 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub factoryVersion: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub poolVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.factoryVersion, + value.poolVersion, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + factoryVersion: tuple.2, + poolVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.factoryVersion, + ), + ::tokenize( + &self.poolVersion, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256,address[],uint256[],bool[],uint256,address)` and selector `0x66b59f6c`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokenRateCacheDurations: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256,address[],uint256[],bool[], + /// uint256,address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.amplificationParameter, + value.rateProviders, + value.tokenRateCacheDurations, + value.exemptFromYieldProtocolFeeFlags, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + amplificationParameter: tuple.3, + rateProviders: tuple.4, + tokenRateCacheDurations: tuple.5, + exemptFromYieldProtocolFeeFlags: tuple.6, + swapFeePercentage: tuple.7, + owner: tuple.8, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [102u8, 181u8, 159u8, 108u8]; + const SIGNATURE: &'static str = "create(string,string,address[],uint256,address[],\ + uint256[],bool[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + , + > as alloy_sol_types::SolType>::tokenize( + &self.tokenRateCacheDurations, + ), + as alloy_sol_types::SolType>::tokenize( + &self.exemptFromYieldProtocolFeeFlags, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV3`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2ComposableStablePoolFactoryV3Calls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2ComposableStablePoolFactoryV3Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 39u8, 112u8, 219u8], + [84u8, 253u8, 77u8, 80u8], + [102u8, 181u8, 159u8, 108u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(disable), + ::core::stringify!(version), + ::core::stringify!(create), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2ComposableStablePoolFactoryV3Calls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV3Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV3Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV3Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV3Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV3Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV3Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV3Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV3Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV3Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV3`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2ComposableStablePoolFactoryV3Events { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2ComposableStablePoolFactoryV3Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2ComposableStablePoolFactoryV3Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV3Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2ComposableStablePoolFactoryV3Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV3`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV3Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2ComposableStablePoolFactoryV3Instance { + BalancerV2ComposableStablePoolFactoryV3Instance::::new(address, __provider) + } + /**A [`BalancerV2ComposableStablePoolFactoryV3`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2ComposableStablePoolFactoryV3`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2ComposableStablePoolFactoryV3Instance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2ComposableStablePoolFactoryV3Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2ComposableStablePoolFactoryV3Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV3Instance + { + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV3`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV3Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2ComposableStablePoolFactoryV3Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2ComposableStablePoolFactoryV3Instance { + BalancerV2ComposableStablePoolFactoryV3Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV3Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + rateProviders: alloy_sol_types::private::Vec, + tokenRateCacheDurations: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + amplificationParameter, + rateProviders, + tokenRateCacheDurations, + exemptFromYieldProtocolFeeFlags, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV3Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2ComposableStablePoolFactoryV3::BalancerV2ComposableStablePoolFactoryV3Instance< + ::alloy_provider::DynProvider, + >; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xdba127fBc23fb20F5929C546af220A991b5C6e01"), + Some(16580899u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xe2E901AB09f37884BA31622dF3Ca7FC19AA443Be"), + Some(72832821u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xacAaC3e6D6Df918Bf3c809DFC7d42de0e4a72d4C"), + Some(25475700u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), + Some(26365805u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x7bc6C0E73EDAa66eF3F6E2f27b0EE8661834c6C9"), + Some(39037615u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x1c99324EDC771c82A0DCCB780CC7DDA0045E50e7"), + Some(58948370u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv4/Cargo.toml b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv4/Cargo.toml new file mode 100644 index 0000000000..c3a2a63457 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv4/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2composablestablepoolfactoryv4" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv4/src/lib.rs b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv4/src/lib.rs new file mode 100644 index 0000000000..a563e1e24a --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv4/src/lib.rs @@ -0,0 +1,1552 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2ComposableStablePoolFactoryV4 { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "factoryVersion", + "type": "string", + "internalType": "string" + }, + { + "name": "poolVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "tokenRateCacheDurations", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]", + "internalType": "bool[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ComposableStablePool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2ComposableStablePoolFactoryV4 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub factoryVersion: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub poolVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.factoryVersion, + value.poolVersion, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + factoryVersion: tuple.2, + poolVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.factoryVersion, + ), + ::tokenize( + &self.poolVersion, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256,address[],uint256[],bool[],uint256,address)` and selector `0x66b59f6c`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokenRateCacheDurations: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256,address[],uint256[],bool[], + /// uint256,address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.amplificationParameter, + value.rateProviders, + value.tokenRateCacheDurations, + value.exemptFromYieldProtocolFeeFlags, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + amplificationParameter: tuple.3, + rateProviders: tuple.4, + tokenRateCacheDurations: tuple.5, + exemptFromYieldProtocolFeeFlags: tuple.6, + swapFeePercentage: tuple.7, + owner: tuple.8, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [102u8, 181u8, 159u8, 108u8]; + const SIGNATURE: &'static str = "create(string,string,address[],uint256,address[],\ + uint256[],bool[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + , + > as alloy_sol_types::SolType>::tokenize( + &self.tokenRateCacheDurations, + ), + as alloy_sol_types::SolType>::tokenize( + &self.exemptFromYieldProtocolFeeFlags, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV4`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2ComposableStablePoolFactoryV4Calls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2ComposableStablePoolFactoryV4Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 39u8, 112u8, 219u8], + [84u8, 253u8, 77u8, 80u8], + [102u8, 181u8, 159u8, 108u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(disable), + ::core::stringify!(version), + ::core::stringify!(create), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2ComposableStablePoolFactoryV4Calls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV4Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV4Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV4Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV4Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV4Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV4Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV4Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV4Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV4Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV4`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2ComposableStablePoolFactoryV4Events { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2ComposableStablePoolFactoryV4Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2ComposableStablePoolFactoryV4Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV4Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2ComposableStablePoolFactoryV4Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV4`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV4Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2ComposableStablePoolFactoryV4Instance { + BalancerV2ComposableStablePoolFactoryV4Instance::::new(address, __provider) + } + /**A [`BalancerV2ComposableStablePoolFactoryV4`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2ComposableStablePoolFactoryV4`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2ComposableStablePoolFactoryV4Instance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2ComposableStablePoolFactoryV4Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2ComposableStablePoolFactoryV4Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV4Instance + { + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV4`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV4Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2ComposableStablePoolFactoryV4Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2ComposableStablePoolFactoryV4Instance { + BalancerV2ComposableStablePoolFactoryV4Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV4Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + rateProviders: alloy_sol_types::private::Vec, + tokenRateCacheDurations: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + amplificationParameter, + rateProviders, + tokenRateCacheDurations, + exemptFromYieldProtocolFeeFlags, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV4Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2ComposableStablePoolFactoryV4::BalancerV2ComposableStablePoolFactoryV4Instance< + ::alloy_provider::DynProvider, + >; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xfADa0f4547AB2de89D1304A668C39B3E09Aa7c76"), + Some(16878679u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), + Some(82748180u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), + Some(26666380u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xD87F44Df0159DC78029AB9CA7D7e57E7249F5ACD"), + Some(27056416u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x6Ab5549bBd766A43aFb687776ad8466F8b42f777"), + Some(40613553u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x2498A2B0d6462d2260EAC50aE1C3e03F4829BA95"), + Some(72235860u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x3B1eb8EB7b43882b385aB30533D9A2BeF9052a98"), + Some(29221425u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xA3fd20E29358c056B727657E83DFd139abBC9924"), + Some(3425277u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv5/Cargo.toml b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv5/Cargo.toml new file mode 100644 index 0000000000..6d8761a537 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv5/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2composablestablepoolfactoryv5" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv5/src/lib.rs b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv5/src/lib.rs new file mode 100644 index 0000000000..8e2a913865 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv5/src/lib.rs @@ -0,0 +1,1556 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2ComposableStablePoolFactoryV5 { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "factoryVersion", + "type": "string", + "internalType": "string" + }, + { + "name": "poolVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "tokenRateCacheDurations", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]", + "internalType": "bool[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ComposableStablePool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2ComposableStablePoolFactoryV5 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub factoryVersion: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub poolVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.factoryVersion, + value.poolVersion, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + factoryVersion: tuple.2, + poolVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.factoryVersion, + ), + ::tokenize( + &self.poolVersion, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256,address[],uint256[],bool[],uint256,address)` and selector `0x66b59f6c`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokenRateCacheDurations: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256,address[],uint256[],bool[], + /// uint256,address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.amplificationParameter, + value.rateProviders, + value.tokenRateCacheDurations, + value.exemptFromYieldProtocolFeeFlags, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + amplificationParameter: tuple.3, + rateProviders: tuple.4, + tokenRateCacheDurations: tuple.5, + exemptFromYieldProtocolFeeFlags: tuple.6, + swapFeePercentage: tuple.7, + owner: tuple.8, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [102u8, 181u8, 159u8, 108u8]; + const SIGNATURE: &'static str = "create(string,string,address[],uint256,address[],\ + uint256[],bool[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + , + > as alloy_sol_types::SolType>::tokenize( + &self.tokenRateCacheDurations, + ), + as alloy_sol_types::SolType>::tokenize( + &self.exemptFromYieldProtocolFeeFlags, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV5`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2ComposableStablePoolFactoryV5Calls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2ComposableStablePoolFactoryV5Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 39u8, 112u8, 219u8], + [84u8, 253u8, 77u8, 80u8], + [102u8, 181u8, 159u8, 108u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(disable), + ::core::stringify!(version), + ::core::stringify!(create), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2ComposableStablePoolFactoryV5Calls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV5Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV5Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV5Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV5Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV5Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV5Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV5Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV5Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV5Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV5`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2ComposableStablePoolFactoryV5Events { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2ComposableStablePoolFactoryV5Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2ComposableStablePoolFactoryV5Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV5Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2ComposableStablePoolFactoryV5Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV5`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV5Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2ComposableStablePoolFactoryV5Instance { + BalancerV2ComposableStablePoolFactoryV5Instance::::new(address, __provider) + } + /**A [`BalancerV2ComposableStablePoolFactoryV5`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2ComposableStablePoolFactoryV5`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2ComposableStablePoolFactoryV5Instance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2ComposableStablePoolFactoryV5Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2ComposableStablePoolFactoryV5Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV5Instance + { + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV5`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV5Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2ComposableStablePoolFactoryV5Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2ComposableStablePoolFactoryV5Instance { + BalancerV2ComposableStablePoolFactoryV5Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV5Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + rateProviders: alloy_sol_types::private::Vec, + tokenRateCacheDurations: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + amplificationParameter, + rateProviders, + tokenRateCacheDurations, + exemptFromYieldProtocolFeeFlags, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV5Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2ComposableStablePoolFactoryV5::BalancerV2ComposableStablePoolFactoryV5Instance< + ::alloy_provider::DynProvider, + >; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A"), + Some(17672478u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x043A2daD730d585C44FB79D2614F295D2d625412"), + Some(106752707u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x4fb47126Fa83A8734991E41B942Ac29A3266C968"), + Some(29877945u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), + Some(28900564u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b"), + Some(44961548u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x8df317a729fcaA260306d7de28888932cb579b88"), + Some(1204710u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xA8920455934Da4D853faac1f94Fe7bEf72943eF1"), + Some(110212282u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xE42FFA682A26EF8F25891db4882932711D42e467"), + Some(32478827u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xa523f47A933D5020b23629dDf689695AA94612Dc"), + Some(3872211u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv6/Cargo.toml b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv6/Cargo.toml new file mode 100644 index 0000000000..fb3f1d1aac --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv6/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2composablestablepoolfactoryv6" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv6/src/lib.rs b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv6/src/lib.rs new file mode 100644 index 0000000000..6e0211989e --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2composablestablepoolfactoryv6/src/lib.rs @@ -0,0 +1,1556 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2ComposableStablePoolFactoryV6 { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "factoryVersion", + "type": "string", + "internalType": "string" + }, + { + "name": "poolVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "tokenRateCacheDurations", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "exemptFromYieldProtocolFeeFlags", + "type": "bool[]", + "internalType": "bool[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ComposableStablePool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2ComposableStablePoolFactoryV6 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub factoryVersion: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub poolVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.factoryVersion, + value.poolVersion, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + factoryVersion: tuple.2, + poolVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.factoryVersion, + ), + ::tokenize( + &self.poolVersion, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256,address[],uint256[],bool[],uint256,address)` and selector `0x66b59f6c`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, address[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool[] memory exemptFromYieldProtocolFeeFlags, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokenRateCacheDurations: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256,address[],uint256[],bool[], + /// uint256,address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.amplificationParameter, + value.rateProviders, + value.tokenRateCacheDurations, + value.exemptFromYieldProtocolFeeFlags, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + amplificationParameter: tuple.3, + rateProviders: tuple.4, + tokenRateCacheDurations: tuple.5, + exemptFromYieldProtocolFeeFlags: tuple.6, + swapFeePercentage: tuple.7, + owner: tuple.8, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [102u8, 181u8, 159u8, 108u8]; + const SIGNATURE: &'static str = "create(string,string,address[],uint256,address[],\ + uint256[],bool[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + , + > as alloy_sol_types::SolType>::tokenize( + &self.tokenRateCacheDurations, + ), + as alloy_sol_types::SolType>::tokenize( + &self.exemptFromYieldProtocolFeeFlags, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV6`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2ComposableStablePoolFactoryV6Calls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2ComposableStablePoolFactoryV6Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 39u8, 112u8, 219u8], + [84u8, 253u8, 77u8, 80u8], + [102u8, 181u8, 159u8, 108u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(disable), + ::core::stringify!(version), + ::core::stringify!(create), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2ComposableStablePoolFactoryV6Calls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV6Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV6Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV6Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV6Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2ComposableStablePoolFactoryV6Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2ComposableStablePoolFactoryV6Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV6Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV6Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2ComposableStablePoolFactoryV6Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2ComposableStablePoolFactoryV6`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2ComposableStablePoolFactoryV6Events { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2ComposableStablePoolFactoryV6Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2ComposableStablePoolFactoryV6Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2ComposableStablePoolFactoryV6Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2ComposableStablePoolFactoryV6Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV6`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV6Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2ComposableStablePoolFactoryV6Instance { + BalancerV2ComposableStablePoolFactoryV6Instance::::new(address, __provider) + } + /**A [`BalancerV2ComposableStablePoolFactoryV6`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2ComposableStablePoolFactoryV6`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2ComposableStablePoolFactoryV6Instance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2ComposableStablePoolFactoryV6Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2ComposableStablePoolFactoryV6Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV6Instance + { + /**Creates a new wrapper around an on-chain [`BalancerV2ComposableStablePoolFactoryV6`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2ComposableStablePoolFactoryV6Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2ComposableStablePoolFactoryV6Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2ComposableStablePoolFactoryV6Instance { + BalancerV2ComposableStablePoolFactoryV6Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV6Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + rateProviders: alloy_sol_types::private::Vec, + tokenRateCacheDurations: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + exemptFromYieldProtocolFeeFlags: alloy_sol_types::private::Vec, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + amplificationParameter, + rateProviders, + tokenRateCacheDurations, + exemptFromYieldProtocolFeeFlags, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2ComposableStablePoolFactoryV6Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2ComposableStablePoolFactoryV6::BalancerV2ComposableStablePoolFactoryV6Instance< + ::alloy_provider::DynProvider, + >; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x5B42eC6D40f7B7965BE5308c70e2603c0281C1E9"), + Some(19314764u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), + Some(116694338u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x6B5dA774890Db7B7b96C6f44e6a4b0F657399E2e"), + Some(36485719u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x47B489bf5836f83ABD928C316F8e39bC0587B020"), + Some(32650879u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xEAedc32a51c510d35ebC11088fD5fF2b47aACF2E"), + Some(53996258u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x956CCab09898C0AF2aCa5e6C228c3aD4E93d9288"), + Some(11099703u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), + Some(184805448u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xb9F8AB3ED3F3aCBa64Bc6cd2DcA74B7F38fD7B88"), + Some(42186350u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x05503B3aDE04aCA81c8D6F88eCB73Ba156982D2B"), + Some(5369821u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpool/Cargo.toml b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpool/Cargo.toml new file mode 100644 index 0000000000..fe895314ac --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpool/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2liquiditybootstrappingpool" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpool/src/lib.rs b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpool/src/lib.rs new file mode 100644 index 0000000000..beb0609a43 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpool/src/lib.rs @@ -0,0 +1,5185 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2LiquidityBootstrappingPool { + event Approval(address indexed owner, address indexed spender, uint256 value); + event GradualWeightUpdateScheduled(uint256 startTime, uint256 endTime, uint256[] startWeights, uint256[] endWeights); + event PausedStateChanged(bool paused); + event SwapEnabledSet(bool swapEnabled); + event SwapFeePercentageChanged(uint256 swapFeePercentage); + event Transfer(address indexed from, address indexed to, uint256 value); + + constructor(address vault, string name, string symbol, address[] tokens, uint256[] normalizedWeights, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner, bool swapEnabledOnStart); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external view returns (uint8); + function getNormalizedWeights() external view returns (uint256[] memory); + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + function getPoolId() external view returns (bytes32); + function getScalingFactors() external view returns (uint256[] memory); + function getSwapEnabled() external view returns (bool); + function getSwapFeePercentage() external view returns (uint256); + function name() external view returns (string memory); + function nonces(address owner) external view returns (uint256); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function symbol() external view returns (string memory); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "normalizedWeights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pauseWindowDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "swapEnabledOnStart", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNormalizedWeights", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPausedState", + "inputs": [], + "outputs": [ + { + "name": "paused", + "type": "bool", + "internalType": "bool" + }, + { + "name": "pauseWindowEndTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodEndTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getScalingFactors", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSwapEnabled", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSwapFeePercentage", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "GradualWeightUpdateScheduled", + "inputs": [ + { + "name": "startTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "endTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "startWeights", + "type": "uint256[]", + "indexed": false, + "internalType": "uint256[]" + }, + { + "name": "endWeights", + "type": "uint256[]", + "indexed": false, + "internalType": "uint256[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PausedStateChanged", + "inputs": [ + { + "name": "paused", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SwapEnabledSet", + "inputs": [ + { + "name": "swapEnabled", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SwapFeePercentageChanged", + "inputs": [ + { + "name": "swapFeePercentage", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2LiquidityBootstrappingPool { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `GradualWeightUpdateScheduled(uint256,uint256,uint256[],uint256[])` and selector `0x0f3631f9dab08169d1db21c6dc5f32536fb2b0a6b9bb5330d71c52132f968be0`. + ```solidity + event GradualWeightUpdateScheduled(uint256 startTime, uint256 endTime, uint256[] startWeights, uint256[] endWeights); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct GradualWeightUpdateScheduled { + #[allow(missing_docs)] + pub startTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub endTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub startWeights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub endWeights: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for GradualWeightUpdateScheduled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "GradualWeightUpdateScheduled(uint256,uint256,uint256[],uint256[])"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 15u8, 54u8, 49u8, 249u8, 218u8, 176u8, 129u8, 105u8, 209u8, 219u8, 33u8, 198u8, + 220u8, 95u8, 50u8, 83u8, 111u8, 178u8, 176u8, 166u8, 185u8, 187u8, 83u8, 48u8, + 215u8, 28u8, 82u8, 19u8, 47u8, 150u8, 139u8, 224u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + startTime: data.0, + endTime: data.1, + startWeights: data.2, + endWeights: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.startTime), + as alloy_sol_types::SolType>::tokenize(&self.endTime), + , + > as alloy_sol_types::SolType>::tokenize(&self.startWeights), + , + > as alloy_sol_types::SolType>::tokenize(&self.endWeights), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for GradualWeightUpdateScheduled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&GradualWeightUpdateScheduled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &GradualWeightUpdateScheduled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PausedStateChanged(bool)` and selector `0x9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be64`. + ```solidity + event PausedStateChanged(bool paused); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PausedStateChanged { + #[allow(missing_docs)] + pub paused: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PausedStateChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PausedStateChanged(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { paused: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.paused, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PausedStateChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PausedStateChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PausedStateChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SwapEnabledSet(bool)` and selector `0x5a9e84f78f7957cb4ed7478eb0fcad35ee4ecbe2e0f298420b28a3955392573f`. + ```solidity + event SwapEnabledSet(bool swapEnabled); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SwapEnabledSet { + #[allow(missing_docs)] + pub swapEnabled: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SwapEnabledSet { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SwapEnabledSet(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 90u8, 158u8, 132u8, 247u8, 143u8, 121u8, 87u8, 203u8, 78u8, 215u8, 71u8, 142u8, + 176u8, 252u8, 173u8, 53u8, 238u8, 78u8, 203u8, 226u8, 224u8, 242u8, 152u8, + 66u8, 11u8, 40u8, 163u8, 149u8, 83u8, 146u8, 87u8, 63u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + swapEnabled: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.swapEnabled, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SwapEnabledSet { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SwapEnabledSet> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SwapEnabledSet) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SwapFeePercentageChanged(uint256)` and selector `0xa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc`. + ```solidity + event SwapFeePercentageChanged(uint256 swapFeePercentage); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SwapFeePercentageChanged { + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SwapFeePercentageChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SwapFeePercentageChanged(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, + 118u8, 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + swapFeePercentage: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.swapFeePercentage, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SwapFeePercentageChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SwapFeePercentageChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SwapFeePercentageChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, string name, string symbol, address[] tokens, uint256[] normalizedWeights, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner, bool swapEnabledOnStart); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub normalizedWeights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub swapEnabledOnStart: bool, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.name, + value.symbol, + value.tokens, + value.normalizedWeights, + value.swapFeePercentage, + value.pauseWindowDuration, + value.bufferPeriodDuration, + value.owner, + value.swapEnabledOnStart, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + name: tuple.1, + symbol: tuple.2, + tokens: tuple.3, + normalizedWeights: tuple.4, + swapFeePercentage: tuple.5, + pauseWindowDuration: tuple.6, + bufferPeriodDuration: tuple.7, + owner: tuple.8, + swapEnabledOnStart: tuple.9, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.normalizedWeights), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + as alloy_sol_types::SolType>::tokenize(&self.pauseWindowDuration), + as alloy_sol_types::SolType>::tokenize(&self.bufferPeriodDuration), + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.swapEnabledOnStart, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external view returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getNormalizedWeights()` and selector `0xf89f27ed`. + ```solidity + function getNormalizedWeights() external view returns (uint256[] memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getNormalizedWeightsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getNormalizedWeights()`](getNormalizedWeightsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getNormalizedWeightsReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getNormalizedWeightsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getNormalizedWeightsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getNormalizedWeightsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getNormalizedWeightsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getNormalizedWeightsCall { + type Parameters<'a> = (); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 159u8, 39u8, 237u8]; + const SIGNATURE: &'static str = "getNormalizedWeights()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getNormalizedWeightsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getNormalizedWeightsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPausedState()` and selector `0x1c0de051`. + ```solidity + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPausedState()`](getPausedStateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateReturn { + #[allow(missing_docs)] + pub paused: bool, + #[allow(missing_docs)] + pub pauseWindowEndTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodEndTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + bool, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateReturn) -> Self { + ( + value.paused, + value.pauseWindowEndTime, + value.bufferPeriodEndTime, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paused: tuple.0, + pauseWindowEndTime: tuple.1, + bufferPeriodEndTime: tuple.2, + } + } + } + } + impl getPausedStateReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self.paused, + ), + as alloy_sol_types::SolType>::tokenize( + &self.pauseWindowEndTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.bufferPeriodEndTime, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPausedStateCall { + type Parameters<'a> = (); + type Return = getPausedStateReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [28u8, 13u8, 224u8, 81u8]; + const SIGNATURE: &'static str = "getPausedState()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPausedStateReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPoolId()` and selector `0x38fff2d0`. + ```solidity + function getPoolId() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPoolId()`](getPoolIdCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolIdCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [56u8, 255u8, 242u8, 208u8]; + const SIGNATURE: &'static str = "getPoolId()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getPoolIdReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getPoolIdReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getScalingFactors()` and selector `0x1dd746ea`. + ```solidity + function getScalingFactors() external view returns (uint256[] memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getScalingFactorsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getScalingFactors()`](getScalingFactorsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getScalingFactorsReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getScalingFactorsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getScalingFactorsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getScalingFactorsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getScalingFactorsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getScalingFactorsCall { + type Parameters<'a> = (); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [29u8, 215u8, 70u8, 234u8]; + const SIGNATURE: &'static str = "getScalingFactors()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getScalingFactorsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getScalingFactorsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getSwapEnabled()` and selector `0x47bc4d92`. + ```solidity + function getSwapEnabled() external view returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapEnabledCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getSwapEnabled()`](getSwapEnabledCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapEnabledReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapEnabledCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapEnabledCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapEnabledReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapEnabledReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getSwapEnabledCall { + type Parameters<'a> = (); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [71u8, 188u8, 77u8, 146u8]; + const SIGNATURE: &'static str = "getSwapEnabled()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getSwapEnabledReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getSwapEnabledReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getSwapFeePercentage()` and selector `0x55c67628`. + ```solidity + function getSwapFeePercentage() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getSwapFeePercentage()`](getSwapFeePercentageCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getSwapFeePercentageCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [85u8, 198u8, 118u8, 40u8]; + const SIGNATURE: &'static str = "getSwapFeePercentage()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2LiquidityBootstrappingPool`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2LiquidityBootstrappingPoolCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + getNormalizedWeights(getNormalizedWeightsCall), + #[allow(missing_docs)] + getPausedState(getPausedStateCall), + #[allow(missing_docs)] + getPoolId(getPoolIdCall), + #[allow(missing_docs)] + getScalingFactors(getScalingFactorsCall), + #[allow(missing_docs)] + getSwapEnabled(getSwapEnabledCall), + #[allow(missing_docs)] + getSwapFeePercentage(getSwapFeePercentageCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl BalancerV2LiquidityBootstrappingPoolCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [28u8, 13u8, 224u8, 81u8], + [29u8, 215u8, 70u8, 234u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [56u8, 255u8, 242u8, 208u8], + [71u8, 188u8, 77u8, 146u8], + [85u8, 198u8, 118u8, 40u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + [248u8, 159u8, 39u8, 237u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(getPausedState), + ::core::stringify!(getScalingFactors), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(getPoolId), + ::core::stringify!(getSwapEnabled), + ::core::stringify!(getSwapFeePercentage), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ::core::stringify!(getNormalizedWeights), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2LiquidityBootstrappingPoolCalls { + const COUNT: usize = 17usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2LiquidityBootstrappingPoolCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::getNormalizedWeights(_) => { + ::SELECTOR + } + Self::getPausedState(_) => { + ::SELECTOR + } + Self::getPoolId(_) => ::SELECTOR, + Self::getScalingFactors(_) => { + ::SELECTOR + } + Self::getSwapEnabled(_) => { + ::SELECTOR + } + Self::getSwapFeePercentage(_) => { + ::SELECTOR + } + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2LiquidityBootstrappingPoolCalls, + >] = &[ + { + fn name( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::name) + } + name + }, + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getPausedState) + } + getPausedState + }, + { + fn getScalingFactors( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getScalingFactors) + } + getScalingFactors + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapEnabled( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getSwapEnabled) + } + getSwapEnabled + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::nonces) + } + nonces + }, + { + fn symbol( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::symbol) + } + symbol + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::transfer) + } + transfer + }, + { + fn permit( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::allowance) + } + allowance + }, + { + fn getNormalizedWeights( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getNormalizedWeights) + } + getNormalizedWeights + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2LiquidityBootstrappingPoolCalls, + >] = &[ + { + fn name( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::name) + } + name + }, + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getPausedState) + } + getPausedState + }, + { + fn getScalingFactors( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + BalancerV2LiquidityBootstrappingPoolCalls::getScalingFactors, + ) + } + getScalingFactors + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2LiquidityBootstrappingPoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2LiquidityBootstrappingPoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapEnabled( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2LiquidityBootstrappingPoolCalls::getSwapEnabled) + } + getSwapEnabled + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + BalancerV2LiquidityBootstrappingPoolCalls::getSwapFeePercentage, + ) + } + getSwapFeePercentage + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::nonces) + } + nonces + }, + { + fn symbol( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::symbol) + } + symbol + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::transfer) + } + transfer + }, + { + fn permit( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolCalls::allowance) + } + allowance + }, + { + fn getNormalizedWeights( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + BalancerV2LiquidityBootstrappingPoolCalls::getNormalizedWeights, + ) + } + getNormalizedWeights + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::getNormalizedWeights(inner) => { + ::abi_encoded_size(inner) + } + Self::getPausedState(inner) => { + ::abi_encoded_size(inner) + } + Self::getPoolId(inner) => { + ::abi_encoded_size(inner) + } + Self::getScalingFactors(inner) => { + ::abi_encoded_size(inner) + } + Self::getSwapEnabled(inner) => { + ::abi_encoded_size(inner) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getNormalizedWeights(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::getPausedState(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPoolId(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getScalingFactors(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getSwapEnabled(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2LiquidityBootstrappingPool`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2LiquidityBootstrappingPoolEvents { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + GradualWeightUpdateScheduled(GradualWeightUpdateScheduled), + #[allow(missing_docs)] + PausedStateChanged(PausedStateChanged), + #[allow(missing_docs)] + SwapEnabledSet(SwapEnabledSet), + #[allow(missing_docs)] + SwapFeePercentageChanged(SwapFeePercentageChanged), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl BalancerV2LiquidityBootstrappingPoolEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 15u8, 54u8, 49u8, 249u8, 218u8, 176u8, 129u8, 105u8, 209u8, 219u8, 33u8, 198u8, + 220u8, 95u8, 50u8, 83u8, 111u8, 178u8, 176u8, 166u8, 185u8, 187u8, 83u8, 48u8, + 215u8, 28u8, 82u8, 19u8, 47u8, 150u8, 139u8, 224u8, + ], + [ + 90u8, 158u8, 132u8, 247u8, 143u8, 121u8, 87u8, 203u8, 78u8, 215u8, 71u8, 142u8, + 176u8, 252u8, 173u8, 53u8, 238u8, 78u8, 203u8, 226u8, 224u8, 242u8, 152u8, 66u8, + 11u8, 40u8, 163u8, 149u8, 83u8, 146u8, 87u8, 63u8, + ], + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ], + [ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, 118u8, + 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(GradualWeightUpdateScheduled), + ::core::stringify!(SwapEnabledSet), + ::core::stringify!(Approval), + ::core::stringify!(PausedStateChanged), + ::core::stringify!(SwapFeePercentageChanged), + ::core::stringify!(Transfer), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2LiquidityBootstrappingPoolEvents { + const COUNT: usize = 6usize; + const NAME: &'static str = "BalancerV2LiquidityBootstrappingPoolEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some( + ::SIGNATURE_HASH, + ) => ::decode_raw_log( + topics, data, + ) + .map(Self::GradualWeightUpdateScheduled), + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PausedStateChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::SwapEnabledSet) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::SwapFeePercentageChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2LiquidityBootstrappingPoolEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::GradualWeightUpdateScheduled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SwapEnabledSet(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::GradualWeightUpdateScheduled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SwapEnabledSet(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2LiquidityBootstrappingPool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2LiquidityBootstrappingPoolInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2LiquidityBootstrappingPoolInstance { + BalancerV2LiquidityBootstrappingPoolInstance::::new(address, __provider) + } + /**A [`BalancerV2LiquidityBootstrappingPool`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2LiquidityBootstrappingPool`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2LiquidityBootstrappingPoolInstance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2LiquidityBootstrappingPoolInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2LiquidityBootstrappingPoolInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2LiquidityBootstrappingPoolInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2LiquidityBootstrappingPool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2LiquidityBootstrappingPoolInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2LiquidityBootstrappingPoolInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2LiquidityBootstrappingPoolInstance { + BalancerV2LiquidityBootstrappingPoolInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2LiquidityBootstrappingPoolInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`getNormalizedWeights`] + /// function. + pub fn getNormalizedWeights( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getNormalizedWeightsCall, N> { + self.call_builder(&getNormalizedWeightsCall) + } + + ///Creates a new call builder for the [`getPausedState`] function. + pub fn getPausedState(&self) -> alloy_contract::SolCallBuilder<&P, getPausedStateCall, N> { + self.call_builder(&getPausedStateCall) + } + + ///Creates a new call builder for the [`getPoolId`] function. + pub fn getPoolId(&self) -> alloy_contract::SolCallBuilder<&P, getPoolIdCall, N> { + self.call_builder(&getPoolIdCall) + } + + ///Creates a new call builder for the [`getScalingFactors`] function. + pub fn getScalingFactors( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getScalingFactorsCall, N> { + self.call_builder(&getScalingFactorsCall) + } + + ///Creates a new call builder for the [`getSwapEnabled`] function. + pub fn getSwapEnabled(&self) -> alloy_contract::SolCallBuilder<&P, getSwapEnabledCall, N> { + self.call_builder(&getSwapEnabledCall) + } + + ///Creates a new call builder for the [`getSwapFeePercentage`] + /// function. + pub fn getSwapFeePercentage( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getSwapFeePercentageCall, N> { + self.call_builder(&getSwapFeePercentageCall) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2LiquidityBootstrappingPoolInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`GradualWeightUpdateScheduled`] + /// event. + pub fn GradualWeightUpdateScheduled_filter( + &self, + ) -> alloy_contract::Event<&P, GradualWeightUpdateScheduled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PausedStateChanged`] event. + pub fn PausedStateChanged_filter( + &self, + ) -> alloy_contract::Event<&P, PausedStateChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SwapEnabledSet`] event. + pub fn SwapEnabledSet_filter(&self) -> alloy_contract::Event<&P, SwapEnabledSet, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SwapFeePercentageChanged`] + /// event. + pub fn SwapFeePercentageChanged_filter( + &self, + ) -> alloy_contract::Event<&P, SwapFeePercentageChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2LiquidityBootstrappingPool::BalancerV2LiquidityBootstrappingPoolInstance< + ::alloy_provider::DynProvider, + >; diff --git a/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpoolfactory/Cargo.toml b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpoolfactory/Cargo.toml new file mode 100644 index 0000000000..7f71999280 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpoolfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2liquiditybootstrappingpoolfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpoolfactory/src/lib.rs b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpoolfactory/src/lib.rs new file mode 100644 index 0000000000..dca2df6fdd --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2liquiditybootstrappingpoolfactory/src/lib.rs @@ -0,0 +1,934 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2LiquidityBootstrappingPoolFactory { + event PoolCreated(address indexed pool); + + constructor(address vault); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, address owner, bool swapEnabledOnStart) external returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "weights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "swapEnabledOnStart", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2LiquidityBootstrappingPoolFactory { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.vault,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { vault: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256[],uint256,address,bool)` and selector `0x23679719`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, address owner, bool swapEnabledOnStart) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub weights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub swapEnabledOnStart: bool, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256[],uint256,address, + /// bool)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.weights, + value.swapFeePercentage, + value.owner, + value.swapEnabledOnStart, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + weights: tuple.3, + swapFeePercentage: tuple.4, + owner: tuple.5, + swapEnabledOnStart: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 103u8, 151u8, 25u8]; + const SIGNATURE: &'static str = + "create(string,string,address[],uint256[],uint256,address,bool)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.weights), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.swapEnabledOnStart, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the + /// [`BalancerV2LiquidityBootstrappingPoolFactory`](self) function calls. + #[derive(Clone)] + pub enum BalancerV2LiquidityBootstrappingPoolFactoryCalls { + #[allow(missing_docs)] + create(createCall), + } + impl BalancerV2LiquidityBootstrappingPoolFactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[35u8, 103u8, 151u8, 25u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(create)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2LiquidityBootstrappingPoolFactoryCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 352usize; + const NAME: &'static str = "BalancerV2LiquidityBootstrappingPoolFactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2LiquidityBootstrappingPoolFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2LiquidityBootstrappingPoolFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2LiquidityBootstrappingPoolFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2LiquidityBootstrappingPoolFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the + /// [`BalancerV2LiquidityBootstrappingPoolFactory`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2LiquidityBootstrappingPoolFactoryEvents { + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2LiquidityBootstrappingPoolFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, 73u8, + 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, 188u8, + 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(PoolCreated)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2LiquidityBootstrappingPoolFactoryEvents { + const COUNT: usize = 1usize; + const NAME: &'static str = "BalancerV2LiquidityBootstrappingPoolFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2LiquidityBootstrappingPoolFactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2LiquidityBootstrappingPoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2LiquidityBootstrappingPoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2LiquidityBootstrappingPoolFactoryInstance { + BalancerV2LiquidityBootstrappingPoolFactoryInstance::::new(address, __provider) + } + /**A [`BalancerV2LiquidityBootstrappingPoolFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2LiquidityBootstrappingPoolFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2LiquidityBootstrappingPoolFactoryInstance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2LiquidityBootstrappingPoolFactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2LiquidityBootstrappingPoolFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2LiquidityBootstrappingPoolFactoryInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2LiquidityBootstrappingPoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2LiquidityBootstrappingPoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2LiquidityBootstrappingPoolFactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider( + self, + ) -> BalancerV2LiquidityBootstrappingPoolFactoryInstance { + BalancerV2LiquidityBootstrappingPoolFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2LiquidityBootstrappingPoolFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + weights: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + swapEnabledOnStart: bool, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + weights, + swapFeePercentage, + owner, + swapEnabledOnStart, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2LiquidityBootstrappingPoolFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2LiquidityBootstrappingPoolFactory::BalancerV2LiquidityBootstrappingPoolFactoryInstance< + ::alloy_provider::DynProvider, +>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE"), + Some(12871780u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE"), + Some(17116402u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x142B9666a0a3A30477b052962ddA81547E7029ab"), + Some(222870u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2noprotocolfeeliquiditybootstrappingpoolfactory/Cargo.toml b/contracts/generated/contracts-generated/balancerv2noprotocolfeeliquiditybootstrappingpoolfactory/Cargo.toml new file mode 100644 index 0000000000..57a32e9b91 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2noprotocolfeeliquiditybootstrappingpoolfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2noprotocolfeeliquiditybootstrappingpoolfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2noprotocolfeeliquiditybootstrappingpoolfactory/src/lib.rs b/contracts/generated/contracts-generated/balancerv2noprotocolfeeliquiditybootstrappingpoolfactory/src/lib.rs new file mode 100644 index 0000000000..5c3a5c4b69 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2noprotocolfeeliquiditybootstrappingpoolfactory/src/lib.rs @@ -0,0 +1,974 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory { + event PoolCreated(address indexed pool); + + constructor(address vault); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, address owner, bool swapEnabledOnStart) external returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "weights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "swapEnabledOnStart", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.vault,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { vault: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256[],uint256,address,bool)` and selector `0x23679719`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, address owner, bool swapEnabledOnStart) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub weights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub swapEnabledOnStart: bool, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256[],uint256,address, + /// bool)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.weights, + value.swapFeePercentage, + value.owner, + value.swapEnabledOnStart, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + weights: tuple.3, + swapFeePercentage: tuple.4, + owner: tuple.5, + swapEnabledOnStart: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 103u8, 151u8, 25u8]; + const SIGNATURE: &'static str = + "create(string,string,address[],uint256[],uint256,address,bool)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.weights), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.swapEnabledOnStart, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the + /// [`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls { + #[allow(missing_docs)] + create(createCall), + } + impl BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[35u8, 103u8, 151u8, 25u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(create)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface + for BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls + { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 352usize; + const NAME: &'static str = "BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result< + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls, + > { + ::abi_decode_raw(data) + .map(BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result< + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls, + > { + ::abi_decode_raw_validate(data) + .map(BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the + /// [`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryEvents { + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, 73u8, + 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, 188u8, + 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(PoolCreated)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface + for BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryEvents + { + const COUNT: usize = 1usize; + const NAME: &'static str = "BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData + for BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryEvents + { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance { + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance::::new( + address, __provider, + ) + } + /**A [`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug + for BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance + { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance<&P, N> + { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider( + self, + ) -> BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance { + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + weights: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + swapEnabledOnStart: bool, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + weights, + swapFeePercentage, + owner, + swapEnabledOnStart, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory::BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactoryInstance< + ::alloy_provider::DynProvider, +>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), + Some(13730248u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xf302f9F50958c5593770FDf4d4812309fF77414f"), + Some(7005915u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), + Some(22691243u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x85a80afee867aDf27B50BdB7b76DA70f1E853062"), + Some(25415236u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x41B953164995c11C81DA73D212ED8Af25741b7Ac"), + Some(22067480u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x0c6052254551EAe3ECac77B01DFcf1025418828f"), + Some(1206531u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), + Some(4859669u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), + Some(26386552u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x45fFd460cC6642B8D8Fb12373DFd77Ceb0f4932B"), + Some(3419649u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2stablepool/Cargo.toml b/contracts/generated/contracts-generated/balancerv2stablepool/Cargo.toml new file mode 100644 index 0000000000..d47208d5b3 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2stablepool/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2stablepool" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2stablepool/src/lib.rs b/contracts/generated/contracts-generated/balancerv2stablepool/src/lib.rs new file mode 100644 index 0000000000..bc74bcee38 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2stablepool/src/lib.rs @@ -0,0 +1,4740 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2StablePool { + event AmpUpdateStarted(uint256 startValue, uint256 endValue, uint256 startTime, uint256 endTime); + event AmpUpdateStopped(uint256 currentValue); + event Approval(address indexed owner, address indexed spender, uint256 value); + event PausedStateChanged(bool paused); + event SwapFeePercentageChanged(uint256 swapFeePercentage); + event Transfer(address indexed from, address indexed to, uint256 value); + + constructor(address vault, string name, string symbol, address[] tokens, uint256 amplificationParameter, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external view returns (uint8); + function getAmplificationParameter() external view returns (uint256 value, bool isUpdating, uint256 precision); + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + function getPoolId() external view returns (bytes32); + function getSwapFeePercentage() external view returns (uint256); + function name() external view returns (string memory); + function nonces(address owner) external view returns (uint256); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function symbol() external view returns (string memory); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pauseWindowDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getAmplificationParameter", + "inputs": [], + "outputs": [ + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "isUpdating", + "type": "bool", + "internalType": "bool" + }, + { + "name": "precision", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPausedState", + "inputs": [], + "outputs": [ + { + "name": "paused", + "type": "bool", + "internalType": "bool" + }, + { + "name": "pauseWindowEndTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodEndTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSwapFeePercentage", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AmpUpdateStarted", + "inputs": [ + { + "name": "startValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "endValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "startTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "endTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "AmpUpdateStopped", + "inputs": [ + { + "name": "currentValue", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PausedStateChanged", + "inputs": [ + { + "name": "paused", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SwapFeePercentageChanged", + "inputs": [ + { + "name": "swapFeePercentage", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2StablePool { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `AmpUpdateStarted(uint256,uint256,uint256,uint256)` and selector `0x1835882ee7a34ac194f717a35e09bb1d24c82a3b9d854ab6c9749525b714cdf2`. + ```solidity + event AmpUpdateStarted(uint256 startValue, uint256 endValue, uint256 startTime, uint256 endTime); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct AmpUpdateStarted { + #[allow(missing_docs)] + pub startValue: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub endValue: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub startTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub endTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for AmpUpdateStarted { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "AmpUpdateStarted(uint256,uint256,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 24u8, 53u8, 136u8, 46u8, 231u8, 163u8, 74u8, 193u8, 148u8, 247u8, 23u8, 163u8, + 94u8, 9u8, 187u8, 29u8, 36u8, 200u8, 42u8, 59u8, 157u8, 133u8, 74u8, 182u8, + 201u8, 116u8, 149u8, 37u8, 183u8, 20u8, 205u8, 242u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + startValue: data.0, + endValue: data.1, + startTime: data.2, + endTime: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.startValue, + ), + as alloy_sol_types::SolType>::tokenize( + &self.endValue, + ), + as alloy_sol_types::SolType>::tokenize( + &self.startTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.endTime, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for AmpUpdateStarted { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&AmpUpdateStarted> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &AmpUpdateStarted) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `AmpUpdateStopped(uint256)` and selector `0xa0d01593e47e69d07e0ccd87bece09411e07dd1ed40ca8f2e7af2976542a0233`. + ```solidity + event AmpUpdateStopped(uint256 currentValue); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct AmpUpdateStopped { + #[allow(missing_docs)] + pub currentValue: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for AmpUpdateStopped { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "AmpUpdateStopped(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 160u8, 208u8, 21u8, 147u8, 228u8, 126u8, 105u8, 208u8, 126u8, 12u8, 205u8, + 135u8, 190u8, 206u8, 9u8, 65u8, 30u8, 7u8, 221u8, 30u8, 212u8, 12u8, 168u8, + 242u8, 231u8, 175u8, 41u8, 118u8, 84u8, 42u8, 2u8, 51u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + currentValue: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.currentValue, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for AmpUpdateStopped { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&AmpUpdateStopped> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &AmpUpdateStopped) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PausedStateChanged(bool)` and selector `0x9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be64`. + ```solidity + event PausedStateChanged(bool paused); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PausedStateChanged { + #[allow(missing_docs)] + pub paused: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PausedStateChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PausedStateChanged(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { paused: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.paused, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PausedStateChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PausedStateChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PausedStateChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SwapFeePercentageChanged(uint256)` and selector `0xa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc`. + ```solidity + event SwapFeePercentageChanged(uint256 swapFeePercentage); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SwapFeePercentageChanged { + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SwapFeePercentageChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SwapFeePercentageChanged(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, + 118u8, 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + swapFeePercentage: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.swapFeePercentage, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SwapFeePercentageChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SwapFeePercentageChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SwapFeePercentageChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, string name, string symbol, address[] tokens, uint256 amplificationParameter, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.name, + value.symbol, + value.tokens, + value.amplificationParameter, + value.swapFeePercentage, + value.pauseWindowDuration, + value.bufferPeriodDuration, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + name: tuple.1, + symbol: tuple.2, + tokens: tuple.3, + amplificationParameter: tuple.4, + swapFeePercentage: tuple.5, + pauseWindowDuration: tuple.6, + bufferPeriodDuration: tuple.7, + owner: tuple.8, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + as alloy_sol_types::SolType>::tokenize(&self.pauseWindowDuration), + as alloy_sol_types::SolType>::tokenize(&self.bufferPeriodDuration), + ::tokenize( + &self.owner, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external view returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getAmplificationParameter()` and selector `0x6daccffa`. + ```solidity + function getAmplificationParameter() external view returns (uint256 value, bool isUpdating, uint256 precision); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getAmplificationParameterCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getAmplificationParameter()`](getAmplificationParameterCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getAmplificationParameterReturn { + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub isUpdating: bool, + #[allow(missing_docs)] + pub precision: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getAmplificationParameterCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getAmplificationParameterCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + bool, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getAmplificationParameterReturn) -> Self { + (value.value, value.isUpdating, value.precision) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getAmplificationParameterReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + value: tuple.0, + isUpdating: tuple.1, + precision: tuple.2, + } + } + } + } + impl getAmplificationParameterReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> + { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.isUpdating, + ), + as alloy_sol_types::SolType>::tokenize( + &self.precision, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getAmplificationParameterCall { + type Parameters<'a> = (); + type Return = getAmplificationParameterReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [109u8, 172u8, 207u8, 250u8]; + const SIGNATURE: &'static str = "getAmplificationParameter()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getAmplificationParameterReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPausedState()` and selector `0x1c0de051`. + ```solidity + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPausedState()`](getPausedStateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateReturn { + #[allow(missing_docs)] + pub paused: bool, + #[allow(missing_docs)] + pub pauseWindowEndTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodEndTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + bool, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateReturn) -> Self { + ( + value.paused, + value.pauseWindowEndTime, + value.bufferPeriodEndTime, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paused: tuple.0, + pauseWindowEndTime: tuple.1, + bufferPeriodEndTime: tuple.2, + } + } + } + } + impl getPausedStateReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self.paused, + ), + as alloy_sol_types::SolType>::tokenize( + &self.pauseWindowEndTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.bufferPeriodEndTime, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPausedStateCall { + type Parameters<'a> = (); + type Return = getPausedStateReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [28u8, 13u8, 224u8, 81u8]; + const SIGNATURE: &'static str = "getPausedState()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPausedStateReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPoolId()` and selector `0x38fff2d0`. + ```solidity + function getPoolId() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPoolId()`](getPoolIdCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolIdCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [56u8, 255u8, 242u8, 208u8]; + const SIGNATURE: &'static str = "getPoolId()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getPoolIdReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getPoolIdReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getSwapFeePercentage()` and selector `0x55c67628`. + ```solidity + function getSwapFeePercentage() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getSwapFeePercentage()`](getSwapFeePercentageCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getSwapFeePercentageCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [85u8, 198u8, 118u8, 40u8]; + const SIGNATURE: &'static str = "getSwapFeePercentage()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2StablePool`](self) function calls. + #[derive(Clone)] + pub enum BalancerV2StablePoolCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + getAmplificationParameter(getAmplificationParameterCall), + #[allow(missing_docs)] + getPausedState(getPausedStateCall), + #[allow(missing_docs)] + getPoolId(getPoolIdCall), + #[allow(missing_docs)] + getSwapFeePercentage(getSwapFeePercentageCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl BalancerV2StablePoolCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [28u8, 13u8, 224u8, 81u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [56u8, 255u8, 242u8, 208u8], + [85u8, 198u8, 118u8, 40u8], + [109u8, 172u8, 207u8, 250u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(getPausedState), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(getPoolId), + ::core::stringify!(getSwapFeePercentage), + ::core::stringify!(getAmplificationParameter), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2StablePoolCalls { + const COUNT: usize = 15usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2StablePoolCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::getAmplificationParameter(_) => { + ::SELECTOR + } + Self::getPausedState(_) => { + ::SELECTOR + } + Self::getPoolId(_) => ::SELECTOR, + Self::getSwapFeePercentage(_) => { + ::SELECTOR + } + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::getPausedState) + } + getPausedState + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn getAmplificationParameter( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(BalancerV2StablePoolCalls::getAmplificationParameter) + } + getAmplificationParameter + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2StablePoolCalls, + >] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2StablePoolCalls::getPausedState) + } + getPausedState + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2StablePoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2StablePoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2StablePoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn getAmplificationParameter( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2StablePoolCalls::getAmplificationParameter) + } + getAmplificationParameter + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::getAmplificationParameter(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::getPausedState(inner) => { + ::abi_encoded_size(inner) + } + Self::getPoolId(inner) => { + ::abi_encoded_size(inner) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getAmplificationParameter(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::getPausedState(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPoolId(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2StablePool`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2StablePoolEvents { + #[allow(missing_docs)] + AmpUpdateStarted(AmpUpdateStarted), + #[allow(missing_docs)] + AmpUpdateStopped(AmpUpdateStopped), + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + PausedStateChanged(PausedStateChanged), + #[allow(missing_docs)] + SwapFeePercentageChanged(SwapFeePercentageChanged), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl BalancerV2StablePoolEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 24u8, 53u8, 136u8, 46u8, 231u8, 163u8, 74u8, 193u8, 148u8, 247u8, 23u8, 163u8, + 94u8, 9u8, 187u8, 29u8, 36u8, 200u8, 42u8, 59u8, 157u8, 133u8, 74u8, 182u8, 201u8, + 116u8, 149u8, 37u8, 183u8, 20u8, 205u8, 242u8, + ], + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ], + [ + 160u8, 208u8, 21u8, 147u8, 228u8, 126u8, 105u8, 208u8, 126u8, 12u8, 205u8, 135u8, + 190u8, 206u8, 9u8, 65u8, 30u8, 7u8, 221u8, 30u8, 212u8, 12u8, 168u8, 242u8, 231u8, + 175u8, 41u8, 118u8, 84u8, 42u8, 2u8, 51u8, + ], + [ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, 118u8, + 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(AmpUpdateStarted), + ::core::stringify!(Approval), + ::core::stringify!(PausedStateChanged), + ::core::stringify!(AmpUpdateStopped), + ::core::stringify!(SwapFeePercentageChanged), + ::core::stringify!(Transfer), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2StablePoolEvents { + const COUNT: usize = 6usize; + const NAME: &'static str = "BalancerV2StablePoolEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::AmpUpdateStarted) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::AmpUpdateStopped) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PausedStateChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::SwapFeePercentageChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2StablePoolEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::AmpUpdateStarted(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::AmpUpdateStopped(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::AmpUpdateStarted(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::AmpUpdateStopped(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2StablePool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2StablePoolInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2StablePoolInstance { + BalancerV2StablePoolInstance::::new(address, __provider) + } + /**A [`BalancerV2StablePool`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2StablePool`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2StablePoolInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2StablePoolInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2StablePoolInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2StablePoolInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2StablePool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2StablePoolInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2StablePoolInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2StablePoolInstance { + BalancerV2StablePoolInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2StablePoolInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`getAmplificationParameter`] + /// function. + pub fn getAmplificationParameter( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getAmplificationParameterCall, N> { + self.call_builder(&getAmplificationParameterCall) + } + + ///Creates a new call builder for the [`getPausedState`] function. + pub fn getPausedState(&self) -> alloy_contract::SolCallBuilder<&P, getPausedStateCall, N> { + self.call_builder(&getPausedStateCall) + } + + ///Creates a new call builder for the [`getPoolId`] function. + pub fn getPoolId(&self) -> alloy_contract::SolCallBuilder<&P, getPoolIdCall, N> { + self.call_builder(&getPoolIdCall) + } + + ///Creates a new call builder for the [`getSwapFeePercentage`] + /// function. + pub fn getSwapFeePercentage( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getSwapFeePercentageCall, N> { + self.call_builder(&getSwapFeePercentageCall) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2StablePoolInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`AmpUpdateStarted`] event. + pub fn AmpUpdateStarted_filter(&self) -> alloy_contract::Event<&P, AmpUpdateStarted, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`AmpUpdateStopped`] event. + pub fn AmpUpdateStopped_filter(&self) -> alloy_contract::Event<&P, AmpUpdateStopped, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PausedStateChanged`] event. + pub fn PausedStateChanged_filter( + &self, + ) -> alloy_contract::Event<&P, PausedStateChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SwapFeePercentageChanged`] + /// event. + pub fn SwapFeePercentageChanged_filter( + &self, + ) -> alloy_contract::Event<&P, SwapFeePercentageChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2StablePool::BalancerV2StablePoolInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/balancerv2stablepoolfactoryv2/Cargo.toml b/contracts/generated/contracts-generated/balancerv2stablepoolfactoryv2/Cargo.toml new file mode 100644 index 0000000000..c0d0126850 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2stablepoolfactoryv2/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2stablepoolfactoryv2" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2stablepoolfactoryv2/src/lib.rs b/contracts/generated/contracts-generated/balancerv2stablepoolfactoryv2/src/lib.rs new file mode 100644 index 0000000000..a5a8161061 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2stablepoolfactoryv2/src/lib.rs @@ -0,0 +1,1232 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2StablePoolFactoryV2 { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amplificationParameter", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2StablePoolFactoryV2 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.vault,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { vault: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256,uint256,address)` and selector `0x7932c7f3`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256 amplificationParameter, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256,uint256,address)`](createCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.amplificationParameter, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + amplificationParameter: tuple.3, + swapFeePercentage: tuple.4, + owner: tuple.5, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [121u8, 50u8, 199u8, 243u8]; + const SIGNATURE: &'static str = + "create(string,string,address[],uint256,uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize( + &self.amplificationParameter, + ), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`BalancerV2StablePoolFactoryV2`](self) function + /// calls. + #[derive(Clone)] + pub enum BalancerV2StablePoolFactoryV2Calls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + } + impl BalancerV2StablePoolFactoryV2Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[47u8, 39u8, 112u8, 219u8], [121u8, 50u8, 199u8, 243u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = + &[::core::stringify!(disable), ::core::stringify!(create)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2StablePoolFactoryV2Calls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2StablePoolFactoryV2Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2StablePoolFactoryV2Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolFactoryV2Calls::disable) + } + disable + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2StablePoolFactoryV2Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2StablePoolFactoryV2Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolFactoryV2Calls::disable) + } + disable + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2StablePoolFactoryV2Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2StablePoolFactoryV2`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2StablePoolFactoryV2Events { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2StablePoolFactoryV2Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2StablePoolFactoryV2Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2StablePoolFactoryV2Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2StablePoolFactoryV2Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2StablePoolFactoryV2`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2StablePoolFactoryV2Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2StablePoolFactoryV2Instance { + BalancerV2StablePoolFactoryV2Instance::::new(address, __provider) + } + /**A [`BalancerV2StablePoolFactoryV2`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2StablePoolFactoryV2`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2StablePoolFactoryV2Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2StablePoolFactoryV2Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2StablePoolFactoryV2Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2StablePoolFactoryV2Instance + { + /**Creates a new wrapper around an on-chain [`BalancerV2StablePoolFactoryV2`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2StablePoolFactoryV2Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2StablePoolFactoryV2Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2StablePoolFactoryV2Instance { + BalancerV2StablePoolFactoryV2Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2StablePoolFactoryV2Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + amplificationParameter: alloy_sol_types::private::primitives::aliases::U256, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + amplificationParameter, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2StablePoolFactoryV2Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2StablePoolFactoryV2::BalancerV2StablePoolFactoryV2Instance< + ::alloy_provider::DynProvider, +>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x8df6efec5547e31b0eb7d1291b511ff8a2bf987c"), + Some(14934936u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xeb151668006CD04DAdD098AFd0a82e78F77076c3"), + Some(11088891u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xf23b4DB826DbA14c0e857029dfF076b1c0264843"), + Some(25415344u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xcA96C4f198d343E251b1a01F3EBA061ef3DA73C1"), + Some(29371951u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xEF44D6786b2b4d544b7850Fe67CE6381626Bf2D6"), + Some(14244664u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2vault/Cargo.toml b/contracts/generated/contracts-generated/balancerv2vault/Cargo.toml new file mode 100644 index 0000000000..36626224e0 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2vault/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2vault" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2vault/src/lib.rs b/contracts/generated/contracts-generated/balancerv2vault/src/lib.rs new file mode 100644 index 0000000000..7001682f53 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2vault/src/lib.rs @@ -0,0 +1,7268 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library IVault { + type PoolSpecialization is uint8; + type SwapKind is uint8; + type UserBalanceOpKind is uint8; + struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } + struct FundManagement { address sender; bool fromInternalBalance; address recipient; bool toInternalBalance; } + struct SingleSwap { bytes32 poolId; SwapKind kind; address assetIn; address assetOut; uint256 amount; bytes userData; } + struct UserBalanceOp { UserBalanceOpKind kind; address asset; uint256 amount; address sender; address recipient; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IVault { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PoolSpecialization(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl PoolSpecialization { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for PoolSpecialization { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: PoolSpecialization) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for PoolSpecialization { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for PoolSpecialization { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SwapKind(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl SwapKind { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for SwapKind { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: SwapKind) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for SwapKind { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for SwapKind { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct UserBalanceOpKind(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl UserBalanceOpKind { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for UserBalanceOpKind { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: UserBalanceOpKind) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for UserBalanceOpKind { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for UserBalanceOpKind { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct BatchSwapStep { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub assetInIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub assetOutIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: BatchSwapStep) -> Self { + ( + value.poolId, + value.assetInIndex, + value.assetOutIndex, + value.amount, + value.userData, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for BatchSwapStep { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + poolId: tuple.0, + assetInIndex: tuple.1, + assetOutIndex: tuple.2, + amount: tuple.3, + userData: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for BatchSwapStep { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for BatchSwapStep { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.poolId), + as alloy_sol_types::SolType>::tokenize(&self.assetInIndex), + as alloy_sol_types::SolType>::tokenize(&self.assetOutIndex), + as alloy_sol_types::SolType>::tokenize(&self.amount), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for BatchSwapStep { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for BatchSwapStep { + const NAME: &'static str = "BatchSwapStep"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "BatchSwapStep(bytes32 poolId,uint256 assetInIndex,uint256 \ + assetOutIndex,uint256 amount,bytes userData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word(&self.poolId) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.assetInIndex) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.assetOutIndex) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ::eip712_data_word( + &self.userData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for BatchSwapStep { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.poolId, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.assetInIndex, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.assetOutIndex, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + ::topic_preimage_length( + &rust.userData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.poolId, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.assetInIndex, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.assetOutIndex, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + ::encode_topic_preimage( + &rust.userData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct FundManagement { address sender; bool fromInternalBalance; address recipient; bool toInternalBalance; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct FundManagement { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub fromInternalBalance: bool, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub toInternalBalance: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + bool, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: FundManagement) -> Self { + ( + value.sender, + value.fromInternalBalance, + value.recipient, + value.toInternalBalance, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for FundManagement { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + fromInternalBalance: tuple.1, + recipient: tuple.2, + toInternalBalance: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for FundManagement { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for FundManagement { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.fromInternalBalance, + ), + ::tokenize( + &self.recipient, + ), + ::tokenize( + &self.toInternalBalance, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for FundManagement { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for FundManagement { + const NAME: &'static str = "FundManagement"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "FundManagement(address sender,bool fromInternalBalance,address \ + recipient,bool toInternalBalance)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.sender, + ) + .0, + ::eip712_data_word( + &self.fromInternalBalance, + ) + .0, + ::eip712_data_word( + &self.recipient, + ) + .0, + ::eip712_data_word( + &self.toInternalBalance, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for FundManagement { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.sender, + ) + + ::topic_preimage_length( + &rust.fromInternalBalance, + ) + + ::topic_preimage_length( + &rust.recipient, + ) + + ::topic_preimage_length( + &rust.toInternalBalance, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.sender, + out, + ); + ::encode_topic_preimage( + &rust.fromInternalBalance, + out, + ); + ::encode_topic_preimage( + &rust.recipient, + out, + ); + ::encode_topic_preimage( + &rust.toInternalBalance, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct SingleSwap { bytes32 poolId; SwapKind kind; address assetIn; address assetOut; uint256 amount; bytes userData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SingleSwap { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub kind: ::RustType, + #[allow(missing_docs)] + pub assetIn: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub assetOut: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + SwapKind, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + ::RustType, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SingleSwap) -> Self { + ( + value.poolId, + value.kind, + value.assetIn, + value.assetOut, + value.amount, + value.userData, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SingleSwap { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + poolId: tuple.0, + kind: tuple.1, + assetIn: tuple.2, + assetOut: tuple.3, + amount: tuple.4, + userData: tuple.5, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for SingleSwap { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for SingleSwap { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.poolId), + ::tokenize(&self.kind), + ::tokenize( + &self.assetIn, + ), + ::tokenize( + &self.assetOut, + ), + as alloy_sol_types::SolType>::tokenize(&self.amount), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for SingleSwap { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for SingleSwap { + const NAME: &'static str = "SingleSwap"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "SingleSwap(bytes32 poolId,uint8 kind,address assetIn,address \ + assetOut,uint256 amount,bytes userData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word(&self.poolId) + .0, + ::eip712_data_word(&self.kind) + .0, + ::eip712_data_word( + &self.assetIn, + ) + .0, + ::eip712_data_word( + &self.assetOut, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ::eip712_data_word( + &self.userData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for SingleSwap { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.poolId, + ) + + ::topic_preimage_length( + &rust.kind, + ) + + ::topic_preimage_length( + &rust.assetIn, + ) + + ::topic_preimage_length( + &rust.assetOut, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + ::topic_preimage_length( + &rust.userData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.poolId, + out, + ); + ::encode_topic_preimage(&rust.kind, out); + ::encode_topic_preimage( + &rust.assetIn, + out, + ); + ::encode_topic_preimage( + &rust.assetOut, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + ::encode_topic_preimage( + &rust.userData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct UserBalanceOp { UserBalanceOpKind kind; address asset; uint256 amount; address sender; address recipient; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct UserBalanceOp { + #[allow(missing_docs)] + pub kind: ::RustType, + #[allow(missing_docs)] + pub asset: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + UserBalanceOpKind, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: UserBalanceOp) -> Self { + ( + value.kind, + value.asset, + value.amount, + value.sender, + value.recipient, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for UserBalanceOp { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + kind: tuple.0, + asset: tuple.1, + amount: tuple.2, + sender: tuple.3, + recipient: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for UserBalanceOp { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for UserBalanceOp { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize(&self.kind), + ::tokenize( + &self.asset, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for UserBalanceOp { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for UserBalanceOp { + const NAME: &'static str = "UserBalanceOp"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "UserBalanceOp(uint8 kind,address asset,uint256 amount,address sender,address \ + recipient)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.kind, + ) + .0, + ::eip712_data_word( + &self.asset, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ::eip712_data_word( + &self.sender, + ) + .0, + ::eip712_data_word( + &self.recipient, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for UserBalanceOp { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.kind, + ) + + ::topic_preimage_length( + &rust.asset, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + ::topic_preimage_length( + &rust.sender, + ) + + ::topic_preimage_length( + &rust.recipient, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.kind, out, + ); + ::encode_topic_preimage( + &rust.asset, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + ::encode_topic_preimage( + &rust.sender, + out, + ); + ::encode_topic_preimage( + &rust.recipient, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IVault`](self) contract instance. + + See the [wrapper's documentation](`IVaultInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IVaultInstance { + IVaultInstance::::new(address, __provider) + } + /**A [`IVault`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IVault`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IVaultInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IVaultInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IVaultInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /**Creates a new wrapper around an on-chain [`IVault`](self) contract instance. + + See the [wrapper's documentation](`IVaultInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IVaultInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IVaultInstance { + IVaultInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library IVault { + type PoolSpecialization is uint8; + type SwapKind is uint8; + type UserBalanceOpKind is uint8; + struct BatchSwapStep { + bytes32 poolId; + uint256 assetInIndex; + uint256 assetOutIndex; + uint256 amount; + bytes userData; + } + struct FundManagement { + address sender; + bool fromInternalBalance; + address payable recipient; + bool toInternalBalance; + } + struct SingleSwap { + bytes32 poolId; + SwapKind kind; + address assetIn; + address assetOut; + uint256 amount; + bytes userData; + } + struct UserBalanceOp { + UserBalanceOpKind kind; + address asset; + uint256 amount; + address sender; + address payable recipient; + } +} + +interface BalancerV2Vault { + event AuthorizerChanged(address indexed newAuthorizer); + event ExternalBalanceTransfer(address indexed token, address indexed sender, address recipient, uint256 amount); + event FlashLoan(address indexed recipient, address indexed token, uint256 amount, uint256 feeAmount); + event InternalBalanceChanged(address indexed user, address indexed token, int256 delta); + event PausedStateChanged(bool paused); + event PoolBalanceChanged(bytes32 indexed poolId, address indexed liquidityProvider, address[] tokens, int256[] deltas, uint256[] protocolFeeAmounts); + event PoolBalanceManaged(bytes32 indexed poolId, address indexed assetManager, address indexed token, int256 cashDelta, int256 managedDelta); + event PoolRegistered(bytes32 indexed poolId, address indexed poolAddress, IVault.PoolSpecialization specialization); + event RelayerApprovalChanged(address indexed relayer, address indexed sender, bool approved); + event Swap(bytes32 indexed poolId, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut); + event TokensDeregistered(bytes32 indexed poolId, address[] tokens); + event TokensRegistered(bytes32 indexed poolId, address[] tokens, address[] assetManagers); + + constructor(address authorizer, address weth, uint256 pauseWindowDuration, uint256 bufferPeriodDuration); + + receive() external payable; + + function WETH() external view returns (address); + function batchSwap(IVault.SwapKind kind, IVault.BatchSwapStep[] memory swaps, address[] memory assets, IVault.FundManagement memory funds, int256[] memory limits, uint256 deadline) external payable returns (int256[] memory assetDeltas); + function flashLoan(address recipient, address[] memory tokens, uint256[] memory amounts, bytes memory userData) external; + function getInternalBalance(address user, address[] memory tokens) external view returns (uint256[] memory balances); + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + function getPool(bytes32 poolId) external view returns (address, IVault.PoolSpecialization); + function getPoolTokens(bytes32 poolId) external view returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); + function hasApprovedRelayer(address user, address relayer) external view returns (bool); + function manageUserBalance(IVault.UserBalanceOp[] memory ops) external payable; + function setRelayerApproval(address sender, address relayer, bool approved) external; + function swap(IVault.SingleSwap memory singleSwap, IVault.FundManagement memory funds, uint256 limit, uint256 deadline) external payable returns (uint256 amountCalculated); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "authorizer", + "type": "address", + "internalType": "contract IAuthorizer" + }, + { + "name": "weth", + "type": "address", + "internalType": "contract IWETH" + }, + { + "name": "pauseWindowDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodDuration", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IWETH" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "batchSwap", + "inputs": [ + { + "name": "kind", + "type": "uint8", + "internalType": "enum IVault.SwapKind" + }, + { + "name": "swaps", + "type": "tuple[]", + "internalType": "struct IVault.BatchSwapStep[]", + "components": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "assetInIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assetOutIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "assets", + "type": "address[]", + "internalType": "contract IAsset[]" + }, + { + "name": "funds", + "type": "tuple", + "internalType": "struct IVault.FundManagement", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "fromInternalBalance", + "type": "bool", + "internalType": "bool" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address payable" + }, + { + "name": "toInternalBalance", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "limits", + "type": "int256[]", + "internalType": "int256[]" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "assetDeltas", + "type": "int256[]", + "internalType": "int256[]" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "flashLoan", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "contract IFlashLoanRecipient" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getInternalBalance", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + } + ], + "outputs": [ + { + "name": "balances", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPausedState", + "inputs": [], + "outputs": [ + { + "name": "paused", + "type": "bool", + "internalType": "bool" + }, + { + "name": "pauseWindowEndTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodEndTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPool", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "uint8", + "internalType": "enum IVault.PoolSpecialization" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolTokens", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "balances", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "lastChangeBlock", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hasApprovedRelayer", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "relayer", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "manageUserBalance", + "inputs": [ + { + "name": "ops", + "type": "tuple[]", + "internalType": "struct IVault.UserBalanceOp[]", + "components": [ + { + "name": "kind", + "type": "uint8", + "internalType": "enum IVault.UserBalanceOpKind" + }, + { + "name": "asset", + "type": "address", + "internalType": "contract IAsset" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address payable" + } + ] + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "setRelayerApproval", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "relayer", + "type": "address", + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "singleSwap", + "type": "tuple", + "internalType": "struct IVault.SingleSwap", + "components": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "kind", + "type": "uint8", + "internalType": "enum IVault.SwapKind" + }, + { + "name": "assetIn", + "type": "address", + "internalType": "contract IAsset" + }, + { + "name": "assetOut", + "type": "address", + "internalType": "contract IAsset" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "funds", + "type": "tuple", + "internalType": "struct IVault.FundManagement", + "components": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "fromInternalBalance", + "type": "bool", + "internalType": "bool" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address payable" + }, + { + "name": "toInternalBalance", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "limit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountCalculated", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + }, + { + "type": "event", + "name": "AuthorizerChanged", + "inputs": [ + { + "name": "newAuthorizer", + "type": "address", + "indexed": true, + "internalType": "contract IAuthorizer" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExternalBalanceTransfer", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "contract IERC20" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FlashLoan", + "inputs": [ + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "contract IFlashLoanRecipient" + }, + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "contract IERC20" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "feeAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "InternalBalanceChanged", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "contract IERC20" + }, + { + "name": "delta", + "type": "int256", + "indexed": false, + "internalType": "int256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PausedStateChanged", + "inputs": [ + { + "name": "paused", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolBalanceChanged", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "liquidityProvider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokens", + "type": "address[]", + "indexed": false, + "internalType": "contract IERC20[]" + }, + { + "name": "deltas", + "type": "int256[]", + "indexed": false, + "internalType": "int256[]" + }, + { + "name": "protocolFeeAmounts", + "type": "uint256[]", + "indexed": false, + "internalType": "uint256[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolBalanceManaged", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "assetManager", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "contract IERC20" + }, + { + "name": "cashDelta", + "type": "int256", + "indexed": false, + "internalType": "int256" + }, + { + "name": "managedDelta", + "type": "int256", + "indexed": false, + "internalType": "int256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolRegistered", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "poolAddress", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "specialization", + "type": "uint8", + "indexed": false, + "internalType": "enum IVault.PoolSpecialization" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RelayerApprovalChanged", + "inputs": [ + { + "name": "relayer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Swap", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "tokenIn", + "type": "address", + "indexed": true, + "internalType": "contract IERC20" + }, + { + "name": "tokenOut", + "type": "address", + "indexed": true, + "internalType": "contract IERC20" + }, + { + "name": "amountIn", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amountOut", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokensDeregistered", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "tokens", + "type": "address[]", + "indexed": false, + "internalType": "contract IERC20[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokensRegistered", + "inputs": [ + { + "name": "poolId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "tokens", + "type": "address[]", + "indexed": false, + "internalType": "contract IERC20[]" + }, + { + "name": "assetManagers", + "type": "address[]", + "indexed": false, + "internalType": "address[]" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2Vault { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6101806040523480156200001257600080fd5b5060405162006ed638038062006ed6833981016040819052620000359162000253565b8382826040518060400160405280601181526020017010985b185b98d95c88158c8815985d5b1d607a1b81525080604051806040016040528060018152602001603160f81b815250306001600160a01b031660001b89806001600160a01b03166080816001600160a01b031660601b815250505030604051620000b89062000245565b620000c491906200029f565b604051809103906000f080158015620000e1573d6000803e3d6000fd5b5060601b6001600160601b03191660a052600160005560c052815160209283012060e052805191012061010052507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61012052620001486276a70083111561019462000181565b6200015c62278d0082111561019562000181565b429091016101408190520161016052620001768162000196565b5050505050620002cc565b8162000192576200019281620001f2565b5050565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b610be680620062f083390190565b6000806000806080858703121562000269578384fd5b84516200027681620002b3565b60208601519094506200028981620002b3565b6040860151606090960151949790965092505050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114620002c957600080fd5b50565b60805160601c60a05160601c60c05160e05161010051610120516101405161016051615fc06200033060003980611aed525080611ac952508061289f5250806128e15250806128c05250806110fd5250806113b15250806105285250615fc06000f3fe6080604052600436106101a55760003560e01c8063945bcec9116100e1578063e6c460921161008a578063f84d066e11610064578063f84d066e1461048a578063f94d4668146104aa578063fa6e671d146104d9578063fec90d72146104f9576101d3565b8063e6c4609214610427578063ed24911d14610447578063f6c009271461045c576101d3565b8063b05f8e48116100bb578063b05f8e48146103cf578063b95cac28146103ff578063d2946c2b14610412576101d3565b8063945bcec914610385578063aaabadc514610398578063ad5c4648146103ba576101d3565b806352bbbe291161014e5780637d3aeb96116101285780637d3aeb9614610305578063851c1bb3146103255780638bdb39131461034557806390193b7c14610365576101d3565b806352bbbe29146102b25780635c38449e146102c557806366a9c7d2146102e5576101d3565b80630f5a6efa1161017f5780630f5a6efa1461024157806316c38b3c1461026e5780631c0de0511461028e576101d3565b8063058a628f146101d857806309b2760f146101f85780630e8e3e841461022e576101d3565b366101d3576101d16101b5610526565b6001600160a01b0316336001600160a01b03161461020661054b565b005b600080fd5b3480156101e457600080fd5b506101d16101f3366004615157565b61055d565b34801561020457600080fd5b506102186102133660046156e6565b610581565b6040516102259190615d3e565b60405180910390f35b6101d161023c36600461531e565b610634565b34801561024d57600080fd5b5061026161025c3660046151f5565b610770565b6040516102259190615d08565b34801561027a57600080fd5b506101d161028936600461545c565b610806565b34801561029a57600080fd5b506102a361081f565b60405161022593929190615d26565b6102186102c036600461588f565b610848565b3480156102d157600080fd5b506101d16102e036600461565b565b6109e9565b3480156102f157600080fd5b506101d1610300366004615545565b610e06565b34801561031157600080fd5b506101d1610320366004615516565b610fa5565b34801561033157600080fd5b50610218610340366004615633565b6110f9565b34801561035157600080fd5b506101d16103603660046154ac565b61114b565b34801561037157600080fd5b50610218610380366004615157565b611161565b610261610393366004615786565b61117c565b3480156103a457600080fd5b506103ad6112b0565b6040516102259190615b63565b3480156103c657600080fd5b506103ad6112c4565b3480156103db57600080fd5b506103ef6103ea36600461560f565b6112d3565b6040516102259493929190615eb9565b6101d161040d3660046154ac565b611396565b34801561041e57600080fd5b506103ad6113af565b34801561043357600080fd5b506101d1610442366004615243565b6113d3565b34801561045357600080fd5b506102186114ef565b34801561046857600080fd5b5061047c610477366004615494565b6114f9565b604051610225929190615b9b565b34801561049657600080fd5b506102616104a5366004615702565b611523565b3480156104b657600080fd5b506104ca6104c5366004615494565b611620565b60405161022593929190615cd2565b3480156104e557600080fd5b506101d16104f43660046151ab565b611654565b34801561050557600080fd5b50610519610514366004615173565b6116e6565b6040516102259190615d1b565b7f00000000000000000000000000000000000000000000000000000000000000005b90565b8161055957610559816116fb565b5050565b610565611768565b61056d611781565b610576816117af565b61057e611822565b50565b600061058b611768565b610593611829565b60006105a2338460065461183e565b6000818152600560205260409020549091506105c49060ff16156101f461054b565b60008181526005602052604090819020805460ff1916600190811790915560068054909101905551339082907f3c13bc30b8e878c53fd2a36b679409c073afd75950be43d8858768e956fbc20e9061061d908790615e3a565b60405180910390a3905061062f611822565b919050565b61063c611768565b6000806000805b845181101561075b5760008060008060006106718a878151811061066357fe5b60200260200101518961187d565b9c50939850919650945092509050600185600381111561068d57fe5b14156106a45761069f848383866118f5565b61074a565b866106b6576106b1611829565b600196505b60008560038111156106c457fe5b14156106f5576106d684838386611918565b6106df84611938565b1561069f576106ee8984611945565b985061074a565b61070a61070185611938565b1561020761054b565b600061071585610548565b9050600286600381111561072557fe5b141561073c5761073781848487611957565b610748565b61074881848487611970565b505b505060019093019250610643915050565b50610765836119de565b50505061057e611822565b6060815167ffffffffffffffff8111801561078a57600080fd5b506040519080825280602002602001820160405280156107b4578160200160208202803683370190505b50905060005b82518110156107ff576107e0848483815181106107d357fe5b6020026020010151611a01565b8282815181106107ec57fe5b60209081029190910101526001016107ba565b5092915050565b61080e611768565b610816611781565b61057681611a2c565b600080600061082c611aaa565b159250610837611ac7565b9150610841611aeb565b9050909192565b6000610852611768565b61085a611829565b835161086581611b0f565b610874834211156101fc61054b565b61088760008760800151116101fe61054b565b60006108968760400151611b41565b905060006108a78860600151611b41565b90506108ca816001600160a01b0316836001600160a01b031614156101fd61054b565b6108d2614ce1565b885160808201526020890151819060018111156108eb57fe5b908160018111156108f857fe5b9052506001600160a01b03808416602083015282811660408084019190915260808b0151606084015260a08b01516101008401528951821660c08401528901511660e082015260008061094a83611b66565b9198509250905061098160008c60200151600181111561096657fe5b146109745789831115610979565b898210155b6101fb61054b565b6109998b60400151838c600001518d60200151611c5a565b6109b18b60600151828c604001518d60600151611d38565b6109d36109c18c60400151611938565b6109cc5760006109ce565b825b6119de565b5050505050506109e1611822565b949350505050565b6109f1611768565b6109f9611829565b610a0583518351611e12565b6060835167ffffffffffffffff81118015610a1f57600080fd5b50604051908082528060200260200182016040528015610a49578160200160208202803683370190505b5090506060845167ffffffffffffffff81118015610a6657600080fd5b50604051908082528060200260200182016040528015610a90578160200160208202803683370190505b5090506000805b8651811015610c09576000878281518110610aae57fe5b602002602001015190506000878381518110610ac657fe5b60200260200101519050610b11846001600160a01b0316836001600160a01b03161160006001600160a01b0316846001600160a01b031614610b09576066610b0c565b60685b61054b565b819350816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b409190615b63565b60206040518083038186803b158015610b5857600080fd5b505afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190615968565b858481518110610b9c57fe5b602002602001018181525050610bb181611e1f565b868481518110610bbd57fe5b602002602001018181525050610beb81868581518110610bd957fe5b6020026020010151101561021061054b565b610bff6001600160a01b0383168b83611ea6565b5050600101610a97565b506040517ff04f27070000000000000000000000000000000000000000000000000000000081526001600160a01b0388169063f04f270790610c55908990899088908a90600401615c85565b600060405180830381600087803b158015610c6f57600080fd5b505af1158015610c83573d6000803e3d6000fd5b5050505060005b8651811015610df4576000878281518110610ca157fe5b602002602001015190506000848381518110610cb957fe5b602002602001015190506000826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610cf19190615b63565b60206040518083038186803b158015610d0957600080fd5b505afa158015610d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d419190615968565b9050610d528282101561020361054b565b60008282039050610d7b888681518110610d6857fe5b602002602001015182101561025a61054b565b610d858482611f11565b836001600160a01b03168c6001600160a01b03167f0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f08c8881518110610dc657fe5b602002602001015184604051610ddd929190615e4d565b60405180910390a350505050806001019050610c8a565b50505050610e00611822565b50505050565b610e0e611768565b610e16611829565b82610e2081611f33565b610e2c83518351611e12565b60005b8351811015610eca576000848281518110610e4657fe5b60200260200101519050610e7260006001600160a01b0316826001600160a01b0316141561013561054b565b838281518110610e7e57fe5b6020908102919091018101516000888152600a835260408082206001600160a01b0395861683529093529190912080546001600160a01b03191692909116919091179055600101610e2f565b506000610ed685611f64565b90506002816002811115610ee657fe5b1415610f3457610efc845160021461020c61054b565b610f2f8585600081518110610f0d57fe5b602002602001015186600181518110610f2257fe5b6020026020010151611f7e565b610f5c565b6001816002811115610f4257fe5b1415610f5257610f2f858561202a565b610f5c8585612082565b847ff5847d3f2197b16cdcd2098ec95d0905cd1abdaf415f07bb7cef2bba8ac5dec48585604051610f8e929190615bed565b60405180910390a25050610fa0611822565b505050565b610fad611768565b610fb5611829565b81610fbf81611f33565b6000610fca84611f64565b90506002816002811115610fda57fe5b141561102857610ff0835160021461020c61054b565b611023848460008151811061100157fe5b60200260200101518560018151811061101657fe5b60200260200101516120d7565b611050565b600181600281111561103657fe5b1415611046576110238484612145565b61105084846121ff565b60005b83518110156110b657600a6000868152602001908152602001600020600085838151811061107d57fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002080546001600160a01b0319169055600101611053565b50837f7dcdc6d02ef40c7c1a7046a011b058bd7f988fa14e20a66344f9d4e60657d610846040516110e79190615bda565b60405180910390a25050610559611822565b60007f00000000000000000000000000000000000000000000000000000000000000008260405160200161112e929190615ac2565b604051602081830303815290604052805190602001209050919050565b610e00600185858561115c86612262565b61226e565b6001600160a01b031660009081526002602052604090205490565b6060611186611768565b61118e611829565b835161119981611b0f565b6111a8834211156101fc61054b565b6111b486518551611e12565b6111c08787878b6123f4565b91506000805b87518110156112925760008882815181106111dd57fe5b6020026020010151905060008583815181106111f557fe5b6020026020010151905061122188848151811061120e57fe5b60200260200101518213156101fb61054b565b600081131561126157885160208a015182916112409185918491611c5a565b61124983611938565b1561125b576112588582611945565b94505b50611288565b600081121561128857600081600003905061128683828c604001518d60600151611d38565b505b50506001016111c6565b5061129c816119de565b50506112a6611822565b9695505050505050565b60035461010090046001600160a01b031690565b60006112ce610526565b905090565b600080600080856112e381612683565b6000806112ef89611f64565b905060028160028111156112ff57fe5b14156113165761130f89896126a1565b9150611341565b600181600281111561132457fe5b14156113345761130f898961271b565b61133e8989612789565b91505b61134a826127a1565b9650611355826127b4565b9550611360826127ca565b6000998a52600a60209081526040808c206001600160a01b039b8c168d5290915290992054969995989796909616955050505050565b61139e611829565b610e00600085858561115c86612262565b7f000000000000000000000000000000000000000000000000000000000000000090565b6113db611768565b6113e3611829565b6113eb614d31565b60005b82518110156114e55782818151811061140357fe5b6020026020010151915060008260200151905061141f81612683565b604083015161143961143183836127d0565b61020961054b565b6000828152600a602090815260408083206001600160a01b03858116855292529091205461146c911633146101f661054b565b835160608501516000806114828487878661282c565b91509150846001600160a01b0316336001600160a01b0316877f6edcaf6241105b4c94c2efdbf3a6b12458eb3d07be3a0e81d24b13c44045fe7a85856040516114cc929190615e4d565b60405180910390a45050505050508060010190506113ee565b505061057e611822565b60006112ce61289b565b6000808261150681612683565b61150f84612938565b61151885611f64565b925092505b50915091565b60603330146115f6576000306001600160a01b0316600036604051611549929190615ada565b6000604051808303816000865af19150503d8060008114611586576040519150601f19603f3d011682016040523d82523d6000602084013e61158b565b606091505b50509050806000811461159a57fe5b60046000803e6000516001600160e01b0319167ffa61cc120000000000000000000000000000000000000000000000000000000081146115de573d6000803e3d6000fd5b50602060005260043d0380600460203e602081016000f35b6060611604858585896123f4565b9050602081510263fa61cc126020830352600482036024820181fd5b60608060008361162f81612683565b606061163a8661293e565b9095509050611648816129a0565b95979096509350505050565b61165c611768565b611664611829565b8261166e81611b0f565b6001600160a01b0384811660008181526004602090815260408083209488168084529490915290819020805460ff1916861515179055519091907f46961fdb4502b646d5095fba7600486a8ac05041d55cdf0f16ed677180b5cad8906116d5908690615d1b565b60405180910390a350610fa0611822565b60006116f28383612a4f565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b61177a6002600054141561019061054b565b6002600055565b60006117986000356001600160e01b0319166110f9565b905061057e6117a78233612a7d565b61019161054b565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b6001600055565b61183c611834611aaa565b61019261054b565b565b600069ffffffffffffffffffff8216605084600281111561185b57fe5b901b17606085901b6bffffffffffffffffffffffff19161790505b9392505050565b600080600080600080600088606001519050336001600160a01b0316816001600160a01b0316146118cf57876118ba576118b5611781565b600197505b6118cf6118c78233612a4f565b6101f761054b565b885160208a015160408b01516080909b0151919b909a9992985090965090945092505050565b61190a8361190286611b41565b836000612b20565b50610e008482846000611d38565b61192b8261192586611b41565b83612b76565b610e008482856000611c5a565b6001600160a01b03161590565b60008282016116f2848210158361054b565b6119648385836000612b20565b50610e00828583612b76565b8015610e005761198b6001600160a01b038516848484612ba6565b826001600160a01b0316846001600160a01b03167f540a1a3f28340caec336c81d8d7b3df139ee5cdc1839a4f283d7ebb7eaae2d5c84846040516119d0929190615bc1565b60405180910390a350505050565b6119ed8134101561020461054b565b348190038015610559576105593382612bc7565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205490565b8015611a4c57611a47611a3d611ac7565b421061019361054b565b611a61565b611a61611a57611aeb565b42106101a961054b565b6003805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490611a9f908390615d1b565b60405180910390a150565b6000611ab4611aeb565b4211806112ce57505060035460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b336001600160a01b0382161461057e57611b27611781565b611b318133612a4f565b61057e5761057e816101f7612c41565b6000611b4c82611938565b611b5e57611b5982610548565b6116f5565b6116f5610526565b600080600080611b798560800151612938565b90506000611b8a8660800151611f64565b90506002816002811115611b9a57fe5b1415611bb157611baa8683612c75565b9450611bdc565b6001816002811115611bbf57fe5b1415611bcf57611baa8683612d25565b611bd98683612db8565b94505b611bef8660000151876060015187612ff7565b809450819550505085604001516001600160a01b031686602001516001600160a01b031687608001517f2170c741c41531aec20e7c107c24eecfdd15e69c9bb0a8dd37b1840b9e0b207b8787604051611c49929190615e4d565b60405180910390a450509193909250565b82611c6457610e00565b611c6d84611938565b15611cee57611c7f811561020261054b565b611c8e8347101561020461054b565b611c96610526565b6001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611cd057600080fd5b505af1158015611ce4573d6000803e3d6000fd5b5050505050610e00565b6000611cf985610548565b90508115611d16576000611d108483876001612b20565b90940393505b8315611d3157611d316001600160a01b038216843087612ba6565b5050505050565b82611d4257610e00565b611d4b84611938565b15611ddb57611d5d811561020261054b565b611d65610526565b6001600160a01b0316632e1a7d4d846040518263ffffffff1660e01b8152600401611d909190615d3e565b600060405180830381600087803b158015611daa57600080fd5b505af1158015611dbe573d6000803e3d6000fd5b50611dd6925050506001600160a01b03831684612bc7565b610e00565b6000611de685610548565b90508115611dfe57611df9838286612b76565b611d31565b611d316001600160a01b0382168486611ea6565b610559818314606761054b565b600080611e2a6113af565b6001600160a01b031663d877845c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6257600080fd5b505afa158015611e76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9a9190615968565b90506118768382613025565b610fa08363a9059cbb60e01b8484604051602401611ec5929190615bc1565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152613072565b801561055957610559611f226113af565b6001600160a01b0384169083611ea6565b611f3c81612683565b61057e611f4882612938565b6001600160a01b0316336001600160a01b0316146101f561054b565b600061ffff605083901c166116f5600382106101f461054b565b611f9f816001600160a01b0316836001600160a01b0316141561020a61054b565b611fbe816001600160a01b0316836001600160a01b031610606661054b565b60008381526009602052604090208054611ffb906001600160a01b0316158015611ff3575060018201546001600160a01b0316155b61020b61054b565b80546001600160a01b039384166001600160a01b03199182161782556001909101805492909316911617905550565b6000828152600860205260408120905b8251811015610e0057600061206b84838151811061205457fe5b60200260200101518461311290919063ffffffff16565b90506120798161020a61054b565b5060010161203a565b6000828152600160205260408120905b8251811015610e005760006120c08483815181106120ac57fe5b602090810291909101015184906000613175565b90506120ce8161020a61054b565b50600101612092565b60008060006120e7868686613222565b9250925092506121116120f9846132e9565b80156121095750612109836132e9565b61020d61054b565b600095865260096020526040862080546001600160a01b031990811682556001909101805490911690559490945550505050565b6000828152600860205260408120905b8251811015610e0057600083828151811061216c57fe5b602002602001015190506121b8612109600760008881526020019081526020016000206000846001600160a01b03166001600160a01b03168152602001908152602001600020546132e9565b60008581526007602090815260408083206001600160a01b038516845290915281208190556121e7848361330b565b90506121f58161020961054b565b5050600101612155565b6000828152600160205260408120905b8251811015610e0057600083828151811061222657fe5b60200260200101519050600061223c8483613412565b905061224a612109826132e9565b6122548483613421565b50505080600101905061220f565b61226a614d5a565b5090565b612276611768565b8361228081612683565b8361228a81611b0f565b61229e836000015151846020015151611e12565b60606122ad84600001516134c3565b905060606122bb8883613552565b905060608060606122d08c8c8c8c8c896135e3565b92509250925060006122e18c611f64565b905060028160028111156122f157fe5b1415612359576123548c8760008151811061230857fe5b60200260200101518660008151811061231d57fe5b60200260200101518960018151811061233257fe5b60200260200101518860018151811061234757fe5b60200260200101516137a8565b612382565b600181600281111561236757fe5b1415612378576123548c87866137e7565b6123828c85613854565b6000808e600181111561239157fe5b1490508b6001600160a01b03168d7fe5ce249087ce04f05a957192435400fd97868dba0e6a4b4c049abf8af80dae78896123cb888661389d565b876040516123db93929190615c4c565b60405180910390a3505050505050505050611d31611822565b6060835167ffffffffffffffff8111801561240e57600080fd5b50604051908082528060200260200182016040528015612438578160200160208202803683370190505b509050612443614d84565b61244b614ce1565b60008060005b89518110156126765789818151811061246657fe5b6020026020010151945060008951866020015110801561248a575089518660400151105b905061249781606461054b565b60006124b98b8860200151815181106124ac57fe5b6020026020010151611b41565b905060006124d08c8960400151815181106124ac57fe5b90506124f3816001600160a01b0316836001600160a01b031614156101fd61054b565b60608801516125435761250b600085116101fe61054b565b60006125188b8484613945565b6001600160a01b0316876001600160a01b031614905061253a816101ff61054b565b50606088018590525b87516080880152868a600181111561255757fe5b9081600181111561256457fe5b9052506001600160a01b0380831660208901528181166040808a01919091526060808b0151908a015260808a01516101008a01528c51821660c08a01528c01511660e08801526000806125b689611b66565b919850925090506125c88c8585613967565b97506125fc6125d683613981565b8c8c60200151815181106125e657fe5b60200260200101516139b190919063ffffffff16565b8b8b602001518151811061260c57fe5b60200260200101818152505061264a61262482613981565b8c8c604001518151811061263457fe5b60200260200101516139e590919063ffffffff16565b8b8b604001518151811061265a57fe5b6020026020010181815250505050505050806001019050612451565b5050505050949350505050565b60008181526005602052604090205461057e9060ff166101f461054b565b60008060008060006126b287613a19565b945094509450945050836001600160a01b0316866001600160a01b031614156126e157829450505050506116f5565b816001600160a01b0316866001600160a01b031614156127065793506116f592505050565b6127116102096116fb565b5050505092915050565b60008281526007602090815260408083206001600160a01b03851684529091528120548161274882613a8f565b80612766575060008581526008602052604090206127669085613aa1565b9050806127815761277685612683565b6127816102096116fb565b509392505050565b60008281526001602052604081206109e18184613412565b6dffffffffffffffffffffffffffff1690565b60701c6dffffffffffffffffffffffffffff1690565b60e01c90565b6000806127dc84611f64565b905060028160028111156127ec57fe5b1415612804576127fc8484613ac2565b9150506116f5565b600181600281111561281257fe5b1415612822576127fc8484613b13565b6127fc8484613b2b565b600080600061283a86611f64565b9050600087600281111561284a57fe5b14156128665761285c86828787613b43565b9250925050612892565b600187600281111561287457fe5b14156128865761285c86828787613bbe565b61285c86828787613c3a565b94509492505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612908613c9d565b3060405160200161291d959493929190615df0565b60405160208183030381529060405280519060200120905090565b60601c90565b606080600061294c84611f64565b9050600281600281111561295c57fe5b14156129755761296b84613ca1565b925092505061299b565b600181600281111561298357fe5b14156129925761296b84613dd6565b61296b84613efd565b915091565b60606000825167ffffffffffffffff811180156129bc57600080fd5b506040519080825280602002602001820160405280156129e6578160200160208202803683370190505b5091506000905060005b825181101561151d576000848281518110612a0757fe5b60200260200101519050612a1a81613ff9565b848381518110612a2657fe5b602002602001018181525050612a4483612a3f836127ca565b614014565b9250506001016129f0565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b6003546040517f9be2a88400000000000000000000000000000000000000000000000000000000815260009161010090046001600160a01b031690639be2a88490612ad090869086903090600401615d47565b60206040518083038186803b158015612ae857600080fd5b505afa158015612afc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f29190615478565b600080612b2d8686611a01565b9050612b468380612b3e5750848210155b61020161054b565b612b50818561402b565b9150818103612b6c878783612b6487613981565b60000361403a565b5050949350505050565b6000612b828484611a01565b90506000612b908284611945565b9050611d31858583612ba187613981565b61403a565b610e00846323b872dd60e01b858585604051602401611ec593929190615b77565b612bd6814710156101a361054b565b6000826001600160a01b031682604051612bef90610548565b60006040518083038185875af1925050503d8060008114612c2c576040519150601f19603f3d011682016040523d82523d6000602084013e612c31565b606091505b50509050610fa0816101a461054b565b6001600160a01b0382166000908152600260205260409020805460018101909155610fa0612c6f8483614095565b8361054b565b600080600080612c92866080015187602001518860400151613222565b92509250925060008087604001516001600160a01b031688602001516001600160a01b03161015612cc7575083905082612ccd565b50829050835b612cd9888884846141bb565b60408b015160208c01519199509294509092506001600160a01b03918216911610612d0d57612d0881836142d1565b612d17565b612d1782826142d1565b909255509295945050505050565b600080612d3a8460800151856020015161271b565b90506000612d508560800151866040015161271b565b9050612d5e858584846141bb565b6080880180516000908152600760208181526040808420828e01516001600160a01b03908116865290835281852098909855935183529081528282209a830151909516815298909352919096209590955550929392505050565b60808201516000908152600160209081526040822090840151829182918290612de290839061430c565b90506000612dfd88604001518461430c90919063ffffffff16565b9050811580612e0a575080155b15612e2757612e1c8860800151612683565b612e276102096116fb565b60001991820191016000612e3a8461432b565b905060608167ffffffffffffffff81118015612e5557600080fd5b50604051908082528060200260200182016040528015612e7f578160200160208202803683370190505b50600060a08c018190529091505b82811015612eff576000612ea1878361432f565b9050612eac81613ff9565b838381518110612eb857fe5b602002602001018181525050612ed58c60a00151612a3f836127ca565b60a08d015281861415612eea57809850612ef6565b84821415612ef6578097505b50600101612e8d565b506040517f01ec954a0000000000000000000000000000000000000000000000000000000081526001600160a01b038a16906301ec954a90612f4b908d90859089908990600401615e5b565b602060405180830381600087803b158015612f6557600080fd5b505af1158015612f79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9d9190615968565b9750600080612fb58c600001518d606001518c612ff7565b9092509050612fc48983614345565b9850612fd08882614376565b9750612fdd87878b61438c565b612fe887868a61438c565b50505050505050505092915050565b6000808085600181111561300757fe5b141561301757508290508161301d565b50819050825b935093915050565b600082820261304984158061304257508385838161303f57fe5b04145b600361054b565b806130585760009150506116f5565b670de0b6b3a76400006000198201046001019150506116f5565b60006060836001600160a01b03168360405161308e9190615aea565b6000604051808303816000865af19150503d80600081146130cb576040519150601f19603f3d011682016040523d82523d6000602084013e6130d0565b606091505b509150915060008214156130e8573d6000803e3d6000fd5b610e0081516000148061310a57508180602001905181019061310a9190615478565b6101a261054b565b600061311e8383613aa1565b61316d57508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b038616908117909155855490825282860190935260409020919091556116f5565b5060006116f5565b6001600160a01b03821660009081526002840160205260408120548061320257505082546040805180820182526001600160a01b03858116808352602080840187815260008781526001808c018452878220965187546001600160a01b03191696169590951786559051948401949094559482018089559083526002880190945291902091909155611876565b600019016000908152600180860160205260408220018390559050611876565b600080600080600061323487876143a4565b91509150600061324483836143d5565b60008a81526009602090815260408083208484526002019091528120805460018201549197509293509061327783613a8f565b80613286575061328682613a8f565b806132a757506132968c87613ac2565b80156132a757506132a78c86613ac2565b9050806132c2576132b78c612683565b6132c26102096116fb565b6132cc8383614408565b98506132d8838361442d565b975050505050505093509350939050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6001600160a01b03811660009081526001830160205260408120548015613408578354600019808301919081019060009087908390811061334857fe5b60009182526020909120015487546001600160a01b039091169150819088908590811061337157fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b039485161790559183168152600189810190925260409020908401905586548790806133ba57fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506116f59350505050565b60009150506116f5565b60006116f28383610209614444565b6001600160a01b0381166000908152600283016020526040812054801561340857835460001990810160008181526001878101602090815260408084209587018452808420865481546001600160a01b03199081166001600160a01b0392831617835588860180549387019390935588548216875260028d018086528488209a909a5588541690975584905593895593871682529390925281205590506116f5565b606080825167ffffffffffffffff811180156134de57600080fd5b50604051908082528060200260200182016040528015613508578160200160208202803683370190505b50905060005b83518110156107ff576135268482815181106124ac57fe5b82828151811061353257fe5b6001600160a01b039092166020928302919091019091015260010161350e565b60608060606135608561293e565b9150915061357082518551611e12565b613580600083511161020f61054b565b60005b82518110156135da576135d285828151811061359b57fe5b60200260200101516001600160a01b03168483815181106135b857fe5b60200260200101516001600160a01b03161461020861054b565b600101613583565b50949350505050565b60608060608060006135f4866129a0565b9150915060006136038b612938565b905060008c600181111561361357fe5b146136b657806001600160a01b03166374f3b0098c8c8c8787613634614481565b8f604001516040518863ffffffff1660e01b815260040161365b9796959493929190615d66565b600060405180830381600087803b15801561367557600080fd5b505af1158015613689573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136b19190810190615405565b61374f565b806001600160a01b031663d5c096c48c8c8c87876136d2614481565b8f604001516040518863ffffffff1660e01b81526004016136f99796959493929190615d66565b600060405180830381600087803b15801561371357600080fd5b505af1158015613727573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261374f9190810190615405565b80955081965050506137658751865186516144fb565b60008c600181111561377357fe5b1461378a576137858989898888614513565b613797565b6137978a8989888861465a565b955050505096509650969350505050565b60006137b485846143d5565b600087815260096020908152604080832084845260020190915290209091506137dd85846142d1565b9055505050505050565b60005b8251811015610e00578181815181106137ff57fe5b602002602001015160076000868152602001908152602001600020600085848151811061382857fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020556001016137ea565b6000828152600160205260408120905b8251811015610e00576138958184838151811061387d57fe5b60200260200101518461438c9092919063ffffffff16565b600101613864565b6060825167ffffffffffffffff811180156138b757600080fd5b506040519080825280602002602001820160405280156138e1578160200160208202803683370190505b50905060005b83518110156107ff57826139115783818151811061390157fe5b6020026020010151600003613926565b83818151811061391d57fe5b60200260200101515b82828151811061393257fe5b60209081029190910101526001016138e7565b60008084600181111561395457fe5b1461395f57816109e1565b509092915050565b60008084600181111561397657fe5b146107ff57826109e1565b600061226a7f800000000000000000000000000000000000000000000000000000000000000083106101a561054b565b60008282016116f28284128015906139c95750848212155b806139de57506000841280156139de57508482125b600061054b565b60008183036116f28284128015906139fd5750848213155b80613a125750600084128015613a1257508482135b600161054b565b6000818152600960205260408120805460018201546001600160a01b0391821692849290911690829081613a4d86856143d5565b6000818152600284016020526040902080546001820154919950919250613a748282614408565b9650613a80828261442d565b94505050505091939590929450565b6000613a9a826132e9565b1592915050565b6001600160a01b031660009081526001919091016020526040902054151590565b600082815260096020526040812080546001600160a01b0384811691161480613afa575060018101546001600160a01b038481169116145b80156109e1575050506001600160a01b03161515919050565b60008281526008602052604081206109e18184613aa1565b60008281526001602052604081206109e181846147d0565b6000806002856002811115613b5457fe5b1415613b6a57613b658685856147f1565b613b94565b6001856002811115613b7857fe5b1415613b8957613b658685856147ff565b613b9486858561480d565b8215613bae57613bae6001600160a01b0385163385611ea6565b5050600081900394909350915050565b6000806002856002811115613bcf57fe5b1415613be557613be086858561481b565b613c0f565b6001856002811115613bf357fe5b1415613c0457613be0868585614829565b613c0f868585614837565b8215613c2a57613c2a6001600160a01b038516333086612ba6565b5090946000869003945092505050565b6000806002856002811115613c4b57fe5b1415613c6357613c5c868585614845565b9050613c90565b6001856002811115613c7157fe5b1415613c8257613c5c868585614855565b613c8d868585614865565b90505b6000915094509492505050565b4690565b606080600080600080613cb387613a19565b92975090955093509150506001600160a01b0384161580613cdb57506001600160a01b038216155b15613d04575050604080516000808252602082019081528183019092529450925061299b915050565b60408051600280825260608201835290916020830190803683370190505095508386600081518110613d3257fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508186600181518110613d6057fe5b6001600160a01b03929092166020928302919091018201526040805160028082526060820183529092909190830190803683370190505094508285600081518110613da757fe5b6020026020010181815250508085600181518110613dc157fe5b60200260200101818152505050505050915091565b60008181526008602052604090206060908190613df28161432b565b67ffffffffffffffff81118015613e0857600080fd5b50604051908082528060200260200182016040528015613e32578160200160208202803683370190505b509250825167ffffffffffffffff81118015613e4d57600080fd5b50604051908082528060200260200182016040528015613e77578160200160208202803683370190505b50915060005b8351811015613ef6576000613e928383614875565b905080858381518110613ea157fe5b6001600160a01b03928316602091820292909201810191909152600088815260078252604080822093851682529290915220548451859084908110613ee257fe5b602090810291909101015250600101613e7d565b5050915091565b60008181526001602052604090206060908190613f198161432b565b67ffffffffffffffff81118015613f2f57600080fd5b50604051908082528060200260200182016040528015613f59578160200160208202803683370190505b509250825167ffffffffffffffff81118015613f7457600080fd5b50604051908082528060200260200182016040528015613f9e578160200160208202803683370190505b50915060005b8351811015613ef657613fb782826148a2565b858381518110613fc357fe5b60200260200101858481518110613fd657fe5b60209081029190910101919091526001600160a01b039091169052600101613fa4565b6000614004826127b4565b61400d836127a1565b0192915050565b60008183101561402457816116f2565b5090919050565b600081831061402457816116f2565b6001600160a01b038085166000818152600b602090815260408083209488168084529490915290819020859055517f18e1ea4139e68413d7d08aa752e71568e36b2c5bf940893314c2c5b01eaa0c42906119d0908590615d3e565b6000806140a06148c6565b9050428110156140b45760009150506116f5565b60006140be6148d2565b9050806140d0576000925050506116f5565b6000816140db6149e3565b80516020918201206040516140f7939233918a91899101615dc4565b604051602081830303815290604052805190602001209050600061411a82614a32565b90506000806000614129614a4e565b9250925092506000600185858585604051600081526020016040526040516141549493929190615e1c565b6020604051602081039080840390855afa158015614176573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906141ac57508a6001600160a01b0316816001600160a01b0316145b9b9a5050505050505050505050565b6000806000806141ca86613ff9565b905060006141d786613ff9565b90506141ee6141e5886127ca565b612a3f886127ca565b60a08a01526040517f9d2c110c0000000000000000000000000000000000000000000000000000000081526001600160a01b03891690639d2c110c9061423c908c9086908690600401615e94565b602060405180830381600087803b15801561425657600080fd5b505af115801561426a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061428e9190615968565b92506000806142a68b600001518c6060015187612ff7565b90925090506142b58983614345565b96506142c18882614376565b9550505050509450945094915050565b6000806142e96142e0856127ca565b612a3f856127ca565b90506109e16142f7856127a1565b614300856127a1565b8363ffffffff16614a75565b6001600160a01b03166000908152600291909101602052604090205490565b5490565b6000908152600191820160205260409020015490565b60008061435b83614355866127a1565b90611945565b90506000614368856127b4565b9050436112a6838383614a83565b60008061435b83614386866127a1565b90614abc565b60009182526001928301602052604090912090910155565b600080826001600160a01b0316846001600160a01b0316106143c75782846143ca565b83835b915091509250929050565b600082826040516020016143ea929190615b06565b60405160208183030381529060405280519060200120905092915050565b60006116f2614416846127a1565b61441f846127a1565b614428866127ca565b614a83565b60006116f261443b846127b4565b61441f846127b4565b6001600160a01b038216600090815260028401602052604081205461446b8115158461054b565b614478856001830361432f565b95945050505050565b600061448b6113af565b6001600160a01b03166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b1580156144c357600080fd5b505afa1580156144d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190615968565b610fa0828414801561450c57508183145b606761054b565b6060835167ffffffffffffffff8111801561452d57600080fd5b50604051908082528060200260200182016040528015614557578160200160208202803683370190505b50905060005b85515181101561465057600084828151811061457557fe5b602002602001015190506145a58760200151838151811061459257fe5b60200260200101518210156101f961054b565b6000876000015183815181106145b757fe5b602002602001015190506145d181838b8b60600151611d38565b60008584815181106145df57fe5b602002602001015190506145fb6145f583611b41565b82611f11565b61462a6146088483611945565b89868151811061461457fe5b602002602001015161437690919063ffffffff16565b85858151811061463657fe5b60200260200101818152505050505080600101905061455d565b5095945050505050565b60606000845167ffffffffffffffff8111801561467657600080fd5b506040519080825280602002602001820160405280156146a0578160200160208202803683370190505b50915060005b8651518110156147c65760008582815181106146be57fe5b602002602001015190506146ee886020015183815181106146db57fe5b60200260200101518211156101fa61054b565b60008860000151838151811061470057fe5b6020026020010151905061471a81838c8c60600151611c5a565b61472381611938565b15614735576147328483611945565b93505b600086848151811061474357fe5b602002602001015190506147596145f583611b41565b80831015614778576147738382038a868151811061461457fe5b6147a0565b6147a08184038a868151811061478a57fe5b602002602001015161434590919063ffffffff16565b8685815181106147ac57fe5b6020026020010181815250505050508060010190506146a6565b50614650816119de565b6001600160a01b031660009081526002919091016020526040902054151590565b610e008383614ad284614b0d565b610e008383614ad284614bb8565b610e008383614ad284614c13565b610e008383614c6284614b0d565b610e008383614c6284614bb8565b610e008383614c6284614c13565b60006109e18484614c8385614b0d565b60006109e18484614c8385614bb8565b60006109e18484614c8385614c13565b600082600001828154811061488657fe5b6000918252602090912001546001600160a01b03169392505050565b600090815260019182016020526040902080549101546001600160a01b0390911691565b60006112ce6000614c9d565b6000803560e01c8063b95cac28811461491a57638bdb39138114614942576352bbbe29811461496a5763945bcec981146149925763fa6e671d81146149ba57600092506149de565b7f3f7b71252bd19113ff48c19c6e004a9bcfcca320a0d74d58e85877cbd7dcae5892506149de565b7f8bbc57f66ea936902f50a71ce12b92c43f3c5340bb40c27c4e90ab84eeae335392506149de565b7fe192dcbc143b1e244ad73b813fd3c097b832ad260a157340b4e5e5beda067abe92506149de565b7f9bfc43a4d98313c6766986ffd7c916c7481566d9f224c6819af0a53388aced3a92506149de565b7fa3f865aa351e51cfeb40f5178d1564bb629fe9030b83caf6361d1baaf5b90b5a92505b505090565b60606000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505082519293505050608010156105485760803603815290565b6000614a3c61289b565b8260405160200161112e929190615b2d565b6000806000614a5d6020614c9d565b9250614a696040614c9d565b91506108416060614c9d565b60e01b60709190911b010190565b6000838301614ab1858210801590614aa957506e01000000000000000000000000000082105b61020e61054b565b614478858585614a75565b6000614acc83831115600161054b565b50900390565b600080614ae283614386866127a1565b90506000614af384614355876127b4565b90506000614b00866127ca565b90506112a6838383614a83565b6000806000806000614b1e89613a19565b9450509350935093506000836001600160a01b0316896001600160a01b03161415614b69576000614b5384898b63ffffffff16565b9050614b5f8185614ca7565b9093509050614b8b565b6000614b7983898b63ffffffff16565b9050614b858184614ca7565b90925090505b614b9583836142d1565b8555614ba18383614cc3565b600190950194909455509192505050949350505050565b600080614bc5868661271b565b90506000614bd782858763ffffffff16565b60008881526007602090815260408083206001600160a01b038b16845290915290208190559050614c088183614ca7565b979650505050505050565b600084815260016020526040812081614c2c8287613412565b90506000614c3e82868863ffffffff16565b9050614c4b838883613175565b50614c568183614ca7565b98975050505050505050565b600080614c7283614355866127a1565b90506000614af384614386876127b4565b600080614c8f846127a1565b905043614478828583614a83565b3601607f19013590565b6000614cb2826127b4565b614cbb846127b4565b039392505050565b60006116f2614cd1846127b4565b614cda846127b4565b6000614a75565b60408051610120810190915280600081526000602082018190526040820181905260608083018290526080830182905260a0830182905260c0830182905260e08301919091526101009091015290565b604080516080810190915280600081526000602082018190526040820181905260609091015290565b60405180608001604052806060815260200160608152602001606081526020016000151581525090565b6040518060a0016040528060008019168152602001600081526020016000815260200160008152602001606081525090565b80356116f581615f5a565b600082601f830112614dd1578081fd5b8135614de4614ddf82615f04565b615edd565b818152915060208083019084810181840286018201871015614e0557600080fd5b60005b84811015614e2d578135614e1b81615f5a565b84529282019290820190600101614e08565b505050505092915050565b600082601f830112614e48578081fd5b8135614e56614ddf82615f04565b818152915060208083019084810160005b84811015614e2d578135870160a080601f19838c03011215614e8857600080fd5b614e9181615edd565b85830135815260408084013587830152606080850135828401526080915081850135818401525082840135925067ffffffffffffffff831115614ed357600080fd5b614ee18c8885870101614fc0565b90820152865250509282019290820190600101614e67565b600082601f830112614f09578081fd5b8135614f17614ddf82615f04565b818152915060208083019084810181840286018201871015614f3857600080fd5b60005b84811015614e2d57813584529282019290820190600101614f3b565b600082601f830112614f67578081fd5b8151614f75614ddf82615f04565b818152915060208083019084810181840286018201871015614f9657600080fd5b60005b84811015614e2d57815184529282019290820190600101614f99565b80356116f581615f6f565b600082601f830112614fd0578081fd5b813567ffffffffffffffff811115614fe6578182fd5b614ff9601f8201601f1916602001615edd565b915080825283602082850101111561501057600080fd5b8060208401602084013760009082016020015292915050565b80356116f581615f7d565b8035600281106116f557600080fd5b8035600481106116f557600080fd5b600060808284031215615063578081fd5b61506d6080615edd565b9050813567ffffffffffffffff8082111561508757600080fd5b61509385838601614dc1565b835260208401359150808211156150a957600080fd5b6150b585838601614ef9565b602084015260408401359150808211156150ce57600080fd5b506150db84828501614fc0565b6040830152506150ee8360608401614fb5565b606082015292915050565b60006080828403121561510a578081fd5b6151146080615edd565b9050813561512181615f5a565b8152602082013561513181615f6f565b6020820152604082013561514481615f5a565b604082015260608201356150ee81615f6f565b600060208284031215615168578081fd5b81356116f281615f5a565b60008060408385031215615185578081fd5b823561519081615f5a565b915060208301356151a081615f5a565b809150509250929050565b6000806000606084860312156151bf578081fd5b83356151ca81615f5a565b925060208401356151da81615f5a565b915060408401356151ea81615f6f565b809150509250925092565b60008060408385031215615207578182fd5b823561521281615f5a565b9150602083013567ffffffffffffffff81111561522d578182fd5b61523985828601614dc1565b9150509250929050565b60006020808385031215615255578182fd5b823567ffffffffffffffff81111561526b578283fd5b8301601f8101851361527b578283fd5b8035615289614ddf82615f04565b818152838101908385016080808502860187018a10156152a7578788fd5b8795505b848610156153105780828b0312156152c1578788fd5b6152ca81615edd565b6152d48b84615029565b8152878301358882015260406152ec8c828601614db6565b908201526060838101359082015284526001959095019492860192908101906152ab565b509098975050505050505050565b60006020808385031215615330578182fd5b823567ffffffffffffffff811115615346578283fd5b8301601f81018513615356578283fd5b8035615364614ddf82615f04565b8181528381019083850160a0808502860187018a1015615382578788fd5b8795505b848610156153105780828b03121561539c578788fd5b6153a581615edd565b6153af8b84615043565b81526153bd8b898501614db6565b818901526040838101359082015260606153d98c828601614db6565b9082015260806153eb8c858301614db6565b908201528452600195909501949286019290810190615386565b60008060408385031215615417578182fd5b825167ffffffffffffffff8082111561542e578384fd5b61543a86838701614f57565b9350602085015191508082111561544f578283fd5b5061523985828601614f57565b60006020828403121561546d578081fd5b81356116f281615f6f565b600060208284031215615489578081fd5b81516116f281615f6f565b6000602082840312156154a5578081fd5b5035919050565b600080600080608085870312156154c1578182fd5b8435935060208501356154d381615f5a565b925060408501356154e381615f5a565b9150606085013567ffffffffffffffff8111156154fe578182fd5b61550a87828801615052565b91505092959194509250565b60008060408385031215615528578182fd5b82359150602083013567ffffffffffffffff81111561522d578182fd5b600080600060608486031215615559578081fd5b8335925060208085013567ffffffffffffffff80821115615578578384fd5b61558488838901614dc1565b94506040870135915080821115615599578384fd5b508501601f810187136155aa578283fd5b80356155b8614ddf82615f04565b81815283810190838501858402850186018b10156155d4578687fd5b8694505b838510156155ff5780356155eb81615f5a565b8352600194909401939185019185016155d8565b5080955050505050509250925092565b60008060408385031215615621578182fd5b8235915060208301356151a081615f5a565b600060208284031215615644578081fd5b81356001600160e01b0319811681146116f2578182fd5b60008060008060808587031215615670578182fd5b843561567b81615f5a565b9350602085013567ffffffffffffffff80821115615697578384fd5b6156a388838901614dc1565b945060408701359150808211156156b8578384fd5b6156c488838901614ef9565b935060608701359150808211156156d9578283fd5b5061550a87828801614fc0565b6000602082840312156156f7578081fd5b81356116f281615f7d565b60008060008060e08587031215615717578182fd5b6157218686615034565b9350602085013567ffffffffffffffff8082111561573d578384fd5b61574988838901614e38565b9450604087013591508082111561575e578384fd5b5061576b87828801614dc1565b92505061577b86606087016150f9565b905092959194509250565b600080600080600080610120878903121561579f578384fd5b6157a98888615034565b955060208088013567ffffffffffffffff808211156157c6578687fd5b6157d28b838c01614e38565b975060408a01359150808211156157e7578687fd5b6157f38b838c01614dc1565b96506158028b60608c016150f9565b955060e08a0135915080821115615817578485fd5b508801601f81018a13615828578384fd5b8035615836614ddf82615f04565b81815283810190838501858402850186018e1015615852578788fd5b8794505b83851015615874578035835260019490940193918501918501615856565b50809650505050505061010087013590509295509295509295565b60008060008060e085870312156158a4578182fd5b843567ffffffffffffffff808211156158bb578384fd5b9086019060c082890312156158ce578384fd5b6158d860c0615edd565b823581526158e98960208501615034565b602082015260408301356158fc81615f5a565b604082015261590e8960608501614db6565b60608201526080830135608082015260a08301358281111561592e578586fd5b61593a8a828601614fc0565b60a08301525080965050505061595386602087016150f9565b939693955050505060a08201359160c0013590565b600060208284031215615979578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208085019450808401835b838110156159c55781516001600160a01b0316875295820195908201906001016159a0565b509495945050505050565b6000815180845260208085019450808401835b838110156159c5578151875295820195908201906001016159e3565b60008151808452615a17816020860160208601615f24565b601f01601f19169290920160200192915050565b6000610120825160028110615a3c57fe5b808552506020830151615a526020860182615980565b506040830151615a656040860182615980565b50606083015160608501526080830151608085015260a083015160a085015260c0830151615a9660c0860182615980565b5060e0830151615aa960e0860182615980565b506101008084015182828701526112a6838701826159ff565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b60008251615afc818460208701615f24565b9190910192915050565b6bffffffffffffffffffffffff19606093841b811682529190921b16601482015260280190565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038316815260408101615bb483615f50565b8260208301529392505050565b6001600160a01b03929092168252602082015260400190565b6000602082526116f2602083018461598d565b600060408252615c00604083018561598d565b828103602084810191909152845180835285820192820190845b81811015615c3f5784516001600160a01b031683529383019391830191600101615c1a565b5090979650505050505050565b600060608252615c5f606083018661598d565b8281036020840152615c7181866159d0565b905082810360408401526112a681856159d0565b600060808252615c98608083018761598d565b8281036020840152615caa81876159d0565b90508281036040840152615cbe81866159d0565b90508281036060840152614c0881856159ff565b600060608252615ce5606083018661598d565b8281036020840152615cf781866159d0565b915050826040830152949350505050565b6000602082526116f260208301846159d0565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60008882526001600160a01b03808916602084015280881660408401525060e06060830152615d9860e08301876159d0565b8560808401528460a084015282810360c0840152615db681856159ff565b9a9950505050505050505050565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b60208101615e4783615f50565b91905290565b918252602082015260400190565b600060808252615e6e6080830187615a2b565b8281036020840152615e8081876159d0565b604084019590955250506060015292915050565b600060608252615ea76060830186615a2b565b60208301949094525060400152919050565b938452602084019290925260408301526001600160a01b0316606082015260800190565b60405181810167ffffffffffffffff81118282101715615efc57600080fd5b604052919050565b600067ffffffffffffffff821115615f1a578081fd5b5060209081020190565b60005b83811015615f3f578181015183820152602001615f27565b83811115610e005750506000910152565b6003811061057e57fe5b6001600160a01b038116811461057e57600080fd5b801515811461057e57600080fd5b6003811061057e57600080fdfea2646970667358221220201e4f926e390fed8dd5318c58846af735c2bebc61b80693ae936a5fe76dcf1464736f6c6343000701003360c060405234801561001057600080fd5b50604051610be6380380610be683398101604081905261002f9161004d565b30608052600160005560601b6001600160601b03191660a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160a05160601c610b406100a66000398061041352806105495250806102a75250610b406000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063851c1bb311610076578063d877845c1161005b578063d877845c14610129578063e42abf3514610131578063fbfa77cf14610151576100a3565b8063851c1bb314610101578063aaabadc514610114576100a3565b806338e9922e146100a857806355c67628146100bd5780636b6b9f69146100db5780636daefab6146100ee575b600080fd5b6100bb6100b636600461099c565b610159565b005b6100c56101b8565b6040516100d29190610aa6565b60405180910390f35b6100bb6100e936600461099c565b6101be565b6100bb6100fc3660046107d1565b610211565b6100c561010f366004610924565b6102a3565b61011c6102f5565b6040516100d29190610a35565b6100c5610304565b61014461013f366004610852565b61030a565b6040516100d29190610a62565b61011c610411565b610161610435565b6101786706f05b59d3b2000082111561025861047e565b60018190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc906101ad908390610aa6565b60405180910390a150565b60015490565b6101c6610435565b6101dc662386f26fc1000082111561025961047e565b60028190556040517f5a0b7386237e7f07fa741efc64e59c9387d2cccafec760efed4d53387f20e19a906101ad908390610aa6565b610219610490565b610221610435565b61022b84836104a9565b60005b8481101561029357600086868381811061024457fe5b90506020020160208101906102599190610980565b9050600085858481811061026957fe5b6020029190910135915061028990506001600160a01b03831685836104b6565b505060010161022e565b5061029c61053e565b5050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016102d89291906109cc565b604051602081830303815290604052805190602001209050919050565b60006102ff610545565b905090565b60025490565b6060815167ffffffffffffffff8111801561032457600080fd5b5060405190808252806020026020018201604052801561034e578160200160208202803683370190505b50905060005b825181101561040b5782818151811061036957fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161039c9190610a35565b60206040518083038186803b1580156103b457600080fd5b505afa1580156103c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ec91906109b4565b8282815181106103f857fe5b6020908102919091010152600101610354565b50919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006104646000357fffffffff00000000000000000000000000000000000000000000000000000000166102a3565b905061047b61047382336105d8565b61019161047e565b50565b8161048c5761048c8161066a565b5050565b6104a26002600054141561019061047e565b6002600055565b61048c818314606761047e565b6105398363a9059cbb60e01b84846040516024016104d5929190610a49565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526106d7565b505050565b6001600055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b1580156105a057600080fd5b505afa1580156105b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ff9190610964565b60006105e2610545565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b815260040161061193929190610aaf565b60206040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066191906108fd565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006060836001600160a01b0316836040516106f391906109fc565b6000604051808303816000865af19150503d8060008114610730576040519150601f19603f3d011682016040523d82523d6000602084013e610735565b606091505b5091509150600082141561074d573d6000803e3d6000fd5b61077781516000148061076f57508180602001905181019061076f91906108fd565b6101a261047e565b50505050565b60008083601f84011261078e578182fd5b50813567ffffffffffffffff8111156107a5578182fd5b60208301915083602080830285010111156107bf57600080fd5b9250929050565b803561066481610af5565b6000806000806000606086880312156107e8578081fd5b853567ffffffffffffffff808211156107ff578283fd5b61080b89838a0161077d565b90975095506020880135915080821115610823578283fd5b506108308882890161077d565b909450925050604086013561084481610af5565b809150509295509295909350565b60006020808385031215610864578182fd5b823567ffffffffffffffff8082111561087b578384fd5b818501915085601f83011261088e578384fd5b81358181111561089c578485fd5b83810291506108ac848301610ace565b8181528481019084860184860187018a10156108c6578788fd5b8795505b838610156108f0576108dc8a826107c6565b8352600195909501949186019186016108ca565b5098975050505050505050565b60006020828403121561090e578081fd5b8151801515811461091d578182fd5b9392505050565b600060208284031215610935578081fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461091d578182fd5b600060208284031215610975578081fd5b815161091d81610af5565b600060208284031215610991578081fd5b813561091d81610af5565b6000602082840312156109ad578081fd5b5035919050565b6000602082840312156109c5578081fd5b5051919050565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260240190565b60008251815b81811015610a1c5760208186018101518583015201610a02565b81811115610a2a5782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015610a9a57835183529284019291840191600101610a7e565b50909695505050505050565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60405181810167ffffffffffffffff81118282101715610aed57600080fd5b604052919050565b6001600160a01b038116811461047b57600080fdfea2646970667358221220be72bdf8e7a3c38606c5f954fbe2d77798347aaa1cfb76fe77ec2f6c245d24bc64736f6c63430007010033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01\x80`@R4\x80\x15b\0\0\x12W`\0\x80\xFD[P`@Qb\0n\xD68\x03\x80b\0n\xD6\x839\x81\x01`@\x81\x90Rb\0\x005\x91b\0\x02SV[\x83\x82\x82`@Q\x80`@\x01`@R\x80`\x11\x81R` \x01p\x10\x98[\x18[\x98\xD9\\\x88\x15\x8C\x88\x15\x98][\x1D`z\x1B\x81RP\x80`@Q\x80`@\x01`@R\x80`\x01\x81R` \x01`1`\xF8\x1B\x81RP0`\x01`\x01`\xA0\x1B\x03\x16`\0\x1B\x89\x80`\x01`\x01`\xA0\x1B\x03\x16`\x80\x81`\x01`\x01`\xA0\x1B\x03\x16``\x1B\x81RPPP0`@Qb\0\0\xB8\x90b\0\x02EV[b\0\0\xC4\x91\x90b\0\x02\x9FV[`@Q\x80\x91\x03\x90`\0\xF0\x80\x15\x80\x15b\0\0\xE1W=`\0\x80>=`\0\xFD[P``\x1B`\x01`\x01``\x1B\x03\x19\x16`\xA0R`\x01`\0U`\xC0R\x81Q` \x92\x83\x01 `\xE0R\x80Q\x91\x01 a\x01\0RP\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0Fa\x01 Rb\0\x01Hbv\xA7\0\x83\x11\x15a\x01\x94b\0\x01\x81V[b\0\x01\\b'\x8D\0\x82\x11\x15a\x01\x95b\0\x01\x81V[B\x90\x91\x01a\x01@\x81\x90R\x01a\x01`Rb\0\x01v\x81b\0\x01\x96V[PPPPPb\0\x02\xCCV[\x81b\0\x01\x92Wb\0\x01\x92\x81b\0\x01\xF2V[PPV[`@Q`\x01`\x01`\xA0\x1B\x03\x82\x16\x90\x7F\x94\xB9y\xB6\x83\x1AQ)>&ABo\x97t\x7F\xEE\xD4o\x17w\x9F\xED\x9C\xD1\x8D\x1E\xCE\xFC\xFE\x92\xEF\x90`\0\x90\xA2`\x03\x80T`\x01`\x01`\xA0\x1B\x03\x90\x92\x16a\x01\0\x02a\x01\0`\x01`\xA8\x1B\x03\x19\x90\x92\x16\x91\x90\x91\x17\x90UV[bF\x1B\xCD`\xE5\x1B`\0\x90\x81R` `\x04R`\x07`$RfBAL#\0\x000`\n\x80\x84\x04\x81\x81\x06`0\x90\x81\x01`\x08\x1B\x95\x83\x90\x06\x95\x90\x95\x01\x90\x82\x90\x04\x91\x82\x06\x90\x94\x01`\x10\x1B\x93\x90\x93\x01\x01`\xC8\x1B`DR`d\x90\xFD[a\x0B\xE6\x80b\0b\xF0\x839\x01\x90V[`\0\x80`\0\x80`\x80\x85\x87\x03\x12\x15b\0\x02iW\x83\x84\xFD[\x84Qb\0\x02v\x81b\0\x02\xB3V[` \x86\x01Q\x90\x94Pb\0\x02\x89\x81b\0\x02\xB3V[`@\x86\x01Q``\x90\x96\x01Q\x94\x97\x90\x96P\x92PPPV[`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x81R` \x01\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x02\xC9W`\0\x80\xFD[PV[`\x80Q``\x1C`\xA0Q``\x1C`\xC0Q`\xE0Qa\x01\0Qa\x01 Qa\x01@Qa\x01`Qa_\xC0b\0\x030`\09\x80a\x1A\xEDRP\x80a\x1A\xC9RP\x80a(\x9FRP\x80a(\xE1RP\x80a(\xC0RP\x80a\x10\xFDRP\x80a\x13\xB1RP\x80a\x05(RPa_\xC0`\0\xF3\xFE`\x80`@R`\x046\x10a\x01\xA5W`\x005`\xE0\x1C\x80c\x94[\xCE\xC9\x11a\0\xE1W\x80c\xE6\xC4`\x92\x11a\0\x8AW\x80c\xF8M\x06n\x11a\0dW\x80c\xF8M\x06n\x14a\x04\x8AW\x80c\xF9MFh\x14a\x04\xAAW\x80c\xFAng\x1D\x14a\x04\xD9W\x80c\xFE\xC9\rr\x14a\x04\xF9Wa\x01\xD3V[\x80c\xE6\xC4`\x92\x14a\x04'W\x80c\xED$\x91\x1D\x14a\x04GW\x80c\xF6\xC0\t'\x14a\x04\\Wa\x01\xD3V[\x80c\xB0_\x8EH\x11a\0\xBBW\x80c\xB0_\x8EH\x14a\x03\xCFW\x80c\xB9\\\xAC(\x14a\x03\xFFW\x80c\xD2\x94l+\x14a\x04\x12Wa\x01\xD3V[\x80c\x94[\xCE\xC9\x14a\x03\x85W\x80c\xAA\xAB\xAD\xC5\x14a\x03\x98W\x80c\xAD\\FH\x14a\x03\xBAWa\x01\xD3V[\x80cR\xBB\xBE)\x11a\x01NW\x80c}:\xEB\x96\x11a\x01(W\x80c}:\xEB\x96\x14a\x03\x05W\x80c\x85\x1C\x1B\xB3\x14a\x03%W\x80c\x8B\xDB9\x13\x14a\x03EW\x80c\x90\x19;|\x14a\x03eWa\x01\xD3V[\x80cR\xBB\xBE)\x14a\x02\xB2W\x80c\\8D\x9E\x14a\x02\xC5W\x80cf\xA9\xC7\xD2\x14a\x02\xE5Wa\x01\xD3V[\x80c\x0FZn\xFA\x11a\x01\x7FW\x80c\x0FZn\xFA\x14a\x02AW\x80c\x16\xC3\x8B<\x14a\x02nW\x80c\x1C\r\xE0Q\x14a\x02\x8EWa\x01\xD3V[\x80c\x05\x8Ab\x8F\x14a\x01\xD8W\x80c\t\xB2v\x0F\x14a\x01\xF8W\x80c\x0E\x8E>\x84\x14a\x02.Wa\x01\xD3V[6a\x01\xD3Wa\x01\xD1a\x01\xB5a\x05&V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14a\x02\x06a\x05KV[\0[`\0\x80\xFD[4\x80\x15a\x01\xE4W`\0\x80\xFD[Pa\x01\xD1a\x01\xF36`\x04aQWV[a\x05]V[4\x80\x15a\x02\x04W`\0\x80\xFD[Pa\x02\x18a\x02\x136`\x04aV\xE6V[a\x05\x81V[`@Qa\x02%\x91\x90a]>V[`@Q\x80\x91\x03\x90\xF3[a\x01\xD1a\x02<6`\x04aS\x1EV[a\x064V[4\x80\x15a\x02MW`\0\x80\xFD[Pa\x02aa\x02\\6`\x04aQ\xF5V[a\x07pV[`@Qa\x02%\x91\x90a]\x08V[4\x80\x15a\x02zW`\0\x80\xFD[Pa\x01\xD1a\x02\x896`\x04aT\\V[a\x08\x06V[4\x80\x15a\x02\x9AW`\0\x80\xFD[Pa\x02\xA3a\x08\x1FV[`@Qa\x02%\x93\x92\x91\x90a]&V[a\x02\x18a\x02\xC06`\x04aX\x8FV[a\x08HV[4\x80\x15a\x02\xD1W`\0\x80\xFD[Pa\x01\xD1a\x02\xE06`\x04aV[V[a\t\xE9V[4\x80\x15a\x02\xF1W`\0\x80\xFD[Pa\x01\xD1a\x03\x006`\x04aUEV[a\x0E\x06V[4\x80\x15a\x03\x11W`\0\x80\xFD[Pa\x01\xD1a\x03 6`\x04aU\x16V[a\x0F\xA5V[4\x80\x15a\x031W`\0\x80\xFD[Pa\x02\x18a\x03@6`\x04aV3V[a\x10\xF9V[4\x80\x15a\x03QW`\0\x80\xFD[Pa\x01\xD1a\x03`6`\x04aT\xACV[a\x11KV[4\x80\x15a\x03qW`\0\x80\xFD[Pa\x02\x18a\x03\x806`\x04aQWV[a\x11aV[a\x02aa\x03\x936`\x04aW\x86V[a\x11|V[4\x80\x15a\x03\xA4W`\0\x80\xFD[Pa\x03\xADa\x12\xB0V[`@Qa\x02%\x91\x90a[cV[4\x80\x15a\x03\xC6W`\0\x80\xFD[Pa\x03\xADa\x12\xC4V[4\x80\x15a\x03\xDBW`\0\x80\xFD[Pa\x03\xEFa\x03\xEA6`\x04aV\x0FV[a\x12\xD3V[`@Qa\x02%\x94\x93\x92\x91\x90a^\xB9V[a\x01\xD1a\x04\r6`\x04aT\xACV[a\x13\x96V[4\x80\x15a\x04\x1EW`\0\x80\xFD[Pa\x03\xADa\x13\xAFV[4\x80\x15a\x043W`\0\x80\xFD[Pa\x01\xD1a\x04B6`\x04aRCV[a\x13\xD3V[4\x80\x15a\x04SW`\0\x80\xFD[Pa\x02\x18a\x14\xEFV[4\x80\x15a\x04hW`\0\x80\xFD[Pa\x04|a\x04w6`\x04aT\x94V[a\x14\xF9V[`@Qa\x02%\x92\x91\x90a[\x9BV[4\x80\x15a\x04\x96W`\0\x80\xFD[Pa\x02aa\x04\xA56`\x04aW\x02V[a\x15#V[4\x80\x15a\x04\xB6W`\0\x80\xFD[Pa\x04\xCAa\x04\xC56`\x04aT\x94V[a\x16 V[`@Qa\x02%\x93\x92\x91\x90a\\\xD2V[4\x80\x15a\x04\xE5W`\0\x80\xFD[Pa\x01\xD1a\x04\xF46`\x04aQ\xABV[a\x16TV[4\x80\x15a\x05\x05W`\0\x80\xFD[Pa\x05\x19a\x05\x146`\x04aQsV[a\x16\xE6V[`@Qa\x02%\x91\x90a]\x1BV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0[\x90V[\x81a\x05YWa\x05Y\x81a\x16\xFBV[PPV[a\x05ea\x17hV[a\x05ma\x17\x81V[a\x05v\x81a\x17\xAFV[a\x05~a\x18\"V[PV[`\0a\x05\x8Ba\x17hV[a\x05\x93a\x18)V[`\0a\x05\xA23\x84`\x06Ta\x18>V[`\0\x81\x81R`\x05` R`@\x90 T\x90\x91Pa\x05\xC4\x90`\xFF\x16\x15a\x01\xF4a\x05KV[`\0\x81\x81R`\x05` R`@\x90\x81\x90 \x80T`\xFF\x19\x16`\x01\x90\x81\x17\x90\x91U`\x06\x80T\x90\x91\x01\x90UQ3\x90\x82\x90\x7F<\x13\xBC0\xB8\xE8x\xC5?\xD2\xA3kg\x94\t\xC0s\xAF\xD7YP\xBEC\xD8\x85\x87h\xE9V\xFB\xC2\x0E\x90a\x06\x1D\x90\x87\x90a^:V[`@Q\x80\x91\x03\x90\xA3\x90Pa\x06/a\x18\"V[\x91\x90PV[a\x06=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0B\x90\x91\x90aYhV[\x85\x84\x81Q\x81\x10a\x0B\x9CW\xFE[` \x02` \x01\x01\x81\x81RPPa\x0B\xB1\x81a\x1E\x1FV[\x86\x84\x81Q\x81\x10a\x0B\xBDW\xFE[` \x02` \x01\x01\x81\x81RPPa\x0B\xEB\x81\x86\x85\x81Q\x81\x10a\x0B\xD9W\xFE[` \x02` \x01\x01Q\x10\x15a\x02\x10a\x05KV[a\x0B\xFF`\x01`\x01`\xA0\x1B\x03\x83\x16\x8B\x83a\x1E\xA6V[PP`\x01\x01a\n\x97V[P`@Q\x7F\xF0O'\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x88\x16\x90c\xF0O'\x07\x90a\x0CU\x90\x89\x90\x89\x90\x88\x90\x8A\x90`\x04\x01a\\\x85V[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x0CoW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x0C\x83W=`\0\x80>=`\0\xFD[PPPP`\0[\x86Q\x81\x10\x15a\r\xF4W`\0\x87\x82\x81Q\x81\x10a\x0C\xA1W\xFE[` \x02` \x01\x01Q\x90P`\0\x84\x83\x81Q\x81\x10a\x0C\xB9W\xFE[` \x02` \x01\x01Q\x90P`\0\x82`\x01`\x01`\xA0\x1B\x03\x16cp\xA0\x8210`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x0C\xF1\x91\x90a[cV[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\r\tW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\r\x1DW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\rA\x91\x90aYhV[\x90Pa\rR\x82\x82\x10\x15a\x02\x03a\x05KV[`\0\x82\x82\x03\x90Pa\r{\x88\x86\x81Q\x81\x10a\rhW\xFE[` \x02` \x01\x01Q\x82\x10\x15a\x02Za\x05KV[a\r\x85\x84\x82a\x1F\x11V[\x83`\x01`\x01`\xA0\x1B\x03\x16\x8C`\x01`\x01`\xA0\x1B\x03\x16\x7F\r}u\xE0\x1A\xB9W\x80\xD3\xCD\x1C\x8E\xC0\xDDl,\xE1\x9E: B~\xEC\x8B\xF52\x83\xB6\xFB\x8E\x95\xF0\x8C\x88\x81Q\x81\x10a\r\xC6W\xFE[` \x02` \x01\x01Q\x84`@Qa\r\xDD\x92\x91\x90a^MV[`@Q\x80\x91\x03\x90\xA3PPPP\x80`\x01\x01\x90Pa\x0C\x8AV[PPPPa\x0E\0a\x18\"V[PPPPV[a\x0E\x0Ea\x17hV[a\x0E\x16a\x18)V[\x82a\x0E \x81a\x1F3V[a\x0E,\x83Q\x83Qa\x1E\x12V[`\0[\x83Q\x81\x10\x15a\x0E\xCAW`\0\x84\x82\x81Q\x81\x10a\x0EFW\xFE[` \x02` \x01\x01Q\x90Pa\x0Er`\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x015a\x05KV[\x83\x82\x81Q\x81\x10a\x0E~W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`\0\x88\x81R`\n\x83R`@\x80\x82 `\x01`\x01`\xA0\x1B\x03\x95\x86\x16\x83R\x90\x93R\x91\x90\x91 \x80T`\x01`\x01`\xA0\x1B\x03\x19\x16\x92\x90\x91\x16\x91\x90\x91\x17\x90U`\x01\x01a\x0E/V[P`\0a\x0E\xD6\x85a\x1FdV[\x90P`\x02\x81`\x02\x81\x11\x15a\x0E\xE6W\xFE[\x14\x15a\x0F4Wa\x0E\xFC\x84Q`\x02\x14a\x02\x0Ca\x05KV[a\x0F/\x85\x85`\0\x81Q\x81\x10a\x0F\rW\xFE[` \x02` \x01\x01Q\x86`\x01\x81Q\x81\x10a\x0F\"W\xFE[` \x02` \x01\x01Qa\x1F~V[a\x0F\\V[`\x01\x81`\x02\x81\x11\x15a\x0FBW\xFE[\x14\x15a\x0FRWa\x0F/\x85\x85a *V[a\x0F\\\x85\x85a \x82V[\x84\x7F\xF5\x84}?!\x97\xB1l\xDC\xD2\t\x8E\xC9]\t\x05\xCD\x1A\xBD\xAFA_\x07\xBB|\xEF+\xBA\x8A\xC5\xDE\xC4\x85\x85`@Qa\x0F\x8E\x92\x91\x90a[\xEDV[`@Q\x80\x91\x03\x90\xA2PPa\x0F\xA0a\x18\"V[PPPV[a\x0F\xADa\x17hV[a\x0F\xB5a\x18)V[\x81a\x0F\xBF\x81a\x1F3V[`\0a\x0F\xCA\x84a\x1FdV[\x90P`\x02\x81`\x02\x81\x11\x15a\x0F\xDAW\xFE[\x14\x15a\x10(Wa\x0F\xF0\x83Q`\x02\x14a\x02\x0Ca\x05KV[a\x10#\x84\x84`\0\x81Q\x81\x10a\x10\x01W\xFE[` \x02` \x01\x01Q\x85`\x01\x81Q\x81\x10a\x10\x16W\xFE[` \x02` \x01\x01Qa \xD7V[a\x10PV[`\x01\x81`\x02\x81\x11\x15a\x106W\xFE[\x14\x15a\x10FWa\x10#\x84\x84a!EV[a\x10P\x84\x84a!\xFFV[`\0[\x83Q\x81\x10\x15a\x10\xB6W`\n`\0\x86\x81R` \x01\x90\x81R` \x01`\0 `\0\x85\x83\x81Q\x81\x10a\x10}W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`\x01`\x01`\xA0\x1B\x03\x16\x82R\x81\x01\x91\x90\x91R`@\x01`\0 \x80T`\x01`\x01`\xA0\x1B\x03\x19\x16\x90U`\x01\x01a\x10SV[P\x83\x7F}\xCD\xC6\xD0.\xF4\x0C|\x1ApF\xA0\x11\xB0X\xBD\x7F\x98\x8F\xA1N \xA6cD\xF9\xD4\xE6\x06W\xD6\x10\x84`@Qa\x10\xE7\x91\x90a[\xDAV[`@Q\x80\x91\x03\x90\xA2PPa\x05Ya\x18\"V[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82`@Q` \x01a\x11.\x92\x91\x90aZ\xC2V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x0E\0`\x01\x85\x85\x85a\x11\\\x86a\"bV[a\"nV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R`\x02` R`@\x90 T\x90V[``a\x11\x86a\x17hV[a\x11\x8Ea\x18)V[\x83Qa\x11\x99\x81a\x1B\x0FV[a\x11\xA8\x83B\x11\x15a\x01\xFCa\x05KV[a\x11\xB4\x86Q\x85Qa\x1E\x12V[a\x11\xC0\x87\x87\x87\x8Ba#\xF4V[\x91P`\0\x80[\x87Q\x81\x10\x15a\x12\x92W`\0\x88\x82\x81Q\x81\x10a\x11\xDDW\xFE[` \x02` \x01\x01Q\x90P`\0\x85\x83\x81Q\x81\x10a\x11\xF5W\xFE[` \x02` \x01\x01Q\x90Pa\x12!\x88\x84\x81Q\x81\x10a\x12\x0EW\xFE[` \x02` \x01\x01Q\x82\x13\x15a\x01\xFBa\x05KV[`\0\x81\x13\x15a\x12aW\x88Q` \x8A\x01Q\x82\x91a\x12@\x91\x85\x91\x84\x91a\x1CZV[a\x12I\x83a\x198V[\x15a\x12[Wa\x12X\x85\x82a\x19EV[\x94P[Pa\x12\x88V[`\0\x81\x12\x15a\x12\x88W`\0\x81`\0\x03\x90Pa\x12\x86\x83\x82\x8C`@\x01Q\x8D``\x01Qa\x1D8V[P[PP`\x01\x01a\x11\xC6V[Pa\x12\x9C\x81a\x19\xDEV[PPa\x12\xA6a\x18\"V[\x96\x95PPPPPPV[`\x03Ta\x01\0\x90\x04`\x01`\x01`\xA0\x1B\x03\x16\x90V[`\0a\x12\xCEa\x05&V[\x90P\x90V[`\0\x80`\0\x80\x85a\x12\xE3\x81a&\x83V[`\0\x80a\x12\xEF\x89a\x1FdV[\x90P`\x02\x81`\x02\x81\x11\x15a\x12\xFFW\xFE[\x14\x15a\x13\x16Wa\x13\x0F\x89\x89a&\xA1V[\x91Pa\x13AV[`\x01\x81`\x02\x81\x11\x15a\x13$W\xFE[\x14\x15a\x134Wa\x13\x0F\x89\x89a'\x1BV[a\x13>\x89\x89a'\x89V[\x91P[a\x13J\x82a'\xA1V[\x96Pa\x13U\x82a'\xB4V[\x95Pa\x13`\x82a'\xCAV[`\0\x99\x8AR`\n` \x90\x81R`@\x80\x8C `\x01`\x01`\xA0\x1B\x03\x9B\x8C\x16\x8DR\x90\x91R\x90\x99 T\x96\x99\x95\x98\x97\x96\x90\x96\x16\x95PPPPPV[a\x13\x9Ea\x18)V[a\x0E\0`\0\x85\x85\x85a\x11\\\x86a\"bV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[a\x13\xDBa\x17hV[a\x13\xE3a\x18)V[a\x13\xEBaM1V[`\0[\x82Q\x81\x10\x15a\x14\xE5W\x82\x81\x81Q\x81\x10a\x14\x03W\xFE[` \x02` \x01\x01Q\x91P`\0\x82` \x01Q\x90Pa\x14\x1F\x81a&\x83V[`@\x83\x01Qa\x149a\x141\x83\x83a'\xD0V[a\x02\ta\x05KV[`\0\x82\x81R`\n` \x90\x81R`@\x80\x83 `\x01`\x01`\xA0\x1B\x03\x85\x81\x16\x85R\x92R\x90\x91 Ta\x14l\x91\x163\x14a\x01\xF6a\x05KV[\x83Q``\x85\x01Q`\0\x80a\x14\x82\x84\x87\x87\x86a(,V[\x91P\x91P\x84`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x87\x7Fn\xDC\xAFbA\x10[L\x94\xC2\xEF\xDB\xF3\xA6\xB1$X\xEB=\x07\xBE:\x0E\x81\xD2K\x13\xC4@E\xFEz\x85\x85`@Qa\x14\xCC\x92\x91\x90a^MV[`@Q\x80\x91\x03\x90\xA4PPPPPP\x80`\x01\x01\x90Pa\x13\xEEV[PPa\x05~a\x18\"V[`\0a\x12\xCEa(\x9BV[`\0\x80\x82a\x15\x06\x81a&\x83V[a\x15\x0F\x84a)8V[a\x15\x18\x85a\x1FdV[\x92P\x92P[P\x91P\x91V[``30\x14a\x15\xF6W`\x000`\x01`\x01`\xA0\x1B\x03\x16`\x006`@Qa\x15I\x92\x91\x90aZ\xDAV[`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x15\x86W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x15\x8BV[``\x91P[PP\x90P\x80`\0\x81\x14a\x15\x9AW\xFE[`\x04`\0\x80>`\0Q`\x01`\x01`\xE0\x1B\x03\x19\x16\x7F\xFAa\xCC\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x14a\x15\xDEW=`\0\x80>=`\0\xFD[P` `\0R`\x04=\x03\x80`\x04` >` \x81\x01`\0\xF3[``a\x16\x04\x85\x85\x85\x89a#\xF4V[\x90P` \x81Q\x02c\xFAa\xCC\x12` \x83\x03R`\x04\x82\x03`$\x82\x01\x81\xFD[``\x80`\0\x83a\x16/\x81a&\x83V[``a\x16:\x86a)>V[\x90\x95P\x90Pa\x16H\x81a)\xA0V[\x95\x97\x90\x96P\x93PPPPV[a\x16\\a\x17hV[a\x16da\x18)V[\x82a\x16n\x81a\x1B\x0FV[`\x01`\x01`\xA0\x1B\x03\x84\x81\x16`\0\x81\x81R`\x04` \x90\x81R`@\x80\x83 \x94\x88\x16\x80\x84R\x94\x90\x91R\x90\x81\x90 \x80T`\xFF\x19\x16\x86\x15\x15\x17\x90UQ\x90\x91\x90\x7FF\x96\x1F\xDBE\x02\xB6F\xD5\t_\xBAv\0Hj\x8A\xC0PA\xD5\\\xDF\x0F\x16\xEDgq\x80\xB5\xCA\xD8\x90a\x16\xD5\x90\x86\x90a]\x1BV[`@Q\x80\x91\x03\x90\xA3Pa\x0F\xA0a\x18\"V[`\0a\x16\xF2\x83\x83a*OV[\x90P[\x92\x91PPV[\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\x90\x81R` `\x04R`\x07`$RfBAL#\0\x000`\n\x80\x84\x04\x81\x81\x06`0\x90\x81\x01`\x08\x1B\x95\x83\x90\x06\x95\x90\x95\x01\x90\x82\x90\x04\x91\x82\x06\x90\x94\x01`\x10\x1B\x93\x90\x93\x01\x01`\xC8\x1B`DR`d\x90\xFD[a\x17z`\x02`\0T\x14\x15a\x01\x90a\x05KV[`\x02`\0UV[`\0a\x17\x98`\x005`\x01`\x01`\xE0\x1B\x03\x19\x16a\x10\xF9V[\x90Pa\x05~a\x17\xA7\x823a*}V[a\x01\x91a\x05KV[`@Q`\x01`\x01`\xA0\x1B\x03\x82\x16\x90\x7F\x94\xB9y\xB6\x83\x1AQ)>&ABo\x97t\x7F\xEE\xD4o\x17w\x9F\xED\x9C\xD1\x8D\x1E\xCE\xFC\xFE\x92\xEF\x90`\0\x90\xA2`\x03\x80T`\x01`\x01`\xA0\x1B\x03\x90\x92\x16a\x01\0\x02\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xFF\x90\x92\x16\x91\x90\x91\x17\x90UV[`\x01`\0UV[a\x18=`\0\xFD[PPPPPa\x0E\0V[`\0a\x1C\xF9\x85a\x05HV[\x90P\x81\x15a\x1D\x16W`\0a\x1D\x10\x84\x83\x87`\x01a+ V[\x90\x94\x03\x93P[\x83\x15a\x1D1Wa\x1D1`\x01`\x01`\xA0\x1B\x03\x82\x16\x840\x87a+\xA6V[PPPPPV[\x82a\x1DBWa\x0E\0V[a\x1DK\x84a\x198V[\x15a\x1D\xDBWa\x1D]\x81\x15a\x02\x02a\x05KV[a\x1Dea\x05&V[`\x01`\x01`\xA0\x1B\x03\x16c.\x1A}M\x84`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x1D\x90\x91\x90a]>V[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x1D\xAAW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x1D\xBEW=`\0\x80>=`\0\xFD[Pa\x1D\xD6\x92PPP`\x01`\x01`\xA0\x1B\x03\x83\x16\x84a+\xC7V[a\x0E\0V[`\0a\x1D\xE6\x85a\x05HV[\x90P\x81\x15a\x1D\xFEWa\x1D\xF9\x83\x82\x86a+vV[a\x1D1V[a\x1D1`\x01`\x01`\xA0\x1B\x03\x82\x16\x84\x86a\x1E\xA6V[a\x05Y\x81\x83\x14`ga\x05KV[`\0\x80a\x1E*a\x13\xAFV[`\x01`\x01`\xA0\x1B\x03\x16c\xD8w\x84\\`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1EbW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1EvW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x1E\x9A\x91\x90aYhV[\x90Pa\x18v\x83\x82a0%V[a\x0F\xA0\x83c\xA9\x05\x9C\xBB`\xE0\x1B\x84\x84`@Q`$\x01a\x1E\xC5\x92\x91\x90a[\xC1V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x01`\x01`\xE0\x1B\x03\x19\x90\x93\x16\x92\x90\x92\x17\x90\x91Ra0rV[\x80\x15a\x05YWa\x05Ya\x1F\"a\x13\xAFV[`\x01`\x01`\xA0\x1B\x03\x84\x16\x90\x83a\x1E\xA6V[a\x1F<\x81a&\x83V[a\x05~a\x1FH\x82a)8V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14a\x01\xF5a\x05KV[`\0a\xFF\xFF`P\x83\x90\x1C\x16a\x16\xF5`\x03\x82\x10a\x01\xF4a\x05KV[a\x1F\x9F\x81`\x01`\x01`\xA0\x1B\x03\x16\x83`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x02\na\x05KV[a\x1F\xBE\x81`\x01`\x01`\xA0\x1B\x03\x16\x83`\x01`\x01`\xA0\x1B\x03\x16\x10`fa\x05KV[`\0\x83\x81R`\t` R`@\x90 \x80Ta\x1F\xFB\x90`\x01`\x01`\xA0\x1B\x03\x16\x15\x80\x15a\x1F\xF3WP`\x01\x82\x01T`\x01`\x01`\xA0\x1B\x03\x16\x15[a\x02\x0Ba\x05KV[\x80T`\x01`\x01`\xA0\x1B\x03\x93\x84\x16`\x01`\x01`\xA0\x1B\x03\x19\x91\x82\x16\x17\x82U`\x01\x90\x91\x01\x80T\x92\x90\x93\x16\x91\x16\x17\x90UPV[`\0\x82\x81R`\x08` R`@\x81 \x90[\x82Q\x81\x10\x15a\x0E\0W`\0a k\x84\x83\x81Q\x81\x10a TW\xFE[` \x02` \x01\x01Q\x84a1\x12\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90Pa y\x81a\x02\na\x05KV[P`\x01\x01a :V[`\0\x82\x81R`\x01` R`@\x81 \x90[\x82Q\x81\x10\x15a\x0E\0W`\0a \xC0\x84\x83\x81Q\x81\x10a \xACW\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01Q\x84\x90`\0a1uV[\x90Pa \xCE\x81a\x02\na\x05KV[P`\x01\x01a \x92V[`\0\x80`\0a \xE7\x86\x86\x86a2\"V[\x92P\x92P\x92Pa!\x11a \xF9\x84a2\xE9V[\x80\x15a!\tWPa!\t\x83a2\xE9V[a\x02\ra\x05KV[`\0\x95\x86R`\t` R`@\x86 \x80T`\x01`\x01`\xA0\x1B\x03\x19\x90\x81\x16\x82U`\x01\x90\x91\x01\x80T\x90\x91\x16\x90U\x94\x90\x94UPPPPV[`\0\x82\x81R`\x08` R`@\x81 \x90[\x82Q\x81\x10\x15a\x0E\0W`\0\x83\x82\x81Q\x81\x10a!lW\xFE[` \x02` \x01\x01Q\x90Pa!\xB8a!\t`\x07`\0\x88\x81R` \x01\x90\x81R` \x01`\0 `\0\x84`\x01`\x01`\xA0\x1B\x03\x16`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x90\x81R` \x01`\0 Ta2\xE9V[`\0\x85\x81R`\x07` \x90\x81R`@\x80\x83 `\x01`\x01`\xA0\x1B\x03\x85\x16\x84R\x90\x91R\x81 \x81\x90Ua!\xE7\x84\x83a3\x0BV[\x90Pa!\xF5\x81a\x02\ta\x05KV[PP`\x01\x01a!UV[`\0\x82\x81R`\x01` R`@\x81 \x90[\x82Q\x81\x10\x15a\x0E\0W`\0\x83\x82\x81Q\x81\x10a\"&W\xFE[` \x02` \x01\x01Q\x90P`\0a\"<\x84\x83a4\x12V[\x90Pa\"Ja!\t\x82a2\xE9V[a\"T\x84\x83a4!V[PPP\x80`\x01\x01\x90Pa\"\x0FV[a\"jaMZV[P\x90V[a\"va\x17hV[\x83a\"\x80\x81a&\x83V[\x83a\"\x8A\x81a\x1B\x0FV[a\"\x9E\x83`\0\x01QQ\x84` \x01QQa\x1E\x12V[``a\"\xAD\x84`\0\x01Qa4\xC3V[\x90P``a\"\xBB\x88\x83a5RV[\x90P``\x80``a\"\xD0\x8C\x8C\x8C\x8C\x8C\x89a5\xE3V[\x92P\x92P\x92P`\0a\"\xE1\x8Ca\x1FdV[\x90P`\x02\x81`\x02\x81\x11\x15a\"\xF1W\xFE[\x14\x15a#YWa#T\x8C\x87`\0\x81Q\x81\x10a#\x08W\xFE[` \x02` \x01\x01Q\x86`\0\x81Q\x81\x10a#\x1DW\xFE[` \x02` \x01\x01Q\x89`\x01\x81Q\x81\x10a#2W\xFE[` \x02` \x01\x01Q\x88`\x01\x81Q\x81\x10a#GW\xFE[` \x02` \x01\x01Qa7\xA8V[a#\x82V[`\x01\x81`\x02\x81\x11\x15a#gW\xFE[\x14\x15a#xWa#T\x8C\x87\x86a7\xE7V[a#\x82\x8C\x85a8TV[`\0\x80\x8E`\x01\x81\x11\x15a#\x91W\xFE[\x14\x90P\x8B`\x01`\x01`\xA0\x1B\x03\x16\x8D\x7F\xE5\xCE$\x90\x87\xCE\x04\xF0Z\x95q\x92CT\0\xFD\x97\x86\x8D\xBA\x0EjKL\x04\x9A\xBF\x8A\xF8\r\xAEx\x89a#\xCB\x88\x86a8\x9DV[\x87`@Qa#\xDB\x93\x92\x91\x90a\\LV[`@Q\x80\x91\x03\x90\xA3PPPPPPPPPa\x1D1a\x18\"V[``\x83Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a$\x0EW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a$8W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90Pa$CaM\x84V[a$KaL\xE1V[`\0\x80`\0[\x89Q\x81\x10\x15a&vW\x89\x81\x81Q\x81\x10a$fW\xFE[` \x02` \x01\x01Q\x94P`\0\x89Q\x86` \x01Q\x10\x80\x15a$\x8AWP\x89Q\x86`@\x01Q\x10[\x90Pa$\x97\x81`da\x05KV[`\0a$\xB9\x8B\x88` \x01Q\x81Q\x81\x10a$\xACW\xFE[` \x02` \x01\x01Qa\x1BAV[\x90P`\0a$\xD0\x8C\x89`@\x01Q\x81Q\x81\x10a$\xACW\xFE[\x90Pa$\xF3\x81`\x01`\x01`\xA0\x1B\x03\x16\x83`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x01\xFDa\x05KV[``\x88\x01Qa%CWa%\x0B`\0\x85\x11a\x01\xFEa\x05KV[`\0a%\x18\x8B\x84\x84a9EV[`\x01`\x01`\xA0\x1B\x03\x16\x87`\x01`\x01`\xA0\x1B\x03\x16\x14\x90Pa%:\x81a\x01\xFFa\x05KV[P``\x88\x01\x85\x90R[\x87Q`\x80\x88\x01R\x86\x8A`\x01\x81\x11\x15a%WW\xFE[\x90\x81`\x01\x81\x11\x15a%dW\xFE[\x90RP`\x01`\x01`\xA0\x1B\x03\x80\x83\x16` \x89\x01R\x81\x81\x16`@\x80\x8A\x01\x91\x90\x91R``\x80\x8B\x01Q\x90\x8A\x01R`\x80\x8A\x01Qa\x01\0\x8A\x01R\x8CQ\x82\x16`\xC0\x8A\x01R\x8C\x01Q\x16`\xE0\x88\x01R`\0\x80a%\xB6\x89a\x1BfV[\x91\x98P\x92P\x90Pa%\xC8\x8C\x85\x85a9gV[\x97Pa%\xFCa%\xD6\x83a9\x81V[\x8C\x8C` \x01Q\x81Q\x81\x10a%\xE6W\xFE[` \x02` \x01\x01Qa9\xB1\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x8B\x8B` \x01Q\x81Q\x81\x10a&\x0CW\xFE[` \x02` \x01\x01\x81\x81RPPa&Ja&$\x82a9\x81V[\x8C\x8C`@\x01Q\x81Q\x81\x10a&4W\xFE[` \x02` \x01\x01Qa9\xE5\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x8B\x8B`@\x01Q\x81Q\x81\x10a&ZW\xFE[` \x02` \x01\x01\x81\x81RPPPPPPP\x80`\x01\x01\x90Pa$QV[PPPPP\x94\x93PPPPV[`\0\x81\x81R`\x05` R`@\x90 Ta\x05~\x90`\xFF\x16a\x01\xF4a\x05KV[`\0\x80`\0\x80`\0a&\xB2\x87a:\x19V[\x94P\x94P\x94P\x94PP\x83`\x01`\x01`\xA0\x1B\x03\x16\x86`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a&\xE1W\x82\x94PPPPPa\x16\xF5V[\x81`\x01`\x01`\xA0\x1B\x03\x16\x86`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a'\x06W\x93Pa\x16\xF5\x92PPPV[a'\x11a\x02\ta\x16\xFBV[PPPP\x92\x91PPV[`\0\x82\x81R`\x07` \x90\x81R`@\x80\x83 `\x01`\x01`\xA0\x1B\x03\x85\x16\x84R\x90\x91R\x81 T\x81a'H\x82a:\x8FV[\x80a'fWP`\0\x85\x81R`\x08` R`@\x90 a'f\x90\x85a:\xA1V[\x90P\x80a'\x81Wa'v\x85a&\x83V[a'\x81a\x02\ta\x16\xFBV[P\x93\x92PPPV[`\0\x82\x81R`\x01` R`@\x81 a\t\xE1\x81\x84a4\x12V[m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90V[`p\x1Cm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90V[`\xE0\x1C\x90V[`\0\x80a'\xDC\x84a\x1FdV[\x90P`\x02\x81`\x02\x81\x11\x15a'\xECW\xFE[\x14\x15a(\x04Wa'\xFC\x84\x84a:\xC2V[\x91PPa\x16\xF5V[`\x01\x81`\x02\x81\x11\x15a(\x12W\xFE[\x14\x15a(\"Wa'\xFC\x84\x84a;\x13V[a'\xFC\x84\x84a;+V[`\0\x80`\0a(:\x86a\x1FdV[\x90P`\0\x87`\x02\x81\x11\x15a(JW\xFE[\x14\x15a(fWa(\\\x86\x82\x87\x87a;CV[\x92P\x92PPa(\x92V[`\x01\x87`\x02\x81\x11\x15a(tW\xFE[\x14\x15a(\x86Wa(\\\x86\x82\x87\x87a;\xBEV[a(\\\x86\x82\x87\x87a<:V[\x94P\x94\x92PPPV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a)\x08a<\x9DV[0`@Q` \x01a)\x1D\x95\x94\x93\x92\x91\x90a]\xF0V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x90V[``\x1C\x90V[``\x80`\0a)L\x84a\x1FdV[\x90P`\x02\x81`\x02\x81\x11\x15a)\\W\xFE[\x14\x15a)uWa)k\x84a<\xA1V[\x92P\x92PPa)\x9BV[`\x01\x81`\x02\x81\x11\x15a)\x83W\xFE[\x14\x15a)\x92Wa)k\x84a=\xD6V[a)k\x84a>\xFDV[\x91P\x91V[```\0\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a)\xBCW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a)\xE6W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x91P`\0\x90P`\0[\x82Q\x81\x10\x15a\x15\x1DW`\0\x84\x82\x81Q\x81\x10a*\x07W\xFE[` \x02` \x01\x01Q\x90Pa*\x1A\x81a?\xF9V[\x84\x83\x81Q\x81\x10a*&W\xFE[` \x02` \x01\x01\x81\x81RPPa*D\x83a*?\x83a'\xCAV[a@\x14V[\x92PP`\x01\x01a)\xF0V[`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\0\x90\x81R`\x04` \x90\x81R`@\x80\x83 \x93\x90\x94\x16\x82R\x91\x90\x91R T`\xFF\x16\x90V[`\x03T`@Q\x7F\x9B\xE2\xA8\x84\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\0\x91a\x01\0\x90\x04`\x01`\x01`\xA0\x1B\x03\x16\x90c\x9B\xE2\xA8\x84\x90a*\xD0\x90\x86\x90\x86\x900\x90`\x04\x01a]GV[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a*\xE8W`\0\x80\xFD[PZ\xFA\x15\x80\x15a*\xFCW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x16\xF2\x91\x90aTxV[`\0\x80a+-\x86\x86a\x1A\x01V[\x90Pa+F\x83\x80a+>WP\x84\x82\x10\x15[a\x02\x01a\x05KV[a+P\x81\x85a@+V[\x91P\x81\x81\x03a+l\x87\x87\x83a+d\x87a9\x81V[`\0\x03a@:V[PP\x94\x93PPPPV[`\0a+\x82\x84\x84a\x1A\x01V[\x90P`\0a+\x90\x82\x84a\x19EV[\x90Pa\x1D1\x85\x85\x83a+\xA1\x87a9\x81V[a@:V[a\x0E\0\x84c#\xB8r\xDD`\xE0\x1B\x85\x85\x85`@Q`$\x01a\x1E\xC5\x93\x92\x91\x90a[wV[a+\xD6\x81G\x10\x15a\x01\xA3a\x05KV[`\0\x82`\x01`\x01`\xA0\x1B\x03\x16\x82`@Qa+\xEF\x90a\x05HV[`\0`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a,,W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a,1V[``\x91P[PP\x90Pa\x0F\xA0\x81a\x01\xA4a\x05KV[`\x01`\x01`\xA0\x1B\x03\x82\x16`\0\x90\x81R`\x02` R`@\x90 \x80T`\x01\x81\x01\x90\x91Ua\x0F\xA0a,o\x84\x83a@\x95V[\x83a\x05KV[`\0\x80`\0\x80a,\x92\x86`\x80\x01Q\x87` \x01Q\x88`@\x01Qa2\"V[\x92P\x92P\x92P`\0\x80\x87`@\x01Q`\x01`\x01`\xA0\x1B\x03\x16\x88` \x01Q`\x01`\x01`\xA0\x1B\x03\x16\x10\x15a,\xC7WP\x83\x90P\x82a,\xCDV[P\x82\x90P\x83[a,\xD9\x88\x88\x84\x84aA\xBBV[`@\x8B\x01Q` \x8C\x01Q\x91\x99P\x92\x94P\x90\x92P`\x01`\x01`\xA0\x1B\x03\x91\x82\x16\x91\x16\x10a-\rWa-\x08\x81\x83aB\xD1V[a-\x17V[a-\x17\x82\x82aB\xD1V[\x90\x92UP\x92\x95\x94PPPPPV[`\0\x80a-:\x84`\x80\x01Q\x85` \x01Qa'\x1BV[\x90P`\0a-P\x85`\x80\x01Q\x86`@\x01Qa'\x1BV[\x90Pa-^\x85\x85\x84\x84aA\xBBV[`\x80\x88\x01\x80Q`\0\x90\x81R`\x07` \x81\x81R`@\x80\x84 \x82\x8E\x01Q`\x01`\x01`\xA0\x1B\x03\x90\x81\x16\x86R\x90\x83R\x81\x85 \x98\x90\x98U\x93Q\x83R\x90\x81R\x82\x82 \x9A\x83\x01Q\x90\x95\x16\x81R\x98\x90\x93R\x91\x90\x96 \x95\x90\x95UP\x92\x93\x92PPPV[`\x80\x82\x01Q`\0\x90\x81R`\x01` \x90\x81R`@\x82 \x90\x84\x01Q\x82\x91\x82\x91\x82\x90a-\xE2\x90\x83\x90aC\x0CV[\x90P`\0a-\xFD\x88`@\x01Q\x84aC\x0C\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90P\x81\x15\x80a.\nWP\x80\x15[\x15a.'Wa.\x1C\x88`\x80\x01Qa&\x83V[a.'a\x02\ta\x16\xFBV[`\0\x19\x91\x82\x01\x91\x01`\0a.:\x84aC+V[\x90P``\x81g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a.UW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a.\x7FW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P`\0`\xA0\x8C\x01\x81\x90R\x90\x91P[\x82\x81\x10\x15a.\xFFW`\0a.\xA1\x87\x83aC/V[\x90Pa.\xAC\x81a?\xF9V[\x83\x83\x81Q\x81\x10a.\xB8W\xFE[` \x02` \x01\x01\x81\x81RPPa.\xD5\x8C`\xA0\x01Qa*?\x83a'\xCAV[`\xA0\x8D\x01R\x81\x86\x14\x15a.\xEAW\x80\x98Pa.\xF6V[\x84\x82\x14\x15a.\xF6W\x80\x97P[P`\x01\x01a.\x8DV[P`@Q\x7F\x01\xEC\x95J\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x8A\x16\x90c\x01\xEC\x95J\x90a/K\x90\x8D\x90\x85\x90\x89\x90\x89\x90`\x04\x01a^[V[` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a/eW`\0\x80\xFD[PZ\xF1\x15\x80\x15a/yW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a/\x9D\x91\x90aYhV[\x97P`\0\x80a/\xB5\x8C`\0\x01Q\x8D``\x01Q\x8Ca/\xF7V[\x90\x92P\x90Pa/\xC4\x89\x83aCEV[\x98Pa/\xD0\x88\x82aCvV[\x97Pa/\xDD\x87\x87\x8BaC\x8CV[a/\xE8\x87\x86\x8AaC\x8CV[PPPPPPPPP\x92\x91PPV[`\0\x80\x80\x85`\x01\x81\x11\x15a0\x07W\xFE[\x14\x15a0\x17WP\x82\x90P\x81a0\x1DV[P\x81\x90P\x82[\x93P\x93\x91PPV[`\0\x82\x82\x02a0I\x84\x15\x80a0BWP\x83\x85\x83\x81a0?W\xFE[\x04\x14[`\x03a\x05KV[\x80a0XW`\0\x91PPa\x16\xF5V[g\r\xE0\xB6\xB3\xA7d\0\0`\0\x19\x82\x01\x04`\x01\x01\x91PPa\x16\xF5V[`\0``\x83`\x01`\x01`\xA0\x1B\x03\x16\x83`@Qa0\x8E\x91\x90aZ\xEAV[`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a0\xCBW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a0\xD0V[``\x91P[P\x91P\x91P`\0\x82\x14\x15a0\xE8W=`\0\x80>=`\0\xFD[a\x0E\0\x81Q`\0\x14\x80a1\nWP\x81\x80` \x01\x90Q\x81\x01\x90a1\n\x91\x90aTxV[a\x01\xA2a\x05KV[`\0a1\x1E\x83\x83a:\xA1V[a1mWP\x81T`\x01\x80\x82\x01\x84U`\0\x84\x81R` \x80\x82 \x90\x93\x01\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16`\x01`\x01`\xA0\x1B\x03\x86\x16\x90\x81\x17\x90\x91U\x85T\x90\x82R\x82\x86\x01\x90\x93R`@\x90 \x91\x90\x91Ua\x16\xF5V[P`\0a\x16\xF5V[`\x01`\x01`\xA0\x1B\x03\x82\x16`\0\x90\x81R`\x02\x84\x01` R`@\x81 T\x80a2\x02WPP\x82T`@\x80Q\x80\x82\x01\x82R`\x01`\x01`\xA0\x1B\x03\x85\x81\x16\x80\x83R` \x80\x84\x01\x87\x81R`\0\x87\x81R`\x01\x80\x8C\x01\x84R\x87\x82 \x96Q\x87T`\x01`\x01`\xA0\x1B\x03\x19\x16\x96\x16\x95\x90\x95\x17\x86U\x90Q\x94\x84\x01\x94\x90\x94U\x94\x82\x01\x80\x89U\x90\x83R`\x02\x88\x01\x90\x94R\x91\x90 \x91\x90\x91Ua\x18vV[`\0\x19\x01`\0\x90\x81R`\x01\x80\x86\x01` R`@\x82 \x01\x83\x90U\x90Pa\x18vV[`\0\x80`\0\x80`\0a24\x87\x87aC\xA4V[\x91P\x91P`\0a2D\x83\x83aC\xD5V[`\0\x8A\x81R`\t` \x90\x81R`@\x80\x83 \x84\x84R`\x02\x01\x90\x91R\x81 \x80T`\x01\x82\x01T\x91\x97P\x92\x93P\x90a2w\x83a:\x8FV[\x80a2\x86WPa2\x86\x82a:\x8FV[\x80a2\xA7WPa2\x96\x8C\x87a:\xC2V[\x80\x15a2\xA7WPa2\xA7\x8C\x86a:\xC2V[\x90P\x80a2\xC2Wa2\xB7\x8Ca&\x83V[a2\xC2a\x02\ta\x16\xFBV[a2\xCC\x83\x83aD\x08V[\x98Pa2\xD8\x83\x83aD-V[\x97PPPPPPP\x93P\x93P\x93\x90PV[{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x15\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16`\0\x90\x81R`\x01\x83\x01` R`@\x81 T\x80\x15a4\x08W\x83T`\0\x19\x80\x83\x01\x91\x90\x81\x01\x90`\0\x90\x87\x90\x83\x90\x81\x10a3HW\xFE[`\0\x91\x82R` \x90\x91 \x01T\x87T`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x91P\x81\x90\x88\x90\x85\x90\x81\x10a3qW\xFE[`\0\x91\x82R` \x80\x83 \x91\x90\x91\x01\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16`\x01`\x01`\xA0\x1B\x03\x94\x85\x16\x17\x90U\x91\x83\x16\x81R`\x01\x89\x81\x01\x90\x92R`@\x90 \x90\x84\x01\x90U\x86T\x87\x90\x80a3\xBAW\xFE[`\0\x82\x81R` \x80\x82 \x83\x01`\0\x19\x90\x81\x01\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16\x90U\x90\x92\x01\x90\x92U`\x01`\x01`\xA0\x1B\x03\x88\x16\x82R`\x01\x89\x81\x01\x90\x91R`@\x82 \x91\x90\x91U\x94Pa\x16\xF5\x93PPPPV[`\0\x91PPa\x16\xF5V[`\0a\x16\xF2\x83\x83a\x02\taDDV[`\x01`\x01`\xA0\x1B\x03\x81\x16`\0\x90\x81R`\x02\x83\x01` R`@\x81 T\x80\x15a4\x08W\x83T`\0\x19\x90\x81\x01`\0\x81\x81R`\x01\x87\x81\x01` \x90\x81R`@\x80\x84 \x95\x87\x01\x84R\x80\x84 \x86T\x81T`\x01`\x01`\xA0\x1B\x03\x19\x90\x81\x16`\x01`\x01`\xA0\x1B\x03\x92\x83\x16\x17\x83U\x88\x86\x01\x80T\x93\x87\x01\x93\x90\x93U\x88T\x82\x16\x87R`\x02\x8D\x01\x80\x86R\x84\x88 \x9A\x90\x9AU\x88T\x16\x90\x97U\x84\x90U\x93\x89U\x93\x87\x16\x82R\x93\x90\x92R\x81 U\x90Pa\x16\xF5V[``\x80\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a4\xDEW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a5\x08W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0[\x83Q\x81\x10\x15a\x07\xFFWa5&\x84\x82\x81Q\x81\x10a$\xACW\xFE[\x82\x82\x81Q\x81\x10a52W\xFE[`\x01`\x01`\xA0\x1B\x03\x90\x92\x16` \x92\x83\x02\x91\x90\x91\x01\x90\x91\x01R`\x01\x01a5\x0EV[``\x80``a5`\x85a)>V[\x91P\x91Pa5p\x82Q\x85Qa\x1E\x12V[a5\x80`\0\x83Q\x11a\x02\x0Fa\x05KV[`\0[\x82Q\x81\x10\x15a5\xDAWa5\xD2\x85\x82\x81Q\x81\x10a5\x9BW\xFE[` \x02` \x01\x01Q`\x01`\x01`\xA0\x1B\x03\x16\x84\x83\x81Q\x81\x10a5\xB8W\xFE[` \x02` \x01\x01Q`\x01`\x01`\xA0\x1B\x03\x16\x14a\x02\x08a\x05KV[`\x01\x01a5\x83V[P\x94\x93PPPPV[``\x80``\x80`\0a5\xF4\x86a)\xA0V[\x91P\x91P`\0a6\x03\x8Ba)8V[\x90P`\0\x8C`\x01\x81\x11\x15a6\x13W\xFE[\x14a6\xB6W\x80`\x01`\x01`\xA0\x1B\x03\x16ct\xF3\xB0\t\x8C\x8C\x8C\x87\x87a64aD\x81V[\x8F`@\x01Q`@Q\x88c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a6[\x97\x96\x95\x94\x93\x92\x91\x90a]fV[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a6uW`\0\x80\xFD[PZ\xF1\x15\x80\x15a6\x89W=`\0\x80>=`\0\xFD[PPPP`@Q=`\0\x82>`\x1F=\x90\x81\x01`\x1F\x19\x16\x82\x01`@Ra6\xB1\x91\x90\x81\x01\x90aT\x05V[a7OV[\x80`\x01`\x01`\xA0\x1B\x03\x16c\xD5\xC0\x96\xC4\x8C\x8C\x8C\x87\x87a6\xD2aD\x81V[\x8F`@\x01Q`@Q\x88c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a6\xF9\x97\x96\x95\x94\x93\x92\x91\x90a]fV[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a7\x13W`\0\x80\xFD[PZ\xF1\x15\x80\x15a7'W=`\0\x80>=`\0\xFD[PPPP`@Q=`\0\x82>`\x1F=\x90\x81\x01`\x1F\x19\x16\x82\x01`@Ra7O\x91\x90\x81\x01\x90aT\x05V[\x80\x95P\x81\x96PPPa7e\x87Q\x86Q\x86QaD\xFBV[`\0\x8C`\x01\x81\x11\x15a7sW\xFE[\x14a7\x8AWa7\x85\x89\x89\x89\x88\x88aE\x13V[a7\x97V[a7\x97\x8A\x89\x89\x88\x88aFZV[\x95PPPP\x96P\x96P\x96\x93PPPPV[`\0a7\xB4\x85\x84aC\xD5V[`\0\x87\x81R`\t` \x90\x81R`@\x80\x83 \x84\x84R`\x02\x01\x90\x91R\x90 \x90\x91Pa7\xDD\x85\x84aB\xD1V[\x90UPPPPPPV[`\0[\x82Q\x81\x10\x15a\x0E\0W\x81\x81\x81Q\x81\x10a7\xFFW\xFE[` \x02` \x01\x01Q`\x07`\0\x86\x81R` \x01\x90\x81R` \x01`\0 `\0\x85\x84\x81Q\x81\x10a8(W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`\x01`\x01`\xA0\x1B\x03\x16\x82R\x81\x01\x91\x90\x91R`@\x01`\0 U`\x01\x01a7\xEAV[`\0\x82\x81R`\x01` R`@\x81 \x90[\x82Q\x81\x10\x15a\x0E\0Wa8\x95\x81\x84\x83\x81Q\x81\x10a8}W\xFE[` \x02` \x01\x01Q\x84aC\x8C\x90\x92\x91\x90c\xFF\xFF\xFF\xFF\x16V[`\x01\x01a8dV[``\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a8\xB7W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a8\xE1W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0[\x83Q\x81\x10\x15a\x07\xFFW\x82a9\x11W\x83\x81\x81Q\x81\x10a9\x01W\xFE[` \x02` \x01\x01Q`\0\x03a9&V[\x83\x81\x81Q\x81\x10a9\x1DW\xFE[` \x02` \x01\x01Q[\x82\x82\x81Q\x81\x10a92W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a8\xE7V[`\0\x80\x84`\x01\x81\x11\x15a9TW\xFE[\x14a9_W\x81a\t\xE1V[P\x90\x92\x91PPV[`\0\x80\x84`\x01\x81\x11\x15a9vW\xFE[\x14a\x07\xFFW\x82a\t\xE1V[`\0a\"j\x7F\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83\x10a\x01\xA5a\x05KV[`\0\x82\x82\x01a\x16\xF2\x82\x84\x12\x80\x15\x90a9\xC9WP\x84\x82\x12\x15[\x80a9\xDEWP`\0\x84\x12\x80\x15a9\xDEWP\x84\x82\x12[`\0a\x05KV[`\0\x81\x83\x03a\x16\xF2\x82\x84\x12\x80\x15\x90a9\xFDWP\x84\x82\x13\x15[\x80a:\x12WP`\0\x84\x12\x80\x15a:\x12WP\x84\x82\x13[`\x01a\x05KV[`\0\x81\x81R`\t` R`@\x81 \x80T`\x01\x82\x01T`\x01`\x01`\xA0\x1B\x03\x91\x82\x16\x92\x84\x92\x90\x91\x16\x90\x82\x90\x81a:M\x86\x85aC\xD5V[`\0\x81\x81R`\x02\x84\x01` R`@\x90 \x80T`\x01\x82\x01T\x91\x99P\x91\x92Pa:t\x82\x82aD\x08V[\x96Pa:\x80\x82\x82aD-V[\x94PPPPP\x91\x93\x95\x90\x92\x94PV[`\0a:\x9A\x82a2\xE9V[\x15\x92\x91PPV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R`\x01\x91\x90\x91\x01` R`@\x90 T\x15\x15\x90V[`\0\x82\x81R`\t` R`@\x81 \x80T`\x01`\x01`\xA0\x1B\x03\x84\x81\x16\x91\x16\x14\x80a:\xFAWP`\x01\x81\x01T`\x01`\x01`\xA0\x1B\x03\x84\x81\x16\x91\x16\x14[\x80\x15a\t\xE1WPPP`\x01`\x01`\xA0\x1B\x03\x16\x15\x15\x91\x90PV[`\0\x82\x81R`\x08` R`@\x81 a\t\xE1\x81\x84a:\xA1V[`\0\x82\x81R`\x01` R`@\x81 a\t\xE1\x81\x84aG\xD0V[`\0\x80`\x02\x85`\x02\x81\x11\x15a;TW\xFE[\x14\x15a;jWa;e\x86\x85\x85aG\xF1V[a;\x94V[`\x01\x85`\x02\x81\x11\x15a;xW\xFE[\x14\x15a;\x89Wa;e\x86\x85\x85aG\xFFV[a;\x94\x86\x85\x85aH\rV[\x82\x15a;\xAEWa;\xAE`\x01`\x01`\xA0\x1B\x03\x85\x163\x85a\x1E\xA6V[PP`\0\x81\x90\x03\x94\x90\x93P\x91PPV[`\0\x80`\x02\x85`\x02\x81\x11\x15a;\xCFW\xFE[\x14\x15a;\xE5Wa;\xE0\x86\x85\x85aH\x1BV[a<\x0FV[`\x01\x85`\x02\x81\x11\x15a;\xF3W\xFE[\x14\x15a<\x04Wa;\xE0\x86\x85\x85aH)V[a<\x0F\x86\x85\x85aH7V[\x82\x15a<*Wa<*`\x01`\x01`\xA0\x1B\x03\x85\x1630\x86a+\xA6V[P\x90\x94`\0\x86\x90\x03\x94P\x92PPPV[`\0\x80`\x02\x85`\x02\x81\x11\x15a\x08W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a>2W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x92P\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a>MW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a>wW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x91P`\0[\x83Q\x81\x10\x15a>\xF6W`\0a>\x92\x83\x83aHuV[\x90P\x80\x85\x83\x81Q\x81\x10a>\xA1W\xFE[`\x01`\x01`\xA0\x1B\x03\x92\x83\x16` \x91\x82\x02\x92\x90\x92\x01\x81\x01\x91\x90\x91R`\0\x88\x81R`\x07\x82R`@\x80\x82 \x93\x85\x16\x82R\x92\x90\x91R T\x84Q\x85\x90\x84\x90\x81\x10a>\xE2W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01RP`\x01\x01a>}V[PP\x91P\x91V[`\0\x81\x81R`\x01` R`@\x90 ``\x90\x81\x90a?\x19\x81aC+V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a?/W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a?YW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x92P\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a?tW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a?\x9EW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x91P`\0[\x83Q\x81\x10\x15a>\xF6Wa?\xB7\x82\x82aH\xA2V[\x85\x83\x81Q\x81\x10a?\xC3W\xFE[` \x02` \x01\x01\x85\x84\x81Q\x81\x10a?\xD6W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01\x91\x90\x91R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x90R`\x01\x01a?\xA4V[`\0a@\x04\x82a'\xB4V[a@\r\x83a'\xA1V[\x01\x92\x91PPV[`\0\x81\x83\x10\x15a@$W\x81a\x16\xF2V[P\x90\x91\x90PV[`\0\x81\x83\x10a@$W\x81a\x16\xF2V[`\x01`\x01`\xA0\x1B\x03\x80\x85\x16`\0\x81\x81R`\x0B` \x90\x81R`@\x80\x83 \x94\x88\x16\x80\x84R\x94\x90\x91R\x90\x81\x90 \x85\x90UQ\x7F\x18\xE1\xEAA9\xE6\x84\x13\xD7\xD0\x8A\xA7R\xE7\x15h\xE3k,[\xF9@\x893\x14\xC2\xC5\xB0\x1E\xAA\x0CB\x90a\x19\xD0\x90\x85\x90a]>V[`\0\x80a@\xA0aH\xC6V[\x90PB\x81\x10\x15a@\xB4W`\0\x91PPa\x16\xF5V[`\0a@\xBEaH\xD2V[\x90P\x80a@\xD0W`\0\x92PPPa\x16\xF5V[`\0\x81a@\xDBaI\xE3V[\x80Q` \x91\x82\x01 `@Qa@\xF7\x93\x923\x91\x8A\x91\x89\x91\x01a]\xC4V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0aA\x1A\x82aJ2V[\x90P`\0\x80`\0aA)aJNV[\x92P\x92P\x92P`\0`\x01\x85\x85\x85\x85`@Q`\0\x81R` \x01`@R`@QaAT\x94\x93\x92\x91\x90a^\x1CV[` `@Q` \x81\x03\x90\x80\x84\x03\x90\x85Z\xFA\x15\x80\x15aAvW=`\0\x80>=`\0\xFD[PP`@Q`\x1F\x19\x01Q\x91PP`\x01`\x01`\xA0\x1B\x03\x81\x16\x15\x80\x15\x90aA\xACWP\x8A`\x01`\x01`\xA0\x1B\x03\x16\x81`\x01`\x01`\xA0\x1B\x03\x16\x14[\x9B\x9APPPPPPPPPPPV[`\0\x80`\0\x80aA\xCA\x86a?\xF9V[\x90P`\0aA\xD7\x86a?\xF9V[\x90PaA\xEEaA\xE5\x88a'\xCAV[a*?\x88a'\xCAV[`\xA0\x8A\x01R`@Q\x7F\x9D,\x11\x0C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x89\x16\x90c\x9D,\x11\x0C\x90aB<\x90\x8C\x90\x86\x90\x86\x90`\x04\x01a^\x94V[` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15aBVW`\0\x80\xFD[PZ\xF1\x15\x80\x15aBjW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90aB\x8E\x91\x90aYhV[\x92P`\0\x80aB\xA6\x8B`\0\x01Q\x8C``\x01Q\x87a/\xF7V[\x90\x92P\x90PaB\xB5\x89\x83aCEV[\x96PaB\xC1\x88\x82aCvV[\x95PPPPP\x94P\x94P\x94\x91PPV[`\0\x80aB\xE9aB\xE0\x85a'\xCAV[a*?\x85a'\xCAV[\x90Pa\t\xE1aB\xF7\x85a'\xA1V[aC\0\x85a'\xA1V[\x83c\xFF\xFF\xFF\xFF\x16aJuV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R`\x02\x91\x90\x91\x01` R`@\x90 T\x90V[T\x90V[`\0\x90\x81R`\x01\x91\x82\x01` R`@\x90 \x01T\x90V[`\0\x80aC[\x83aCU\x86a'\xA1V[\x90a\x19EV[\x90P`\0aCh\x85a'\xB4V[\x90PCa\x12\xA6\x83\x83\x83aJ\x83V[`\0\x80aC[\x83aC\x86\x86a'\xA1V[\x90aJ\xBCV[`\0\x91\x82R`\x01\x92\x83\x01` R`@\x90\x91 \x90\x91\x01UV[`\0\x80\x82`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x10aC\xC7W\x82\x84aC\xCAV[\x83\x83[\x91P\x91P\x92P\x92\x90PV[`\0\x82\x82`@Q` \x01aC\xEA\x92\x91\x90a[\x06V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x92\x91PPV[`\0a\x16\xF2aD\x16\x84a'\xA1V[aD\x1F\x84a'\xA1V[aD(\x86a'\xCAV[aJ\x83V[`\0a\x16\xF2aD;\x84a'\xB4V[aD\x1F\x84a'\xB4V[`\x01`\x01`\xA0\x1B\x03\x82\x16`\0\x90\x81R`\x02\x84\x01` R`@\x81 TaDk\x81\x15\x15\x84a\x05KV[aDx\x85`\x01\x83\x03aC/V[\x95\x94PPPPPV[`\0aD\x8Ba\x13\xAFV[`\x01`\x01`\xA0\x1B\x03\x16cU\xC6v(`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15aD\xC3W`\0\x80\xFD[PZ\xFA\x15\x80\x15aD\xD7W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x12\xCE\x91\x90aYhV[a\x0F\xA0\x82\x84\x14\x80\x15aE\x0CWP\x81\x83\x14[`ga\x05KV[``\x83Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15aE-W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15aEWW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0[\x85QQ\x81\x10\x15aFPW`\0\x84\x82\x81Q\x81\x10aEuW\xFE[` \x02` \x01\x01Q\x90PaE\xA5\x87` \x01Q\x83\x81Q\x81\x10aE\x92W\xFE[` \x02` \x01\x01Q\x82\x10\x15a\x01\xF9a\x05KV[`\0\x87`\0\x01Q\x83\x81Q\x81\x10aE\xB7W\xFE[` \x02` \x01\x01Q\x90PaE\xD1\x81\x83\x8B\x8B``\x01Qa\x1D8V[`\0\x85\x84\x81Q\x81\x10aE\xDFW\xFE[` \x02` \x01\x01Q\x90PaE\xFBaE\xF5\x83a\x1BAV[\x82a\x1F\x11V[aF*aF\x08\x84\x83a\x19EV[\x89\x86\x81Q\x81\x10aF\x14W\xFE[` \x02` \x01\x01QaCv\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x85\x85\x81Q\x81\x10aF6W\xFE[` \x02` \x01\x01\x81\x81RPPPPP\x80`\x01\x01\x90PaE]V[P\x95\x94PPPPPV[```\0\x84Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15aFvW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15aF\xA0W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x91P`\0[\x86QQ\x81\x10\x15aG\xC6W`\0\x85\x82\x81Q\x81\x10aF\xBEW\xFE[` \x02` \x01\x01Q\x90PaF\xEE\x88` \x01Q\x83\x81Q\x81\x10aF\xDBW\xFE[` \x02` \x01\x01Q\x82\x11\x15a\x01\xFAa\x05KV[`\0\x88`\0\x01Q\x83\x81Q\x81\x10aG\0W\xFE[` \x02` \x01\x01Q\x90PaG\x1A\x81\x83\x8C\x8C``\x01Qa\x1CZV[aG#\x81a\x198V[\x15aG5WaG2\x84\x83a\x19EV[\x93P[`\0\x86\x84\x81Q\x81\x10aGCW\xFE[` \x02` \x01\x01Q\x90PaGYaE\xF5\x83a\x1BAV[\x80\x83\x10\x15aGxWaGs\x83\x82\x03\x8A\x86\x81Q\x81\x10aF\x14W\xFE[aG\xA0V[aG\xA0\x81\x84\x03\x8A\x86\x81Q\x81\x10aG\x8AW\xFE[` \x02` \x01\x01QaCE\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x86\x85\x81Q\x81\x10aG\xACW\xFE[` \x02` \x01\x01\x81\x81RPPPPP\x80`\x01\x01\x90PaF\xA6V[PaFP\x81a\x19\xDEV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R`\x02\x91\x90\x91\x01` R`@\x90 T\x15\x15\x90V[a\x0E\0\x83\x83aJ\xD2\x84aK\rV[a\x0E\0\x83\x83aJ\xD2\x84aK\xB8V[a\x0E\0\x83\x83aJ\xD2\x84aL\x13V[a\x0E\0\x83\x83aLb\x84aK\rV[a\x0E\0\x83\x83aLb\x84aK\xB8V[a\x0E\0\x83\x83aLb\x84aL\x13V[`\0a\t\xE1\x84\x84aL\x83\x85aK\rV[`\0a\t\xE1\x84\x84aL\x83\x85aK\xB8V[`\0a\t\xE1\x84\x84aL\x83\x85aL\x13V[`\0\x82`\0\x01\x82\x81T\x81\x10aH\x86W\xFE[`\0\x91\x82R` \x90\x91 \x01T`\x01`\x01`\xA0\x1B\x03\x16\x93\x92PPPV[`\0\x90\x81R`\x01\x91\x82\x01` R`@\x90 \x80T\x91\x01T`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x91V[`\0a\x12\xCE`\0aL\x9DV[`\0\x805`\xE0\x1C\x80c\xB9\\\xAC(\x81\x14aI\x1AWc\x8B\xDB9\x13\x81\x14aIBWcR\xBB\xBE)\x81\x14aIjWc\x94[\xCE\xC9\x81\x14aI\x92Wc\xFAng\x1D\x81\x14aI\xBAW`\0\x92PaI\xDEV[\x7F?{q%+\xD1\x91\x13\xFFH\xC1\x9Cn\0J\x9B\xCF\xCC\xA3 \xA0\xD7MX\xE8Xw\xCB\xD7\xDC\xAEX\x92PaI\xDEV[\x7F\x8B\xBCW\xF6n\xA96\x90/P\xA7\x1C\xE1+\x92\xC4?\x82\x86\x88c\xFF\xFF\xFF\xFF\x16V[\x90PaLK\x83\x88\x83a1uV[PaLV\x81\x83aL\xA7V[\x98\x97PPPPPPPPV[`\0\x80aLr\x83aCU\x86a'\xA1V[\x90P`\0aJ\xF3\x84aC\x86\x87a'\xB4V[`\0\x80aL\x8F\x84a'\xA1V[\x90PCaDx\x82\x85\x83aJ\x83V[6\x01`\x7F\x19\x015\x90V[`\0aL\xB2\x82a'\xB4V[aL\xBB\x84a'\xB4V[\x03\x93\x92PPPV[`\0a\x16\xF2aL\xD1\x84a'\xB4V[aL\xDA\x84a'\xB4V[`\0aJuV[`@\x80Qa\x01 \x81\x01\x90\x91R\x80`\0\x81R`\0` \x82\x01\x81\x90R`@\x82\x01\x81\x90R``\x80\x83\x01\x82\x90R`\x80\x83\x01\x82\x90R`\xA0\x83\x01\x82\x90R`\xC0\x83\x01\x82\x90R`\xE0\x83\x01\x91\x90\x91Ra\x01\0\x90\x91\x01R\x90V[`@\x80Q`\x80\x81\x01\x90\x91R\x80`\0\x81R`\0` \x82\x01\x81\x90R`@\x82\x01\x81\x90R``\x90\x91\x01R\x90V[`@Q\x80`\x80\x01`@R\x80``\x81R` \x01``\x81R` \x01``\x81R` \x01`\0\x15\x15\x81RP\x90V[`@Q\x80`\xA0\x01`@R\x80`\0\x80\x19\x16\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01``\x81RP\x90V[\x805a\x16\xF5\x81a_ZV[`\0\x82`\x1F\x83\x01\x12aM\xD1W\x80\x81\xFD[\x815aM\xE4aM\xDF\x82a_\x04V[a^\xDDV[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15aN\x05W`\0\x80\xFD[`\0[\x84\x81\x10\x15aN-W\x815aN\x1B\x81a_ZV[\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01aN\x08V[PPPPP\x92\x91PPV[`\0\x82`\x1F\x83\x01\x12aNHW\x80\x81\xFD[\x815aNVaM\xDF\x82a_\x04V[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01`\0[\x84\x81\x10\x15aN-W\x815\x87\x01`\xA0\x80`\x1F\x19\x83\x8C\x03\x01\x12\x15aN\x88W`\0\x80\xFD[aN\x91\x81a^\xDDV[\x85\x83\x015\x81R`@\x80\x84\x015\x87\x83\x01R``\x80\x85\x015\x82\x84\x01R`\x80\x91P\x81\x85\x015\x81\x84\x01RP\x82\x84\x015\x92Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11\x15aN\xD3W`\0\x80\xFD[aN\xE1\x8C\x88\x85\x87\x01\x01aO\xC0V[\x90\x82\x01R\x86RPP\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01aNgV[`\0\x82`\x1F\x83\x01\x12aO\tW\x80\x81\xFD[\x815aO\x17aM\xDF\x82a_\x04V[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15aO8W`\0\x80\xFD[`\0[\x84\x81\x10\x15aN-W\x815\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01aO;V[`\0\x82`\x1F\x83\x01\x12aOgW\x80\x81\xFD[\x81QaOuaM\xDF\x82a_\x04V[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15aO\x96W`\0\x80\xFD[`\0[\x84\x81\x10\x15aN-W\x81Q\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01aO\x99V[\x805a\x16\xF5\x81a_oV[`\0\x82`\x1F\x83\x01\x12aO\xD0W\x80\x81\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aO\xE6W\x81\x82\xFD[aO\xF9`\x1F\x82\x01`\x1F\x19\x16` \x01a^\xDDV[\x91P\x80\x82R\x83` \x82\x85\x01\x01\x11\x15aP\x10W`\0\x80\xFD[\x80` \x84\x01` \x84\x017`\0\x90\x82\x01` \x01R\x92\x91PPV[\x805a\x16\xF5\x81a_}V[\x805`\x02\x81\x10a\x16\xF5W`\0\x80\xFD[\x805`\x04\x81\x10a\x16\xF5W`\0\x80\xFD[`\0`\x80\x82\x84\x03\x12\x15aPcW\x80\x81\xFD[aPm`\x80a^\xDDV[\x90P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aP\x87W`\0\x80\xFD[aP\x93\x85\x83\x86\x01aM\xC1V[\x83R` \x84\x015\x91P\x80\x82\x11\x15aP\xA9W`\0\x80\xFD[aP\xB5\x85\x83\x86\x01aN\xF9V[` \x84\x01R`@\x84\x015\x91P\x80\x82\x11\x15aP\xCEW`\0\x80\xFD[PaP\xDB\x84\x82\x85\x01aO\xC0V[`@\x83\x01RPaP\xEE\x83``\x84\x01aO\xB5V[``\x82\x01R\x92\x91PPV[`\0`\x80\x82\x84\x03\x12\x15aQ\nW\x80\x81\xFD[aQ\x14`\x80a^\xDDV[\x90P\x815aQ!\x81a_ZV[\x81R` \x82\x015aQ1\x81a_oV[` \x82\x01R`@\x82\x015aQD\x81a_ZV[`@\x82\x01R``\x82\x015aP\xEE\x81a_oV[`\0` \x82\x84\x03\x12\x15aQhW\x80\x81\xFD[\x815a\x16\xF2\x81a_ZV[`\0\x80`@\x83\x85\x03\x12\x15aQ\x85W\x80\x81\xFD[\x825aQ\x90\x81a_ZV[\x91P` \x83\x015aQ\xA0\x81a_ZV[\x80\x91PP\x92P\x92\x90PV[`\0\x80`\0``\x84\x86\x03\x12\x15aQ\xBFW\x80\x81\xFD[\x835aQ\xCA\x81a_ZV[\x92P` \x84\x015aQ\xDA\x81a_ZV[\x91P`@\x84\x015aQ\xEA\x81a_oV[\x80\x91PP\x92P\x92P\x92V[`\0\x80`@\x83\x85\x03\x12\x15aR\x07W\x81\x82\xFD[\x825aR\x12\x81a_ZV[\x91P` \x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aR-W\x81\x82\xFD[aR9\x85\x82\x86\x01aM\xC1V[\x91PP\x92P\x92\x90PV[`\0` \x80\x83\x85\x03\x12\x15aRUW\x81\x82\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aRkW\x82\x83\xFD[\x83\x01`\x1F\x81\x01\x85\x13aR{W\x82\x83\xFD[\x805aR\x89aM\xDF\x82a_\x04V[\x81\x81R\x83\x81\x01\x90\x83\x85\x01`\x80\x80\x85\x02\x86\x01\x87\x01\x8A\x10\x15aR\xA7W\x87\x88\xFD[\x87\x95P[\x84\x86\x10\x15aS\x10W\x80\x82\x8B\x03\x12\x15aR\xC1W\x87\x88\xFD[aR\xCA\x81a^\xDDV[aR\xD4\x8B\x84aP)V[\x81R\x87\x83\x015\x88\x82\x01R`@aR\xEC\x8C\x82\x86\x01aM\xB6V[\x90\x82\x01R``\x83\x81\x015\x90\x82\x01R\x84R`\x01\x95\x90\x95\x01\x94\x92\x86\x01\x92\x90\x81\x01\x90aR\xABV[P\x90\x98\x97PPPPPPPPV[`\0` \x80\x83\x85\x03\x12\x15aS0W\x81\x82\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aSFW\x82\x83\xFD[\x83\x01`\x1F\x81\x01\x85\x13aSVW\x82\x83\xFD[\x805aSdaM\xDF\x82a_\x04V[\x81\x81R\x83\x81\x01\x90\x83\x85\x01`\xA0\x80\x85\x02\x86\x01\x87\x01\x8A\x10\x15aS\x82W\x87\x88\xFD[\x87\x95P[\x84\x86\x10\x15aS\x10W\x80\x82\x8B\x03\x12\x15aS\x9CW\x87\x88\xFD[aS\xA5\x81a^\xDDV[aS\xAF\x8B\x84aPCV[\x81RaS\xBD\x8B\x89\x85\x01aM\xB6V[\x81\x89\x01R`@\x83\x81\x015\x90\x82\x01R``aS\xD9\x8C\x82\x86\x01aM\xB6V[\x90\x82\x01R`\x80aS\xEB\x8C\x85\x83\x01aM\xB6V[\x90\x82\x01R\x84R`\x01\x95\x90\x95\x01\x94\x92\x86\x01\x92\x90\x81\x01\x90aS\x86V[`\0\x80`@\x83\x85\x03\x12\x15aT\x17W\x81\x82\xFD[\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aT.W\x83\x84\xFD[aT:\x86\x83\x87\x01aOWV[\x93P` \x85\x01Q\x91P\x80\x82\x11\x15aTOW\x82\x83\xFD[PaR9\x85\x82\x86\x01aOWV[`\0` \x82\x84\x03\x12\x15aTmW\x80\x81\xFD[\x815a\x16\xF2\x81a_oV[`\0` \x82\x84\x03\x12\x15aT\x89W\x80\x81\xFD[\x81Qa\x16\xF2\x81a_oV[`\0` \x82\x84\x03\x12\x15aT\xA5W\x80\x81\xFD[P5\x91\x90PV[`\0\x80`\0\x80`\x80\x85\x87\x03\x12\x15aT\xC1W\x81\x82\xFD[\x845\x93P` \x85\x015aT\xD3\x81a_ZV[\x92P`@\x85\x015aT\xE3\x81a_ZV[\x91P``\x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aT\xFEW\x81\x82\xFD[aU\n\x87\x82\x88\x01aPRV[\x91PP\x92\x95\x91\x94P\x92PV[`\0\x80`@\x83\x85\x03\x12\x15aU(W\x81\x82\xFD[\x825\x91P` \x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aR-W\x81\x82\xFD[`\0\x80`\0``\x84\x86\x03\x12\x15aUYW\x80\x81\xFD[\x835\x92P` \x80\x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aUxW\x83\x84\xFD[aU\x84\x88\x83\x89\x01aM\xC1V[\x94P`@\x87\x015\x91P\x80\x82\x11\x15aU\x99W\x83\x84\xFD[P\x85\x01`\x1F\x81\x01\x87\x13aU\xAAW\x82\x83\xFD[\x805aU\xB8aM\xDF\x82a_\x04V[\x81\x81R\x83\x81\x01\x90\x83\x85\x01\x85\x84\x02\x85\x01\x86\x01\x8B\x10\x15aU\xD4W\x86\x87\xFD[\x86\x94P[\x83\x85\x10\x15aU\xFFW\x805aU\xEB\x81a_ZV[\x83R`\x01\x94\x90\x94\x01\x93\x91\x85\x01\x91\x85\x01aU\xD8V[P\x80\x95PPPPPP\x92P\x92P\x92V[`\0\x80`@\x83\x85\x03\x12\x15aV!W\x81\x82\xFD[\x825\x91P` \x83\x015aQ\xA0\x81a_ZV[`\0` \x82\x84\x03\x12\x15aVDW\x80\x81\xFD[\x815`\x01`\x01`\xE0\x1B\x03\x19\x81\x16\x81\x14a\x16\xF2W\x81\x82\xFD[`\0\x80`\0\x80`\x80\x85\x87\x03\x12\x15aVpW\x81\x82\xFD[\x845aV{\x81a_ZV[\x93P` \x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aV\x97W\x83\x84\xFD[aV\xA3\x88\x83\x89\x01aM\xC1V[\x94P`@\x87\x015\x91P\x80\x82\x11\x15aV\xB8W\x83\x84\xFD[aV\xC4\x88\x83\x89\x01aN\xF9V[\x93P``\x87\x015\x91P\x80\x82\x11\x15aV\xD9W\x82\x83\xFD[PaU\n\x87\x82\x88\x01aO\xC0V[`\0` \x82\x84\x03\x12\x15aV\xF7W\x80\x81\xFD[\x815a\x16\xF2\x81a_}V[`\0\x80`\0\x80`\xE0\x85\x87\x03\x12\x15aW\x17W\x81\x82\xFD[aW!\x86\x86aP4V[\x93P` \x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aW=W\x83\x84\xFD[aWI\x88\x83\x89\x01aN8V[\x94P`@\x87\x015\x91P\x80\x82\x11\x15aW^W\x83\x84\xFD[PaWk\x87\x82\x88\x01aM\xC1V[\x92PPaW{\x86``\x87\x01aP\xF9V[\x90P\x92\x95\x91\x94P\x92PV[`\0\x80`\0\x80`\0\x80a\x01 \x87\x89\x03\x12\x15aW\x9FW\x83\x84\xFD[aW\xA9\x88\x88aP4V[\x95P` \x80\x88\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aW\xC6W\x86\x87\xFD[aW\xD2\x8B\x83\x8C\x01aN8V[\x97P`@\x8A\x015\x91P\x80\x82\x11\x15aW\xE7W\x86\x87\xFD[aW\xF3\x8B\x83\x8C\x01aM\xC1V[\x96PaX\x02\x8B``\x8C\x01aP\xF9V[\x95P`\xE0\x8A\x015\x91P\x80\x82\x11\x15aX\x17W\x84\x85\xFD[P\x88\x01`\x1F\x81\x01\x8A\x13aX(W\x83\x84\xFD[\x805aX6aM\xDF\x82a_\x04V[\x81\x81R\x83\x81\x01\x90\x83\x85\x01\x85\x84\x02\x85\x01\x86\x01\x8E\x10\x15aXRW\x87\x88\xFD[\x87\x94P[\x83\x85\x10\x15aXtW\x805\x83R`\x01\x94\x90\x94\x01\x93\x91\x85\x01\x91\x85\x01aXVV[P\x80\x96PPPPPPa\x01\0\x87\x015\x90P\x92\x95P\x92\x95P\x92\x95V[`\0\x80`\0\x80`\xE0\x85\x87\x03\x12\x15aX\xA4W\x81\x82\xFD[\x845g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aX\xBBW\x83\x84\xFD[\x90\x86\x01\x90`\xC0\x82\x89\x03\x12\x15aX\xCEW\x83\x84\xFD[aX\xD8`\xC0a^\xDDV[\x825\x81RaX\xE9\x89` \x85\x01aP4V[` \x82\x01R`@\x83\x015aX\xFC\x81a_ZV[`@\x82\x01RaY\x0E\x89``\x85\x01aM\xB6V[``\x82\x01R`\x80\x83\x015`\x80\x82\x01R`\xA0\x83\x015\x82\x81\x11\x15aY.W\x85\x86\xFD[aY:\x8A\x82\x86\x01aO\xC0V[`\xA0\x83\x01RP\x80\x96PPPPaYS\x86` \x87\x01aP\xF9V[\x93\x96\x93\x95PPPP`\xA0\x82\x015\x91`\xC0\x015\x90V[`\0` \x82\x84\x03\x12\x15aYyW\x80\x81\xFD[PQ\x91\x90PV[`\x01`\x01`\xA0\x1B\x03\x16\x90RV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15aY\xC5W\x81Q`\x01`\x01`\xA0\x1B\x03\x16\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01aY\xA0V[P\x94\x95\x94PPPPPV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15aY\xC5W\x81Q\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01aY\xE3V[`\0\x81Q\x80\x84RaZ\x17\x81` \x86\x01` \x86\x01a_$V[`\x1F\x01`\x1F\x19\x16\x92\x90\x92\x01` \x01\x92\x91PPV[`\0a\x01 \x82Q`\x02\x81\x10aZV[PPPPPV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82`@Q` \x01a\x02\xD8\x92\x91\x90a\t\xCCV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[`\0a\x02\xFFa\x05EV[\x90P\x90V[`\x02T\x90V[``\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x03$W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x03NW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0[\x82Q\x81\x10\x15a\x04\x0BW\x82\x81\x81Q\x81\x10a\x03iW\xFE[` \x02` \x01\x01Q`\x01`\x01`\xA0\x1B\x03\x16cp\xA0\x8210`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x03\x9C\x91\x90a\n5V[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x03\xB4W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x03\xC8W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03\xEC\x91\x90a\t\xB4V[\x82\x82\x81Q\x81\x10a\x03\xF8W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a\x03TV[P\x91\x90PV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`\0a\x04d`\x005\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16a\x02\xA3V[\x90Pa\x04{a\x04s\x823a\x05\xD8V[a\x01\x91a\x04~V[PV[\x81a\x04\x8CWa\x04\x8C\x81a\x06jV[PPV[a\x04\xA2`\x02`\0T\x14\x15a\x01\x90a\x04~V[`\x02`\0UV[a\x04\x8C\x81\x83\x14`ga\x04~V[a\x059\x83c\xA9\x05\x9C\xBB`\xE0\x1B\x84\x84`@Q`$\x01a\x04\xD5\x92\x91\x90a\nIV[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x93\x16\x92\x90\x92\x17\x90\x91Ra\x06\xD7V[PPPV[`\x01`\0UV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xAA\xAB\xAD\xC5`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x05\xA0W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x05\xB4W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x02\xFF\x91\x90a\tdV[`\0a\x05\xE2a\x05EV[`\x01`\x01`\xA0\x1B\x03\x16c\x9B\xE2\xA8\x84\x84\x840`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x06\x11\x93\x92\x91\x90a\n\xAFV[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x06)W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x06=W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x06a\x91\x90a\x08\xFDV[\x90P[\x92\x91PPV[\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\x90\x81R` `\x04R`\x07`$RfBAL#\0\x000`\n\x80\x84\x04\x81\x81\x06`0\x90\x81\x01`\x08\x1B\x95\x83\x90\x06\x95\x90\x95\x01\x90\x82\x90\x04\x91\x82\x06\x90\x94\x01`\x10\x1B\x93\x90\x93\x01\x01`\xC8\x1B`DR`d\x90\xFD[`\0``\x83`\x01`\x01`\xA0\x1B\x03\x16\x83`@Qa\x06\xF3\x91\x90a\t\xFCV[`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x070W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x075V[``\x91P[P\x91P\x91P`\0\x82\x14\x15a\x07MW=`\0\x80>=`\0\xFD[a\x07w\x81Q`\0\x14\x80a\x07oWP\x81\x80` \x01\x90Q\x81\x01\x90a\x07o\x91\x90a\x08\xFDV[a\x01\xA2a\x04~V[PPPPV[`\0\x80\x83`\x1F\x84\x01\x12a\x07\x8EW\x81\x82\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x07\xA5W\x81\x82\xFD[` \x83\x01\x91P\x83` \x80\x83\x02\x85\x01\x01\x11\x15a\x07\xBFW`\0\x80\xFD[\x92P\x92\x90PV[\x805a\x06d\x81a\n\xF5V[`\0\x80`\0\x80`\0``\x86\x88\x03\x12\x15a\x07\xE8W\x80\x81\xFD[\x855g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x07\xFFW\x82\x83\xFD[a\x08\x0B\x89\x83\x8A\x01a\x07}V[\x90\x97P\x95P` \x88\x015\x91P\x80\x82\x11\x15a\x08#W\x82\x83\xFD[Pa\x080\x88\x82\x89\x01a\x07}V[\x90\x94P\x92PP`@\x86\x015a\x08D\x81a\n\xF5V[\x80\x91PP\x92\x95P\x92\x95\x90\x93PV[`\0` \x80\x83\x85\x03\x12\x15a\x08dW\x81\x82\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x08{W\x83\x84\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x08\x8EW\x83\x84\xFD[\x815\x81\x81\x11\x15a\x08\x9CW\x84\x85\xFD[\x83\x81\x02\x91Pa\x08\xAC\x84\x83\x01a\n\xCEV[\x81\x81R\x84\x81\x01\x90\x84\x86\x01\x84\x86\x01\x87\x01\x8A\x10\x15a\x08\xC6W\x87\x88\xFD[\x87\x95P[\x83\x86\x10\x15a\x08\xF0Wa\x08\xDC\x8A\x82a\x07\xC6V[\x83R`\x01\x95\x90\x95\x01\x94\x91\x86\x01\x91\x86\x01a\x08\xCAV[P\x98\x97PPPPPPPPV[`\0` \x82\x84\x03\x12\x15a\t\x0EW\x80\x81\xFD[\x81Q\x80\x15\x15\x81\x14a\t\x1DW\x81\x82\xFD[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\t5W\x80\x81\xFD[\x815\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x81\x14a\t\x1DW\x81\x82\xFD[`\0` \x82\x84\x03\x12\x15a\tuW\x80\x81\xFD[\x81Qa\t\x1D\x81a\n\xF5V[`\0` \x82\x84\x03\x12\x15a\t\x91W\x80\x81\xFD[\x815a\t\x1D\x81a\n\xF5V[`\0` \x82\x84\x03\x12\x15a\t\xADW\x80\x81\xFD[P5\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\t\xC5W\x80\x81\xFD[PQ\x91\x90PV[\x91\x82R\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16` \x82\x01R`$\x01\x90V[`\0\x82Q\x81[\x81\x81\x10\x15a\n\x1CW` \x81\x86\x01\x81\x01Q\x85\x83\x01R\x01a\n\x02V[\x81\x81\x11\x15a\n*W\x82\x82\x85\x01R[P\x91\x90\x91\x01\x92\x91PPV[`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x81R` \x01\x90V[`\x01`\x01`\xA0\x1B\x03\x92\x90\x92\x16\x82R` \x82\x01R`@\x01\x90V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\n\x9AW\x83Q\x83R\x92\x84\x01\x92\x91\x84\x01\x91`\x01\x01a\n~V[P\x90\x96\x95PPPPPPV[\x90\x81R` \x01\x90V[\x92\x83R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16` \x84\x01R\x16`@\x82\x01R``\x01\x90V[`@Q\x81\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\n\xEDW`\0\x80\xFD[`@R\x91\x90PV[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x04{W`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \xBEr\xBD\xF8\xE7\xA3\xC3\x86\x06\xC5\xF9T\xFB\xE2\xD7w\x984z\xAA\x1C\xFBv\xFEw\xEC/l$]$\xBCdsolcC\0\x07\x01\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `AuthorizerChanged(address)` and selector `0x94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef`. + ```solidity + event AuthorizerChanged(address indexed newAuthorizer); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct AuthorizerChanged { + #[allow(missing_docs)] + pub newAuthorizer: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for AuthorizerChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "AuthorizerChanged(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 148u8, 185u8, 121u8, 182u8, 131u8, 26u8, 81u8, 41u8, 62u8, 38u8, 65u8, 66u8, + 111u8, 151u8, 116u8, 127u8, 238u8, 212u8, 111u8, 23u8, 119u8, 159u8, 237u8, + 156u8, 209u8, 141u8, 30u8, 206u8, 252u8, 254u8, 146u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + newAuthorizer: topics.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.newAuthorizer.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.newAuthorizer, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for AuthorizerChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&AuthorizerChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &AuthorizerChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ExternalBalanceTransfer(address,address,address,uint256)` and selector `0x540a1a3f28340caec336c81d8d7b3df139ee5cdc1839a4f283d7ebb7eaae2d5c`. + ```solidity + event ExternalBalanceTransfer(address indexed token, address indexed sender, address recipient, uint256 amount); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ExternalBalanceTransfer { + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ExternalBalanceTransfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "ExternalBalanceTransfer(address,address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 84u8, 10u8, 26u8, 63u8, 40u8, 52u8, 12u8, 174u8, 195u8, 54u8, 200u8, 29u8, + 141u8, 123u8, 61u8, 241u8, 57u8, 238u8, 92u8, 220u8, 24u8, 57u8, 164u8, 242u8, + 131u8, 215u8, 235u8, 183u8, 234u8, 174u8, 45u8, 92u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + token: topics.1, + sender: topics.2, + recipient: data.0, + amount: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.token.clone(), + self.sender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.token, + ); + out[2usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ExternalBalanceTransfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ExternalBalanceTransfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ExternalBalanceTransfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FlashLoan(address,address,uint256,uint256)` and selector `0x0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f0`. + ```solidity + event FlashLoan(address indexed recipient, address indexed token, uint256 amount, uint256 feeAmount); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FlashLoan { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FlashLoan { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FlashLoan(address,address,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 13u8, 125u8, 117u8, 224u8, 26u8, 185u8, 87u8, 128u8, 211u8, 205u8, 28u8, 142u8, + 192u8, 221u8, 108u8, 44u8, 225u8, 158u8, 58u8, 32u8, 66u8, 126u8, 236u8, 139u8, + 245u8, 50u8, 131u8, 182u8, 251u8, 142u8, 149u8, 240u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + recipient: topics.1, + token: topics.2, + amount: data.0, + feeAmount: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeAmount, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.recipient.clone(), + self.token.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.recipient, + ); + out[2usize] = ::encode_topic( + &self.token, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FlashLoan { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FlashLoan> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FlashLoan) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `InternalBalanceChanged(address,address,int256)` and selector `0x18e1ea4139e68413d7d08aa752e71568e36b2c5bf940893314c2c5b01eaa0c42`. + ```solidity + event InternalBalanceChanged(address indexed user, address indexed token, int256 delta); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct InternalBalanceChanged { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub delta: alloy_sol_types::private::primitives::aliases::I256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for InternalBalanceChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Int<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "InternalBalanceChanged(address,address,int256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 24u8, 225u8, 234u8, 65u8, 57u8, 230u8, 132u8, 19u8, 215u8, 208u8, 138u8, 167u8, + 82u8, 231u8, 21u8, 104u8, 227u8, 107u8, 44u8, 91u8, 249u8, 64u8, 137u8, 51u8, + 20u8, 194u8, 197u8, 176u8, 30u8, 170u8, 12u8, 66u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + user: topics.1, + token: topics.2, + delta: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.delta, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.user.clone(), + self.token.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.user, + ); + out[2usize] = ::encode_topic( + &self.token, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for InternalBalanceChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&InternalBalanceChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &InternalBalanceChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PausedStateChanged(bool)` and selector `0x9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be64`. + ```solidity + event PausedStateChanged(bool paused); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PausedStateChanged { + #[allow(missing_docs)] + pub paused: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PausedStateChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PausedStateChanged(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { paused: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.paused, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PausedStateChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PausedStateChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PausedStateChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolBalanceChanged(bytes32,address,address[],int256[],uint256[])` and selector `0xe5ce249087ce04f05a957192435400fd97868dba0e6a4b4c049abf8af80dae78`. + ```solidity + event PoolBalanceChanged(bytes32 indexed poolId, address indexed liquidityProvider, address[] tokens, int256[] deltas, uint256[] protocolFeeAmounts); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolBalanceChanged { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub liquidityProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub deltas: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub protocolFeeAmounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolBalanceChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "PoolBalanceChanged(bytes32,address,address[],int256[],uint256[])"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 229u8, 206u8, 36u8, 144u8, 135u8, 206u8, 4u8, 240u8, 90u8, 149u8, 113u8, 146u8, + 67u8, 84u8, 0u8, 253u8, 151u8, 134u8, 141u8, 186u8, 14u8, 106u8, 75u8, 76u8, + 4u8, 154u8, 191u8, 138u8, 248u8, 13u8, 174u8, 120u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + poolId: topics.1, + liquidityProvider: topics.2, + tokens: data.0, + deltas: data.1, + protocolFeeAmounts: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.deltas), + , + > as alloy_sol_types::SolType>::tokenize(&self.protocolFeeAmounts), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.poolId.clone(), + self.liquidityProvider.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.poolId); + out[2usize] = ::encode_topic( + &self.liquidityProvider, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolBalanceChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolBalanceChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolBalanceChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolBalanceManaged(bytes32,address,address,int256,int256)` and selector `0x6edcaf6241105b4c94c2efdbf3a6b12458eb3d07be3a0e81d24b13c44045fe7a`. + ```solidity + event PoolBalanceManaged(bytes32 indexed poolId, address indexed assetManager, address indexed token, int256 cashDelta, int256 managedDelta); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolBalanceManaged { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub assetManager: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub cashDelta: alloy_sol_types::private::primitives::aliases::I256, + #[allow(missing_docs)] + pub managedDelta: alloy_sol_types::private::primitives::aliases::I256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolBalanceManaged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Int<256>, + alloy_sol_types::sol_data::Int<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "PoolBalanceManaged(bytes32,address,address,int256,int256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 110u8, 220u8, 175u8, 98u8, 65u8, 16u8, 91u8, 76u8, 148u8, 194u8, 239u8, 219u8, + 243u8, 166u8, 177u8, 36u8, 88u8, 235u8, 61u8, 7u8, 190u8, 58u8, 14u8, 129u8, + 210u8, 75u8, 19u8, 196u8, 64u8, 69u8, 254u8, 122u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + poolId: topics.1, + assetManager: topics.2, + token: topics.3, + cashDelta: data.0, + managedDelta: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.cashDelta, + ), + as alloy_sol_types::SolType>::tokenize( + &self.managedDelta, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.poolId.clone(), + self.assetManager.clone(), + self.token.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.poolId); + out[2usize] = ::encode_topic( + &self.assetManager, + ); + out[3usize] = ::encode_topic( + &self.token, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolBalanceManaged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolBalanceManaged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolBalanceManaged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolRegistered(bytes32,address,uint8)` and selector `0x3c13bc30b8e878c53fd2a36b679409c073afd75950be43d8858768e956fbc20e`. + ```solidity + event PoolRegistered(bytes32 indexed poolId, address indexed poolAddress, IVault.PoolSpecialization specialization); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolRegistered { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub poolAddress: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub specialization: ::RustType, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolRegistered { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (IVault::PoolSpecialization,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolRegistered(bytes32,address,uint8)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 60u8, 19u8, 188u8, 48u8, 184u8, 232u8, 120u8, 197u8, 63u8, 210u8, 163u8, 107u8, + 103u8, 148u8, 9u8, 192u8, 115u8, 175u8, 215u8, 89u8, 80u8, 190u8, 67u8, 216u8, + 133u8, 135u8, 104u8, 233u8, 86u8, 251u8, 194u8, 14u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + poolId: topics.1, + poolAddress: topics.2, + specialization: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.specialization, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.poolId.clone(), + self.poolAddress.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.poolId); + out[2usize] = ::encode_topic( + &self.poolAddress, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolRegistered { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolRegistered> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolRegistered) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `RelayerApprovalChanged(address,address,bool)` and selector `0x46961fdb4502b646d5095fba7600486a8ac05041d55cdf0f16ed677180b5cad8`. + ```solidity + event RelayerApprovalChanged(address indexed relayer, address indexed sender, bool approved); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct RelayerApprovalChanged { + #[allow(missing_docs)] + pub relayer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub approved: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RelayerApprovalChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "RelayerApprovalChanged(address,address,bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 70u8, 150u8, 31u8, 219u8, 69u8, 2u8, 182u8, 70u8, 213u8, 9u8, 95u8, 186u8, + 118u8, 0u8, 72u8, 106u8, 138u8, 192u8, 80u8, 65u8, 213u8, 92u8, 223u8, 15u8, + 22u8, 237u8, 103u8, 113u8, 128u8, 181u8, 202u8, 216u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + relayer: topics.1, + sender: topics.2, + approved: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.approved, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.relayer.clone(), + self.sender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.relayer, + ); + out[2usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RelayerApprovalChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RelayerApprovalChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RelayerApprovalChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Swap(bytes32,address,address,uint256,uint256)` and selector `0x2170c741c41531aec20e7c107c24eecfdd15e69c9bb0a8dd37b1840b9e0b207b`. + ```solidity + event Swap(bytes32 indexed poolId, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Swap { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub tokenIn: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenOut: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountIn: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Swap { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Swap(bytes32,address,address,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 33u8, 112u8, 199u8, 65u8, 196u8, 21u8, 49u8, 174u8, 194u8, 14u8, 124u8, 16u8, + 124u8, 36u8, 238u8, 207u8, 221u8, 21u8, 230u8, 156u8, 155u8, 176u8, 168u8, + 221u8, 55u8, 177u8, 132u8, 11u8, 158u8, 11u8, 32u8, 123u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + poolId: topics.1, + tokenIn: topics.2, + tokenOut: topics.3, + amountIn: data.0, + amountOut: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountIn, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountOut, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.poolId.clone(), + self.tokenIn.clone(), + self.tokenOut.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.poolId); + out[2usize] = ::encode_topic( + &self.tokenIn, + ); + out[3usize] = ::encode_topic( + &self.tokenOut, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Swap { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Swap> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Swap) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TokensDeregistered(bytes32,address[])` and selector `0x7dcdc6d02ef40c7c1a7046a011b058bd7f988fa14e20a66344f9d4e60657d610`. + ```solidity + event TokensDeregistered(bytes32 indexed poolId, address[] tokens); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TokensDeregistered { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TokensDeregistered { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = + (alloy_sol_types::sol_data::Array,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "TokensDeregistered(bytes32,address[])"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 125u8, 205u8, 198u8, 208u8, 46u8, 244u8, 12u8, 124u8, 26u8, 112u8, 70u8, 160u8, + 17u8, 176u8, 88u8, 189u8, 127u8, 152u8, 143u8, 161u8, 78u8, 32u8, 166u8, 99u8, + 68u8, 249u8, 212u8, 230u8, 6u8, 87u8, 214u8, 16u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + poolId: topics.1, + tokens: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( as alloy_sol_types::SolType>::tokenize( + &self.tokens + ),) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.poolId.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.poolId); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TokensDeregistered { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TokensDeregistered> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TokensDeregistered) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TokensRegistered(bytes32,address[],address[])` and selector `0xf5847d3f2197b16cdcd2098ec95d0905cd1abdaf415f07bb7cef2bba8ac5dec4`. + ```solidity + event TokensRegistered(bytes32 indexed poolId, address[] tokens, address[] assetManagers); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TokensRegistered { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub assetManagers: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TokensRegistered { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "TokensRegistered(bytes32,address[],address[])"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 245u8, 132u8, 125u8, 63u8, 33u8, 151u8, 177u8, 108u8, 220u8, 210u8, 9u8, 142u8, + 201u8, 93u8, 9u8, 5u8, 205u8, 26u8, 189u8, 175u8, 65u8, 95u8, 7u8, 187u8, + 124u8, 239u8, 43u8, 186u8, 138u8, 197u8, 222u8, 196u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + poolId: topics.1, + tokens: data.0, + assetManagers: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.tokens), + as alloy_sol_types::SolType>::tokenize(&self.assetManagers), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.poolId.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.poolId); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TokensRegistered { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TokensRegistered> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TokensRegistered) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address authorizer, address weth, uint256 pauseWindowDuration, uint256 bufferPeriodDuration); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub authorizer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub weth: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.authorizer, + value.weth, + value.pauseWindowDuration, + value.bufferPeriodDuration, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + authorizer: tuple.0, + weth: tuple.1, + pauseWindowDuration: tuple.2, + bufferPeriodDuration: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.authorizer, + ), + ::tokenize( + &self.weth, + ), + as alloy_sol_types::SolType>::tokenize( + &self.pauseWindowDuration, + ), + as alloy_sol_types::SolType>::tokenize( + &self.bufferPeriodDuration, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `batchSwap(uint8,(bytes32,uint256,uint256,uint256,bytes)[],address[],(address,bool,address,bool),int256[],uint256)` and selector `0x945bcec9`. + ```solidity + function batchSwap(IVault.SwapKind kind, IVault.BatchSwapStep[] memory swaps, address[] memory assets, IVault.FundManagement memory funds, int256[] memory limits, uint256 deadline) external payable returns (int256[] memory assetDeltas); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct batchSwapCall { + #[allow(missing_docs)] + pub kind: ::RustType, + #[allow(missing_docs)] + pub swaps: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub assets: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub funds: ::RustType, + #[allow(missing_docs)] + pub limits: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`batchSwap(uint8,(bytes32,uint256,uint256,uint256,bytes)[],address[], + /// (address,bool,address,bool),int256[],uint256)`](batchSwapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct batchSwapReturn { + #[allow(missing_docs)] + pub assetDeltas: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + IVault::SwapKind, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + IVault::FundManagement, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Vec, + ::RustType, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: batchSwapCall) -> Self { + ( + value.kind, + value.swaps, + value.assets, + value.funds, + value.limits, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for batchSwapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + kind: tuple.0, + swaps: tuple.1, + assets: tuple.2, + funds: tuple.3, + limits: tuple.4, + deadline: tuple.5, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: batchSwapReturn) -> Self { + (value.assetDeltas,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for batchSwapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + assetDeltas: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for batchSwapCall { + type Parameters<'a> = ( + IVault::SwapKind, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + IVault::FundManagement, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [148u8, 91u8, 206u8, 201u8]; + const SIGNATURE: &'static str = "batchSwap(uint8,(bytes32,uint256,uint256,uint256,\ + bytes)[],address[],(address,bool,address,bool),\ + int256[],uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize(&self.kind), + as alloy_sol_types::SolType>::tokenize(&self.swaps), + as alloy_sol_types::SolType>::tokenize(&self.assets), + ::tokenize( + &self.funds, + ), + , + > as alloy_sol_types::SolType>::tokenize(&self.limits), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: batchSwapReturn = r.into(); + r.assetDeltas + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: batchSwapReturn = r.into(); + r.assetDeltas + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `flashLoan(address,address[],uint256[],bytes)` and selector `0x5c38449e`. + ```solidity + function flashLoan(address recipient, address[] memory tokens, uint256[] memory amounts, bytes memory userData) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct flashLoanCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`flashLoan(address,address[],uint256[],bytes)`](flashLoanCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct flashLoanReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: flashLoanCall) -> Self { + (value.recipient, value.tokens, value.amounts, value.userData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for flashLoanCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + tokens: tuple.1, + amounts: tuple.2, + userData: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: flashLoanReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for flashLoanReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl flashLoanReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for flashLoanCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = flashLoanReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [92u8, 56u8, 68u8, 158u8]; + const SIGNATURE: &'static str = "flashLoan(address,address[],uint256[],bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.amounts), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + flashLoanReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getInternalBalance(address,address[])` and selector `0x0f5a6efa`. + ```solidity + function getInternalBalance(address user, address[] memory tokens) external view returns (uint256[] memory balances); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getInternalBalanceCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getInternalBalance(address,address[])`](getInternalBalanceCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getInternalBalanceReturn { + #[allow(missing_docs)] + pub balances: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getInternalBalanceCall) -> Self { + (value.user, value.tokens) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getInternalBalanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + user: tuple.0, + tokens: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getInternalBalanceReturn) -> Self { + (value.balances,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getInternalBalanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { balances: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getInternalBalanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [15u8, 90u8, 110u8, 250u8]; + const SIGNATURE: &'static str = "getInternalBalance(address,address[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getInternalBalanceReturn = r.into(); + r.balances + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getInternalBalanceReturn = r.into(); + r.balances + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPausedState()` and selector `0x1c0de051`. + ```solidity + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPausedState()`](getPausedStateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateReturn { + #[allow(missing_docs)] + pub paused: bool, + #[allow(missing_docs)] + pub pauseWindowEndTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodEndTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + bool, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateReturn) -> Self { + ( + value.paused, + value.pauseWindowEndTime, + value.bufferPeriodEndTime, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paused: tuple.0, + pauseWindowEndTime: tuple.1, + bufferPeriodEndTime: tuple.2, + } + } + } + } + impl getPausedStateReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self.paused, + ), + as alloy_sol_types::SolType>::tokenize( + &self.pauseWindowEndTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.bufferPeriodEndTime, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPausedStateCall { + type Parameters<'a> = (); + type Return = getPausedStateReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [28u8, 13u8, 224u8, 81u8]; + const SIGNATURE: &'static str = "getPausedState()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPausedStateReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPool(bytes32)` and selector `0xf6c00927`. + ```solidity + function getPool(bytes32 poolId) external view returns (address, IVault.PoolSpecialization); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolCall { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPool(bytes32)`](getPoolCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _1: ::RustType, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolCall) -> Self { + (value.poolId,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { poolId: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + IVault::PoolSpecialization, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolReturn) -> Self { + (value._0, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + } + } + } + } + impl getPoolReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self._0, + ), + ::tokenize(&self._1), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolCall { + type Parameters<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Return = getPoolReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Address, + IVault::PoolSpecialization, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [246u8, 192u8, 9u8, 39u8]; + const SIGNATURE: &'static str = "getPool(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.poolId), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPoolReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPoolTokens(bytes32)` and selector `0xf94d4668`. + ```solidity + function getPoolTokens(bytes32 poolId) external view returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolTokensCall { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPoolTokens(bytes32)`](getPoolTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolTokensReturn { + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub balances: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub lastChangeBlock: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolTokensCall) -> Self { + (value.poolId,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { poolId: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolTokensReturn) -> Self { + (value.tokens, value.balances, value.lastChangeBlock) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokens: tuple.0, + balances: tuple.1, + lastChangeBlock: tuple.2, + } + } + } + } + impl getPoolTokensReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.balances), + as alloy_sol_types::SolType>::tokenize(&self.lastChangeBlock), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolTokensCall { + type Parameters<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Return = getPoolTokensReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [249u8, 77u8, 70u8, 104u8]; + const SIGNATURE: &'static str = "getPoolTokens(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.poolId), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPoolTokensReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `hasApprovedRelayer(address,address)` and selector `0xfec90d72`. + ```solidity + function hasApprovedRelayer(address user, address relayer) external view returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct hasApprovedRelayerCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub relayer: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`hasApprovedRelayer(address,address)`](hasApprovedRelayerCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct hasApprovedRelayerReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: hasApprovedRelayerCall) -> Self { + (value.user, value.relayer) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for hasApprovedRelayerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + user: tuple.0, + relayer: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: hasApprovedRelayerReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for hasApprovedRelayerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for hasApprovedRelayerCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [254u8, 201u8, 13u8, 114u8]; + const SIGNATURE: &'static str = "hasApprovedRelayer(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + ::tokenize( + &self.relayer, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: hasApprovedRelayerReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: hasApprovedRelayerReturn = r.into(); + r._0 + }) + } + } + }; + #[derive()] + /**Function with signature `manageUserBalance((uint8,address,uint256,address,address)[])` and selector `0x0e8e3e84`. + ```solidity + function manageUserBalance(IVault.UserBalanceOp[] memory ops) external payable; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct manageUserBalanceCall { + #[allow(missing_docs)] + pub ops: alloy_sol_types::private::Vec< + ::RustType, + >, + } + ///Container type for the return parameters of the + /// [`manageUserBalance((uint8,address,uint256,address, + /// address)[])`](manageUserBalanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct manageUserBalanceReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: manageUserBalanceCall) -> Self { + (value.ops,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for manageUserBalanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { ops: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: manageUserBalanceReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for manageUserBalanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl manageUserBalanceReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for manageUserBalanceCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Array,); + type Return = manageUserBalanceReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [14u8, 142u8, 62u8, 132u8]; + const SIGNATURE: &'static str = + "manageUserBalance((uint8,address,uint256,address,address)[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.ops), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + manageUserBalanceReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `setRelayerApproval(address,address,bool)` and selector `0xfa6e671d`. + ```solidity + function setRelayerApproval(address sender, address relayer, bool approved) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setRelayerApprovalCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub relayer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub approved: bool, + } + ///Container type for the return parameters of the + /// [`setRelayerApproval(address,address,bool)`](setRelayerApprovalCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setRelayerApprovalReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setRelayerApprovalCall) -> Self { + (value.sender, value.relayer, value.approved) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setRelayerApprovalCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + relayer: tuple.1, + approved: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setRelayerApprovalReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setRelayerApprovalReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl setRelayerApprovalReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for setRelayerApprovalCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + type Return = setRelayerApprovalReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [250u8, 110u8, 103u8, 29u8]; + const SIGNATURE: &'static str = "setRelayerApproval(address,address,bool)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.relayer, + ), + ::tokenize( + &self.approved, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + setRelayerApprovalReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive()] + /**Function with signature `swap((bytes32,uint8,address,address,uint256,bytes),(address,bool,address,bool),uint256,uint256)` and selector `0x52bbbe29`. + ```solidity + function swap(IVault.SingleSwap memory singleSwap, IVault.FundManagement memory funds, uint256 limit, uint256 deadline) external payable returns (uint256 amountCalculated); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapCall { + #[allow(missing_docs)] + pub singleSwap: ::RustType, + #[allow(missing_docs)] + pub funds: ::RustType, + #[allow(missing_docs)] + pub limit: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swap((bytes32,uint8,address,address,uint256,bytes),(address,bool, + /// address,bool),uint256,uint256)`](swapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapReturn { + #[allow(missing_docs)] + pub amountCalculated: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + IVault::SingleSwap, + IVault::FundManagement, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + ::RustType, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapCall) -> Self { + (value.singleSwap, value.funds, value.limit, value.deadline) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + singleSwap: tuple.0, + funds: tuple.1, + limit: tuple.2, + deadline: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapReturn) -> Self { + (value.amountCalculated,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountCalculated: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapCall { + type Parameters<'a> = ( + IVault::SingleSwap, + IVault::FundManagement, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [82u8, 187u8, 190u8, 41u8]; + const SIGNATURE: &'static str = "swap((bytes32,uint8,address,address,uint256,bytes),\ + (address,bool,address,bool),uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize(&self.singleSwap), + ::tokenize(&self.funds), + as alloy_sol_types::SolType>::tokenize( + &self.limit, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapReturn = r.into(); + r.amountCalculated + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapReturn = r.into(); + r.amountCalculated + }) + } + } + }; + ///Container for all the [`BalancerV2Vault`](self) function calls. + #[derive(Clone)] + pub enum BalancerV2VaultCalls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + batchSwap(batchSwapCall), + #[allow(missing_docs)] + flashLoan(flashLoanCall), + #[allow(missing_docs)] + getInternalBalance(getInternalBalanceCall), + #[allow(missing_docs)] + getPausedState(getPausedStateCall), + #[allow(missing_docs)] + getPool(getPoolCall), + #[allow(missing_docs)] + getPoolTokens(getPoolTokensCall), + #[allow(missing_docs)] + hasApprovedRelayer(hasApprovedRelayerCall), + #[allow(missing_docs)] + manageUserBalance(manageUserBalanceCall), + #[allow(missing_docs)] + setRelayerApproval(setRelayerApprovalCall), + #[allow(missing_docs)] + swap(swapCall), + } + impl BalancerV2VaultCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [14u8, 142u8, 62u8, 132u8], + [15u8, 90u8, 110u8, 250u8], + [28u8, 13u8, 224u8, 81u8], + [82u8, 187u8, 190u8, 41u8], + [92u8, 56u8, 68u8, 158u8], + [148u8, 91u8, 206u8, 201u8], + [173u8, 92u8, 70u8, 72u8], + [246u8, 192u8, 9u8, 39u8], + [249u8, 77u8, 70u8, 104u8], + [250u8, 110u8, 103u8, 29u8], + [254u8, 201u8, 13u8, 114u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(manageUserBalance), + ::core::stringify!(getInternalBalance), + ::core::stringify!(getPausedState), + ::core::stringify!(swap), + ::core::stringify!(flashLoan), + ::core::stringify!(batchSwap), + ::core::stringify!(WETH), + ::core::stringify!(getPool), + ::core::stringify!(getPoolTokens), + ::core::stringify!(setRelayerApproval), + ::core::stringify!(hasApprovedRelayer), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2VaultCalls { + const COUNT: usize = 11usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2VaultCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::batchSwap(_) => ::SELECTOR, + Self::flashLoan(_) => ::SELECTOR, + Self::getInternalBalance(_) => { + ::SELECTOR + } + Self::getPausedState(_) => { + ::SELECTOR + } + Self::getPool(_) => ::SELECTOR, + Self::getPoolTokens(_) => ::SELECTOR, + Self::hasApprovedRelayer(_) => { + ::SELECTOR + } + Self::manageUserBalance(_) => { + ::SELECTOR + } + Self::setRelayerApproval(_) => { + ::SELECTOR + } + Self::swap(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn manageUserBalance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::manageUserBalance) + } + manageUserBalance + }, + { + fn getInternalBalance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::getInternalBalance) + } + getInternalBalance + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::getPausedState) + } + getPausedState + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::swap) + } + swap + }, + { + fn flashLoan(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::flashLoan) + } + flashLoan + }, + { + fn batchSwap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::batchSwap) + } + batchSwap + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::WETH) + } + WETH + }, + { + fn getPool(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::getPool) + } + getPool + }, + { + fn getPoolTokens(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::getPoolTokens) + } + getPoolTokens + }, + { + fn setRelayerApproval( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::setRelayerApproval) + } + setRelayerApproval + }, + { + fn hasApprovedRelayer( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2VaultCalls::hasApprovedRelayer) + } + hasApprovedRelayer + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn manageUserBalance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2VaultCalls::manageUserBalance) + } + manageUserBalance + }, + { + fn getInternalBalance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2VaultCalls::getInternalBalance) + } + getInternalBalance + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2VaultCalls::getPausedState) + } + getPausedState + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2VaultCalls::swap) + } + swap + }, + { + fn flashLoan(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2VaultCalls::flashLoan) + } + flashLoan + }, + { + fn batchSwap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2VaultCalls::batchSwap) + } + batchSwap + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2VaultCalls::WETH) + } + WETH + }, + { + fn getPool(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2VaultCalls::getPool) + } + getPool + }, + { + fn getPoolTokens(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2VaultCalls::getPoolTokens) + } + getPoolTokens + }, + { + fn setRelayerApproval( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2VaultCalls::setRelayerApproval) + } + setRelayerApproval + }, + { + fn hasApprovedRelayer( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2VaultCalls::hasApprovedRelayer) + } + hasApprovedRelayer + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::batchSwap(inner) => { + ::abi_encoded_size(inner) + } + Self::flashLoan(inner) => { + ::abi_encoded_size(inner) + } + Self::getInternalBalance(inner) => { + ::abi_encoded_size(inner) + } + Self::getPausedState(inner) => { + ::abi_encoded_size(inner) + } + Self::getPool(inner) => { + ::abi_encoded_size(inner) + } + Self::getPoolTokens(inner) => { + ::abi_encoded_size(inner) + } + Self::hasApprovedRelayer(inner) => { + ::abi_encoded_size(inner) + } + Self::manageUserBalance(inner) => { + ::abi_encoded_size(inner) + } + Self::setRelayerApproval(inner) => { + ::abi_encoded_size(inner) + } + Self::swap(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::batchSwap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::flashLoan(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getInternalBalance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPausedState(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPool(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPoolTokens(inner) => { + ::abi_encode_raw(inner, out) + } + Self::hasApprovedRelayer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::manageUserBalance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::setRelayerApproval(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swap(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2Vault`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2VaultEvents { + #[allow(missing_docs)] + AuthorizerChanged(AuthorizerChanged), + #[allow(missing_docs)] + ExternalBalanceTransfer(ExternalBalanceTransfer), + #[allow(missing_docs)] + FlashLoan(FlashLoan), + #[allow(missing_docs)] + InternalBalanceChanged(InternalBalanceChanged), + #[allow(missing_docs)] + PausedStateChanged(PausedStateChanged), + #[allow(missing_docs)] + PoolBalanceChanged(PoolBalanceChanged), + #[allow(missing_docs)] + PoolBalanceManaged(PoolBalanceManaged), + #[allow(missing_docs)] + PoolRegistered(PoolRegistered), + #[allow(missing_docs)] + RelayerApprovalChanged(RelayerApprovalChanged), + #[allow(missing_docs)] + Swap(Swap), + #[allow(missing_docs)] + TokensDeregistered(TokensDeregistered), + #[allow(missing_docs)] + TokensRegistered(TokensRegistered), + } + impl BalancerV2VaultEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 13u8, 125u8, 117u8, 224u8, 26u8, 185u8, 87u8, 128u8, 211u8, 205u8, 28u8, 142u8, + 192u8, 221u8, 108u8, 44u8, 225u8, 158u8, 58u8, 32u8, 66u8, 126u8, 236u8, 139u8, + 245u8, 50u8, 131u8, 182u8, 251u8, 142u8, 149u8, 240u8, + ], + [ + 24u8, 225u8, 234u8, 65u8, 57u8, 230u8, 132u8, 19u8, 215u8, 208u8, 138u8, 167u8, + 82u8, 231u8, 21u8, 104u8, 227u8, 107u8, 44u8, 91u8, 249u8, 64u8, 137u8, 51u8, 20u8, + 194u8, 197u8, 176u8, 30u8, 170u8, 12u8, 66u8, + ], + [ + 33u8, 112u8, 199u8, 65u8, 196u8, 21u8, 49u8, 174u8, 194u8, 14u8, 124u8, 16u8, + 124u8, 36u8, 238u8, 207u8, 221u8, 21u8, 230u8, 156u8, 155u8, 176u8, 168u8, 221u8, + 55u8, 177u8, 132u8, 11u8, 158u8, 11u8, 32u8, 123u8, + ], + [ + 60u8, 19u8, 188u8, 48u8, 184u8, 232u8, 120u8, 197u8, 63u8, 210u8, 163u8, 107u8, + 103u8, 148u8, 9u8, 192u8, 115u8, 175u8, 215u8, 89u8, 80u8, 190u8, 67u8, 216u8, + 133u8, 135u8, 104u8, 233u8, 86u8, 251u8, 194u8, 14u8, + ], + [ + 70u8, 150u8, 31u8, 219u8, 69u8, 2u8, 182u8, 70u8, 213u8, 9u8, 95u8, 186u8, 118u8, + 0u8, 72u8, 106u8, 138u8, 192u8, 80u8, 65u8, 213u8, 92u8, 223u8, 15u8, 22u8, 237u8, + 103u8, 113u8, 128u8, 181u8, 202u8, 216u8, + ], + [ + 84u8, 10u8, 26u8, 63u8, 40u8, 52u8, 12u8, 174u8, 195u8, 54u8, 200u8, 29u8, 141u8, + 123u8, 61u8, 241u8, 57u8, 238u8, 92u8, 220u8, 24u8, 57u8, 164u8, 242u8, 131u8, + 215u8, 235u8, 183u8, 234u8, 174u8, 45u8, 92u8, + ], + [ + 110u8, 220u8, 175u8, 98u8, 65u8, 16u8, 91u8, 76u8, 148u8, 194u8, 239u8, 219u8, + 243u8, 166u8, 177u8, 36u8, 88u8, 235u8, 61u8, 7u8, 190u8, 58u8, 14u8, 129u8, 210u8, + 75u8, 19u8, 196u8, 64u8, 69u8, 254u8, 122u8, + ], + [ + 125u8, 205u8, 198u8, 208u8, 46u8, 244u8, 12u8, 124u8, 26u8, 112u8, 70u8, 160u8, + 17u8, 176u8, 88u8, 189u8, 127u8, 152u8, 143u8, 161u8, 78u8, 32u8, 166u8, 99u8, + 68u8, 249u8, 212u8, 230u8, 6u8, 87u8, 214u8, 16u8, + ], + [ + 148u8, 185u8, 121u8, 182u8, 131u8, 26u8, 81u8, 41u8, 62u8, 38u8, 65u8, 66u8, 111u8, + 151u8, 116u8, 127u8, 238u8, 212u8, 111u8, 23u8, 119u8, 159u8, 237u8, 156u8, 209u8, + 141u8, 30u8, 206u8, 252u8, 254u8, 146u8, 239u8, + ], + [ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ], + [ + 229u8, 206u8, 36u8, 144u8, 135u8, 206u8, 4u8, 240u8, 90u8, 149u8, 113u8, 146u8, + 67u8, 84u8, 0u8, 253u8, 151u8, 134u8, 141u8, 186u8, 14u8, 106u8, 75u8, 76u8, 4u8, + 154u8, 191u8, 138u8, 248u8, 13u8, 174u8, 120u8, + ], + [ + 245u8, 132u8, 125u8, 63u8, 33u8, 151u8, 177u8, 108u8, 220u8, 210u8, 9u8, 142u8, + 201u8, 93u8, 9u8, 5u8, 205u8, 26u8, 189u8, 175u8, 65u8, 95u8, 7u8, 187u8, 124u8, + 239u8, 43u8, 186u8, 138u8, 197u8, 222u8, 196u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FlashLoan), + ::core::stringify!(InternalBalanceChanged), + ::core::stringify!(Swap), + ::core::stringify!(PoolRegistered), + ::core::stringify!(RelayerApprovalChanged), + ::core::stringify!(ExternalBalanceTransfer), + ::core::stringify!(PoolBalanceManaged), + ::core::stringify!(TokensDeregistered), + ::core::stringify!(AuthorizerChanged), + ::core::stringify!(PausedStateChanged), + ::core::stringify!(PoolBalanceChanged), + ::core::stringify!(TokensRegistered), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2VaultEvents { + const COUNT: usize = 12usize; + const NAME: &'static str = "BalancerV2VaultEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::AuthorizerChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ExternalBalanceTransfer) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FlashLoan) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::InternalBalanceChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PausedStateChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolBalanceChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolBalanceManaged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolRegistered) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::RelayerApprovalChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Swap) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::TokensDeregistered) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::TokensRegistered) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2VaultEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::AuthorizerChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ExternalBalanceTransfer(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::FlashLoan(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::InternalBalanceChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolBalanceChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolBalanceManaged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolRegistered(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::RelayerApprovalChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::TokensDeregistered(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::TokensRegistered(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::AuthorizerChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ExternalBalanceTransfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::FlashLoan(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::InternalBalanceChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolBalanceChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolBalanceManaged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolRegistered(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::RelayerApprovalChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::TokensDeregistered(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TokensRegistered(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2Vault`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2VaultInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2VaultInstance { + BalancerV2VaultInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + authorizer: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + ) -> impl ::core::future::Future>> + { + BalancerV2VaultInstance::::deploy( + __provider, + authorizer, + weth, + pauseWindowDuration, + bufferPeriodDuration, + ) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + authorizer: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::RawCallBuilder { + BalancerV2VaultInstance::::deploy_builder( + __provider, + authorizer, + weth, + pauseWindowDuration, + bufferPeriodDuration, + ) + } + /**A [`BalancerV2Vault`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2Vault`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2VaultInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2VaultInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2VaultInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2VaultInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2Vault`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2VaultInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + authorizer: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder( + __provider, + authorizer, + weth, + pauseWindowDuration, + bufferPeriodDuration, + ); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + authorizer: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + authorizer, + weth, + pauseWindowDuration, + bufferPeriodDuration, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2VaultInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2VaultInstance { + BalancerV2VaultInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2VaultInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`batchSwap`] function. + pub fn batchSwap( + &self, + kind: ::RustType, + swaps: alloy_sol_types::private::Vec< + ::RustType, + >, + assets: alloy_sol_types::private::Vec, + funds: ::RustType, + limits: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::I256, + >, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, batchSwapCall, N> { + self.call_builder(&batchSwapCall { + kind, + swaps, + assets, + funds, + limits, + deadline, + }) + } + + ///Creates a new call builder for the [`flashLoan`] function. + pub fn flashLoan( + &self, + recipient: alloy_sol_types::private::Address, + tokens: alloy_sol_types::private::Vec, + amounts: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + userData: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, flashLoanCall, N> { + self.call_builder(&flashLoanCall { + recipient, + tokens, + amounts, + userData, + }) + } + + ///Creates a new call builder for the [`getInternalBalance`] function. + pub fn getInternalBalance( + &self, + user: alloy_sol_types::private::Address, + tokens: alloy_sol_types::private::Vec, + ) -> alloy_contract::SolCallBuilder<&P, getInternalBalanceCall, N> { + self.call_builder(&getInternalBalanceCall { user, tokens }) + } + + ///Creates a new call builder for the [`getPausedState`] function. + pub fn getPausedState(&self) -> alloy_contract::SolCallBuilder<&P, getPausedStateCall, N> { + self.call_builder(&getPausedStateCall) + } + + ///Creates a new call builder for the [`getPool`] function. + pub fn getPool( + &self, + poolId: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, getPoolCall, N> { + self.call_builder(&getPoolCall { poolId }) + } + + ///Creates a new call builder for the [`getPoolTokens`] function. + pub fn getPoolTokens( + &self, + poolId: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, getPoolTokensCall, N> { + self.call_builder(&getPoolTokensCall { poolId }) + } + + ///Creates a new call builder for the [`hasApprovedRelayer`] function. + pub fn hasApprovedRelayer( + &self, + user: alloy_sol_types::private::Address, + relayer: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, hasApprovedRelayerCall, N> { + self.call_builder(&hasApprovedRelayerCall { user, relayer }) + } + + ///Creates a new call builder for the [`manageUserBalance`] function. + pub fn manageUserBalance( + &self, + ops: alloy_sol_types::private::Vec< + ::RustType, + >, + ) -> alloy_contract::SolCallBuilder<&P, manageUserBalanceCall, N> { + self.call_builder(&manageUserBalanceCall { ops }) + } + + ///Creates a new call builder for the [`setRelayerApproval`] function. + pub fn setRelayerApproval( + &self, + sender: alloy_sol_types::private::Address, + relayer: alloy_sol_types::private::Address, + approved: bool, + ) -> alloy_contract::SolCallBuilder<&P, setRelayerApprovalCall, N> { + self.call_builder(&setRelayerApprovalCall { + sender, + relayer, + approved, + }) + } + + ///Creates a new call builder for the [`swap`] function. + pub fn swap( + &self, + singleSwap: ::RustType, + funds: ::RustType, + limit: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapCall, N> { + self.call_builder(&swapCall { + singleSwap, + funds, + limit, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2VaultInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`AuthorizerChanged`] event. + pub fn AuthorizerChanged_filter(&self) -> alloy_contract::Event<&P, AuthorizerChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ExternalBalanceTransfer`] + /// event. + pub fn ExternalBalanceTransfer_filter( + &self, + ) -> alloy_contract::Event<&P, ExternalBalanceTransfer, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`FlashLoan`] event. + pub fn FlashLoan_filter(&self) -> alloy_contract::Event<&P, FlashLoan, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`InternalBalanceChanged`] event. + pub fn InternalBalanceChanged_filter( + &self, + ) -> alloy_contract::Event<&P, InternalBalanceChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PausedStateChanged`] event. + pub fn PausedStateChanged_filter( + &self, + ) -> alloy_contract::Event<&P, PausedStateChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolBalanceChanged`] event. + pub fn PoolBalanceChanged_filter( + &self, + ) -> alloy_contract::Event<&P, PoolBalanceChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolBalanceManaged`] event. + pub fn PoolBalanceManaged_filter( + &self, + ) -> alloy_contract::Event<&P, PoolBalanceManaged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolRegistered`] event. + pub fn PoolRegistered_filter(&self) -> alloy_contract::Event<&P, PoolRegistered, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`RelayerApprovalChanged`] event. + pub fn RelayerApprovalChanged_filter( + &self, + ) -> alloy_contract::Event<&P, RelayerApprovalChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Swap`] event. + pub fn Swap_filter(&self) -> alloy_contract::Event<&P, Swap, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TokensDeregistered`] event. + pub fn TokensDeregistered_filter( + &self, + ) -> alloy_contract::Event<&P, TokensDeregistered, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TokensRegistered`] event. + pub fn TokensRegistered_filter(&self) -> alloy_contract::Event<&P, TokensRegistered, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2Vault::BalancerV2VaultInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(12272146u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(7003431u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(22691002u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(24821598u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(15832990u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(1196036u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(222832u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(26386141u64), + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(34313901u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), + Some(3418831u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2weightedpool/Cargo.toml b/contracts/generated/contracts-generated/balancerv2weightedpool/Cargo.toml new file mode 100644 index 0000000000..b1f3d89221 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpool/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2weightedpool" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2weightedpool/src/lib.rs b/contracts/generated/contracts-generated/balancerv2weightedpool/src/lib.rs new file mode 100644 index 0000000000..88378b5913 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpool/src/lib.rs @@ -0,0 +1,4380 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2WeightedPool { + event Approval(address indexed owner, address indexed spender, uint256 value); + event PausedStateChanged(bool paused); + event SwapFeePercentageChanged(uint256 swapFeePercentage); + event Transfer(address indexed from, address indexed to, uint256 value); + + constructor(address vault, string name, string symbol, address[] tokens, uint256[] normalizedWeights, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external pure returns (uint8); + function getNormalizedWeights() external view returns (uint256[] memory); + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + function getPoolId() external view returns (bytes32); + function getSwapFeePercentage() external view returns (uint256); + function name() external view returns (string memory); + function nonces(address owner) external view returns (uint256); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function symbol() external view returns (string memory); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "normalizedWeights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "pauseWindowDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getNormalizedWeights", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPausedState", + "inputs": [], + "outputs": [ + { + "name": "paused", + "type": "bool", + "internalType": "bool" + }, + { + "name": "pauseWindowEndTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bufferPeriodEndTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getSwapFeePercentage", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PausedStateChanged", + "inputs": [ + { + "name": "paused", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SwapFeePercentageChanged", + "inputs": [ + { + "name": "swapFeePercentage", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2WeightedPool { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PausedStateChanged(bool)` and selector `0x9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be64`. + ```solidity + event PausedStateChanged(bool paused); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PausedStateChanged { + #[allow(missing_docs)] + pub paused: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PausedStateChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PausedStateChanged(bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { paused: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.paused, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PausedStateChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PausedStateChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PausedStateChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SwapFeePercentageChanged(uint256)` and selector `0xa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc`. + ```solidity + event SwapFeePercentageChanged(uint256 swapFeePercentage); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SwapFeePercentageChanged { + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SwapFeePercentageChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SwapFeePercentageChanged(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, + 118u8, 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + swapFeePercentage: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.swapFeePercentage, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SwapFeePercentageChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SwapFeePercentageChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SwapFeePercentageChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, string name, string symbol, address[] tokens, uint256[] normalizedWeights, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub normalizedWeights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub pauseWindowDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodDuration: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.name, + value.symbol, + value.tokens, + value.normalizedWeights, + value.swapFeePercentage, + value.pauseWindowDuration, + value.bufferPeriodDuration, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + name: tuple.1, + symbol: tuple.2, + tokens: tuple.3, + normalizedWeights: tuple.4, + swapFeePercentage: tuple.5, + pauseWindowDuration: tuple.6, + bufferPeriodDuration: tuple.7, + owner: tuple.8, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.normalizedWeights), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + as alloy_sol_types::SolType>::tokenize(&self.pauseWindowDuration), + as alloy_sol_types::SolType>::tokenize(&self.bufferPeriodDuration), + ::tokenize( + &self.owner, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external pure returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getNormalizedWeights()` and selector `0xf89f27ed`. + ```solidity + function getNormalizedWeights() external view returns (uint256[] memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getNormalizedWeightsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getNormalizedWeights()`](getNormalizedWeightsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getNormalizedWeightsReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getNormalizedWeightsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getNormalizedWeightsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getNormalizedWeightsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getNormalizedWeightsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getNormalizedWeightsCall { + type Parameters<'a> = (); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 159u8, 39u8, 237u8]; + const SIGNATURE: &'static str = "getNormalizedWeights()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getNormalizedWeightsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getNormalizedWeightsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPausedState()` and selector `0x1c0de051`. + ```solidity + function getPausedState() external view returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPausedState()`](getPausedStateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPausedStateReturn { + #[allow(missing_docs)] + pub paused: bool, + #[allow(missing_docs)] + pub pauseWindowEndTime: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub bufferPeriodEndTime: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + bool, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPausedStateReturn) -> Self { + ( + value.paused, + value.pauseWindowEndTime, + value.bufferPeriodEndTime, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPausedStateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paused: tuple.0, + pauseWindowEndTime: tuple.1, + bufferPeriodEndTime: tuple.2, + } + } + } + } + impl getPausedStateReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self.paused, + ), + as alloy_sol_types::SolType>::tokenize( + &self.pauseWindowEndTime, + ), + as alloy_sol_types::SolType>::tokenize( + &self.bufferPeriodEndTime, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPausedStateCall { + type Parameters<'a> = (); + type Return = getPausedStateReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [28u8, 13u8, 224u8, 81u8]; + const SIGNATURE: &'static str = "getPausedState()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getPausedStateReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPoolId()` and selector `0x38fff2d0`. + ```solidity + function getPoolId() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPoolId()`](getPoolIdCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolIdReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolIdReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolIdReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolIdCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [56u8, 255u8, 242u8, 208u8]; + const SIGNATURE: &'static str = "getPoolId()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getPoolIdReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getPoolIdReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getSwapFeePercentage()` and selector `0x55c67628`. + ```solidity + function getSwapFeePercentage() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getSwapFeePercentage()`](getSwapFeePercentageCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getSwapFeePercentageReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getSwapFeePercentageReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getSwapFeePercentageReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getSwapFeePercentageCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [85u8, 198u8, 118u8, 40u8]; + const SIGNATURE: &'static str = "getSwapFeePercentage()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getSwapFeePercentageReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2WeightedPool`](self) function calls. + #[derive(Clone)] + pub enum BalancerV2WeightedPoolCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + getNormalizedWeights(getNormalizedWeightsCall), + #[allow(missing_docs)] + getPausedState(getPausedStateCall), + #[allow(missing_docs)] + getPoolId(getPoolIdCall), + #[allow(missing_docs)] + getSwapFeePercentage(getSwapFeePercentageCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl BalancerV2WeightedPoolCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [28u8, 13u8, 224u8, 81u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [56u8, 255u8, 242u8, 208u8], + [85u8, 198u8, 118u8, 40u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + [248u8, 159u8, 39u8, 237u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(getPausedState), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(getPoolId), + ::core::stringify!(getSwapFeePercentage), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ::core::stringify!(getNormalizedWeights), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2WeightedPoolCalls { + const COUNT: usize = 15usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2WeightedPoolCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::getNormalizedWeights(_) => { + ::SELECTOR + } + Self::getPausedState(_) => { + ::SELECTOR + } + Self::getPoolId(_) => ::SELECTOR, + Self::getSwapFeePercentage(_) => { + ::SELECTOR + } + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::name) + } + name + }, + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::getPausedState) + } + getPausedState + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::symbol) + } + symbol + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::allowance) + } + allowance + }, + { + fn getNormalizedWeights( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolCalls::getNormalizedWeights) + } + getNormalizedWeights + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPoolCalls, + >] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::name) + } + name + }, + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::approve) + } + approve + }, + { + fn getPausedState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2WeightedPoolCalls::getPausedState) + } + getPausedState + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2WeightedPoolCalls::transferFrom) + } + transferFrom + }, + { + fn decimals( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2WeightedPoolCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn getPoolId( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::getPoolId) + } + getPoolId + }, + { + fn getSwapFeePercentage( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2WeightedPoolCalls::getSwapFeePercentage) + } + getSwapFeePercentage + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::symbol) + } + symbol + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::permit) + } + permit + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolCalls::allowance) + } + allowance + }, + { + fn getNormalizedWeights( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV2WeightedPoolCalls::getNormalizedWeights) + } + getNormalizedWeights + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::getNormalizedWeights(inner) => { + ::abi_encoded_size(inner) + } + Self::getPausedState(inner) => { + ::abi_encoded_size(inner) + } + Self::getPoolId(inner) => { + ::abi_encoded_size(inner) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getNormalizedWeights(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::getPausedState(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPoolId(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getSwapFeePercentage(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2WeightedPool`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2WeightedPoolEvents { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + PausedStateChanged(PausedStateChanged), + #[allow(missing_docs)] + SwapFeePercentageChanged(SwapFeePercentageChanged), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl BalancerV2WeightedPoolEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 158u8, 58u8, 94u8, 55u8, 34u8, 69u8, 50u8, 222u8, 166u8, 123u8, 137u8, 250u8, + 206u8, 24u8, 87u8, 3u8, 115u8, 138u8, 34u8, 138u8, 110u8, 138u8, 35u8, 222u8, + 229u8, 70u8, 150u8, 1u8, 128u8, 211u8, 190u8, 100u8, + ], + [ + 169u8, 186u8, 63u8, 254u8, 11u8, 108u8, 54u8, 107u8, 129u8, 35u8, 44u8, 170u8, + 179u8, 134u8, 5u8, 160u8, 105u8, 154u8, 213u8, 57u8, 141u8, 108u8, 206u8, 118u8, + 249u8, 30u8, 232u8, 9u8, 227u8, 34u8, 218u8, 252u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(Approval), + ::core::stringify!(PausedStateChanged), + ::core::stringify!(SwapFeePercentageChanged), + ::core::stringify!(Transfer), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2WeightedPoolEvents { + const COUNT: usize = 4usize; + const NAME: &'static str = "BalancerV2WeightedPoolEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PausedStateChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::SwapFeePercentageChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2WeightedPoolEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PausedStateChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SwapFeePercentageChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2WeightedPoolInstance { + BalancerV2WeightedPoolInstance::::new(address, __provider) + } + /**A [`BalancerV2WeightedPool`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2WeightedPool`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2WeightedPoolInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2WeightedPoolInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2WeightedPoolInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPool`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2WeightedPoolInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2WeightedPoolInstance { + BalancerV2WeightedPoolInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`getNormalizedWeights`] + /// function. + pub fn getNormalizedWeights( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getNormalizedWeightsCall, N> { + self.call_builder(&getNormalizedWeightsCall) + } + + ///Creates a new call builder for the [`getPausedState`] function. + pub fn getPausedState(&self) -> alloy_contract::SolCallBuilder<&P, getPausedStateCall, N> { + self.call_builder(&getPausedStateCall) + } + + ///Creates a new call builder for the [`getPoolId`] function. + pub fn getPoolId(&self) -> alloy_contract::SolCallBuilder<&P, getPoolIdCall, N> { + self.call_builder(&getPoolIdCall) + } + + ///Creates a new call builder for the [`getSwapFeePercentage`] + /// function. + pub fn getSwapFeePercentage( + &self, + ) -> alloy_contract::SolCallBuilder<&P, getSwapFeePercentageCall, N> { + self.call_builder(&getSwapFeePercentageCall) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PausedStateChanged`] event. + pub fn PausedStateChanged_filter( + &self, + ) -> alloy_contract::Event<&P, PausedStateChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SwapFeePercentageChanged`] + /// event. + pub fn SwapFeePercentageChanged_filter( + &self, + ) -> alloy_contract::Event<&P, SwapFeePercentageChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2WeightedPool::BalancerV2WeightedPoolInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/balancerv2weightedpool2tokensfactory/Cargo.toml b/contracts/generated/contracts-generated/balancerv2weightedpool2tokensfactory/Cargo.toml new file mode 100644 index 0000000000..464db67155 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpool2tokensfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2weightedpool2tokensfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2weightedpool2tokensfactory/src/lib.rs b/contracts/generated/contracts-generated/balancerv2weightedpool2tokensfactory/src/lib.rs new file mode 100644 index 0000000000..e6f5149677 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpool2tokensfactory/src/lib.rs @@ -0,0 +1,1012 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2WeightedPool2TokensFactory { + event PoolCreated(address indexed pool); + + constructor(address vault); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, bool oracleEnabled, address owner) external returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "weights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "oracleEnabled", + "type": "bool", + "internalType": "bool" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2WeightedPool2TokensFactory { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60c060405234801561001057600080fd5b50604051615fe1380380615fe183398101604081905261002f9161004d565b60601b6001600160601b0319166080526276a700420160a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160601c60a051615f3b6100a660003980610221528061024b5250806102a75250615f3b6000f3fe60806040523480156200001157600080fd5b5060043610620000525760003560e01c80631596019b14620000575780632da47c4014620000865780636634b75314620000a05780638d928af814620000c6575b600080fd5b6200006e6200006836600462000548565b620000d0565b6040516200007d91906200068f565b60405180910390f35b620000906200021b565b6040516200007d929190620007a2565b620000b7620000b136600462000522565b62000287565b6040516200007d9190620006a3565b6200006e620002a5565b6000806000620000df6200021b565b91509150620000ed62000315565b60405180610180016040528062000103620002a5565b6001600160a01b031681526020018c81526020018b81526020018a6000815181106200012b57fe5b60200260200101516001600160a01b031681526020018a6001815181106200014f57fe5b60200260200101516001600160a01b03168152602001896000815181106200017357fe5b60200260200101518152602001896001815181106200018e57fe5b602002602001015181526020018881526020018481526020018381526020018715158152602001866001600160a01b03168152509050600081604051620001d5906200039c565b620001e19190620006ae565b604051809103906000f080158015620001fe573d6000803e3d6000fd5b5090506200020c81620002c9565b9b9a5050505050505050505050565b600080427f00000000000000000000000000000000000000000000000000000000000000008110156200027957807f000000000000000000000000000000000000000000000000000000000000000003925062278d00915062000282565b60009250600091505b509091565b6001600160a01b031660009081526020819052604090205460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b038116600081815260208190526040808220805460ff19166001179055517f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9190a250565b60405180610180016040528060006001600160a01b03168152602001606081526020016060815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b031681525090565b6156f3806200081383390190565b8035620003b781620007f9565b92915050565b600082601f830112620003ce578081fd5b8135620003e5620003df82620007d8565b620007b0565b8181529150602080830190848101818402860182018710156200040757600080fd5b60005b84811015620004335781356200042081620007f9565b845292820192908201906001016200040a565b505050505092915050565b600082601f8301126200044f578081fd5b813562000460620003df82620007d8565b8181529150602080830190848101818402860182018710156200048257600080fd5b60005b84811015620004335781358452928201929082019060010162000485565b80358015158114620003b757600080fd5b600082601f830112620004c5578081fd5b813567ffffffffffffffff811115620004dc578182fd5b620004f1601f8201601f1916602001620007b0565b91508082528360208285010111156200050957600080fd5b8060208401602084013760009082016020015292915050565b60006020828403121562000534578081fd5b81356200054181620007f9565b9392505050565b600080600080600080600060e0888a03121562000563578283fd5b873567ffffffffffffffff808211156200057b578485fd5b620005898b838c01620004b4565b985060208a01359150808211156200059f578485fd5b620005ad8b838c01620004b4565b975060408a0135915080821115620005c3578485fd5b620005d18b838c01620003bd565b965060608a0135915080821115620005e7578485fd5b50620005f68a828b016200043e565b945050608088013592506200060f8960a08a01620004a3565b9150620006208960c08a01620003aa565b905092959891949750929550565b6001600160a01b03169052565b15159052565b60008151808452815b8181101562000668576020818501810151868301820152016200064a565b818111156200067a5782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b901515815260200190565b600060208252620006c46020830184516200062e565b6020830151610180806040850152620006e26101a085018362000641565b91506040850151601f1985840301606086015262000701838262000641565b92505060608501516200071860808601826200062e565b5060808501516200072d60a08601826200062e565b5060a085015160c085015260c085015160e085015260e085015161010081818701528087015191505061012081818701528087015191505061014081818701528087015191505061016062000785818701836200063b565b860151905062000798858301826200062e565b5090949350505050565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715620007d057600080fd5b604052919050565b600067ffffffffffffffff821115620007ef578081fd5b5060209081020190565b6001600160a01b03811681146200080f57600080fd5b5056fe6102a06040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9610120523480156200003757600080fd5b50604051620056f3380380620056f38339810160408190526200005a916200080c565b61010081810151610120830151602080850151604080870151815180830190925260018252603160f81b8285019081526101608901513360805260601b6001600160601b03191660a052835194840194852060c052915190912060e0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f909552805193949293909291620000f391600391906200069f565b508051620001099060049060208401906200069f565b50620001219150506276a7008311156101946200040a565b6200013562278d008211156101956200040a565b4290910161014081815291016101605281015162000153906200041f565b60e081015162000163906200047b565b80516040516309b2760f60e01b81526000916001600160a01b0316906309b2760f90620001969060029060040162000a12565b602060405180830381600087803b158015620001b157600080fd5b505af1158015620001c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ec9190620007f3565b6040805160028082526060808301845293945090916020830190803683370190505090508260600151816000815181106200022357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508260800151816001815181106200025657fe5b6001600160a01b0392831660209182029290920101528351166366a9c7d283836002604051908082528060200260200182016040528015620002a2578160200160208202803683370190505b506040518463ffffffff1660e01b8152600401620002c39392919062000976565b600060405180830381600087803b158015620002de57600080fd5b505af1158015620002f3573d6000803e3d6000fd5b505084516001600160601b0319606091821b8116610180526101a08690528187018051831b82166101c052608088015190921b166101e052516200033a92509050620004f9565b6102605260808301516200034e90620004f9565b6102805260a08301516200036f90662386f26fc10000111561012e6200040a565b62000391662386f26fc100008460c00151101561012e6200040a60201b60201c565b6000620003b58460c001518560a001516200059b60201b620011c61790919060201c565b9050620003cf670de0b6b3a764000082146101346200040a565b60a0840180516102005260c085018051610220525190511015620003f5576001620003f8565b60005b60ff16610240525062000a6392505050565b816200041b576200041b81620005b8565b5050565b6200043b816008546200060b60201b620011d81790919060201c565b6008556040517f3e350b41e86a8e10f804ade6d35340d620be35569cc75ac943e8bb14ab80ead190620004709083906200096b565b60405180910390a150565b6200049064e8d4a5100082101560cb6200040a565b620004a867016345785d8a000082111560ca6200040a565b620004c4816008546200062a60201b620011e61790919060201c565b6008556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc906200047090839062000a27565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200053657600080fd5b505afa1580156200054b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000571919062000948565b60ff1690506000620005906012836200064960201b620011f41760201c565b600a0a949350505050565b6000828201620005af84821015836200040a565b90505b92915050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b6000620005af826055856200066160201b6200120a179092919060201c565b6000620005af826056856200068a60201b62001231179092919060201c565b60006200065b8383111560016200040a565b50900390565b60006001821b1984168284620006795760006200067c565b60015b60ff16901b17949350505050565b6001600160401b03811b1992909216911b1790565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620006e257805160ff191683800117855562000712565b8280016001018555821562000712579182015b8281111562000712578251825591602001919060010190620006f5565b506200072092915062000724565b5090565b5b8082111562000720576000815560010162000725565b80516001600160a01b0381168114620005b257600080fd5b80518015158114620005b257600080fd5b600082601f83011262000775578081fd5b81516001600160401b038111156200078b578182fd5b6020620007a1601f8301601f1916820162000a30565b92508183528481838601011115620007b857600080fd5b60005b82811015620007d8578481018201518482018301528101620007bb565b82811115620007ea5760008284860101525b50505092915050565b60006020828403121562000805578081fd5b5051919050565b6000602082840312156200081e578081fd5b81516001600160401b038082111562000835578283fd5b81840191506101808083870312156200084c578384fd5b620008578162000a30565b90506200086586846200073b565b815260208301518281111562000879578485fd5b620008878782860162000764565b6020830152506040830151828111156200089f578485fd5b620008ad8782860162000764565b604083015250620008c286606085016200073b565b6060820152620008d686608085016200073b565b608082015260a0838101519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101409150620009228683850162000753565b82820152610160915062000939868385016200073b565b91810191909152949350505050565b6000602082840312156200095a578081fd5b815160ff81168114620005af578182fd5b901515815260200190565b60006060820185835260206060818501528186518084526080860191508288019350845b81811015620009c257620009af855162000a57565b835293830193918301916001016200099a565b505084810360408601528551808252908201925081860190845b8181101562000a0457620009f1835162000a57565b85529383019391830191600101620009dc565b509298975050505050505050565b602081016003831062000a2157fe5b91905290565b90815260200190565b6040518181016001600160401b038111828210171562000a4f57600080fd5b604052919050565b6001600160a01b031690565b60805160a05160601c60c05160e051610100516101205161014051610160516101805160601c6101a0516101c05160601c6101e05160601c6102005161022051610240516102605161028051614bb862000b3b60003980611d12525080611d395250806129e25280612a165280612a52525080611d665280611e02525080611d8d5280611de05280611e3052505080610c6a525080610808525080610bb852508061139d525080611379525080610f205250806116a55250806116e75250806116c6525080610b94525080610b1f5250614bb86000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c806374f3b0091161013b578063aaabadc5116100b8578063d5c096c41161007c578063d5c096c4146104e1578063d73dd623146104f4578063dd62ed3e14610507578063f89f27ed1461051a578063ffd088eb1461052257610248565b8063aaabadc5146104a3578063b10be739146104ab578063b48b5b40146104be578063c0ff1a15146104c6578063d505accf146104ce57610248565b80638d928af8116100ff5780638d928af81461046557806395d89b411461046d5780639b02cdde146104755780639d2c110c1461047d578063a9059cbb1461049057610248565b806374f3b009146103f65780637ecebe0014610417578063851c1bb31461042a57806387ec68171461043d578063893d20e81461045057610248565b806338e9922e116101c957806360d1507c1161018d57806360d1507c1461038257806366188463146103a8578063679aefce146103bb5780636b843239146103c357806370a08231146103e357610248565b806338e9922e1461032457806338fff2d0146103375780634a6b0b151461033f57806355c67628146103595780636028bfd41461036157610248565b80631dccd830116102105780631dccd830146102cc57806323b872dd146102ec578063292c914a146102ff578063313ce567146103075780633644e5151461031c57610248565b806306fdde031461024d578063095ea7b31461026b57806316c38b3c1461028b57806318160ddd146102a05780631c0de051146102b5575b600080fd5b61025561052a565b6040516102629190614a93565b60405180910390f35b61027e61027936600461423b565b6105c0565b6040516102629190614970565b61029e6102993660046144a9565b6105d7565b005b6102a86105eb565b6040516102629190614993565b6102bd6105f1565b6040516102629392919061497b565b6102df6102da3660046143ef565b61061a565b6040516102629190614938565b61027e6102fa366004614186565b610722565b61029e6107a5565b61030f6107d9565b6040516102629190614aff565b6102a86107de565b61029e61033236600461484b565b6107ed565b6102a8610806565b61034761082a565b60405161026296959493929190614a69565b6102a8610885565b61037461036f3660046144e1565b610892565b604051610262929190614ae6565b61039561039036600461484b565b6108c3565b6040516102629796959493929190614a39565b61027e6103b636600461423b565b61090c565b6102a8610966565b6103d66103d1366004614331565b61098b565b60405161026291906148f4565b6102a86103f1366004614132565b610a3c565b6104096104043660046144e1565b610a5b565b60405161026292919061494b565b6102a8610425366004614132565b610b00565b6102a86104383660046145dd565b610b1b565b61037461044b3660046144e1565b610b6d565b610458610b92565b60405161026291906148e0565b610458610bb6565b610255610bda565b6102a8610c3b565b6102a861048b366004614750565b610c41565b61027e61049e36600461423b565b610df0565b610458610dfd565b6102a86104b9366004614734565b610e07565b6102a8610e29565b6102a8610e2f565b61029e6104dc3660046141c6565b610eeb565b6104096104ef3660046144e1565b611034565b61027e61050236600461423b565b611154565b6102a861051536600461414e565b61118a565b6102df6111b5565b6102a86111bf565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105b65780601f1061058b576101008083540402835291602001916105b6565b820191906000526020600020905b81548152906001019060200180831161059957829003601f168201915b5050505050905090565b60006105cd338484611246565b5060015b92915050565b6105df6112ae565b6105e8816112dc565b50565b60025490565b60008060006105fe61135a565b159250610609611377565b915061061361139b565b9050909192565b606081516001600160401b038111801561063357600080fd5b5060405190808252806020026020018201604052801561065d578160200160208202803683370190505b509050600061066d6008546113bf565b9050610677613ffe565b60005b845181101561071a5784818151811061068f57fe5b602002602001015191506106ad82602001516000141561013c6113cc565b60006106c883600001518585602001518660400151016113de565b905060006106df84600001518686604001516113de565b90506106f98460200151838303816106f357fe5b05611524565b86848151811061070557fe5b6020908102919091010152505060010161067a565b505050919050565b6001600160a01b038316600081815260016020908152604080832033808552925282205491926107609114806107585750838210155b6101976113cc565b61076b858585611537565b336001600160a01b0386161480159061078657506000198114155b15610798576107988533858403611246565b60019150505b9392505050565b6107ad611606565b6107b56112ae565b6107bf6001611619565b60006107c96105eb565b11156107d7576107d7611659565b565b601290565b60006107e86116a1565b905090565b6107f56112ae565b6107fd611606565b6105e88161173e565b7f000000000000000000000000000000000000000000000000000000000000000090565b60008060008060008060006008549050610843816117a7565b965061084e816117b3565b9550610859816117c0565b9450610864816113bf565b935061086f816117cd565b925061087a816117da565b915050909192939495565b60006107e86008546117da565b600060606108a2865160026117e7565b6108b7898989898989896117f46118ae61192c565b97509795505050505050565b60008060008060008060006108de610400891061013b6113cc565b60006108e989611a4b565b90506108f481611a5d565b959f949e50929c50909a509850965090945092505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106109485761094333856000611246565b61095c565b61095c338561095784876111f4565b611246565b5060019392505050565b60006107e86109736105eb565b61098561097e610e2f565b6002611ac0565b90611ae4565b606081516001600160401b03811180156109a457600080fd5b506040519080825280602002602001820160405280156109ce578160200160208202803683370190505b50905060006109de6008546113bf565b90506109e8614020565b60005b845181101561071a57848181518110610a0057fe5b60200260200101519150610a1d82600001518484602001516113de565b848281518110610a2957fe5b60209081029190910101526001016109eb565b6001600160a01b0381166000908152602081905260409020545b919050565b60608088610a85610a6a610bb6565b6001600160a01b0316336001600160a01b03161460cd6113cc565b610a9a610a90610806565b82146101f46113cc565b610aa387611b35565b6000606080610ab78d8d8d8d8d8d8d6117f4565b925092509250610ac78c84611b97565b610ad0826118ae565b610ad9816118ae565b610ae161135a565b15610aee57610aee611659565b909c909b509950505050505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f000000000000000000000000000000000000000000000000000000000000000082604051602001610b5092919061489d565b604051602081830303815290604052805190602001209050919050565b60006060610b7d865160026117e7565b6108b789898989898989611c2a611cab61192c565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156105b65780601f1061058b576101008083540402835291602001916105b6565b60095490565b6000610c4b611606565b8360800151610c5b610a6a610bb6565b610c66610a90610806565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686602001516001600160a01b03161490506000610cae82611d09565b90506000610cbc8315611d09565b90506000610cc984611d5d565b90506000610cd78515611d5d565b9050610ce38985611db1565b9850610cef8884611db1565b9750610d188a60a0015186610d045789610d06565b8a5b87610d11578b610d13565b8a5b611dbd565b60008a516001811115610d2757fe5b1415610d95576000610d45610d3a610885565b60608d015190611ec3565b9050610d67610d61828d606001516111f490919063ffffffff16565b86611db1565b60608c01526000610d7b8c8c8c8787611f07565b9050610d878186611f26565b985050505050505050610de8565b610da38a6060015184611db1565b60608b01526000610db78b8b8b8686611f32565b9050610dc38186611f45565b9050610ddf610dd8610dd3610885565b611f51565b8290611f77565b97505050505050505b509392505050565b60006105cd338484611537565b60006107e8611fb9565b600080610e1e83610e196008546113bf565b612033565b905061079e81611524565b61040090565b60006060610e3b610bb6565b6001600160a01b031663f94d4668610e51610806565b6040518263ffffffff1660e01b8152600401610e6d9190614993565b60006040518083038186803b158015610e8557600080fd5b505afa158015610e99573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec19190810190614266565b50915050610ece81611b35565b6060610ed861206a565b9050610ee481836120d8565b9250505090565b610ef98442111560d16113cc565b6001600160a01b0387166000908152600560209081526040808320549051909291610f50917f0000000000000000000000000000000000000000000000000000000000000000918c918c918c9188918d91016149bb565b6040516020818303038152906040528051906020012090506000610f738261214a565b9050600060018288888860405160008152602001604052604051610f9a9493929190614a1b565b6020604051602081039080840390855afa158015610fbc573d6000803e3d6000fd5b5050604051601f1901519150610ffe90506001600160a01b03821615801590610ff657508b6001600160a01b0316826001600160a01b0316145b6101f86113cc565b6001600160a01b038b1660009081526005602052604090206001850190556110278b8b8b611246565b5050505050505050505050565b60608088611043610a6a610bb6565b61104e610a90610806565b611056611606565b60006110606105eb565b6110d0576110708b8b8b88612166565b94509050611085620f424082101560cc6113cc565b6110936000620f42406121ef565b6110a289620f424083036121ef565b6110ab84611cab565b604080516002808252606082018352909160208301908036833701905050925061113e565b6110d988611b35565b61110c87896000815181106110ea57fe5b60200260200101518a6001815181106110ff57fe5b6020026020010151611dbd565b61111b8b8b8b8b8b8b8b611c2a565b9095509350905061112c89826121ef565b61113584611cab565b61113e836118ae565b611146611659565b505097509795505050505050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916105cd91859061095790866111c6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606107e861206a565b6201de2090565b600082820161079e84821015836113cc565b600061079e8383605561120a565b600061079e83836056611231565b60006112048383111560016113cc565b50900390565b60006001821b1984168284611220576000611223565b60015b60ff16901b17949350505050565b6001600160401b03811b1992909216911b1790565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906112a1908590614993565b60405180910390a3505050565b60006112c56000356001600160e01b031916610b1b565b90506105e86112d48233612285565b6101916113cc565b80156112fc576112f76112ed611377565b42106101936113cc565b611311565b61131161130761139b565b42106101a96113cc565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be649061134f908390614970565b60405180910390a150565b600061136461139b565b4211806107e857505060065460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006105d182604b612375565b816113da576113da8161237d565b5050565b60006113ef824210156101386113cc565b4282900360006113fe85611a4b565b9050600061140b826123d0565b905061141c600082116101396113cc565b8281116114485780830380611431848a6123dc565b0261143c848a612420565b0194505050505061079e565b600061145387612464565b9050600061146082611a4b565b9050600061146d826123d0565b905061147e600082116101396113cc565b61148d8682111561013a6113cc565b505060008061149c8684612471565b9150915060006114ab836123d0565b6114b4836123d0565b039050801561150c5760006114c9848d612420565b6114d3848e612420565b03905060006114e1856123d0565b8903905082818302816114f057fe5b056114fb868f612420565b01995050505050505050505061079e565b611516838c612420565b97505050505050505061079e565b60006105d1655af3107a40008302612524565b6001600160a01b03831660009081526020819052604090205461155f828210156101966113cc565b6115766001600160a01b03841615156101996113cc565b6001600160a01b038085166000908152602081905260408082208585039055918516815220546115a690836111c6565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906115f8908690614993565b60405180910390a350505050565b6107d761161161135a565b6101926113cc565b60085461162690826111d8565b6008556040517f3e350b41e86a8e10f804ade6d35340d620be35569cc75ac943e8bb14ab80ead19061134f908390614970565b600854611665816117cd565b156105e85761167f611678600954612901565b8290612945565b905061169b61169461168f6105eb565b612901565b8290612952565b60085550565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061170e612960565b306040516020016117239594939291906149ef565b60405160208183030381529060405280519060200120905090565b61175164e8d4a5100082101560cb6113cc565b61176767016345785d8a000082111560ca6113cc565b60085461177490826111e6565b6008556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc9061134f908390614993565b60006105d18282612964565b60006105d1826016612964565b60006105d182602c61298b565b60006105d1826055612995565b60006105d182605661299f565b6113da81831460676113cc565b6000606080606061180361206a565b905061180d61135a565b156118555761182387896000815181106110ea57fe5b600061182f828a6120d8565b90506118408983600954848b6129ac565b925061184f89846111f4612a90565b50611876565b60408051600280825260608201835290916020830190803683370190505091505b611881888287612b22565b909450925061189388846111f4612a90565b61189d81896120d8565b600955509750975097945050505050565b6118d5816000815181106118be57fe5b60200260200101516118d06001611d09565b612b8f565b816000815181106118e257fe5b602002602001018181525050611910816001815181106118fe57fe5b60200260200101516118d06000611d09565b8160018151811061191d57fe5b60200260200101818152505050565b3330146119ea576000306001600160a01b03166000366040516119509291906148b5565b6000604051808303816000865af19150503d806000811461198d576040519150601f19603f3d011682016040523d82523d6000602084013e611992565b606091505b5050905080600081146119a157fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146119cc573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b6119f386611b35565b60006060611a0a8b8b8b8b8b8b8b8b63ffffffff16565b5091509150611a1c818463ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b505050505050505050565b60009081526007602052604090205490565b6000806000806000806000611a7188612baf565b9650611a7c88612bbc565b9550611a8788612bc9565b9450611a9288612bd6565b9350611a9d88612be3565b9250611aa888612bf0565b9150611ab3886123d0565b9050919395979092949650565b600082820261079e841580611add575083858381611ada57fe5b04145b60036113cc565b6000611af382151560046113cc565b82611b00575060006105d1565b670de0b6b3a764000083810290611b2390858381611b1a57fe5b041460056113cc565b828181611b2c57fe5b049150506105d1565b611b5c81600081518110611b4557fe5b6020026020010151611b576001611d09565b611ac0565b81600081518110611b6957fe5b60200260200101818152505061191081600181518110611b8557fe5b6020026020010151611b576000611d09565b6001600160a01b038216600090815260208190526040902054611bbf828210156101966113cc565b6001600160a01b03831660009081526020819052604090208282039055600254611be990836111f4565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906112a1908690614993565b60006060806060611c3961206a565b90506000611c47828a6120d8565b90506060611c5a8a84600954858c6129ac565b9050611c698a826111f4612a90565b60006060611c788c868b612bfd565b91509150611c898c826111c6612a90565b611c93858d6120d8565b600955909e909d50909b509950505050505050505050565b611cd281600081518110611cbb57fe5b6020026020010151611ccd6001611d09565b612c57565b81600081518110611cdf57fe5b60200260200101818152505061191081600181518110611cfb57fe5b6020026020010151611ccd60005b600081611d36577f00000000000000000000000000000000000000000000000000000000000000006105d1565b507f0000000000000000000000000000000000000000000000000000000000000000919050565b600081611d8a577f00000000000000000000000000000000000000000000000000000000000000006105d1565b507f0000000000000000000000000000000000000000000000000000000000000000919050565b600061079e8383611ac0565b600854611dc9816117cd565b8015611dd457508343115b15611ebd576000611e277f0000000000000000000000000000000000000000000000000000000000000000857f000000000000000000000000000000000000000000000000000000000000000086612c8a565b90506000611e5e7f000000000000000000000000000000000000000000000000000000000000000086611e59866117b3565b612cbf565b90506000611e6b846113bf565b90506000611e78856117c0565b90506000611e9182848787611e8c8b6117a7565b612cdb565b9050808314611a4057611ea48682612d32565b9550611eb08642612d40565b6008819055955050505050505b50505050565b6000828202611edd841580611add575083858381611ada57fe5b80611eec5760009150506105d1565b670de0b6b3a764000060001982015b046001019150506105d1565b6000611f1a858486858a60600151612d4e565b90505b95945050505050565b600061079e8383612b8f565b6000611f1a858486858a60600151612dc9565b600061079e8383612c57565b6000670de0b6b3a76400008210611f695760006105d1565b50670de0b6b3a76400000390565b6000611f8682151560046113cc565b82611f93575060006105d1565b670de0b6b3a764000083810290611fad90858381611b1a57fe5b826001820381611efb57fe5b6000611fc3610bb6565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611ffb57600080fd5b505afa15801561200f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e89190614605565b60008061203f83611a4b565b9050612058600061204f836123d0565b116101396113cc565b61206281856123dc565b949350505050565b6040805160028082526060808301845292839291906020830190803683370190505090506120986001611d5d565b816000815181106120a557fe5b6020026020010181815250506120bb6000611d5d565b816001815181106120c857fe5b6020908102919091010152905090565b670de0b6b3a764000060005b835181101561213a576121306121298583815181106120ff57fe5b602002602001015185848151811061211357fe5b6020026020010151612e3f90919063ffffffff16565b8390612e8e565b91506001016120e4565b506105d1600082116101376113cc565b60006121546116a1565b82604051602001610b509291906148c5565b60006060600061217584612eba565b9050612190600082600281111561218857fe5b1460ce6113cc565b606061219b85612ed0565b90506121a9815160026117e7565b6121b281611b35565b60606121bc61206a565b905060006121ca82846120d8565b905060006121d9826002611ac0565b6009929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461221290826111c6565b6001600160a01b03831660009081526020819052604090205560025461223890826111c6565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612279908590614993565b60405180910390a35050565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b6122a4610b92565b6001600160a01b0316141580156122bf57506122bf83612ee6565b156122e7576122cc610b92565b6001600160a01b0316336001600160a01b03161490506105d1565b6122ef611fb9565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b815260040161231e9392919061499c565b60206040518083038186803b15801561233657600080fd5b505afa15801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e91906144c5565b90506105d1565b1c6103ff1690565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006105d1828261298b565b6000808260028111156123eb57fe5b14156123fa5761236e83612baf565b600182600281111561240857fe5b14156124175761236e83612bc9565b61236e83612be3565b60008082600281111561242f57fe5b141561243e5761236e83612bbc565b600182600281111561244c57fe5b141561245b5761236e83612bd6565b61236e83612bf0565b60006105d1826001612f00565b600080806103ff8180805b8385116124e857600285850104612493818a612f00565b935061249e84611a4b565b92506124a9836123d0565b9150898210156124be578060010195506124e2565b898211156124d1576001810394506124e2565b82839750975050505050505061251d565b5061247c565b888110612506576125006124fb84612f11565b611a4b565b82612513565b816125136124fb85612464565b9650965050505050505b9250929050565b6000612553680238fd42c5cf03ffff19831215801561254c575068070c1cc73b00c800008313155b60096113cc565b60008212156125865761256882600003612524565b6a0c097ce7bc90715b34b9f160241b8161257e57fe5b059050610a56565b60006806f05b59d3b200000083126125c657506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec6302628270000000006125fc565b6803782dace9d900000083126125f857506803782dace9d8ffffff19909101906b1425982cf597cd205cef73806125fc565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac62000000841261264c5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412612688576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b1880000084126126c257682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c40000084126126fc576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac6200000841261273557680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d63100000841261276e5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b188000084126127a7576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c4000084126127e05768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b60008061290d83612f1e565b9050655af3107a40006000821361292c57652d79883d20008203612936565b652d79883d200082015b8161293d57fe5b059392505050565b600061079e838383612f7a565b600061079e83836016612f7a565b4690565b600082821c623fffff16621fffff811361297e5780612062565b623fffff19179392505050565b1c637fffffff1690565b1c60019081161490565b1c6001600160401b031690565b604080516002808252606080830184529283929190602083019080368337019050509050826129dc579050611f1d565b612a4f877f000000000000000000000000000000000000000000000000000000000000000081518110612a0b57fe5b6020026020010151877f000000000000000000000000000000000000000000000000000000000000000081518110612a3f57fe5b6020026020010151878787612f91565b817f000000000000000000000000000000000000000000000000000000000000000081518110612a7b57fe5b60209081029190910101529695505050505050565b612ac683600081518110612aa057fe5b602002602001015183600081518110612ab557fe5b60200260200101518363ffffffff16565b83600081518110612ad357fe5b602002602001018181525050612b0483600181518110612aef57fe5b602002602001015183600181518110612ab557fe5b83600181518110612b1157fe5b602002602001018181525050505050565b600060606000612b3184612eba565b90506000816002811115612b4157fe5b1415612b5c57612b52868686613009565b9250925050612b87565b6001816002811115612b6a57fe5b1415612b7a57612b5286856130b9565b612b528686866130eb565b505b935093915050565b6000612b9e82151560046113cc565b818381612ba757fe5b049392505050565b60006105d18260ea612964565b60006105d18260b5613157565b60006105d182609f612964565b60006105d182606a613157565b60006105d1826054612964565b60006105d182601f613157565b600060606000612c0c84612eba565b90506001816002811115612c1c57fe5b1415612c2d57612b5286868661318a565b6002816002811115612c3b57fe5b1415612c4c57612b528686866131e0565b612b8561013661237d565b6000612c6682151560046113cc565b82612c73575060006105d1565b816001840381612c7f57fe5b0460010190506105d1565b600080612caa612c9a8486611f77565b612ca48789611f77565b90611f77565b9050612cb581612901565b9695505050505050565b600080612ccf61168f8587611f77565b92909203949350505050565b600080612cf785858542612cee8b611a4b565b93929190613263565b9050607842889003101580612d0c5786612d15565b612d1587612464565b600081815260076020526040902092909255509695505050505050565b600061079e8383604b6132b5565b600061079e8383602c6132c5565b6000612d70612d6587670429d069189e0000612e8e565b8311156101306113cc565b6000612d7c87846111c6565b90506000612d8a8883611f77565b90506000612d988887611ae4565b90506000612da683836132d7565b9050612dbb612db482611f51565b8990612e8e565b9a9950505050505050505050565b6000612deb612de085670429d069189e0000612e8e565b8311156101316113cc565b6000612e01612dfa86856111f4565b8690611f77565b90506000612e0f8588611f77565b90506000612e1d83836132d7565b90506000612e3382670de0b6b3a76400006111f4565b9050612dbb8a82611ec3565b600080612e4c8484613303565b90506000612e66612e5f83612710611ec3565b60016111c6565b905080821015612e7b576000925050506105d1565b612e8582826111f4565b925050506105d1565b6000828202612ea8841580611add575083858381611ada57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906105d19190614621565b60608180602001905181019061079e91906146e6565b6000612ef8631c74c91760e11b610b1b565b909114919050565b60006104008383015b069392505050565b60006105d1826001613404565b6000612f2e6000831360646113cc565b670c7d713b49da000082138015612f4c5750670f43fc2c04ee000082125b15612f6a57670de0b6b3a7640000612f6383613413565b8161257e57fe5b612f7382613531565b9050610a56565b623fffff828116821b90821b198416179392505050565b6000838311612fa257506000611f1d565b6000612fae8585611f77565b90506000612fc4670de0b6b3a764000088611ae4565b9050612fd8826709b6e64a8ec600006138d0565b91506000612fe683836132d7565b90506000612ffd612ff683611f51565b8b90612e8e565b9050612dbb8187612e8e565b60006060613015611606565b600080613021856138e7565b915091506130336002821060646113cc565b604080516002808252606080830184529260208301908036833701905050905061309488838151811061306257fe5b602002602001015188848151811061307657fe5b6020026020010151856130876105eb565b61308f610885565b613909565b8183815181106130a057fe5b6020908102919091010152919791965090945050505050565b6000606060006130c8846139c0565b905060606130de86836130d96105eb565b6139d6565b9196919550909350505050565b600060606130f7611606565b6060600061310485613a87565b91509150613114825160026117e7565b61311d82611b35565b600061313a88888561312d6105eb565b613135610885565b613a9f565b905061314a8282111560cf6113cc565b9791965090945050505050565b600082821c661fffffffffffff16660fffffffffffff81136131795780612062565b661fffffffffffff19179392505050565b6000606080600061319a85613a87565b915091506131aa825160026117e7565b6131b382611b35565b60006131d08888856131c36105eb565b6131cb610885565b613cca565b905061314a8282101560d06113cc565b600060606000806131f0856138e7565b915091506132026002821060646113cc565b604080516002808252606080830184529260208301908036833701905050905061309488838151811061323157fe5b602002602001015188848151811061324557fe5b6020026020010151856132566105eb565b61325e610885565b613eda565b60008061326f876123d0565b83039050600081870261328189612bbc565b01905060008287026132928a612bd6565b01905060008387026132a38b612bf0565b019050612dbb89848a858b868c613f7c565b6103ff811b1992909216911b1790565b637fffffff811b1992909216911b1790565b6000806132e48484613303565b905060006132f7612e5f83612710611ec3565b9050611f1d82826111c6565b6000816133195750670de0b6b3a76400006105d1565b82613326575060006105d1565b613337600160ff1b841060066113cc565b8261335d770bce5086492111aea88f4bb1ca6bcf584181ea8059f76532841060076113cc565b826000670c7d713b49da00008313801561337e5750670f43fc2c04ee000083125b156133b557600061338e84613413565b9050670de0b6b3a764000080820784020583670de0b6b3a7640000830502019150506133c3565b816133bf84613531565b0290505b670de0b6b3a764000090056133fb680238fd42c5cf03ffff1982128015906133f4575068070c1cc73b00c800008213155b60086113cc565b612cb581612524565b60006104008284038101612f09565b670de0b6b3a7640000026000806a0c097ce7bc90715b34b9f160241b808401906ec097ce7bc90715b34b9f0fffffffff198501028161344e57fe5b05905060006a0c097ce7bc90715b34b9f160241b82800205905081806a0c097ce7bc90715b34b9f160241b81840205915060038205016a0c097ce7bc90715b34b9f160241b82840205915060058205016a0c097ce7bc90715b34b9f160241b82840205915060078205016a0c097ce7bc90715b34b9f160241b82840205915060098205016a0c097ce7bc90715b34b9f160241b828402059150600b8205016a0c097ce7bc90715b34b9f160241b828402059150600d8205016a0c097ce7bc90715b34b9f160241b828402059150600f826002919005919091010295945050505050565b6000670de0b6b3a764000082121561356d57613563826a0c097ce7bc90715b34b9f160241b8161355d57fe5b05613531565b6000039050610a56565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c000000000000083126135be57770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e00000083126135f6576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff0084000831261363e576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a7008312613679576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf85083126136b057693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e283126136e757690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d03831261371c5768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb41746121110831261374757680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d831261377c576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f177578893793783126137b1576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b28660383126137e5576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac8312613819576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d63100000808603028161383c57fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000818310156138e0578161079e565b5090919050565b600080828060200190518101906138fe91906146b0565b909590945092505050565b60008061391a84612ca481886111f4565b90506139336709b6e64a8ec600008210156101326113cc565b600061395161394a670de0b6b3a764000089611ae4565b83906132d7565b9050600061396861396183611f51565b8a90612e8e565b9050600061397589611f51565b905060006139838383611ec3565b9050600061399184836111f4565b90506139b06139a96139a28a611f51565b8490612e8e565b82906111c6565b9c9b505050505050505050505050565b60008180602001905181019061079e9190614683565b606060006139e48484611ae4565b9050606085516001600160401b03811180156139ff57600080fd5b50604051908082528060200260200182016040528015613a29578160200160208202803683370190505b50905060005b8651811015613a7d57613a5e83888381518110613a4857fe5b6020026020010151612e8e90919063ffffffff16565b828281518110613a6a57fe5b6020908102919091010152600101613a2f565b5095945050505050565b60606000828060200190518101906138fe919061463d565b6000606084516001600160401b0381118015613aba57600080fd5b50604051908082528060200260200182016040528015613ae4578160200160208202803683370190505b5090506000805b8851811015613ba957613b44898281518110613b0357fe5b6020026020010151612ca4898481518110613b1a57fe5b60200260200101518c8581518110613b2e57fe5b60200260200101516111f490919063ffffffff16565b838281518110613b5057fe5b602002602001018181525050613b9f613b98898381518110613b6e57fe5b6020026020010151858481518110613b8257fe5b6020026020010151611ec390919063ffffffff16565b83906111c6565b9150600101613aeb565b50670de0b6b3a764000060005b8951811015613ca9576000848281518110613bcd57fe5b6020026020010151841115613c2b576000613bf6613bea86611f51565b8d8581518110613a4857fe5b90506000613c0a828c8681518110613b2e57fe5b9050613c22613b98613c1b8b611f51565b8390611f77565b92505050613c42565b888281518110613c3757fe5b602002602001015190505b6000613c6b8c8481518110613c5357fe5b6020026020010151610985848f8781518110613b2e57fe5b9050613c9d613c968c8581518110613c7f57fe5b602002602001015183612e3f90919063ffffffff16565b8590612e8e565b93505050600101613bb6565b50613cbd613cb682611f51565b8790611ec3565b9998505050505050505050565b6000606084516001600160401b0381118015613ce557600080fd5b50604051908082528060200260200182016040528015613d0f578160200160208202803683370190505b5090506000805b8851811015613db757613d6f898281518110613d2e57fe5b6020026020010151610985898481518110613d4557fe5b60200260200101518c8581518110613d5957fe5b60200260200101516111c690919063ffffffff16565b838281518110613d7b57fe5b602002602001018181525050613dad613b98898381518110613d9957fe5b6020026020010151858481518110613a4857fe5b9150600101613d16565b50670de0b6b3a764000060005b8951811015613e9857600083858381518110613ddc57fe5b60200260200101511115613e38576000613e01613bea86670de0b6b3a76400006111f4565b90506000613e15828c8681518110613b2e57fe5b9050613e2f613b98612129670de0b6b3a76400008c6111f4565b92505050613e4f565b888281518110613e4457fe5b602002602001015190505b6000613e788c8481518110613e6057fe5b6020026020010151610985848f8781518110613d5957fe5b9050613e8c613c968c8581518110613c7f57fe5b93505050600101613dc4565b50670de0b6b3a76400008110613ece57613ec4613ebd82670de0b6b3a76400006111f4565b8790612e8e565b9350505050611f1d565b60009350505050611f1d565b600080613eeb84612ca481886111c6565b9050613f046729a2241af62c00008211156101336113cc565b6000613f1b61394a670de0b6b3a764000089611f77565b90506000613f3b613f3483670de0b6b3a76400006111f4565b8a90611ec3565b90506000613f4889611f51565b90506000613f568383611ec3565b90506000613f6484836111f4565b90506139b06139a9613f758a611f51565b8490611f77565b6000613f888282613fdc565b613f9384601f613fe0565b613f9e866054613ff1565b613fa988606a613fe0565b613fb48a609f613ff1565b613fbf8c60b5613fe0565b613fca8e60ea613ff1565b17171717171798975050505050505050565b1b90565b661fffffffffffff91909116901b90565b623fffff91909116901b90565b6040805160608101909152806000815260200160008152602001600081525090565b604080518082019091526000808252602082015290565b80356105d181614b52565b600082601f830112614052578081fd5b815161406561406082614b33565b614b0d565b81815291506020808301908481018184028601820187101561408657600080fd5b60005b848110156140a557815184529282019290820190600101614089565b505050505092915050565b600082601f8301126140c0578081fd5b81356001600160401b038111156140d5578182fd5b6140e8601f8201601f1916602001614b0d565b91508082528360208285010111156140ff57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106105d157600080fd5b80356105d181614b75565b600060208284031215614143578081fd5b813561079e81614b52565b60008060408385031215614160578081fd5b823561416b81614b52565b9150602083013561417b81614b52565b809150509250929050565b60008060006060848603121561419a578081fd5b83356141a581614b52565b925060208401356141b581614b52565b929592945050506040919091013590565b600080600080600080600060e0888a0312156141e0578485fd5b87356141eb81614b52565b965060208801356141fb81614b52565b95506040880135945060608801359350608088013560ff8116811461421e578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561424d578182fd5b823561425881614b52565b946020939093013593505050565b60008060006060848603121561427a578081fd5b83516001600160401b0380821115614290578283fd5b818601915086601f8301126142a3578283fd5b81516142b161406082614b33565b80828252602080830192508086018b8283870289010111156142d1578788fd5b8796505b848710156142fc5780516142e881614b52565b8452600196909601959281019281016142d5565b508901519097509350505080821115614313578283fd5b5061432086828701614042565b925050604084015190509250925092565b60006020808385031215614343578182fd5b82356001600160401b03811115614358578283fd5b8301601f81018513614368578283fd5b803561437661406082614b33565b818152838101908385016040808502860187018a1015614394578788fd5b8795505b848610156143e15780828b0312156143ae578788fd5b6143b781614b0d565b6143c18b84614127565b815282880135888201528452600195909501949286019290810190614398565b509098975050505050505050565b60006020808385031215614401578182fd5b82356001600160401b03811115614416578283fd5b8301601f81018513614426578283fd5b803561443461406082614b33565b818152838101908385016060808502860187018a1015614452578788fd5b8795505b848610156143e15780828b03121561446c578788fd5b61447581614b0d565b61447f8b84614127565b81528288013588820152604080840135908201528452600195909501949286019290810190614456565b6000602082840312156144ba578081fd5b813561079e81614b67565b6000602082840312156144d6578081fd5b815161079e81614b67565b600080600080600080600060e0888a0312156144fb578081fd5b8735965060208089013561450e81614b52565b9650604089013561451e81614b52565b955060608901356001600160401b0380821115614539578384fd5b818b0191508b601f83011261454c578384fd5b813561455a61406082614b33565b8082825285820191508585018f878886028801011115614578578788fd5b8795505b8386101561459a57803583526001959095019491860191860161457c565b509850505060808b0135955060a08b0135945060c08b01359250808311156145c0578384fd5b50506145ce8a828b016140b0565b91505092959891949750929550565b6000602082840312156145ee578081fd5b81356001600160e01b03198116811461079e578182fd5b600060208284031215614616578081fd5b815161079e81614b52565b600060208284031215614632578081fd5b815161079e81614b75565b600080600060608486031215614651578081fd5b835161465c81614b75565b60208501519093506001600160401b03811115614677578182fd5b61432086828701614042565b60008060408385031215614695578182fd5b82516146a081614b75565b6020939093015192949293505050565b6000806000606084860312156146c4578081fd5b83516146cf81614b75565b602085015160409095015190969495509392505050565b600080604083850312156146f8578182fd5b825161470381614b75565b60208401519092506001600160401b0381111561471e578182fd5b61472a85828601614042565b9150509250929050565b600060208284031215614745578081fd5b813561079e81614b75565b600080600060608486031215614764578081fd5b83356001600160401b038082111561477a578283fd5b8186019150610120808389031215614790578384fd5b61479981614b0d565b90506147a58884614118565b81526147b48860208501614037565b60208201526147c68860408501614037565b6040820152606083013560608201526080830135608082015260a083013560a08201526147f68860c08501614037565b60c08201526148088860e08501614037565b60e08201526101008084013583811115614820578586fd5b61482c8a8287016140b0565b9183019190915250976020870135975060409096013595945050505050565b60006020828403121561485c578081fd5b5035919050565b6000815180845260208085019450808401835b8381101561489257815187529582019590820190600101614876565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b8181101561492c57835183529284019291840191600101614910565b50909695505050505050565b60006020825261079e6020830184614863565b60006040825261495e6040830185614863565b8281036020840152611f1d8185614863565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b9586526020860194909452604085019290925260608401521515608083015260a082015260c00190565b6000602080835283518082850152825b81811015614abf57858101830151858201604001528201614aa3565b81811115614ad05783604083870101525b50601f01601f1916929092016040019392505050565b6000838252604060208301526120626040830184614863565b60ff91909116815260200190565b6040518181016001600160401b0381118282101715614b2b57600080fd5b604052919050565b60006001600160401b03821115614b48578081fd5b5060209081020190565b6001600160a01b03811681146105e857600080fd5b80151581146105e857600080fd5b600381106105e857600080fdfea26469706673582212201dbf8d364d926088a19c5f3f5d0ca0ab72cf3eda8f3f78dda45ab2619de4b6d664736f6c63430007010033a264697066735822122062c63a2c3089490a939fe9f20e0e99ef310f04a393c33a92c66f45a3b2cea18064736f6c63430007010033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xC0`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa_\xE18\x03\x80a_\xE1\x839\x81\x01`@\x81\x90Ra\0/\x91a\0MV[``\x1B`\x01`\x01``\x1B\x03\x19\x16`\x80Rbv\xA7\0B\x01`\xA0Ra\0{V[`\0` \x82\x84\x03\x12\x15a\0^W\x80\x81\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0tW\x81\x82\xFD[\x93\x92PPPV[`\x80Q``\x1C`\xA0Qa_;a\0\xA6`\09\x80a\x02!R\x80a\x02KRP\x80a\x02\xA7RPa_;`\0\xF3\xFE`\x80`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`\x046\x10b\0\0RW`\x005`\xE0\x1C\x80c\x15\x96\x01\x9B\x14b\0\0WW\x80c-\xA4|@\x14b\0\0\x86W\x80cf4\xB7S\x14b\0\0\xA0W\x80c\x8D\x92\x8A\xF8\x14b\0\0\xC6W[`\0\x80\xFD[b\0\0nb\0\0h6`\x04b\0\x05HV[b\0\0\xD0V[`@Qb\0\0}\x91\x90b\0\x06\x8FV[`@Q\x80\x91\x03\x90\xF3[b\0\0\x90b\0\x02\x1BV[`@Qb\0\0}\x92\x91\x90b\0\x07\xA2V[b\0\0\xB7b\0\0\xB16`\x04b\0\x05\"V[b\0\x02\x87V[`@Qb\0\0}\x91\x90b\0\x06\xA3V[b\0\0nb\0\x02\xA5V[`\0\x80`\0b\0\0\xDFb\0\x02\x1BV[\x91P\x91Pb\0\0\xEDb\0\x03\x15V[`@Q\x80a\x01\x80\x01`@R\x80b\0\x01\x03b\0\x02\xA5V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8C\x81R` \x01\x8B\x81R` \x01\x8A`\0\x81Q\x81\x10b\0\x01+W\xFE[` \x02` \x01\x01Q`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8A`\x01\x81Q\x81\x10b\0\x01OW\xFE[` \x02` \x01\x01Q`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x89`\0\x81Q\x81\x10b\0\x01sW\xFE[` \x02` \x01\x01Q\x81R` \x01\x89`\x01\x81Q\x81\x10b\0\x01\x8EW\xFE[` \x02` \x01\x01Q\x81R` \x01\x88\x81R` \x01\x84\x81R` \x01\x83\x81R` \x01\x87\x15\x15\x81R` \x01\x86`\x01`\x01`\xA0\x1B\x03\x16\x81RP\x90P`\0\x81`@Qb\0\x01\xD5\x90b\0\x03\x9CV[b\0\x01\xE1\x91\x90b\0\x06\xAEV[`@Q\x80\x91\x03\x90`\0\xF0\x80\x15\x80\x15b\0\x01\xFEW=`\0\x80>=`\0\xFD[P\x90Pb\0\x02\x0C\x81b\0\x02\xC9V[\x9B\x9APPPPPPPPPPPV[`\0\x80B\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x10\x15b\0\x02yW\x80\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\x92Pb'\x8D\0\x91Pb\0\x02\x82V[`\0\x92P`\0\x91P[P\x90\x91V[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R` \x81\x90R`@\x90 T`\xFF\x16\x90V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16`\0\x81\x81R` \x81\x90R`@\x80\x82 \x80T`\xFF\x19\x16`\x01\x17\x90UQ\x7F\x83\xA4\x8F\xBC\xFC\x99\x1351Nt\xD0Ij\xABj\x19\x87\xE9\x92\xDD\xC8]\xDD\xBC\xC4\xD6\xDDn\xF2\xE9\xFC\x91\x90\xA2PV[`@Q\x80a\x01\x80\x01`@R\x80`\0`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01``\x81R` \x01``\x81R` \x01`\0`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01`\0`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x15\x15\x81R` \x01`\0`\x01`\x01`\xA0\x1B\x03\x16\x81RP\x90V[aV\xF3\x80b\0\x08\x13\x839\x01\x90V[\x805b\0\x03\xB7\x81b\0\x07\xF9V[\x92\x91PPV[`\0\x82`\x1F\x83\x01\x12b\0\x03\xCEW\x80\x81\xFD[\x815b\0\x03\xE5b\0\x03\xDF\x82b\0\x07\xD8V[b\0\x07\xB0V[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15b\0\x04\x07W`\0\x80\xFD[`\0[\x84\x81\x10\x15b\0\x043W\x815b\0\x04 \x81b\0\x07\xF9V[\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01b\0\x04\nV[PPPPP\x92\x91PPV[`\0\x82`\x1F\x83\x01\x12b\0\x04OW\x80\x81\xFD[\x815b\0\x04`b\0\x03\xDF\x82b\0\x07\xD8V[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15b\0\x04\x82W`\0\x80\xFD[`\0[\x84\x81\x10\x15b\0\x043W\x815\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01b\0\x04\x85V[\x805\x80\x15\x15\x81\x14b\0\x03\xB7W`\0\x80\xFD[`\0\x82`\x1F\x83\x01\x12b\0\x04\xC5W\x80\x81\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15b\0\x04\xDCW\x81\x82\xFD[b\0\x04\xF1`\x1F\x82\x01`\x1F\x19\x16` \x01b\0\x07\xB0V[\x91P\x80\x82R\x83` \x82\x85\x01\x01\x11\x15b\0\x05\tW`\0\x80\xFD[\x80` \x84\x01` \x84\x017`\0\x90\x82\x01` \x01R\x92\x91PPV[`\0` \x82\x84\x03\x12\x15b\0\x054W\x80\x81\xFD[\x815b\0\x05A\x81b\0\x07\xF9V[\x93\x92PPPV[`\0\x80`\0\x80`\0\x80`\0`\xE0\x88\x8A\x03\x12\x15b\0\x05cW\x82\x83\xFD[\x875g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15b\0\x05{W\x84\x85\xFD[b\0\x05\x89\x8B\x83\x8C\x01b\0\x04\xB4V[\x98P` \x8A\x015\x91P\x80\x82\x11\x15b\0\x05\x9FW\x84\x85\xFD[b\0\x05\xAD\x8B\x83\x8C\x01b\0\x04\xB4V[\x97P`@\x8A\x015\x91P\x80\x82\x11\x15b\0\x05\xC3W\x84\x85\xFD[b\0\x05\xD1\x8B\x83\x8C\x01b\0\x03\xBDV[\x96P``\x8A\x015\x91P\x80\x82\x11\x15b\0\x05\xE7W\x84\x85\xFD[Pb\0\x05\xF6\x8A\x82\x8B\x01b\0\x04>V[\x94PP`\x80\x88\x015\x92Pb\0\x06\x0F\x89`\xA0\x8A\x01b\0\x04\xA3V[\x91Pb\0\x06 \x89`\xC0\x8A\x01b\0\x03\xAAV[\x90P\x92\x95\x98\x91\x94\x97P\x92\x95PV[`\x01`\x01`\xA0\x1B\x03\x16\x90RV[\x15\x15\x90RV[`\0\x81Q\x80\x84R\x81[\x81\x81\x10\x15b\0\x06hW` \x81\x85\x01\x81\x01Q\x86\x83\x01\x82\x01R\x01b\0\x06JV[\x81\x81\x11\x15b\0\x06zW\x82` \x83\x87\x01\x01R[P`\x1F\x01`\x1F\x19\x16\x92\x90\x92\x01` \x01\x92\x91PPV[`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x81R` \x01\x90V[\x90\x15\x15\x81R` \x01\x90V[`\0` \x82Rb\0\x06\xC4` \x83\x01\x84Qb\0\x06.V[` \x83\x01Qa\x01\x80\x80`@\x85\x01Rb\0\x06\xE2a\x01\xA0\x85\x01\x83b\0\x06AV[\x91P`@\x85\x01Q`\x1F\x19\x85\x84\x03\x01``\x86\x01Rb\0\x07\x01\x83\x82b\0\x06AV[\x92PP``\x85\x01Qb\0\x07\x18`\x80\x86\x01\x82b\0\x06.V[P`\x80\x85\x01Qb\0\x07-`\xA0\x86\x01\x82b\0\x06.V[P`\xA0\x85\x01Q`\xC0\x85\x01R`\xC0\x85\x01Q`\xE0\x85\x01R`\xE0\x85\x01Qa\x01\0\x81\x81\x87\x01R\x80\x87\x01Q\x91PPa\x01 \x81\x81\x87\x01R\x80\x87\x01Q\x91PPa\x01@\x81\x81\x87\x01R\x80\x87\x01Q\x91PPa\x01`b\0\x07\x85\x81\x87\x01\x83b\0\x06;V[\x86\x01Q\x90Pb\0\x07\x98\x85\x83\x01\x82b\0\x06.V[P\x90\x94\x93PPPPV[\x91\x82R` \x82\x01R`@\x01\x90V[`@Q\x81\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15b\0\x07\xD0W`\0\x80\xFD[`@R\x91\x90PV[`\0g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15b\0\x07\xEFW\x80\x81\xFD[P` \x90\x81\x02\x01\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x08\x0FW`\0\x80\xFD[PV\xFEa\x02\xA0`@R\x7Fnq\xED\xAE\x12\xB1\xB9\x7FM\x1F`7\x0F\xEF\x10\x10_\xA2\xFA\xAE\x01&\x11J\x16\x9Cd\x84]a&\xC9a\x01 R4\x80\x15b\0\x007W`\0\x80\xFD[P`@Qb\0V\xF38\x03\x80b\0V\xF3\x839\x81\x01`@\x81\x90Rb\0\0Z\x91b\0\x08\x0CV[a\x01\0\x81\x81\x01Qa\x01 \x83\x01Q` \x80\x85\x01Q`@\x80\x87\x01Q\x81Q\x80\x83\x01\x90\x92R`\x01\x82R`1`\xF8\x1B\x82\x85\x01\x90\x81Ra\x01`\x89\x01Q3`\x80R``\x1B`\x01`\x01``\x1B\x03\x19\x16`\xA0R\x83Q\x94\x84\x01\x94\x85 `\xC0R\x91Q\x90\x91 `\xE0R\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0F\x90\x95R\x80Q\x93\x94\x92\x93\x90\x92\x91b\0\0\xF3\x91`\x03\x91\x90b\0\x06\x9FV[P\x80Qb\0\x01\t\x90`\x04\x90` \x84\x01\x90b\0\x06\x9FV[Pb\0\x01!\x91PPbv\xA7\0\x83\x11\x15a\x01\x94b\0\x04\nV[b\0\x015b'\x8D\0\x82\x11\x15a\x01\x95b\0\x04\nV[B\x90\x91\x01a\x01@\x81\x81R\x91\x01a\x01`R\x81\x01Qb\0\x01S\x90b\0\x04\x1FV[`\xE0\x81\x01Qb\0\x01c\x90b\0\x04{V[\x80Q`@Qc\t\xB2v\x0F`\xE0\x1B\x81R`\0\x91`\x01`\x01`\xA0\x1B\x03\x16\x90c\t\xB2v\x0F\x90b\0\x01\x96\x90`\x02\x90`\x04\x01b\0\n\x12V[` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15b\0\x01\xB1W`\0\x80\xFD[PZ\xF1\x15\x80\x15b\0\x01\xC6W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90b\0\x01\xEC\x91\x90b\0\x07\xF3V[`@\x80Q`\x02\x80\x82R``\x80\x83\x01\x84R\x93\x94P\x90\x91` \x83\x01\x90\x806\x837\x01\x90PP\x90P\x82``\x01Q\x81`\0\x81Q\x81\x10b\0\x02#W\xFE[` \x02` \x01\x01\x90`\x01`\x01`\xA0\x1B\x03\x16\x90\x81`\x01`\x01`\xA0\x1B\x03\x16\x81RPP\x82`\x80\x01Q\x81`\x01\x81Q\x81\x10b\0\x02VW\xFE[`\x01`\x01`\xA0\x1B\x03\x92\x83\x16` \x91\x82\x02\x92\x90\x92\x01\x01R\x83Q\x16cf\xA9\xC7\xD2\x83\x83`\x02`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15b\0\x02\xA2W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01b\0\x02\xC3\x93\x92\x91\x90b\0\tvV[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15b\0\x02\xDEW`\0\x80\xFD[PZ\xF1\x15\x80\x15b\0\x02\xF3W=`\0\x80>=`\0\xFD[PP\x84Q`\x01`\x01``\x1B\x03\x19``\x91\x82\x1B\x81\x16a\x01\x80Ra\x01\xA0\x86\x90R\x81\x87\x01\x80Q\x83\x1B\x82\x16a\x01\xC0R`\x80\x88\x01Q\x90\x92\x1B\x16a\x01\xE0RQb\0\x03:\x92P\x90Pb\0\x04\xF9V[a\x02`R`\x80\x83\x01Qb\0\x03N\x90b\0\x04\xF9V[a\x02\x80R`\xA0\x83\x01Qb\0\x03o\x90f#\x86\xF2o\xC1\0\0\x11\x15a\x01.b\0\x04\nV[b\0\x03\x91f#\x86\xF2o\xC1\0\0\x84`\xC0\x01Q\x10\x15a\x01.b\0\x04\n` \x1B` \x1CV[`\0b\0\x03\xB5\x84`\xC0\x01Q\x85`\xA0\x01Qb\0\x05\x9B` \x1Bb\0\x11\xC6\x17\x90\x91\x90` \x1CV[\x90Pb\0\x03\xCFg\r\xE0\xB6\xB3\xA7d\0\0\x82\x14a\x014b\0\x04\nV[`\xA0\x84\x01\x80Qa\x02\0R`\xC0\x85\x01\x80Qa\x02 RQ\x90Q\x10\x15b\0\x03\xF5W`\x01b\0\x03\xF8V[`\0[`\xFF\x16a\x02@RPb\0\nc\x92PPPV[\x81b\0\x04\x1BWb\0\x04\x1B\x81b\0\x05\xB8V[PPV[b\0\x04;\x81`\x08Tb\0\x06\x0B` \x1Bb\0\x11\xD8\x17\x90\x91\x90` \x1CV[`\x08U`@Q\x7F>5\x0BA\xE8j\x8E\x10\xF8\x04\xAD\xE6\xD3S@\xD6 \xBE5V\x9C\xC7Z\xC9C\xE8\xBB\x14\xAB\x80\xEA\xD1\x90b\0\x04p\x90\x83\x90b\0\tkV[`@Q\x80\x91\x03\x90\xA1PV[b\0\x04\x90d\xE8\xD4\xA5\x10\0\x82\x10\x15`\xCBb\0\x04\nV[b\0\x04\xA8g\x01cEx]\x8A\0\0\x82\x11\x15`\xCAb\0\x04\nV[b\0\x04\xC4\x81`\x08Tb\0\x06*` \x1Bb\0\x11\xE6\x17\x90\x91\x90` \x1CV[`\x08U`@Q\x7F\xA9\xBA?\xFE\x0Bl6k\x81#,\xAA\xB3\x86\x05\xA0i\x9A\xD59\x8Dl\xCEv\xF9\x1E\xE8\t\xE3\"\xDA\xFC\x90b\0\x04p\x90\x83\x90b\0\n'V[`\0\x80\x82`\x01`\x01`\xA0\x1B\x03\x16c1<\xE5g`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15b\0\x056W`\0\x80\xFD[PZ\xFA\x15\x80\x15b\0\x05KW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90b\0\x05q\x91\x90b\0\tHV[`\xFF\x16\x90P`\0b\0\x05\x90`\x12\x83b\0\x06I` \x1Bb\0\x11\xF4\x17` \x1CV[`\n\n\x94\x93PPPPV[`\0\x82\x82\x01b\0\x05\xAF\x84\x82\x10\x15\x83b\0\x04\nV[\x90P[\x92\x91PPV[bF\x1B\xCD`\xE5\x1B`\0\x90\x81R` `\x04R`\x07`$RfBAL#\0\x000`\n\x80\x84\x04\x81\x81\x06`0\x90\x81\x01`\x08\x1B\x95\x83\x90\x06\x95\x90\x95\x01\x90\x82\x90\x04\x91\x82\x06\x90\x94\x01`\x10\x1B\x93\x90\x93\x01\x01`\xC8\x1B`DR`d\x90\xFD[`\0b\0\x05\xAF\x82`U\x85b\0\x06a` \x1Bb\0\x12\n\x17\x90\x92\x91\x90` \x1CV[`\0b\0\x05\xAF\x82`V\x85b\0\x06\x8A` \x1Bb\0\x121\x17\x90\x92\x91\x90` \x1CV[`\0b\0\x06[\x83\x83\x11\x15`\x01b\0\x04\nV[P\x90\x03\x90V[`\0`\x01\x82\x1B\x19\x84\x16\x82\x84b\0\x06yW`\0b\0\x06|V[`\x01[`\xFF\x16\x90\x1B\x17\x94\x93PPPPV[`\x01`\x01`@\x1B\x03\x81\x1B\x19\x92\x90\x92\x16\x91\x1B\x17\x90V[\x82\x80T`\x01\x81`\x01\x16\x15a\x01\0\x02\x03\x16`\x02\x90\x04\x90`\0R` `\0 \x90`\x1F\x01` \x90\x04\x81\x01\x92\x82`\x1F\x10b\0\x06\xE2W\x80Q`\xFF\x19\x16\x83\x80\x01\x17\x85Ub\0\x07\x12V[\x82\x80\x01`\x01\x01\x85U\x82\x15b\0\x07\x12W\x91\x82\x01[\x82\x81\x11\x15b\0\x07\x12W\x82Q\x82U\x91` \x01\x91\x90`\x01\x01\x90b\0\x06\xF5V[Pb\0\x07 \x92\x91Pb\0\x07$V[P\x90V[[\x80\x82\x11\x15b\0\x07 W`\0\x81U`\x01\x01b\0\x07%V[\x80Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x05\xB2W`\0\x80\xFD[\x80Q\x80\x15\x15\x81\x14b\0\x05\xB2W`\0\x80\xFD[`\0\x82`\x1F\x83\x01\x12b\0\x07uW\x80\x81\xFD[\x81Q`\x01`\x01`@\x1B\x03\x81\x11\x15b\0\x07\x8BW\x81\x82\xFD[` b\0\x07\xA1`\x1F\x83\x01`\x1F\x19\x16\x82\x01b\0\n0V[\x92P\x81\x83R\x84\x81\x83\x86\x01\x01\x11\x15b\0\x07\xB8W`\0\x80\xFD[`\0[\x82\x81\x10\x15b\0\x07\xD8W\x84\x81\x01\x82\x01Q\x84\x82\x01\x83\x01R\x81\x01b\0\x07\xBBV[\x82\x81\x11\x15b\0\x07\xEAW`\0\x82\x84\x86\x01\x01R[PPP\x92\x91PPV[`\0` \x82\x84\x03\x12\x15b\0\x08\x05W\x80\x81\xFD[PQ\x91\x90PV[`\0` \x82\x84\x03\x12\x15b\0\x08\x1EW\x80\x81\xFD[\x81Q`\x01`\x01`@\x1B\x03\x80\x82\x11\x15b\0\x085W\x82\x83\xFD[\x81\x84\x01\x91Pa\x01\x80\x80\x83\x87\x03\x12\x15b\0\x08LW\x83\x84\xFD[b\0\x08W\x81b\0\n0V[\x90Pb\0\x08e\x86\x84b\0\x07;V[\x81R` \x83\x01Q\x82\x81\x11\x15b\0\x08yW\x84\x85\xFD[b\0\x08\x87\x87\x82\x86\x01b\0\x07dV[` \x83\x01RP`@\x83\x01Q\x82\x81\x11\x15b\0\x08\x9FW\x84\x85\xFD[b\0\x08\xAD\x87\x82\x86\x01b\0\x07dV[`@\x83\x01RPb\0\x08\xC2\x86``\x85\x01b\0\x07;V[``\x82\x01Rb\0\x08\xD6\x86`\x80\x85\x01b\0\x07;V[`\x80\x82\x01R`\xA0\x83\x81\x01Q\x90\x82\x01R`\xC0\x80\x84\x01Q\x90\x82\x01R`\xE0\x80\x84\x01Q\x90\x82\x01Ra\x01\0\x80\x84\x01Q\x90\x82\x01Ra\x01 \x80\x84\x01Q\x90\x82\x01Ra\x01@\x91Pb\0\t\"\x86\x83\x85\x01b\0\x07SV[\x82\x82\x01Ra\x01`\x91Pb\0\t9\x86\x83\x85\x01b\0\x07;V[\x91\x81\x01\x91\x90\x91R\x94\x93PPPPV[`\0` \x82\x84\x03\x12\x15b\0\tZW\x80\x81\xFD[\x81Q`\xFF\x81\x16\x81\x14b\0\x05\xAFW\x81\x82\xFD[\x90\x15\x15\x81R` \x01\x90V[`\0``\x82\x01\x85\x83R` ``\x81\x85\x01R\x81\x86Q\x80\x84R`\x80\x86\x01\x91P\x82\x88\x01\x93P\x84[\x81\x81\x10\x15b\0\t\xC2Wb\0\t\xAF\x85Qb\0\nWV[\x83R\x93\x83\x01\x93\x91\x83\x01\x91`\x01\x01b\0\t\x9AV[PP\x84\x81\x03`@\x86\x01R\x85Q\x80\x82R\x90\x82\x01\x92P\x81\x86\x01\x90\x84[\x81\x81\x10\x15b\0\n\x04Wb\0\t\xF1\x83Qb\0\nWV[\x85R\x93\x83\x01\x93\x91\x83\x01\x91`\x01\x01b\0\t\xDCV[P\x92\x98\x97PPPPPPPPV[` \x81\x01`\x03\x83\x10b\0\n!W\xFE[\x91\x90R\x90V[\x90\x81R` \x01\x90V[`@Q\x81\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\nOW`\0\x80\xFD[`@R\x91\x90PV[`\x01`\x01`\xA0\x1B\x03\x16\x90V[`\x80Q`\xA0Q``\x1C`\xC0Q`\xE0Qa\x01\0Qa\x01 Qa\x01@Qa\x01`Qa\x01\x80Q``\x1Ca\x01\xA0Qa\x01\xC0Q``\x1Ca\x01\xE0Q``\x1Ca\x02\0Qa\x02 Qa\x02@Qa\x02`Qa\x02\x80QaK\xB8b\0\x0B;`\09\x80a\x1D\x12RP\x80a\x1D9RP\x80a)\xE2R\x80a*\x16R\x80a*RRP\x80a\x1DfR\x80a\x1E\x02RP\x80a\x1D\x8DR\x80a\x1D\xE0R\x80a\x1E0RPP\x80a\x0CjRP\x80a\x08\x08RP\x80a\x0B\xB8RP\x80a\x13\x9DRP\x80a\x13yRP\x80a\x0F RP\x80a\x16\xA5RP\x80a\x16\xE7RP\x80a\x16\xC6RP\x80a\x0B\x94RP\x80a\x0B\x1FRPaK\xB8`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x02HW`\x005`\xE0\x1C\x80ct\xF3\xB0\t\x11a\x01;W\x80c\xAA\xAB\xAD\xC5\x11a\0\xB8W\x80c\xD5\xC0\x96\xC4\x11a\0|W\x80c\xD5\xC0\x96\xC4\x14a\x04\xE1W\x80c\xD7=\xD6#\x14a\x04\xF4W\x80c\xDDb\xED>\x14a\x05\x07W\x80c\xF8\x9F'\xED\x14a\x05\x1AW\x80c\xFF\xD0\x88\xEB\x14a\x05\"Wa\x02HV[\x80c\xAA\xAB\xAD\xC5\x14a\x04\xA3W\x80c\xB1\x0B\xE79\x14a\x04\xABW\x80c\xB4\x8B[@\x14a\x04\xBEW\x80c\xC0\xFF\x1A\x15\x14a\x04\xC6W\x80c\xD5\x05\xAC\xCF\x14a\x04\xCEWa\x02HV[\x80c\x8D\x92\x8A\xF8\x11a\0\xFFW\x80c\x8D\x92\x8A\xF8\x14a\x04eW\x80c\x95\xD8\x9BA\x14a\x04mW\x80c\x9B\x02\xCD\xDE\x14a\x04uW\x80c\x9D,\x11\x0C\x14a\x04}W\x80c\xA9\x05\x9C\xBB\x14a\x04\x90Wa\x02HV[\x80ct\xF3\xB0\t\x14a\x03\xF6W\x80c~\xCE\xBE\0\x14a\x04\x17W\x80c\x85\x1C\x1B\xB3\x14a\x04*W\x80c\x87\xECh\x17\x14a\x04=W\x80c\x89= \xE8\x14a\x04PWa\x02HV[\x80c8\xE9\x92.\x11a\x01\xC9W\x80c`\xD1P|\x11a\x01\x8DW\x80c`\xD1P|\x14a\x03\x82W\x80cf\x18\x84c\x14a\x03\xA8W\x80cg\x9A\xEF\xCE\x14a\x03\xBBW\x80ck\x8429\x14a\x03\xC3W\x80cp\xA0\x821\x14a\x03\xE3Wa\x02HV[\x80c8\xE9\x92.\x14a\x03$W\x80c8\xFF\xF2\xD0\x14a\x037W\x80cJk\x0B\x15\x14a\x03?W\x80cU\xC6v(\x14a\x03YW\x80c`(\xBF\xD4\x14a\x03aWa\x02HV[\x80c\x1D\xCC\xD80\x11a\x02\x10W\x80c\x1D\xCC\xD80\x14a\x02\xCCW\x80c#\xB8r\xDD\x14a\x02\xECW\x80c),\x91J\x14a\x02\xFFW\x80c1<\xE5g\x14a\x03\x07W\x80c6D\xE5\x15\x14a\x03\x1CWa\x02HV[\x80c\x06\xFD\xDE\x03\x14a\x02MW\x80c\t^\xA7\xB3\x14a\x02kW\x80c\x16\xC3\x8B<\x14a\x02\x8BW\x80c\x18\x16\r\xDD\x14a\x02\xA0W\x80c\x1C\r\xE0Q\x14a\x02\xB5W[`\0\x80\xFD[a\x02Ua\x05*V[`@Qa\x02b\x91\x90aJ\x93V[`@Q\x80\x91\x03\x90\xF3[a\x02~a\x02y6`\x04aB;V[a\x05\xC0V[`@Qa\x02b\x91\x90aIpV[a\x02\x9Ea\x02\x996`\x04aD\xA9V[a\x05\xD7V[\0[a\x02\xA8a\x05\xEBV[`@Qa\x02b\x91\x90aI\x93V[a\x02\xBDa\x05\xF1V[`@Qa\x02b\x93\x92\x91\x90aI{V[a\x02\xDFa\x02\xDA6`\x04aC\xEFV[a\x06\x1AV[`@Qa\x02b\x91\x90aI8V[a\x02~a\x02\xFA6`\x04aA\x86V[a\x07\"V[a\x02\x9Ea\x07\xA5V[a\x03\x0Fa\x07\xD9V[`@Qa\x02b\x91\x90aJ\xFFV[a\x02\xA8a\x07\xDEV[a\x02\x9Ea\x0326`\x04aHKV[a\x07\xEDV[a\x02\xA8a\x08\x06V[a\x03Ga\x08*V[`@Qa\x02b\x96\x95\x94\x93\x92\x91\x90aJiV[a\x02\xA8a\x08\x85V[a\x03ta\x03o6`\x04aD\xE1V[a\x08\x92V[`@Qa\x02b\x92\x91\x90aJ\xE6V[a\x03\x95a\x03\x906`\x04aHKV[a\x08\xC3V[`@Qa\x02b\x97\x96\x95\x94\x93\x92\x91\x90aJ9V[a\x02~a\x03\xB66`\x04aB;V[a\t\x0CV[a\x02\xA8a\tfV[a\x03\xD6a\x03\xD16`\x04aC1V[a\t\x8BV[`@Qa\x02b\x91\x90aH\xF4V[a\x02\xA8a\x03\xF16`\x04aA2V[a\nV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[`\0\x80`\0\x80`\0\x80`\0`\x08T\x90Pa\x08C\x81a\x17\xA7V[\x96Pa\x08N\x81a\x17\xB3V[\x95Pa\x08Y\x81a\x17\xC0V[\x94Pa\x08d\x81a\x13\xBFV[\x93Pa\x08o\x81a\x17\xCDV[\x92Pa\x08z\x81a\x17\xDAV[\x91PP\x90\x91\x92\x93\x94\x95V[`\0a\x07\xE8`\x08Ta\x17\xDAV[`\0``a\x08\xA2\x86Q`\x02a\x17\xE7V[a\x08\xB7\x89\x89\x89\x89\x89\x89\x89a\x17\xF4a\x18\xAEa\x19,V[\x97P\x97\x95PPPPPPV[`\0\x80`\0\x80`\0\x80`\0a\x08\xDEa\x04\0\x89\x10a\x01;a\x13\xCCV[`\0a\x08\xE9\x89a\x1AKV[\x90Pa\x08\xF4\x81a\x1A]V[\x95\x9F\x94\x9EP\x92\x9CP\x90\x9AP\x98P\x96P\x90\x94P\x92PPPV[3`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 `\x01`\x01`\xA0\x1B\x03\x86\x16\x84R\x90\x91R\x81 T\x80\x83\x10a\tHWa\tC3\x85`\0a\x12FV[a\t\\V[a\t\\3\x85a\tW\x84\x87a\x11\xF4V[a\x12FV[P`\x01\x93\x92PPPV[`\0a\x07\xE8a\tsa\x05\xEBV[a\t\x85a\t~a\x0E/V[`\x02a\x1A\xC0V[\x90a\x1A\xE4V[``\x81Q`\x01`\x01`@\x1B\x03\x81\x11\x80\x15a\t\xA4W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\t\xCEW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\t\xDE`\x08Ta\x13\xBFV[\x90Pa\t\xE8a@ V[`\0[\x84Q\x81\x10\x15a\x07\x1AW\x84\x81\x81Q\x81\x10a\n\0W\xFE[` \x02` \x01\x01Q\x91Pa\n\x1D\x82`\0\x01Q\x84\x84` \x01Qa\x13\xDEV[\x84\x82\x81Q\x81\x10a\n)W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a\t\xEBV[`\x01`\x01`\xA0\x1B\x03\x81\x16`\0\x90\x81R` \x81\x90R`@\x90 T[\x91\x90PV[``\x80\x88a\n\x85a\nja\x0B\xB6V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14`\xCDa\x13\xCCV[a\n\x9Aa\n\x90a\x08\x06V[\x82\x14a\x01\xF4a\x13\xCCV[a\n\xA3\x87a\x1B5V[`\0``\x80a\n\xB7\x8D\x8D\x8D\x8D\x8D\x8D\x8Da\x17\xF4V[\x92P\x92P\x92Pa\n\xC7\x8C\x84a\x1B\x97V[a\n\xD0\x82a\x18\xAEV[a\n\xD9\x81a\x18\xAEV[a\n\xE1a\x13ZV[\x15a\n\xEEWa\n\xEEa\x16YV[\x90\x9C\x90\x9BP\x99PPPPPPPPPPV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R`\x05` R`@\x90 T\x90V[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82`@Q` \x01a\x0BP\x92\x91\x90aH\x9DV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[`\0``a\x0B}\x86Q`\x02a\x17\xE7V[a\x08\xB7\x89\x89\x89\x89\x89\x89\x89a\x1C*a\x1C\xABa\x19,V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[`\x04\x80T`@\x80Q` `\x1F`\x02`\0\x19a\x01\0`\x01\x88\x16\x15\x02\x01\x90\x95\x16\x94\x90\x94\x04\x93\x84\x01\x81\x90\x04\x81\x02\x82\x01\x81\x01\x90\x92R\x82\x81R``\x93\x90\x92\x90\x91\x83\x01\x82\x82\x80\x15a\x05\xB6W\x80`\x1F\x10a\x05\x8BWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x05\xB6V[`\tT\x90V[`\0a\x0CKa\x16\x06V[\x83`\x80\x01Qa\x0C[a\nja\x0B\xB6V[a\x0Cfa\n\x90a\x08\x06V[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x86` \x01Q`\x01`\x01`\xA0\x1B\x03\x16\x14\x90P`\0a\x0C\xAE\x82a\x1D\tV[\x90P`\0a\x0C\xBC\x83\x15a\x1D\tV[\x90P`\0a\x0C\xC9\x84a\x1D]V[\x90P`\0a\x0C\xD7\x85\x15a\x1D]V[\x90Pa\x0C\xE3\x89\x85a\x1D\xB1V[\x98Pa\x0C\xEF\x88\x84a\x1D\xB1V[\x97Pa\r\x18\x8A`\xA0\x01Q\x86a\r\x04W\x89a\r\x06V[\x8A[\x87a\r\x11W\x8Ba\r\x13V[\x8A[a\x1D\xBDV[`\0\x8AQ`\x01\x81\x11\x15a\r'W\xFE[\x14\x15a\r\x95W`\0a\rEa\r:a\x08\x85V[``\x8D\x01Q\x90a\x1E\xC3V[\x90Pa\rga\ra\x82\x8D``\x01Qa\x11\xF4\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x86a\x1D\xB1V[``\x8C\x01R`\0a\r{\x8C\x8C\x8C\x87\x87a\x1F\x07V[\x90Pa\r\x87\x81\x86a\x1F&V[\x98PPPPPPPPa\r\xE8V[a\r\xA3\x8A``\x01Q\x84a\x1D\xB1V[``\x8B\x01R`\0a\r\xB7\x8B\x8B\x8B\x86\x86a\x1F2V[\x90Pa\r\xC3\x81\x86a\x1FEV[\x90Pa\r\xDFa\r\xD8a\r\xD3a\x08\x85V[a\x1FQV[\x82\x90a\x1FwV[\x97PPPPPPP[P\x93\x92PPPV[`\0a\x05\xCD3\x84\x84a\x157V[`\0a\x07\xE8a\x1F\xB9V[`\0\x80a\x0E\x1E\x83a\x0E\x19`\x08Ta\x13\xBFV[a 3V[\x90Pa\x07\x9E\x81a\x15$V[a\x04\0\x90V[`\0``a\x0E;a\x0B\xB6V[`\x01`\x01`\xA0\x1B\x03\x16c\xF9MFha\x0EQa\x08\x06V[`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x0Em\x91\x90aI\x93V[`\0`@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x0E\x85W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x0E\x99W=`\0\x80>=`\0\xFD[PPPP`@Q=`\0\x82>`\x1F=\x90\x81\x01`\x1F\x19\x16\x82\x01`@Ra\x0E\xC1\x91\x90\x81\x01\x90aBfV[P\x91PPa\x0E\xCE\x81a\x1B5V[``a\x0E\xD8a jV[\x90Pa\x0E\xE4\x81\x83a \xD8V[\x92PPP\x90V[a\x0E\xF9\x84B\x11\x15`\xD1a\x13\xCCV[`\x01`\x01`\xA0\x1B\x03\x87\x16`\0\x90\x81R`\x05` \x90\x81R`@\x80\x83 T\x90Q\x90\x92\x91a\x0FP\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x8C\x91\x8C\x91\x8C\x91\x88\x91\x8D\x91\x01aI\xBBV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0a\x0Fs\x82a!JV[\x90P`\0`\x01\x82\x88\x88\x88`@Q`\0\x81R` \x01`@R`@Qa\x0F\x9A\x94\x93\x92\x91\x90aJ\x1BV[` `@Q` \x81\x03\x90\x80\x84\x03\x90\x85Z\xFA\x15\x80\x15a\x0F\xBCW=`\0\x80>=`\0\xFD[PP`@Q`\x1F\x19\x01Q\x91Pa\x0F\xFE\x90P`\x01`\x01`\xA0\x1B\x03\x82\x16\x15\x80\x15\x90a\x0F\xF6WP\x8B`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14[a\x01\xF8a\x13\xCCV[`\x01`\x01`\xA0\x1B\x03\x8B\x16`\0\x90\x81R`\x05` R`@\x90 `\x01\x85\x01\x90Ua\x10'\x8B\x8B\x8Ba\x12FV[PPPPPPPPPPPV[``\x80\x88a\x10Ca\nja\x0B\xB6V[a\x10Na\n\x90a\x08\x06V[a\x10Va\x16\x06V[`\0a\x10`a\x05\xEBV[a\x10\xD0Wa\x10p\x8B\x8B\x8B\x88a!fV[\x94P\x90Pa\x10\x85b\x0FB@\x82\x10\x15`\xCCa\x13\xCCV[a\x10\x93`\0b\x0FB@a!\xEFV[a\x10\xA2\x89b\x0FB@\x83\x03a!\xEFV[a\x10\xAB\x84a\x1C\xABV[`@\x80Q`\x02\x80\x82R``\x82\x01\x83R\x90\x91` \x83\x01\x90\x806\x837\x01\x90PP\x92Pa\x11>V[a\x10\xD9\x88a\x1B5V[a\x11\x0C\x87\x89`\0\x81Q\x81\x10a\x10\xEAW\xFE[` \x02` \x01\x01Q\x8A`\x01\x81Q\x81\x10a\x10\xFFW\xFE[` \x02` \x01\x01Qa\x1D\xBDV[a\x11\x1B\x8B\x8B\x8B\x8B\x8B\x8B\x8Ba\x1C*V[\x90\x95P\x93P\x90Pa\x11,\x89\x82a!\xEFV[a\x115\x84a\x1C\xABV[a\x11>\x83a\x18\xAEV[a\x11Fa\x16YV[PP\x97P\x97\x95PPPPPPV[3`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 `\x01`\x01`\xA0\x1B\x03\x87\x16\x84R\x90\x91R\x81 T\x90\x91a\x05\xCD\x91\x85\x90a\tW\x90\x86a\x11\xC6V[`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 \x93\x90\x94\x16\x82R\x91\x90\x91R T\x90V[``a\x07\xE8a jV[b\x01\xDE \x90V[`\0\x82\x82\x01a\x07\x9E\x84\x82\x10\x15\x83a\x13\xCCV[`\0a\x07\x9E\x83\x83`Ua\x12\nV[`\0a\x07\x9E\x83\x83`Va\x121V[`\0a\x12\x04\x83\x83\x11\x15`\x01a\x13\xCCV[P\x90\x03\x90V[`\0`\x01\x82\x1B\x19\x84\x16\x82\x84a\x12 W`\0a\x12#V[`\x01[`\xFF\x16\x90\x1B\x17\x94\x93PPPPV[`\x01`\x01`@\x1B\x03\x81\x1B\x19\x92\x90\x92\x16\x91\x1B\x17\x90V[`\x01`\x01`\xA0\x1B\x03\x80\x84\x16`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 \x94\x87\x16\x80\x84R\x94\x90\x91R\x90\x81\x90 \x84\x90UQ\x7F\x8C[\xE1\xE5\xEB\xEC}[\xD1OqB}\x1E\x84\xF3\xDD\x03\x14\xC0\xF7\xB2)\x1E[ \n\xC8\xC7\xC3\xB9%\x90a\x12\xA1\x90\x85\x90aI\x93V[`@Q\x80\x91\x03\x90\xA3PPPV[`\0a\x12\xC5`\x005`\x01`\x01`\xE0\x1B\x03\x19\x16a\x0B\x1BV[\x90Pa\x05\xE8a\x12\xD4\x823a\"\x85V[a\x01\x91a\x13\xCCV[\x80\x15a\x12\xFCWa\x12\xF7a\x12\xEDa\x13wV[B\x10a\x01\x93a\x13\xCCV[a\x13\x11V[a\x13\x11a\x13\x07a\x13\x9BV[B\x10a\x01\xA9a\x13\xCCV[`\x06\x80T`\xFF\x19\x16\x82\x15\x15\x17\x90U`@Q\x7F\x9E:^7\"E2\xDE\xA6{\x89\xFA\xCE\x18W\x03s\x8A\"\x8An\x8A#\xDE\xE5F\x96\x01\x80\xD3\xBEd\x90a\x13O\x90\x83\x90aIpV[`@Q\x80\x91\x03\x90\xA1PV[`\0a\x13da\x13\x9BV[B\x11\x80a\x07\xE8WPP`\x06T`\xFF\x16\x15\x90V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[`\0a\x05\xD1\x82`Ka#uV[\x81a\x13\xDAWa\x13\xDA\x81a#}V[PPV[`\0a\x13\xEF\x82B\x10\x15a\x018a\x13\xCCV[B\x82\x90\x03`\0a\x13\xFE\x85a\x1AKV[\x90P`\0a\x14\x0B\x82a#\xD0V[\x90Pa\x14\x1C`\0\x82\x11a\x019a\x13\xCCV[\x82\x81\x11a\x14HW\x80\x83\x03\x80a\x141\x84\x8Aa#\xDCV[\x02a\x14<\x84\x8Aa$ V[\x01\x94PPPPPa\x07\x9EV[`\0a\x14S\x87a$dV[\x90P`\0a\x14`\x82a\x1AKV[\x90P`\0a\x14m\x82a#\xD0V[\x90Pa\x14~`\0\x82\x11a\x019a\x13\xCCV[a\x14\x8D\x86\x82\x11\x15a\x01:a\x13\xCCV[PP`\0\x80a\x14\x9C\x86\x84a$qV[\x91P\x91P`\0a\x14\xAB\x83a#\xD0V[a\x14\xB4\x83a#\xD0V[\x03\x90P\x80\x15a\x15\x0CW`\0a\x14\xC9\x84\x8Da$ V[a\x14\xD3\x84\x8Ea$ V[\x03\x90P`\0a\x14\xE1\x85a#\xD0V[\x89\x03\x90P\x82\x81\x83\x02\x81a\x14\xF0W\xFE[\x05a\x14\xFB\x86\x8Fa$ V[\x01\x99PPPPPPPPPPa\x07\x9EV[a\x15\x16\x83\x8Ca$ V[\x97PPPPPPPPa\x07\x9EV[`\0a\x05\xD1eZ\xF3\x10z@\0\x83\x02a%$V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 Ta\x15_\x82\x82\x10\x15a\x01\x96a\x13\xCCV[a\x15v`\x01`\x01`\xA0\x1B\x03\x84\x16\x15\x15a\x01\x99a\x13\xCCV[`\x01`\x01`\xA0\x1B\x03\x80\x85\x16`\0\x90\x81R` \x81\x90R`@\x80\x82 \x85\x85\x03\x90U\x91\x85\x16\x81R Ta\x15\xA6\x90\x83a\x11\xC6V[`\x01`\x01`\xA0\x1B\x03\x80\x85\x16`\0\x81\x81R` \x81\x90R`@\x90\x81\x90 \x93\x90\x93U\x91Q\x90\x86\x16\x90\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x90a\x15\xF8\x90\x86\x90aI\x93V[`@Q\x80\x91\x03\x90\xA3PPPPV[a\x07\xD7a\x16\x11a\x13ZV[a\x01\x92a\x13\xCCV[`\x08Ta\x16&\x90\x82a\x11\xD8V[`\x08U`@Q\x7F>5\x0BA\xE8j\x8E\x10\xF8\x04\xAD\xE6\xD3S@\xD6 \xBE5V\x9C\xC7Z\xC9C\xE8\xBB\x14\xAB\x80\xEA\xD1\x90a\x13O\x90\x83\x90aIpV[`\x08Ta\x16e\x81a\x17\xCDV[\x15a\x05\xE8Wa\x16\x7Fa\x16x`\tTa)\x01V[\x82\x90a)EV[\x90Pa\x16\x9Ba\x16\x94a\x16\x8Fa\x05\xEBV[a)\x01V[\x82\x90a)RV[`\x08UPV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x17\x0Ea)`V[0`@Q` \x01a\x17#\x95\x94\x93\x92\x91\x90aI\xEFV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x90V[a\x17Qd\xE8\xD4\xA5\x10\0\x82\x10\x15`\xCBa\x13\xCCV[a\x17gg\x01cEx]\x8A\0\0\x82\x11\x15`\xCAa\x13\xCCV[`\x08Ta\x17t\x90\x82a\x11\xE6V[`\x08U`@Q\x7F\xA9\xBA?\xFE\x0Bl6k\x81#,\xAA\xB3\x86\x05\xA0i\x9A\xD59\x8Dl\xCEv\xF9\x1E\xE8\t\xE3\"\xDA\xFC\x90a\x13O\x90\x83\x90aI\x93V[`\0a\x05\xD1\x82\x82a)dV[`\0a\x05\xD1\x82`\x16a)dV[`\0a\x05\xD1\x82`,a)\x8BV[`\0a\x05\xD1\x82`Ua)\x95V[`\0a\x05\xD1\x82`Va)\x9FV[a\x13\xDA\x81\x83\x14`ga\x13\xCCV[`\0``\x80``a\x18\x03a jV[\x90Pa\x18\ra\x13ZV[\x15a\x18UWa\x18#\x87\x89`\0\x81Q\x81\x10a\x10\xEAW\xFE[`\0a\x18/\x82\x8Aa \xD8V[\x90Pa\x18@\x89\x83`\tT\x84\x8Ba)\xACV[\x92Pa\x18O\x89\x84a\x11\xF4a*\x90V[Pa\x18vV[`@\x80Q`\x02\x80\x82R``\x82\x01\x83R\x90\x91` \x83\x01\x90\x806\x837\x01\x90PP\x91P[a\x18\x81\x88\x82\x87a+\"V[\x90\x94P\x92Pa\x18\x93\x88\x84a\x11\xF4a*\x90V[a\x18\x9D\x81\x89a \xD8V[`\tUP\x97P\x97P\x97\x94PPPPPV[a\x18\xD5\x81`\0\x81Q\x81\x10a\x18\xBEW\xFE[` \x02` \x01\x01Qa\x18\xD0`\x01a\x1D\tV[a+\x8FV[\x81`\0\x81Q\x81\x10a\x18\xE2W\xFE[` \x02` \x01\x01\x81\x81RPPa\x19\x10\x81`\x01\x81Q\x81\x10a\x18\xFEW\xFE[` \x02` \x01\x01Qa\x18\xD0`\0a\x1D\tV[\x81`\x01\x81Q\x81\x10a\x19\x1DW\xFE[` \x02` \x01\x01\x81\x81RPPPV[30\x14a\x19\xEAW`\x000`\x01`\x01`\xA0\x1B\x03\x16`\x006`@Qa\x19P\x92\x91\x90aH\xB5V[`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x19\x8DW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x19\x92V[``\x91P[PP\x90P\x80`\0\x81\x14a\x19\xA1W\xFE[`\x04`\0\x80>`\0Q`\x01`\x01`\xE0\x1B\x03\x19\x16cC\xAD\xBA\xFB`\xE0\x1B\x81\x14a\x19\xCCW=`\0\x80>=`\0\xFD[P` `\x04`\0>`@` R`$=\x03`$`@>`\x1C=\x01`\0\xF3[a\x19\xF3\x86a\x1B5V[`\0``a\x1A\n\x8B\x8B\x8B\x8B\x8B\x8B\x8B\x8Bc\xFF\xFF\xFF\xFF\x16V[P\x91P\x91Pa\x1A\x1C\x81\x84c\xFF\xFF\xFF\xFF\x16V[\x80Q`\x1F\x19\x82\x01\x83\x90RcC\xAD\xBA\xFB`?\x19\x83\x01R` \x02`#\x19\x82\x01`D\x82\x01\x81\xFD[PPPPPPPPPV[`\0\x90\x81R`\x07` R`@\x90 T\x90V[`\0\x80`\0\x80`\0\x80`\0a\x1Aq\x88a+\xAFV[\x96Pa\x1A|\x88a+\xBCV[\x95Pa\x1A\x87\x88a+\xC9V[\x94Pa\x1A\x92\x88a+\xD6V[\x93Pa\x1A\x9D\x88a+\xE3V[\x92Pa\x1A\xA8\x88a+\xF0V[\x91Pa\x1A\xB3\x88a#\xD0V[\x90P\x91\x93\x95\x97\x90\x92\x94\x96PV[`\0\x82\x82\x02a\x07\x9E\x84\x15\x80a\x1A\xDDWP\x83\x85\x83\x81a\x1A\xDAW\xFE[\x04\x14[`\x03a\x13\xCCV[`\0a\x1A\xF3\x82\x15\x15`\x04a\x13\xCCV[\x82a\x1B\0WP`\0a\x05\xD1V[g\r\xE0\xB6\xB3\xA7d\0\0\x83\x81\x02\x90a\x1B#\x90\x85\x83\x81a\x1B\x1AW\xFE[\x04\x14`\x05a\x13\xCCV[\x82\x81\x81a\x1B,W\xFE[\x04\x91PPa\x05\xD1V[a\x1B\\\x81`\0\x81Q\x81\x10a\x1BEW\xFE[` \x02` \x01\x01Qa\x1BW`\x01a\x1D\tV[a\x1A\xC0V[\x81`\0\x81Q\x81\x10a\x1BiW\xFE[` \x02` \x01\x01\x81\x81RPPa\x19\x10\x81`\x01\x81Q\x81\x10a\x1B\x85W\xFE[` \x02` \x01\x01Qa\x1BW`\0a\x1D\tV[`\x01`\x01`\xA0\x1B\x03\x82\x16`\0\x90\x81R` \x81\x90R`@\x90 Ta\x1B\xBF\x82\x82\x10\x15a\x01\x96a\x13\xCCV[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 \x82\x82\x03\x90U`\x02Ta\x1B\xE9\x90\x83a\x11\xF4V[`\x02U`@Q`\0\x90`\x01`\x01`\xA0\x1B\x03\x85\x16\x90\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x90a\x12\xA1\x90\x86\x90aI\x93V[`\0``\x80``a\x1C9a jV[\x90P`\0a\x1CG\x82\x8Aa \xD8V[\x90P``a\x1CZ\x8A\x84`\tT\x85\x8Ca)\xACV[\x90Pa\x1Ci\x8A\x82a\x11\xF4a*\x90V[`\0``a\x1Cx\x8C\x86\x8Ba+\xFDV[\x91P\x91Pa\x1C\x89\x8C\x82a\x11\xC6a*\x90V[a\x1C\x93\x85\x8Da \xD8V[`\tU\x90\x9E\x90\x9DP\x90\x9BP\x99PPPPPPPPPPV[a\x1C\xD2\x81`\0\x81Q\x81\x10a\x1C\xBBW\xFE[` \x02` \x01\x01Qa\x1C\xCD`\x01a\x1D\tV[a,WV[\x81`\0\x81Q\x81\x10a\x1C\xDFW\xFE[` \x02` \x01\x01\x81\x81RPPa\x19\x10\x81`\x01\x81Q\x81\x10a\x1C\xFBW\xFE[` \x02` \x01\x01Qa\x1C\xCD`\0[`\0\x81a\x1D6W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x05\xD1V[P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x90PV[`\0\x81a\x1D\x8AW\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x05\xD1V[P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x90PV[`\0a\x07\x9E\x83\x83a\x1A\xC0V[`\x08Ta\x1D\xC9\x81a\x17\xCDV[\x80\x15a\x1D\xD4WP\x83C\x11[\x15a\x1E\xBDW`\0a\x1E'\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86a,\x8AV[\x90P`\0a\x1E^\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86a\x1EY\x86a\x17\xB3V[a,\xBFV[\x90P`\0a\x1Ek\x84a\x13\xBFV[\x90P`\0a\x1Ex\x85a\x17\xC0V[\x90P`\0a\x1E\x91\x82\x84\x87\x87a\x1E\x8C\x8Ba\x17\xA7V[a,\xDBV[\x90P\x80\x83\x14a\x1A@Wa\x1E\xA4\x86\x82a-2V[\x95Pa\x1E\xB0\x86Ba-@V[`\x08\x81\x90U\x95PPPPPP[PPPPV[`\0\x82\x82\x02a\x1E\xDD\x84\x15\x80a\x1A\xDDWP\x83\x85\x83\x81a\x1A\xDAW\xFE[\x80a\x1E\xECW`\0\x91PPa\x05\xD1V[g\r\xE0\xB6\xB3\xA7d\0\0`\0\x19\x82\x01[\x04`\x01\x01\x91PPa\x05\xD1V[`\0a\x1F\x1A\x85\x84\x86\x85\x8A``\x01Qa-NV[\x90P[\x95\x94PPPPPV[`\0a\x07\x9E\x83\x83a+\x8FV[`\0a\x1F\x1A\x85\x84\x86\x85\x8A``\x01Qa-\xC9V[`\0a\x07\x9E\x83\x83a,WV[`\0g\r\xE0\xB6\xB3\xA7d\0\0\x82\x10a\x1FiW`\0a\x05\xD1V[Pg\r\xE0\xB6\xB3\xA7d\0\0\x03\x90V[`\0a\x1F\x86\x82\x15\x15`\x04a\x13\xCCV[\x82a\x1F\x93WP`\0a\x05\xD1V[g\r\xE0\xB6\xB3\xA7d\0\0\x83\x81\x02\x90a\x1F\xAD\x90\x85\x83\x81a\x1B\x1AW\xFE[\x82`\x01\x82\x03\x81a\x1E\xFBW\xFE[`\0a\x1F\xC3a\x0B\xB6V[`\x01`\x01`\xA0\x1B\x03\x16c\xAA\xAB\xAD\xC5`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1F\xFBW`\0\x80\xFD[PZ\xFA\x15\x80\x15a \x0FW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\xE8\x91\x90aF\x05V[`\0\x80a ?\x83a\x1AKV[\x90Pa X`\0a O\x83a#\xD0V[\x11a\x019a\x13\xCCV[a b\x81\x85a#\xDCV[\x94\x93PPPPV[`@\x80Q`\x02\x80\x82R``\x80\x83\x01\x84R\x92\x83\x92\x91\x90` \x83\x01\x90\x806\x837\x01\x90PP\x90Pa \x98`\x01a\x1D]V[\x81`\0\x81Q\x81\x10a \xA5W\xFE[` \x02` \x01\x01\x81\x81RPPa \xBB`\0a\x1D]V[\x81`\x01\x81Q\x81\x10a \xC8W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R\x90P\x90V[g\r\xE0\xB6\xB3\xA7d\0\0`\0[\x83Q\x81\x10\x15a!:Wa!0a!)\x85\x83\x81Q\x81\x10a \xFFW\xFE[` \x02` \x01\x01Q\x85\x84\x81Q\x81\x10a!\x13W\xFE[` \x02` \x01\x01Qa.?\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x83\x90a.\x8EV[\x91P`\x01\x01a \xE4V[Pa\x05\xD1`\0\x82\x11a\x017a\x13\xCCV[`\0a!Ta\x16\xA1V[\x82`@Q` \x01a\x0BP\x92\x91\x90aH\xC5V[`\0```\0a!u\x84a.\xBAV[\x90Pa!\x90`\0\x82`\x02\x81\x11\x15a!\x88W\xFE[\x14`\xCEa\x13\xCCV[``a!\x9B\x85a.\xD0V[\x90Pa!\xA9\x81Q`\x02a\x17\xE7V[a!\xB2\x81a\x1B5V[``a!\xBCa jV[\x90P`\0a!\xCA\x82\x84a \xD8V[\x90P`\0a!\xD9\x82`\x02a\x1A\xC0V[`\t\x92\x90\x92UP\x99\x91\x98P\x90\x96PPPPPPPV[`\x01`\x01`\xA0\x1B\x03\x82\x16`\0\x90\x81R` \x81\x90R`@\x90 Ta\"\x12\x90\x82a\x11\xC6V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 U`\x02Ta\"8\x90\x82a\x11\xC6V[`\x02U`@Q`\x01`\x01`\xA0\x1B\x03\x83\x16\x90`\0\x90\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x90a\"y\x90\x85\x90aI\x93V[`@Q\x80\x91\x03\x90\xA3PPV[`\0s\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1Ba\"\xA4a\x0B\x92V[`\x01`\x01`\xA0\x1B\x03\x16\x14\x15\x80\x15a\"\xBFWPa\"\xBF\x83a.\xE6V[\x15a\"\xE7Wa\"\xCCa\x0B\x92V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14\x90Pa\x05\xD1V[a\"\xEFa\x1F\xB9V[`\x01`\x01`\xA0\x1B\x03\x16c\x9B\xE2\xA8\x84\x84\x840`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a#\x1E\x93\x92\x91\x90aI\x9CV[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a#6W`\0\x80\xFD[PZ\xFA\x15\x80\x15a#JW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a#n\x91\x90aD\xC5V[\x90Pa\x05\xD1V[\x1Ca\x03\xFF\x16\x90V[bF\x1B\xCD`\xE5\x1B`\0\x90\x81R` `\x04R`\x07`$RfBAL#\0\x000`\n\x80\x84\x04\x81\x81\x06`0\x90\x81\x01`\x08\x1B\x95\x83\x90\x06\x95\x90\x95\x01\x90\x82\x90\x04\x91\x82\x06\x90\x94\x01`\x10\x1B\x93\x90\x93\x01\x01`\xC8\x1B`DR`d\x90\xFD[`\0a\x05\xD1\x82\x82a)\x8BV[`\0\x80\x82`\x02\x81\x11\x15a#\xEBW\xFE[\x14\x15a#\xFAWa#n\x83a+\xAFV[`\x01\x82`\x02\x81\x11\x15a$\x08W\xFE[\x14\x15a$\x17Wa#n\x83a+\xC9V[a#n\x83a+\xE3V[`\0\x80\x82`\x02\x81\x11\x15a$/W\xFE[\x14\x15a$>Wa#n\x83a+\xBCV[`\x01\x82`\x02\x81\x11\x15a$LW\xFE[\x14\x15a$[Wa#n\x83a+\xD6V[a#n\x83a+\xF0V[`\0a\x05\xD1\x82`\x01a/\0V[`\0\x80\x80a\x03\xFF\x81\x80\x80[\x83\x85\x11a$\xE8W`\x02\x85\x85\x01\x04a$\x93\x81\x8Aa/\0V[\x93Pa$\x9E\x84a\x1AKV[\x92Pa$\xA9\x83a#\xD0V[\x91P\x89\x82\x10\x15a$\xBEW\x80`\x01\x01\x95Pa$\xE2V[\x89\x82\x11\x15a$\xD1W`\x01\x81\x03\x94Pa$\xE2V[\x82\x83\x97P\x97PPPPPPPa%\x1DV[Pa$|V[\x88\x81\x10a%\x06Wa%\0a$\xFB\x84a/\x11V[a\x1AKV[\x82a%\x13V[\x81a%\x13a$\xFB\x85a$dV[\x96P\x96PPPPPP[\x92P\x92\x90PV[`\0a%Sh\x028\xFDB\xC5\xCF\x03\xFF\xFF\x19\x83\x12\x15\x80\x15a%LWPh\x07\x0C\x1C\xC7;\0\xC8\0\0\x83\x13\x15[`\ta\x13\xCCV[`\0\x82\x12\x15a%\x86Wa%h\x82`\0\x03a%$V[j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x81a%~W\xFE[\x05\x90Pa\nVV[`\0h\x06\xF0[Y\xD3\xB2\0\0\0\x83\x12a%\xC6WPh\x06\xF0[Y\xD3\xB1\xFF\xFF\xFF\x19\x90\x91\x01\x90w\x01\x95\xE5L]\xD4!w\xF5:'\x17/\xA9\xECc\x02b\x82p\0\0\0\0a%\xFCV[h\x03x-\xAC\xE9\xD9\0\0\0\x83\x12a%\xF8WPh\x03x-\xAC\xE9\xD8\xFF\xFF\xFF\x19\x90\x91\x01\x90k\x14%\x98,\xF5\x97\xCD \\\xEFs\x80a%\xFCV[P`\x01[`d\x92\x90\x92\x02\x91h\x05k\xC7^-c\x10\0\0h\xADx\xEB\xC5\xACb\0\0\0\x84\x12a&LWh\xADx\xEB\xC5\xACa\xFF\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0n\x01\x85QD\x81J\x7F\xF8\x05\x98\x0F\xF0\x08@\0\x82\x02\x05\x90P[hV\xBCu\xE2\xD61\0\0\0\x84\x12a&\x88WhV\xBCu\xE2\xD60\xFF\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0k\x02\xDF\n\xB5\xA8\n\"\xC6\x1A\xB5\xA7\0\x82\x02\x05\x90P[h+^:\xF1k\x18\x80\0\0\x84\x12a&\xC2Wh+^:\xF1k\x18\x7F\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0i?\x1F\xCE=\xA66\xEA\\\xF8P\x82\x02\x05\x90P[h\x15\xAF\x1Dx\xB5\x8C@\0\0\x84\x12a&\xFCWh\x15\xAF\x1Dx\xB5\x8C?\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0i\x01'\xFA'r,\xC0l\xC5\xE2\x82\x02\x05\x90P[h\n\xD7\x8E\xBCZ\xC6 \0\0\x84\x12a'5Wh\n\xD7\x8E\xBCZ\xC6\x1F\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0h(\x0E`\x11N\xDB\x80]\x03\x82\x02\x05\x90P[h\x05k\xC7^-c\x10\0\0\x84\x12a'nWh\x05k\xC7^-c\x0F\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0h\x0E\xBC_\xB4\x17F\x12\x11\x10\x82\x02\x05\x90P[h\x02\xB5\xE3\xAF\x16\xB1\x88\0\0\x84\x12a'\xA7Wh\x02\xB5\xE3\xAF\x16\xB1\x87\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0h\x08\xF0\x0Fv\nK-\xB5]\x82\x02\x05\x90P[h\x01Z\xF1\xD7\x8BX\xC4\0\0\x84\x12a'\xE0Wh\x01Z\xF1\xD7\x8BX\xC3\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0h\x06\xF5\xF1wW\x88\x93y7\x82\x02\x05\x90P[h\x05k\xC7^-c\x10\0\0\x84\x81\x01\x90\x85\x90`\x02\x90\x82\x80\x02\x05\x05\x91\x82\x01\x91\x90P`\x03h\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\x04h\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\x05h\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\x06h\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\x07h\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\x08h\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\th\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\nh\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\x0Bh\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`\x0Ch\x05k\xC7^-c\x10\0\0\x87\x83\x02\x05\x05\x91\x82\x01\x91\x90P`dh\x05k\xC7^-c\x10\0\0\x84\x84\x02\x05\x85\x02\x05\x96\x95PPPPPPV[`\0\x80a)\r\x83a/\x1EV[\x90PeZ\xF3\x10z@\0`\0\x82\x13a),We-y\x88= \0\x82\x03a)6V[e-y\x88= \0\x82\x01[\x81a)=W\xFE[\x05\x93\x92PPPV[`\0a\x07\x9E\x83\x83\x83a/zV[`\0a\x07\x9E\x83\x83`\x16a/zV[F\x90V[`\0\x82\x82\x1Cb?\xFF\xFF\x16b\x1F\xFF\xFF\x81\x13a)~W\x80a bV[b?\xFF\xFF\x19\x17\x93\x92PPPV[\x1Cc\x7F\xFF\xFF\xFF\x16\x90V[\x1C`\x01\x90\x81\x16\x14\x90V[\x1C`\x01`\x01`@\x1B\x03\x16\x90V[`@\x80Q`\x02\x80\x82R``\x80\x83\x01\x84R\x92\x83\x92\x91\x90` \x83\x01\x90\x806\x837\x01\x90PP\x90P\x82a)\xDCW\x90Pa\x1F\x1DV[a*O\x87\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Q\x81\x10a*\x0BW\xFE[` \x02` \x01\x01Q\x87\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Q\x81\x10a*?W\xFE[` \x02` \x01\x01Q\x87\x87\x87a/\x91V[\x81\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Q\x81\x10a*{W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R\x96\x95PPPPPPV[a*\xC6\x83`\0\x81Q\x81\x10a*\xA0W\xFE[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a*\xB5W\xFE[` \x02` \x01\x01Q\x83c\xFF\xFF\xFF\xFF\x16V[\x83`\0\x81Q\x81\x10a*\xD3W\xFE[` \x02` \x01\x01\x81\x81RPPa+\x04\x83`\x01\x81Q\x81\x10a*\xEFW\xFE[` \x02` \x01\x01Q\x83`\x01\x81Q\x81\x10a*\xB5W\xFE[\x83`\x01\x81Q\x81\x10a+\x11W\xFE[` \x02` \x01\x01\x81\x81RPPPPPV[`\0```\0a+1\x84a.\xBAV[\x90P`\0\x81`\x02\x81\x11\x15a+AW\xFE[\x14\x15a+\\Wa+R\x86\x86\x86a0\tV[\x92P\x92PPa+\x87V[`\x01\x81`\x02\x81\x11\x15a+jW\xFE[\x14\x15a+zWa+R\x86\x85a0\xB9V[a+R\x86\x86\x86a0\xEBV[P[\x93P\x93\x91PPV[`\0a+\x9E\x82\x15\x15`\x04a\x13\xCCV[\x81\x83\x81a+\xA7W\xFE[\x04\x93\x92PPPV[`\0a\x05\xD1\x82`\xEAa)dV[`\0a\x05\xD1\x82`\xB5a1WV[`\0a\x05\xD1\x82`\x9Fa)dV[`\0a\x05\xD1\x82`ja1WV[`\0a\x05\xD1\x82`Ta)dV[`\0a\x05\xD1\x82`\x1Fa1WV[`\0```\0a,\x0C\x84a.\xBAV[\x90P`\x01\x81`\x02\x81\x11\x15a,\x1CW\xFE[\x14\x15a,-Wa+R\x86\x86\x86a1\x8AV[`\x02\x81`\x02\x81\x11\x15a,;W\xFE[\x14\x15a,LWa+R\x86\x86\x86a1\xE0V[a+\x85a\x016a#}V[`\0a,f\x82\x15\x15`\x04a\x13\xCCV[\x82a,sWP`\0a\x05\xD1V[\x81`\x01\x84\x03\x81a,\x7FW\xFE[\x04`\x01\x01\x90Pa\x05\xD1V[`\0\x80a,\xAAa,\x9A\x84\x86a\x1FwV[a,\xA4\x87\x89a\x1FwV[\x90a\x1FwV[\x90Pa,\xB5\x81a)\x01V[\x96\x95PPPPPPV[`\0\x80a,\xCFa\x16\x8F\x85\x87a\x1FwV[\x92\x90\x92\x03\x94\x93PPPPV[`\0\x80a,\xF7\x85\x85\x85Ba,\xEE\x8Ba\x1AKV[\x93\x92\x91\x90a2cV[\x90P`xB\x88\x90\x03\x10\x15\x80a-\x0CW\x86a-\x15V[a-\x15\x87a$dV[`\0\x81\x81R`\x07` R`@\x90 \x92\x90\x92UP\x96\x95PPPPPPV[`\0a\x07\x9E\x83\x83`Ka2\xB5V[`\0a\x07\x9E\x83\x83`,a2\xC5V[`\0a-pa-e\x87g\x04)\xD0i\x18\x9E\0\0a.\x8EV[\x83\x11\x15a\x010a\x13\xCCV[`\0a-|\x87\x84a\x11\xC6V[\x90P`\0a-\x8A\x88\x83a\x1FwV[\x90P`\0a-\x98\x88\x87a\x1A\xE4V[\x90P`\0a-\xA6\x83\x83a2\xD7V[\x90Pa-\xBBa-\xB4\x82a\x1FQV[\x89\x90a.\x8EV[\x9A\x99PPPPPPPPPPV[`\0a-\xEBa-\xE0\x85g\x04)\xD0i\x18\x9E\0\0a.\x8EV[\x83\x11\x15a\x011a\x13\xCCV[`\0a.\x01a-\xFA\x86\x85a\x11\xF4V[\x86\x90a\x1FwV[\x90P`\0a.\x0F\x85\x88a\x1FwV[\x90P`\0a.\x1D\x83\x83a2\xD7V[\x90P`\0a.3\x82g\r\xE0\xB6\xB3\xA7d\0\0a\x11\xF4V[\x90Pa-\xBB\x8A\x82a\x1E\xC3V[`\0\x80a.L\x84\x84a3\x03V[\x90P`\0a.fa._\x83a'\x10a\x1E\xC3V[`\x01a\x11\xC6V[\x90P\x80\x82\x10\x15a.{W`\0\x92PPPa\x05\xD1V[a.\x85\x82\x82a\x11\xF4V[\x92PPPa\x05\xD1V[`\0\x82\x82\x02a.\xA8\x84\x15\x80a\x1A\xDDWP\x83\x85\x83\x81a\x1A\xDAW\xFE[g\r\xE0\xB6\xB3\xA7d\0\0\x90\x04\x93\x92PPPV[`\0\x81\x80` \x01\x90Q\x81\x01\x90a\x05\xD1\x91\x90aF!V[``\x81\x80` \x01\x90Q\x81\x01\x90a\x07\x9E\x91\x90aF\xE6V[`\0a.\xF8c\x1Ct\xC9\x17`\xE1\x1Ba\x0B\x1BV[\x90\x91\x14\x91\x90PV[`\0a\x04\0\x83\x83\x01[\x06\x93\x92PPPV[`\0a\x05\xD1\x82`\x01a4\x04V[`\0a/.`\0\x83\x13`da\x13\xCCV[g\x0C}q;I\xDA\0\0\x82\x13\x80\x15a/LWPg\x0FC\xFC,\x04\xEE\0\0\x82\x12[\x15a/jWg\r\xE0\xB6\xB3\xA7d\0\0a/c\x83a4\x13V[\x81a%~W\xFE[a/s\x82a51V[\x90Pa\nVV[b?\xFF\xFF\x82\x81\x16\x82\x1B\x90\x82\x1B\x19\x84\x16\x17\x93\x92PPPV[`\0\x83\x83\x11a/\xA2WP`\0a\x1F\x1DV[`\0a/\xAE\x85\x85a\x1FwV[\x90P`\0a/\xC4g\r\xE0\xB6\xB3\xA7d\0\0\x88a\x1A\xE4V[\x90Pa/\xD8\x82g\t\xB6\xE6J\x8E\xC6\0\0a8\xD0V[\x91P`\0a/\xE6\x83\x83a2\xD7V[\x90P`\0a/\xFDa/\xF6\x83a\x1FQV[\x8B\x90a.\x8EV[\x90Pa-\xBB\x81\x87a.\x8EV[`\0``a0\x15a\x16\x06V[`\0\x80a0!\x85a8\xE7V[\x91P\x91Pa03`\x02\x82\x10`da\x13\xCCV[`@\x80Q`\x02\x80\x82R``\x80\x83\x01\x84R\x92` \x83\x01\x90\x806\x837\x01\x90PP\x90Pa0\x94\x88\x83\x81Q\x81\x10a0bW\xFE[` \x02` \x01\x01Q\x88\x84\x81Q\x81\x10a0vW\xFE[` \x02` \x01\x01Q\x85a0\x87a\x05\xEBV[a0\x8Fa\x08\x85V[a9\tV[\x81\x83\x81Q\x81\x10a0\xA0W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R\x91\x97\x91\x96P\x90\x94PPPPPV[`\0```\0a0\xC8\x84a9\xC0V[\x90P``a0\xDE\x86\x83a0\xD9a\x05\xEBV[a9\xD6V[\x91\x96\x91\x95P\x90\x93PPPPV[`\0``a0\xF7a\x16\x06V[```\0a1\x04\x85a:\x87V[\x91P\x91Pa1\x14\x82Q`\x02a\x17\xE7V[a1\x1D\x82a\x1B5V[`\0a1:\x88\x88\x85a1-a\x05\xEBV[a15a\x08\x85V[a:\x9FV[\x90Pa1J\x82\x82\x11\x15`\xCFa\x13\xCCV[\x97\x91\x96P\x90\x94PPPPPV[`\0\x82\x82\x1Cf\x1F\xFF\xFF\xFF\xFF\xFF\xFF\x16f\x0F\xFF\xFF\xFF\xFF\xFF\xFF\x81\x13a1yW\x80a bV[f\x1F\xFF\xFF\xFF\xFF\xFF\xFF\x19\x17\x93\x92PPPV[`\0``\x80`\0a1\x9A\x85a:\x87V[\x91P\x91Pa1\xAA\x82Q`\x02a\x17\xE7V[a1\xB3\x82a\x1B5V[`\0a1\xD0\x88\x88\x85a1\xC3a\x05\xEBV[a1\xCBa\x08\x85V[a<\xCAV[\x90Pa1J\x82\x82\x10\x15`\xD0a\x13\xCCV[`\0```\0\x80a1\xF0\x85a8\xE7V[\x91P\x91Pa2\x02`\x02\x82\x10`da\x13\xCCV[`@\x80Q`\x02\x80\x82R``\x80\x83\x01\x84R\x92` \x83\x01\x90\x806\x837\x01\x90PP\x90Pa0\x94\x88\x83\x81Q\x81\x10a21W\xFE[` \x02` \x01\x01Q\x88\x84\x81Q\x81\x10a2EW\xFE[` \x02` \x01\x01Q\x85a2Va\x05\xEBV[a2^a\x08\x85V[a>\xDAV[`\0\x80a2o\x87a#\xD0V[\x83\x03\x90P`\0\x81\x87\x02a2\x81\x89a+\xBCV[\x01\x90P`\0\x82\x87\x02a2\x92\x8Aa+\xD6V[\x01\x90P`\0\x83\x87\x02a2\xA3\x8Ba+\xF0V[\x01\x90Pa-\xBB\x89\x84\x8A\x85\x8B\x86\x8Ca?|V[a\x03\xFF\x81\x1B\x19\x92\x90\x92\x16\x91\x1B\x17\x90V[c\x7F\xFF\xFF\xFF\x81\x1B\x19\x92\x90\x92\x16\x91\x1B\x17\x90V[`\0\x80a2\xE4\x84\x84a3\x03V[\x90P`\0a2\xF7a._\x83a'\x10a\x1E\xC3V[\x90Pa\x1F\x1D\x82\x82a\x11\xC6V[`\0\x81a3\x19WPg\r\xE0\xB6\xB3\xA7d\0\0a\x05\xD1V[\x82a3&WP`\0a\x05\xD1V[a37`\x01`\xFF\x1B\x84\x10`\x06a\x13\xCCV[\x82a3]w\x0B\xCEP\x86I!\x11\xAE\xA8\x8FK\xB1\xCAk\xCFXA\x81\xEA\x80Y\xF7e2\x84\x10`\x07a\x13\xCCV[\x82`\0g\x0C}q;I\xDA\0\0\x83\x13\x80\x15a3~WPg\x0FC\xFC,\x04\xEE\0\0\x83\x12[\x15a3\xB5W`\0a3\x8E\x84a4\x13V[\x90Pg\r\xE0\xB6\xB3\xA7d\0\0\x80\x82\x07\x84\x02\x05\x83g\r\xE0\xB6\xB3\xA7d\0\0\x83\x05\x02\x01\x91PPa3\xC3V[\x81a3\xBF\x84a51V[\x02\x90P[g\r\xE0\xB6\xB3\xA7d\0\0\x90\x05a3\xFBh\x028\xFDB\xC5\xCF\x03\xFF\xFF\x19\x82\x12\x80\x15\x90a3\xF4WPh\x07\x0C\x1C\xC7;\0\xC8\0\0\x82\x13\x15[`\x08a\x13\xCCV[a,\xB5\x81a%$V[`\0a\x04\0\x82\x84\x03\x81\x01a/\tV[g\r\xE0\xB6\xB3\xA7d\0\0\x02`\0\x80j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x80\x84\x01\x90n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x0F\xFF\xFF\xFF\xFF\x19\x85\x01\x02\x81a4NW\xFE[\x05\x90P`\0j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x82\x80\x02\x05\x90P\x81\x80j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x81\x84\x02\x05\x91P`\x03\x82\x05\x01j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x82\x84\x02\x05\x91P`\x05\x82\x05\x01j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x82\x84\x02\x05\x91P`\x07\x82\x05\x01j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x82\x84\x02\x05\x91P`\t\x82\x05\x01j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x82\x84\x02\x05\x91P`\x0B\x82\x05\x01j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x82\x84\x02\x05\x91P`\r\x82\x05\x01j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x82\x84\x02\x05\x91P`\x0F\x82`\x02\x91\x90\x05\x91\x90\x91\x01\x02\x95\x94PPPPPV[`\0g\r\xE0\xB6\xB3\xA7d\0\0\x82\x12\x15a5mWa5c\x82j\x0C\t|\xE7\xBC\x90q[4\xB9\xF1`$\x1B\x81a5]W\xFE[\x05a51V[`\0\x03\x90Pa\nVV[`\0~\x16\0\xEF1r\xE5\x8D.\x93>\xC8\x84\xFD\xE1\0d\xC6;Sr\xD8\x05\xE2\x03\xC0\0\0\0\0\0\0\x83\x12a5\xBEWw\x01\x95\xE5L]\xD4!w\xF5:'\x17/\xA9\xECc\x02b\x82p\0\0\0\0\x83\x05\x92Ph\x06\xF0[Y\xD3\xB2\0\0\0\x01[s\x01\x17\x98\0Mu]<\x8B\xC8\xE02\x04\xCFDa\x9E\0\0\0\x83\x12a5\xF6Wk\x14%\x98,\xF5\x97\xCD \\\xEFs\x80\x83\x05\x92Ph\x03x-\xAC\xE9\xD9\0\0\0\x01[`d\x92\x83\x02\x92\x02n\x01\x85QD\x81J\x7F\xF8\x05\x98\x0F\xF0\x08@\0\x83\x12a6>Wn\x01\x85QD\x81J\x7F\xF8\x05\x98\x0F\xF0\x08@\0h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\xADx\xEB\xC5\xACb\0\0\0\x01[k\x02\xDF\n\xB5\xA8\n\"\xC6\x1A\xB5\xA7\0\x83\x12a6yWk\x02\xDF\n\xB5\xA8\n\"\xC6\x1A\xB5\xA7\0h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92PhV\xBCu\xE2\xD61\0\0\0\x01[i?\x1F\xCE=\xA66\xEA\\\xF8P\x83\x12a6\xB0Wi?\x1F\xCE=\xA66\xEA\\\xF8Ph\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph+^:\xF1k\x18\x80\0\0\x01[i\x01'\xFA'r,\xC0l\xC5\xE2\x83\x12a6\xE7Wi\x01'\xFA'r,\xC0l\xC5\xE2h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\x15\xAF\x1Dx\xB5\x8C@\0\0\x01[h(\x0E`\x11N\xDB\x80]\x03\x83\x12a7\x1CWh(\x0E`\x11N\xDB\x80]\x03h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\n\xD7\x8E\xBCZ\xC6 \0\0\x01[h\x0E\xBC_\xB4\x17F\x12\x11\x10\x83\x12a7GWh\x0E\xBC_\xB4\x17F\x12\x11\x10h\x05k\xC7^-c\x10\0\0\x93\x84\x02\x05\x92\x01[h\x08\xF0\x0Fv\nK-\xB5]\x83\x12a7|Wh\x08\xF0\x0Fv\nK-\xB5]h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\x02\xB5\xE3\xAF\x16\xB1\x88\0\0\x01[h\x06\xF5\xF1wW\x88\x93y7\x83\x12a7\xB1Wh\x06\xF5\xF1wW\x88\x93y7h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\x01Z\xF1\xD7\x8BX\xC4\0\0\x01[h\x06$\x8F3pK(f\x03\x83\x12a7\xE5Wh\x06$\x8F3pK(f\x03h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Pg\xADx\xEB\xC5\xACb\0\0\x01[h\x05\xC5Hg\x0B\x95\x10\xE7\xAC\x83\x12a8\x19Wh\x05\xC5Hg\x0B\x95\x10\xE7\xACh\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92PgV\xBCu\xE2\xD61\0\0\x01[`\0h\x05k\xC7^-c\x10\0\0\x84\x01h\x05k\xC7^-c\x10\0\0\x80\x86\x03\x02\x81a8\x98W`\0\x83\x85\x83\x81Q\x81\x10a=\xDCW\xFE[` \x02` \x01\x01Q\x11\x15a>8W`\0a>\x01a;\xEA\x86g\r\xE0\xB6\xB3\xA7d\0\0a\x11\xF4V[\x90P`\0a>\x15\x82\x8C\x86\x81Q\x81\x10a;.W\xFE[\x90Pa>/a;\x98a!)g\r\xE0\xB6\xB3\xA7d\0\0\x8Ca\x11\xF4V[\x92PPPa>OV[\x88\x82\x81Q\x81\x10a>DW\xFE[` \x02` \x01\x01Q\x90P[`\0a>x\x8C\x84\x81Q\x81\x10a>`W\xFE[` \x02` \x01\x01Qa\t\x85\x84\x8F\x87\x81Q\x81\x10a=YW\xFE[\x90Pa>\x8Ca<\x96\x8C\x85\x81Q\x81\x10a<\x7FW\xFE[\x93PPP`\x01\x01a=\xC4V[Pg\r\xE0\xB6\xB3\xA7d\0\0\x81\x10a>\xCEWa>\xC4a>\xBD\x82g\r\xE0\xB6\xB3\xA7d\0\0a\x11\xF4V[\x87\x90a.\x8EV[\x93PPPPa\x1F\x1DV[`\0\x93PPPPa\x1F\x1DV[`\0\x80a>\xEB\x84a,\xA4\x81\x88a\x11\xC6V[\x90Pa?\x04g)\xA2$\x1A\xF6,\0\0\x82\x11\x15a\x013a\x13\xCCV[`\0a?\x1Ba9Jg\r\xE0\xB6\xB3\xA7d\0\0\x89a\x1FwV[\x90P`\0a?;a?4\x83g\r\xE0\xB6\xB3\xA7d\0\0a\x11\xF4V[\x8A\x90a\x1E\xC3V[\x90P`\0a?H\x89a\x1FQV[\x90P`\0a?V\x83\x83a\x1E\xC3V[\x90P`\0a?d\x84\x83a\x11\xF4V[\x90Pa9\xB0a9\xA9a?u\x8Aa\x1FQV[\x84\x90a\x1FwV[`\0a?\x88\x82\x82a?\xDCV[a?\x93\x84`\x1Fa?\xE0V[a?\x9E\x86`Ta?\xF1V[a?\xA9\x88`ja?\xE0V[a?\xB4\x8A`\x9Fa?\xF1V[a?\xBF\x8C`\xB5a?\xE0V[a?\xCA\x8E`\xEAa?\xF1V[\x17\x17\x17\x17\x17\x17\x98\x97PPPPPPPPV[\x1B\x90V[f\x1F\xFF\xFF\xFF\xFF\xFF\xFF\x91\x90\x91\x16\x90\x1B\x90V[b?\xFF\xFF\x91\x90\x91\x16\x90\x1B\x90V[`@\x80Q``\x81\x01\x90\x91R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x90V[\x805a\x05\xD1\x81aKRV[`\0\x82`\x1F\x83\x01\x12a@RW\x80\x81\xFD[\x81Qa@ea@`\x82aK3V[aK\rV[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15a@\x86W`\0\x80\xFD[`\0[\x84\x81\x10\x15a@\xA5W\x81Q\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01a@\x89V[PPPPP\x92\x91PPV[`\0\x82`\x1F\x83\x01\x12a@\xC0W\x80\x81\xFD[\x815`\x01`\x01`@\x1B\x03\x81\x11\x15a@\xD5W\x81\x82\xFD[a@\xE8`\x1F\x82\x01`\x1F\x19\x16` \x01aK\rV[\x91P\x80\x82R\x83` \x82\x85\x01\x01\x11\x15a@\xFFW`\0\x80\xFD[\x80` \x84\x01` \x84\x017`\0\x90\x82\x01` \x01R\x92\x91PPV[\x805`\x02\x81\x10a\x05\xD1W`\0\x80\xFD[\x805a\x05\xD1\x81aKuV[`\0` \x82\x84\x03\x12\x15aACW\x80\x81\xFD[\x815a\x07\x9E\x81aKRV[`\0\x80`@\x83\x85\x03\x12\x15aA`W\x80\x81\xFD[\x825aAk\x81aKRV[\x91P` \x83\x015aA{\x81aKRV[\x80\x91PP\x92P\x92\x90PV[`\0\x80`\0``\x84\x86\x03\x12\x15aA\x9AW\x80\x81\xFD[\x835aA\xA5\x81aKRV[\x92P` \x84\x015aA\xB5\x81aKRV[\x92\x95\x92\x94PPP`@\x91\x90\x91\x015\x90V[`\0\x80`\0\x80`\0\x80`\0`\xE0\x88\x8A\x03\x12\x15aA\xE0W\x84\x85\xFD[\x875aA\xEB\x81aKRV[\x96P` \x88\x015aA\xFB\x81aKRV[\x95P`@\x88\x015\x94P``\x88\x015\x93P`\x80\x88\x015`\xFF\x81\x16\x81\x14aB\x1EW\x83\x84\xFD[\x96\x99\x95\x98P\x93\x96\x92\x95\x94`\xA0\x84\x015\x94P`\xC0\x90\x93\x015\x92\x91PPV[`\0\x80`@\x83\x85\x03\x12\x15aBMW\x81\x82\xFD[\x825aBX\x81aKRV[\x94` \x93\x90\x93\x015\x93PPPV[`\0\x80`\0``\x84\x86\x03\x12\x15aBzW\x80\x81\xFD[\x83Q`\x01`\x01`@\x1B\x03\x80\x82\x11\x15aB\x90W\x82\x83\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12aB\xA3W\x82\x83\xFD[\x81QaB\xB1a@`\x82aK3V[\x80\x82\x82R` \x80\x83\x01\x92P\x80\x86\x01\x8B\x82\x83\x87\x02\x89\x01\x01\x11\x15aB\xD1W\x87\x88\xFD[\x87\x96P[\x84\x87\x10\x15aB\xFCW\x80QaB\xE8\x81aKRV[\x84R`\x01\x96\x90\x96\x01\x95\x92\x81\x01\x92\x81\x01aB\xD5V[P\x89\x01Q\x90\x97P\x93PPP\x80\x82\x11\x15aC\x13W\x82\x83\xFD[PaC \x86\x82\x87\x01a@BV[\x92PP`@\x84\x01Q\x90P\x92P\x92P\x92V[`\0` \x80\x83\x85\x03\x12\x15aCCW\x81\x82\xFD[\x825`\x01`\x01`@\x1B\x03\x81\x11\x15aCXW\x82\x83\xFD[\x83\x01`\x1F\x81\x01\x85\x13aChW\x82\x83\xFD[\x805aCva@`\x82aK3V[\x81\x81R\x83\x81\x01\x90\x83\x85\x01`@\x80\x85\x02\x86\x01\x87\x01\x8A\x10\x15aC\x94W\x87\x88\xFD[\x87\x95P[\x84\x86\x10\x15aC\xE1W\x80\x82\x8B\x03\x12\x15aC\xAEW\x87\x88\xFD[aC\xB7\x81aK\rV[aC\xC1\x8B\x84aA'V[\x81R\x82\x88\x015\x88\x82\x01R\x84R`\x01\x95\x90\x95\x01\x94\x92\x86\x01\x92\x90\x81\x01\x90aC\x98V[P\x90\x98\x97PPPPPPPPV[`\0` \x80\x83\x85\x03\x12\x15aD\x01W\x81\x82\xFD[\x825`\x01`\x01`@\x1B\x03\x81\x11\x15aD\x16W\x82\x83\xFD[\x83\x01`\x1F\x81\x01\x85\x13aD&W\x82\x83\xFD[\x805aD4a@`\x82aK3V[\x81\x81R\x83\x81\x01\x90\x83\x85\x01``\x80\x85\x02\x86\x01\x87\x01\x8A\x10\x15aDRW\x87\x88\xFD[\x87\x95P[\x84\x86\x10\x15aC\xE1W\x80\x82\x8B\x03\x12\x15aDlW\x87\x88\xFD[aDu\x81aK\rV[aD\x7F\x8B\x84aA'V[\x81R\x82\x88\x015\x88\x82\x01R`@\x80\x84\x015\x90\x82\x01R\x84R`\x01\x95\x90\x95\x01\x94\x92\x86\x01\x92\x90\x81\x01\x90aDVV[`\0` \x82\x84\x03\x12\x15aD\xBAW\x80\x81\xFD[\x815a\x07\x9E\x81aKgV[`\0` \x82\x84\x03\x12\x15aD\xD6W\x80\x81\xFD[\x81Qa\x07\x9E\x81aKgV[`\0\x80`\0\x80`\0\x80`\0`\xE0\x88\x8A\x03\x12\x15aD\xFBW\x80\x81\xFD[\x875\x96P` \x80\x89\x015aE\x0E\x81aKRV[\x96P`@\x89\x015aE\x1E\x81aKRV[\x95P``\x89\x015`\x01`\x01`@\x1B\x03\x80\x82\x11\x15aE9W\x83\x84\xFD[\x81\x8B\x01\x91P\x8B`\x1F\x83\x01\x12aELW\x83\x84\xFD[\x815aEZa@`\x82aK3V[\x80\x82\x82R\x85\x82\x01\x91P\x85\x85\x01\x8F\x87\x88\x86\x02\x88\x01\x01\x11\x15aExW\x87\x88\xFD[\x87\x95P[\x83\x86\x10\x15aE\x9AW\x805\x83R`\x01\x95\x90\x95\x01\x94\x91\x86\x01\x91\x86\x01aE|V[P\x98PPP`\x80\x8B\x015\x95P`\xA0\x8B\x015\x94P`\xC0\x8B\x015\x92P\x80\x83\x11\x15aE\xC0W\x83\x84\xFD[PPaE\xCE\x8A\x82\x8B\x01a@\xB0V[\x91PP\x92\x95\x98\x91\x94\x97P\x92\x95PV[`\0` \x82\x84\x03\x12\x15aE\xEEW\x80\x81\xFD[\x815`\x01`\x01`\xE0\x1B\x03\x19\x81\x16\x81\x14a\x07\x9EW\x81\x82\xFD[`\0` \x82\x84\x03\x12\x15aF\x16W\x80\x81\xFD[\x81Qa\x07\x9E\x81aKRV[`\0` \x82\x84\x03\x12\x15aF2W\x80\x81\xFD[\x81Qa\x07\x9E\x81aKuV[`\0\x80`\0``\x84\x86\x03\x12\x15aFQW\x80\x81\xFD[\x83QaF\\\x81aKuV[` \x85\x01Q\x90\x93P`\x01`\x01`@\x1B\x03\x81\x11\x15aFwW\x81\x82\xFD[aC \x86\x82\x87\x01a@BV[`\0\x80`@\x83\x85\x03\x12\x15aF\x95W\x81\x82\xFD[\x82QaF\xA0\x81aKuV[` \x93\x90\x93\x01Q\x92\x94\x92\x93PPPV[`\0\x80`\0``\x84\x86\x03\x12\x15aF\xC4W\x80\x81\xFD[\x83QaF\xCF\x81aKuV[` \x85\x01Q`@\x90\x95\x01Q\x90\x96\x94\x95P\x93\x92PPPV[`\0\x80`@\x83\x85\x03\x12\x15aF\xF8W\x81\x82\xFD[\x82QaG\x03\x81aKuV[` \x84\x01Q\x90\x92P`\x01`\x01`@\x1B\x03\x81\x11\x15aG\x1EW\x81\x82\xFD[aG*\x85\x82\x86\x01a@BV[\x91PP\x92P\x92\x90PV[`\0` \x82\x84\x03\x12\x15aGEW\x80\x81\xFD[\x815a\x07\x9E\x81aKuV[`\0\x80`\0``\x84\x86\x03\x12\x15aGdW\x80\x81\xFD[\x835`\x01`\x01`@\x1B\x03\x80\x82\x11\x15aGzW\x82\x83\xFD[\x81\x86\x01\x91Pa\x01 \x80\x83\x89\x03\x12\x15aG\x90W\x83\x84\xFD[aG\x99\x81aK\rV[\x90PaG\xA5\x88\x84aA\x18V[\x81RaG\xB4\x88` \x85\x01a@7V[` \x82\x01RaG\xC6\x88`@\x85\x01a@7V[`@\x82\x01R``\x83\x015``\x82\x01R`\x80\x83\x015`\x80\x82\x01R`\xA0\x83\x015`\xA0\x82\x01RaG\xF6\x88`\xC0\x85\x01a@7V[`\xC0\x82\x01RaH\x08\x88`\xE0\x85\x01a@7V[`\xE0\x82\x01Ra\x01\0\x80\x84\x015\x83\x81\x11\x15aH W\x85\x86\xFD[aH,\x8A\x82\x87\x01a@\xB0V[\x91\x83\x01\x91\x90\x91RP\x97` \x87\x015\x97P`@\x90\x96\x015\x95\x94PPPPPV[`\0` \x82\x84\x03\x12\x15aH\\W\x80\x81\xFD[P5\x91\x90PV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15aH\x92W\x81Q\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01aHvV[P\x94\x95\x94PPPPPV[\x91\x82R`\x01`\x01`\xE0\x1B\x03\x19\x16` \x82\x01R`$\x01\x90V[`\0\x82\x84\x837\x91\x01\x90\x81R\x91\x90PV[a\x19\x01`\xF0\x1B\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x01\x90V[`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x81R` \x01\x90V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15aI,W\x83Q\x83R\x92\x84\x01\x92\x91\x84\x01\x91`\x01\x01aI\x10V[P\x90\x96\x95PPPPPPV[`\0` \x82Ra\x07\x9E` \x83\x01\x84aHcV[`\0`@\x82RaI^`@\x83\x01\x85aHcV[\x82\x81\x03` \x84\x01Ra\x1F\x1D\x81\x85aHcV[\x90\x15\x15\x81R` \x01\x90V[\x92\x15\x15\x83R` \x83\x01\x91\x90\x91R`@\x82\x01R``\x01\x90V[\x90\x81R` \x01\x90V[\x92\x83R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16` \x84\x01R\x16`@\x82\x01R``\x01\x90V[\x95\x86R`\x01`\x01`\xA0\x1B\x03\x94\x85\x16` \x87\x01R\x92\x90\x93\x16`@\x85\x01R``\x84\x01R`\x80\x83\x01\x91\x90\x91R`\xA0\x82\x01R`\xC0\x01\x90V[\x94\x85R` \x85\x01\x93\x90\x93R`@\x84\x01\x91\x90\x91R``\x83\x01R`\x01`\x01`\xA0\x1B\x03\x16`\x80\x82\x01R`\xA0\x01\x90V[\x93\x84R`\xFF\x92\x90\x92\x16` \x84\x01R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[\x96\x87R` \x87\x01\x95\x90\x95R`@\x86\x01\x93\x90\x93R``\x85\x01\x91\x90\x91R`\x80\x84\x01R`\xA0\x83\x01R`\xC0\x82\x01R`\xE0\x01\x90V[\x95\x86R` \x86\x01\x94\x90\x94R`@\x85\x01\x92\x90\x92R``\x84\x01R\x15\x15`\x80\x83\x01R`\xA0\x82\x01R`\xC0\x01\x90V[`\0` \x80\x83R\x83Q\x80\x82\x85\x01R\x82[\x81\x81\x10\x15aJ\xBFW\x85\x81\x01\x83\x01Q\x85\x82\x01`@\x01R\x82\x01aJ\xA3V[\x81\x81\x11\x15aJ\xD0W\x83`@\x83\x87\x01\x01R[P`\x1F\x01`\x1F\x19\x16\x92\x90\x92\x01`@\x01\x93\x92PPPV[`\0\x83\x82R`@` \x83\x01Ra b`@\x83\x01\x84aHcV[`\xFF\x91\x90\x91\x16\x81R` \x01\x90V[`@Q\x81\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15aK+W`\0\x80\xFD[`@R\x91\x90PV[`\0`\x01`\x01`@\x1B\x03\x82\x11\x15aKHW\x80\x81\xFD[P` \x90\x81\x02\x01\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05\xE8W`\0\x80\xFD[\x80\x15\x15\x81\x14a\x05\xE8W`\0\x80\xFD[`\x03\x81\x10a\x05\xE8W`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x1D\xBF\x8D6M\x92`\x88\xA1\x9C_?]\x0C\xA0\xABr\xCF>\xDA\x8F?x\xDD\xA4Z\xB2a\x9D\xE4\xB6\xD6dsolcC\0\x07\x01\x003\xA2dipfsX\"\x12 b\xC6:,0\x89I\n\x93\x9F\xE9\xF2\x0E\x0E\x99\xEF1\x0F\x04\xA3\x93\xC3:\x92\xC6oE\xA3\xB2\xCE\xA1\x80dsolcC\0\x07\x01\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.vault,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { vault: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256[],uint256,bool,address)` and selector `0x1596019b`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, bool oracleEnabled, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub weights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub oracleEnabled: bool, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256[],uint256,bool, + /// address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + bool, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.weights, + value.swapFeePercentage, + value.oracleEnabled, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + weights: tuple.3, + swapFeePercentage: tuple.4, + oracleEnabled: tuple.5, + owner: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [21u8, 150u8, 1u8, 155u8]; + const SIGNATURE: &'static str = + "create(string,string,address[],uint256[],uint256,bool,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.weights), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.oracleEnabled, + ), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2WeightedPool2TokensFactory`](self) + /// function calls. + #[derive(Clone)] + pub enum BalancerV2WeightedPool2TokensFactoryCalls { + #[allow(missing_docs)] + create(createCall), + } + impl BalancerV2WeightedPool2TokensFactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[21u8, 150u8, 1u8, 155u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(create)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2WeightedPool2TokensFactoryCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 352usize; + const NAME: &'static str = "BalancerV2WeightedPool2TokensFactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPool2TokensFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPool2TokensFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPool2TokensFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPool2TokensFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2WeightedPool2TokensFactory`](self) + /// events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2WeightedPool2TokensFactoryEvents { + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2WeightedPool2TokensFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, 73u8, + 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, 188u8, + 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(PoolCreated)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2WeightedPool2TokensFactoryEvents { + const COUNT: usize = 1usize; + const NAME: &'static str = "BalancerV2WeightedPool2TokensFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2WeightedPool2TokensFactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPool2TokensFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPool2TokensFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2WeightedPool2TokensFactoryInstance { + BalancerV2WeightedPool2TokensFactoryInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + BalancerV2WeightedPool2TokensFactoryInstance::::deploy(__provider, vault) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + BalancerV2WeightedPool2TokensFactoryInstance::::deploy_builder(__provider, vault) + } + /**A [`BalancerV2WeightedPool2TokensFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2WeightedPool2TokensFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2WeightedPool2TokensFactoryInstance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2WeightedPool2TokensFactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2WeightedPool2TokensFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPool2TokensFactoryInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPool2TokensFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPool2TokensFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, vault); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { vault })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2WeightedPool2TokensFactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2WeightedPool2TokensFactoryInstance { + BalancerV2WeightedPool2TokensFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPool2TokensFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + weights: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + oracleEnabled: bool, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + weights, + swapFeePercentage, + oracleEnabled, + owner, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPool2TokensFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = + BalancerV2WeightedPool2TokensFactory::BalancerV2WeightedPool2TokensFactoryInstance< + ::alloy_provider::DynProvider, + >; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xa5bf2ddf098bb0ef6d120c98217dd6b141c74ee0"), + Some(12349891u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xdAE7e32ADc5d490a43cCba1f0c736033F2b4eFca"), + Some(7005512u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9"), + Some(15832998u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xCF0a32Bbef8F064969F21f7e02328FB577382018"), + Some(222864u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2weightedpoolfactory/Cargo.toml b/contracts/generated/contracts-generated/balancerv2weightedpoolfactory/Cargo.toml new file mode 100644 index 0000000000..23a0e3bbc9 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpoolfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2weightedpoolfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2weightedpoolfactory/src/lib.rs b/contracts/generated/contracts-generated/balancerv2weightedpoolfactory/src/lib.rs new file mode 100644 index 0000000000..d735a11363 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpoolfactory/src/lib.rs @@ -0,0 +1,976 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2WeightedPoolFactory { + event PoolCreated(address indexed pool); + + constructor(address vault); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, address owner) external returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "weights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2WeightedPoolFactory { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60c060405234801561001057600080fd5b5060405161604138038061604183398101604081905261002f9161004d565b60601b6001600160601b0319166080526276a700420160a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160601c60a051615f9c6100a56000398060d6528061010052508061015c5250615f9c6000f3fe60806040523480156200001157600080fd5b5060043610620000525760003560e01c80632da47c4014620000575780636634b753146200007a5780638d928af814620000a0578063fbce039314620000b9575b600080fd5b62000061620000d0565b6040516200007192919062000634565b60405180910390f35b620000916200008b366004620003c0565b6200013c565b60405162000071919062000562565b620000aa6200015a565b6040516200007191906200054e565b620000aa620000ca366004620003e6565b6200017e565b600080427f00000000000000000000000000000000000000000000000000000000000000008110156200012e57807f000000000000000000000000000000000000000000000000000000000000000003925062278d00915062000137565b60009250600091505b509091565b6001600160a01b031660009081526020819052604090205460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000090565b60008060006200018d620000d0565b9150915060006200019d6200015a565b8a8a8a8a8a88888c604051620001b3906200024b565b620001c7999897969594939291906200056d565b604051809103906000f080158015620001e4573d6000803e3d6000fd5b509050620001f281620001ff565b9998505050505050505050565b6001600160a01b038116600081815260208190526040808220805460ff19166001179055517f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9190a250565b6158b680620006b183390190565b8035620002668162000697565b92915050565b600082601f8301126200027d578081fd5b8135620002946200028e826200066a565b62000642565b818152915060208083019084810181840286018201871015620002b657600080fd5b60005b84811015620002e2578135620002cf8162000697565b84529282019290820190600101620002b9565b505050505092915050565b600082601f830112620002fe578081fd5b81356200030f6200028e826200066a565b8181529150602080830190848101818402860182018710156200033157600080fd5b60005b84811015620002e25781358452928201929082019060010162000334565b600082601f83011262000363578081fd5b813567ffffffffffffffff8111156200037a578182fd5b6200038f601f8201601f191660200162000642565b9150808252836020828501011115620003a757600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215620003d2578081fd5b8135620003df8162000697565b9392505050565b60008060008060008060c08789031215620003ff578182fd5b863567ffffffffffffffff8082111562000417578384fd5b620004258a838b0162000352565b975060208901359150808211156200043b578384fd5b620004498a838b0162000352565b965060408901359150808211156200045f578384fd5b6200046d8a838b016200026c565b9550606089013591508082111562000483578384fd5b506200049289828a01620002ed565b93505060808701359150620004ab8860a0890162000259565b90509295509295509295565b6001600160a01b03169052565b6000815180845260208085019450808401835b83811015620004f557815187529582019590820190600101620004d7565b509495945050505050565b60008151808452815b81811015620005275760208185018101518683018201520162000509565b81811115620005395782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b901515815260200190565b60006101206001600160a01b038c16835260208181850152620005938285018d62000500565b91508382036040850152620005a9828c62000500565b84810360608601528a51808252828c01935090820190845b81811015620005e957620005d685516200068b565b83529383019391830191600101620005c1565b50508481036080860152620005ff818b620004c4565b93505050508560a08301528460c08301528360e083015262000626610100830184620004b7565b9a9950505050505050505050565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156200066257600080fd5b604052919050565b600067ffffffffffffffff82111562000681578081fd5b5060209081020190565b6001600160a01b031690565b6001600160a01b0381168114620006ad57600080fd5b5056fe6105006040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9610120523480156200003757600080fd5b50604051620058b6380380620058b68339810160408190526200005a9162000cf2565b88888888878787878785516002146200007557600162000078565b60025b6040805180820190915260018152603160f81b6020808301918252336080526001600160601b0319606087901b1660a0528b51908c0190812060c0529151902060e0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6101005289518a918a918a918a918a918a918a91849184918a918a9162000107916003919062000abb565b5080516200011d90600490602084019062000abb565b50620001359150506276a70083111561019462000865565b6200014962278d0082111561019562000865565b42909101610140819052016101605284516200016b906002111560c862000865565b6200018360088651111560c96200086560201b60201c565b62000199856200087a60201b62000d571760201c565b620001a48462000886565b6040516309b2760f60e01b81526000906001600160a01b038b16906309b2760f90620001d5908c9060040162000eab565b602060405180830381600087803b158015620001f057600080fd5b505af115801562000205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022b919062000cd9565b9050896001600160a01b03166366a9c7d2828889516001600160401b03811180156200025657600080fd5b5060405190808252806020026020018201604052801562000281578160200160208202803683370190505b506040518463ffffffff1660e01b8152600401620002a29392919062000e0f565b600060405180830381600087803b158015620002bd57600080fd5b505af1158015620002d2573d6000803e3d6000fd5b5050506001600160601b031960608c901b1661018052506101a081905285516101c0528551620003045760006200031b565b856000815181106200031257fe5b60200260200101515b60601b6001600160601b0319166101e05285516001106200033e57600062000355565b856001815181106200034c57fe5b60200260200101515b60601b6001600160601b031916610200528551600210620003785760006200038f565b856002815181106200038657fe5b60200260200101515b60601b6001600160601b031916610220528551600310620003b2576000620003c9565b85600381518110620003c057fe5b60200260200101515b60601b6001600160601b031916610240528551600410620003ec57600062000403565b85600481518110620003fa57fe5b60200260200101515b60601b6001600160601b031916610260528551600510620004265760006200043d565b856005815181106200043457fe5b60200260200101515b60601b6001600160601b0319166102805285516006106200046057600062000477565b856006815181106200046e57fe5b60200260200101515b60601b6001600160601b0319166102a05285516007106200049a576000620004b1565b85600781518110620004a857fe5b60200260200101515b60601b6001600160601b0319166102c0528551620004d1576000620004f7565b620004f786600081518110620004e357fe5b6020026020010151620008f560201b60201c565b6102e05285516001106200050d5760006200051f565b6200051f86600181518110620004e357fe5b6103005285516002106200053557600062000547565b6200054786600281518110620004e357fe5b6103205285516003106200055d5760006200056f565b6200056f86600381518110620004e357fe5b6103405285516004106200058557600062000597565b6200059786600481518110620004e357fe5b610360528551600510620005ad576000620005bf565b620005bf86600581518110620004e357fe5b610380528551600610620005d5576000620005e7565b620005e786600681518110620004e357fe5b6103a0528551600710620005fd5760006200060f565b6200060f86600781518110620004e357fe5b6103c08181525050505050505050505050505050505050505050600086519050620006478187516200099760201b62000d651760201c565b6000806000805b848160ff161015620006cd5760008a8260ff16815181106200066c57fe5b6020026020010151905062000694662386f26fc1000082101561012e6200086560201b60201c565b620006ae8186620009a660201b62000d721790919060201c565b945082811115620006c3578160ff1693508092505b506001016200064e565b50620006e6670de0b6b3a7640000841461013462000865565b6103e08290528851620006fb57600062000712565b886000815181106200070957fe5b60200260200101515b610400528851600110620007285760006200073f565b886001815181106200073657fe5b60200260200101515b610420528851600210620007555760006200076c565b886002815181106200076357fe5b60200260200101515b6104405288516003106200078257600062000799565b886003815181106200079057fe5b60200260200101515b610460528851600410620007af576000620007c6565b88600481518110620007bd57fe5b60200260200101515b610480528851600510620007dc576000620007f3565b88600581518110620007ea57fe5b60200260200101515b6104a05288516006106200080957600062000820565b886006815181106200081757fe5b60200260200101515b6104c0528851600710620008365760006200084d565b886007815181106200084457fe5b60200260200101515b6104e0525062000f329b505050505050505050505050565b8162000876576200087681620009c3565b5050565b80620008768162000a16565b6200089b64e8d4a5100082101560cb62000865565b620008b367016345785d8a000082111560ca62000865565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90620008ea90839062000ec0565b60405180910390a150565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200093257600080fd5b505afa15801562000947573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200096d919062000dec565b60ff16905060006200098c60128362000aa360201b62000d841760201c565b600a0a949350505050565b62000876828214606762000865565b6000828201620009ba848210158362000865565b90505b92915050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60028151101562000a275762000aa0565b60008160008151811062000a3757fe5b602002602001015190506000600190505b825181101562000a9d57600083828151811062000a6157fe5b6020026020010151905062000a92816001600160a01b0316846001600160a01b03161060656200086560201b60201c565b915060010162000a48565b50505b50565b600062000ab583831115600162000865565b50900390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1062000afe57805160ff191683800117855562000b2e565b8280016001018555821562000b2e579182015b8281111562000b2e57825182559160200191906001019062000b11565b5062000b3c92915062000b40565b5090565b5b8082111562000b3c576000815560010162000b41565b8051620009bd8162000f1c565b600082601f83011262000b75578081fd5b815162000b8c62000b868262000ef0565b62000ec9565b81815291506020808301908481018184028601820187101562000bae57600080fd5b60005b8481101562000bda57815162000bc78162000f1c565b8452928201929082019060010162000bb1565b505050505092915050565b600082601f83011262000bf6578081fd5b815162000c0762000b868262000ef0565b81815291506020808301908481018184028601820187101562000c2957600080fd5b60005b8481101562000bda5781518452928201929082019060010162000c2c565b600082601f83011262000c5b578081fd5b81516001600160401b0381111562000c71578182fd5b602062000c87601f8301601f1916820162000ec9565b9250818352848183860101111562000c9e57600080fd5b60005b8281101562000cbe57848101820151848201830152810162000ca1565b8281111562000cd05760008284860101525b50505092915050565b60006020828403121562000ceb578081fd5b5051919050565b60008060008060008060008060006101208a8c03121562000d11578485fd5b62000d1d8b8b62000b57565b60208b01519099506001600160401b038082111562000d3a578687fd5b62000d488d838e0162000c4a565b995060408c015191508082111562000d5e578687fd5b62000d6c8d838e0162000c4a565b985060608c015191508082111562000d82578687fd5b62000d908d838e0162000b64565b975060808c015191508082111562000da6578687fd5b5062000db58c828d0162000be5565b95505060a08a0151935060c08a0151925060e08a0151915062000ddd8b6101008c0162000b57565b90509295985092959850929598565b60006020828403121562000dfe578081fd5b815160ff81168114620009ba578182fd5b60006060820185835260206060818501528186518084526080860191508288019350845b8181101562000e5b5762000e48855162000f10565b8352938301939183019160010162000e33565b505084810360408601528551808252908201925081860190845b8181101562000e9d5762000e8a835162000f10565b8552938301939183019160010162000e75565b509298975050505050505050565b602081016003831062000eba57fe5b91905290565b90815260200190565b6040518181016001600160401b038111828210171562000ee857600080fd5b604052919050565b60006001600160401b0382111562000f06578081fd5b5060209081020190565b6001600160a01b031690565b6001600160a01b038116811462000aa057600080fd5b60805160a05160601c60c05160e051610100516101205161014051610160516101805160601c6101a0516101c0516101e05160601c6102005160601c6102205160601c6102405160601c6102605160601c6102805160601c6102a05160601c6102c05160601c6102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a0516104c0516104e05161476e6200114860003980611ec55280612857525080611e8252806127f6525080611e3f5280612795525080611dfc5280612734525080611db952806126d3525080611d765280612672525080611d335280612611525080611cf052806125b05250806122d0528061230452806123405250806116285280611b1e5250806115e55280611abd5250806115a25280611a5c52508061155f52806119fb52508061151c528061199a5250806114d9528061193952508061149652806118d85250806114455280611877525080611ae3528061281c525080611a8252806127bb525080611a21528061275a5250806119c052806126f952508061195f52806126985250806118fe528061263752508061189d52806125d652508061183c52806125755250806111025250806105d7525080610835525080610ef1525080610ecd525080610ab5525080610ff452508061103652508061101552508061081152508061079b525061476e6000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c80637ecebe001161010f578063a9059cbb116100a2578063d5c096c411610071578063d5c096c4146103e6578063d73dd623146103f9578063dd62ed3e1461040c578063f89f27ed1461041f576101f0565b8063a9059cbb146103b0578063aaabadc5146103c3578063c0ff1a15146103cb578063d505accf146103d3576101f0565b80638d928af8116100de5780638d928af81461038557806395d89b411461038d5780639b02cdde146103955780639d2c110c1461039d576101f0565b80637ecebe0014610337578063851c1bb31461034a57806387ec68171461035d578063893d20e814610370576101f0565b806338e9922e11610187578063661884631161015657806366188463146102e8578063679aefce146102fb57806370a082311461030357806374f3b00914610316576101f0565b806338e9922e146102a457806338fff2d0146102b757806355c67628146102bf5780636028bfd4146102c7576101f0565b80631c0de051116101c35780631c0de0511461025d57806323b872dd14610274578063313ce567146102875780633644e5151461029c576101f0565b806306fdde03146101f5578063095ea7b31461021357806316c38b3c1461023357806318160ddd14610248575b600080fd5b6101fd610434565b60405161020a9190614647565b60405180910390f35b61022661022136600461401c565b6104cb565b60405161020a919061457e565b610246610241366004614113565b6104e2565b005b6102506104f6565b60405161020a91906145a1565b6102656104fc565b60405161020a93929190614589565b610226610282366004613f67565b610525565b61028f6105a8565b60405161020a91906146b3565b6102506105ad565b6102466102b236600461449d565b6105bc565b6102506105d5565b6102506105f9565b6102da6102d536600461414b565b6105ff565b60405161020a92919061469a565b6102266102f636600461401c565b610636565b610250610690565b610250610311366004613f13565b6106bb565b61032961032436600461414b565b6106da565b60405161020a929190614559565b610250610345366004613f13565b61077c565b610250610358366004614248565b610797565b6102da61036b36600461414b565b6107e9565b61037861080f565b60405161020a9190614532565b610378610833565b6101fd610857565b6102506108b8565b6102506103ab3660046143a1565b6108be565b6102266103be36600461401c565b6109a5565b6103786109b2565b6102506109bc565b6102466103e1366004613fa7565b610a80565b6103296103f436600461414b565b610bc9565b61022661040736600461401c565b610cec565b61025061041a366004613f2f565b610d22565b610427610d4d565b60405161020a9190614546565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b820191906000526020600020905b8154815290600101906020018083116104a357829003601f168201915b505050505090505b90565b60006104d8338484610d9a565b5060015b92915050565b6104ea610e02565b6104f381610e30565b50565b60025490565b6000806000610509610eae565b159250610514610ecb565b915061051e610eef565b9050909192565b6001600160a01b0383166000818152600160209081526040808320338085529252822054919261056391148061055b5750838210155b610197610f13565b61056e858585610f21565b336001600160a01b0386161480159061058957506000198114155b1561059b5761059b8533858403610d9a565b60019150505b9392505050565b601290565b60006105b7610ff0565b905090565b6105c4610e02565b6105cc61108d565b6104f3816110a2565b7f000000000000000000000000000000000000000000000000000000000000000090565b60075490565b600060606106158651610610611100565b610d65565b61062a898989898989896111246111ec611252565b97509795505050505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106106725761066d33856000610d9a565b610686565b61068633856106818487610d84565b610d9a565b5060019392505050565b60006105b761069d6104f6565b6106b56106a86109bc565b6106b0611100565b611374565b90611398565b6001600160a01b0381166000908152602081905260409020545b919050565b606080886107046106e9610833565b6001600160a01b0316336001600160a01b03161460cd610f13565b61071961070f6105d5565b82146101f4610f13565b60606107236113e9565b905061072f8882611666565b60006060806107438e8e8e8e8e8e8e611124565b9250925092506107538d846116c7565b61075d82856111ec565b61076781856111ec565b909550935050505b5097509795505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016107cc9291906144ef565b604051602081830303815290604052805190602001209050919050565b600060606107fa8651610610611100565b61062a8989898989898961175a6117d7611252565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b60085490565b6000806108ce8560200151611838565b905060006108df8660400151611838565b90506000865160018111156108f057fe5b1415610956576109038660600151611b4d565b60608701526109128583611b71565b945061091e8482611b71565b935061092e866060015183611b71565b60608701526000610940878787611b7d565b905061094c8183611bb8565b93505050506105a1565b6109608583611b71565b945061096c8482611b71565b935061097c866060015182611b71565b6060870152600061098e878787611bc4565b905061099a8184611bf7565b905061094c81611c03565b60006104d8338484610f21565b60006105b7611c1a565b600060606109c8610833565b6001600160a01b031663f94d46686109de6105d5565b6040518263ffffffff1660e01b81526004016109fa91906145a1565b60006040518083038186803b158015610a1257600080fd5b505afa158015610a26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a4e9190810190614047565b50915050610a6381610a5e6113e9565b611666565b6060610a6d611c94565b9050610a798183611ef1565b9250505090565b610a8e8442111560d1610f13565b6001600160a01b0387166000908152600560209081526040808320549051909291610ae5917f0000000000000000000000000000000000000000000000000000000000000000918c918c918c9188918d91016145c9565b6040516020818303038152906040528051906020012090506000610b0882611f63565b9050600060018288888860405160008152602001604052604051610b2f9493929190614629565b6020604051602081039080840390855afa158015610b51573d6000803e3d6000fd5b5050604051601f1901519150610b9390506001600160a01b03821615801590610b8b57508b6001600160a01b0316826001600160a01b0316145b6101f8610f13565b6001600160a01b038b166000908152600560205260409020600185019055610bbc8b8b8b610d9a565b5050505050505050505050565b60608088610bd86106e9610833565b610be361070f6105d5565b6060610bed6113e9565b9050610bf76104f6565b610c9d5760006060610c0b8d8d8d8a611f7f565b91509150610c20620f424083101560cc610f13565b610c2e6000620f424061201a565b610c3d8b620f4240840361201a565b610c4781846117d7565b80610c50611100565b67ffffffffffffffff81118015610c6657600080fd5b50604051908082528060200260200182016040528015610c90578160200160208202803683370190505b509550955050505061076f565b610ca78882611666565b6000606080610cbb8e8e8e8e8e8e8e61175a565b925092509250610ccb8c8461201a565b610cd582856117d7565b610cdf81856111ec565b909550935061076f915050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916104d89185906106819086610d72565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606105b7611c94565b80610d61816120b0565b5050565b610d618183146067610f13565b60008282016105a18482101583610f13565b6000610d94838311156001610f13565b50900390565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610df59085906145a1565b60405180910390a3505050565b6000610e196000356001600160e01b031916610797565b90506104f3610e288233612129565b610191610f13565b8015610e5057610e4b610e41610ecb565b4210610193610f13565b610e65565b610e65610e5b610eef565b42106101a9610f13565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490610ea390839061457e565b60405180910390a150565b6000610eb8610eef565b4211806105b757505060065460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b81610d6157610d6181612219565b6001600160a01b038316600090815260208190526040902054610f4982821015610196610f13565b610f606001600160a01b0384161515610199610f13565b6001600160a01b03808516600090815260208190526040808220858503905591851681522054610f909083610d72565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610fe29086906145a1565b60405180910390a350505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061105d61226c565b306040516020016110729594939291906145fd565b60405160208183030381529060405280519060200120905090565b6110a0611098610eae565b610192610f13565b565b6110b564e8d4a5100082101560cb610f13565b6110cb67016345785d8a000082111560ca610f13565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90610ea39083906145a1565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006060806060611133611c94565b905061113d610eae565b1561117457600061114e828a611ef1565b905061115f8983600854848b612270565b925061116e8984610d84612380565b506111c0565b61117c611100565b67ffffffffffffffff8111801561119257600080fd5b506040519080825280602002602001820160405280156111bc578160200160208202803683370190505b5091505b6111cb8882876123eb565b90945092506111db888483612458565b600855509750975097945050505050565b60005b6111f7611100565b81101561124d5761122e83828151811061120d57fe5b602002602001015183838151811061122157fe5b6020026020010151612471565b83828151811061123a57fe5b60209081029190910101526001016111ef565b505050565b333014611310576000306001600160a01b0316600036604051611276929190614507565b6000604051808303816000865af19150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5050905080600081146112c757fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146112f2573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b606061131a6113e9565b90506113268782611666565b6000606061133d8c8c8c8c8c8c8c8c63ffffffff16565b509150915061135081848663ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b60008282026105a184158061139157508385838161138e57fe5b04145b6003610f13565b60006113a78215156004610f13565b826113b4575060006104dc565b670de0b6b3a7640000838102906113d7908583816113ce57fe5b04146005610f13565b8281816113e057fe5b049150506104dc565b606060006113f5611100565b905060608167ffffffffffffffff8111801561141057600080fd5b5060405190808252806020026020018201604052801561143a578160200160208202803683370190505b5090508115611482577f00000000000000000000000000000000000000000000000000000000000000008160008151811061147157fe5b60200260200101818152505061148b565b91506104c89050565b6001821115611482577f0000000000000000000000000000000000000000000000000000000000000000816001815181106114c257fe5b6020026020010181815250506002821115611482577f00000000000000000000000000000000000000000000000000000000000000008160028151811061150557fe5b6020026020010181815250506003821115611482577f00000000000000000000000000000000000000000000000000000000000000008160038151811061154857fe5b6020026020010181815250506004821115611482577f00000000000000000000000000000000000000000000000000000000000000008160048151811061158b57fe5b6020026020010181815250506005821115611482577f0000000000000000000000000000000000000000000000000000000000000000816005815181106115ce57fe5b6020026020010181815250506006821115611482577f00000000000000000000000000000000000000000000000000000000000000008160068151811061161157fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b60200260200101818152505091505090565b60005b611671611100565b81101561124d576116a883828151811061168757fe5b602002602001015183838151811061169b57fe5b6020026020010151611374565b8382815181106116b457fe5b6020908102919091010152600101611669565b6001600160a01b0382166000908152602081905260409020546116ef82821015610196610f13565b6001600160a01b038316600090815260208190526040902082820390556002546117199083610d84565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610df59086906145a1565b600060608061176761108d565b6060611771611c94565b9050600061177f828a611ef1565b905060606117928a84600854858c612270565b90506117a18a82610d84612380565b600060606117b08c868b612491565b915091506117bf8c82876124eb565b600855909e909d50909b509950505050505050505050565b60005b6117e2611100565b81101561124d576118198382815181106117f857fe5b602002602001015183838151811061180c57fe5b60200260200101516124fa565b83828151811061182557fe5b60209081029190910101526001016117da565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561189b57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156118fc57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561195d57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156119be57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a1f57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a8057507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611ae157507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b6106d5610135612219565b600080611b656007548461252d90919063ffffffff16565b90506105a18382610d84565b60006105a18383611374565b6000611b8761108d565b611bb083611b988660200151612571565b84611ba68860400151612571565b886060015161287b565b949350505050565b60006105a18383612471565b6000611bce61108d565b611bb083611bdf8660200151612571565b84611bed8860400151612571565b88606001516128f6565b60006105a183836124fa565b60006104dc611c1360075461296c565b8390612992565b6000611c24610833565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5c57600080fd5b505afa158015611c70573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b79190614270565b60606000611ca0611100565b905060608167ffffffffffffffff81118015611cbb57600080fd5b50604051908082528060200260200182016040528015611ce5578160200160208202803683370190505b5090508115611482577f000000000000000000000000000000000000000000000000000000000000000081600081518110611d1c57fe5b6020026020010181815250506001821115611482577f000000000000000000000000000000000000000000000000000000000000000081600181518110611d5f57fe5b6020026020010181815250506002821115611482577f000000000000000000000000000000000000000000000000000000000000000081600281518110611da257fe5b6020026020010181815250506003821115611482577f000000000000000000000000000000000000000000000000000000000000000081600381518110611de557fe5b6020026020010181815250506004821115611482577f000000000000000000000000000000000000000000000000000000000000000081600481518110611e2857fe5b6020026020010181815250506005821115611482577f000000000000000000000000000000000000000000000000000000000000000081600581518110611e6b57fe5b6020026020010181815250506006821115611482577f000000000000000000000000000000000000000000000000000000000000000081600681518110611eae57fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b670de0b6b3a764000060005b8351811015611f5357611f49611f42858381518110611f1857fe5b6020026020010151858481518110611f2c57fe5b60200260200101516129d490919063ffffffff16565b8390612a23565b9150600101611efd565b506104dc60008211610137610f13565b6000611f6d610ff0565b826040516020016107cc929190614517565b60006060611f8b61108d565b6000611f9684612a4f565b9050611fb16000826002811115611fa957fe5b1460ce610f13565b6060611fbc85612a65565b9050611fd0611fc9611100565b8251610d65565b611fdc81610a5e6113e9565b6060611fe6611c94565b90506000611ff48284611ef1565b90506000612004826106b0611100565b6008929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461203d9082610d72565b6001600160a01b0383166000908152602081905260409020556002546120639082610d72565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906120a49085906145a1565b60405180910390a35050565b6002815110156120bf576104f3565b6000816000815181106120ce57fe5b602002602001015190506000600190505b825181101561124d5760008382815181106120f657fe5b6020026020010151905061211f816001600160a01b0316846001600160a01b0316106065610f13565b91506001016120df565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b61214861080f565b6001600160a01b031614158015612163575061216383612a7b565b1561218b5761217061080f565b6001600160a01b0316336001600160a01b03161490506104dc565b612193611c1a565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b81526004016121c2939291906145aa565b60206040518083038186803b1580156121da57600080fd5b505afa1580156121ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612212919061412f565b90506104dc565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b4690565b60608061227b611100565b67ffffffffffffffff8111801561229157600080fd5b506040519080825280602002602001820160405280156122bb578160200160208202803683370190505b509050826122ca579050612377565b61233d877f0000000000000000000000000000000000000000000000000000000000000000815181106122f957fe5b6020026020010151877f00000000000000000000000000000000000000000000000000000000000000008151811061232d57fe5b6020026020010151878787612a95565b817f00000000000000000000000000000000000000000000000000000000000000008151811061236957fe5b602090810291909101015290505b95945050505050565b60005b61238b611100565b8110156123e5576123c68482815181106123a157fe5b60200260200101518483815181106123b557fe5b60200260200101518463ffffffff16565b8482815181106123d257fe5b6020908102919091010152600101612383565b50505050565b6000606060006123fa84612a4f565b9050600081600281111561240a57fe5b14156124255761241b868686612b0d565b9250925050612450565b600181600281111561243357fe5b14156124435761241b8685612beb565b61241b868686612c1d565b505b935093915050565b60006124678484610d84612380565b611bb08285611ef1565b60006124808215156004610f13565b81838161248957fe5b049392505050565b6000606060006124a084612a4f565b905060018160028111156124b057fe5b14156124c15761241b868686612c88565b60028160028111156124cf57fe5b14156124e05761241b868686612ce2565b61244e610136612219565b60006124678484610d72612380565b60006125098215156004610f13565b82612516575060006104dc565b81600184038161252257fe5b0460010190506104dc565b600082820261254784158061139157508385838161138e57fe5b806125565760009150506104dc565b670de0b6b3a764000060001982015b046001019150506104dc565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156125d457507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561263557507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561269657507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156126f757507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561275857507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156127b957507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561281a57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b600061289d61289287670429d069189e0000612a23565b831115610130610f13565b60006128a98784610d72565b905060006128b78883612992565b905060006128c58887611398565b905060006128d38383612d8a565b90506128e86128e18261296c565b8990612a23565b9a9950505050505050505050565b600061291861290d85670429d069189e0000612a23565b831115610131610f13565b600061292e6129278685610d84565b8690612992565b9050600061293c8588612992565b9050600061294a8383612d8a565b9050600061296082670de0b6b3a7640000610d84565b90506128e88a8261252d565b6000670de0b6b3a764000082106129845760006104dc565b50670de0b6b3a76400000390565b60006129a18215156004610f13565b826129ae575060006104dc565b670de0b6b3a7640000838102906129c8908583816113ce57fe5b82600182038161256557fe5b6000806129e18484612db6565b905060006129fb6129f48361271061252d565b6001610d72565b905080821015612a10576000925050506104dc565b612a1a8282610d84565b925050506104dc565b6000828202612a3d84158061139157508385838161138e57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906104dc919061428c565b6060818060200190518101906105a19190614352565b6000612a8d631c74c91760e11b610797565b909114919050565b6000838311612aa657506000612377565b6000612ab28585612992565b90506000612ac8670de0b6b3a764000088611398565b9050612adc826709b6e64a8ec60000612ec1565b91506000612aea8383612d8a565b90506000612b01612afa8361296c565b8b90612a23565b90506128e88187612a23565b60006060612b1961108d565b600080612b2585612ed8565b91509150612b3d612b34611100565b82106064610f13565b6060612b47611100565b67ffffffffffffffff81118015612b5d57600080fd5b50604051908082528060200260200182016040528015612b87578160200160208202803683370190505b509050612bc6888381518110612b9957fe5b6020026020010151888481518110612bad57fe5b602002602001015185612bbe6104f6565b600754612efa565b818381518110612bd257fe5b6020908102919091010152919791965090945050505050565b600060606000612bfa84612fb7565b90506060612c108683612c0b6104f6565b612fcd565b9196919550909350505050565b60006060612c2961108d565b60606000612c368561307f565b91509150612c478251610610611100565b612c5382610a5e6113e9565b6000612c6b888885612c636104f6565b600754613097565b9050612c7b8282111560cf610f13565b9791965090945050505050565b60006060806000612c988561307f565b91509150612cae612ca7611100565b8351610d65565b612cba82610a5e6113e9565b6000612cd2888885612cca6104f6565b6007546132bc565b9050612c7b8282101560d0610f13565b60006060600080612cf285612ed8565b91509150612d01612b34611100565b6060612d0b611100565b67ffffffffffffffff81118015612d2157600080fd5b50604051908082528060200260200182016040528015612d4b578160200160208202803683370190505b509050612bc6888381518110612d5d57fe5b6020026020010151888481518110612d7157fe5b602002602001015185612d826104f6565b6007546134cd565b600080612d978484612db6565b90506000612daa6129f48361271061252d565b90506123778282610d72565b600081612dcc5750670de0b6b3a76400006104dc565b82612dd9575060006104dc565b612dea600160ff1b84106006610f13565b82612e10770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007610f13565b826000670c7d713b49da000083138015612e315750670f43fc2c04ee000083125b15612e68576000612e418461356f565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050612e76565b81612e7284613696565b0290505b670de0b6b3a76400009005612eae680238fd42c5cf03ffff198212801590612ea7575068070c1cc73b00c800008213155b6008610f13565b612eb781613a44565b9695505050505050565b600081831015612ed157816105a1565b5090919050565b60008082806020019051810190612eef919061431c565b909590945092505050565b600080612f1184612f0b8188610d84565b90612992565b9050612f2a6709b6e64a8ec60000821015610132610f13565b6000612f48612f41670de0b6b3a764000089611398565b8390612d8a565b90506000612f5f612f588361296c565b8a90612a23565b90506000612f6c8961296c565b90506000612f7a838361252d565b90506000612f888483610d84565b9050612fa7612fa0612f998a61296c565b8490612a23565b8290610d72565b9c9b505050505050505050505050565b6000818060200190518101906105a191906142ef565b60606000612fdb8484611398565b90506060855167ffffffffffffffff81118015612ff757600080fd5b50604051908082528060200260200182016040528015613021578160200160208202803683370190505b50905060005b8651811015613075576130568388838151811061304057fe5b6020026020010151612a2390919063ffffffff16565b82828151811061306257fe5b6020908102919091010152600101613027565b5095945050505050565b6060600082806020019051810190612eef91906142a8565b60006060845167ffffffffffffffff811180156130b357600080fd5b506040519080825280602002602001820160405280156130dd578160200160208202803683370190505b5090506000805b88518110156131a25761313d8982815181106130fc57fe5b6020026020010151612f0b89848151811061311357fe5b60200260200101518c858151811061312757fe5b6020026020010151610d8490919063ffffffff16565b83828151811061314957fe5b60200260200101818152505061319861319189838151811061316757fe5b602002602001015185848151811061317b57fe5b602002602001015161252d90919063ffffffff16565b8390610d72565b91506001016130e4565b50670de0b6b3a764000060005b895181101561329b5760008482815181106131c657fe5b602002602001015184111561321d5760006131ef6131e38661296c565b8d858151811061304057fe5b90506000613203828c868151811061312757fe5b9050613214613191611c138b61296c565b92505050613234565b88828151811061322957fe5b602002602001015190505b600061325d8c848151811061324557fe5b60200260200101516106b5848f878151811061312757fe5b905061328f6132888c858151811061327157fe5b6020026020010151836129d490919063ffffffff16565b8590612a23565b935050506001016131af565b506132af6132a88261296c565b879061252d565b9998505050505050505050565b60006060845167ffffffffffffffff811180156132d857600080fd5b50604051908082528060200260200182016040528015613302578160200160208202803683370190505b5090506000805b88518110156133aa5761336289828151811061332157fe5b60200260200101516106b589848151811061333857fe5b60200260200101518c858151811061334c57fe5b6020026020010151610d7290919063ffffffff16565b83828151811061336e57fe5b6020026020010181815250506133a061319189838151811061338c57fe5b602002602001015185848151811061304057fe5b9150600101613309565b50670de0b6b3a764000060005b895181101561348b576000838583815181106133cf57fe5b6020026020010151111561342b5760006133f46131e386670de0b6b3a7640000610d84565b90506000613408828c868151811061312757fe5b9050613422613191611f42670de0b6b3a76400008c610d84565b92505050613442565b88828151811061343757fe5b602002602001015190505b600061346b8c848151811061345357fe5b60200260200101516106b5848f878151811061334c57fe5b905061347f6132888c858151811061327157fe5b935050506001016133b7565b50670de0b6b3a764000081106134c1576134b76134b082670de0b6b3a7640000610d84565b8790612a23565b9350505050612377565b60009350505050612377565b6000806134de84612f0b8188610d72565b90506134f76729a2241af62c0000821115610133610f13565b600061350e612f41670de0b6b3a764000089612992565b9050600061352e61352783670de0b6b3a7640000610d84565b8a9061252d565b9050600061353b8961296c565b90506000613549838361252d565b905060006135578483610d84565b9050612fa7612fa06135688a61296c565b8490612992565b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401906ec097ce7bc90715b34b9f0fffffffff19850102816135ab57fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f826002919005919091010295945050505050565b60006136a6600083136064610f13565b670de0b6b3a76400008212156136e1576136d7826ec097ce7bc90715b34b9f1000000000816136d157fe5b05613696565b60000390506106d5565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261373257770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261376a576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126137b2576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126137ed576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261382457693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e2831261385b57690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126138905768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb4174612111083126138bb57680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d83126138f0576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312613925576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b2866038312613959576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac831261398d576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d6310000080860302816139b057fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000613a73680238fd42c5cf03ffff198312158015613a6c575068070c1cc73b00c800008313155b6009610f13565b6000821215613aa757613a8882600003613a44565b6ec097ce7bc90715b34b9f100000000081613a9f57fe5b0590506106d5565b60006806f05b59d3b20000008312613ae757506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000613b1d565b6803782dace9d90000008312613b1957506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380613b1d565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412613b6d5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412613ba9576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412613be357682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412613c1d576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412613c5657680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412613c8f5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613cc8576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412613d015768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b80356104dc81614708565b600082601f830112613e3d578081fd5b8151613e50613e4b826146e8565b6146c1565b818152915060208083019084810181840286018201871015613e7157600080fd5b60005b84811015613e9057815184529282019290820190600101613e74565b505050505092915050565b600082601f830112613eab578081fd5b813567ffffffffffffffff811115613ec1578182fd5b613ed4601f8201601f19166020016146c1565b9150808252836020828501011115613eeb57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106104dc57600080fd5b600060208284031215613f24578081fd5b81356105a181614708565b60008060408385031215613f41578081fd5b8235613f4c81614708565b91506020830135613f5c81614708565b809150509250929050565b600080600060608486031215613f7b578081fd5b8335613f8681614708565b92506020840135613f9681614708565b929592945050506040919091013590565b600080600080600080600060e0888a031215613fc1578283fd5b8735613fcc81614708565b96506020880135613fdc81614708565b95506040880135945060608801359350608088013560ff81168114613fff578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561402e578182fd5b823561403981614708565b946020939093013593505050565b60008060006060848603121561405b578081fd5b835167ffffffffffffffff80821115614072578283fd5b818601915086601f830112614085578283fd5b8151614093613e4b826146e8565b80828252602080830192508086018b8283870289010111156140b3578788fd5b8796505b848710156140de5780516140ca81614708565b8452600196909601959281019281016140b7565b5089015190975093505050808211156140f5578283fd5b5061410286828701613e2d565b925050604084015190509250925092565b600060208284031215614124578081fd5b81356105a18161471d565b600060208284031215614140578081fd5b81516105a18161471d565b600080600080600080600060e0888a031215614165578081fd5b8735965060208089013561417881614708565b9650604089013561418881614708565b9550606089013567ffffffffffffffff808211156141a4578384fd5b818b0191508b601f8301126141b7578384fd5b81356141c5613e4b826146e8565b8082825285820191508585018f8788860288010111156141e3578788fd5b8795505b838610156142055780358352600195909501949186019186016141e7565b509850505060808b0135955060a08b0135945060c08b013592508083111561422b578384fd5b50506142398a828b01613e9b565b91505092959891949750929550565b600060208284031215614259578081fd5b81356001600160e01b0319811681146105a1578182fd5b600060208284031215614281578081fd5b81516105a181614708565b60006020828403121561429d578081fd5b81516105a18161472b565b6000806000606084860312156142bc578081fd5b83516142c78161472b565b602085015190935067ffffffffffffffff8111156142e3578182fd5b61410286828701613e2d565b60008060408385031215614301578182fd5b825161430c8161472b565b6020939093015192949293505050565b600080600060608486031215614330578081fd5b835161433b8161472b565b602085015160409095015190969495509392505050565b60008060408385031215614364578182fd5b825161436f8161472b565b602084015190925067ffffffffffffffff81111561438b578182fd5b61439785828601613e2d565b9150509250929050565b6000806000606084860312156143b5578081fd5b833567ffffffffffffffff808211156143cc578283fd5b81860191506101208083890312156143e2578384fd5b6143eb816146c1565b90506143f78884613f04565b81526144068860208501613e22565b60208201526144188860408501613e22565b6040820152606083013560608201526080830135608082015260a083013560a08201526144488860c08501613e22565b60c082015261445a8860e08501613e22565b60e08201526101008084013583811115614472578586fd5b61447e8a828701613e9b565b9183019190915250976020870135975060409096013595945050505050565b6000602082840312156144ae578081fd5b5035919050565b6000815180845260208085019450808401835b838110156144e4578151875295820195908201906001016144c8565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6000602082526105a160208301846144b5565b60006040825261456c60408301856144b5565b828103602084015261237781856144b5565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b6000602080835283518082850152825b8181101561467357858101830151858201604001528201614657565b818111156146845783604083870101525b50601f01601f1916929092016040019392505050565b600083825260406020830152611bb060408301846144b5565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156146e057600080fd5b604052919050565b600067ffffffffffffffff8211156146fe578081fd5b5060209081020190565b6001600160a01b03811681146104f357600080fd5b80151581146104f357600080fd5b600381106104f357600080fdfea2646970667358221220a2c3b62e0bc50507598395387e1557612d7ad59e817ddae4d5279907402fedb464736f6c63430007010033a26469706673582212201bcb3a953b00c5c4dcf4d3cf74f047f69d25320298f41e6f635cb029516f583764736f6c63430007010033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xC0`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa`A8\x03\x80a`A\x839\x81\x01`@\x81\x90Ra\0/\x91a\0MV[``\x1B`\x01`\x01``\x1B\x03\x19\x16`\x80Rbv\xA7\0B\x01`\xA0Ra\0{V[`\0` \x82\x84\x03\x12\x15a\0^W\x80\x81\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0tW\x81\x82\xFD[\x93\x92PPPV[`\x80Q``\x1C`\xA0Qa_\x9Ca\0\xA5`\09\x80`\xD6R\x80a\x01\0RP\x80a\x01\\RPa_\x9C`\0\xF3\xFE`\x80`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`\x046\x10b\0\0RW`\x005`\xE0\x1C\x80c-\xA4|@\x14b\0\0WW\x80cf4\xB7S\x14b\0\0zW\x80c\x8D\x92\x8A\xF8\x14b\0\0\xA0W\x80c\xFB\xCE\x03\x93\x14b\0\0\xB9W[`\0\x80\xFD[b\0\0ab\0\0\xD0V[`@Qb\0\0q\x92\x91\x90b\0\x064V[`@Q\x80\x91\x03\x90\xF3[b\0\0\x91b\0\0\x8B6`\x04b\0\x03\xC0V[b\0\x01=`\0\xFD[P\x90Pb\0\x01\xF2\x81b\0\x01\xFFV[\x99\x98PPPPPPPPPV[`\x01`\x01`\xA0\x1B\x03\x81\x16`\0\x81\x81R` \x81\x90R`@\x80\x82 \x80T`\xFF\x19\x16`\x01\x17\x90UQ\x7F\x83\xA4\x8F\xBC\xFC\x99\x1351Nt\xD0Ij\xABj\x19\x87\xE9\x92\xDD\xC8]\xDD\xBC\xC4\xD6\xDDn\xF2\xE9\xFC\x91\x90\xA2PV[aX\xB6\x80b\0\x06\xB1\x839\x01\x90V[\x805b\0\x02f\x81b\0\x06\x97V[\x92\x91PPV[`\0\x82`\x1F\x83\x01\x12b\0\x02}W\x80\x81\xFD[\x815b\0\x02\x94b\0\x02\x8E\x82b\0\x06jV[b\0\x06BV[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15b\0\x02\xB6W`\0\x80\xFD[`\0[\x84\x81\x10\x15b\0\x02\xE2W\x815b\0\x02\xCF\x81b\0\x06\x97V[\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01b\0\x02\xB9V[PPPPP\x92\x91PPV[`\0\x82`\x1F\x83\x01\x12b\0\x02\xFEW\x80\x81\xFD[\x815b\0\x03\x0Fb\0\x02\x8E\x82b\0\x06jV[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15b\0\x031W`\0\x80\xFD[`\0[\x84\x81\x10\x15b\0\x02\xE2W\x815\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01b\0\x034V[`\0\x82`\x1F\x83\x01\x12b\0\x03cW\x80\x81\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15b\0\x03zW\x81\x82\xFD[b\0\x03\x8F`\x1F\x82\x01`\x1F\x19\x16` \x01b\0\x06BV[\x91P\x80\x82R\x83` \x82\x85\x01\x01\x11\x15b\0\x03\xA7W`\0\x80\xFD[\x80` \x84\x01` \x84\x017`\0\x90\x82\x01` \x01R\x92\x91PPV[`\0` \x82\x84\x03\x12\x15b\0\x03\xD2W\x80\x81\xFD[\x815b\0\x03\xDF\x81b\0\x06\x97V[\x93\x92PPPV[`\0\x80`\0\x80`\0\x80`\xC0\x87\x89\x03\x12\x15b\0\x03\xFFW\x81\x82\xFD[\x865g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15b\0\x04\x17W\x83\x84\xFD[b\0\x04%\x8A\x83\x8B\x01b\0\x03RV[\x97P` \x89\x015\x91P\x80\x82\x11\x15b\0\x04;W\x83\x84\xFD[b\0\x04I\x8A\x83\x8B\x01b\0\x03RV[\x96P`@\x89\x015\x91P\x80\x82\x11\x15b\0\x04_W\x83\x84\xFD[b\0\x04m\x8A\x83\x8B\x01b\0\x02lV[\x95P``\x89\x015\x91P\x80\x82\x11\x15b\0\x04\x83W\x83\x84\xFD[Pb\0\x04\x92\x89\x82\x8A\x01b\0\x02\xEDV[\x93PP`\x80\x87\x015\x91Pb\0\x04\xAB\x88`\xA0\x89\x01b\0\x02YV[\x90P\x92\x95P\x92\x95P\x92\x95V[`\x01`\x01`\xA0\x1B\x03\x16\x90RV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15b\0\x04\xF5W\x81Q\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01b\0\x04\xD7V[P\x94\x95\x94PPPPPV[`\0\x81Q\x80\x84R\x81[\x81\x81\x10\x15b\0\x05'W` \x81\x85\x01\x81\x01Q\x86\x83\x01\x82\x01R\x01b\0\x05\tV[\x81\x81\x11\x15b\0\x059W\x82` \x83\x87\x01\x01R[P`\x1F\x01`\x1F\x19\x16\x92\x90\x92\x01` \x01\x92\x91PPV[`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x81R` \x01\x90V[\x90\x15\x15\x81R` \x01\x90V[`\0a\x01 `\x01`\x01`\xA0\x1B\x03\x8C\x16\x83R` \x81\x81\x85\x01Rb\0\x05\x93\x82\x85\x01\x8Db\0\x05\0V[\x91P\x83\x82\x03`@\x85\x01Rb\0\x05\xA9\x82\x8Cb\0\x05\0V[\x84\x81\x03``\x86\x01R\x8AQ\x80\x82R\x82\x8C\x01\x93P\x90\x82\x01\x90\x84[\x81\x81\x10\x15b\0\x05\xE9Wb\0\x05\xD6\x85Qb\0\x06\x8BV[\x83R\x93\x83\x01\x93\x91\x83\x01\x91`\x01\x01b\0\x05\xC1V[PP\x84\x81\x03`\x80\x86\x01Rb\0\x05\xFF\x81\x8Bb\0\x04\xC4V[\x93PPPP\x85`\xA0\x83\x01R\x84`\xC0\x83\x01R\x83`\xE0\x83\x01Rb\0\x06&a\x01\0\x83\x01\x84b\0\x04\xB7V[\x9A\x99PPPPPPPPPPV[\x91\x82R` \x82\x01R`@\x01\x90V[`@Q\x81\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15b\0\x06bW`\0\x80\xFD[`@R\x91\x90PV[`\0g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15b\0\x06\x81W\x80\x81\xFD[P` \x90\x81\x02\x01\x90V[`\x01`\x01`\xA0\x1B\x03\x16\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x06\xADW`\0\x80\xFD[PV\xFEa\x05\0`@R\x7Fnq\xED\xAE\x12\xB1\xB9\x7FM\x1F`7\x0F\xEF\x10\x10_\xA2\xFA\xAE\x01&\x11J\x16\x9Cd\x84]a&\xC9a\x01 R4\x80\x15b\0\x007W`\0\x80\xFD[P`@Qb\0X\xB68\x03\x80b\0X\xB6\x839\x81\x01`@\x81\x90Rb\0\0Z\x91b\0\x0C\xF2V[\x88\x88\x88\x88\x87\x87\x87\x87\x87\x85Q`\x02\x14b\0\0uW`\x01b\0\0xV[`\x02[`@\x80Q\x80\x82\x01\x90\x91R`\x01\x81R`1`\xF8\x1B` \x80\x83\x01\x91\x82R3`\x80R`\x01`\x01``\x1B\x03\x19``\x87\x90\x1B\x16`\xA0R\x8BQ\x90\x8C\x01\x90\x81 `\xC0R\x91Q\x90 `\xE0R\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0Fa\x01\0R\x89Q\x8A\x91\x8A\x91\x8A\x91\x8A\x91\x8A\x91\x8A\x91\x8A\x91\x84\x91\x84\x91\x8A\x91\x8A\x91b\0\x01\x07\x91`\x03\x91\x90b\0\n\xBBV[P\x80Qb\0\x01\x1D\x90`\x04\x90` \x84\x01\x90b\0\n\xBBV[Pb\0\x015\x91PPbv\xA7\0\x83\x11\x15a\x01\x94b\0\x08eV[b\0\x01Ib'\x8D\0\x82\x11\x15a\x01\x95b\0\x08eV[B\x90\x91\x01a\x01@\x81\x90R\x01a\x01`R\x84Qb\0\x01k\x90`\x02\x11\x15`\xC8b\0\x08eV[b\0\x01\x83`\x08\x86Q\x11\x15`\xC9b\0\x08e` \x1B` \x1CV[b\0\x01\x99\x85b\0\x08z` \x1Bb\0\rW\x17` \x1CV[b\0\x01\xA4\x84b\0\x08\x86V[`@Qc\t\xB2v\x0F`\xE0\x1B\x81R`\0\x90`\x01`\x01`\xA0\x1B\x03\x8B\x16\x90c\t\xB2v\x0F\x90b\0\x01\xD5\x90\x8C\x90`\x04\x01b\0\x0E\xABV[` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15b\0\x01\xF0W`\0\x80\xFD[PZ\xF1\x15\x80\x15b\0\x02\x05W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90b\0\x02+\x91\x90b\0\x0C\xD9V[\x90P\x89`\x01`\x01`\xA0\x1B\x03\x16cf\xA9\xC7\xD2\x82\x88\x89Q`\x01`\x01`@\x1B\x03\x81\x11\x80\x15b\0\x02VW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15b\0\x02\x81W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01b\0\x02\xA2\x93\x92\x91\x90b\0\x0E\x0FV[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15b\0\x02\xBDW`\0\x80\xFD[PZ\xF1\x15\x80\x15b\0\x02\xD2W=`\0\x80>=`\0\xFD[PPP`\x01`\x01``\x1B\x03\x19``\x8C\x90\x1B\x16a\x01\x80RPa\x01\xA0\x81\x90R\x85Qa\x01\xC0R\x85Qb\0\x03\x04W`\0b\0\x03\x1BV[\x85`\0\x81Q\x81\x10b\0\x03\x12W\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x01\xE0R\x85Q`\x01\x10b\0\x03>W`\0b\0\x03UV[\x85`\x01\x81Q\x81\x10b\0\x03LW\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x02\0R\x85Q`\x02\x10b\0\x03xW`\0b\0\x03\x8FV[\x85`\x02\x81Q\x81\x10b\0\x03\x86W\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x02 R\x85Q`\x03\x10b\0\x03\xB2W`\0b\0\x03\xC9V[\x85`\x03\x81Q\x81\x10b\0\x03\xC0W\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x02@R\x85Q`\x04\x10b\0\x03\xECW`\0b\0\x04\x03V[\x85`\x04\x81Q\x81\x10b\0\x03\xFAW\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x02`R\x85Q`\x05\x10b\0\x04&W`\0b\0\x04=V[\x85`\x05\x81Q\x81\x10b\0\x044W\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x02\x80R\x85Q`\x06\x10b\0\x04`W`\0b\0\x04wV[\x85`\x06\x81Q\x81\x10b\0\x04nW\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x02\xA0R\x85Q`\x07\x10b\0\x04\x9AW`\0b\0\x04\xB1V[\x85`\x07\x81Q\x81\x10b\0\x04\xA8W\xFE[` \x02` \x01\x01Q[``\x1B`\x01`\x01``\x1B\x03\x19\x16a\x02\xC0R\x85Qb\0\x04\xD1W`\0b\0\x04\xF7V[b\0\x04\xF7\x86`\0\x81Q\x81\x10b\0\x04\xE3W\xFE[` \x02` \x01\x01Qb\0\x08\xF5` \x1B` \x1CV[a\x02\xE0R\x85Q`\x01\x10b\0\x05\rW`\0b\0\x05\x1FV[b\0\x05\x1F\x86`\x01\x81Q\x81\x10b\0\x04\xE3W\xFE[a\x03\0R\x85Q`\x02\x10b\0\x055W`\0b\0\x05GV[b\0\x05G\x86`\x02\x81Q\x81\x10b\0\x04\xE3W\xFE[a\x03 R\x85Q`\x03\x10b\0\x05]W`\0b\0\x05oV[b\0\x05o\x86`\x03\x81Q\x81\x10b\0\x04\xE3W\xFE[a\x03@R\x85Q`\x04\x10b\0\x05\x85W`\0b\0\x05\x97V[b\0\x05\x97\x86`\x04\x81Q\x81\x10b\0\x04\xE3W\xFE[a\x03`R\x85Q`\x05\x10b\0\x05\xADW`\0b\0\x05\xBFV[b\0\x05\xBF\x86`\x05\x81Q\x81\x10b\0\x04\xE3W\xFE[a\x03\x80R\x85Q`\x06\x10b\0\x05\xD5W`\0b\0\x05\xE7V[b\0\x05\xE7\x86`\x06\x81Q\x81\x10b\0\x04\xE3W\xFE[a\x03\xA0R\x85Q`\x07\x10b\0\x05\xFDW`\0b\0\x06\x0FV[b\0\x06\x0F\x86`\x07\x81Q\x81\x10b\0\x04\xE3W\xFE[a\x03\xC0\x81\x81RPPPPPPPPPPPPPPPPPPPP`\0\x86Q\x90Pb\0\x06G\x81\x87Qb\0\t\x97` \x1Bb\0\re\x17` \x1CV[`\0\x80`\0\x80[\x84\x81`\xFF\x16\x10\x15b\0\x06\xCDW`\0\x8A\x82`\xFF\x16\x81Q\x81\x10b\0\x06lW\xFE[` \x02` \x01\x01Q\x90Pb\0\x06\x94f#\x86\xF2o\xC1\0\0\x82\x10\x15a\x01.b\0\x08e` \x1B` \x1CV[b\0\x06\xAE\x81\x86b\0\t\xA6` \x1Bb\0\rr\x17\x90\x91\x90` \x1CV[\x94P\x82\x81\x11\x15b\0\x06\xC3W\x81`\xFF\x16\x93P\x80\x92P[P`\x01\x01b\0\x06NV[Pb\0\x06\xE6g\r\xE0\xB6\xB3\xA7d\0\0\x84\x14a\x014b\0\x08eV[a\x03\xE0\x82\x90R\x88Qb\0\x06\xFBW`\0b\0\x07\x12V[\x88`\0\x81Q\x81\x10b\0\x07\tW\xFE[` \x02` \x01\x01Q[a\x04\0R\x88Q`\x01\x10b\0\x07(W`\0b\0\x07?V[\x88`\x01\x81Q\x81\x10b\0\x076W\xFE[` \x02` \x01\x01Q[a\x04 R\x88Q`\x02\x10b\0\x07UW`\0b\0\x07lV[\x88`\x02\x81Q\x81\x10b\0\x07cW\xFE[` \x02` \x01\x01Q[a\x04@R\x88Q`\x03\x10b\0\x07\x82W`\0b\0\x07\x99V[\x88`\x03\x81Q\x81\x10b\0\x07\x90W\xFE[` \x02` \x01\x01Q[a\x04`R\x88Q`\x04\x10b\0\x07\xAFW`\0b\0\x07\xC6V[\x88`\x04\x81Q\x81\x10b\0\x07\xBDW\xFE[` \x02` \x01\x01Q[a\x04\x80R\x88Q`\x05\x10b\0\x07\xDCW`\0b\0\x07\xF3V[\x88`\x05\x81Q\x81\x10b\0\x07\xEAW\xFE[` \x02` \x01\x01Q[a\x04\xA0R\x88Q`\x06\x10b\0\x08\tW`\0b\0\x08 V[\x88`\x06\x81Q\x81\x10b\0\x08\x17W\xFE[` \x02` \x01\x01Q[a\x04\xC0R\x88Q`\x07\x10b\0\x086W`\0b\0\x08MV[\x88`\x07\x81Q\x81\x10b\0\x08DW\xFE[` \x02` \x01\x01Q[a\x04\xE0RPb\0\x0F2\x9BPPPPPPPPPPPPV[\x81b\0\x08vWb\0\x08v\x81b\0\t\xC3V[PPV[\x80b\0\x08v\x81b\0\n\x16V[b\0\x08\x9Bd\xE8\xD4\xA5\x10\0\x82\x10\x15`\xCBb\0\x08eV[b\0\x08\xB3g\x01cEx]\x8A\0\0\x82\x11\x15`\xCAb\0\x08eV[`\x07\x81\x90U`@Q\x7F\xA9\xBA?\xFE\x0Bl6k\x81#,\xAA\xB3\x86\x05\xA0i\x9A\xD59\x8Dl\xCEv\xF9\x1E\xE8\t\xE3\"\xDA\xFC\x90b\0\x08\xEA\x90\x83\x90b\0\x0E\xC0V[`@Q\x80\x91\x03\x90\xA1PV[`\0\x80\x82`\x01`\x01`\xA0\x1B\x03\x16c1<\xE5g`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15b\0\t2W`\0\x80\xFD[PZ\xFA\x15\x80\x15b\0\tGW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90b\0\tm\x91\x90b\0\r\xECV[`\xFF\x16\x90P`\0b\0\t\x8C`\x12\x83b\0\n\xA3` \x1Bb\0\r\x84\x17` \x1CV[`\n\n\x94\x93PPPPV[b\0\x08v\x82\x82\x14`gb\0\x08eV[`\0\x82\x82\x01b\0\t\xBA\x84\x82\x10\x15\x83b\0\x08eV[\x90P[\x92\x91PPV[bF\x1B\xCD`\xE5\x1B`\0\x90\x81R` `\x04R`\x07`$RfBAL#\0\x000`\n\x80\x84\x04\x81\x81\x06`0\x90\x81\x01`\x08\x1B\x95\x83\x90\x06\x95\x90\x95\x01\x90\x82\x90\x04\x91\x82\x06\x90\x94\x01`\x10\x1B\x93\x90\x93\x01\x01`\xC8\x1B`DR`d\x90\xFD[`\x02\x81Q\x10\x15b\0\n'Wb\0\n\xA0V[`\0\x81`\0\x81Q\x81\x10b\0\n7W\xFE[` \x02` \x01\x01Q\x90P`\0`\x01\x90P[\x82Q\x81\x10\x15b\0\n\x9DW`\0\x83\x82\x81Q\x81\x10b\0\naW\xFE[` \x02` \x01\x01Q\x90Pb\0\n\x92\x81`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x10`eb\0\x08e` \x1B` \x1CV[\x91P`\x01\x01b\0\nHV[PP[PV[`\0b\0\n\xB5\x83\x83\x11\x15`\x01b\0\x08eV[P\x90\x03\x90V[\x82\x80T`\x01\x81`\x01\x16\x15a\x01\0\x02\x03\x16`\x02\x90\x04\x90`\0R` `\0 \x90`\x1F\x01` \x90\x04\x81\x01\x92\x82`\x1F\x10b\0\n\xFEW\x80Q`\xFF\x19\x16\x83\x80\x01\x17\x85Ub\0\x0B.V[\x82\x80\x01`\x01\x01\x85U\x82\x15b\0\x0B.W\x91\x82\x01[\x82\x81\x11\x15b\0\x0B.W\x82Q\x82U\x91` \x01\x91\x90`\x01\x01\x90b\0\x0B\x11V[Pb\0\x0B<\x92\x91Pb\0\x0B@V[P\x90V[[\x80\x82\x11\x15b\0\x0B\x14a\x04\x0CW\x80c\xF8\x9F'\xED\x14a\x04\x1FWa\x01\xF0V[\x80c\xA9\x05\x9C\xBB\x14a\x03\xB0W\x80c\xAA\xAB\xAD\xC5\x14a\x03\xC3W\x80c\xC0\xFF\x1A\x15\x14a\x03\xCBW\x80c\xD5\x05\xAC\xCF\x14a\x03\xD3Wa\x01\xF0V[\x80c\x8D\x92\x8A\xF8\x11a\0\xDEW\x80c\x8D\x92\x8A\xF8\x14a\x03\x85W\x80c\x95\xD8\x9BA\x14a\x03\x8DW\x80c\x9B\x02\xCD\xDE\x14a\x03\x95W\x80c\x9D,\x11\x0C\x14a\x03\x9DWa\x01\xF0V[\x80c~\xCE\xBE\0\x14a\x037W\x80c\x85\x1C\x1B\xB3\x14a\x03JW\x80c\x87\xECh\x17\x14a\x03]W\x80c\x89= \xE8\x14a\x03pWa\x01\xF0V[\x80c8\xE9\x92.\x11a\x01\x87W\x80cf\x18\x84c\x11a\x01VW\x80cf\x18\x84c\x14a\x02\xE8W\x80cg\x9A\xEF\xCE\x14a\x02\xFBW\x80cp\xA0\x821\x14a\x03\x03W\x80ct\xF3\xB0\t\x14a\x03\x16Wa\x01\xF0V[\x80c8\xE9\x92.\x14a\x02\xA4W\x80c8\xFF\xF2\xD0\x14a\x02\xB7W\x80cU\xC6v(\x14a\x02\xBFW\x80c`(\xBF\xD4\x14a\x02\xC7Wa\x01\xF0V[\x80c\x1C\r\xE0Q\x11a\x01\xC3W\x80c\x1C\r\xE0Q\x14a\x02]W\x80c#\xB8r\xDD\x14a\x02tW\x80c1<\xE5g\x14a\x02\x87W\x80c6D\xE5\x15\x14a\x02\x9CWa\x01\xF0V[\x80c\x06\xFD\xDE\x03\x14a\x01\xF5W\x80c\t^\xA7\xB3\x14a\x02\x13W\x80c\x16\xC3\x8B<\x14a\x023W\x80c\x18\x16\r\xDD\x14a\x02HW[`\0\x80\xFD[a\x01\xFDa\x044V[`@Qa\x02\n\x91\x90aFGV[`@Q\x80\x91\x03\x90\xF3[a\x02&a\x02!6`\x04a@\x1CV[a\x04\xCBV[`@Qa\x02\n\x91\x90aE~V[a\x02Fa\x02A6`\x04aA\x13V[a\x04\xE2V[\0[a\x02Pa\x04\xF6V[`@Qa\x02\n\x91\x90aE\xA1V[a\x02ea\x04\xFCV[`@Qa\x02\n\x93\x92\x91\x90aE\x89V[a\x02&a\x02\x826`\x04a?gV[a\x05%V[a\x02\x8Fa\x05\xA8V[`@Qa\x02\n\x91\x90aF\xB3V[a\x02Pa\x05\xADV[a\x02Fa\x02\xB26`\x04aD\x9DV[a\x05\xBCV[a\x02Pa\x05\xD5V[a\x02Pa\x05\xF9V[a\x02\xDAa\x02\xD56`\x04aAKV[a\x05\xFFV[`@Qa\x02\n\x92\x91\x90aF\x9AV[a\x02&a\x02\xF66`\x04a@\x1CV[a\x066V[a\x02Pa\x06\x90V[a\x02Pa\x03\x116`\x04a?\x13V[a\x06\xBBV[a\x03)a\x03$6`\x04aAKV[a\x06\xDAV[`@Qa\x02\n\x92\x91\x90aEYV[a\x02Pa\x03E6`\x04a?\x13V[a\x07|V[a\x02Pa\x03X6`\x04aBHV[a\x07\x97V[a\x02\xDAa\x03k6`\x04aAKV[a\x07\xE9V[a\x03xa\x08\x0FV[`@Qa\x02\n\x91\x90aE2V[a\x03xa\x083V[a\x01\xFDa\x08WV[a\x02Pa\x08\xB8V[a\x02Pa\x03\xAB6`\x04aC\xA1V[a\x08\xBEV[a\x02&a\x03\xBE6`\x04a@\x1CV[a\t\xA5V[a\x03xa\t\xB2V[a\x02Pa\t\xBCV[a\x02Fa\x03\xE16`\x04a?\xA7V[a\n\x80V[a\x03)a\x03\xF46`\x04aAKV[a\x0B\xC9V[a\x02&a\x04\x076`\x04a@\x1CV[a\x0C\xECV[a\x02Pa\x04\x1A6`\x04a?/V[a\r\"V[a\x04'a\rMV[`@Qa\x02\n\x91\x90aEFV[`\x03\x80T`@\x80Q` `\x1F`\x02`\0\x19a\x01\0`\x01\x88\x16\x15\x02\x01\x90\x95\x16\x94\x90\x94\x04\x93\x84\x01\x81\x90\x04\x81\x02\x82\x01\x81\x01\x90\x92R\x82\x81R``\x93\x90\x92\x90\x91\x83\x01\x82\x82\x80\x15a\x04\xC0W\x80`\x1F\x10a\x04\x95Wa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x04\xC0V[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x04\xA3W\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x90P[\x90V[`\0a\x04\xD83\x84\x84a\r\x9AV[P`\x01[\x92\x91PPV[a\x04\xEAa\x0E\x02V[a\x04\xF3\x81a\x0E0V[PV[`\x02T\x90V[`\0\x80`\0a\x05\ta\x0E\xAEV[\x15\x92Pa\x05\x14a\x0E\xCBV[\x91Pa\x05\x1Ea\x0E\xEFV[\x90P\x90\x91\x92V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 3\x80\x85R\x92R\x82 T\x91\x92a\x05c\x91\x14\x80a\x05[WP\x83\x82\x10\x15[a\x01\x97a\x0F\x13V[a\x05n\x85\x85\x85a\x0F!V[3`\x01`\x01`\xA0\x1B\x03\x86\x16\x14\x80\x15\x90a\x05\x89WP`\0\x19\x81\x14\x15[\x15a\x05\x9BWa\x05\x9B\x853\x85\x84\x03a\r\x9AV[`\x01\x91PP[\x93\x92PPPV[`\x12\x90V[`\0a\x05\xB7a\x0F\xF0V[\x90P\x90V[a\x05\xC4a\x0E\x02V[a\x05\xCCa\x10\x8DV[a\x04\xF3\x81a\x10\xA2V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[`\x07T\x90V[`\0``a\x06\x15\x86Qa\x06\x10a\x11\0V[a\reV[a\x06*\x89\x89\x89\x89\x89\x89\x89a\x11$a\x11\xECa\x12RV[\x97P\x97\x95PPPPPPV[3`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 `\x01`\x01`\xA0\x1B\x03\x86\x16\x84R\x90\x91R\x81 T\x80\x83\x10a\x06rWa\x06m3\x85`\0a\r\x9AV[a\x06\x86V[a\x06\x863\x85a\x06\x81\x84\x87a\r\x84V[a\r\x9AV[P`\x01\x93\x92PPPV[`\0a\x05\xB7a\x06\x9Da\x04\xF6V[a\x06\xB5a\x06\xA8a\t\xBCV[a\x06\xB0a\x11\0V[a\x13tV[\x90a\x13\x98V[`\x01`\x01`\xA0\x1B\x03\x81\x16`\0\x90\x81R` \x81\x90R`@\x90 T[\x91\x90PV[``\x80\x88a\x07\x04a\x06\xE9a\x083V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14`\xCDa\x0F\x13V[a\x07\x19a\x07\x0Fa\x05\xD5V[\x82\x14a\x01\xF4a\x0F\x13V[``a\x07#a\x13\xE9V[\x90Pa\x07/\x88\x82a\x16fV[`\0``\x80a\x07C\x8E\x8E\x8E\x8E\x8E\x8E\x8Ea\x11$V[\x92P\x92P\x92Pa\x07S\x8D\x84a\x16\xC7V[a\x07]\x82\x85a\x11\xECV[a\x07g\x81\x85a\x11\xECV[\x90\x95P\x93PPP[P\x97P\x97\x95PPPPPPV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R`\x05` R`@\x90 T\x90V[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82`@Q` \x01a\x07\xCC\x92\x91\x90aD\xEFV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[`\0``a\x07\xFA\x86Qa\x06\x10a\x11\0V[a\x06*\x89\x89\x89\x89\x89\x89\x89a\x17Za\x17\xD7a\x12RV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[`\x04\x80T`@\x80Q` `\x1F`\x02`\0\x19a\x01\0`\x01\x88\x16\x15\x02\x01\x90\x95\x16\x94\x90\x94\x04\x93\x84\x01\x81\x90\x04\x81\x02\x82\x01\x81\x01\x90\x92R\x82\x81R``\x93\x90\x92\x90\x91\x83\x01\x82\x82\x80\x15a\x04\xC0W\x80`\x1F\x10a\x04\x95Wa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x04\xC0V[`\x08T\x90V[`\0\x80a\x08\xCE\x85` \x01Qa\x188V[\x90P`\0a\x08\xDF\x86`@\x01Qa\x188V[\x90P`\0\x86Q`\x01\x81\x11\x15a\x08\xF0W\xFE[\x14\x15a\tVWa\t\x03\x86``\x01Qa\x1BMV[``\x87\x01Ra\t\x12\x85\x83a\x1BqV[\x94Pa\t\x1E\x84\x82a\x1BqV[\x93Pa\t.\x86``\x01Q\x83a\x1BqV[``\x87\x01R`\0a\t@\x87\x87\x87a\x1B}V[\x90Pa\tL\x81\x83a\x1B\xB8V[\x93PPPPa\x05\xA1V[a\t`\x85\x83a\x1BqV[\x94Pa\tl\x84\x82a\x1BqV[\x93Pa\t|\x86``\x01Q\x82a\x1BqV[``\x87\x01R`\0a\t\x8E\x87\x87\x87a\x1B\xC4V[\x90Pa\t\x9A\x81\x84a\x1B\xF7V[\x90Pa\tL\x81a\x1C\x03V[`\0a\x04\xD83\x84\x84a\x0F!V[`\0a\x05\xB7a\x1C\x1AV[`\0``a\t\xC8a\x083V[`\x01`\x01`\xA0\x1B\x03\x16c\xF9MFha\t\xDEa\x05\xD5V[`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\t\xFA\x91\x90aE\xA1V[`\0`@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\n\x12W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\n&W=`\0\x80>=`\0\xFD[PPPP`@Q=`\0\x82>`\x1F=\x90\x81\x01`\x1F\x19\x16\x82\x01`@Ra\nN\x91\x90\x81\x01\x90a@GV[P\x91PPa\nc\x81a\n^a\x13\xE9V[a\x16fV[``a\nma\x1C\x94V[\x90Pa\ny\x81\x83a\x1E\xF1V[\x92PPP\x90V[a\n\x8E\x84B\x11\x15`\xD1a\x0F\x13V[`\x01`\x01`\xA0\x1B\x03\x87\x16`\0\x90\x81R`\x05` \x90\x81R`@\x80\x83 T\x90Q\x90\x92\x91a\n\xE5\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x8C\x91\x8C\x91\x8C\x91\x88\x91\x8D\x91\x01aE\xC9V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0a\x0B\x08\x82a\x1FcV[\x90P`\0`\x01\x82\x88\x88\x88`@Q`\0\x81R` \x01`@R`@Qa\x0B/\x94\x93\x92\x91\x90aF)V[` `@Q` \x81\x03\x90\x80\x84\x03\x90\x85Z\xFA\x15\x80\x15a\x0BQW=`\0\x80>=`\0\xFD[PP`@Q`\x1F\x19\x01Q\x91Pa\x0B\x93\x90P`\x01`\x01`\xA0\x1B\x03\x82\x16\x15\x80\x15\x90a\x0B\x8BWP\x8B`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14[a\x01\xF8a\x0F\x13V[`\x01`\x01`\xA0\x1B\x03\x8B\x16`\0\x90\x81R`\x05` R`@\x90 `\x01\x85\x01\x90Ua\x0B\xBC\x8B\x8B\x8Ba\r\x9AV[PPPPPPPPPPPV[``\x80\x88a\x0B\xD8a\x06\xE9a\x083V[a\x0B\xE3a\x07\x0Fa\x05\xD5V[``a\x0B\xEDa\x13\xE9V[\x90Pa\x0B\xF7a\x04\xF6V[a\x0C\x9DW`\0``a\x0C\x0B\x8D\x8D\x8D\x8Aa\x1F\x7FV[\x91P\x91Pa\x0C b\x0FB@\x83\x10\x15`\xCCa\x0F\x13V[a\x0C.`\0b\x0FB@a \x1AV[a\x0C=\x8Bb\x0FB@\x84\x03a \x1AV[a\x0CG\x81\x84a\x17\xD7V[\x80a\x0CPa\x11\0V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x0CfW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x0C\x90W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x95P\x95PPPPa\x07oV[a\x0C\xA7\x88\x82a\x16fV[`\0``\x80a\x0C\xBB\x8E\x8E\x8E\x8E\x8E\x8E\x8Ea\x17ZV[\x92P\x92P\x92Pa\x0C\xCB\x8C\x84a \x1AV[a\x0C\xD5\x82\x85a\x17\xD7V[a\x0C\xDF\x81\x85a\x11\xECV[\x90\x95P\x93Pa\x07o\x91PPV[3`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 `\x01`\x01`\xA0\x1B\x03\x87\x16\x84R\x90\x91R\x81 T\x90\x91a\x04\xD8\x91\x85\x90a\x06\x81\x90\x86a\rrV[`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 \x93\x90\x94\x16\x82R\x91\x90\x91R T\x90V[``a\x05\xB7a\x1C\x94V[\x80a\ra\x81a \xB0V[PPV[a\ra\x81\x83\x14`ga\x0F\x13V[`\0\x82\x82\x01a\x05\xA1\x84\x82\x10\x15\x83a\x0F\x13V[`\0a\r\x94\x83\x83\x11\x15`\x01a\x0F\x13V[P\x90\x03\x90V[`\x01`\x01`\xA0\x1B\x03\x80\x84\x16`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 \x94\x87\x16\x80\x84R\x94\x90\x91R\x90\x81\x90 \x84\x90UQ\x7F\x8C[\xE1\xE5\xEB\xEC}[\xD1OqB}\x1E\x84\xF3\xDD\x03\x14\xC0\xF7\xB2)\x1E[ \n\xC8\xC7\xC3\xB9%\x90a\r\xF5\x90\x85\x90aE\xA1V[`@Q\x80\x91\x03\x90\xA3PPPV[`\0a\x0E\x19`\x005`\x01`\x01`\xE0\x1B\x03\x19\x16a\x07\x97V[\x90Pa\x04\xF3a\x0E(\x823a!)V[a\x01\x91a\x0F\x13V[\x80\x15a\x0EPWa\x0EKa\x0EAa\x0E\xCBV[B\x10a\x01\x93a\x0F\x13V[a\x0EeV[a\x0Eea\x0E[a\x0E\xEFV[B\x10a\x01\xA9a\x0F\x13V[`\x06\x80T`\xFF\x19\x16\x82\x15\x15\x17\x90U`@Q\x7F\x9E:^7\"E2\xDE\xA6{\x89\xFA\xCE\x18W\x03s\x8A\"\x8An\x8A#\xDE\xE5F\x96\x01\x80\xD3\xBEd\x90a\x0E\xA3\x90\x83\x90aE~V[`@Q\x80\x91\x03\x90\xA1PV[`\0a\x0E\xB8a\x0E\xEFV[B\x11\x80a\x05\xB7WPP`\x06T`\xFF\x16\x15\x90V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[\x81a\raWa\ra\x81a\"\x19V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 Ta\x0FI\x82\x82\x10\x15a\x01\x96a\x0F\x13V[a\x0F``\x01`\x01`\xA0\x1B\x03\x84\x16\x15\x15a\x01\x99a\x0F\x13V[`\x01`\x01`\xA0\x1B\x03\x80\x85\x16`\0\x90\x81R` \x81\x90R`@\x80\x82 \x85\x85\x03\x90U\x91\x85\x16\x81R Ta\x0F\x90\x90\x83a\rrV[`\x01`\x01`\xA0\x1B\x03\x80\x85\x16`\0\x81\x81R` \x81\x90R`@\x90\x81\x90 \x93\x90\x93U\x91Q\x90\x86\x16\x90\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x90a\x0F\xE2\x90\x86\x90aE\xA1V[`@Q\x80\x91\x03\x90\xA3PPPPV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x10]a\"lV[0`@Q` \x01a\x10r\x95\x94\x93\x92\x91\x90aE\xFDV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x90V[a\x10\xA0a\x10\x98a\x0E\xAEV[a\x01\x92a\x0F\x13V[V[a\x10\xB5d\xE8\xD4\xA5\x10\0\x82\x10\x15`\xCBa\x0F\x13V[a\x10\xCBg\x01cEx]\x8A\0\0\x82\x11\x15`\xCAa\x0F\x13V[`\x07\x81\x90U`@Q\x7F\xA9\xBA?\xFE\x0Bl6k\x81#,\xAA\xB3\x86\x05\xA0i\x9A\xD59\x8Dl\xCEv\xF9\x1E\xE8\t\xE3\"\xDA\xFC\x90a\x0E\xA3\x90\x83\x90aE\xA1V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[`\0``\x80``a\x113a\x1C\x94V[\x90Pa\x11=a\x0E\xAEV[\x15a\x11tW`\0a\x11N\x82\x8Aa\x1E\xF1V[\x90Pa\x11_\x89\x83`\x08T\x84\x8Ba\"pV[\x92Pa\x11n\x89\x84a\r\x84a#\x80V[Pa\x11\xC0V[a\x11|a\x11\0V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x11\x92W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x11\xBCW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x91P[a\x11\xCB\x88\x82\x87a#\xEBV[\x90\x94P\x92Pa\x11\xDB\x88\x84\x83a$XV[`\x08UP\x97P\x97P\x97\x94PPPPPV[`\0[a\x11\xF7a\x11\0V[\x81\x10\x15a\x12MWa\x12.\x83\x82\x81Q\x81\x10a\x12\rW\xFE[` \x02` \x01\x01Q\x83\x83\x81Q\x81\x10a\x12!W\xFE[` \x02` \x01\x01Qa$qV[\x83\x82\x81Q\x81\x10a\x12:W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a\x11\xEFV[PPPV[30\x14a\x13\x10W`\x000`\x01`\x01`\xA0\x1B\x03\x16`\x006`@Qa\x12v\x92\x91\x90aE\x07V[`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x12\xB3W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x12\xB8V[``\x91P[PP\x90P\x80`\0\x81\x14a\x12\xC7W\xFE[`\x04`\0\x80>`\0Q`\x01`\x01`\xE0\x1B\x03\x19\x16cC\xAD\xBA\xFB`\xE0\x1B\x81\x14a\x12\xF2W=`\0\x80>=`\0\xFD[P` `\x04`\0>`@` R`$=\x03`$`@>`\x1C=\x01`\0\xF3[``a\x13\x1Aa\x13\xE9V[\x90Pa\x13&\x87\x82a\x16fV[`\0``a\x13=\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8Cc\xFF\xFF\xFF\xFF\x16V[P\x91P\x91Pa\x13P\x81\x84\x86c\xFF\xFF\xFF\xFF\x16V[\x80Q`\x1F\x19\x82\x01\x83\x90RcC\xAD\xBA\xFB`?\x19\x83\x01R` \x02`#\x19\x82\x01`D\x82\x01\x81\xFD[`\0\x82\x82\x02a\x05\xA1\x84\x15\x80a\x13\x91WP\x83\x85\x83\x81a\x13\x8EW\xFE[\x04\x14[`\x03a\x0F\x13V[`\0a\x13\xA7\x82\x15\x15`\x04a\x0F\x13V[\x82a\x13\xB4WP`\0a\x04\xDCV[g\r\xE0\xB6\xB3\xA7d\0\0\x83\x81\x02\x90a\x13\xD7\x90\x85\x83\x81a\x13\xCEW\xFE[\x04\x14`\x05a\x0F\x13V[\x82\x81\x81a\x13\xE0W\xFE[\x04\x91PPa\x04\xDCV[```\0a\x13\xF5a\x11\0V[\x90P``\x81g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x14\x10W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x14:W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P\x81\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\0\x81Q\x81\x10a\x14qW\xFE[` \x02` \x01\x01\x81\x81RPPa\x14\x8BV[\x91Pa\x04\xC8\x90PV[`\x01\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x01\x81Q\x81\x10a\x14\xC2W\xFE[` \x02` \x01\x01\x81\x81RPP`\x02\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x02\x81Q\x81\x10a\x15\x05W\xFE[` \x02` \x01\x01\x81\x81RPP`\x03\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x03\x81Q\x81\x10a\x15HW\xFE[` \x02` \x01\x01\x81\x81RPP`\x04\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x04\x81Q\x81\x10a\x15\x8BW\xFE[` \x02` \x01\x01\x81\x81RPP`\x05\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x05\x81Q\x81\x10a\x15\xCEW\xFE[` \x02` \x01\x01\x81\x81RPP`\x06\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x06\x81Q\x81\x10a\x16\x11W\xFE[` \x02` \x01\x01\x81\x81RPP`\x07\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x07\x81Q\x81\x10a\x16TW\xFE[` \x02` \x01\x01\x81\x81RPP\x91PP\x90V[`\0[a\x16qa\x11\0V[\x81\x10\x15a\x12MWa\x16\xA8\x83\x82\x81Q\x81\x10a\x16\x87W\xFE[` \x02` \x01\x01Q\x83\x83\x81Q\x81\x10a\x16\x9BW\xFE[` \x02` \x01\x01Qa\x13tV[\x83\x82\x81Q\x81\x10a\x16\xB4W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a\x16iV[`\x01`\x01`\xA0\x1B\x03\x82\x16`\0\x90\x81R` \x81\x90R`@\x90 Ta\x16\xEF\x82\x82\x10\x15a\x01\x96a\x0F\x13V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 \x82\x82\x03\x90U`\x02Ta\x17\x19\x90\x83a\r\x84V[`\x02U`@Q`\0\x90`\x01`\x01`\xA0\x1B\x03\x85\x16\x90\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x90a\r\xF5\x90\x86\x90aE\xA1V[`\0``\x80a\x17ga\x10\x8DV[``a\x17qa\x1C\x94V[\x90P`\0a\x17\x7F\x82\x8Aa\x1E\xF1V[\x90P``a\x17\x92\x8A\x84`\x08T\x85\x8Ca\"pV[\x90Pa\x17\xA1\x8A\x82a\r\x84a#\x80V[`\0``a\x17\xB0\x8C\x86\x8Ba$\x91V[\x91P\x91Pa\x17\xBF\x8C\x82\x87a$\xEBV[`\x08U\x90\x9E\x90\x9DP\x90\x9BP\x99PPPPPPPPPPV[`\0[a\x17\xE2a\x11\0V[\x81\x10\x15a\x12MWa\x18\x19\x83\x82\x81Q\x81\x10a\x17\xF8W\xFE[` \x02` \x01\x01Q\x83\x83\x81Q\x81\x10a\x18\x0CW\xFE[` \x02` \x01\x01Qa$\xFAV[\x83\x82\x81Q\x81\x10a\x18%W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a\x17\xDAV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x18\x9BWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x18\xFCWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x19]WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x19\xBEWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x1A\x1FWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x1A\x80WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x1A\xE1WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x1BBWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[a\x06\xD5a\x015a\"\x19V[`\0\x80a\x1Be`\x07T\x84a%-\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90Pa\x05\xA1\x83\x82a\r\x84V[`\0a\x05\xA1\x83\x83a\x13tV[`\0a\x1B\x87a\x10\x8DV[a\x1B\xB0\x83a\x1B\x98\x86` \x01Qa%qV[\x84a\x1B\xA6\x88`@\x01Qa%qV[\x88``\x01Qa({V[\x94\x93PPPPV[`\0a\x05\xA1\x83\x83a$qV[`\0a\x1B\xCEa\x10\x8DV[a\x1B\xB0\x83a\x1B\xDF\x86` \x01Qa%qV[\x84a\x1B\xED\x88`@\x01Qa%qV[\x88``\x01Qa(\xF6V[`\0a\x05\xA1\x83\x83a$\xFAV[`\0a\x04\xDCa\x1C\x13`\x07Ta)lV[\x83\x90a)\x92V[`\0a\x1C$a\x083V[`\x01`\x01`\xA0\x1B\x03\x16c\xAA\xAB\xAD\xC5`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1C\\W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1CpW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05\xB7\x91\x90aBpV[```\0a\x1C\xA0a\x11\0V[\x90P``\x81g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x1C\xBBW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x1C\xE5W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P\x81\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\0\x81Q\x81\x10a\x1D\x1CW\xFE[` \x02` \x01\x01\x81\x81RPP`\x01\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x01\x81Q\x81\x10a\x1D_W\xFE[` \x02` \x01\x01\x81\x81RPP`\x02\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x02\x81Q\x81\x10a\x1D\xA2W\xFE[` \x02` \x01\x01\x81\x81RPP`\x03\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x03\x81Q\x81\x10a\x1D\xE5W\xFE[` \x02` \x01\x01\x81\x81RPP`\x04\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x04\x81Q\x81\x10a\x1E(W\xFE[` \x02` \x01\x01\x81\x81RPP`\x05\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x05\x81Q\x81\x10a\x1EkW\xFE[` \x02` \x01\x01\x81\x81RPP`\x06\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x06\x81Q\x81\x10a\x1E\xAEW\xFE[` \x02` \x01\x01\x81\x81RPP`\x07\x82\x11\x15a\x14\x82W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81`\x07\x81Q\x81\x10a\x16TW\xFE[g\r\xE0\xB6\xB3\xA7d\0\0`\0[\x83Q\x81\x10\x15a\x1FSWa\x1FIa\x1FB\x85\x83\x81Q\x81\x10a\x1F\x18W\xFE[` \x02` \x01\x01Q\x85\x84\x81Q\x81\x10a\x1F,W\xFE[` \x02` \x01\x01Qa)\xD4\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x83\x90a*#V[\x91P`\x01\x01a\x1E\xFDV[Pa\x04\xDC`\0\x82\x11a\x017a\x0F\x13V[`\0a\x1Fma\x0F\xF0V[\x82`@Q` \x01a\x07\xCC\x92\x91\x90aE\x17V[`\0``a\x1F\x8Ba\x10\x8DV[`\0a\x1F\x96\x84a*OV[\x90Pa\x1F\xB1`\0\x82`\x02\x81\x11\x15a\x1F\xA9W\xFE[\x14`\xCEa\x0F\x13V[``a\x1F\xBC\x85a*eV[\x90Pa\x1F\xD0a\x1F\xC9a\x11\0V[\x82Qa\reV[a\x1F\xDC\x81a\n^a\x13\xE9V[``a\x1F\xE6a\x1C\x94V[\x90P`\0a\x1F\xF4\x82\x84a\x1E\xF1V[\x90P`\0a \x04\x82a\x06\xB0a\x11\0V[`\x08\x92\x90\x92UP\x99\x91\x98P\x90\x96PPPPPPPV[`\x01`\x01`\xA0\x1B\x03\x82\x16`\0\x90\x81R` \x81\x90R`@\x90 Ta =\x90\x82a\rrV[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 U`\x02Ta c\x90\x82a\rrV[`\x02U`@Q`\x01`\x01`\xA0\x1B\x03\x83\x16\x90`\0\x90\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x90a \xA4\x90\x85\x90aE\xA1V[`@Q\x80\x91\x03\x90\xA3PPV[`\x02\x81Q\x10\x15a \xBFWa\x04\xF3V[`\0\x81`\0\x81Q\x81\x10a \xCEW\xFE[` \x02` \x01\x01Q\x90P`\0`\x01\x90P[\x82Q\x81\x10\x15a\x12MW`\0\x83\x82\x81Q\x81\x10a \xF6W\xFE[` \x02` \x01\x01Q\x90Pa!\x1F\x81`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x10`ea\x0F\x13V[\x91P`\x01\x01a \xDFV[`\0s\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1B\xA1\xBA\x1Ba!Ha\x08\x0FV[`\x01`\x01`\xA0\x1B\x03\x16\x14\x15\x80\x15a!cWPa!c\x83a*{V[\x15a!\x8BWa!pa\x08\x0FV[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14\x90Pa\x04\xDCV[a!\x93a\x1C\x1AV[`\x01`\x01`\xA0\x1B\x03\x16c\x9B\xE2\xA8\x84\x84\x840`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a!\xC2\x93\x92\x91\x90aE\xAAV[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a!\xDAW`\0\x80\xFD[PZ\xFA\x15\x80\x15a!\xEEW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\"\x12\x91\x90aA/V[\x90Pa\x04\xDCV[bF\x1B\xCD`\xE5\x1B`\0\x90\x81R` `\x04R`\x07`$RfBAL#\0\x000`\n\x80\x84\x04\x81\x81\x06`0\x90\x81\x01`\x08\x1B\x95\x83\x90\x06\x95\x90\x95\x01\x90\x82\x90\x04\x91\x82\x06\x90\x94\x01`\x10\x1B\x93\x90\x93\x01\x01`\xC8\x1B`DR`d\x90\xFD[F\x90V[``\x80a\"{a\x11\0V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\"\x91W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\"\xBBW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P\x82a\"\xCAW\x90Pa#wV[a#=\x87\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Q\x81\x10a\"\xF9W\xFE[` \x02` \x01\x01Q\x87\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Q\x81\x10a#-W\xFE[` \x02` \x01\x01Q\x87\x87\x87a*\x95V[\x81\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Q\x81\x10a#iW\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R\x90P[\x95\x94PPPPPV[`\0[a#\x8Ba\x11\0V[\x81\x10\x15a#\xE5Wa#\xC6\x84\x82\x81Q\x81\x10a#\xA1W\xFE[` \x02` \x01\x01Q\x84\x83\x81Q\x81\x10a#\xB5W\xFE[` \x02` \x01\x01Q\x84c\xFF\xFF\xFF\xFF\x16V[\x84\x82\x81Q\x81\x10a#\xD2W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a#\x83V[PPPPV[`\0```\0a#\xFA\x84a*OV[\x90P`\0\x81`\x02\x81\x11\x15a$\nW\xFE[\x14\x15a$%Wa$\x1B\x86\x86\x86a+\rV[\x92P\x92PPa$PV[`\x01\x81`\x02\x81\x11\x15a$3W\xFE[\x14\x15a$CWa$\x1B\x86\x85a+\xEBV[a$\x1B\x86\x86\x86a,\x1DV[P[\x93P\x93\x91PPV[`\0a$g\x84\x84a\r\x84a#\x80V[a\x1B\xB0\x82\x85a\x1E\xF1V[`\0a$\x80\x82\x15\x15`\x04a\x0F\x13V[\x81\x83\x81a$\x89W\xFE[\x04\x93\x92PPPV[`\0```\0a$\xA0\x84a*OV[\x90P`\x01\x81`\x02\x81\x11\x15a$\xB0W\xFE[\x14\x15a$\xC1Wa$\x1B\x86\x86\x86a,\x88V[`\x02\x81`\x02\x81\x11\x15a$\xCFW\xFE[\x14\x15a$\xE0Wa$\x1B\x86\x86\x86a,\xE2V[a$Na\x016a\"\x19V[`\0a$g\x84\x84a\rra#\x80V[`\0a%\t\x82\x15\x15`\x04a\x0F\x13V[\x82a%\x16WP`\0a\x04\xDCV[\x81`\x01\x84\x03\x81a%\"W\xFE[\x04`\x01\x01\x90Pa\x04\xDCV[`\0\x82\x82\x02a%G\x84\x15\x80a\x13\x91WP\x83\x85\x83\x81a\x13\x8EW\xFE[\x80a%VW`\0\x91PPa\x04\xDCV[g\r\xE0\xB6\xB3\xA7d\0\0`\0\x19\x82\x01[\x04`\x01\x01\x91PPa\x04\xDCV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a%\xD4WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a&5WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a&\x96WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a&\xF7WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a'XWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a'\xB9WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a(\x1AWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14\x15a\x1BBWP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06\xD5V[`\0a(\x9Da(\x92\x87g\x04)\xD0i\x18\x9E\0\0a*#V[\x83\x11\x15a\x010a\x0F\x13V[`\0a(\xA9\x87\x84a\rrV[\x90P`\0a(\xB7\x88\x83a)\x92V[\x90P`\0a(\xC5\x88\x87a\x13\x98V[\x90P`\0a(\xD3\x83\x83a-\x8AV[\x90Pa(\xE8a(\xE1\x82a)lV[\x89\x90a*#V[\x9A\x99PPPPPPPPPPV[`\0a)\x18a)\r\x85g\x04)\xD0i\x18\x9E\0\0a*#V[\x83\x11\x15a\x011a\x0F\x13V[`\0a).a)'\x86\x85a\r\x84V[\x86\x90a)\x92V[\x90P`\0a)<\x85\x88a)\x92V[\x90P`\0a)J\x83\x83a-\x8AV[\x90P`\0a)`\x82g\r\xE0\xB6\xB3\xA7d\0\0a\r\x84V[\x90Pa(\xE8\x8A\x82a%-V[`\0g\r\xE0\xB6\xB3\xA7d\0\0\x82\x10a)\x84W`\0a\x04\xDCV[Pg\r\xE0\xB6\xB3\xA7d\0\0\x03\x90V[`\0a)\xA1\x82\x15\x15`\x04a\x0F\x13V[\x82a)\xAEWP`\0a\x04\xDCV[g\r\xE0\xB6\xB3\xA7d\0\0\x83\x81\x02\x90a)\xC8\x90\x85\x83\x81a\x13\xCEW\xFE[\x82`\x01\x82\x03\x81a%eW\xFE[`\0\x80a)\xE1\x84\x84a-\xB6V[\x90P`\0a)\xFBa)\xF4\x83a'\x10a%-V[`\x01a\rrV[\x90P\x80\x82\x10\x15a*\x10W`\0\x92PPPa\x04\xDCV[a*\x1A\x82\x82a\r\x84V[\x92PPPa\x04\xDCV[`\0\x82\x82\x02a*=\x84\x15\x80a\x13\x91WP\x83\x85\x83\x81a\x13\x8EW\xFE[g\r\xE0\xB6\xB3\xA7d\0\0\x90\x04\x93\x92PPPV[`\0\x81\x80` \x01\x90Q\x81\x01\x90a\x04\xDC\x91\x90aB\x8CV[``\x81\x80` \x01\x90Q\x81\x01\x90a\x05\xA1\x91\x90aCRV[`\0a*\x8Dc\x1Ct\xC9\x17`\xE1\x1Ba\x07\x97V[\x90\x91\x14\x91\x90PV[`\0\x83\x83\x11a*\xA6WP`\0a#wV[`\0a*\xB2\x85\x85a)\x92V[\x90P`\0a*\xC8g\r\xE0\xB6\xB3\xA7d\0\0\x88a\x13\x98V[\x90Pa*\xDC\x82g\t\xB6\xE6J\x8E\xC6\0\0a.\xC1V[\x91P`\0a*\xEA\x83\x83a-\x8AV[\x90P`\0a+\x01a*\xFA\x83a)lV[\x8B\x90a*#V[\x90Pa(\xE8\x81\x87a*#V[`\0``a+\x19a\x10\x8DV[`\0\x80a+%\x85a.\xD8V[\x91P\x91Pa+=a+4a\x11\0V[\x82\x10`da\x0F\x13V[``a+Ga\x11\0V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a+]W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a+\x87W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90Pa+\xC6\x88\x83\x81Q\x81\x10a+\x99W\xFE[` \x02` \x01\x01Q\x88\x84\x81Q\x81\x10a+\xADW\xFE[` \x02` \x01\x01Q\x85a+\xBEa\x04\xF6V[`\x07Ta.\xFAV[\x81\x83\x81Q\x81\x10a+\xD2W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R\x91\x97\x91\x96P\x90\x94PPPPPV[`\0```\0a+\xFA\x84a/\xB7V[\x90P``a,\x10\x86\x83a,\x0Ba\x04\xF6V[a/\xCDV[\x91\x96\x91\x95P\x90\x93PPPPV[`\0``a,)a\x10\x8DV[```\0a,6\x85a0\x7FV[\x91P\x91Pa,G\x82Qa\x06\x10a\x11\0V[a,S\x82a\n^a\x13\xE9V[`\0a,k\x88\x88\x85a,ca\x04\xF6V[`\x07Ta0\x97V[\x90Pa,{\x82\x82\x11\x15`\xCFa\x0F\x13V[\x97\x91\x96P\x90\x94PPPPPV[`\0``\x80`\0a,\x98\x85a0\x7FV[\x91P\x91Pa,\xAEa,\xA7a\x11\0V[\x83Qa\reV[a,\xBA\x82a\n^a\x13\xE9V[`\0a,\xD2\x88\x88\x85a,\xCAa\x04\xF6V[`\x07Ta2\xBCV[\x90Pa,{\x82\x82\x10\x15`\xD0a\x0F\x13V[`\0```\0\x80a,\xF2\x85a.\xD8V[\x91P\x91Pa-\x01a+4a\x11\0V[``a-\x0Ba\x11\0V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a-!W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a-KW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90Pa+\xC6\x88\x83\x81Q\x81\x10a-]W\xFE[` \x02` \x01\x01Q\x88\x84\x81Q\x81\x10a-qW\xFE[` \x02` \x01\x01Q\x85a-\x82a\x04\xF6V[`\x07Ta4\xCDV[`\0\x80a-\x97\x84\x84a-\xB6V[\x90P`\0a-\xAAa)\xF4\x83a'\x10a%-V[\x90Pa#w\x82\x82a\rrV[`\0\x81a-\xCCWPg\r\xE0\xB6\xB3\xA7d\0\0a\x04\xDCV[\x82a-\xD9WP`\0a\x04\xDCV[a-\xEA`\x01`\xFF\x1B\x84\x10`\x06a\x0F\x13V[\x82a.\x10w\x0B\xCEP\x86I!\x11\xAE\xA8\x8FK\xB1\xCAk\xCFXA\x81\xEA\x80Y\xF7e2\x84\x10`\x07a\x0F\x13V[\x82`\0g\x0C}q;I\xDA\0\0\x83\x13\x80\x15a.1WPg\x0FC\xFC,\x04\xEE\0\0\x83\x12[\x15a.hW`\0a.A\x84a5oV[\x90Pg\r\xE0\xB6\xB3\xA7d\0\0\x80\x82\x07\x84\x02\x05\x83g\r\xE0\xB6\xB3\xA7d\0\0\x83\x05\x02\x01\x91PPa.vV[\x81a.r\x84a6\x96V[\x02\x90P[g\r\xE0\xB6\xB3\xA7d\0\0\x90\x05a.\xAEh\x028\xFDB\xC5\xCF\x03\xFF\xFF\x19\x82\x12\x80\x15\x90a.\xA7WPh\x07\x0C\x1C\xC7;\0\xC8\0\0\x82\x13\x15[`\x08a\x0F\x13V[a.\xB7\x81a:DV[\x96\x95PPPPPPV[`\0\x81\x83\x10\x15a.\xD1W\x81a\x05\xA1V[P\x90\x91\x90PV[`\0\x80\x82\x80` \x01\x90Q\x81\x01\x90a.\xEF\x91\x90aC\x1CV[\x90\x95\x90\x94P\x92PPPV[`\0\x80a/\x11\x84a/\x0B\x81\x88a\r\x84V[\x90a)\x92V[\x90Pa/*g\t\xB6\xE6J\x8E\xC6\0\0\x82\x10\x15a\x012a\x0F\x13V[`\0a/Ha/Ag\r\xE0\xB6\xB3\xA7d\0\0\x89a\x13\x98V[\x83\x90a-\x8AV[\x90P`\0a/_a/X\x83a)lV[\x8A\x90a*#V[\x90P`\0a/l\x89a)lV[\x90P`\0a/z\x83\x83a%-V[\x90P`\0a/\x88\x84\x83a\r\x84V[\x90Pa/\xA7a/\xA0a/\x99\x8Aa)lV[\x84\x90a*#V[\x82\x90a\rrV[\x9C\x9BPPPPPPPPPPPPV[`\0\x81\x80` \x01\x90Q\x81\x01\x90a\x05\xA1\x91\x90aB\xEFV[```\0a/\xDB\x84\x84a\x13\x98V[\x90P``\x85Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a/\xF7W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a0!W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0[\x86Q\x81\x10\x15a0uWa0V\x83\x88\x83\x81Q\x81\x10a0@W\xFE[` \x02` \x01\x01Qa*#\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x82\x82\x81Q\x81\x10a0bW\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R`\x01\x01a0'V[P\x95\x94PPPPPV[```\0\x82\x80` \x01\x90Q\x81\x01\x90a.\xEF\x91\x90aB\xA8V[`\0``\x84Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a0\xB3W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a0\xDDW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0\x80[\x88Q\x81\x10\x15a1\xA2Wa1=\x89\x82\x81Q\x81\x10a0\xFCW\xFE[` \x02` \x01\x01Qa/\x0B\x89\x84\x81Q\x81\x10a1\x13W\xFE[` \x02` \x01\x01Q\x8C\x85\x81Q\x81\x10a1'W\xFE[` \x02` \x01\x01Qa\r\x84\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x83\x82\x81Q\x81\x10a1IW\xFE[` \x02` \x01\x01\x81\x81RPPa1\x98a1\x91\x89\x83\x81Q\x81\x10a1gW\xFE[` \x02` \x01\x01Q\x85\x84\x81Q\x81\x10a1{W\xFE[` \x02` \x01\x01Qa%-\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x83\x90a\rrV[\x91P`\x01\x01a0\xE4V[Pg\r\xE0\xB6\xB3\xA7d\0\0`\0[\x89Q\x81\x10\x15a2\x9BW`\0\x84\x82\x81Q\x81\x10a1\xC6W\xFE[` \x02` \x01\x01Q\x84\x11\x15a2\x1DW`\0a1\xEFa1\xE3\x86a)lV[\x8D\x85\x81Q\x81\x10a0@W\xFE[\x90P`\0a2\x03\x82\x8C\x86\x81Q\x81\x10a1'W\xFE[\x90Pa2\x14a1\x91a\x1C\x13\x8Ba)lV[\x92PPPa24V[\x88\x82\x81Q\x81\x10a2)W\xFE[` \x02` \x01\x01Q\x90P[`\0a2]\x8C\x84\x81Q\x81\x10a2EW\xFE[` \x02` \x01\x01Qa\x06\xB5\x84\x8F\x87\x81Q\x81\x10a1'W\xFE[\x90Pa2\x8Fa2\x88\x8C\x85\x81Q\x81\x10a2qW\xFE[` \x02` \x01\x01Q\x83a)\xD4\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x85\x90a*#V[\x93PPP`\x01\x01a1\xAFV[Pa2\xAFa2\xA8\x82a)lV[\x87\x90a%-V[\x99\x98PPPPPPPPPV[`\0``\x84Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a2\xD8W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a3\x02W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0\x80[\x88Q\x81\x10\x15a3\xAAWa3b\x89\x82\x81Q\x81\x10a3!W\xFE[` \x02` \x01\x01Qa\x06\xB5\x89\x84\x81Q\x81\x10a38W\xFE[` \x02` \x01\x01Q\x8C\x85\x81Q\x81\x10a3LW\xFE[` \x02` \x01\x01Qa\rr\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x83\x82\x81Q\x81\x10a3nW\xFE[` \x02` \x01\x01\x81\x81RPPa3\xA0a1\x91\x89\x83\x81Q\x81\x10a3\x8CW\xFE[` \x02` \x01\x01Q\x85\x84\x81Q\x81\x10a0@W\xFE[\x91P`\x01\x01a3\tV[Pg\r\xE0\xB6\xB3\xA7d\0\0`\0[\x89Q\x81\x10\x15a4\x8BW`\0\x83\x85\x83\x81Q\x81\x10a3\xCFW\xFE[` \x02` \x01\x01Q\x11\x15a4+W`\0a3\xF4a1\xE3\x86g\r\xE0\xB6\xB3\xA7d\0\0a\r\x84V[\x90P`\0a4\x08\x82\x8C\x86\x81Q\x81\x10a1'W\xFE[\x90Pa4\"a1\x91a\x1FBg\r\xE0\xB6\xB3\xA7d\0\0\x8Ca\r\x84V[\x92PPPa4BV[\x88\x82\x81Q\x81\x10a47W\xFE[` \x02` \x01\x01Q\x90P[`\0a4k\x8C\x84\x81Q\x81\x10a4SW\xFE[` \x02` \x01\x01Qa\x06\xB5\x84\x8F\x87\x81Q\x81\x10a3LW\xFE[\x90Pa4\x7Fa2\x88\x8C\x85\x81Q\x81\x10a2qW\xFE[\x93PPP`\x01\x01a3\xB7V[Pg\r\xE0\xB6\xB3\xA7d\0\0\x81\x10a4\xC1Wa4\xB7a4\xB0\x82g\r\xE0\xB6\xB3\xA7d\0\0a\r\x84V[\x87\x90a*#V[\x93PPPPa#wV[`\0\x93PPPPa#wV[`\0\x80a4\xDE\x84a/\x0B\x81\x88a\rrV[\x90Pa4\xF7g)\xA2$\x1A\xF6,\0\0\x82\x11\x15a\x013a\x0F\x13V[`\0a5\x0Ea/Ag\r\xE0\xB6\xB3\xA7d\0\0\x89a)\x92V[\x90P`\0a5.a5'\x83g\r\xE0\xB6\xB3\xA7d\0\0a\r\x84V[\x8A\x90a%-V[\x90P`\0a5;\x89a)lV[\x90P`\0a5I\x83\x83a%-V[\x90P`\0a5W\x84\x83a\r\x84V[\x90Pa/\xA7a/\xA0a5h\x8Aa)lV[\x84\x90a)\x92V[g\r\xE0\xB6\xB3\xA7d\0\0\x02`\0\x80n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x80\x84\x01\x90n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x0F\xFF\xFF\xFF\xFF\x19\x85\x01\x02\x81a5\xABW\xFE[\x05\x90P`\0n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x82\x80\x02\x05\x90P\x81\x80n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x81\x84\x02\x05\x91P`\x03\x82\x05\x01n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x82\x84\x02\x05\x91P`\x05\x82\x05\x01n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x82\x84\x02\x05\x91P`\x07\x82\x05\x01n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x82\x84\x02\x05\x91P`\t\x82\x05\x01n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x82\x84\x02\x05\x91P`\x0B\x82\x05\x01n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x82\x84\x02\x05\x91P`\r\x82\x05\x01n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x82\x84\x02\x05\x91P`\x0F\x82`\x02\x91\x90\x05\x91\x90\x91\x01\x02\x95\x94PPPPPV[`\0a6\xA6`\0\x83\x13`da\x0F\x13V[g\r\xE0\xB6\xB3\xA7d\0\0\x82\x12\x15a6\xE1Wa6\xD7\x82n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x81a6\xD1W\xFE[\x05a6\x96V[`\0\x03\x90Pa\x06\xD5V[`\0~\x16\0\xEF1r\xE5\x8D.\x93>\xC8\x84\xFD\xE1\0d\xC6;Sr\xD8\x05\xE2\x03\xC0\0\0\0\0\0\0\x83\x12a72Ww\x01\x95\xE5L]\xD4!w\xF5:'\x17/\xA9\xECc\x02b\x82p\0\0\0\0\x83\x05\x92Ph\x06\xF0[Y\xD3\xB2\0\0\0\x01[s\x01\x17\x98\0Mu]<\x8B\xC8\xE02\x04\xCFDa\x9E\0\0\0\x83\x12a7jWk\x14%\x98,\xF5\x97\xCD \\\xEFs\x80\x83\x05\x92Ph\x03x-\xAC\xE9\xD9\0\0\0\x01[`d\x92\x83\x02\x92\x02n\x01\x85QD\x81J\x7F\xF8\x05\x98\x0F\xF0\x08@\0\x83\x12a7\xB2Wn\x01\x85QD\x81J\x7F\xF8\x05\x98\x0F\xF0\x08@\0h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\xADx\xEB\xC5\xACb\0\0\0\x01[k\x02\xDF\n\xB5\xA8\n\"\xC6\x1A\xB5\xA7\0\x83\x12a7\xEDWk\x02\xDF\n\xB5\xA8\n\"\xC6\x1A\xB5\xA7\0h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92PhV\xBCu\xE2\xD61\0\0\0\x01[i?\x1F\xCE=\xA66\xEA\\\xF8P\x83\x12a8$Wi?\x1F\xCE=\xA66\xEA\\\xF8Ph\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph+^:\xF1k\x18\x80\0\0\x01[i\x01'\xFA'r,\xC0l\xC5\xE2\x83\x12a8[Wi\x01'\xFA'r,\xC0l\xC5\xE2h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\x15\xAF\x1Dx\xB5\x8C@\0\0\x01[h(\x0E`\x11N\xDB\x80]\x03\x83\x12a8\x90Wh(\x0E`\x11N\xDB\x80]\x03h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\n\xD7\x8E\xBCZ\xC6 \0\0\x01[h\x0E\xBC_\xB4\x17F\x12\x11\x10\x83\x12a8\xBBWh\x0E\xBC_\xB4\x17F\x12\x11\x10h\x05k\xC7^-c\x10\0\0\x93\x84\x02\x05\x92\x01[h\x08\xF0\x0Fv\nK-\xB5]\x83\x12a8\xF0Wh\x08\xF0\x0Fv\nK-\xB5]h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\x02\xB5\xE3\xAF\x16\xB1\x88\0\0\x01[h\x06\xF5\xF1wW\x88\x93y7\x83\x12a9%Wh\x06\xF5\xF1wW\x88\x93y7h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Ph\x01Z\xF1\xD7\x8BX\xC4\0\0\x01[h\x06$\x8F3pK(f\x03\x83\x12a9YWh\x06$\x8F3pK(f\x03h\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92Pg\xADx\xEB\xC5\xACb\0\0\x01[h\x05\xC5Hg\x0B\x95\x10\xE7\xAC\x83\x12a9\x8DWh\x05\xC5Hg\x0B\x95\x10\xE7\xACh\x05k\xC7^-c\x10\0\0\x84\x02\x05\x92PgV\xBCu\xE2\xD61\0\0\x01[`\0h\x05k\xC7^-c\x10\0\0\x84\x01h\x05k\xC7^-c\x10\0\0\x80\x86\x03\x02\x81a9\xB0W\xFE[\x05\x90P`\0h\x05k\xC7^-c\x10\0\0\x82\x80\x02\x05\x90P\x81\x80h\x05k\xC7^-c\x10\0\0\x81\x84\x02\x05\x91P`\x03\x82\x05\x01h\x05k\xC7^-c\x10\0\0\x82\x84\x02\x05\x91P`\x05\x82\x05\x01h\x05k\xC7^-c\x10\0\0\x82\x84\x02\x05\x91P`\x07\x82\x05\x01h\x05k\xC7^-c\x10\0\0\x82\x84\x02\x05\x91P`\t\x82\x05\x01h\x05k\xC7^-c\x10\0\0\x82\x84\x02\x05\x91P`\x0B\x82\x05\x01`\x02\x02`d\x85\x82\x01\x05\x97\x96PPPPPPPV[`\0a:sh\x028\xFDB\xC5\xCF\x03\xFF\xFF\x19\x83\x12\x15\x80\x15a:lWPh\x07\x0C\x1C\xC7;\0\xC8\0\0\x83\x13\x15[`\ta\x0F\x13V[`\0\x82\x12\x15a:\xA7Wa:\x88\x82`\0\x03a:DV[n\xC0\x97\xCE{\xC9\x07\x15\xB3K\x9F\x10\0\0\0\0\x81a:\x9FW\xFE[\x05\x90Pa\x06\xD5V[`\0h\x06\xF0[Y\xD3\xB2\0\0\0\x83\x12a:\xE7WPh\x06\xF0[Y\xD3\xB1\xFF\xFF\xFF\x19\x90\x91\x01\x90w\x01\x95\xE5L]\xD4!w\xF5:'\x17/\xA9\xECc\x02b\x82p\0\0\0\0a;\x1DV[h\x03x-\xAC\xE9\xD9\0\0\0\x83\x12a;\x19WPh\x03x-\xAC\xE9\xD8\xFF\xFF\xFF\x19\x90\x91\x01\x90k\x14%\x98,\xF5\x97\xCD \\\xEFs\x80a;\x1DV[P`\x01[`d\x92\x90\x92\x02\x91h\x05k\xC7^-c\x10\0\0h\xADx\xEB\xC5\xACb\0\0\0\x84\x12a;mWh\xADx\xEB\xC5\xACa\xFF\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0n\x01\x85QD\x81J\x7F\xF8\x05\x98\x0F\xF0\x08@\0\x82\x02\x05\x90P[hV\xBCu\xE2\xD61\0\0\0\x84\x12a;\xA9WhV\xBCu\xE2\xD60\xFF\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0k\x02\xDF\n\xB5\xA8\n\"\xC6\x1A\xB5\xA7\0\x82\x02\x05\x90P[h+^:\xF1k\x18\x80\0\0\x84\x12a;\xE3Wh+^:\xF1k\x18\x7F\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0i?\x1F\xCE=\xA66\xEA\\\xF8P\x82\x02\x05\x90P[h\x15\xAF\x1Dx\xB5\x8C@\0\0\x84\x12a<\x1DWh\x15\xAF\x1Dx\xB5\x8C?\xFF\xFF\x19\x90\x93\x01\x92h\x05k\xC7^-c\x10\0\0i\x01'\xFA'r,\xC0l\xC5\xE2\x82\x02\x05\x90P[h\n\xD7\x8E\xBCZ\xC6 \0\0\x84\x12a=W\x80\x81\xFD[\x81Qa>Pa>K\x82aF\xE8V[aF\xC1V[\x81\x81R\x91P` \x80\x83\x01\x90\x84\x81\x01\x81\x84\x02\x86\x01\x82\x01\x87\x10\x15a>qW`\0\x80\xFD[`\0[\x84\x81\x10\x15a>\x90W\x81Q\x84R\x92\x82\x01\x92\x90\x82\x01\x90`\x01\x01a>tV[PPPPP\x92\x91PPV[`\0\x82`\x1F\x83\x01\x12a>\xABW\x80\x81\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a>\xC1W\x81\x82\xFD[a>\xD4`\x1F\x82\x01`\x1F\x19\x16` \x01aF\xC1V[\x91P\x80\x82R\x83` \x82\x85\x01\x01\x11\x15a>\xEBW`\0\x80\xFD[\x80` \x84\x01` \x84\x017`\0\x90\x82\x01` \x01R\x92\x91PPV[\x805`\x02\x81\x10a\x04\xDCW`\0\x80\xFD[`\0` \x82\x84\x03\x12\x15a?$W\x80\x81\xFD[\x815a\x05\xA1\x81aG\x08V[`\0\x80`@\x83\x85\x03\x12\x15a?AW\x80\x81\xFD[\x825a?L\x81aG\x08V[\x91P` \x83\x015a?\\\x81aG\x08V[\x80\x91PP\x92P\x92\x90PV[`\0\x80`\0``\x84\x86\x03\x12\x15a?{W\x80\x81\xFD[\x835a?\x86\x81aG\x08V[\x92P` \x84\x015a?\x96\x81aG\x08V[\x92\x95\x92\x94PPP`@\x91\x90\x91\x015\x90V[`\0\x80`\0\x80`\0\x80`\0`\xE0\x88\x8A\x03\x12\x15a?\xC1W\x82\x83\xFD[\x875a?\xCC\x81aG\x08V[\x96P` \x88\x015a?\xDC\x81aG\x08V[\x95P`@\x88\x015\x94P``\x88\x015\x93P`\x80\x88\x015`\xFF\x81\x16\x81\x14a?\xFFW\x83\x84\xFD[\x96\x99\x95\x98P\x93\x96\x92\x95\x94`\xA0\x84\x015\x94P`\xC0\x90\x93\x015\x92\x91PPV[`\0\x80`@\x83\x85\x03\x12\x15a@.W\x81\x82\xFD[\x825a@9\x81aG\x08V[\x94` \x93\x90\x93\x015\x93PPPV[`\0\x80`\0``\x84\x86\x03\x12\x15a@[W\x80\x81\xFD[\x83Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a@rW\x82\x83\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a@\x85W\x82\x83\xFD[\x81Qa@\x93a>K\x82aF\xE8V[\x80\x82\x82R` \x80\x83\x01\x92P\x80\x86\x01\x8B\x82\x83\x87\x02\x89\x01\x01\x11\x15a@\xB3W\x87\x88\xFD[\x87\x96P[\x84\x87\x10\x15a@\xDEW\x80Qa@\xCA\x81aG\x08V[\x84R`\x01\x96\x90\x96\x01\x95\x92\x81\x01\x92\x81\x01a@\xB7V[P\x89\x01Q\x90\x97P\x93PPP\x80\x82\x11\x15a@\xF5W\x82\x83\xFD[PaA\x02\x86\x82\x87\x01a>-V[\x92PP`@\x84\x01Q\x90P\x92P\x92P\x92V[`\0` \x82\x84\x03\x12\x15aA$W\x80\x81\xFD[\x815a\x05\xA1\x81aG\x1DV[`\0` \x82\x84\x03\x12\x15aA@W\x80\x81\xFD[\x81Qa\x05\xA1\x81aG\x1DV[`\0\x80`\0\x80`\0\x80`\0`\xE0\x88\x8A\x03\x12\x15aAeW\x80\x81\xFD[\x875\x96P` \x80\x89\x015aAx\x81aG\x08V[\x96P`@\x89\x015aA\x88\x81aG\x08V[\x95P``\x89\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aA\xA4W\x83\x84\xFD[\x81\x8B\x01\x91P\x8B`\x1F\x83\x01\x12aA\xB7W\x83\x84\xFD[\x815aA\xC5a>K\x82aF\xE8V[\x80\x82\x82R\x85\x82\x01\x91P\x85\x85\x01\x8F\x87\x88\x86\x02\x88\x01\x01\x11\x15aA\xE3W\x87\x88\xFD[\x87\x95P[\x83\x86\x10\x15aB\x05W\x805\x83R`\x01\x95\x90\x95\x01\x94\x91\x86\x01\x91\x86\x01aA\xE7V[P\x98PPP`\x80\x8B\x015\x95P`\xA0\x8B\x015\x94P`\xC0\x8B\x015\x92P\x80\x83\x11\x15aB+W\x83\x84\xFD[PPaB9\x8A\x82\x8B\x01a>\x9BV[\x91PP\x92\x95\x98\x91\x94\x97P\x92\x95PV[`\0` \x82\x84\x03\x12\x15aBYW\x80\x81\xFD[\x815`\x01`\x01`\xE0\x1B\x03\x19\x81\x16\x81\x14a\x05\xA1W\x81\x82\xFD[`\0` \x82\x84\x03\x12\x15aB\x81W\x80\x81\xFD[\x81Qa\x05\xA1\x81aG\x08V[`\0` \x82\x84\x03\x12\x15aB\x9DW\x80\x81\xFD[\x81Qa\x05\xA1\x81aG+V[`\0\x80`\0``\x84\x86\x03\x12\x15aB\xBCW\x80\x81\xFD[\x83QaB\xC7\x81aG+V[` \x85\x01Q\x90\x93Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aB\xE3W\x81\x82\xFD[aA\x02\x86\x82\x87\x01a>-V[`\0\x80`@\x83\x85\x03\x12\x15aC\x01W\x81\x82\xFD[\x82QaC\x0C\x81aG+V[` \x93\x90\x93\x01Q\x92\x94\x92\x93PPPV[`\0\x80`\0``\x84\x86\x03\x12\x15aC0W\x80\x81\xFD[\x83QaC;\x81aG+V[` \x85\x01Q`@\x90\x95\x01Q\x90\x96\x94\x95P\x93\x92PPPV[`\0\x80`@\x83\x85\x03\x12\x15aCdW\x81\x82\xFD[\x82QaCo\x81aG+V[` \x84\x01Q\x90\x92Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15aC\x8BW\x81\x82\xFD[aC\x97\x85\x82\x86\x01a>-V[\x91PP\x92P\x92\x90PV[`\0\x80`\0``\x84\x86\x03\x12\x15aC\xB5W\x80\x81\xFD[\x835g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15aC\xCCW\x82\x83\xFD[\x81\x86\x01\x91Pa\x01 \x80\x83\x89\x03\x12\x15aC\xE2W\x83\x84\xFD[aC\xEB\x81aF\xC1V[\x90PaC\xF7\x88\x84a?\x04V[\x81RaD\x06\x88` \x85\x01a>\"V[` \x82\x01RaD\x18\x88`@\x85\x01a>\"V[`@\x82\x01R``\x83\x015``\x82\x01R`\x80\x83\x015`\x80\x82\x01R`\xA0\x83\x015`\xA0\x82\x01RaDH\x88`\xC0\x85\x01a>\"V[`\xC0\x82\x01RaDZ\x88`\xE0\x85\x01a>\"V[`\xE0\x82\x01Ra\x01\0\x80\x84\x015\x83\x81\x11\x15aDrW\x85\x86\xFD[aD~\x8A\x82\x87\x01a>\x9BV[\x91\x83\x01\x91\x90\x91RP\x97` \x87\x015\x97P`@\x90\x96\x015\x95\x94PPPPPV[`\0` \x82\x84\x03\x12\x15aD\xAEW\x80\x81\xFD[P5\x91\x90PV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15aD\xE4W\x81Q\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01aD\xC8V[P\x94\x95\x94PPPPPV[\x91\x82R`\x01`\x01`\xE0\x1B\x03\x19\x16` \x82\x01R`$\x01\x90V[`\0\x82\x84\x837\x91\x01\x90\x81R\x91\x90PV[a\x19\x01`\xF0\x1B\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x01\x90V[`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x81R` \x01\x90V[`\0` \x82Ra\x05\xA1` \x83\x01\x84aD\xB5V[`\0`@\x82RaEl`@\x83\x01\x85aD\xB5V[\x82\x81\x03` \x84\x01Ra#w\x81\x85aD\xB5V[\x90\x15\x15\x81R` \x01\x90V[\x92\x15\x15\x83R` \x83\x01\x91\x90\x91R`@\x82\x01R``\x01\x90V[\x90\x81R` \x01\x90V[\x92\x83R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16` \x84\x01R\x16`@\x82\x01R``\x01\x90V[\x95\x86R`\x01`\x01`\xA0\x1B\x03\x94\x85\x16` \x87\x01R\x92\x90\x93\x16`@\x85\x01R``\x84\x01R`\x80\x83\x01\x91\x90\x91R`\xA0\x82\x01R`\xC0\x01\x90V[\x94\x85R` \x85\x01\x93\x90\x93R`@\x84\x01\x91\x90\x91R``\x83\x01R`\x01`\x01`\xA0\x1B\x03\x16`\x80\x82\x01R`\xA0\x01\x90V[\x93\x84R`\xFF\x92\x90\x92\x16` \x84\x01R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`\0` \x80\x83R\x83Q\x80\x82\x85\x01R\x82[\x81\x81\x10\x15aFsW\x85\x81\x01\x83\x01Q\x85\x82\x01`@\x01R\x82\x01aFWV[\x81\x81\x11\x15aF\x84W\x83`@\x83\x87\x01\x01R[P`\x1F\x01`\x1F\x19\x16\x92\x90\x92\x01`@\x01\x93\x92PPPV[`\0\x83\x82R`@` \x83\x01Ra\x1B\xB0`@\x83\x01\x84aD\xB5V[`\xFF\x91\x90\x91\x16\x81R` \x01\x90V[`@Q\x81\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15aF\xE0W`\0\x80\xFD[`@R\x91\x90PV[`\0g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15aF\xFEW\x80\x81\xFD[P` \x90\x81\x02\x01\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x04\xF3W`\0\x80\xFD[\x80\x15\x15\x81\x14a\x04\xF3W`\0\x80\xFD[`\x03\x81\x10a\x04\xF3W`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \xA2\xC3\xB6.\x0B\xC5\x05\x07Y\x83\x958~\x15Wa-z\xD5\x9E\x81}\xDA\xE4\xD5'\x99\x07@/\xED\xB4dsolcC\0\x07\x01\x003\xA2dipfsX\"\x12 \x1B\xCB:\x95;\0\xC5\xC4\xDC\xF4\xD3\xCFt\xF0G\xF6\x9D%2\x02\x98\xF4\x1Eoc\\\xB0)QoX7dsolcC\0\x07\x01\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.vault,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { vault: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256[],uint256,address)` and selector `0xfbce0393`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub weights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256[],uint256, + /// address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.weights, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + weights: tuple.3, + swapFeePercentage: tuple.4, + owner: tuple.5, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [251u8, 206u8, 3u8, 147u8]; + const SIGNATURE: &'static str = + "create(string,string,address[],uint256[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.weights), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2WeightedPoolFactory`](self) function + /// calls. + #[derive(Clone)] + pub enum BalancerV2WeightedPoolFactoryCalls { + #[allow(missing_docs)] + create(createCall), + } + impl BalancerV2WeightedPoolFactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[251u8, 206u8, 3u8, 147u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(create)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2WeightedPoolFactoryCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 320usize; + const NAME: &'static str = "BalancerV2WeightedPoolFactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPoolFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPoolFactoryCalls, + >] = &[{ + fn create( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolFactoryCalls::create) + } + create + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2WeightedPoolFactory`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2WeightedPoolFactoryEvents { + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2WeightedPoolFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, 73u8, + 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, 188u8, + 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(PoolCreated)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2WeightedPoolFactoryEvents { + const COUNT: usize = 1usize; + const NAME: &'static str = "BalancerV2WeightedPoolFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2WeightedPoolFactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2WeightedPoolFactoryInstance { + BalancerV2WeightedPoolFactoryInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + BalancerV2WeightedPoolFactoryInstance::::deploy(__provider, vault) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + BalancerV2WeightedPoolFactoryInstance::::deploy_builder(__provider, vault) + } + /**A [`BalancerV2WeightedPoolFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2WeightedPoolFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2WeightedPoolFactoryInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2WeightedPoolFactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2WeightedPoolFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPoolFactory`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, vault); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + vault: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { vault })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2WeightedPoolFactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2WeightedPoolFactoryInstance { + BalancerV2WeightedPoolFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + weights: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + weights, + swapFeePercentage, + owner, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2WeightedPoolFactory::BalancerV2WeightedPoolFactoryInstance< + ::alloy_provider::DynProvider, +>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9"), + Some(12272147u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv3/Cargo.toml b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv3/Cargo.toml new file mode 100644 index 0000000000..7978bc8ca0 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv3/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2weightedpoolfactoryv3" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv3/src/lib.rs b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv3/src/lib.rs new file mode 100644 index 0000000000..ed8832987d --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv3/src/lib.rs @@ -0,0 +1,1499 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2WeightedPoolFactoryV3 { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory normalizedWeights, address[] memory rateProviders, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "factoryVersion", + "type": "string", + "internalType": "string" + }, + { + "name": "poolVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "normalizedWeights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2WeightedPoolFactoryV3 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub factoryVersion: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub poolVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.factoryVersion, + value.poolVersion, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + factoryVersion: tuple.2, + poolVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.factoryVersion, + ), + ::tokenize( + &self.poolVersion, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256[],address[],uint256,address)` and selector `0x80773a93`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory normalizedWeights, address[] memory rateProviders, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub normalizedWeights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256[],address[],uint256, + /// address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.normalizedWeights, + value.rateProviders, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + normalizedWeights: tuple.3, + rateProviders: tuple.4, + swapFeePercentage: tuple.5, + owner: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [128u8, 119u8, 58u8, 147u8]; + const SIGNATURE: &'static str = + "create(string,string,address[],uint256[],address[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.normalizedWeights), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2WeightedPoolFactoryV3`](self) function + /// calls. + #[derive(Clone)] + pub enum BalancerV2WeightedPoolFactoryV3Calls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2WeightedPoolFactoryV3Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 39u8, 112u8, 219u8], + [84u8, 253u8, 77u8, 80u8], + [128u8, 119u8, 58u8, 147u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(disable), + ::core::stringify!(version), + ::core::stringify!(create), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2WeightedPoolFactoryV3Calls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2WeightedPoolFactoryV3Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPoolFactoryV3Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolFactoryV3Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolFactoryV3Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolFactoryV3Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPoolFactoryV3Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolFactoryV3Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolFactoryV3Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolFactoryV3Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2WeightedPoolFactoryV3`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2WeightedPoolFactoryV3Events { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2WeightedPoolFactoryV3Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2WeightedPoolFactoryV3Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2WeightedPoolFactoryV3Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2WeightedPoolFactoryV3Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPoolFactoryV3`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolFactoryV3Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2WeightedPoolFactoryV3Instance { + BalancerV2WeightedPoolFactoryV3Instance::::new(address, __provider) + } + /**A [`BalancerV2WeightedPoolFactoryV3`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2WeightedPoolFactoryV3`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2WeightedPoolFactoryV3Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2WeightedPoolFactoryV3Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2WeightedPoolFactoryV3Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryV3Instance + { + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPoolFactoryV3`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolFactoryV3Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2WeightedPoolFactoryV3Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2WeightedPoolFactoryV3Instance { + BalancerV2WeightedPoolFactoryV3Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryV3Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + normalizedWeights: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + rateProviders: alloy_sol_types::private::Vec, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + normalizedWeights, + rateProviders, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryV3Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2WeightedPoolFactoryV3::BalancerV2WeightedPoolFactoryV3Instance< + ::alloy_provider::DynProvider, +>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x5Dd94Da3644DDD055fcf6B3E1aa310Bb7801EB8b"), + Some(16520627u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xA0DAbEBAAd1b243BBb243f933013d560819eB66f"), + Some(72832703u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x6e4cF292C5349c79cCd66349c3Ed56357dD11B46"), + Some(25474982u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xC128a9954e6c874eA3d62ce62B468bA073093F25"), + Some(26226256u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x82e4cFaef85b1B6299935340c964C942280327f4"), + Some(39036828u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x94f68b54191F62f781Fe8298A8A5Fa3ed772d227"), + Some(26389236u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv4/Cargo.toml b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv4/Cargo.toml new file mode 100644 index 0000000000..65c20b6a27 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv4/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv2weightedpoolfactoryv4" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv4/src/lib.rs b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv4/src/lib.rs new file mode 100644 index 0000000000..792af07fa8 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv2weightedpoolfactoryv4/src/lib.rs @@ -0,0 +1,1511 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BalancerV2WeightedPoolFactoryV4 { + event FactoryDisabled(); + event PoolCreated(address indexed pool); + + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory normalizedWeights, address[] memory rateProviders, uint256 swapFeePercentage, address owner) external returns (address); + function disable() external; + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "protocolFeeProvider", + "type": "address", + "internalType": "contract IProtocolFeePercentagesProvider" + }, + { + "name": "factoryVersion", + "type": "string", + "internalType": "string" + }, + { + "name": "poolVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "name", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol", + "type": "string", + "internalType": "string" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "normalizedWeights", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "rateProviders", + "type": "address[]", + "internalType": "contract IRateProvider[]" + }, + { + "name": "swapFeePercentage", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "disable", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FactoryDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "pool", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV2WeightedPoolFactoryV4 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FactoryDisabled()` and selector `0x432acbfd662dbb5d8b378384a67159b47ca9d0f1b79f97cf64cf8585fa362d50`. + ```solidity + event FactoryDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FactoryDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FactoryDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FactoryDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, + 207u8, 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FactoryDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FactoryDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FactoryDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address)` and selector `0x83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc`. + ```solidity + event PoolCreated(address indexed pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, + 221u8, 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { pool: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.pool.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.pool, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address protocolFeeProvider, string factoryVersion, string poolVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub protocolFeeProvider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub factoryVersion: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub poolVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value.vault, + value.protocolFeeProvider, + value.factoryVersion, + value.poolVersion, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + protocolFeeProvider: tuple.1, + factoryVersion: tuple.2, + poolVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.protocolFeeProvider, + ), + ::tokenize( + &self.factoryVersion, + ), + ::tokenize( + &self.poolVersion, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(string,string,address[],uint256[],address[],uint256,address)` and selector `0x80773a93`. + ```solidity + function create(string memory name, string memory symbol, address[] memory tokens, uint256[] memory normalizedWeights, address[] memory rateProviders, uint256 swapFeePercentage, address owner) external returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub name: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub normalizedWeights: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub rateProviders: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(string,string,address[],uint256[],address[],uint256, + /// address)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.name, + value.symbol, + value.tokens, + value.normalizedWeights, + value.rateProviders, + value.swapFeePercentage, + value.owner, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name: tuple.0, + symbol: tuple.1, + tokens: tuple.2, + normalizedWeights: tuple.3, + rateProviders: tuple.4, + swapFeePercentage: tuple.5, + owner: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [128u8, 119u8, 58u8, 147u8]; + const SIGNATURE: &'static str = + "create(string,string,address[],uint256[],address[],uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name, + ), + ::tokenize( + &self.symbol, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.normalizedWeights), + as alloy_sol_types::SolType>::tokenize(&self.rateProviders), + as alloy_sol_types::SolType>::tokenize(&self.swapFeePercentage), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `disable()` and selector `0x2f2770db`. + ```solidity + function disable() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableCall; + ///Container type for the return parameters of the + /// [`disable()`](disableCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct disableReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: disableReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for disableReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl disableReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for disableCall { + type Parameters<'a> = (); + type Return = disableReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + const SIGNATURE: &'static str = "disable()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + disableReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV2WeightedPoolFactoryV4`](self) function + /// calls. + #[derive(Clone)] + pub enum BalancerV2WeightedPoolFactoryV4Calls { + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + disable(disableCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV2WeightedPoolFactoryV4Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 39u8, 112u8, 219u8], + [84u8, 253u8, 77u8, 80u8], + [128u8, 119u8, 58u8, 147u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(disable), + ::core::stringify!(version), + ::core::stringify!(create), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV2WeightedPoolFactoryV4Calls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV2WeightedPoolFactoryV4Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::create(_) => ::SELECTOR, + Self::disable(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPoolFactoryV4Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolFactoryV4Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolFactoryV4Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(BalancerV2WeightedPoolFactoryV4Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV2WeightedPoolFactoryV4Calls, + >] = &[ + { + fn disable( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolFactoryV4Calls::disable) + } + disable + }, + { + fn version( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolFactoryV4Calls::version) + } + version + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(BalancerV2WeightedPoolFactoryV4Calls::create) + } + create + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::disable(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::disable(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV2WeightedPoolFactoryV4`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV2WeightedPoolFactoryV4Events { + #[allow(missing_docs)] + FactoryDisabled(FactoryDisabled), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl BalancerV2WeightedPoolFactoryV4Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 67u8, 42u8, 203u8, 253u8, 102u8, 45u8, 187u8, 93u8, 139u8, 55u8, 131u8, 132u8, + 166u8, 113u8, 89u8, 180u8, 124u8, 169u8, 208u8, 241u8, 183u8, 159u8, 151u8, 207u8, + 100u8, 207u8, 133u8, 133u8, 250u8, 54u8, 45u8, 80u8, + ], + [ + 131u8, 164u8, 143u8, 188u8, 252u8, 153u8, 19u8, 53u8, 49u8, 78u8, 116u8, 208u8, + 73u8, 106u8, 171u8, 106u8, 25u8, 135u8, 233u8, 146u8, 221u8, 200u8, 93u8, 221u8, + 188u8, 196u8, 214u8, 221u8, 110u8, 242u8, 233u8, 252u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(FactoryDisabled), + ::core::stringify!(PoolCreated), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for BalancerV2WeightedPoolFactoryV4Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "BalancerV2WeightedPoolFactoryV4Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FactoryDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for BalancerV2WeightedPoolFactoryV4Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FactoryDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPoolFactoryV4`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolFactoryV4Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV2WeightedPoolFactoryV4Instance { + BalancerV2WeightedPoolFactoryV4Instance::::new(address, __provider) + } + /**A [`BalancerV2WeightedPoolFactoryV4`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV2WeightedPoolFactoryV4`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV2WeightedPoolFactoryV4Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV2WeightedPoolFactoryV4Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV2WeightedPoolFactoryV4Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryV4Instance + { + /**Creates a new wrapper around an on-chain [`BalancerV2WeightedPoolFactoryV4`](self) contract instance. + + See the [wrapper's documentation](`BalancerV2WeightedPoolFactoryV4Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV2WeightedPoolFactoryV4Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV2WeightedPoolFactoryV4Instance { + BalancerV2WeightedPoolFactoryV4Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryV4Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + name: alloy_sol_types::private::String, + symbol: alloy_sol_types::private::String, + tokens: alloy_sol_types::private::Vec, + normalizedWeights: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + rateProviders: alloy_sol_types::private::Vec, + swapFeePercentage: alloy_sol_types::private::primitives::aliases::U256, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + name, + symbol, + tokens, + normalizedWeights, + rateProviders, + swapFeePercentage, + owner, + }) + } + + ///Creates a new call builder for the [`disable`] function. + pub fn disable(&self) -> alloy_contract::SolCallBuilder<&P, disableCall, N> { + self.call_builder(&disableCall) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV2WeightedPoolFactoryV4Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FactoryDisabled`] event. + pub fn FactoryDisabled_filter(&self) -> alloy_contract::Event<&P, FactoryDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = BalancerV2WeightedPoolFactoryV4::BalancerV2WeightedPoolFactoryV4Instance< + ::alloy_provider::DynProvider, +>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x897888115Ada5773E02aA29F775430BFB5F34c51"), + Some(16878323u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), + Some(82737545u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), + Some(26665331u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x6CaD2ea22BFA7F4C14Aae92E47F510Cd5C509bc7"), + Some(27055829u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xFc8a407Bba312ac761D8BFe04CE1201904842B76"), + Some(40611103u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x4C32a8a8fDa4E24139B51b456B42290f51d6A1c4"), + Some(1204869u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xc7E5ED1054A24Ef31D827E6F86caA58B3Bc168d7"), + Some(72222060u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), + Some(27739006u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x7920BFa1b2041911b354747CA7A6cDD2dfC50Cfd"), + Some(3424893u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balancerv3batchrouter/Cargo.toml b/contracts/generated/contracts-generated/balancerv3batchrouter/Cargo.toml new file mode 100644 index 0000000000..2fb3bae445 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv3batchrouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balancerv3batchrouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balancerv3batchrouter/src/lib.rs b/contracts/generated/contracts-generated/balancerv3batchrouter/src/lib.rs new file mode 100644 index 0000000000..05ca10c031 --- /dev/null +++ b/contracts/generated/contracts-generated/balancerv3batchrouter/src/lib.rs @@ -0,0 +1,4736 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library IBatchRouter { + struct SwapPathExactAmountIn { address tokenIn; SwapPathStep[] steps; uint256 exactAmountIn; uint256 minAmountOut; } + struct SwapPathExactAmountOut { address tokenIn; SwapPathStep[] steps; uint256 maxAmountIn; uint256 exactAmountOut; } + struct SwapPathStep { address pool; address tokenOut; bool isBuffer; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IBatchRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct SwapPathExactAmountIn { address tokenIn; SwapPathStep[] steps; uint256 exactAmountIn; uint256 minAmountOut; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SwapPathExactAmountIn { + #[allow(missing_docs)] + pub tokenIn: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub steps: + alloy_sol_types::private::Vec<::RustType>, + #[allow(missing_docs)] + pub exactAmountIn: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub minAmountOut: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Vec<::RustType>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SwapPathExactAmountIn) -> Self { + ( + value.tokenIn, + value.steps, + value.exactAmountIn, + value.minAmountOut, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SwapPathExactAmountIn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenIn: tuple.0, + steps: tuple.1, + exactAmountIn: tuple.2, + minAmountOut: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for SwapPathExactAmountIn { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for SwapPathExactAmountIn { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.tokenIn, + ), + as alloy_sol_types::SolType>::tokenize(&self.steps), + as alloy_sol_types::SolType>::tokenize(&self.exactAmountIn), + as alloy_sol_types::SolType>::tokenize(&self.minAmountOut), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for SwapPathExactAmountIn { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for SwapPathExactAmountIn { + const NAME: &'static str = "SwapPathExactAmountIn"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "SwapPathExactAmountIn(address tokenIn,SwapPathStep[] steps,uint256 \ + exactAmountIn,uint256 minAmountOut)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + let mut components = alloy_sol_types::private::Vec::with_capacity(1); + components.push(::eip712_root_type()); + components + .extend(::eip712_components()); + components + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.tokenIn, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.steps) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.exactAmountIn) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.minAmountOut) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for SwapPathExactAmountIn { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.tokenIn, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.steps) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.exactAmountIn, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.minAmountOut, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.tokenIn, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.steps, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.exactAmountIn, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.minAmountOut, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct SwapPathExactAmountOut { address tokenIn; SwapPathStep[] steps; uint256 maxAmountIn; uint256 exactAmountOut; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SwapPathExactAmountOut { + #[allow(missing_docs)] + pub tokenIn: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub steps: + alloy_sol_types::private::Vec<::RustType>, + #[allow(missing_docs)] + pub maxAmountIn: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub exactAmountOut: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Vec<::RustType>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SwapPathExactAmountOut) -> Self { + ( + value.tokenIn, + value.steps, + value.maxAmountIn, + value.exactAmountOut, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SwapPathExactAmountOut { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenIn: tuple.0, + steps: tuple.1, + maxAmountIn: tuple.2, + exactAmountOut: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for SwapPathExactAmountOut { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for SwapPathExactAmountOut { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.tokenIn, + ), + as alloy_sol_types::SolType>::tokenize(&self.steps), + as alloy_sol_types::SolType>::tokenize(&self.maxAmountIn), + as alloy_sol_types::SolType>::tokenize(&self.exactAmountOut), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for SwapPathExactAmountOut { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for SwapPathExactAmountOut { + const NAME: &'static str = "SwapPathExactAmountOut"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "SwapPathExactAmountOut(address tokenIn,SwapPathStep[] steps,uint256 \ + maxAmountIn,uint256 exactAmountOut)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + let mut components = alloy_sol_types::private::Vec::with_capacity(1); + components.push(::eip712_root_type()); + components + .extend(::eip712_components()); + components + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.tokenIn, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.steps) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.maxAmountIn) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.exactAmountOut, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for SwapPathExactAmountOut { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.tokenIn, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.steps) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.maxAmountIn, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.exactAmountOut, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.tokenIn, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.steps, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.maxAmountIn, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.exactAmountOut, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct SwapPathStep { address pool; address tokenOut; bool isBuffer; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SwapPathStep { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenOut: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub isBuffer: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SwapPathStep) -> Self { + (value.pool, value.tokenOut, value.isBuffer) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SwapPathStep { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + pool: tuple.0, + tokenOut: tuple.1, + isBuffer: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for SwapPathStep { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for SwapPathStep { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.pool, + ), + ::tokenize( + &self.tokenOut, + ), + ::tokenize( + &self.isBuffer, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for SwapPathStep { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for SwapPathStep { + const NAME: &'static str = "SwapPathStep"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "SwapPathStep(address pool,address tokenOut,bool isBuffer)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.pool, + ) + .0, + ::eip712_data_word( + &self.tokenOut, + ) + .0, + ::eip712_data_word( + &self.isBuffer, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for SwapPathStep { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.pool, + ) + + ::topic_preimage_length( + &rust.tokenOut, + ) + + ::topic_preimage_length( + &rust.isBuffer, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.pool, + out, + ); + ::encode_topic_preimage( + &rust.tokenOut, + out, + ); + ::encode_topic_preimage( + &rust.isBuffer, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IBatchRouter`](self) contract instance. + + See the [wrapper's documentation](`IBatchRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IBatchRouterInstance { + IBatchRouterInstance::::new(address, __provider) + } + /**A [`IBatchRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IBatchRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IBatchRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IBatchRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IBatchRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IBatchRouterInstance + { + /**Creates a new wrapper around an on-chain [`IBatchRouter`](self) contract instance. + + See the [wrapper's documentation](`IBatchRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IBatchRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IBatchRouterInstance { + IBatchRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IBatchRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IBatchRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library IBatchRouter { + struct SwapPathExactAmountIn { + address tokenIn; + SwapPathStep[] steps; + uint256 exactAmountIn; + uint256 minAmountOut; + } + struct SwapPathExactAmountOut { + address tokenIn; + SwapPathStep[] steps; + uint256 maxAmountIn; + uint256 exactAmountOut; + } + struct SwapPathStep { + address pool; + address tokenOut; + bool isBuffer; + } +} + +interface BalancerV3BatchRouter { + error AddressEmptyCode(address target); + error AddressInsufficientBalance(address account); + error ErrorSelectorNotFound(); + error EthTransfer(); + error FailedInnerCall(); + error InputLengthMismatch(); + error InsufficientEth(); + error ReentrancyGuardReentrantCall(); + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + error SafeERC20FailedOperation(address token); + error SenderIsNotVault(address sender); + error SwapDeadline(); + error TransientIndexOutOfBounds(); + + constructor(address vault, address weth, address permit2, string routerVersion); + + receive() external payable; + + function querySwapExactIn(IBatchRouter.SwapPathExactAmountIn[] memory paths, address sender, bytes memory userData) external returns (uint256[] memory pathAmountsOut, address[] memory tokensOut, uint256[] memory amountsOut); + function querySwapExactOut(IBatchRouter.SwapPathExactAmountOut[] memory paths, address sender, bytes memory userData) external returns (uint256[] memory pathAmountsIn, address[] memory tokensIn, uint256[] memory amountsIn); + function swapExactIn(IBatchRouter.SwapPathExactAmountIn[] memory paths, uint256 deadline, bool wethIsEth, bytes memory userData) external payable returns (uint256[] memory pathAmountsOut, address[] memory tokensOut, uint256[] memory amountsOut); + function swapExactOut(IBatchRouter.SwapPathExactAmountOut[] memory paths, uint256 deadline, bool wethIsEth, bytes memory userData) external payable returns (uint256[] memory pathAmountsIn, address[] memory tokensIn, uint256[] memory amountsIn); + function version() external view returns (string memory); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + }, + { + "name": "weth", + "type": "address", + "internalType": "contract IWETH" + }, + { + "name": "permit2", + "type": "address", + "internalType": "contract IPermit2" + }, + { + "name": "routerVersion", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "querySwapExactIn", + "inputs": [ + { + "name": "paths", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", + "components": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "steps", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathStep[]", + "components": [ + { + "name": "pool", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "isBuffer", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "exactAmountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minAmountOut", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "pathAmountsOut", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "tokensOut", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "amountsOut", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "querySwapExactOut", + "inputs": [ + { + "name": "paths", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "components": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "steps", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathStep[]", + "components": [ + { + "name": "pool", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "isBuffer", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "maxAmountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "exactAmountOut", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "pathAmountsIn", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "tokensIn", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "amountsIn", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swapExactIn", + "inputs": [ + { + "name": "paths", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", + "components": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "steps", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathStep[]", + "components": [ + { + "name": "pool", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "isBuffer", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "exactAmountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minAmountOut", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "wethIsEth", + "type": "bool", + "internalType": "bool" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "pathAmountsOut", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "tokensOut", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "amountsOut", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "swapExactOut", + "inputs": [ + { + "name": "paths", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "components": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "steps", + "type": "tuple[]", + "internalType": "struct IBatchRouter.SwapPathStep[]", + "components": [ + { + "name": "pool", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "isBuffer", + "type": "bool", + "internalType": "bool" + } + ] + }, + { + "name": "maxAmountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "exactAmountOut", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "wethIsEth", + "type": "bool", + "internalType": "bool" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "pathAmountsIn", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "tokensIn", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "amountsIn", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "AddressInsufficientBalance", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ErrorSelectorNotFound", + "inputs": [] + }, + { + "type": "error", + "name": "EthTransfer", + "inputs": [] + }, + { + "type": "error", + "name": "FailedInnerCall", + "inputs": [] + }, + { + "type": "error", + "name": "InputLengthMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "InsufficientEth", + "inputs": [] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "SafeCastOverflowedUintDowncast", + "inputs": [ + { + "name": "bits", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SafeERC20FailedOperation", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SenderIsNotVault", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SwapDeadline", + "inputs": [] + }, + { + "type": "error", + "name": "TransientIndexOutOfBounds", + "inputs": [] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BalancerV3BatchRouter { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6101c0604090808252346105c957614bbd803803809161001f82856105e8565b83398101916080828403126105c95781516001600160a01b03939084811681036105c957602093848101519286841684036105c9578482015196871687036105c95760608201516001600160401b03928382116105c9570192601f908282860112156105c95784518481116105b557601f19958851946100a58b898786011601876105e8565b8286528a83830101116105c957815f928b8093018388015e8501015260805281519283116105b5575f54916001928381811c911680156105ab575b8982101461059757828111610554575b50879184116001146104f757839450908392915f946104ec575b50501b915f199060031b1c1916175f555b61014961012661060b565b835190610132826105cd565b600682526539b2b73232b960d11b86830152610669565b60a05261018561015761060b565b835190610163826105cd565b60118252701a5cd4995d1d5c9b915d1a131bd8dad959607a1b86830152610669565b60c05260e0526101009283526101cd815161019f816105cd565b601381527f63757272656e7453776170546f6b656e73496e0000000000000000000000000084820152610633565b9161012092835261021082516101e2816105cd565b601481527f63757272656e7453776170546f6b656e734f757400000000000000000000000083820152610633565b6101409081526102528351610224816105cd565b601981527f63757272656e7453776170546f6b656e496e416d6f756e74730000000000000084820152610633565b906101609182526102d8610298855161026a816105cd565b601a81527f63757272656e7453776170546f6b656e4f7574416d6f756e747300000000000086820152610633565b936101809485527f736574746c6564546f6b656e416d6f756e7473000000000000000000000000008651916102cc836105cd565b60138352820152610633565b936101a094855251946144a1968761071c88396080518781816102460152818161197c01528181611be001528181611e22015281816120790152818161221201528181612323015281816123b10152818161247301528181612aad01528181612c8c01528181612cd401528181612d5201528181612df901528181612f0701528181612f840152818161321901528181613348015281816133e5015281816134ab01528181613b6c01528181613c9101528181613ed0015281816140150152614271015260a0518781816102aa015281816105350152818161181f01526128be015260c0518781816117a901526136ba015260e051878181602201528181613afe01528181613de401528181613f5801526140af0152518681816109f001528181610b0401528181611f6e01528181611ff4015281816130790152613c6d015251858181612569015281816127500152818161295a01526135d8015251848181611c4301528181611e8f01528181612275015281816124d7015281816125ce0152818161272c01528181612b1201526135a8015251838181611d43015281816125950152818161277c0152818161328e01528181613509015261362b015251828181611c6c01528181611ec00152818161250101528181612621015281816127b401528181612b5101526132d001525181818161229f015281816125ff01528181612b8201528181612e5601526136090152f35b015192505f8061010a565b91938316915f805283885f20935f5b8a8883831061053d5750505010610525575b505050811b015f5561011b565b01515f1960f88460031b161c191690555f8080610518565b868601518855909601959485019487935001610506565b5f8052885f208380870160051c8201928b881061058e575b0160051c019084905b8281106105835750506100f0565b5f8155018490610575565b9250819261056c565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100e0565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b604081019081106001600160401b038211176105b557604052565b601f909101601f19168101906001600160401b038211908210176105b557604052565b60405190610618826105cd565b600c82526b2937baba32b921b7b6b6b7b760a11b6020830152565b61066690604051610643816105cd565b60118152702130ba31b42937baba32b921b7b6b6b7b760791b6020820152610669565b90565b906106d6603a60209260405193849181808401977f62616c616e6365722d6c6162732e76332e73746f726167652e000000000000008952805191829101603986015e830190601760f91b60398301528051928391018583015e015f8382015203601a8101845201826105e8565b5190205f198101908111610707576040519060208201908152602082526106fc826105cd565b9051902060ff191690565b634e487b7160e01b5f52601160045260245ffdfe60806040526004361015610072575b3615610018575f80fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361004a57005b7f0540ddf6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f3560e01c806308a465f614610e9d57806319c6989f1461084e578063286f580d146107b75780632950286e146106cc57806354fd4d501461058f5780635a3c3987146105665780635e01eb5a146105215780638a12a08c146104c65780638eb1b65e146103bf578063945ed33f14610344578063ac9650d8146103005763e3b5dff40361000e57346102fc576060806003193601126102fc5767ffffffffffffffff6004358181116102fc5761012d9036906004016112c4565b6101356111a1565b6044359283116102fc57610150610158933690600401610fcd565b9390916128b9565b905f5b835181101561017c57805f8761017360019488611691565b5101520161015b565b506101f06101fe610239946101b65f94886040519361019a8561111a565b30855260208501525f1960408501528660608501523691611381565b60808201526040519283917f8a12a08c0000000000000000000000000000000000000000000000000000000060208401526024830161143e565b03601f198101835282611152565b604051809481927fedfa3568000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39261028e915f916102cf575b50602080825183010191016115d4565b909391926102a7575b60405193849384610f2f565b0390f35b5f7f00000000000000000000000000000000000000000000000000000000000000005d610297565b6102eb91503d805f833e6102e38183611152565b81019061154d565b8461027e565b6040513d5f823e3d90fd5b5f80fd5b60206003193601126102fc5760043567ffffffffffffffff81116102fc576103386103326102a3923690600401610f9c565b9061179b565b60405191829182611020565b346102fc5761035236610eca565b61035a611945565b610362611972565b6103906102a3610371836128fb565b9193909461038a606061038383611344565b9201611358565b90612729565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d60405193849384610f2f565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576103ec9036906004016112c4565b906103f56111b7565b906064359081116102fc576101f061048b6102399461045161041c5f953690600401610fcd565b610425336128b9565b97604051946104338661111a565b33865260208601526024356040860152151560608501523691611381565b60808201526040519283917f945ed33f000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b604051809481927f48c89491000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b346102fc576102a36104ef6104da36610eca565b6104e2611945565b6104ea611972565b611a3b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009492945d60405193849384610f2f565b346102fc575f6003193601126102fc5760207f00000000000000000000000000000000000000000000000000000000000000005c6001600160a01b0360405191168152f35b346102fc576102a36104ef61057a36610eca565b610582611945565b61058a611972565b6128fb565b346102fc575f6003193601126102fc576040515f80549060018260011c91600184169182156106c2575b60209485851084146106955785879486865291825f146106575750506001146105fe575b506105ea92500383611152565b6102a3604051928284938452830190610ffb565b5f808052859250907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061063f5750506105ea9350820101856105dd565b80548389018501528794508693909201918101610628565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858201526105ea95151560051b85010192508791506105dd9050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b92607f16926105b9565b346102fc5760606003193601126102fc5767ffffffffffffffff6004358181116102fc576106fe9036906004016112c4565b906107076111a1565b6044359182116102fc5761072261072a923690600401610fcd565b9290916128b9565b905f5b845181101561075f57806fffffffffffffffffffffffffffffffff604061075660019489611691565b5101520161072d565b506101f06101fe8561077d5f94610239976040519361019a8561111a565b60808201526040519283917f5a3c3987000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576107e49036906004016112c4565b906107ed6111b7565b906064359081116102fc576101f061048b6102399461081461041c5f953690600401610fcd565b60808201526040519283917f08a465f60000000000000000000000000000000000000000000000000000000060208401526024830161143e565b60a06003193601126102fc5767ffffffffffffffff600435116102fc573660236004350112156102fc5767ffffffffffffffff60043560040135116102fc5736602460c060043560040135026004350101116102fc5760243567ffffffffffffffff81116102fc576108c4903690600401610f9c565b67ffffffffffffffff604435116102fc576060600319604435360301126102fc5760643567ffffffffffffffff81116102fc57610905903690600401610fcd565b60843567ffffffffffffffff81116102fc57610925903690600401610f9c565b949093610930611945565b806004356004013503610e75575f5b600435600401358110610bd25750505060443560040135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd6044353603018212156102fc57816044350160048101359067ffffffffffffffff82116102fc5760248260071b36039101136102fc576109e3575b6102a361033886865f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d61179b565b6001600160a01b039492947f0000000000000000000000000000000000000000000000000000000000000000163b156102fc57604051947f2a2d80d10000000000000000000000000000000000000000000000000000000086523360048701526060602487015260c486019260443501602481019367ffffffffffffffff6004830135116102fc57600482013560071b360385136102fc5760606064890152600482013590529192869260e484019291905f905b60048101358210610b5457505050602091601f19601f865f9787956001600160a01b03610ac860246044350161118d565b16608488015260448035013560a48801526003198787030160448801528186528786013787868286010152011601030181836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39361033893610b45575b8294508193506109b3565b610b4e90611106565b84610b3a565b9195945091926001600160a01b03610b6b8761118d565b168152602080870135916001600160a01b0383168093036102fc57600492600192820152610b9b604089016128a6565b65ffffffffffff8091166040830152610bb660608a016128a6565b1660608201526080809101970193019050889495939291610a97565b610be7610be082848661192a565b3691611381565b604051610bf3816110a1565b5f81526020915f838301525f60408301528281015190606060408201519101515f1a91835283830152604082015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc81850260043501360301126102fc5760405190610c60826110ea565b610c73602460c08602600435010161118d565b808352610c89604460c08702600435010161118d565b908185850152610ca2606460c08802600435010161118d565b60408581019190915260043560c08802016084810135606087015260a4810135608087015260c4013560a086015283015183519386015160ff91909116926001600160a01b0383163b156102fc575f6001600160a01b03809460e4948b98849860c460c06040519c8d9b8c9a7fd505accf000000000000000000000000000000000000000000000000000000008c521660048b01523060248b0152608482820260043501013560448b0152026004350101356064880152608487015260a486015260c4850152165af19081610e66575b50610e5c57610d7f612877565b906001600160a01b0381511690836001600160a01b0381830151166044604051809581937fdd62ed3e00000000000000000000000000000000000000000000000000000000835260048301523060248301525afa9182156102f1575f92610e2c575b506060015103610df75750506001905b0161093f565b805115610e045780519101fd5b7fa7285689000000000000000000000000000000000000000000000000000000005f5260045ffd5b9091508381813d8311610e55575b610e448183611152565b810103126102fc5751906060610de1565b503d610e3a565b5050600190610df1565b610e6f90611106565b8a610d72565b7faaad13f7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102fc57610eab36610eca565b610eb3611945565b610ebb611972565b6103906102a361037183611a3b565b600319906020828201126102fc576004359167ffffffffffffffff83116102fc578260a0920301126102fc5760040190565b9081518082526020808093019301915f5b828110610f1b575050505090565b835185529381019392810192600101610f0d565b939290610f4490606086526060860190610efc565b936020948181036020830152602080855192838152019401905f5b818110610f7f57505050610f7c9394506040818403910152610efc565b90565b82516001600160a01b031686529487019491870191600101610f5f565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc576020808501948460051b0101116102fc57565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc57602083818601950101116102fc57565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110555750505050505090565b9091929394958480611091837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51610ffb565b9801930193019194939290611045565b6060810190811067ffffffffffffffff8211176110bd57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd57604052565b60a0810190811067ffffffffffffffff8211176110bd57604052565b60e0810190811067ffffffffffffffff8211176110bd57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd5760051b60200190565b35906001600160a01b03821682036102fc57565b602435906001600160a01b03821682036102fc57565b6044359081151582036102fc57565b9190916080818403126102fc57604090815191608083019467ffffffffffffffff95848110878211176110bd57825283956112008461118d565b8552602090818501359081116102fc57840182601f820112156102fc5780359061122982611175565b9361123686519586611152565b82855283850190846060809502840101928184116102fc578501915b8383106112745750505050508401528181013590830152606090810135910152565b84838303126102fc57875190611289826110a1565b6112928461118d565b825261129f87850161118d565b87830152888401359081151582036102fc578288928b89950152815201920191611252565b81601f820112156102fc578035916020916112de84611175565b936112ec6040519586611152565b808552838086019160051b830101928084116102fc57848301915b8483106113175750505050505090565b823567ffffffffffffffff81116102fc578691611339848480948901016111c6565b815201920191611307565b356001600160a01b03811681036102fc5790565b3580151581036102fc5790565b67ffffffffffffffff81116110bd57601f01601f191660200190565b92919261138d82611365565b9161139b6040519384611152565b8294818452818301116102fc578281602093845f960137010152565b9060808101916001600160a01b03808251168352602093848301519460808186015285518092528060a086019601925f905b83821061140b5750505050506060816040829301516040850152015191015290565b845180518216895280840151821689850152604090810151151590890152606090970196938201936001909101906113e9565b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106114bd5750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b909192939583806114f8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611481565b81601f820112156102fc5780519061151e82611365565b9261152c6040519485611152565b828452602083830101116102fc57815f9260208093018386015e8301015290565b906020828203126102fc57815167ffffffffffffffff81116102fc57610f7c9201611507565b9080601f830112156102fc5781519060209161158e81611175565b9361159c6040519586611152565b81855260208086019260051b8201019283116102fc57602001905b8282106115c5575050505090565b815181529083019083016115b7565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc5784611600918301611573565b936020808301518581116102fc5783019082601f830112156102fc5781519161162883611175565b926116366040519485611152565b808452828085019160051b830101918583116102fc578301905b82821061167257505050509360408301519081116102fc57610f7c9201611573565b81516001600160a01b03811681036102fc578152908301908301611650565b80518210156116a55760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106117515750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b9091929395838061178c837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611715565b91906117a6336128b9565b907f000000000000000000000000000000000000000000000000000000000000000093845c6118b1576001906001865d6117df83611175565b926117ed6040519485611152565b808452601f196117fc82611175565b015f5b8181106118a05750505f5b8181106118575750505050905f61184c92945d7f0000000000000000000000000000000000000000000000000000000000000000805c9161184e575b506136b1565b565b5f905d5f611846565b806118845f8061186c610be08996888a61192a565b602081519101305af461187d612877565b903061415c565b61188e8288611691565b526118998187611691565b500161180a565b8060606020809389010152016117ff565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc576020019181360383136102fc57565b908210156116a5576119419160051b8101906118d9565b9091565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c6118b1576001905d565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633036119a457565b7f089676d5000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906119da82611175565b6119e76040519182611152565b828152601f196119f78294611175565b0190602036910137565b91908201809211611a0e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b604081013542116126c35790611a5e611a5760208401846136f4565b90506119d0565b915f5b611a6e60208301836136f4565b90508110156125c757611a9881611a93611a8b60208601866136f4565b369391613748565b6111c6565b936040850151936001600160a01b038651169060208701518051156116a55760200151604001511515806125be575b1561256357611aec611ad886611344565b8784611ae660608a01611358565b92613add565b5f5b60208801515181101561255357611b03613788565b6020890151515f198101908111611a0e578214806020830152821582525f1461254c576060890151905b611b3b8360208c0151611691565b51604081015190919015611cee57611bd36001600160a01b03835116936001600160a01b03881685145f14611ce7576001945b60405195611b7b8761111a565b5f8752611b87816137be565b6020870152604086015260609485918d838301526080820152604051809381927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611cb0575b50506020015115611c9657816001600160a01b036020611c909360019695611c388c8c611691565b5201611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b5051167f000000000000000000000000000000000000000000000000000000000000000061420a565b01611aee565b602001519097506001600160a01b03169250600190611c90565b60209294509081611cd592903d10611ce0575b611ccd8183611152565b8101906137f5565b91505092905f611c10565b503d611cc3565b5f94611b6e565b888a6001600160a01b038495945116806001600160a01b038a16145f14612132575050815115905061206e57888a80151580612053575b611f4d575b6001600160a01b03939291611ddd82611e15978b5f95897f0000000000000000000000000000000000000000000000000000000000000000921680885282602052604088205c611f3c575b5050505b6001611d9c8983511660208401998b8b51169080158a14611f3657508391614223565b999092511694611db1608091828101906118d9565b93909460405197611dc1896110ea565b8852306020890152604088015260608701528501523691611381565b60a0820152604051809681927f21457897000000000000000000000000000000000000000000000000000000008352600483016139b1565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611f0c575b506020015115611ee95791611ebc826001600160a01b0360019695611e7a611ee49686611691565b51611e858d8d611691565b52611eb3828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b50511692611691565b51907f000000000000000000000000000000000000000000000000000000000000000061420a565b611c90565b98506001929450611f02906001600160a01b0392611691565b5197511692611c90565b6020919450611f2c903d805f833e611f248183611152565b810190613969565b5094919050611e52565b91614223565b611f4592614341565b5f8281611d75565b50611f5a90929192611344565b91611f648b6142fd565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039485166004820152306024820152908416604482015292871660648401525f8380608481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f1578a611ddd8d611e15976001600160a01b03975f95612044575b50975092505091929350611d2a565b61204d90611106565b5f612035565b5061205d82611344565b6001600160a01b0316301415611d25565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916001600160a01b0384511692803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03949094166004850152306024850152604484018c90525f908490606490829084905af180156102f1578a611ddd8d611e15976001600160a01b03975f95612123575b50611d79565b61212c90611106565b5f61211d565b6001600160a01b0360208796949701511690898183145f146123d7576121cd925061220597915060016121735f96956001600160a01b0393848b5116614223565b509282895116956020890151151588146123ae5761219082611344565b945b6121a1608093848101906118d9565b959096604051996121b18b6110ea565b8a52166020890152604088015260608701528501523691611381565b60a0820152604051809581927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f1575f93612384575b5060200151156122c357816001600160a01b036020611ee493600196956122698c8c611691565b526122998383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b60208181015191516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101859052939a50909116945081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612359575b50600190611c90565b602090813d831161237d575b61236f8183611152565b810103126102fc575f612350565b503d612365565b60209193506123a4903d805f833e61239c8183611152565b81019061387c565b5093919050612242565b837f00000000000000000000000000000000000000000000000000000000000000001694612192565b6001600160a01b036124669561242e9394956123f860809b8c8101906118d9565b9390946040519761240889611136565b5f8952602089015216604087015260609a8b978888015286015260a08501523691611381565b60c0820152604051809381927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612525575b50506020015115611c9657816001600160a01b036020611ee493600196956124cb8c8c611691565b526124fb8383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b6020929450908161254192903d10611ce057611ccd8183611152565b91505092905f6124a3565b5f90611b2d565b5091955090935050600101611a61565b61258d827f00000000000000000000000000000000000000000000000000000000000000006141c0565b506125b986837f000000000000000000000000000000000000000000000000000000000000000061420a565b611aec565b50321515611ac7565b50506125f27f0000000000000000000000000000000000000000000000000000000000000000613a71565b916125fd83516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b0380612663838b611691565b51165f528560205261269160405f205c8261267e858d611691565b51165f528860205260405f205c90611a01565b61269b8387611691565b526126a6828a611691565b51165f52856020525f604081205d01612644565b50949391509150565b7fe08b8af0000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f198201918213600116611a0e57565b7f80000000000000000000000000000000000000000000000000000000000000008114611a0e575f190190565b907f000000000000000000000000000000000000000000000000000000000000000090815c7f0000000000000000000000000000000000000000000000000000000000000000612779815c6126eb565b907f0000000000000000000000000000000000000000000000000000000000000000915b5f81121561283a575050506127b1906126eb565b917f0000000000000000000000000000000000000000000000000000000000000000925b5f8112156127ea575050505061184c906136b1565b61283590825f5261282f60205f83828220015c91828252888152886040916128228a8d8587205c906001600160a01b03891690613eb0565b8484525281205d84613e0d565b506126fc565b6127d5565b61287290825f5261282f60205f8a8785848420015c938484528181526128228c6040948587205c906001600160a01b03891690613add565b61279d565b3d156128a1573d9061288882611365565b916128966040519384611152565b82523d5f602084013e565b606090565b359065ffffffffffff821682036102fc57565b905f917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03815c16156128f1575050565b909192505d600190565b90604082013542116126c357612917611a5760208401846136f4565b915f5b61292760208301836136f4565b90508110156135d15761294481611a93611a8b60208601866136f4565b60608101519061297e6001600160a01b038251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506020810151515f198101908111611a0e575b5f8112156129a45750505060010161291a565b6129b2816020840151611691565b516129bb613788565b9082156020830152602084015151805f19810111611a0e575f1901831480835261358f575b6020820151156135545760408401516001600160a01b03855116915b604081015115612c1d5783916001600160a01b036060926020612aa0970151151580612c14575b612bed575b5116906001600160a01b0385168203612be6576001915b60405192612a4c8461111a565b60018452612a59816137be565b6020840152604083015288838301526080820152604051809581927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f95612bbf575b506020015115612bb057612ba69284612b02612bab979694612b7594611691565b52612b366001600160a01b0382167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506001600160a01b03612b4d8460408a01516137b1565b91167f000000000000000000000000000000000000000000000000000000000000000061420a565b6001600160a01b038551167f000000000000000000000000000000000000000000000000000000000000000061420a565b6126fc565b612991565b505050612bab919350926126fc565b6020919550612bdc9060603d606011611ce057611ccd8183611152565b5095919050612ae1565b5f91612a3f565b612c0f612bf98d611344565b8d8b611ae6886040888451169301519301611358565b612a28565b50321515612a23565b906001600160a01b03825116806001600160a01b038516145f14613137575060208401516130495750604051927f967870920000000000000000000000000000000000000000000000000000000084526001600160a01b03831660048501526020846024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9384156102f1575f94613015575b5083916001600160a01b038151166001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015230602482015260448101959095525f8580606481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f157612dec955f92613006575b505b611ddd6001600160a01b03612da88b828551168360208701511690614223565b50925116918c6002612dbf608092838101906118d9565b92909360405196612dcf886110ea565b875230602088015289604088015260608701528501523691611381565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612fe3575b506020015115612ecf57908291612bab9493612e45898d611691565b52612e7a836001600160a01b0384167f000000000000000000000000000000000000000000000000000000000000000061420a565b80831080612eb4575b612e90575b5050506126fc565b612ea6612eac93612ea08b611344565b926137b1565b91614356565b5f8080612e88565b50306001600160a01b03612ec78b611344565b161415612e83565b9450908094808210612ee8575b505050612bab906126fc565b91612ef8602092612f77946137b1565b90612f2d826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683614356565b60405193849283927f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612fb8575b8080612edc565b602090813d8311612fdc575b612fce8183611152565b810103126102fc575f612fb1565b503d612fc4565b6020919450612ffb903d805f833e611f248183611152565b509094919050612e29565b61300f90611106565b5f612d86565b9093506020813d602011613041575b8161303160209383611152565b810103126102fc5751925f612cbc565b3d9150613024565b909261305489611344565b6001600160a01b033091160361306f575b5f612dec94612d88565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936130a38a611344565b6130ac846142fd565b90863b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152306024820152918116604483015285166064820152945f908690608490829084905af19081156102f157612dec955f92613128575b50945050613065565b61313190611106565b5f61311f565b6001600160a01b036020849695940151168a8282145f1461340b5750505061320c61316e5f92846001600160a01b03885116614223565b92906131d48c6001600160a01b03808a5116938951151586146133df576131a361319784611344565b935b60808101906118d9565b929093604051966131b3886110ea565b875216602086015260408501528c6060850152600260808501523691611381565b60a0820152604051809381927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f1575f916133c4575b5060208401518c908a90156133aa5783836001600160a01b03936132836132899461327c8f9c9b9a98996132b29a611691565b5192611691565b52611691565b5191167f000000000000000000000000000000000000000000000000000000000000000061420a565b51156132f457612bab92916001600160a01b036020612ba6930151167f0000000000000000000000000000000000000000000000000000000000000000614341565b516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024810191909152602081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f15761337f575b50612bab906126fc565b602090813d83116133a3575b6133958183611152565b810103126102fc575f613375565b503d61338b565b50509091506133bb92939650611691565b519384916132b2565b6133d891503d805f833e61239c8183611152565b9050613249565b6131a3827f00000000000000000000000000000000000000000000000000000000000000001693613199565b61349e965090613466916060948b61342b608099989993848101906118d9565b9390946040519761343b89611136565b6001895260208901526001600160a01b038b1660408901528888015286015260a08501523691611381565b60c0820152604051809581927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f9561352d575b506020015115612bb057612ba69284613505612bab9796946001600160a01b0394611691565b52167f000000000000000000000000000000000000000000000000000000000000000061420a565b602091955061354a9060603d606011611ce057611ccd8183611152565b50959190506134df565b6fffffffffffffffffffffffffffffffff6001600160a01b0360206135858188015161357f886126eb565b90611691565b51015116916129fc565b6135cc856001600160a01b0360208401611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b6129e0565b50506135fc7f0000000000000000000000000000000000000000000000000000000000000000613a71565b9161360783516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b038061366d838b611691565b51165f528560205261368860405f205c8261267e858d611691565b6136928387611691565b5261369d828a611691565b51165f52856020525f604081205d0161364e565b4780156136f0577f00000000000000000000000000000000000000000000000000000000000000005c6136f0576001600160a01b0361184c92166140e0565b5050565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc57602001918160051b360383136102fc57565b91908110156116a55760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81813603018212156102fc570190565b604051906040820182811067ffffffffffffffff8211176110bd576040525f6020838281520152565b91908203918211611a0e57565b600211156137c857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b908160609103126102fc578051916040602083015192015190565b61010060c0610f7c93602084528051613828816137be565b602085015260208101516001600160a01b0380911660408601528060408301511660608601526060820151166080850152608081015160a085015260a08101518285015201519160e0808201520190610ffb565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc57846138a8918301611573565b9360208201519360408301519081116102fc57610f7c9201611507565b9081518082526020808093019301915f5b8281106138e4575050505090565b8351855293810193928101926001016138d6565b602081526001600160a01b038083511660208301526020830151166040820152613931604083015160c0606084015260e08301906138c5565b9060608301516080820152608083015160058110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b916060838303126102fc5782519260208101519267ffffffffffffffff938481116102fc578161399a918401611573565b9360408301519081116102fc57610f7c9201611507565b602081526001600160a01b038083511660208301526020830151166040820152604082015160608201526139f4606083015160c0608084015260e08301906138c5565b90608083015160048110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b91909160808060a08301948051613a38816137be565b84526020810151613a48816137be565b60208501526001600160a01b036040820151166040850152606081015160608501520151910152565b90815c613a7d81611175565b613a8a6040519182611152565b818152613a9682611175565b601f196020910136602084013781945f5b848110613ab5575050505050565b600190825f5280845f20015c6001600160a01b03613ad38388611691565b9116905201613aa7565b919280613dd8575b15613c51575050804710613c29576001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001691823b156102fc57604051907fd0e30db00000000000000000000000000000000000000000000000000000000082525f915f8160048185895af180156102f157613c12575b506044602092937f00000000000000000000000000000000000000000000000000000000000000001694613b98838783614356565b8460405196879485937f15afd409000000000000000000000000000000000000000000000000000000008552600485015260248401525af1908115613c065750613bdf5750565b602090813d8311613bff575b613bf58183611152565b810103126102fc57565b503d613beb565b604051903d90823e3d90fd5b60209250613c1f90611106565b60445f9250613b63565b7fa01a9df6000000000000000000000000000000000000000000000000000000005f5260045ffd5b90915f9080613c61575b50505050565b6001600160a01b0393847f00000000000000000000000000000000000000000000000000000000000000001694807f00000000000000000000000000000000000000000000000000000000000000001691613cbb846142fd565b96803b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152848316602482015297821660448901529186161660648701525f908690608490829084905af19485156102f157613d8095613dc4575b5082936020936040518097819582947f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1908115613c065750613d99575b808080613c5b565b602090813d8311613dbd575b613daf8183611152565b810103126102fc575f613d91565b503d613da5565b60209350613dd190611106565b5f92613d2f565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690821614613ae5565b6001810191805f5260209183835260405f205c8015155f14613ea7575f1990818101835c8380820191828403613e6a575b5050505050815c81810192818411611a0e575f93815d835284832001015d5f52525f604081205d600190565b613e77613e87938861443a565b865f52885f2001015c918561443a565b835f52808383885f2001015d5f5285855260405f205d5f80808381613e3e565b50505050505f90565b5f949383156140d857806140a3575b15614007576001600160a01b0391827f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03929092166004830152306024830152604482018590525f908290606490829084905af180156102f157613ff4575b5084827f000000000000000000000000000000000000000000000000000000000000000016803b15613ff05781906024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015613fe557613fcd575b5061184c939450166140e0565b613fd78691611106565b613fe15784613fc0565b8480fd5b6040513d88823e3d90fd5b5080fd5b613fff919550611106565b5f935f613f53565b929350906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015293909216602484015260448301525f908290606490829084905af180156102f15761409a5750565b61184c90611106565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690831614613ebf565b505050509050565b814710614130575f8080936001600160a01b038294165af1614100612877565b501561410857565b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcd786059000000000000000000000000000000000000000000000000000000005f523060045260245ffd5b90614171575080511561410857805190602001fd5b815115806141b7575b614182575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561417a565b6001810190825f528160205260405f205c155f1461420357805c815f52838160205f20015d60018101809111611a0e57815d5c915f5260205260405f205d600190565b5050505f90565b905f5260205261421f60405f2091825c611a01565b905d565b916044929391936001600160a01b03604094859282808551998a9586947fc9c1661b0000000000000000000000000000000000000000000000000000000086521660048501521660248301527f0000000000000000000000000000000000000000000000000000000000000000165afa9384156142f3575f935f956142bc575b50506142b96142b285946119d0565b9485611691565b52565b809295508194503d83116142ec575b6142d58183611152565b810103126102fc5760208251920151925f806142a3565b503d6142cb565b83513d5f823e3d90fd5b6001600160a01b0390818111614311571690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f5260a060045260245260445ffd5b905f5260205261421f60405f2091825c6137b1565b6040519260208401907fa9059cbb0000000000000000000000000000000000000000000000000000000082526001600160a01b038094166024860152604485015260448452608084019084821067ffffffffffffffff8311176110bd576143d5935f9384936040521694519082865af16143ce612877565b908361415c565b8051908115159182614416575b50506143eb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126102fc57602001518015908115036102fc575f806143e2565b5c111561444357565b7f0f4ae0e4000000000000000000000000000000000000000000000000000000005f5260045ffdfea2646970667358221220229a5cf89aa7c2d0a4b4d5db20bba6c2b3a74b080303fc6ec00ba582a5dcf75164736f6c634300081a0033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01\xC0`@\x90\x80\x82R4a\x05\xC9WaK\xBD\x808\x03\x80\x91a\0\x1F\x82\x85a\x05\xE8V[\x839\x81\x01\x91`\x80\x82\x84\x03\x12a\x05\xC9W\x81Q`\x01`\x01`\xA0\x1B\x03\x93\x90\x84\x81\x16\x81\x03a\x05\xC9W` \x93\x84\x81\x01Q\x92\x86\x84\x16\x84\x03a\x05\xC9W\x84\x82\x01Q\x96\x87\x16\x87\x03a\x05\xC9W``\x82\x01Q`\x01`\x01`@\x1B\x03\x92\x83\x82\x11a\x05\xC9W\x01\x92`\x1F\x90\x82\x82\x86\x01\x12\x15a\x05\xC9W\x84Q\x84\x81\x11a\x05\xB5W`\x1F\x19\x95\x88Q\x94a\0\xA5\x8B\x89\x87\x86\x01\x16\x01\x87a\x05\xE8V[\x82\x86R\x8A\x83\x83\x01\x01\x11a\x05\xC9W\x81_\x92\x8B\x80\x93\x01\x83\x88\x01^\x85\x01\x01R`\x80R\x81Q\x92\x83\x11a\x05\xB5W_T\x91`\x01\x92\x83\x81\x81\x1C\x91\x16\x80\x15a\x05\xABW[\x89\x82\x10\x14a\x05\x97W\x82\x81\x11a\x05TW[P\x87\x91\x84\x11`\x01\x14a\x04\xF7W\x83\x94P\x90\x83\x92\x91_\x94a\x04\xECW[PP\x1B\x91_\x19\x90`\x03\x1B\x1C\x19\x16\x17_U[a\x01Ia\x01&a\x06\x0BV[\x83Q\x90a\x012\x82a\x05\xCDV[`\x06\x82Re9\xB2\xB722\xB9`\xD1\x1B\x86\x83\x01Ra\x06iV[`\xA0Ra\x01\x85a\x01Wa\x06\x0BV[\x83Q\x90a\x01c\x82a\x05\xCDV[`\x11\x82Rp\x1A\\\xD4\x99]\x1D\\\x9B\x91]\x1A\x13\x1B\xD8\xDA\xD9Y`z\x1B\x86\x83\x01Ra\x06iV[`\xC0R`\xE0Ra\x01\0\x92\x83Ra\x01\xCD\x81Qa\x01\x9F\x81a\x05\xCDV[`\x13\x81R\x7FcurrentSwapTokensIn\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x82\x01Ra\x063V[\x91a\x01 \x92\x83Ra\x02\x10\x82Qa\x01\xE2\x81a\x05\xCDV[`\x14\x81R\x7FcurrentSwapTokensOut\0\0\0\0\0\0\0\0\0\0\0\0\x83\x82\x01Ra\x063V[a\x01@\x90\x81Ra\x02R\x83Qa\x02$\x81a\x05\xCDV[`\x19\x81R\x7FcurrentSwapTokenInAmounts\0\0\0\0\0\0\0\x84\x82\x01Ra\x063V[\x90a\x01`\x91\x82Ra\x02\xD8a\x02\x98\x85Qa\x02j\x81a\x05\xCDV[`\x1A\x81R\x7FcurrentSwapTokenOutAmounts\0\0\0\0\0\0\x86\x82\x01Ra\x063V[\x93a\x01\x80\x94\x85R\x7FsettledTokenAmounts\0\0\0\0\0\0\0\0\0\0\0\0\0\x86Q\x91a\x02\xCC\x83a\x05\xCDV[`\x13\x83R\x82\x01Ra\x063V[\x93a\x01\xA0\x94\x85RQ\x94aD\xA1\x96\x87a\x07\x1C\x889`\x80Q\x87\x81\x81a\x02F\x01R\x81\x81a\x19|\x01R\x81\x81a\x1B\xE0\x01R\x81\x81a\x1E\"\x01R\x81\x81a y\x01R\x81\x81a\"\x12\x01R\x81\x81a##\x01R\x81\x81a#\xB1\x01R\x81\x81a$s\x01R\x81\x81a*\xAD\x01R\x81\x81a,\x8C\x01R\x81\x81a,\xD4\x01R\x81\x81a-R\x01R\x81\x81a-\xF9\x01R\x81\x81a/\x07\x01R\x81\x81a/\x84\x01R\x81\x81a2\x19\x01R\x81\x81a3H\x01R\x81\x81a3\xE5\x01R\x81\x81a4\xAB\x01R\x81\x81a;l\x01R\x81\x81a<\x91\x01R\x81\x81a>\xD0\x01R\x81\x81a@\x15\x01RaBq\x01R`\xA0Q\x87\x81\x81a\x02\xAA\x01R\x81\x81a\x055\x01R\x81\x81a\x18\x1F\x01Ra(\xBE\x01R`\xC0Q\x87\x81\x81a\x17\xA9\x01Ra6\xBA\x01R`\xE0Q\x87\x81\x81`\"\x01R\x81\x81a:\xFE\x01R\x81\x81a=\xE4\x01R\x81\x81a?X\x01Ra@\xAF\x01RQ\x86\x81\x81a\t\xF0\x01R\x81\x81a\x0B\x04\x01R\x81\x81a\x1Fn\x01R\x81\x81a\x1F\xF4\x01R\x81\x81a0y\x01RaV[\x03`\x1F\x19\x81\x01\x83R\x82a\x11RV[`@Q\x80\x94\x81\x92\x7F\xED\xFA5h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R` `\x04\x84\x01R`$\x83\x01\x90a\x0F\xFBV[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x91\x82\x15a\x02\xF1Wa\x02\xA3\x92a\x02\x8E\x91_\x91a\x02\xCFW[P` \x80\x82Q\x83\x01\x01\x91\x01a\x15\xD4V[\x90\x93\x91\x92a\x02\xA7W[`@Q\x93\x84\x93\x84a\x0F/V[\x03\x90\xF3[_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0]a\x02\x97V[a\x02\xEB\x91P=\x80_\x83>a\x02\xE3\x81\x83a\x11RV[\x81\x01\x90a\x15MV[\x84a\x02~V[`@Q=_\x82>=\x90\xFD[_\x80\xFD[` `\x03\x196\x01\x12a\x02\xFCW`\x045g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\x038a\x032a\x02\xA3\x926\x90`\x04\x01a\x0F\x9CV[\x90a\x17\x9BV[`@Q\x91\x82\x91\x82a\x10 V[4a\x02\xFCWa\x03R6a\x0E\xCAV[a\x03Za\x19EV[a\x03ba\x19rV[a\x03\x90a\x02\xA3a\x03q\x83a(\xFBV[\x91\x93\x90\x94a\x03\x8A``a\x03\x83\x83a\x13DV[\x92\x01a\x13XV[\x90a')V[_\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0]`@Q\x93\x84\x93\x84a\x0F/V[`\x80`\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x81\x81\x11a\x02\xFCWa\x03\xEC\x906\x90`\x04\x01a\x12\xC4V[\x90a\x03\xF5a\x11\xB7V[\x90`d5\x90\x81\x11a\x02\xFCWa\x01\xF0a\x04\x8Ba\x029\x94a\x04Qa\x04\x1C_\x956\x90`\x04\x01a\x0F\xCDV[a\x04%3a(\xB9V[\x97`@Q\x94a\x043\x86a\x11\x1AV[3\x86R` \x86\x01R`$5`@\x86\x01R\x15\x15``\x85\x01R6\x91a\x13\x81V[`\x80\x82\x01R`@Q\x92\x83\x91\x7F\x94^\xD3?\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x84\x01R`$\x83\x01a\x16\xD2V[`@Q\x80\x94\x81\x92\x7FH\xC8\x94\x91\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R` `\x04\x84\x01R`$\x83\x01\x90a\x0F\xFBV[4a\x02\xFCWa\x02\xA3a\x04\xEFa\x04\xDA6a\x0E\xCAV[a\x04\xE2a\x19EV[a\x04\xEAa\x19rV[a\x1A;V[_\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0\x94\x92\x94]`@Q\x93\x84\x93\x84a\x0F/V[4a\x02\xFCW_`\x03\x196\x01\x12a\x02\xFCW` \x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\`\x01`\x01`\xA0\x1B\x03`@Q\x91\x16\x81R\xF3[4a\x02\xFCWa\x02\xA3a\x04\xEFa\x05z6a\x0E\xCAV[a\x05\x82a\x19EV[a\x05\x8Aa\x19rV[a(\xFBV[4a\x02\xFCW_`\x03\x196\x01\x12a\x02\xFCW`@Q_\x80T\x90`\x01\x82`\x01\x1C\x91`\x01\x84\x16\x91\x82\x15a\x06\xC2W[` \x94\x85\x85\x10\x84\x14a\x06\x95W\x85\x87\x94\x86\x86R\x91\x82_\x14a\x06WWPP`\x01\x14a\x05\xFEW[Pa\x05\xEA\x92P\x03\x83a\x11RV[a\x02\xA3`@Q\x92\x82\x84\x93\x84R\x83\x01\x90a\x0F\xFBV[_\x80\x80R\x85\x92P\x90\x7F)\r\xEC\xD9T\x8Bb\xA8\xD6\x03E\xA9\x888o\xC8K\xA6\xBC\x95H@\x08\xF66/\x93\x16\x0E\xF3\xE5c[\x85\x83\x10a\x06?WPPa\x05\xEA\x93P\x82\x01\x01\x85a\x05\xDDV[\x80T\x83\x89\x01\x85\x01R\x87\x94P\x86\x93\x90\x92\x01\x91\x81\x01a\x06(V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x16\x85\x82\x01Ra\x05\xEA\x95\x15\x15`\x05\x1B\x85\x01\x01\x92P\x87\x91Pa\x05\xDD\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\"`\x04R`$_\xFD[\x92`\x7F\x16\x92a\x05\xB9V[4a\x02\xFCW```\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x81\x81\x11a\x02\xFCWa\x06\xFE\x906\x90`\x04\x01a\x12\xC4V[\x90a\x07\x07a\x11\xA1V[`D5\x91\x82\x11a\x02\xFCWa\x07\"a\x07*\x926\x90`\x04\x01a\x0F\xCDV[\x92\x90\x91a(\xB9V[\x90_[\x84Q\x81\x10\x15a\x07_W\x80o\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`@a\x07V`\x01\x94\x89a\x16\x91V[Q\x01R\x01a\x07-V[Pa\x01\xF0a\x01\xFE\x85a\x07}_\x94a\x029\x97`@Q\x93a\x01\x9A\x85a\x11\x1AV[`\x80\x82\x01R`@Q\x92\x83\x91\x7FZ<9\x87\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x84\x01R`$\x83\x01a\x16\xD2V[`\x80`\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x81\x81\x11a\x02\xFCWa\x07\xE4\x906\x90`\x04\x01a\x12\xC4V[\x90a\x07\xEDa\x11\xB7V[\x90`d5\x90\x81\x11a\x02\xFCWa\x01\xF0a\x04\x8Ba\x029\x94a\x08\x14a\x04\x1C_\x956\x90`\x04\x01a\x0F\xCDV[`\x80\x82\x01R`@Q\x92\x83\x91\x7F\x08\xA4e\xF6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x84\x01R`$\x83\x01a\x14>V[`\xA0`\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x11a\x02\xFCW6`#`\x045\x01\x12\x15a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045`\x04\x015\x11a\x02\xFCW6`$`\xC0`\x045`\x04\x015\x02`\x045\x01\x01\x11a\x02\xFCW`$5g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\x08\xC4\x906\x90`\x04\x01a\x0F\x9CV[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`D5\x11a\x02\xFCW```\x03\x19`D56\x03\x01\x12a\x02\xFCW`d5g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\t\x05\x906\x90`\x04\x01a\x0F\xCDV[`\x845g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\t%\x906\x90`\x04\x01a\x0F\x9CV[\x94\x90\x93a\t0a\x19EV[\x80`\x045`\x04\x015\x03a\x0EuW_[`\x045`\x04\x015\x81\x10a\x0B\xD2WPPP`D5`\x04\x015\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDD`D56\x03\x01\x82\x12\x15a\x02\xFCW\x81`D5\x01`\x04\x81\x015\x90g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11a\x02\xFCW`$\x82`\x07\x1B6\x03\x91\x01\x13a\x02\xFCWa\t\xE3W[a\x02\xA3a\x038\x86\x86_\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0]a\x17\x9BV[`\x01`\x01`\xA0\x1B\x03\x94\x92\x94\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16;\x15a\x02\xFCW`@Q\x94\x7F*-\x80\xD1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86R3`\x04\x87\x01R```$\x87\x01R`\xC4\x86\x01\x92`D5\x01`$\x81\x01\x93g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x04\x83\x015\x11a\x02\xFCW`\x04\x82\x015`\x07\x1B6\x03\x85\x13a\x02\xFCW```d\x89\x01R`\x04\x82\x015\x90R\x91\x92\x86\x92`\xE4\x84\x01\x92\x91\x90_\x90[`\x04\x81\x015\x82\x10a\x0BTWPPP` \x91`\x1F\x19`\x1F\x86_\x97\x87\x95`\x01`\x01`\xA0\x1B\x03a\n\xC8`$`D5\x01a\x11\x8DV[\x16`\x84\x88\x01R`D\x805\x015`\xA4\x88\x01R`\x03\x19\x87\x87\x03\x01`D\x88\x01R\x81\x86R\x87\x86\x017\x87\x86\x82\x86\x01\x01R\x01\x16\x01\x03\x01\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x91\x82\x15a\x02\xF1Wa\x02\xA3\x93a\x038\x93a\x0BEW[\x82\x94P\x81\x93Pa\t\xB3V[a\x0BN\x90a\x11\x06V[\x84a\x0B:V[\x91\x95\x94P\x91\x92`\x01`\x01`\xA0\x1B\x03a\x0Bk\x87a\x11\x8DV[\x16\x81R` \x80\x87\x015\x91`\x01`\x01`\xA0\x1B\x03\x83\x16\x80\x93\x03a\x02\xFCW`\x04\x92`\x01\x92\x82\x01Ra\x0B\x9B`@\x89\x01a(\xA6V[e\xFF\xFF\xFF\xFF\xFF\xFF\x80\x91\x16`@\x83\x01Ra\x0B\xB6``\x8A\x01a(\xA6V[\x16``\x82\x01R`\x80\x80\x91\x01\x97\x01\x93\x01\x90P\x88\x94\x95\x93\x92\x91a\n\x97V[a\x0B\xE7a\x0B\xE0\x82\x84\x86a\x19*V[6\x91a\x13\x81V[`@Qa\x0B\xF3\x81a\x10\xA1V[_\x81R` \x91_\x83\x83\x01R_`@\x83\x01R\x82\x81\x01Q\x90```@\x82\x01Q\x91\x01Q_\x1A\x91\x83R\x83\x83\x01R`@\x82\x01R`\xC0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDC\x81\x85\x02`\x045\x016\x03\x01\x12a\x02\xFCW`@Q\x90a\x0C`\x82a\x10\xEAV[a\x0Cs`$`\xC0\x86\x02`\x045\x01\x01a\x11\x8DV[\x80\x83Ra\x0C\x89`D`\xC0\x87\x02`\x045\x01\x01a\x11\x8DV[\x90\x81\x85\x85\x01Ra\x0C\xA2`d`\xC0\x88\x02`\x045\x01\x01a\x11\x8DV[`@\x85\x81\x01\x91\x90\x91R`\x045`\xC0\x88\x02\x01`\x84\x81\x015``\x87\x01R`\xA4\x81\x015`\x80\x87\x01R`\xC4\x015`\xA0\x86\x01R\x83\x01Q\x83Q\x93\x86\x01Q`\xFF\x91\x90\x91\x16\x92`\x01`\x01`\xA0\x1B\x03\x83\x16;\x15a\x02\xFCW_`\x01`\x01`\xA0\x1B\x03\x80\x94`\xE4\x94\x8B\x98\x84\x98`\xC4`\xC0`@Q\x9C\x8D\x9B\x8C\x9A\x7F\xD5\x05\xAC\xCF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8CR\x16`\x04\x8B\x01R0`$\x8B\x01R`\x84\x82\x82\x02`\x045\x01\x015`D\x8B\x01R\x02`\x045\x01\x015`d\x88\x01R`\x84\x87\x01R`\xA4\x86\x01R`\xC4\x85\x01R\x16Z\xF1\x90\x81a\x0EfW[Pa\x0E\\Wa\r\x7Fa(wV[\x90`\x01`\x01`\xA0\x1B\x03\x81Q\x16\x90\x83`\x01`\x01`\xA0\x1B\x03\x81\x83\x01Q\x16`D`@Q\x80\x95\x81\x93\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01R0`$\x83\x01RZ\xFA\x91\x82\x15a\x02\xF1W_\x92a\x0E,W[P``\x01Q\x03a\r\xF7WPP`\x01\x90[\x01a\t?V[\x80Q\x15a\x0E\x04W\x80Q\x91\x01\xFD[\x7F\xA7(V\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x90\x91P\x83\x81\x81=\x83\x11a\x0EUW[a\x0ED\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCWQ\x90``a\r\xE1V[P=a\x0E:V[PP`\x01\x90a\r\xF1V[a\x0Eo\x90a\x11\x06V[\x8Aa\rrV[\x7F\xAA\xAD\x13\xF7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[4a\x02\xFCWa\x0E\xAB6a\x0E\xCAV[a\x0E\xB3a\x19EV[a\x0E\xBBa\x19rV[a\x03\x90a\x02\xA3a\x03q\x83a\x1A;V[`\x03\x19\x90` \x82\x82\x01\x12a\x02\xFCW`\x045\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11a\x02\xFCW\x82`\xA0\x92\x03\x01\x12a\x02\xFCW`\x04\x01\x90V[\x90\x81Q\x80\x82R` \x80\x80\x93\x01\x93\x01\x91_[\x82\x81\x10a\x0F\x1BWPPPP\x90V[\x83Q\x85R\x93\x81\x01\x93\x92\x81\x01\x92`\x01\x01a\x0F\rV[\x93\x92\x90a\x0FD\x90``\x86R``\x86\x01\x90a\x0E\xFCV[\x93` \x94\x81\x81\x03` \x83\x01R` \x80\x85Q\x92\x83\x81R\x01\x94\x01\x90_[\x81\x81\x10a\x0F\x7FWPPPa\x0F|\x93\x94P`@\x81\x84\x03\x91\x01Ra\x0E\xFCV[\x90V[\x82Q`\x01`\x01`\xA0\x1B\x03\x16\x86R\x94\x87\x01\x94\x91\x87\x01\x91`\x01\x01a\x0F_V[\x91\x81`\x1F\x84\x01\x12\x15a\x02\xFCW\x825\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11a\x02\xFCW` \x80\x85\x01\x94\x84`\x05\x1B\x01\x01\x11a\x02\xFCWV[\x91\x81`\x1F\x84\x01\x12\x15a\x02\xFCW\x825\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11a\x02\xFCW` \x83\x81\x86\x01\x95\x01\x01\x11a\x02\xFCWV[\x90`\x1F\x19`\x1F` \x80\x94\x80Q\x91\x82\x91\x82\x87R\x01\x86\x86\x01^_\x85\x82\x86\x01\x01R\x01\x16\x01\x01\x90V[` \x80\x82\x01\x90` \x83R\x83Q\x80\x92R`@\x83\x01\x92` `@\x84`\x05\x1B\x83\x01\x01\x95\x01\x93_\x91[\x84\x83\x10a\x10UWPPPPPP\x90V[\x90\x91\x92\x93\x94\x95\x84\x80a\x10\x91\x83\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x86`\x01\x96\x03\x01\x87R\x8AQa\x0F\xFBV[\x98\x01\x93\x01\x93\x01\x91\x94\x93\x92\x90a\x10EV[``\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`\xC0\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x10\xBDW`@RV[`\xA0\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[`\xE0\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[\x90`\x1F`\x1F\x19\x91\x01\x16\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x10\xBDW`\x05\x1B` \x01\x90V[5\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x82\x03a\x02\xFCWV[`$5\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x82\x03a\x02\xFCWV[`D5\x90\x81\x15\x15\x82\x03a\x02\xFCWV[\x91\x90\x91`\x80\x81\x84\x03\x12a\x02\xFCW`@\x90\x81Q\x91`\x80\x83\x01\x94g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x95\x84\x81\x10\x87\x82\x11\x17a\x10\xBDW\x82R\x83\x95a\x12\0\x84a\x11\x8DV[\x85R` \x90\x81\x85\x015\x90\x81\x11a\x02\xFCW\x84\x01\x82`\x1F\x82\x01\x12\x15a\x02\xFCW\x805\x90a\x12)\x82a\x11uV[\x93a\x126\x86Q\x95\x86a\x11RV[\x82\x85R\x83\x85\x01\x90\x84``\x80\x95\x02\x84\x01\x01\x92\x81\x84\x11a\x02\xFCW\x85\x01\x91[\x83\x83\x10a\x12tWPPPPP\x84\x01R\x81\x81\x015\x90\x83\x01R``\x90\x81\x015\x91\x01RV[\x84\x83\x83\x03\x12a\x02\xFCW\x87Q\x90a\x12\x89\x82a\x10\xA1V[a\x12\x92\x84a\x11\x8DV[\x82Ra\x12\x9F\x87\x85\x01a\x11\x8DV[\x87\x83\x01R\x88\x84\x015\x90\x81\x15\x15\x82\x03a\x02\xFCW\x82\x88\x92\x8B\x89\x95\x01R\x81R\x01\x92\x01\x91a\x12RV[\x81`\x1F\x82\x01\x12\x15a\x02\xFCW\x805\x91` \x91a\x12\xDE\x84a\x11uV[\x93a\x12\xEC`@Q\x95\x86a\x11RV[\x80\x85R\x83\x80\x86\x01\x91`\x05\x1B\x83\x01\x01\x92\x80\x84\x11a\x02\xFCW\x84\x83\x01\x91[\x84\x83\x10a\x13\x17WPPPPPP\x90V[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCW\x86\x91a\x139\x84\x84\x80\x94\x89\x01\x01a\x11\xC6V[\x81R\x01\x92\x01\x91a\x13\x07V[5`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x03a\x02\xFCW\x90V[5\x80\x15\x15\x81\x03a\x02\xFCW\x90V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x10\xBDW`\x1F\x01`\x1F\x19\x16` \x01\x90V[\x92\x91\x92a\x13\x8D\x82a\x13eV[\x91a\x13\x9B`@Q\x93\x84a\x11RV[\x82\x94\x81\x84R\x81\x83\x01\x11a\x02\xFCW\x82\x81` \x93\x84_\x96\x017\x01\x01RV[\x90`\x80\x81\x01\x91`\x01`\x01`\xA0\x1B\x03\x80\x82Q\x16\x83R` \x93\x84\x83\x01Q\x94`\x80\x81\x86\x01R\x85Q\x80\x92R\x80`\xA0\x86\x01\x96\x01\x92_\x90[\x83\x82\x10a\x14\x0BWPPPPP``\x81`@\x82\x93\x01Q`@\x85\x01R\x01Q\x91\x01R\x90V[\x84Q\x80Q\x82\x16\x89R\x80\x84\x01Q\x82\x16\x89\x85\x01R`@\x90\x81\x01Q\x15\x15\x90\x89\x01R``\x90\x97\x01\x96\x93\x82\x01\x93`\x01\x90\x91\x01\x90a\x13\xE9V[\x91\x90\x91` \x90\x81\x81R`\xC0\x81\x01\x91`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x81\x83\x01R\x80\x85\x01Q\x92`\xA0`@\x84\x01R\x83Q\x80\x91R`\xE0\x83\x01\x91\x80`\xE0\x83`\x05\x1B\x86\x01\x01\x95\x01\x92_\x90[\x83\x82\x10a\x14\xBDWPPPPP`\x80\x84`@a\x0F|\x95\x96\x01Q``\x84\x01R``\x81\x01Q\x15\x15\x82\x84\x01R\x01Q\x90`\xA0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x90\x91\x92\x93\x95\x83\x80a\x14\xF8\x83\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF \x8A`\x01\x96\x03\x01\x86R\x8AQa\x13\xB7V[\x98\x01\x92\x01\x92\x01\x90\x93\x92\x91a\x14\x81V[\x81`\x1F\x82\x01\x12\x15a\x02\xFCW\x80Q\x90a\x15\x1E\x82a\x13eV[\x92a\x15,`@Q\x94\x85a\x11RV[\x82\x84R` \x83\x83\x01\x01\x11a\x02\xFCW\x81_\x92` \x80\x93\x01\x83\x86\x01^\x83\x01\x01R\x90V[\x90` \x82\x82\x03\x12a\x02\xFCW\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15\x07V[\x90\x80`\x1F\x83\x01\x12\x15a\x02\xFCW\x81Q\x90` \x91a\x15\x8E\x81a\x11uV[\x93a\x15\x9C`@Q\x95\x86a\x11RV[\x81\x85R` \x80\x86\x01\x92`\x05\x1B\x82\x01\x01\x92\x83\x11a\x02\xFCW` \x01\x90[\x82\x82\x10a\x15\xC5WPPPP\x90V[\x81Q\x81R\x90\x83\x01\x90\x83\x01a\x15\xB7V[\x90\x91``\x82\x84\x03\x12a\x02\xFCW\x81Q\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x81\x11a\x02\xFCW\x84a\x16\0\x91\x83\x01a\x15sV[\x93` \x80\x83\x01Q\x85\x81\x11a\x02\xFCW\x83\x01\x90\x82`\x1F\x83\x01\x12\x15a\x02\xFCW\x81Q\x91a\x16(\x83a\x11uV[\x92a\x166`@Q\x94\x85a\x11RV[\x80\x84R\x82\x80\x85\x01\x91`\x05\x1B\x83\x01\x01\x91\x85\x83\x11a\x02\xFCW\x83\x01\x90[\x82\x82\x10a\x16rWPPPP\x93`@\x83\x01Q\x90\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15sV[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x03a\x02\xFCW\x81R\x90\x83\x01\x90\x83\x01a\x16PV[\x80Q\x82\x10\x15a\x16\xA5W` \x91`\x05\x1B\x01\x01\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[\x91\x90\x91` \x90\x81\x81R`\xC0\x81\x01\x91`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x81\x83\x01R\x80\x85\x01Q\x92`\xA0`@\x84\x01R\x83Q\x80\x91R`\xE0\x83\x01\x91\x80`\xE0\x83`\x05\x1B\x86\x01\x01\x95\x01\x92_\x90[\x83\x82\x10a\x17QWPPPPP`\x80\x84`@a\x0F|\x95\x96\x01Q``\x84\x01R``\x81\x01Q\x15\x15\x82\x84\x01R\x01Q\x90`\xA0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x90\x91\x92\x93\x95\x83\x80a\x17\x8C\x83\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF \x8A`\x01\x96\x03\x01\x86R\x8AQa\x13\xB7V[\x98\x01\x92\x01\x92\x01\x90\x93\x92\x91a\x17\x15V[\x91\x90a\x17\xA63a(\xB9V[\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\x84\\a\x18\xB1W`\x01\x90`\x01\x86]a\x17\xDF\x83a\x11uV[\x92a\x17\xED`@Q\x94\x85a\x11RV[\x80\x84R`\x1F\x19a\x17\xFC\x82a\x11uV[\x01_[\x81\x81\x10a\x18\xA0WPP_[\x81\x81\x10a\x18WWPPPP\x90_a\x18L\x92\x94]\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\\\x91a\x18NW[Pa6\xB1V[V[_\x90]_a\x18FV[\x80a\x18\x84_\x80a\x18la\x0B\xE0\x89\x96\x88\x8Aa\x19*V[` \x81Q\x91\x010Z\xF4a\x18}a(wV[\x900aA\\V[a\x18\x8E\x82\x88a\x16\x91V[Ra\x18\x99\x81\x87a\x16\x91V[P\x01a\x18\nV[\x80``` \x80\x93\x89\x01\x01R\x01a\x17\xFFV[\x7F>\xE5\xAE\xB5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x905\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x816\x03\x01\x82\x12\x15a\x02\xFCW\x01\x805\x90g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11a\x02\xFCW` \x01\x91\x816\x03\x83\x13a\x02\xFCWV[\x90\x82\x10\x15a\x16\xA5Wa\x19A\x91`\x05\x1B\x81\x01\x90a\x18\xD9V[\x90\x91V[\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0\x80\\a\x18\xB1W`\x01\x90]V[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x163\x03a\x19\xA4WV[\x7F\x08\x96v\xD5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R3`\x04R`$_\xFD[\x90a\x19\xDA\x82a\x11uV[a\x19\xE7`@Q\x91\x82a\x11RV[\x82\x81R`\x1F\x19a\x19\xF7\x82\x94a\x11uV[\x01\x90` 6\x91\x017V[\x91\x90\x82\x01\x80\x92\x11a\x1A\x0EWV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[`@\x81\x015B\x11a&\xC3W\x90a\x1A^a\x1AW` \x84\x01\x84a6\xF4V[\x90Pa\x19\xD0V[\x91_[a\x1An` \x83\x01\x83a6\xF4V[\x90P\x81\x10\x15a%\xC7Wa\x1A\x98\x81a\x1A\x93a\x1A\x8B` \x86\x01\x86a6\xF4V[6\x93\x91a7HV[a\x11\xC6V[\x93`@\x85\x01Q\x93`\x01`\x01`\xA0\x1B\x03\x86Q\x16\x90` \x87\x01Q\x80Q\x15a\x16\xA5W` \x01Q`@\x01Q\x15\x15\x80a%\xBEW[\x15a%cWa\x1A\xECa\x1A\xD8\x86a\x13DV[\x87\x84a\x1A\xE6``\x8A\x01a\x13XV[\x92a:\xDDV[_[` \x88\x01QQ\x81\x10\x15a%SWa\x1B\x03a7\x88V[` \x89\x01QQ_\x19\x81\x01\x90\x81\x11a\x1A\x0EW\x82\x14\x80` \x83\x01R\x82\x15\x82R_\x14a%LW``\x89\x01Q\x90[a\x1B;\x83` \x8C\x01Qa\x16\x91V[Q`@\x81\x01Q\x90\x91\x90\x15a\x1C\xEEWa\x1B\xD3`\x01`\x01`\xA0\x1B\x03\x83Q\x16\x93`\x01`\x01`\xA0\x1B\x03\x88\x16\x85\x14_\x14a\x1C\xE7W`\x01\x94[`@Q\x95a\x1B{\x87a\x11\x1AV[_\x87Ra\x1B\x87\x81a7\xBEV[` \x87\x01R`@\x86\x01R``\x94\x85\x91\x8D\x83\x83\x01R`\x80\x82\x01R`@Q\x80\x93\x81\x92\x7FCX;\xE5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a:\"V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x93\x84\x15a\x02\xF1W_\x94a\x1C\xB0W[PP` \x01Q\x15a\x1C\x96W\x81`\x01`\x01`\xA0\x1B\x03` a\x1C\x90\x93`\x01\x96\x95a\x1C8\x8C\x8Ca\x16\x91V[R\x01a\x1Cg\x82\x82Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[PQ\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[\x01a\x1A\xEEV[` \x01Q\x90\x97P`\x01`\x01`\xA0\x1B\x03\x16\x92P`\x01\x90a\x1C\x90V[` \x92\x94P\x90\x81a\x1C\xD5\x92\x90=\x10a\x1C\xE0W[a\x1C\xCD\x81\x83a\x11RV[\x81\x01\x90a7\xF5V[\x91PP\x92\x90_a\x1C\x10V[P=a\x1C\xC3V[_\x94a\x1BnV[\x88\x8A`\x01`\x01`\xA0\x1B\x03\x84\x95\x94Q\x16\x80`\x01`\x01`\xA0\x1B\x03\x8A\x16\x14_\x14a!2WPP\x81Q\x15\x90Pa nW\x88\x8A\x80\x15\x15\x80a SW[a\x1FMW[`\x01`\x01`\xA0\x1B\x03\x93\x92\x91a\x1D\xDD\x82a\x1E\x15\x97\x8B_\x95\x89\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92\x16\x80\x88R\x82` R`@\x88 \\a\x1Fa\x1F$\x81\x83a\x11RV[\x81\x01\x90a9iV[P\x94\x91\x90Pa\x1ERV[\x91aB#V[a\x1FE\x92aCAV[_\x82\x81a\x1DuV[Pa\x1FZ\x90\x92\x91\x92a\x13DV[\x91a\x1Fd\x8BaB\xFDV[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16;\x15a\x02\xFCW`@Q\x7F6\xC7\x85\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x94\x85\x16`\x04\x82\x01R0`$\x82\x01R\x90\x84\x16`D\x82\x01R\x92\x87\x16`d\x84\x01R_\x83\x80`\x84\x81\x01\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1W\x8Aa\x1D\xDD\x8Da\x1E\x15\x97`\x01`\x01`\xA0\x1B\x03\x97_\x95a DW[P\x97P\x92PP\x91\x92\x93Pa\x1D*V[a M\x90a\x11\x06V[_a 5V[Pa ]\x82a\x13DV[`\x01`\x01`\xA0\x1B\x03\x160\x14\x15a\x1D%V[\x90`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x91`\x01`\x01`\xA0\x1B\x03\x84Q\x16\x92\x80;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x94\x90\x94\x16`\x04\x85\x01R0`$\x85\x01R`D\x84\x01\x8C\x90R_\x90\x84\x90`d\x90\x82\x90\x84\x90Z\xF1\x80\x15a\x02\xF1W\x8Aa\x1D\xDD\x8Da\x1E\x15\x97`\x01`\x01`\xA0\x1B\x03\x97_\x95a!#W[Pa\x1DyV[a!,\x90a\x11\x06V[_a!\x1DV[`\x01`\x01`\xA0\x1B\x03` \x87\x96\x94\x97\x01Q\x16\x90\x89\x81\x83\x14_\x14a#\xD7Wa!\xCD\x92Pa\"\x05\x97\x91P`\x01a!s_\x96\x95`\x01`\x01`\xA0\x1B\x03\x93\x84\x8BQ\x16aB#V[P\x92\x82\x89Q\x16\x95` \x89\x01Q\x15\x15\x88\x14a#\xAEWa!\x90\x82a\x13DV[\x94[a!\xA1`\x80\x93\x84\x81\x01\x90a\x18\xD9V[\x95\x90\x96`@Q\x99a!\xB1\x8Ba\x10\xEAV[\x8AR\x16` \x89\x01R`@\x88\x01R``\x87\x01R\x85\x01R6\x91a\x13\x81V[`\xA0\x82\x01R`@Q\x80\x95\x81\x92\x7FJ\xF2\x9E\xC4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\xF8V[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x92\x83\x15a\x02\xF1W_\x93a#\x84W[P` \x01Q\x15a\"\xC3W\x81`\x01`\x01`\xA0\x1B\x03` a\x1E\xE4\x93`\x01\x96\x95a\"i\x8C\x8Ca\x16\x91V[Ra\"\x99\x83\x83\x83\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[` \x81\x81\x01Q\x91Q`@Q\x7F\x15\xAF\xD4\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\x04\x82\x01R`$\x81\x01\x85\x90R\x93\x9AP\x90\x91\x16\x94P\x81\x80`D\x81\x01\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1Wa#YW[P`\x01\x90a\x1C\x90V[` \x90\x81=\x83\x11a#}W[a#o\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW_a#PV[P=a#eV[` \x91\x93Pa#\xA4\x90=\x80_\x83>a#\x9C\x81\x83a\x11RV[\x81\x01\x90a8|V[P\x93\x91\x90Pa\"BV[\x83\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x94a!\x92V[`\x01`\x01`\xA0\x1B\x03a$f\x95a$.\x93\x94\x95a#\xF8`\x80\x9B\x8C\x81\x01\x90a\x18\xD9V[\x93\x90\x94`@Q\x97a$\x08\x89a\x116V[_\x89R` \x89\x01R\x16`@\x87\x01R``\x9A\x8B\x97\x88\x88\x01R\x86\x01R`\xA0\x85\x01R6\x91a\x13\x81V[`\xC0\x82\x01R`@Q\x80\x93\x81\x92\x7F+\xFBx\x0C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\x10V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x93\x84\x15a\x02\xF1W_\x94a%%W[PP` \x01Q\x15a\x1C\x96W\x81`\x01`\x01`\xA0\x1B\x03` a\x1E\xE4\x93`\x01\x96\x95a$\xCB\x8C\x8Ca\x16\x91V[Ra$\xFB\x83\x83\x83\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[` \x92\x94P\x90\x81a%A\x92\x90=\x10a\x1C\xE0Wa\x1C\xCD\x81\x83a\x11RV[\x91PP\x92\x90_a$\xA3V[_\x90a\x1B-V[P\x91\x95P\x90\x93PP`\x01\x01a\x1AaV[a%\x8D\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[Pa%\xB9\x86\x83\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[a\x1A\xECV[P2\x15\x15a\x1A\xC7V[PPa%\xF2\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a:qV[\x91a%\xFD\x83Qa\x19\xD0V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x90_[\x86Q\x81\x10\x15a&\xBAW`\x01\x90`\x01`\x01`\xA0\x1B\x03\x80a&c\x83\x8Ba\x16\x91V[Q\x16_R\x85` Ra&\x91`@_ \\\x82a&~\x85\x8Da\x16\x91V[Q\x16_R\x88` R`@_ \\\x90a\x1A\x01V[a&\x9B\x83\x87a\x16\x91V[Ra&\xA6\x82\x8Aa\x16\x91V[Q\x16_R\x85` R_`@\x81 ]\x01a&DV[P\x94\x93\x91P\x91PV[\x7F\xE0\x8B\x8A\xF0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x90_\x19\x82\x01\x91\x82\x13`\x01\x16a\x1A\x0EWV[\x7F\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x14a\x1A\x0EW_\x19\x01\x90V[\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x81\\\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a'y\x81\\a&\xEBV[\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91[_\x81\x12\x15a(:WPPPa'\xB1\x90a&\xEBV[\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92[_\x81\x12\x15a'\xEAWPPPPa\x18L\x90a6\xB1V[a(5\x90\x82_Ra(/` _\x83\x82\x82 \x01\\\x91\x82\x82R\x88\x81R\x88`@\x91a(\"\x8A\x8D\x85\x87 \\\x90`\x01`\x01`\xA0\x1B\x03\x89\x16\x90a>\xB0V[\x84\x84RR\x81 ]\x84a>\rV[Pa&\xFCV[a'\xD5V[a(r\x90\x82_Ra(/` _\x8A\x87\x85\x84\x84 \x01\\\x93\x84\x84R\x81\x81Ra(\"\x8C`@\x94\x85\x87 \\\x90`\x01`\x01`\xA0\x1B\x03\x89\x16\x90a:\xDDV[a'\x9DV[=\x15a(\xA1W=\x90a(\x88\x82a\x13eV[\x91a(\x96`@Q\x93\x84a\x11RV[\x82R=_` \x84\x01>V[``\x90V[5\x90e\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x82\x03a\x02\xFCWV[\x90_\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x81\\\x16\x15a(\xF1WPPV[\x90\x91\x92P]`\x01\x90V[\x90`@\x82\x015B\x11a&\xC3Wa)\x17a\x1AW` \x84\x01\x84a6\xF4V[\x91_[a)'` \x83\x01\x83a6\xF4V[\x90P\x81\x10\x15a5\xD1Wa)D\x81a\x1A\x93a\x1A\x8B` \x86\x01\x86a6\xF4V[``\x81\x01Q\x90a)~`\x01`\x01`\xA0\x1B\x03\x82Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P` \x81\x01QQ_\x19\x81\x01\x90\x81\x11a\x1A\x0EW[_\x81\x12\x15a)\xA4WPPP`\x01\x01a)\x1AV[a)\xB2\x81` \x84\x01Qa\x16\x91V[Qa)\xBBa7\x88V[\x90\x82\x15` \x83\x01R` \x84\x01QQ\x80_\x19\x81\x01\x11a\x1A\x0EW_\x19\x01\x83\x14\x80\x83Ra5\x8FW[` \x82\x01Q\x15a5TW`@\x84\x01Q`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x91[`@\x81\x01Q\x15a,\x1DW\x83\x91`\x01`\x01`\xA0\x1B\x03``\x92` a*\xA0\x97\x01Q\x15\x15\x80a,\x14W[a+\xEDW[Q\x16\x90`\x01`\x01`\xA0\x1B\x03\x85\x16\x82\x03a+\xE6W`\x01\x91[`@Q\x92a*L\x84a\x11\x1AV[`\x01\x84Ra*Y\x81a7\xBEV[` \x84\x01R`@\x83\x01R\x88\x83\x83\x01R`\x80\x82\x01R`@Q\x80\x95\x81\x92\x7FCX;\xE5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a:\"V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x92\x83\x15a\x02\xF1W\x87\x91\x8B\x91_\x95a+\xBFW[P` \x01Q\x15a+\xB0Wa+\xA6\x92\x84a+\x02a+\xAB\x97\x96\x94a+u\x94a\x16\x91V[Ra+6`\x01`\x01`\xA0\x1B\x03\x82\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P`\x01`\x01`\xA0\x1B\x03a+M\x84`@\x8A\x01Qa7\xB1V[\x91\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[a&\xFCV[a)\x91V[PPPa+\xAB\x91\x93P\x92a&\xFCV[` \x91\x95Pa+\xDC\x90``=``\x11a\x1C\xE0Wa\x1C\xCD\x81\x83a\x11RV[P\x95\x91\x90Pa*\xE1V[_\x91a*?V[a,\x0Fa+\xF9\x8Da\x13DV[\x8D\x8Ba\x1A\xE6\x88`@\x88\x84Q\x16\x93\x01Q\x93\x01a\x13XV[a*(V[P2\x15\x15a*#V[\x90`\x01`\x01`\xA0\x1B\x03\x82Q\x16\x80`\x01`\x01`\xA0\x1B\x03\x85\x16\x14_\x14a17WP` \x84\x01Qa0IWP`@Q\x92\x7F\x96xp\x92\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84R`\x01`\x01`\xA0\x1B\x03\x83\x16`\x04\x85\x01R` \x84`$\x81`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xFA\x93\x84\x15a\x02\xF1W_\x94a0\x15W[P\x83\x91`\x01`\x01`\xA0\x1B\x03\x81Q\x16`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R0`$\x82\x01R`D\x81\x01\x95\x90\x95R_\x85\x80`d\x81\x01\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x90\x81\x15a\x02\xF1Wa-\xEC\x95_\x92a0\x06W[P[a\x1D\xDD`\x01`\x01`\xA0\x1B\x03a-\xA8\x8B\x82\x85Q\x16\x83` \x87\x01Q\x16\x90aB#V[P\x92Q\x16\x91\x8C`\x02a-\xBF`\x80\x92\x83\x81\x01\x90a\x18\xD9V[\x92\x90\x93`@Q\x96a-\xCF\x88a\x10\xEAV[\x87R0` \x88\x01R\x89`@\x88\x01R``\x87\x01R\x85\x01R6\x91a\x13\x81V[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x93\x84\x15a\x02\xF1W_\x94a/\xE3W[P` \x01Q\x15a.\xCFW\x90\x82\x91a+\xAB\x94\x93a.E\x89\x8Da\x16\x91V[Ra.z\x83`\x01`\x01`\xA0\x1B\x03\x84\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[\x80\x83\x10\x80a.\xB4W[a.\x90W[PPPa&\xFCV[a.\xA6a.\xAC\x93a.\xA0\x8Ba\x13DV[\x92a7\xB1V[\x91aCVV[_\x80\x80a.\x88V[P0`\x01`\x01`\xA0\x1B\x03a.\xC7\x8Ba\x13DV[\x16\x14\x15a.\x83V[\x94P\x90\x80\x94\x80\x82\x10a.\xE8W[PPPa+\xAB\x90a&\xFCV[\x91a.\xF8` \x92a/w\x94a7\xB1V[\x90a/-\x82`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x83aCVV[`@Q\x93\x84\x92\x83\x92\x7F\x15\xAF\xD4\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84R`\x04\x84\x01` \x90\x93\x92\x91\x93`\x01`\x01`\xA0\x1B\x03`@\x82\x01\x95\x16\x81R\x01RV[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1Wa/\xB8W[\x80\x80a.\xDCV[` \x90\x81=\x83\x11a/\xDCW[a/\xCE\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW_a/\xB1V[P=a/\xC4V[` \x91\x94Pa/\xFB\x90=\x80_\x83>a\x1F$\x81\x83a\x11RV[P\x90\x94\x91\x90Pa.)V[a0\x0F\x90a\x11\x06V[_a-\x86V[\x90\x93P` \x81=` \x11a0AW[\x81a01` \x93\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCWQ\x92_a,\xBCV[=\x91Pa0$V[\x90\x92a0T\x89a\x13DV[`\x01`\x01`\xA0\x1B\x030\x91\x16\x03a0oW[_a-\xEC\x94a-\x88V[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x93a0\xA3\x8Aa\x13DV[a0\xAC\x84aB\xFDV[\x90\x86;\x15a\x02\xFCW`@Q\x7F6\xC7\x85\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\x04\x82\x01R0`$\x82\x01R\x91\x81\x16`D\x83\x01R\x85\x16`d\x82\x01R\x94_\x90\x86\x90`\x84\x90\x82\x90\x84\x90Z\xF1\x90\x81\x15a\x02\xF1Wa-\xEC\x95_\x92a1(W[P\x94PPa0eV[a11\x90a\x11\x06V[_a1\x1FV[`\x01`\x01`\xA0\x1B\x03` \x84\x96\x95\x94\x01Q\x16\x8A\x82\x82\x14_\x14a4\x0BWPPPa2\x0Ca1n_\x92\x84`\x01`\x01`\xA0\x1B\x03\x88Q\x16aB#V[\x92\x90a1\xD4\x8C`\x01`\x01`\xA0\x1B\x03\x80\x8AQ\x16\x93\x89Q\x15\x15\x86\x14a3\xDFWa1\xA3a1\x97\x84a\x13DV[\x93[`\x80\x81\x01\x90a\x18\xD9V[\x92\x90\x93`@Q\x96a1\xB3\x88a\x10\xEAV[\x87R\x16` \x86\x01R`@\x85\x01R\x8C``\x85\x01R`\x02`\x80\x85\x01R6\x91a\x13\x81V[`\xA0\x82\x01R`@Q\x80\x93\x81\x92\x7FJ\xF2\x9E\xC4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\xF8V[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x90\x81\x15a\x02\xF1W_\x91a3\xC4W[P` \x84\x01Q\x8C\x90\x8A\x90\x15a3\xAAW\x83\x83`\x01`\x01`\xA0\x1B\x03\x93a2\x83a2\x89\x94a2|\x8F\x9C\x9B\x9A\x98\x99a2\xB2\x9Aa\x16\x91V[Q\x92a\x16\x91V[Ra\x16\x91V[Q\x91\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[Q\x15a2\xF4Wa+\xAB\x92\x91`\x01`\x01`\xA0\x1B\x03` a+\xA6\x93\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aCAV[Q`@Q\x7F\x15\xAF\xD4\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x81\x01\x91\x90\x91R` \x81\x80`D\x81\x01\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1Wa3\x7FW[Pa+\xAB\x90a&\xFCV[` \x90\x81=\x83\x11a3\xA3W[a3\x95\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW_a3uV[P=a3\x8BV[PP\x90\x91Pa3\xBB\x92\x93\x96Pa\x16\x91V[Q\x93\x84\x91a2\xB2V[a3\xD8\x91P=\x80_\x83>a#\x9C\x81\x83a\x11RV[\x90Pa2IV[a1\xA3\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x93a1\x99V[a4\x9E\x96P\x90a4f\x91``\x94\x8Ba4+`\x80\x99\x98\x99\x93\x84\x81\x01\x90a\x18\xD9V[\x93\x90\x94`@Q\x97a4;\x89a\x116V[`\x01\x89R` \x89\x01R`\x01`\x01`\xA0\x1B\x03\x8B\x16`@\x89\x01R\x88\x88\x01R\x86\x01R`\xA0\x85\x01R6\x91a\x13\x81V[`\xC0\x82\x01R`@Q\x80\x95\x81\x92\x7F+\xFBx\x0C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\x10V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x92\x83\x15a\x02\xF1W\x87\x91\x8B\x91_\x95a5-W[P` \x01Q\x15a+\xB0Wa+\xA6\x92\x84a5\x05a+\xAB\x97\x96\x94`\x01`\x01`\xA0\x1B\x03\x94a\x16\x91V[R\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[` \x91\x95Pa5J\x90``=``\x11a\x1C\xE0Wa\x1C\xCD\x81\x83a\x11RV[P\x95\x91\x90Pa4\xDFV[o\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x01`\x01`\xA0\x1B\x03` a5\x85\x81\x88\x01Qa5\x7F\x88a&\xEBV[\x90a\x16\x91V[Q\x01Q\x16\x91a)\xFCV[a5\xCC\x85`\x01`\x01`\xA0\x1B\x03` \x84\x01a\x1Cg\x82\x82Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[a)\xE0V[PPa5\xFC\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a:qV[\x91a6\x07\x83Qa\x19\xD0V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x90_[\x86Q\x81\x10\x15a&\xBAW`\x01\x90`\x01`\x01`\xA0\x1B\x03\x80a6m\x83\x8Ba\x16\x91V[Q\x16_R\x85` Ra6\x88`@_ \\\x82a&~\x85\x8Da\x16\x91V[a6\x92\x83\x87a\x16\x91V[Ra6\x9D\x82\x8Aa\x16\x91V[Q\x16_R\x85` R_`@\x81 ]\x01a6NV[G\x80\x15a6\xF0W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\a6\xF0W`\x01`\x01`\xA0\x1B\x03a\x18L\x92\x16a@\xE0V[PPV[\x905\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x816\x03\x01\x82\x12\x15a\x02\xFCW\x01\x805\x90g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11a\x02\xFCW` \x01\x91\x81`\x05\x1B6\x03\x83\x13a\x02\xFCWV[\x91\x90\x81\x10\x15a\x16\xA5W`\x05\x1B\x81\x015\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x816\x03\x01\x82\x12\x15a\x02\xFCW\x01\x90V[`@Q\x90`@\x82\x01\x82\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@R_` \x83\x82\x81R\x01RV[\x91\x90\x82\x03\x91\x82\x11a\x1A\x0EWV[`\x02\x11\x15a7\xC8WV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x90\x81``\x91\x03\x12a\x02\xFCW\x80Q\x91`@` \x83\x01Q\x92\x01Q\x90V[a\x01\0`\xC0a\x0F|\x93` \x84R\x80Qa8(\x81a7\xBEV[` \x85\x01R` \x81\x01Q`\x01`\x01`\xA0\x1B\x03\x80\x91\x16`@\x86\x01R\x80`@\x83\x01Q\x16``\x86\x01R``\x82\x01Q\x16`\x80\x85\x01R`\x80\x81\x01Q`\xA0\x85\x01R`\xA0\x81\x01Q\x82\x85\x01R\x01Q\x91`\xE0\x80\x82\x01R\x01\x90a\x0F\xFBV[\x90\x91``\x82\x84\x03\x12a\x02\xFCW\x81Q\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x81\x11a\x02\xFCW\x84a8\xA8\x91\x83\x01a\x15sV[\x93` \x82\x01Q\x93`@\x83\x01Q\x90\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15\x07V[\x90\x81Q\x80\x82R` \x80\x80\x93\x01\x93\x01\x91_[\x82\x81\x10a8\xE4WPPPP\x90V[\x83Q\x85R\x93\x81\x01\x93\x92\x81\x01\x92`\x01\x01a8\xD6V[` \x81R`\x01`\x01`\xA0\x1B\x03\x80\x83Q\x16` \x83\x01R` \x83\x01Q\x16`@\x82\x01Ra91`@\x83\x01Q`\xC0``\x84\x01R`\xE0\x83\x01\x90a8\xC5V[\x90``\x83\x01Q`\x80\x82\x01R`\x80\x83\x01Q`\x05\x81\x10\x15a7\xC8Wa\x0F|\x93`\xA0\x91\x82\x84\x01R\x01Q\x90`\xC0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x91``\x83\x83\x03\x12a\x02\xFCW\x82Q\x92` \x81\x01Q\x92g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x93\x84\x81\x11a\x02\xFCW\x81a9\x9A\x91\x84\x01a\x15sV[\x93`@\x83\x01Q\x90\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15\x07V[` \x81R`\x01`\x01`\xA0\x1B\x03\x80\x83Q\x16` \x83\x01R` \x83\x01Q\x16`@\x82\x01R`@\x82\x01Q``\x82\x01Ra9\xF4``\x83\x01Q`\xC0`\x80\x84\x01R`\xE0\x83\x01\x90a8\xC5V[\x90`\x80\x83\x01Q`\x04\x81\x10\x15a7\xC8Wa\x0F|\x93`\xA0\x91\x82\x84\x01R\x01Q\x90`\xC0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x91\x90\x91`\x80\x80`\xA0\x83\x01\x94\x80Qa:8\x81a7\xBEV[\x84R` \x81\x01Qa:H\x81a7\xBEV[` \x85\x01R`\x01`\x01`\xA0\x1B\x03`@\x82\x01Q\x16`@\x85\x01R``\x81\x01Q``\x85\x01R\x01Q\x91\x01RV[\x90\x81\\a:}\x81a\x11uV[a:\x8A`@Q\x91\x82a\x11RV[\x81\x81Ra:\x96\x82a\x11uV[`\x1F\x19` \x91\x016` \x84\x017\x81\x94_[\x84\x81\x10a:\xB5WPPPPPV[`\x01\x90\x82_R\x80\x84_ \x01\\`\x01`\x01`\xA0\x1B\x03a:\xD3\x83\x88a\x16\x91V[\x91\x16\x90R\x01a:\xA7V[\x91\x92\x80a=\xD8W[\x15a=\x90\xFD[` \x92Pa<\x1F\x90a\x11\x06V[`D_\x92Pa;cV[\x7F\xA0\x1A\x9D\xF6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x90\x91_\x90\x80a\xA7W_\x19\x90\x81\x81\x01\x83\\\x83\x80\x82\x01\x91\x82\x84\x03a>jW[PPPPP\x81\\\x81\x81\x01\x92\x81\x84\x11a\x1A\x0EW_\x93\x81]\x83R\x84\x83 \x01\x01]_RR_`@\x81 ]`\x01\x90V[a>wa>\x87\x93\x88aD:V[\x86_R\x88_ \x01\x01\\\x91\x85aD:V[\x83_R\x80\x83\x83\x88_ \x01\x01]_R\x85\x85R`@_ ]_\x80\x80\x83\x81a>>V[PPPPP_\x90V[_\x94\x93\x83\x15a@\xD8W\x80a@\xA3W[\x15a@\x07W`\x01`\x01`\xA0\x1B\x03\x91\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x80;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x92\x90\x92\x16`\x04\x83\x01R0`$\x83\x01R`D\x82\x01\x85\x90R_\x90\x82\x90`d\x90\x82\x90\x84\x90Z\xF1\x80\x15a\x02\xF1Wa?\xF4W[P\x84\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x80;\x15a?\xF0W\x81\x90`$`@Q\x80\x94\x81\x93\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R\x89`\x04\x84\x01RZ\xF1\x80\x15a?\xE5Wa?\xCDW[Pa\x18L\x93\x94P\x16a@\xE0V[a?\xD7\x86\x91a\x11\x06V[a?\xE1W\x84a?\xC0V[\x84\x80\xFD[`@Q=\x88\x82>=\x90\xFD[P\x80\xFD[a?\xFF\x91\x95Pa\x11\x06V[_\x93_a?SV[\x92\x93P\x90`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x80;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x93\x84\x16`\x04\x82\x01R\x93\x90\x92\x16`$\x84\x01R`D\x83\x01R_\x90\x82\x90`d\x90\x82\x90\x84\x90Z\xF1\x80\x15a\x02\xF1Wa@\x9AWPV[a\x18L\x90a\x11\x06V[P`\x01`\x01`\xA0\x1B\x03\x80\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90\x83\x16\x14a>\xBFV[PPPP\x90PV[\x81G\x10aA0W_\x80\x80\x93`\x01`\x01`\xA0\x1B\x03\x82\x94\x16Z\xF1aA\0a(wV[P\x15aA\x08WV[\x7F\x14%\xEAB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x7F\xCDx`Y\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R0`\x04R`$_\xFD[\x90aAqWP\x80Q\x15aA\x08W\x80Q\x90` \x01\xFD[\x81Q\x15\x80aA\xB7W[aA\x82WP\x90V[`\x01`\x01`\xA0\x1B\x03\x90\x7F\x99\x96\xB3\x15\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R\x16`\x04R`$_\xFD[P\x80;\x15aAzV[`\x01\x81\x01\x90\x82_R\x81` R`@_ \\\x15_\x14aB\x03W\x80\\\x81_R\x83\x81` _ \x01]`\x01\x81\x01\x80\x91\x11a\x1A\x0EW\x81]\\\x91_R` R`@_ ]`\x01\x90V[PPP_\x90V[\x90_R` RaB\x1F`@_ \x91\x82\\a\x1A\x01V[\x90]V[\x91`D\x92\x93\x91\x93`\x01`\x01`\xA0\x1B\x03`@\x94\x85\x92\x82\x80\x85Q\x99\x8A\x95\x86\x94\x7F\xC9\xC1f\x1B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86R\x16`\x04\x85\x01R\x16`$\x83\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xFA\x93\x84\x15aB\xF3W_\x93_\x95aB\xBCW[PPaB\xB9aB\xB2\x85\x94a\x19\xD0V[\x94\x85a\x16\x91V[RV[\x80\x92\x95P\x81\x94P=\x83\x11aB\xECW[aB\xD5\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW` \x82Q\x92\x01Q\x92_\x80aB\xA3V[P=aB\xCBV[\x83Q=_\x82>=\x90\xFD[`\x01`\x01`\xA0\x1B\x03\x90\x81\x81\x11aC\x11W\x16\x90V[\x7Fm\xFC\xC6P\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\xA0`\x04R`$R`D_\xFD[\x90_R` RaB\x1F`@_ \x91\x82\\a7\xB1V[`@Q\x92` \x84\x01\x90\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82R`\x01`\x01`\xA0\x1B\x03\x80\x94\x16`$\x86\x01R`D\x85\x01R`D\x84R`\x80\x84\x01\x90\x84\x82\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11\x17a\x10\xBDWaC\xD5\x93_\x93\x84\x93`@R\x16\x94Q\x90\x82\x86Z\xF1aC\xCEa(wV[\x90\x83aA\\V[\x80Q\x90\x81\x15\x15\x91\x82aD\x16W[PPaC\xEBWPV[\x7FRt\xAF\xE7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04R`$_\xFD[\x81\x92P\x90` \x91\x81\x01\x03\x12a\x02\xFCW` \x01Q\x80\x15\x90\x81\x15\x03a\x02\xFCW_\x80aC\xE2V[\\\x11\x15aDCWV[\x7F\x0FJ\xE0\xE4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD\xFE\xA2dipfsX\"\x12 \"\x9A\\\xF8\x9A\xA7\xC2\xD0\xA4\xB4\xD5\xDB \xBB\xA6\xC2\xB3\xA7K\x08\x03\x03\xFCn\xC0\x0B\xA5\x82\xA5\xDC\xF7QdsolcC\0\x08\x1A\x003", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x60806040526004361015610072575b3615610018575f80fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361004a57005b7f0540ddf6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f3560e01c806308a465f614610e9d57806319c6989f1461084e578063286f580d146107b75780632950286e146106cc57806354fd4d501461058f5780635a3c3987146105665780635e01eb5a146105215780638a12a08c146104c65780638eb1b65e146103bf578063945ed33f14610344578063ac9650d8146103005763e3b5dff40361000e57346102fc576060806003193601126102fc5767ffffffffffffffff6004358181116102fc5761012d9036906004016112c4565b6101356111a1565b6044359283116102fc57610150610158933690600401610fcd565b9390916128b9565b905f5b835181101561017c57805f8761017360019488611691565b5101520161015b565b506101f06101fe610239946101b65f94886040519361019a8561111a565b30855260208501525f1960408501528660608501523691611381565b60808201526040519283917f8a12a08c0000000000000000000000000000000000000000000000000000000060208401526024830161143e565b03601f198101835282611152565b604051809481927fedfa3568000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39261028e915f916102cf575b50602080825183010191016115d4565b909391926102a7575b60405193849384610f2f565b0390f35b5f7f00000000000000000000000000000000000000000000000000000000000000005d610297565b6102eb91503d805f833e6102e38183611152565b81019061154d565b8461027e565b6040513d5f823e3d90fd5b5f80fd5b60206003193601126102fc5760043567ffffffffffffffff81116102fc576103386103326102a3923690600401610f9c565b9061179b565b60405191829182611020565b346102fc5761035236610eca565b61035a611945565b610362611972565b6103906102a3610371836128fb565b9193909461038a606061038383611344565b9201611358565b90612729565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d60405193849384610f2f565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576103ec9036906004016112c4565b906103f56111b7565b906064359081116102fc576101f061048b6102399461045161041c5f953690600401610fcd565b610425336128b9565b97604051946104338661111a565b33865260208601526024356040860152151560608501523691611381565b60808201526040519283917f945ed33f000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b604051809481927f48c89491000000000000000000000000000000000000000000000000000000008352602060048401526024830190610ffb565b346102fc576102a36104ef6104da36610eca565b6104e2611945565b6104ea611972565b611a3b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f009492945d60405193849384610f2f565b346102fc575f6003193601126102fc5760207f00000000000000000000000000000000000000000000000000000000000000005c6001600160a01b0360405191168152f35b346102fc576102a36104ef61057a36610eca565b610582611945565b61058a611972565b6128fb565b346102fc575f6003193601126102fc576040515f80549060018260011c91600184169182156106c2575b60209485851084146106955785879486865291825f146106575750506001146105fe575b506105ea92500383611152565b6102a3604051928284938452830190610ffb565b5f808052859250907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061063f5750506105ea9350820101856105dd565b80548389018501528794508693909201918101610628565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858201526105ea95151560051b85010192508791506105dd9050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b92607f16926105b9565b346102fc5760606003193601126102fc5767ffffffffffffffff6004358181116102fc576106fe9036906004016112c4565b906107076111a1565b6044359182116102fc5761072261072a923690600401610fcd565b9290916128b9565b905f5b845181101561075f57806fffffffffffffffffffffffffffffffff604061075660019489611691565b5101520161072d565b506101f06101fe8561077d5f94610239976040519361019a8561111a565b60808201526040519283917f5a3c3987000000000000000000000000000000000000000000000000000000006020840152602483016116d2565b60806003193601126102fc5767ffffffffffffffff6004358181116102fc576107e49036906004016112c4565b906107ed6111b7565b906064359081116102fc576101f061048b6102399461081461041c5f953690600401610fcd565b60808201526040519283917f08a465f60000000000000000000000000000000000000000000000000000000060208401526024830161143e565b60a06003193601126102fc5767ffffffffffffffff600435116102fc573660236004350112156102fc5767ffffffffffffffff60043560040135116102fc5736602460c060043560040135026004350101116102fc5760243567ffffffffffffffff81116102fc576108c4903690600401610f9c565b67ffffffffffffffff604435116102fc576060600319604435360301126102fc5760643567ffffffffffffffff81116102fc57610905903690600401610fcd565b60843567ffffffffffffffff81116102fc57610925903690600401610f9c565b949093610930611945565b806004356004013503610e75575f5b600435600401358110610bd25750505060443560040135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd6044353603018212156102fc57816044350160048101359067ffffffffffffffff82116102fc5760248260071b36039101136102fc576109e3575b6102a361033886865f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d61179b565b6001600160a01b039492947f0000000000000000000000000000000000000000000000000000000000000000163b156102fc57604051947f2a2d80d10000000000000000000000000000000000000000000000000000000086523360048701526060602487015260c486019260443501602481019367ffffffffffffffff6004830135116102fc57600482013560071b360385136102fc5760606064890152600482013590529192869260e484019291905f905b60048101358210610b5457505050602091601f19601f865f9787956001600160a01b03610ac860246044350161118d565b16608488015260448035013560a48801526003198787030160448801528186528786013787868286010152011601030181836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19182156102f1576102a39361033893610b45575b8294508193506109b3565b610b4e90611106565b84610b3a565b9195945091926001600160a01b03610b6b8761118d565b168152602080870135916001600160a01b0383168093036102fc57600492600192820152610b9b604089016128a6565b65ffffffffffff8091166040830152610bb660608a016128a6565b1660608201526080809101970193019050889495939291610a97565b610be7610be082848661192a565b3691611381565b604051610bf3816110a1565b5f81526020915f838301525f60408301528281015190606060408201519101515f1a91835283830152604082015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc81850260043501360301126102fc5760405190610c60826110ea565b610c73602460c08602600435010161118d565b808352610c89604460c08702600435010161118d565b908185850152610ca2606460c08802600435010161118d565b60408581019190915260043560c08802016084810135606087015260a4810135608087015260c4013560a086015283015183519386015160ff91909116926001600160a01b0383163b156102fc575f6001600160a01b03809460e4948b98849860c460c06040519c8d9b8c9a7fd505accf000000000000000000000000000000000000000000000000000000008c521660048b01523060248b0152608482820260043501013560448b0152026004350101356064880152608487015260a486015260c4850152165af19081610e66575b50610e5c57610d7f612877565b906001600160a01b0381511690836001600160a01b0381830151166044604051809581937fdd62ed3e00000000000000000000000000000000000000000000000000000000835260048301523060248301525afa9182156102f1575f92610e2c575b506060015103610df75750506001905b0161093f565b805115610e045780519101fd5b7fa7285689000000000000000000000000000000000000000000000000000000005f5260045ffd5b9091508381813d8311610e55575b610e448183611152565b810103126102fc5751906060610de1565b503d610e3a565b5050600190610df1565b610e6f90611106565b8a610d72565b7faaad13f7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102fc57610eab36610eca565b610eb3611945565b610ebb611972565b6103906102a361037183611a3b565b600319906020828201126102fc576004359167ffffffffffffffff83116102fc578260a0920301126102fc5760040190565b9081518082526020808093019301915f5b828110610f1b575050505090565b835185529381019392810192600101610f0d565b939290610f4490606086526060860190610efc565b936020948181036020830152602080855192838152019401905f5b818110610f7f57505050610f7c9394506040818403910152610efc565b90565b82516001600160a01b031686529487019491870191600101610f5f565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc576020808501948460051b0101116102fc57565b9181601f840112156102fc5782359167ffffffffffffffff83116102fc57602083818601950101116102fc57565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110555750505050505090565b9091929394958480611091837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51610ffb565b9801930193019194939290611045565b6060810190811067ffffffffffffffff8211176110bd57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd57604052565b60a0810190811067ffffffffffffffff8211176110bd57604052565b60e0810190811067ffffffffffffffff8211176110bd57604052565b90601f601f19910116810190811067ffffffffffffffff8211176110bd57604052565b67ffffffffffffffff81116110bd5760051b60200190565b35906001600160a01b03821682036102fc57565b602435906001600160a01b03821682036102fc57565b6044359081151582036102fc57565b9190916080818403126102fc57604090815191608083019467ffffffffffffffff95848110878211176110bd57825283956112008461118d565b8552602090818501359081116102fc57840182601f820112156102fc5780359061122982611175565b9361123686519586611152565b82855283850190846060809502840101928184116102fc578501915b8383106112745750505050508401528181013590830152606090810135910152565b84838303126102fc57875190611289826110a1565b6112928461118d565b825261129f87850161118d565b87830152888401359081151582036102fc578288928b89950152815201920191611252565b81601f820112156102fc578035916020916112de84611175565b936112ec6040519586611152565b808552838086019160051b830101928084116102fc57848301915b8483106113175750505050505090565b823567ffffffffffffffff81116102fc578691611339848480948901016111c6565b815201920191611307565b356001600160a01b03811681036102fc5790565b3580151581036102fc5790565b67ffffffffffffffff81116110bd57601f01601f191660200190565b92919261138d82611365565b9161139b6040519384611152565b8294818452818301116102fc578281602093845f960137010152565b9060808101916001600160a01b03808251168352602093848301519460808186015285518092528060a086019601925f905b83821061140b5750505050506060816040829301516040850152015191015290565b845180518216895280840151821689850152604090810151151590890152606090970196938201936001909101906113e9565b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106114bd5750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b909192939583806114f8837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611481565b81601f820112156102fc5780519061151e82611365565b9261152c6040519485611152565b828452602083830101116102fc57815f9260208093018386015e8301015290565b906020828203126102fc57815167ffffffffffffffff81116102fc57610f7c9201611507565b9080601f830112156102fc5781519060209161158e81611175565b9361159c6040519586611152565b81855260208086019260051b8201019283116102fc57602001905b8282106115c5575050505090565b815181529083019083016115b7565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc5784611600918301611573565b936020808301518581116102fc5783019082601f830112156102fc5781519161162883611175565b926116366040519485611152565b808452828085019160051b830101918583116102fc578301905b82821061167257505050509360408301519081116102fc57610f7c9201611573565b81516001600160a01b03811681036102fc578152908301908301611650565b80518210156116a55760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b91909160209081815260c08101916001600160a01b0385511681830152808501519260a06040840152835180915260e08301918060e08360051b8601019501925f905b8382106117515750505050506080846040610f7c959601516060840152606081015115158284015201519060a0601f1982850301910152610ffb565b9091929395838061178c837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208a600196030186528a516113b7565b98019201920190939291611715565b91906117a6336128b9565b907f000000000000000000000000000000000000000000000000000000000000000093845c6118b1576001906001865d6117df83611175565b926117ed6040519485611152565b808452601f196117fc82611175565b015f5b8181106118a05750505f5b8181106118575750505050905f61184c92945d7f0000000000000000000000000000000000000000000000000000000000000000805c9161184e575b506136b1565b565b5f905d5f611846565b806118845f8061186c610be08996888a61192a565b602081519101305af461187d612877565b903061415c565b61188e8288611691565b526118998187611691565b500161180a565b8060606020809389010152016117ff565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc576020019181360383136102fc57565b908210156116a5576119419160051b8101906118d9565b9091565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805c6118b1576001905d565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633036119a457565b7f089676d5000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906119da82611175565b6119e76040519182611152565b828152601f196119f78294611175565b0190602036910137565b91908201809211611a0e57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b604081013542116126c35790611a5e611a5760208401846136f4565b90506119d0565b915f5b611a6e60208301836136f4565b90508110156125c757611a9881611a93611a8b60208601866136f4565b369391613748565b6111c6565b936040850151936001600160a01b038651169060208701518051156116a55760200151604001511515806125be575b1561256357611aec611ad886611344565b8784611ae660608a01611358565b92613add565b5f5b60208801515181101561255357611b03613788565b6020890151515f198101908111611a0e578214806020830152821582525f1461254c576060890151905b611b3b8360208c0151611691565b51604081015190919015611cee57611bd36001600160a01b03835116936001600160a01b03881685145f14611ce7576001945b60405195611b7b8761111a565b5f8752611b87816137be565b6020870152604086015260609485918d838301526080820152604051809381927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611cb0575b50506020015115611c9657816001600160a01b036020611c909360019695611c388c8c611691565b5201611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b5051167f000000000000000000000000000000000000000000000000000000000000000061420a565b01611aee565b602001519097506001600160a01b03169250600190611c90565b60209294509081611cd592903d10611ce0575b611ccd8183611152565b8101906137f5565b91505092905f611c10565b503d611cc3565b5f94611b6e565b888a6001600160a01b038495945116806001600160a01b038a16145f14612132575050815115905061206e57888a80151580612053575b611f4d575b6001600160a01b03939291611ddd82611e15978b5f95897f0000000000000000000000000000000000000000000000000000000000000000921680885282602052604088205c611f3c575b5050505b6001611d9c8983511660208401998b8b51169080158a14611f3657508391614223565b999092511694611db1608091828101906118d9565b93909460405197611dc1896110ea565b8852306020890152604088015260608701528501523691611381565b60a0820152604051809681927f21457897000000000000000000000000000000000000000000000000000000008352600483016139b1565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94611f0c575b506020015115611ee95791611ebc826001600160a01b0360019695611e7a611ee49686611691565b51611e858d8d611691565b52611eb3828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b50511692611691565b51907f000000000000000000000000000000000000000000000000000000000000000061420a565b611c90565b98506001929450611f02906001600160a01b0392611691565b5197511692611c90565b6020919450611f2c903d805f833e611f248183611152565b810190613969565b5094919050611e52565b91614223565b611f4592614341565b5f8281611d75565b50611f5a90929192611344565b91611f648b6142fd565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039485166004820152306024820152908416604482015292871660648401525f8380608481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f1578a611ddd8d611e15976001600160a01b03975f95612044575b50975092505091929350611d2a565b61204d90611106565b5f612035565b5061205d82611344565b6001600160a01b0316301415611d25565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916001600160a01b0384511692803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03949094166004850152306024850152604484018c90525f908490606490829084905af180156102f1578a611ddd8d611e15976001600160a01b03975f95612123575b50611d79565b61212c90611106565b5f61211d565b6001600160a01b0360208796949701511690898183145f146123d7576121cd925061220597915060016121735f96956001600160a01b0393848b5116614223565b509282895116956020890151151588146123ae5761219082611344565b945b6121a1608093848101906118d9565b959096604051996121b18b6110ea565b8a52166020890152604088015260608701528501523691611381565b60a0820152604051809581927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f1575f93612384575b5060200151156122c357816001600160a01b036020611ee493600196956122698c8c611691565b526122998383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b60208181015191516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101859052939a50909116945081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612359575b50600190611c90565b602090813d831161237d575b61236f8183611152565b810103126102fc575f612350565b503d612365565b60209193506123a4903d805f833e61239c8183611152565b81019061387c565b5093919050612242565b837f00000000000000000000000000000000000000000000000000000000000000001694612192565b6001600160a01b036124669561242e9394956123f860809b8c8101906118d9565b9390946040519761240889611136565b5f8952602089015216604087015260609a8b978888015286015260a08501523691611381565b60c0820152604051809381927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612525575b50506020015115611c9657816001600160a01b036020611ee493600196956124cb8c8c611691565b526124fb8383830151167f00000000000000000000000000000000000000000000000000000000000000006141c0565b500151167f000000000000000000000000000000000000000000000000000000000000000061420a565b6020929450908161254192903d10611ce057611ccd8183611152565b91505092905f6124a3565b5f90611b2d565b5091955090935050600101611a61565b61258d827f00000000000000000000000000000000000000000000000000000000000000006141c0565b506125b986837f000000000000000000000000000000000000000000000000000000000000000061420a565b611aec565b50321515611ac7565b50506125f27f0000000000000000000000000000000000000000000000000000000000000000613a71565b916125fd83516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b0380612663838b611691565b51165f528560205261269160405f205c8261267e858d611691565b51165f528860205260405f205c90611a01565b61269b8387611691565b526126a6828a611691565b51165f52856020525f604081205d01612644565b50949391509150565b7fe08b8af0000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f198201918213600116611a0e57565b7f80000000000000000000000000000000000000000000000000000000000000008114611a0e575f190190565b907f000000000000000000000000000000000000000000000000000000000000000090815c7f0000000000000000000000000000000000000000000000000000000000000000612779815c6126eb565b907f0000000000000000000000000000000000000000000000000000000000000000915b5f81121561283a575050506127b1906126eb565b917f0000000000000000000000000000000000000000000000000000000000000000925b5f8112156127ea575050505061184c906136b1565b61283590825f5261282f60205f83828220015c91828252888152886040916128228a8d8587205c906001600160a01b03891690613eb0565b8484525281205d84613e0d565b506126fc565b6127d5565b61287290825f5261282f60205f8a8785848420015c938484528181526128228c6040948587205c906001600160a01b03891690613add565b61279d565b3d156128a1573d9061288882611365565b916128966040519384611152565b82523d5f602084013e565b606090565b359065ffffffffffff821682036102fc57565b905f917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03815c16156128f1575050565b909192505d600190565b90604082013542116126c357612917611a5760208401846136f4565b915f5b61292760208301836136f4565b90508110156135d15761294481611a93611a8b60208601866136f4565b60608101519061297e6001600160a01b038251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506020810151515f198101908111611a0e575b5f8112156129a45750505060010161291a565b6129b2816020840151611691565b516129bb613788565b9082156020830152602084015151805f19810111611a0e575f1901831480835261358f575b6020820151156135545760408401516001600160a01b03855116915b604081015115612c1d5783916001600160a01b036060926020612aa0970151151580612c14575b612bed575b5116906001600160a01b0385168203612be6576001915b60405192612a4c8461111a565b60018452612a59816137be565b6020840152604083015288838301526080820152604051809581927f43583be500000000000000000000000000000000000000000000000000000000835260048301613a22565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f95612bbf575b506020015115612bb057612ba69284612b02612bab979694612b7594611691565b52612b366001600160a01b0382167f00000000000000000000000000000000000000000000000000000000000000006141c0565b506001600160a01b03612b4d8460408a01516137b1565b91167f000000000000000000000000000000000000000000000000000000000000000061420a565b6001600160a01b038551167f000000000000000000000000000000000000000000000000000000000000000061420a565b6126fc565b612991565b505050612bab919350926126fc565b6020919550612bdc9060603d606011611ce057611ccd8183611152565b5095919050612ae1565b5f91612a3f565b612c0f612bf98d611344565b8d8b611ae6886040888451169301519301611358565b612a28565b50321515612a23565b906001600160a01b03825116806001600160a01b038516145f14613137575060208401516130495750604051927f967870920000000000000000000000000000000000000000000000000000000084526001600160a01b03831660048501526020846024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9384156102f1575f94613015575b5083916001600160a01b038151166001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03909116600482015230602482015260448101959095525f8580606481010381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f157612dec955f92613006575b505b611ddd6001600160a01b03612da88b828551168360208701511690614223565b50925116918c6002612dbf608092838101906118d9565b92909360405196612dcf886110ea565b875230602088015289604088015260608701528501523691611381565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19384156102f1575f94612fe3575b506020015115612ecf57908291612bab9493612e45898d611691565b52612e7a836001600160a01b0384167f000000000000000000000000000000000000000000000000000000000000000061420a565b80831080612eb4575b612e90575b5050506126fc565b612ea6612eac93612ea08b611344565b926137b1565b91614356565b5f8080612e88565b50306001600160a01b03612ec78b611344565b161415612e83565b9450908094808210612ee8575b505050612bab906126fc565b91612ef8602092612f77946137b1565b90612f2d826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683614356565b60405193849283927f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f157612fb8575b8080612edc565b602090813d8311612fdc575b612fce8183611152565b810103126102fc575f612fb1565b503d612fc4565b6020919450612ffb903d805f833e611f248183611152565b509094919050612e29565b61300f90611106565b5f612d86565b9093506020813d602011613041575b8161303160209383611152565b810103126102fc5751925f612cbc565b3d9150613024565b909261305489611344565b6001600160a01b033091160361306f575b5f612dec94612d88565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936130a38a611344565b6130ac846142fd565b90863b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152306024820152918116604483015285166064820152945f908690608490829084905af19081156102f157612dec955f92613128575b50945050613065565b61313190611106565b5f61311f565b6001600160a01b036020849695940151168a8282145f1461340b5750505061320c61316e5f92846001600160a01b03885116614223565b92906131d48c6001600160a01b03808a5116938951151586146133df576131a361319784611344565b935b60808101906118d9565b929093604051966131b3886110ea565b875216602086015260408501528c6060850152600260808501523691611381565b60a0820152604051809381927f4af29ec4000000000000000000000000000000000000000000000000000000008352600483016138f8565b0381836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19081156102f1575f916133c4575b5060208401518c908a90156133aa5783836001600160a01b03936132836132899461327c8f9c9b9a98996132b29a611691565b5192611691565b52611691565b5191167f000000000000000000000000000000000000000000000000000000000000000061420a565b51156132f457612bab92916001600160a01b036020612ba6930151167f0000000000000000000000000000000000000000000000000000000000000000614341565b516040517f15afd4090000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024810191909152602081806044810103815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af180156102f15761337f575b50612bab906126fc565b602090813d83116133a3575b6133958183611152565b810103126102fc575f613375565b503d61338b565b50509091506133bb92939650611691565b519384916132b2565b6133d891503d805f833e61239c8183611152565b9050613249565b6131a3827f00000000000000000000000000000000000000000000000000000000000000001693613199565b61349e965090613466916060948b61342b608099989993848101906118d9565b9390946040519761343b89611136565b6001895260208901526001600160a01b038b1660408901528888015286015260a08501523691611381565b60c0820152604051809581927f2bfb780c00000000000000000000000000000000000000000000000000000000835260048301613810565b03815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af19283156102f15787918b915f9561352d575b506020015115612bb057612ba69284613505612bab9796946001600160a01b0394611691565b52167f000000000000000000000000000000000000000000000000000000000000000061420a565b602091955061354a9060603d606011611ce057611ccd8183611152565b50959190506134df565b6fffffffffffffffffffffffffffffffff6001600160a01b0360206135858188015161357f886126eb565b90611691565b51015116916129fc565b6135cc856001600160a01b0360208401611c67828251167f00000000000000000000000000000000000000000000000000000000000000006141c0565b6129e0565b50506135fc7f0000000000000000000000000000000000000000000000000000000000000000613a71565b9161360783516119d0565b7f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091905f5b86518110156126ba576001906001600160a01b038061366d838b611691565b51165f528560205261368860405f205c8261267e858d611691565b6136928387611691565b5261369d828a611691565b51165f52856020525f604081205d0161364e565b4780156136f0577f00000000000000000000000000000000000000000000000000000000000000005c6136f0576001600160a01b0361184c92166140e0565b5050565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102fc570180359067ffffffffffffffff82116102fc57602001918160051b360383136102fc57565b91908110156116a55760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81813603018212156102fc570190565b604051906040820182811067ffffffffffffffff8211176110bd576040525f6020838281520152565b91908203918211611a0e57565b600211156137c857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b908160609103126102fc578051916040602083015192015190565b61010060c0610f7c93602084528051613828816137be565b602085015260208101516001600160a01b0380911660408601528060408301511660608601526060820151166080850152608081015160a085015260a08101518285015201519160e0808201520190610ffb565b90916060828403126102fc5781519167ffffffffffffffff928381116102fc57846138a8918301611573565b9360208201519360408301519081116102fc57610f7c9201611507565b9081518082526020808093019301915f5b8281106138e4575050505090565b8351855293810193928101926001016138d6565b602081526001600160a01b038083511660208301526020830151166040820152613931604083015160c0606084015260e08301906138c5565b9060608301516080820152608083015160058110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b916060838303126102fc5782519260208101519267ffffffffffffffff938481116102fc578161399a918401611573565b9360408301519081116102fc57610f7c9201611507565b602081526001600160a01b038083511660208301526020830151166040820152604082015160608201526139f4606083015160c0608084015260e08301906138c5565b90608083015160048110156137c857610f7c9360a0918284015201519060c0601f1982850301910152610ffb565b91909160808060a08301948051613a38816137be565b84526020810151613a48816137be565b60208501526001600160a01b036040820151166040850152606081015160608501520151910152565b90815c613a7d81611175565b613a8a6040519182611152565b818152613a9682611175565b601f196020910136602084013781945f5b848110613ab5575050505050565b600190825f5280845f20015c6001600160a01b03613ad38388611691565b9116905201613aa7565b919280613dd8575b15613c51575050804710613c29576001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001691823b156102fc57604051907fd0e30db00000000000000000000000000000000000000000000000000000000082525f915f8160048185895af180156102f157613c12575b506044602092937f00000000000000000000000000000000000000000000000000000000000000001694613b98838783614356565b8460405196879485937f15afd409000000000000000000000000000000000000000000000000000000008552600485015260248401525af1908115613c065750613bdf5750565b602090813d8311613bff575b613bf58183611152565b810103126102fc57565b503d613beb565b604051903d90823e3d90fd5b60209250613c1f90611106565b60445f9250613b63565b7fa01a9df6000000000000000000000000000000000000000000000000000000005f5260045ffd5b90915f9080613c61575b50505050565b6001600160a01b0393847f00000000000000000000000000000000000000000000000000000000000000001694807f00000000000000000000000000000000000000000000000000000000000000001691613cbb846142fd565b96803b156102fc576040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152848316602482015297821660448901529186161660648701525f908690608490829084905af19485156102f157613d8095613dc4575b5082936020936040518097819582947f15afd40900000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1908115613c065750613d99575b808080613c5b565b602090813d8311613dbd575b613daf8183611152565b810103126102fc575f613d91565b503d613da5565b60209350613dd190611106565b5f92613d2f565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690821614613ae5565b6001810191805f5260209183835260405f205c8015155f14613ea7575f1990818101835c8380820191828403613e6a575b5050505050815c81810192818411611a0e575f93815d835284832001015d5f52525f604081205d600190565b613e77613e87938861443a565b865f52885f2001015c918561443a565b835f52808383885f2001015d5f5285855260405f205d5f80808381613e3e565b50505050505f90565b5f949383156140d857806140a3575b15614007576001600160a01b0391827f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03929092166004830152306024830152604482018590525f908290606490829084905af180156102f157613ff4575b5084827f000000000000000000000000000000000000000000000000000000000000000016803b15613ff05781906024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015613fe557613fcd575b5061184c939450166140e0565b613fd78691611106565b613fe15784613fc0565b8480fd5b6040513d88823e3d90fd5b5080fd5b613fff919550611106565b5f935f613f53565b929350906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102fc576040517fae6393290000000000000000000000000000000000000000000000000000000081526001600160a01b03938416600482015293909216602484015260448301525f908290606490829084905af180156102f15761409a5750565b61184c90611106565b506001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690831614613ebf565b505050509050565b814710614130575f8080936001600160a01b038294165af1614100612877565b501561410857565b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fcd786059000000000000000000000000000000000000000000000000000000005f523060045260245ffd5b90614171575080511561410857805190602001fd5b815115806141b7575b614182575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561417a565b6001810190825f528160205260405f205c155f1461420357805c815f52838160205f20015d60018101809111611a0e57815d5c915f5260205260405f205d600190565b5050505f90565b905f5260205261421f60405f2091825c611a01565b905d565b916044929391936001600160a01b03604094859282808551998a9586947fc9c1661b0000000000000000000000000000000000000000000000000000000086521660048501521660248301527f0000000000000000000000000000000000000000000000000000000000000000165afa9384156142f3575f935f956142bc575b50506142b96142b285946119d0565b9485611691565b52565b809295508194503d83116142ec575b6142d58183611152565b810103126102fc5760208251920151925f806142a3565b503d6142cb565b83513d5f823e3d90fd5b6001600160a01b0390818111614311571690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f5260a060045260245260445ffd5b905f5260205261421f60405f2091825c6137b1565b6040519260208401907fa9059cbb0000000000000000000000000000000000000000000000000000000082526001600160a01b038094166024860152604485015260448452608084019084821067ffffffffffffffff8311176110bd576143d5935f9384936040521694519082865af16143ce612877565b908361415c565b8051908115159182614416575b50506143eb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126102fc57602001518015908115036102fc575f806143e2565b5c111561444357565b7f0f4ae0e4000000000000000000000000000000000000000000000000000000005f5260045ffdfea2646970667358221220229a5cf89aa7c2d0a4b4d5db20bba6c2b3a74b080303fc6ec00ba582a5dcf75164736f6c634300081a0033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R`\x046\x10\x15a\0rW[6\x15a\0\x18W_\x80\xFD[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x163\x03a\0JW\0[\x7F\x05@\xDD\xF6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[_5`\xE0\x1C\x80c\x08\xA4e\xF6\x14a\x0E\x9DW\x80c\x19\xC6\x98\x9F\x14a\x08NW\x80c(oX\r\x14a\x07\xB7W\x80c)P(n\x14a\x06\xCCW\x80cT\xFDMP\x14a\x05\x8FW\x80cZ<9\x87\x14a\x05fW\x80c^\x01\xEBZ\x14a\x05!W\x80c\x8A\x12\xA0\x8C\x14a\x04\xC6W\x80c\x8E\xB1\xB6^\x14a\x03\xBFW\x80c\x94^\xD3?\x14a\x03DW\x80c\xAC\x96P\xD8\x14a\x03\0Wc\xE3\xB5\xDF\xF4\x03a\0\x0EW4a\x02\xFCW``\x80`\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x81\x81\x11a\x02\xFCWa\x01-\x906\x90`\x04\x01a\x12\xC4V[a\x015a\x11\xA1V[`D5\x92\x83\x11a\x02\xFCWa\x01Pa\x01X\x936\x90`\x04\x01a\x0F\xCDV[\x93\x90\x91a(\xB9V[\x90_[\x83Q\x81\x10\x15a\x01|W\x80_\x87a\x01s`\x01\x94\x88a\x16\x91V[Q\x01R\x01a\x01[V[Pa\x01\xF0a\x01\xFEa\x029\x94a\x01\xB6_\x94\x88`@Q\x93a\x01\x9A\x85a\x11\x1AV[0\x85R` \x85\x01R_\x19`@\x85\x01R\x86``\x85\x01R6\x91a\x13\x81V[`\x80\x82\x01R`@Q\x92\x83\x91\x7F\x8A\x12\xA0\x8C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x84\x01R`$\x83\x01a\x14>V[\x03`\x1F\x19\x81\x01\x83R\x82a\x11RV[`@Q\x80\x94\x81\x92\x7F\xED\xFA5h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R` `\x04\x84\x01R`$\x83\x01\x90a\x0F\xFBV[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x91\x82\x15a\x02\xF1Wa\x02\xA3\x92a\x02\x8E\x91_\x91a\x02\xCFW[P` \x80\x82Q\x83\x01\x01\x91\x01a\x15\xD4V[\x90\x93\x91\x92a\x02\xA7W[`@Q\x93\x84\x93\x84a\x0F/V[\x03\x90\xF3[_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0]a\x02\x97V[a\x02\xEB\x91P=\x80_\x83>a\x02\xE3\x81\x83a\x11RV[\x81\x01\x90a\x15MV[\x84a\x02~V[`@Q=_\x82>=\x90\xFD[_\x80\xFD[` `\x03\x196\x01\x12a\x02\xFCW`\x045g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\x038a\x032a\x02\xA3\x926\x90`\x04\x01a\x0F\x9CV[\x90a\x17\x9BV[`@Q\x91\x82\x91\x82a\x10 V[4a\x02\xFCWa\x03R6a\x0E\xCAV[a\x03Za\x19EV[a\x03ba\x19rV[a\x03\x90a\x02\xA3a\x03q\x83a(\xFBV[\x91\x93\x90\x94a\x03\x8A``a\x03\x83\x83a\x13DV[\x92\x01a\x13XV[\x90a')V[_\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0]`@Q\x93\x84\x93\x84a\x0F/V[`\x80`\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x81\x81\x11a\x02\xFCWa\x03\xEC\x906\x90`\x04\x01a\x12\xC4V[\x90a\x03\xF5a\x11\xB7V[\x90`d5\x90\x81\x11a\x02\xFCWa\x01\xF0a\x04\x8Ba\x029\x94a\x04Qa\x04\x1C_\x956\x90`\x04\x01a\x0F\xCDV[a\x04%3a(\xB9V[\x97`@Q\x94a\x043\x86a\x11\x1AV[3\x86R` \x86\x01R`$5`@\x86\x01R\x15\x15``\x85\x01R6\x91a\x13\x81V[`\x80\x82\x01R`@Q\x92\x83\x91\x7F\x94^\xD3?\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x84\x01R`$\x83\x01a\x16\xD2V[`@Q\x80\x94\x81\x92\x7FH\xC8\x94\x91\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R` `\x04\x84\x01R`$\x83\x01\x90a\x0F\xFBV[4a\x02\xFCWa\x02\xA3a\x04\xEFa\x04\xDA6a\x0E\xCAV[a\x04\xE2a\x19EV[a\x04\xEAa\x19rV[a\x1A;V[_\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0\x94\x92\x94]`@Q\x93\x84\x93\x84a\x0F/V[4a\x02\xFCW_`\x03\x196\x01\x12a\x02\xFCW` \x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\`\x01`\x01`\xA0\x1B\x03`@Q\x91\x16\x81R\xF3[4a\x02\xFCWa\x02\xA3a\x04\xEFa\x05z6a\x0E\xCAV[a\x05\x82a\x19EV[a\x05\x8Aa\x19rV[a(\xFBV[4a\x02\xFCW_`\x03\x196\x01\x12a\x02\xFCW`@Q_\x80T\x90`\x01\x82`\x01\x1C\x91`\x01\x84\x16\x91\x82\x15a\x06\xC2W[` \x94\x85\x85\x10\x84\x14a\x06\x95W\x85\x87\x94\x86\x86R\x91\x82_\x14a\x06WWPP`\x01\x14a\x05\xFEW[Pa\x05\xEA\x92P\x03\x83a\x11RV[a\x02\xA3`@Q\x92\x82\x84\x93\x84R\x83\x01\x90a\x0F\xFBV[_\x80\x80R\x85\x92P\x90\x7F)\r\xEC\xD9T\x8Bb\xA8\xD6\x03E\xA9\x888o\xC8K\xA6\xBC\x95H@\x08\xF66/\x93\x16\x0E\xF3\xE5c[\x85\x83\x10a\x06?WPPa\x05\xEA\x93P\x82\x01\x01\x85a\x05\xDDV[\x80T\x83\x89\x01\x85\x01R\x87\x94P\x86\x93\x90\x92\x01\x91\x81\x01a\x06(V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x16\x85\x82\x01Ra\x05\xEA\x95\x15\x15`\x05\x1B\x85\x01\x01\x92P\x87\x91Pa\x05\xDD\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\"`\x04R`$_\xFD[\x92`\x7F\x16\x92a\x05\xB9V[4a\x02\xFCW```\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x81\x81\x11a\x02\xFCWa\x06\xFE\x906\x90`\x04\x01a\x12\xC4V[\x90a\x07\x07a\x11\xA1V[`D5\x91\x82\x11a\x02\xFCWa\x07\"a\x07*\x926\x90`\x04\x01a\x0F\xCDV[\x92\x90\x91a(\xB9V[\x90_[\x84Q\x81\x10\x15a\x07_W\x80o\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`@a\x07V`\x01\x94\x89a\x16\x91V[Q\x01R\x01a\x07-V[Pa\x01\xF0a\x01\xFE\x85a\x07}_\x94a\x029\x97`@Q\x93a\x01\x9A\x85a\x11\x1AV[`\x80\x82\x01R`@Q\x92\x83\x91\x7FZ<9\x87\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x84\x01R`$\x83\x01a\x16\xD2V[`\x80`\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x81\x81\x11a\x02\xFCWa\x07\xE4\x906\x90`\x04\x01a\x12\xC4V[\x90a\x07\xEDa\x11\xB7V[\x90`d5\x90\x81\x11a\x02\xFCWa\x01\xF0a\x04\x8Ba\x029\x94a\x08\x14a\x04\x1C_\x956\x90`\x04\x01a\x0F\xCDV[`\x80\x82\x01R`@Q\x92\x83\x91\x7F\x08\xA4e\xF6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x84\x01R`$\x83\x01a\x14>V[`\xA0`\x03\x196\x01\x12a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045\x11a\x02\xFCW6`#`\x045\x01\x12\x15a\x02\xFCWg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x045`\x04\x015\x11a\x02\xFCW6`$`\xC0`\x045`\x04\x015\x02`\x045\x01\x01\x11a\x02\xFCW`$5g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\x08\xC4\x906\x90`\x04\x01a\x0F\x9CV[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`D5\x11a\x02\xFCW```\x03\x19`D56\x03\x01\x12a\x02\xFCW`d5g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\t\x05\x906\x90`\x04\x01a\x0F\xCDV[`\x845g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\t%\x906\x90`\x04\x01a\x0F\x9CV[\x94\x90\x93a\t0a\x19EV[\x80`\x045`\x04\x015\x03a\x0EuW_[`\x045`\x04\x015\x81\x10a\x0B\xD2WPPP`D5`\x04\x015\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDD`D56\x03\x01\x82\x12\x15a\x02\xFCW\x81`D5\x01`\x04\x81\x015\x90g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11a\x02\xFCW`$\x82`\x07\x1B6\x03\x91\x01\x13a\x02\xFCWa\t\xE3W[a\x02\xA3a\x038\x86\x86_\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0]a\x17\x9BV[`\x01`\x01`\xA0\x1B\x03\x94\x92\x94\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16;\x15a\x02\xFCW`@Q\x94\x7F*-\x80\xD1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86R3`\x04\x87\x01R```$\x87\x01R`\xC4\x86\x01\x92`D5\x01`$\x81\x01\x93g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x04\x83\x015\x11a\x02\xFCW`\x04\x82\x015`\x07\x1B6\x03\x85\x13a\x02\xFCW```d\x89\x01R`\x04\x82\x015\x90R\x91\x92\x86\x92`\xE4\x84\x01\x92\x91\x90_\x90[`\x04\x81\x015\x82\x10a\x0BTWPPP` \x91`\x1F\x19`\x1F\x86_\x97\x87\x95`\x01`\x01`\xA0\x1B\x03a\n\xC8`$`D5\x01a\x11\x8DV[\x16`\x84\x88\x01R`D\x805\x015`\xA4\x88\x01R`\x03\x19\x87\x87\x03\x01`D\x88\x01R\x81\x86R\x87\x86\x017\x87\x86\x82\x86\x01\x01R\x01\x16\x01\x03\x01\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x91\x82\x15a\x02\xF1Wa\x02\xA3\x93a\x038\x93a\x0BEW[\x82\x94P\x81\x93Pa\t\xB3V[a\x0BN\x90a\x11\x06V[\x84a\x0B:V[\x91\x95\x94P\x91\x92`\x01`\x01`\xA0\x1B\x03a\x0Bk\x87a\x11\x8DV[\x16\x81R` \x80\x87\x015\x91`\x01`\x01`\xA0\x1B\x03\x83\x16\x80\x93\x03a\x02\xFCW`\x04\x92`\x01\x92\x82\x01Ra\x0B\x9B`@\x89\x01a(\xA6V[e\xFF\xFF\xFF\xFF\xFF\xFF\x80\x91\x16`@\x83\x01Ra\x0B\xB6``\x8A\x01a(\xA6V[\x16``\x82\x01R`\x80\x80\x91\x01\x97\x01\x93\x01\x90P\x88\x94\x95\x93\x92\x91a\n\x97V[a\x0B\xE7a\x0B\xE0\x82\x84\x86a\x19*V[6\x91a\x13\x81V[`@Qa\x0B\xF3\x81a\x10\xA1V[_\x81R` \x91_\x83\x83\x01R_`@\x83\x01R\x82\x81\x01Q\x90```@\x82\x01Q\x91\x01Q_\x1A\x91\x83R\x83\x83\x01R`@\x82\x01R`\xC0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDC\x81\x85\x02`\x045\x016\x03\x01\x12a\x02\xFCW`@Q\x90a\x0C`\x82a\x10\xEAV[a\x0Cs`$`\xC0\x86\x02`\x045\x01\x01a\x11\x8DV[\x80\x83Ra\x0C\x89`D`\xC0\x87\x02`\x045\x01\x01a\x11\x8DV[\x90\x81\x85\x85\x01Ra\x0C\xA2`d`\xC0\x88\x02`\x045\x01\x01a\x11\x8DV[`@\x85\x81\x01\x91\x90\x91R`\x045`\xC0\x88\x02\x01`\x84\x81\x015``\x87\x01R`\xA4\x81\x015`\x80\x87\x01R`\xC4\x015`\xA0\x86\x01R\x83\x01Q\x83Q\x93\x86\x01Q`\xFF\x91\x90\x91\x16\x92`\x01`\x01`\xA0\x1B\x03\x83\x16;\x15a\x02\xFCW_`\x01`\x01`\xA0\x1B\x03\x80\x94`\xE4\x94\x8B\x98\x84\x98`\xC4`\xC0`@Q\x9C\x8D\x9B\x8C\x9A\x7F\xD5\x05\xAC\xCF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8CR\x16`\x04\x8B\x01R0`$\x8B\x01R`\x84\x82\x82\x02`\x045\x01\x015`D\x8B\x01R\x02`\x045\x01\x015`d\x88\x01R`\x84\x87\x01R`\xA4\x86\x01R`\xC4\x85\x01R\x16Z\xF1\x90\x81a\x0EfW[Pa\x0E\\Wa\r\x7Fa(wV[\x90`\x01`\x01`\xA0\x1B\x03\x81Q\x16\x90\x83`\x01`\x01`\xA0\x1B\x03\x81\x83\x01Q\x16`D`@Q\x80\x95\x81\x93\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01R0`$\x83\x01RZ\xFA\x91\x82\x15a\x02\xF1W_\x92a\x0E,W[P``\x01Q\x03a\r\xF7WPP`\x01\x90[\x01a\t?V[\x80Q\x15a\x0E\x04W\x80Q\x91\x01\xFD[\x7F\xA7(V\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x90\x91P\x83\x81\x81=\x83\x11a\x0EUW[a\x0ED\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCWQ\x90``a\r\xE1V[P=a\x0E:V[PP`\x01\x90a\r\xF1V[a\x0Eo\x90a\x11\x06V[\x8Aa\rrV[\x7F\xAA\xAD\x13\xF7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[4a\x02\xFCWa\x0E\xAB6a\x0E\xCAV[a\x0E\xB3a\x19EV[a\x0E\xBBa\x19rV[a\x03\x90a\x02\xA3a\x03q\x83a\x1A;V[`\x03\x19\x90` \x82\x82\x01\x12a\x02\xFCW`\x045\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11a\x02\xFCW\x82`\xA0\x92\x03\x01\x12a\x02\xFCW`\x04\x01\x90V[\x90\x81Q\x80\x82R` \x80\x80\x93\x01\x93\x01\x91_[\x82\x81\x10a\x0F\x1BWPPPP\x90V[\x83Q\x85R\x93\x81\x01\x93\x92\x81\x01\x92`\x01\x01a\x0F\rV[\x93\x92\x90a\x0FD\x90``\x86R``\x86\x01\x90a\x0E\xFCV[\x93` \x94\x81\x81\x03` \x83\x01R` \x80\x85Q\x92\x83\x81R\x01\x94\x01\x90_[\x81\x81\x10a\x0F\x7FWPPPa\x0F|\x93\x94P`@\x81\x84\x03\x91\x01Ra\x0E\xFCV[\x90V[\x82Q`\x01`\x01`\xA0\x1B\x03\x16\x86R\x94\x87\x01\x94\x91\x87\x01\x91`\x01\x01a\x0F_V[\x91\x81`\x1F\x84\x01\x12\x15a\x02\xFCW\x825\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11a\x02\xFCW` \x80\x85\x01\x94\x84`\x05\x1B\x01\x01\x11a\x02\xFCWV[\x91\x81`\x1F\x84\x01\x12\x15a\x02\xFCW\x825\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11a\x02\xFCW` \x83\x81\x86\x01\x95\x01\x01\x11a\x02\xFCWV[\x90`\x1F\x19`\x1F` \x80\x94\x80Q\x91\x82\x91\x82\x87R\x01\x86\x86\x01^_\x85\x82\x86\x01\x01R\x01\x16\x01\x01\x90V[` \x80\x82\x01\x90` \x83R\x83Q\x80\x92R`@\x83\x01\x92` `@\x84`\x05\x1B\x83\x01\x01\x95\x01\x93_\x91[\x84\x83\x10a\x10UWPPPPPP\x90V[\x90\x91\x92\x93\x94\x95\x84\x80a\x10\x91\x83\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC0\x86`\x01\x96\x03\x01\x87R\x8AQa\x0F\xFBV[\x98\x01\x93\x01\x93\x01\x91\x94\x93\x92\x90a\x10EV[``\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`\xC0\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x10\xBDW`@RV[`\xA0\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[`\xE0\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[\x90`\x1F`\x1F\x19\x91\x01\x16\x81\x01\x90\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@RV[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x10\xBDW`\x05\x1B` \x01\x90V[5\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x82\x03a\x02\xFCWV[`$5\x90`\x01`\x01`\xA0\x1B\x03\x82\x16\x82\x03a\x02\xFCWV[`D5\x90\x81\x15\x15\x82\x03a\x02\xFCWV[\x91\x90\x91`\x80\x81\x84\x03\x12a\x02\xFCW`@\x90\x81Q\x91`\x80\x83\x01\x94g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x95\x84\x81\x10\x87\x82\x11\x17a\x10\xBDW\x82R\x83\x95a\x12\0\x84a\x11\x8DV[\x85R` \x90\x81\x85\x015\x90\x81\x11a\x02\xFCW\x84\x01\x82`\x1F\x82\x01\x12\x15a\x02\xFCW\x805\x90a\x12)\x82a\x11uV[\x93a\x126\x86Q\x95\x86a\x11RV[\x82\x85R\x83\x85\x01\x90\x84``\x80\x95\x02\x84\x01\x01\x92\x81\x84\x11a\x02\xFCW\x85\x01\x91[\x83\x83\x10a\x12tWPPPPP\x84\x01R\x81\x81\x015\x90\x83\x01R``\x90\x81\x015\x91\x01RV[\x84\x83\x83\x03\x12a\x02\xFCW\x87Q\x90a\x12\x89\x82a\x10\xA1V[a\x12\x92\x84a\x11\x8DV[\x82Ra\x12\x9F\x87\x85\x01a\x11\x8DV[\x87\x83\x01R\x88\x84\x015\x90\x81\x15\x15\x82\x03a\x02\xFCW\x82\x88\x92\x8B\x89\x95\x01R\x81R\x01\x92\x01\x91a\x12RV[\x81`\x1F\x82\x01\x12\x15a\x02\xFCW\x805\x91` \x91a\x12\xDE\x84a\x11uV[\x93a\x12\xEC`@Q\x95\x86a\x11RV[\x80\x85R\x83\x80\x86\x01\x91`\x05\x1B\x83\x01\x01\x92\x80\x84\x11a\x02\xFCW\x84\x83\x01\x91[\x84\x83\x10a\x13\x17WPPPPPP\x90V[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCW\x86\x91a\x139\x84\x84\x80\x94\x89\x01\x01a\x11\xC6V[\x81R\x01\x92\x01\x91a\x13\x07V[5`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x03a\x02\xFCW\x90V[5\x80\x15\x15\x81\x03a\x02\xFCW\x90V[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x10\xBDW`\x1F\x01`\x1F\x19\x16` \x01\x90V[\x92\x91\x92a\x13\x8D\x82a\x13eV[\x91a\x13\x9B`@Q\x93\x84a\x11RV[\x82\x94\x81\x84R\x81\x83\x01\x11a\x02\xFCW\x82\x81` \x93\x84_\x96\x017\x01\x01RV[\x90`\x80\x81\x01\x91`\x01`\x01`\xA0\x1B\x03\x80\x82Q\x16\x83R` \x93\x84\x83\x01Q\x94`\x80\x81\x86\x01R\x85Q\x80\x92R\x80`\xA0\x86\x01\x96\x01\x92_\x90[\x83\x82\x10a\x14\x0BWPPPPP``\x81`@\x82\x93\x01Q`@\x85\x01R\x01Q\x91\x01R\x90V[\x84Q\x80Q\x82\x16\x89R\x80\x84\x01Q\x82\x16\x89\x85\x01R`@\x90\x81\x01Q\x15\x15\x90\x89\x01R``\x90\x97\x01\x96\x93\x82\x01\x93`\x01\x90\x91\x01\x90a\x13\xE9V[\x91\x90\x91` \x90\x81\x81R`\xC0\x81\x01\x91`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x81\x83\x01R\x80\x85\x01Q\x92`\xA0`@\x84\x01R\x83Q\x80\x91R`\xE0\x83\x01\x91\x80`\xE0\x83`\x05\x1B\x86\x01\x01\x95\x01\x92_\x90[\x83\x82\x10a\x14\xBDWPPPPP`\x80\x84`@a\x0F|\x95\x96\x01Q``\x84\x01R``\x81\x01Q\x15\x15\x82\x84\x01R\x01Q\x90`\xA0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x90\x91\x92\x93\x95\x83\x80a\x14\xF8\x83\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF \x8A`\x01\x96\x03\x01\x86R\x8AQa\x13\xB7V[\x98\x01\x92\x01\x92\x01\x90\x93\x92\x91a\x14\x81V[\x81`\x1F\x82\x01\x12\x15a\x02\xFCW\x80Q\x90a\x15\x1E\x82a\x13eV[\x92a\x15,`@Q\x94\x85a\x11RV[\x82\x84R` \x83\x83\x01\x01\x11a\x02\xFCW\x81_\x92` \x80\x93\x01\x83\x86\x01^\x83\x01\x01R\x90V[\x90` \x82\x82\x03\x12a\x02\xFCW\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15\x07V[\x90\x80`\x1F\x83\x01\x12\x15a\x02\xFCW\x81Q\x90` \x91a\x15\x8E\x81a\x11uV[\x93a\x15\x9C`@Q\x95\x86a\x11RV[\x81\x85R` \x80\x86\x01\x92`\x05\x1B\x82\x01\x01\x92\x83\x11a\x02\xFCW` \x01\x90[\x82\x82\x10a\x15\xC5WPPPP\x90V[\x81Q\x81R\x90\x83\x01\x90\x83\x01a\x15\xB7V[\x90\x91``\x82\x84\x03\x12a\x02\xFCW\x81Q\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x81\x11a\x02\xFCW\x84a\x16\0\x91\x83\x01a\x15sV[\x93` \x80\x83\x01Q\x85\x81\x11a\x02\xFCW\x83\x01\x90\x82`\x1F\x83\x01\x12\x15a\x02\xFCW\x81Q\x91a\x16(\x83a\x11uV[\x92a\x166`@Q\x94\x85a\x11RV[\x80\x84R\x82\x80\x85\x01\x91`\x05\x1B\x83\x01\x01\x91\x85\x83\x11a\x02\xFCW\x83\x01\x90[\x82\x82\x10a\x16rWPPPP\x93`@\x83\x01Q\x90\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15sV[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x03a\x02\xFCW\x81R\x90\x83\x01\x90\x83\x01a\x16PV[\x80Q\x82\x10\x15a\x16\xA5W` \x91`\x05\x1B\x01\x01\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[\x91\x90\x91` \x90\x81\x81R`\xC0\x81\x01\x91`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x81\x83\x01R\x80\x85\x01Q\x92`\xA0`@\x84\x01R\x83Q\x80\x91R`\xE0\x83\x01\x91\x80`\xE0\x83`\x05\x1B\x86\x01\x01\x95\x01\x92_\x90[\x83\x82\x10a\x17QWPPPPP`\x80\x84`@a\x0F|\x95\x96\x01Q``\x84\x01R``\x81\x01Q\x15\x15\x82\x84\x01R\x01Q\x90`\xA0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x90\x91\x92\x93\x95\x83\x80a\x17\x8C\x83\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF \x8A`\x01\x96\x03\x01\x86R\x8AQa\x13\xB7V[\x98\x01\x92\x01\x92\x01\x90\x93\x92\x91a\x17\x15V[\x91\x90a\x17\xA63a(\xB9V[\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\x84\\a\x18\xB1W`\x01\x90`\x01\x86]a\x17\xDF\x83a\x11uV[\x92a\x17\xED`@Q\x94\x85a\x11RV[\x80\x84R`\x1F\x19a\x17\xFC\x82a\x11uV[\x01_[\x81\x81\x10a\x18\xA0WPP_[\x81\x81\x10a\x18WWPPPP\x90_a\x18L\x92\x94]\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\\\x91a\x18NW[Pa6\xB1V[V[_\x90]_a\x18FV[\x80a\x18\x84_\x80a\x18la\x0B\xE0\x89\x96\x88\x8Aa\x19*V[` \x81Q\x91\x010Z\xF4a\x18}a(wV[\x900aA\\V[a\x18\x8E\x82\x88a\x16\x91V[Ra\x18\x99\x81\x87a\x16\x91V[P\x01a\x18\nV[\x80``` \x80\x93\x89\x01\x01R\x01a\x17\xFFV[\x7F>\xE5\xAE\xB5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x905\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x816\x03\x01\x82\x12\x15a\x02\xFCW\x01\x805\x90g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11a\x02\xFCW` \x01\x91\x816\x03\x83\x13a\x02\xFCWV[\x90\x82\x10\x15a\x16\xA5Wa\x19A\x91`\x05\x1B\x81\x01\x90a\x18\xD9V[\x90\x91V[\x7F\x9Bw\x9B\x17B-\r\xF9\"#\x01\x8B2\xB4\xD1\xFAF\xE0qr=h\x17\xE2Hm\0;\xEC\xC5_\0\x80\\a\x18\xB1W`\x01\x90]V[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x163\x03a\x19\xA4WV[\x7F\x08\x96v\xD5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R3`\x04R`$_\xFD[\x90a\x19\xDA\x82a\x11uV[a\x19\xE7`@Q\x91\x82a\x11RV[\x82\x81R`\x1F\x19a\x19\xF7\x82\x94a\x11uV[\x01\x90` 6\x91\x017V[\x91\x90\x82\x01\x80\x92\x11a\x1A\x0EWV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[`@\x81\x015B\x11a&\xC3W\x90a\x1A^a\x1AW` \x84\x01\x84a6\xF4V[\x90Pa\x19\xD0V[\x91_[a\x1An` \x83\x01\x83a6\xF4V[\x90P\x81\x10\x15a%\xC7Wa\x1A\x98\x81a\x1A\x93a\x1A\x8B` \x86\x01\x86a6\xF4V[6\x93\x91a7HV[a\x11\xC6V[\x93`@\x85\x01Q\x93`\x01`\x01`\xA0\x1B\x03\x86Q\x16\x90` \x87\x01Q\x80Q\x15a\x16\xA5W` \x01Q`@\x01Q\x15\x15\x80a%\xBEW[\x15a%cWa\x1A\xECa\x1A\xD8\x86a\x13DV[\x87\x84a\x1A\xE6``\x8A\x01a\x13XV[\x92a:\xDDV[_[` \x88\x01QQ\x81\x10\x15a%SWa\x1B\x03a7\x88V[` \x89\x01QQ_\x19\x81\x01\x90\x81\x11a\x1A\x0EW\x82\x14\x80` \x83\x01R\x82\x15\x82R_\x14a%LW``\x89\x01Q\x90[a\x1B;\x83` \x8C\x01Qa\x16\x91V[Q`@\x81\x01Q\x90\x91\x90\x15a\x1C\xEEWa\x1B\xD3`\x01`\x01`\xA0\x1B\x03\x83Q\x16\x93`\x01`\x01`\xA0\x1B\x03\x88\x16\x85\x14_\x14a\x1C\xE7W`\x01\x94[`@Q\x95a\x1B{\x87a\x11\x1AV[_\x87Ra\x1B\x87\x81a7\xBEV[` \x87\x01R`@\x86\x01R``\x94\x85\x91\x8D\x83\x83\x01R`\x80\x82\x01R`@Q\x80\x93\x81\x92\x7FCX;\xE5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a:\"V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x93\x84\x15a\x02\xF1W_\x94a\x1C\xB0W[PP` \x01Q\x15a\x1C\x96W\x81`\x01`\x01`\xA0\x1B\x03` a\x1C\x90\x93`\x01\x96\x95a\x1C8\x8C\x8Ca\x16\x91V[R\x01a\x1Cg\x82\x82Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[PQ\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[\x01a\x1A\xEEV[` \x01Q\x90\x97P`\x01`\x01`\xA0\x1B\x03\x16\x92P`\x01\x90a\x1C\x90V[` \x92\x94P\x90\x81a\x1C\xD5\x92\x90=\x10a\x1C\xE0W[a\x1C\xCD\x81\x83a\x11RV[\x81\x01\x90a7\xF5V[\x91PP\x92\x90_a\x1C\x10V[P=a\x1C\xC3V[_\x94a\x1BnV[\x88\x8A`\x01`\x01`\xA0\x1B\x03\x84\x95\x94Q\x16\x80`\x01`\x01`\xA0\x1B\x03\x8A\x16\x14_\x14a!2WPP\x81Q\x15\x90Pa nW\x88\x8A\x80\x15\x15\x80a SW[a\x1FMW[`\x01`\x01`\xA0\x1B\x03\x93\x92\x91a\x1D\xDD\x82a\x1E\x15\x97\x8B_\x95\x89\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92\x16\x80\x88R\x82` R`@\x88 \\a\x1Fa\x1F$\x81\x83a\x11RV[\x81\x01\x90a9iV[P\x94\x91\x90Pa\x1ERV[\x91aB#V[a\x1FE\x92aCAV[_\x82\x81a\x1DuV[Pa\x1FZ\x90\x92\x91\x92a\x13DV[\x91a\x1Fd\x8BaB\xFDV[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16;\x15a\x02\xFCW`@Q\x7F6\xC7\x85\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x94\x85\x16`\x04\x82\x01R0`$\x82\x01R\x90\x84\x16`D\x82\x01R\x92\x87\x16`d\x84\x01R_\x83\x80`\x84\x81\x01\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1W\x8Aa\x1D\xDD\x8Da\x1E\x15\x97`\x01`\x01`\xA0\x1B\x03\x97_\x95a DW[P\x97P\x92PP\x91\x92\x93Pa\x1D*V[a M\x90a\x11\x06V[_a 5V[Pa ]\x82a\x13DV[`\x01`\x01`\xA0\x1B\x03\x160\x14\x15a\x1D%V[\x90`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x91`\x01`\x01`\xA0\x1B\x03\x84Q\x16\x92\x80;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x94\x90\x94\x16`\x04\x85\x01R0`$\x85\x01R`D\x84\x01\x8C\x90R_\x90\x84\x90`d\x90\x82\x90\x84\x90Z\xF1\x80\x15a\x02\xF1W\x8Aa\x1D\xDD\x8Da\x1E\x15\x97`\x01`\x01`\xA0\x1B\x03\x97_\x95a!#W[Pa\x1DyV[a!,\x90a\x11\x06V[_a!\x1DV[`\x01`\x01`\xA0\x1B\x03` \x87\x96\x94\x97\x01Q\x16\x90\x89\x81\x83\x14_\x14a#\xD7Wa!\xCD\x92Pa\"\x05\x97\x91P`\x01a!s_\x96\x95`\x01`\x01`\xA0\x1B\x03\x93\x84\x8BQ\x16aB#V[P\x92\x82\x89Q\x16\x95` \x89\x01Q\x15\x15\x88\x14a#\xAEWa!\x90\x82a\x13DV[\x94[a!\xA1`\x80\x93\x84\x81\x01\x90a\x18\xD9V[\x95\x90\x96`@Q\x99a!\xB1\x8Ba\x10\xEAV[\x8AR\x16` \x89\x01R`@\x88\x01R``\x87\x01R\x85\x01R6\x91a\x13\x81V[`\xA0\x82\x01R`@Q\x80\x95\x81\x92\x7FJ\xF2\x9E\xC4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\xF8V[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x92\x83\x15a\x02\xF1W_\x93a#\x84W[P` \x01Q\x15a\"\xC3W\x81`\x01`\x01`\xA0\x1B\x03` a\x1E\xE4\x93`\x01\x96\x95a\"i\x8C\x8Ca\x16\x91V[Ra\"\x99\x83\x83\x83\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[` \x81\x81\x01Q\x91Q`@Q\x7F\x15\xAF\xD4\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\x04\x82\x01R`$\x81\x01\x85\x90R\x93\x9AP\x90\x91\x16\x94P\x81\x80`D\x81\x01\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1Wa#YW[P`\x01\x90a\x1C\x90V[` \x90\x81=\x83\x11a#}W[a#o\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW_a#PV[P=a#eV[` \x91\x93Pa#\xA4\x90=\x80_\x83>a#\x9C\x81\x83a\x11RV[\x81\x01\x90a8|V[P\x93\x91\x90Pa\"BV[\x83\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x94a!\x92V[`\x01`\x01`\xA0\x1B\x03a$f\x95a$.\x93\x94\x95a#\xF8`\x80\x9B\x8C\x81\x01\x90a\x18\xD9V[\x93\x90\x94`@Q\x97a$\x08\x89a\x116V[_\x89R` \x89\x01R\x16`@\x87\x01R``\x9A\x8B\x97\x88\x88\x01R\x86\x01R`\xA0\x85\x01R6\x91a\x13\x81V[`\xC0\x82\x01R`@Q\x80\x93\x81\x92\x7F+\xFBx\x0C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\x10V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x93\x84\x15a\x02\xF1W_\x94a%%W[PP` \x01Q\x15a\x1C\x96W\x81`\x01`\x01`\xA0\x1B\x03` a\x1E\xE4\x93`\x01\x96\x95a$\xCB\x8C\x8Ca\x16\x91V[Ra$\xFB\x83\x83\x83\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[` \x92\x94P\x90\x81a%A\x92\x90=\x10a\x1C\xE0Wa\x1C\xCD\x81\x83a\x11RV[\x91PP\x92\x90_a$\xA3V[_\x90a\x1B-V[P\x91\x95P\x90\x93PP`\x01\x01a\x1AaV[a%\x8D\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[Pa%\xB9\x86\x83\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[a\x1A\xECV[P2\x15\x15a\x1A\xC7V[PPa%\xF2\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a:qV[\x91a%\xFD\x83Qa\x19\xD0V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x90_[\x86Q\x81\x10\x15a&\xBAW`\x01\x90`\x01`\x01`\xA0\x1B\x03\x80a&c\x83\x8Ba\x16\x91V[Q\x16_R\x85` Ra&\x91`@_ \\\x82a&~\x85\x8Da\x16\x91V[Q\x16_R\x88` R`@_ \\\x90a\x1A\x01V[a&\x9B\x83\x87a\x16\x91V[Ra&\xA6\x82\x8Aa\x16\x91V[Q\x16_R\x85` R_`@\x81 ]\x01a&DV[P\x94\x93\x91P\x91PV[\x7F\xE0\x8B\x8A\xF0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x90_\x19\x82\x01\x91\x82\x13`\x01\x16a\x1A\x0EWV[\x7F\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x14a\x1A\x0EW_\x19\x01\x90V[\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x81\\\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a'y\x81\\a&\xEBV[\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91[_\x81\x12\x15a(:WPPPa'\xB1\x90a&\xEBV[\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92[_\x81\x12\x15a'\xEAWPPPPa\x18L\x90a6\xB1V[a(5\x90\x82_Ra(/` _\x83\x82\x82 \x01\\\x91\x82\x82R\x88\x81R\x88`@\x91a(\"\x8A\x8D\x85\x87 \\\x90`\x01`\x01`\xA0\x1B\x03\x89\x16\x90a>\xB0V[\x84\x84RR\x81 ]\x84a>\rV[Pa&\xFCV[a'\xD5V[a(r\x90\x82_Ra(/` _\x8A\x87\x85\x84\x84 \x01\\\x93\x84\x84R\x81\x81Ra(\"\x8C`@\x94\x85\x87 \\\x90`\x01`\x01`\xA0\x1B\x03\x89\x16\x90a:\xDDV[a'\x9DV[=\x15a(\xA1W=\x90a(\x88\x82a\x13eV[\x91a(\x96`@Q\x93\x84a\x11RV[\x82R=_` \x84\x01>V[``\x90V[5\x90e\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x82\x03a\x02\xFCWV[\x90_\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x81\\\x16\x15a(\xF1WPPV[\x90\x91\x92P]`\x01\x90V[\x90`@\x82\x015B\x11a&\xC3Wa)\x17a\x1AW` \x84\x01\x84a6\xF4V[\x91_[a)'` \x83\x01\x83a6\xF4V[\x90P\x81\x10\x15a5\xD1Wa)D\x81a\x1A\x93a\x1A\x8B` \x86\x01\x86a6\xF4V[``\x81\x01Q\x90a)~`\x01`\x01`\xA0\x1B\x03\x82Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P` \x81\x01QQ_\x19\x81\x01\x90\x81\x11a\x1A\x0EW[_\x81\x12\x15a)\xA4WPPP`\x01\x01a)\x1AV[a)\xB2\x81` \x84\x01Qa\x16\x91V[Qa)\xBBa7\x88V[\x90\x82\x15` \x83\x01R` \x84\x01QQ\x80_\x19\x81\x01\x11a\x1A\x0EW_\x19\x01\x83\x14\x80\x83Ra5\x8FW[` \x82\x01Q\x15a5TW`@\x84\x01Q`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x91[`@\x81\x01Q\x15a,\x1DW\x83\x91`\x01`\x01`\xA0\x1B\x03``\x92` a*\xA0\x97\x01Q\x15\x15\x80a,\x14W[a+\xEDW[Q\x16\x90`\x01`\x01`\xA0\x1B\x03\x85\x16\x82\x03a+\xE6W`\x01\x91[`@Q\x92a*L\x84a\x11\x1AV[`\x01\x84Ra*Y\x81a7\xBEV[` \x84\x01R`@\x83\x01R\x88\x83\x83\x01R`\x80\x82\x01R`@Q\x80\x95\x81\x92\x7FCX;\xE5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a:\"V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x92\x83\x15a\x02\xF1W\x87\x91\x8B\x91_\x95a+\xBFW[P` \x01Q\x15a+\xB0Wa+\xA6\x92\x84a+\x02a+\xAB\x97\x96\x94a+u\x94a\x16\x91V[Ra+6`\x01`\x01`\xA0\x1B\x03\x82\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[P`\x01`\x01`\xA0\x1B\x03a+M\x84`@\x8A\x01Qa7\xB1V[\x91\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[`\x01`\x01`\xA0\x1B\x03\x85Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[a&\xFCV[a)\x91V[PPPa+\xAB\x91\x93P\x92a&\xFCV[` \x91\x95Pa+\xDC\x90``=``\x11a\x1C\xE0Wa\x1C\xCD\x81\x83a\x11RV[P\x95\x91\x90Pa*\xE1V[_\x91a*?V[a,\x0Fa+\xF9\x8Da\x13DV[\x8D\x8Ba\x1A\xE6\x88`@\x88\x84Q\x16\x93\x01Q\x93\x01a\x13XV[a*(V[P2\x15\x15a*#V[\x90`\x01`\x01`\xA0\x1B\x03\x82Q\x16\x80`\x01`\x01`\xA0\x1B\x03\x85\x16\x14_\x14a17WP` \x84\x01Qa0IWP`@Q\x92\x7F\x96xp\x92\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84R`\x01`\x01`\xA0\x1B\x03\x83\x16`\x04\x85\x01R` \x84`$\x81`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xFA\x93\x84\x15a\x02\xF1W_\x94a0\x15W[P\x83\x91`\x01`\x01`\xA0\x1B\x03\x81Q\x16`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R0`$\x82\x01R`D\x81\x01\x95\x90\x95R_\x85\x80`d\x81\x01\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x90\x81\x15a\x02\xF1Wa-\xEC\x95_\x92a0\x06W[P[a\x1D\xDD`\x01`\x01`\xA0\x1B\x03a-\xA8\x8B\x82\x85Q\x16\x83` \x87\x01Q\x16\x90aB#V[P\x92Q\x16\x91\x8C`\x02a-\xBF`\x80\x92\x83\x81\x01\x90a\x18\xD9V[\x92\x90\x93`@Q\x96a-\xCF\x88a\x10\xEAV[\x87R0` \x88\x01R\x89`@\x88\x01R``\x87\x01R\x85\x01R6\x91a\x13\x81V[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x93\x84\x15a\x02\xF1W_\x94a/\xE3W[P` \x01Q\x15a.\xCFW\x90\x82\x91a+\xAB\x94\x93a.E\x89\x8Da\x16\x91V[Ra.z\x83`\x01`\x01`\xA0\x1B\x03\x84\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[\x80\x83\x10\x80a.\xB4W[a.\x90W[PPPa&\xFCV[a.\xA6a.\xAC\x93a.\xA0\x8Ba\x13DV[\x92a7\xB1V[\x91aCVV[_\x80\x80a.\x88V[P0`\x01`\x01`\xA0\x1B\x03a.\xC7\x8Ba\x13DV[\x16\x14\x15a.\x83V[\x94P\x90\x80\x94\x80\x82\x10a.\xE8W[PPPa+\xAB\x90a&\xFCV[\x91a.\xF8` \x92a/w\x94a7\xB1V[\x90a/-\x82`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x83aCVV[`@Q\x93\x84\x92\x83\x92\x7F\x15\xAF\xD4\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84R`\x04\x84\x01` \x90\x93\x92\x91\x93`\x01`\x01`\xA0\x1B\x03`@\x82\x01\x95\x16\x81R\x01RV[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1Wa/\xB8W[\x80\x80a.\xDCV[` \x90\x81=\x83\x11a/\xDCW[a/\xCE\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW_a/\xB1V[P=a/\xC4V[` \x91\x94Pa/\xFB\x90=\x80_\x83>a\x1F$\x81\x83a\x11RV[P\x90\x94\x91\x90Pa.)V[a0\x0F\x90a\x11\x06V[_a-\x86V[\x90\x93P` \x81=` \x11a0AW[\x81a01` \x93\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCWQ\x92_a,\xBCV[=\x91Pa0$V[\x90\x92a0T\x89a\x13DV[`\x01`\x01`\xA0\x1B\x030\x91\x16\x03a0oW[_a-\xEC\x94a-\x88V[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x93a0\xA3\x8Aa\x13DV[a0\xAC\x84aB\xFDV[\x90\x86;\x15a\x02\xFCW`@Q\x7F6\xC7\x85\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\x04\x82\x01R0`$\x82\x01R\x91\x81\x16`D\x83\x01R\x85\x16`d\x82\x01R\x94_\x90\x86\x90`\x84\x90\x82\x90\x84\x90Z\xF1\x90\x81\x15a\x02\xF1Wa-\xEC\x95_\x92a1(W[P\x94PPa0eV[a11\x90a\x11\x06V[_a1\x1FV[`\x01`\x01`\xA0\x1B\x03` \x84\x96\x95\x94\x01Q\x16\x8A\x82\x82\x14_\x14a4\x0BWPPPa2\x0Ca1n_\x92\x84`\x01`\x01`\xA0\x1B\x03\x88Q\x16aB#V[\x92\x90a1\xD4\x8C`\x01`\x01`\xA0\x1B\x03\x80\x8AQ\x16\x93\x89Q\x15\x15\x86\x14a3\xDFWa1\xA3a1\x97\x84a\x13DV[\x93[`\x80\x81\x01\x90a\x18\xD9V[\x92\x90\x93`@Q\x96a1\xB3\x88a\x10\xEAV[\x87R\x16` \x86\x01R`@\x85\x01R\x8C``\x85\x01R`\x02`\x80\x85\x01R6\x91a\x13\x81V[`\xA0\x82\x01R`@Q\x80\x93\x81\x92\x7FJ\xF2\x9E\xC4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\xF8V[\x03\x81\x83`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x90\x81\x15a\x02\xF1W_\x91a3\xC4W[P` \x84\x01Q\x8C\x90\x8A\x90\x15a3\xAAW\x83\x83`\x01`\x01`\xA0\x1B\x03\x93a2\x83a2\x89\x94a2|\x8F\x9C\x9B\x9A\x98\x99a2\xB2\x9Aa\x16\x91V[Q\x92a\x16\x91V[Ra\x16\x91V[Q\x91\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[Q\x15a2\xF4Wa+\xAB\x92\x91`\x01`\x01`\xA0\x1B\x03` a+\xA6\x93\x01Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aCAV[Q`@Q\x7F\x15\xAF\xD4\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x81\x01\x91\x90\x91R` \x81\x80`D\x81\x01\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x80\x15a\x02\xF1Wa3\x7FW[Pa+\xAB\x90a&\xFCV[` \x90\x81=\x83\x11a3\xA3W[a3\x95\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW_a3uV[P=a3\x8BV[PP\x90\x91Pa3\xBB\x92\x93\x96Pa\x16\x91V[Q\x93\x84\x91a2\xB2V[a3\xD8\x91P=\x80_\x83>a#\x9C\x81\x83a\x11RV[\x90Pa2IV[a1\xA3\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x93a1\x99V[a4\x9E\x96P\x90a4f\x91``\x94\x8Ba4+`\x80\x99\x98\x99\x93\x84\x81\x01\x90a\x18\xD9V[\x93\x90\x94`@Q\x97a4;\x89a\x116V[`\x01\x89R` \x89\x01R`\x01`\x01`\xA0\x1B\x03\x8B\x16`@\x89\x01R\x88\x88\x01R\x86\x01R`\xA0\x85\x01R6\x91a\x13\x81V[`\xC0\x82\x01R`@Q\x80\x95\x81\x92\x7F+\xFBx\x0C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R`\x04\x83\x01a8\x10V[\x03\x81_`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xF1\x92\x83\x15a\x02\xF1W\x87\x91\x8B\x91_\x95a5-W[P` \x01Q\x15a+\xB0Wa+\xA6\x92\x84a5\x05a+\xAB\x97\x96\x94`\x01`\x01`\xA0\x1B\x03\x94a\x16\x91V[R\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aB\nV[` \x91\x95Pa5J\x90``=``\x11a\x1C\xE0Wa\x1C\xCD\x81\x83a\x11RV[P\x95\x91\x90Pa4\xDFV[o\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x01`\x01`\xA0\x1B\x03` a5\x85\x81\x88\x01Qa5\x7F\x88a&\xEBV[\x90a\x16\x91V[Q\x01Q\x16\x91a)\xFCV[a5\xCC\x85`\x01`\x01`\xA0\x1B\x03` \x84\x01a\x1Cg\x82\x82Q\x16\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0aA\xC0V[a)\xE0V[PPa5\xFC\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a:qV[\x91a6\x07\x83Qa\x19\xD0V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x90_[\x86Q\x81\x10\x15a&\xBAW`\x01\x90`\x01`\x01`\xA0\x1B\x03\x80a6m\x83\x8Ba\x16\x91V[Q\x16_R\x85` Ra6\x88`@_ \\\x82a&~\x85\x8Da\x16\x91V[a6\x92\x83\x87a\x16\x91V[Ra6\x9D\x82\x8Aa\x16\x91V[Q\x16_R\x85` R_`@\x81 ]\x01a6NV[G\x80\x15a6\xF0W\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\a6\xF0W`\x01`\x01`\xA0\x1B\x03a\x18L\x92\x16a@\xE0V[PPV[\x905\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x816\x03\x01\x82\x12\x15a\x02\xFCW\x01\x805\x90g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11a\x02\xFCW` \x01\x91\x81`\x05\x1B6\x03\x83\x13a\x02\xFCWV[\x91\x90\x81\x10\x15a\x16\xA5W`\x05\x1B\x81\x015\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x816\x03\x01\x82\x12\x15a\x02\xFCW\x01\x90V[`@Q\x90`@\x82\x01\x82\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x10\xBDW`@R_` \x83\x82\x81R\x01RV[\x91\x90\x82\x03\x91\x82\x11a\x1A\x0EWV[`\x02\x11\x15a7\xC8WV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x90\x81``\x91\x03\x12a\x02\xFCW\x80Q\x91`@` \x83\x01Q\x92\x01Q\x90V[a\x01\0`\xC0a\x0F|\x93` \x84R\x80Qa8(\x81a7\xBEV[` \x85\x01R` \x81\x01Q`\x01`\x01`\xA0\x1B\x03\x80\x91\x16`@\x86\x01R\x80`@\x83\x01Q\x16``\x86\x01R``\x82\x01Q\x16`\x80\x85\x01R`\x80\x81\x01Q`\xA0\x85\x01R`\xA0\x81\x01Q\x82\x85\x01R\x01Q\x91`\xE0\x80\x82\x01R\x01\x90a\x0F\xFBV[\x90\x91``\x82\x84\x03\x12a\x02\xFCW\x81Q\x91g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x81\x11a\x02\xFCW\x84a8\xA8\x91\x83\x01a\x15sV[\x93` \x82\x01Q\x93`@\x83\x01Q\x90\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15\x07V[\x90\x81Q\x80\x82R` \x80\x80\x93\x01\x93\x01\x91_[\x82\x81\x10a8\xE4WPPPP\x90V[\x83Q\x85R\x93\x81\x01\x93\x92\x81\x01\x92`\x01\x01a8\xD6V[` \x81R`\x01`\x01`\xA0\x1B\x03\x80\x83Q\x16` \x83\x01R` \x83\x01Q\x16`@\x82\x01Ra91`@\x83\x01Q`\xC0``\x84\x01R`\xE0\x83\x01\x90a8\xC5V[\x90``\x83\x01Q`\x80\x82\x01R`\x80\x83\x01Q`\x05\x81\x10\x15a7\xC8Wa\x0F|\x93`\xA0\x91\x82\x84\x01R\x01Q\x90`\xC0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x91``\x83\x83\x03\x12a\x02\xFCW\x82Q\x92` \x81\x01Q\x92g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x93\x84\x81\x11a\x02\xFCW\x81a9\x9A\x91\x84\x01a\x15sV[\x93`@\x83\x01Q\x90\x81\x11a\x02\xFCWa\x0F|\x92\x01a\x15\x07V[` \x81R`\x01`\x01`\xA0\x1B\x03\x80\x83Q\x16` \x83\x01R` \x83\x01Q\x16`@\x82\x01R`@\x82\x01Q``\x82\x01Ra9\xF4``\x83\x01Q`\xC0`\x80\x84\x01R`\xE0\x83\x01\x90a8\xC5V[\x90`\x80\x83\x01Q`\x04\x81\x10\x15a7\xC8Wa\x0F|\x93`\xA0\x91\x82\x84\x01R\x01Q\x90`\xC0`\x1F\x19\x82\x85\x03\x01\x91\x01Ra\x0F\xFBV[\x91\x90\x91`\x80\x80`\xA0\x83\x01\x94\x80Qa:8\x81a7\xBEV[\x84R` \x81\x01Qa:H\x81a7\xBEV[` \x85\x01R`\x01`\x01`\xA0\x1B\x03`@\x82\x01Q\x16`@\x85\x01R``\x81\x01Q``\x85\x01R\x01Q\x91\x01RV[\x90\x81\\a:}\x81a\x11uV[a:\x8A`@Q\x91\x82a\x11RV[\x81\x81Ra:\x96\x82a\x11uV[`\x1F\x19` \x91\x016` \x84\x017\x81\x94_[\x84\x81\x10a:\xB5WPPPPPV[`\x01\x90\x82_R\x80\x84_ \x01\\`\x01`\x01`\xA0\x1B\x03a:\xD3\x83\x88a\x16\x91V[\x91\x16\x90R\x01a:\xA7V[\x91\x92\x80a=\xD8W[\x15a=\x90\xFD[` \x92Pa<\x1F\x90a\x11\x06V[`D_\x92Pa;cV[\x7F\xA0\x1A\x9D\xF6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x90\x91_\x90\x80a\xA7W_\x19\x90\x81\x81\x01\x83\\\x83\x80\x82\x01\x91\x82\x84\x03a>jW[PPPPP\x81\\\x81\x81\x01\x92\x81\x84\x11a\x1A\x0EW_\x93\x81]\x83R\x84\x83 \x01\x01]_RR_`@\x81 ]`\x01\x90V[a>wa>\x87\x93\x88aD:V[\x86_R\x88_ \x01\x01\\\x91\x85aD:V[\x83_R\x80\x83\x83\x88_ \x01\x01]_R\x85\x85R`@_ ]_\x80\x80\x83\x81a>>V[PPPPP_\x90V[_\x94\x93\x83\x15a@\xD8W\x80a@\xA3W[\x15a@\x07W`\x01`\x01`\xA0\x1B\x03\x91\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x80;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x92\x90\x92\x16`\x04\x83\x01R0`$\x83\x01R`D\x82\x01\x85\x90R_\x90\x82\x90`d\x90\x82\x90\x84\x90Z\xF1\x80\x15a\x02\xF1Wa?\xF4W[P\x84\x82\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x80;\x15a?\xF0W\x81\x90`$`@Q\x80\x94\x81\x93\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83R\x89`\x04\x84\x01RZ\xF1\x80\x15a?\xE5Wa?\xCDW[Pa\x18L\x93\x94P\x16a@\xE0V[a?\xD7\x86\x91a\x11\x06V[a?\xE1W\x84a?\xC0V[\x84\x80\xFD[`@Q=\x88\x82>=\x90\xFD[P\x80\xFD[a?\xFF\x91\x95Pa\x11\x06V[_\x93_a?SV[\x92\x93P\x90`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x80;\x15a\x02\xFCW`@Q\x7F\xAEc\x93)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x93\x84\x16`\x04\x82\x01R\x93\x90\x92\x16`$\x84\x01R`D\x83\x01R_\x90\x82\x90`d\x90\x82\x90\x84\x90Z\xF1\x80\x15a\x02\xF1Wa@\x9AWPV[a\x18L\x90a\x11\x06V[P`\x01`\x01`\xA0\x1B\x03\x80\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90\x83\x16\x14a>\xBFV[PPPP\x90PV[\x81G\x10aA0W_\x80\x80\x93`\x01`\x01`\xA0\x1B\x03\x82\x94\x16Z\xF1aA\0a(wV[P\x15aA\x08WV[\x7F\x14%\xEAB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD[\x7F\xCDx`Y\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R0`\x04R`$_\xFD[\x90aAqWP\x80Q\x15aA\x08W\x80Q\x90` \x01\xFD[\x81Q\x15\x80aA\xB7W[aA\x82WP\x90V[`\x01`\x01`\xA0\x1B\x03\x90\x7F\x99\x96\xB3\x15\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R\x16`\x04R`$_\xFD[P\x80;\x15aAzV[`\x01\x81\x01\x90\x82_R\x81` R`@_ \\\x15_\x14aB\x03W\x80\\\x81_R\x83\x81` _ \x01]`\x01\x81\x01\x80\x91\x11a\x1A\x0EW\x81]\\\x91_R` R`@_ ]`\x01\x90V[PPP_\x90V[\x90_R` RaB\x1F`@_ \x91\x82\\a\x1A\x01V[\x90]V[\x91`D\x92\x93\x91\x93`\x01`\x01`\xA0\x1B\x03`@\x94\x85\x92\x82\x80\x85Q\x99\x8A\x95\x86\x94\x7F\xC9\xC1f\x1B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x86R\x16`\x04\x85\x01R\x16`$\x83\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16Z\xFA\x93\x84\x15aB\xF3W_\x93_\x95aB\xBCW[PPaB\xB9aB\xB2\x85\x94a\x19\xD0V[\x94\x85a\x16\x91V[RV[\x80\x92\x95P\x81\x94P=\x83\x11aB\xECW[aB\xD5\x81\x83a\x11RV[\x81\x01\x03\x12a\x02\xFCW` \x82Q\x92\x01Q\x92_\x80aB\xA3V[P=aB\xCBV[\x83Q=_\x82>=\x90\xFD[`\x01`\x01`\xA0\x1B\x03\x90\x81\x81\x11aC\x11W\x16\x90V[\x7Fm\xFC\xC6P\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\xA0`\x04R`$R`D_\xFD[\x90_R` RaB\x1F`@_ \x91\x82\\a7\xB1V[`@Q\x92` \x84\x01\x90\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82R`\x01`\x01`\xA0\x1B\x03\x80\x94\x16`$\x86\x01R`D\x85\x01R`D\x84R`\x80\x84\x01\x90\x84\x82\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11\x17a\x10\xBDWaC\xD5\x93_\x93\x84\x93`@R\x16\x94Q\x90\x82\x86Z\xF1aC\xCEa(wV[\x90\x83aA\\V[\x80Q\x90\x81\x15\x15\x91\x82aD\x16W[PPaC\xEBWPV[\x7FRt\xAF\xE7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04R`$_\xFD[\x81\x92P\x90` \x91\x81\x01\x03\x12a\x02\xFCW` \x01Q\x80\x15\x90\x81\x15\x03a\x02\xFCW_\x80aC\xE2V[\\\x11\x15aDCWV[\x7F\x0FJ\xE0\xE4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x04_\xFD\xFE\xA2dipfsX\"\x12 \"\x9A\\\xF8\x9A\xA7\xC2\xD0\xA4\xB4\xD5\xDB \xBB\xA6\xC2\xB3\xA7K\x08\x03\x03\xFCn\xC0\x0B\xA5\x82\xA5\xDC\xF7QdsolcC\0\x08\x1A\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `AddressEmptyCode(address)` and selector `0x9996b315`. + ```solidity + error AddressEmptyCode(address target); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct AddressEmptyCode { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: AddressEmptyCode) -> Self { + (value.target,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for AddressEmptyCode { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { target: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for AddressEmptyCode { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [153u8, 150u8, 179u8, 21u8]; + const SIGNATURE: &'static str = "AddressEmptyCode(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.target, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `AddressInsufficientBalance(address)` and selector `0xcd786059`. + ```solidity + error AddressInsufficientBalance(address account); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct AddressInsufficientBalance { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: AddressInsufficientBalance) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for AddressInsufficientBalance { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for AddressInsufficientBalance { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [205u8, 120u8, 96u8, 89u8]; + const SIGNATURE: &'static str = "AddressInsufficientBalance(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ErrorSelectorNotFound()` and selector `0xa7285689`. + ```solidity + error ErrorSelectorNotFound(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ErrorSelectorNotFound; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ErrorSelectorNotFound) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ErrorSelectorNotFound { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ErrorSelectorNotFound { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [167u8, 40u8, 86u8, 137u8]; + const SIGNATURE: &'static str = "ErrorSelectorNotFound()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `EthTransfer()` and selector `0x0540ddf6`. + ```solidity + error EthTransfer(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct EthTransfer; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: EthTransfer) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for EthTransfer { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for EthTransfer { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [5u8, 64u8, 221u8, 246u8]; + const SIGNATURE: &'static str = "EthTransfer()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `FailedInnerCall()` and selector `0x1425ea42`. + ```solidity + error FailedInnerCall(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct FailedInnerCall; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: FailedInnerCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for FailedInnerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for FailedInnerCall { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [20u8, 37u8, 234u8, 66u8]; + const SIGNATURE: &'static str = "FailedInnerCall()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InputLengthMismatch()` and selector `0xaaad13f7`. + ```solidity + error InputLengthMismatch(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InputLengthMismatch; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InputLengthMismatch) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InputLengthMismatch { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InputLengthMismatch { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [170u8, 173u8, 19u8, 247u8]; + const SIGNATURE: &'static str = "InputLengthMismatch()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InsufficientEth()` and selector `0xa01a9df6`. + ```solidity + error InsufficientEth(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InsufficientEth; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InsufficientEth) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InsufficientEth { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InsufficientEth { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [160u8, 26u8, 157u8, 246u8]; + const SIGNATURE: &'static str = "InsufficientEth()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ReentrancyGuardReentrantCall()` and selector `0x3ee5aeb5`. + ```solidity + error ReentrancyGuardReentrantCall(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ReentrancyGuardReentrantCall; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ReentrancyGuardReentrantCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ReentrancyGuardReentrantCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ReentrancyGuardReentrantCall { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [62u8, 229u8, 174u8, 181u8]; + const SIGNATURE: &'static str = "ReentrancyGuardReentrantCall()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SafeCastOverflowedUintDowncast(uint8,uint256)` and selector `0x6dfcc650`. + ```solidity + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SafeCastOverflowedUintDowncast { + #[allow(missing_docs)] + pub bits: u8, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8, alloy_sol_types::private::primitives::aliases::U256); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SafeCastOverflowedUintDowncast) -> Self { + (value.bits, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SafeCastOverflowedUintDowncast { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + bits: tuple.0, + value: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SafeCastOverflowedUintDowncast { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [109u8, 252u8, 198u8, 80u8]; + const SIGNATURE: &'static str = "SafeCastOverflowedUintDowncast(uint8,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.bits, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SafeERC20FailedOperation(address)` and selector `0x5274afe7`. + ```solidity + error SafeERC20FailedOperation(address token); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SafeERC20FailedOperation { + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SafeERC20FailedOperation) -> Self { + (value.token,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SafeERC20FailedOperation { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { token: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SafeERC20FailedOperation { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [82u8, 116u8, 175u8, 231u8]; + const SIGNATURE: &'static str = "SafeERC20FailedOperation(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.token, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SenderIsNotVault(address)` and selector `0x089676d5`. + ```solidity + error SenderIsNotVault(address sender); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SenderIsNotVault { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SenderIsNotVault) -> Self { + (value.sender,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SenderIsNotVault { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { sender: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SenderIsNotVault { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [8u8, 150u8, 118u8, 213u8]; + const SIGNATURE: &'static str = "SenderIsNotVault(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SwapDeadline()` and selector `0xe08b8af0`. + ```solidity + error SwapDeadline(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SwapDeadline; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SwapDeadline) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SwapDeadline { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SwapDeadline { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [224u8, 139u8, 138u8, 240u8]; + const SIGNATURE: &'static str = "SwapDeadline()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `TransientIndexOutOfBounds()` and selector `0x0f4ae0e4`. + ```solidity + error TransientIndexOutOfBounds(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct TransientIndexOutOfBounds; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: TransientIndexOutOfBounds) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for TransientIndexOutOfBounds { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for TransientIndexOutOfBounds { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [15u8, 74u8, 224u8, 228u8]; + const SIGNATURE: &'static str = "TransientIndexOutOfBounds()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + /**Constructor`. + ```solidity + constructor(address vault, address weth, address permit2, string routerVersion); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub weth: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub permit2: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub routerVersion: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.vault, value.weth, value.permit2, value.routerVersion) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + vault: tuple.0, + weth: tuple.1, + permit2: tuple.2, + routerVersion: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.vault, + ), + ::tokenize( + &self.weth, + ), + ::tokenize( + &self.permit2, + ), + ::tokenize( + &self.routerVersion, + ), + ) + } + } + }; + #[derive()] + /**Function with signature `querySwapExactIn((address,(address,address,bool)[],uint256,uint256)[],address,bytes)` and selector `0xe3b5dff4`. + ```solidity + function querySwapExactIn(IBatchRouter.SwapPathExactAmountIn[] memory paths, address sender, bytes memory userData) external returns (uint256[] memory pathAmountsOut, address[] memory tokensOut, uint256[] memory amountsOut); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct querySwapExactInCall { + #[allow(missing_docs)] + pub paths: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`querySwapExactIn((address,(address,address,bool)[],uint256,uint256)[], + /// address,bytes)`](querySwapExactInCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct querySwapExactInReturn { + #[allow(missing_docs)] + pub pathAmountsOut: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokensOut: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amountsOut: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: querySwapExactInCall) -> Self { + (value.paths, value.sender, value.userData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for querySwapExactInCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paths: tuple.0, + sender: tuple.1, + userData: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: querySwapExactInReturn) -> Self { + (value.pathAmountsOut, value.tokensOut, value.amountsOut) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for querySwapExactInReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + pathAmountsOut: tuple.0, + tokensOut: tuple.1, + amountsOut: tuple.2, + } + } + } + } + impl querySwapExactInReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + , + > as alloy_sol_types::SolType>::tokenize(&self.pathAmountsOut), + as alloy_sol_types::SolType>::tokenize(&self.tokensOut), + , + > as alloy_sol_types::SolType>::tokenize(&self.amountsOut), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for querySwapExactInCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = querySwapExactInReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [227u8, 181u8, 223u8, 244u8]; + const SIGNATURE: &'static str = "querySwapExactIn((address,(address,address,bool)[],\ + uint256,uint256)[],address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.paths), + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + querySwapExactInReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive()] + /**Function with signature `querySwapExactOut((address,(address,address,bool)[],uint256,uint256)[],address,bytes)` and selector `0x2950286e`. + ```solidity + function querySwapExactOut(IBatchRouter.SwapPathExactAmountOut[] memory paths, address sender, bytes memory userData) external returns (uint256[] memory pathAmountsIn, address[] memory tokensIn, uint256[] memory amountsIn); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct querySwapExactOutCall { + #[allow(missing_docs)] + pub paths: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`querySwapExactOut((address,(address,address,bool)[],uint256, + /// uint256)[],address,bytes)`](querySwapExactOutCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct querySwapExactOutReturn { + #[allow(missing_docs)] + pub pathAmountsIn: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokensIn: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amountsIn: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: querySwapExactOutCall) -> Self { + (value.paths, value.sender, value.userData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for querySwapExactOutCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paths: tuple.0, + sender: tuple.1, + userData: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: querySwapExactOutReturn) -> Self { + (value.pathAmountsIn, value.tokensIn, value.amountsIn) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for querySwapExactOutReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + pathAmountsIn: tuple.0, + tokensIn: tuple.1, + amountsIn: tuple.2, + } + } + } + } + impl querySwapExactOutReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + , + > as alloy_sol_types::SolType>::tokenize(&self.pathAmountsIn), + as alloy_sol_types::SolType>::tokenize(&self.tokensIn), + , + > as alloy_sol_types::SolType>::tokenize(&self.amountsIn), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for querySwapExactOutCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = querySwapExactOutReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [41u8, 80u8, 40u8, 110u8]; + const SIGNATURE: &'static str = "querySwapExactOut((address,(address,address,bool)[],\ + uint256,uint256)[],address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.paths), + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + querySwapExactOutReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive()] + /**Function with signature `swapExactIn((address,(address,address,bool)[],uint256,uint256)[],uint256,bool,bytes)` and selector `0x286f580d`. + ```solidity + function swapExactIn(IBatchRouter.SwapPathExactAmountIn[] memory paths, uint256 deadline, bool wethIsEth, bytes memory userData) external payable returns (uint256[] memory pathAmountsOut, address[] memory tokensOut, uint256[] memory amountsOut); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapExactInCall { + #[allow(missing_docs)] + pub paths: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub wethIsEth: bool, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapExactIn((address,(address,address,bool)[],uint256,uint256)[], + /// uint256,bool,bytes)`](swapExactInCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapExactInReturn { + #[allow(missing_docs)] + pub pathAmountsOut: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokensOut: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amountsOut: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::primitives::aliases::U256, + bool, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapExactInCall) -> Self { + (value.paths, value.deadline, value.wethIsEth, value.userData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapExactInCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paths: tuple.0, + deadline: tuple.1, + wethIsEth: tuple.2, + userData: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapExactInReturn) -> Self { + (value.pathAmountsOut, value.tokensOut, value.amountsOut) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapExactInReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + pathAmountsOut: tuple.0, + tokensOut: tuple.1, + amountsOut: tuple.2, + } + } + } + } + impl swapExactInReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + , + > as alloy_sol_types::SolType>::tokenize(&self.pathAmountsOut), + as alloy_sol_types::SolType>::tokenize(&self.tokensOut), + , + > as alloy_sol_types::SolType>::tokenize(&self.amountsOut), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapExactInCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Bytes, + ); + type Return = swapExactInReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [40u8, 111u8, 88u8, 13u8]; + const SIGNATURE: &'static str = "swapExactIn((address,(address,address,bool)[],\ + uint256,uint256)[],uint256,bool,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.paths), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ::tokenize( + &self.wethIsEth, + ), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + swapExactInReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive()] + /**Function with signature `swapExactOut((address,(address,address,bool)[],uint256,uint256)[],uint256,bool,bytes)` and selector `0x8eb1b65e`. + ```solidity + function swapExactOut(IBatchRouter.SwapPathExactAmountOut[] memory paths, uint256 deadline, bool wethIsEth, bytes memory userData) external payable returns (uint256[] memory pathAmountsIn, address[] memory tokensIn, uint256[] memory amountsIn); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapExactOutCall { + #[allow(missing_docs)] + pub paths: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub wethIsEth: bool, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapExactOut((address,(address,address,bool)[],uint256,uint256)[], + /// uint256,bool,bytes)`](swapExactOutCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapExactOutReturn { + #[allow(missing_docs)] + pub pathAmountsIn: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub tokensIn: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub amountsIn: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::primitives::aliases::U256, + bool, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapExactOutCall) -> Self { + (value.paths, value.deadline, value.wethIsEth, value.userData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapExactOutCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + paths: tuple.0, + deadline: tuple.1, + wethIsEth: tuple.2, + userData: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapExactOutReturn) -> Self { + (value.pathAmountsIn, value.tokensIn, value.amountsIn) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapExactOutReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + pathAmountsIn: tuple.0, + tokensIn: tuple.1, + amountsIn: tuple.2, + } + } + } + } + impl swapExactOutReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + , + > as alloy_sol_types::SolType>::tokenize(&self.pathAmountsIn), + as alloy_sol_types::SolType>::tokenize(&self.tokensIn), + , + > as alloy_sol_types::SolType>::tokenize(&self.amountsIn), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapExactOutCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Bytes, + ); + type Return = swapExactOutReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [142u8, 177u8, 182u8, 94u8]; + const SIGNATURE: &'static str = "swapExactOut((address,(address,address,bool)[],\ + uint256,uint256)[],uint256,bool,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.paths), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ::tokenize( + &self.wethIsEth, + ), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + swapExactOutReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `version()` and selector `0x54fd4d50`. + ```solidity + function version() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`version()`](versionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct versionReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: versionReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for versionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for versionCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + const SIGNATURE: &'static str = "version()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: versionReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: versionReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`BalancerV3BatchRouter`](self) function calls. + #[derive(Clone)] + pub enum BalancerV3BatchRouterCalls { + #[allow(missing_docs)] + querySwapExactIn(querySwapExactInCall), + #[allow(missing_docs)] + querySwapExactOut(querySwapExactOutCall), + #[allow(missing_docs)] + swapExactIn(swapExactInCall), + #[allow(missing_docs)] + swapExactOut(swapExactOutCall), + #[allow(missing_docs)] + version(versionCall), + } + impl BalancerV3BatchRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [40u8, 111u8, 88u8, 13u8], + [41u8, 80u8, 40u8, 110u8], + [84u8, 253u8, 77u8, 80u8], + [142u8, 177u8, 182u8, 94u8], + [227u8, 181u8, 223u8, 244u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapExactIn), + ::core::stringify!(querySwapExactOut), + ::core::stringify!(version), + ::core::stringify!(swapExactOut), + ::core::stringify!(querySwapExactIn), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV3BatchRouterCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV3BatchRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::querySwapExactIn(_) => { + ::SELECTOR + } + Self::querySwapExactOut(_) => { + ::SELECTOR + } + Self::swapExactIn(_) => ::SELECTOR, + Self::swapExactOut(_) => ::SELECTOR, + Self::version(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapExactIn( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterCalls::swapExactIn) + } + swapExactIn + }, + { + fn querySwapExactOut( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterCalls::querySwapExactOut) + } + querySwapExactOut + }, + { + fn version(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterCalls::version) + } + version + }, + { + fn swapExactOut( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterCalls::swapExactOut) + } + swapExactOut + }, + { + fn querySwapExactIn( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterCalls::querySwapExactIn) + } + querySwapExactIn + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV3BatchRouterCalls, + >] = &[ + { + fn swapExactIn( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV3BatchRouterCalls::swapExactIn) + } + swapExactIn + }, + { + fn querySwapExactOut( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterCalls::querySwapExactOut) + } + querySwapExactOut + }, + { + fn version(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV3BatchRouterCalls::version) + } + version + }, + { + fn swapExactOut( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterCalls::swapExactOut) + } + swapExactOut + }, + { + fn querySwapExactIn( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterCalls::querySwapExactIn) + } + querySwapExactIn + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::querySwapExactIn(inner) => { + ::abi_encoded_size(inner) + } + Self::querySwapExactOut(inner) => { + ::abi_encoded_size(inner) + } + Self::swapExactIn(inner) => { + ::abi_encoded_size(inner) + } + Self::swapExactOut(inner) => { + ::abi_encoded_size(inner) + } + Self::version(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::querySwapExactIn(inner) => { + ::abi_encode_raw(inner, out) + } + Self::querySwapExactOut(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapExactIn(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapExactOut(inner) => { + ::abi_encode_raw(inner, out) + } + Self::version(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`BalancerV3BatchRouter`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum BalancerV3BatchRouterErrors { + #[allow(missing_docs)] + AddressEmptyCode(AddressEmptyCode), + #[allow(missing_docs)] + AddressInsufficientBalance(AddressInsufficientBalance), + #[allow(missing_docs)] + ErrorSelectorNotFound(ErrorSelectorNotFound), + #[allow(missing_docs)] + EthTransfer(EthTransfer), + #[allow(missing_docs)] + FailedInnerCall(FailedInnerCall), + #[allow(missing_docs)] + InputLengthMismatch(InputLengthMismatch), + #[allow(missing_docs)] + InsufficientEth(InsufficientEth), + #[allow(missing_docs)] + ReentrancyGuardReentrantCall(ReentrancyGuardReentrantCall), + #[allow(missing_docs)] + SafeCastOverflowedUintDowncast(SafeCastOverflowedUintDowncast), + #[allow(missing_docs)] + SafeERC20FailedOperation(SafeERC20FailedOperation), + #[allow(missing_docs)] + SenderIsNotVault(SenderIsNotVault), + #[allow(missing_docs)] + SwapDeadline(SwapDeadline), + #[allow(missing_docs)] + TransientIndexOutOfBounds(TransientIndexOutOfBounds), + } + impl BalancerV3BatchRouterErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [5u8, 64u8, 221u8, 246u8], + [8u8, 150u8, 118u8, 213u8], + [15u8, 74u8, 224u8, 228u8], + [20u8, 37u8, 234u8, 66u8], + [62u8, 229u8, 174u8, 181u8], + [82u8, 116u8, 175u8, 231u8], + [109u8, 252u8, 198u8, 80u8], + [153u8, 150u8, 179u8, 21u8], + [160u8, 26u8, 157u8, 246u8], + [167u8, 40u8, 86u8, 137u8], + [170u8, 173u8, 19u8, 247u8], + [205u8, 120u8, 96u8, 89u8], + [224u8, 139u8, 138u8, 240u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(EthTransfer), + ::core::stringify!(SenderIsNotVault), + ::core::stringify!(TransientIndexOutOfBounds), + ::core::stringify!(FailedInnerCall), + ::core::stringify!(ReentrancyGuardReentrantCall), + ::core::stringify!(SafeERC20FailedOperation), + ::core::stringify!(SafeCastOverflowedUintDowncast), + ::core::stringify!(AddressEmptyCode), + ::core::stringify!(InsufficientEth), + ::core::stringify!(ErrorSelectorNotFound), + ::core::stringify!(InputLengthMismatch), + ::core::stringify!(AddressInsufficientBalance), + ::core::stringify!(SwapDeadline), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancerV3BatchRouterErrors { + const COUNT: usize = 13usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BalancerV3BatchRouterErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::AddressEmptyCode(_) => { + ::SELECTOR + } + Self::AddressInsufficientBalance(_) => { + ::SELECTOR + } + Self::ErrorSelectorNotFound(_) => { + ::SELECTOR + } + Self::EthTransfer(_) => ::SELECTOR, + Self::FailedInnerCall(_) => { + ::SELECTOR + } + Self::InputLengthMismatch(_) => { + ::SELECTOR + } + Self::InsufficientEth(_) => { + ::SELECTOR + } + Self::ReentrancyGuardReentrantCall(_) => { + ::SELECTOR + } + Self::SafeCastOverflowedUintDowncast(_) => { + ::SELECTOR + } + Self::SafeERC20FailedOperation(_) => { + ::SELECTOR + } + Self::SenderIsNotVault(_) => { + ::SELECTOR + } + Self::SwapDeadline(_) => ::SELECTOR, + Self::TransientIndexOutOfBounds(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn EthTransfer( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::EthTransfer) + } + EthTransfer + }, + { + fn SenderIsNotVault( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::SenderIsNotVault) + } + SenderIsNotVault + }, + { + fn TransientIndexOutOfBounds( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(BalancerV3BatchRouterErrors::TransientIndexOutOfBounds) + } + TransientIndexOutOfBounds + }, + { + fn FailedInnerCall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::FailedInnerCall) + } + FailedInnerCall + }, + { + fn ReentrancyGuardReentrantCall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(BalancerV3BatchRouterErrors::ReentrancyGuardReentrantCall) + } + ReentrancyGuardReentrantCall + }, + { + fn SafeERC20FailedOperation( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(BalancerV3BatchRouterErrors::SafeERC20FailedOperation) + } + SafeERC20FailedOperation + }, + { + fn SafeCastOverflowedUintDowncast( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map( + BalancerV3BatchRouterErrors::SafeCastOverflowedUintDowncast, + ) + } + SafeCastOverflowedUintDowncast + }, + { + fn AddressEmptyCode( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::AddressEmptyCode) + } + AddressEmptyCode + }, + { + fn InsufficientEth( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::InsufficientEth) + } + InsufficientEth + }, + { + fn ErrorSelectorNotFound( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::ErrorSelectorNotFound) + } + ErrorSelectorNotFound + }, + { + fn InputLengthMismatch( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::InputLengthMismatch) + } + InputLengthMismatch + }, + { + fn AddressInsufficientBalance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(BalancerV3BatchRouterErrors::AddressInsufficientBalance) + } + AddressInsufficientBalance + }, + { + fn SwapDeadline( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancerV3BatchRouterErrors::SwapDeadline) + } + SwapDeadline + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + BalancerV3BatchRouterErrors, + >] = &[ + { + fn EthTransfer( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV3BatchRouterErrors::EthTransfer) + } + EthTransfer + }, + { + fn SenderIsNotVault( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::SenderIsNotVault) + } + SenderIsNotVault + }, + { + fn TransientIndexOutOfBounds( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::TransientIndexOutOfBounds) + } + TransientIndexOutOfBounds + }, + { + fn FailedInnerCall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::FailedInnerCall) + } + FailedInnerCall + }, + { + fn ReentrancyGuardReentrantCall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map( + BalancerV3BatchRouterErrors::ReentrancyGuardReentrantCall, + ) + } + ReentrancyGuardReentrantCall + }, + { + fn SafeERC20FailedOperation( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::SafeERC20FailedOperation) + } + SafeERC20FailedOperation + }, + { + fn SafeCastOverflowedUintDowncast( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map( + BalancerV3BatchRouterErrors::SafeCastOverflowedUintDowncast, + ) + } + SafeCastOverflowedUintDowncast + }, + { + fn AddressEmptyCode( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::AddressEmptyCode) + } + AddressEmptyCode + }, + { + fn InsufficientEth( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::InsufficientEth) + } + InsufficientEth + }, + { + fn ErrorSelectorNotFound( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::ErrorSelectorNotFound) + } + ErrorSelectorNotFound + }, + { + fn InputLengthMismatch( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::InputLengthMismatch) + } + InputLengthMismatch + }, + { + fn AddressInsufficientBalance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BalancerV3BatchRouterErrors::AddressInsufficientBalance) + } + AddressInsufficientBalance + }, + { + fn SwapDeadline( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancerV3BatchRouterErrors::SwapDeadline) + } + SwapDeadline + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::AddressEmptyCode(inner) => { + ::abi_encoded_size(inner) + } + Self::AddressInsufficientBalance(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::ErrorSelectorNotFound(inner) => { + ::abi_encoded_size(inner) + } + Self::EthTransfer(inner) => { + ::abi_encoded_size(inner) + } + Self::FailedInnerCall(inner) => { + ::abi_encoded_size(inner) + } + Self::InputLengthMismatch(inner) => { + ::abi_encoded_size(inner) + } + Self::InsufficientEth(inner) => { + ::abi_encoded_size(inner) + } + Self::ReentrancyGuardReentrantCall(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::SafeCastOverflowedUintDowncast(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::SafeERC20FailedOperation(inner) => { + ::abi_encoded_size(inner) + } + Self::SenderIsNotVault(inner) => { + ::abi_encoded_size(inner) + } + Self::SwapDeadline(inner) => { + ::abi_encoded_size(inner) + } + Self::TransientIndexOutOfBounds(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::AddressEmptyCode(inner) => { + ::abi_encode_raw(inner, out) + } + Self::AddressInsufficientBalance(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::ErrorSelectorNotFound(inner) => { + ::abi_encode_raw(inner, out) + } + Self::EthTransfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::FailedInnerCall(inner) => { + ::abi_encode_raw(inner, out) + } + Self::InputLengthMismatch(inner) => { + ::abi_encode_raw(inner, out) + } + Self::InsufficientEth(inner) => { + ::abi_encode_raw(inner, out) + } + Self::ReentrancyGuardReentrantCall(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::SafeCastOverflowedUintDowncast(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::SafeERC20FailedOperation(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::SenderIsNotVault(inner) => { + ::abi_encode_raw(inner, out) + } + Self::SwapDeadline(inner) => { + ::abi_encode_raw(inner, out) + } + Self::TransientIndexOutOfBounds(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BalancerV3BatchRouter`](self) contract instance. + + See the [wrapper's documentation](`BalancerV3BatchRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancerV3BatchRouterInstance { + BalancerV3BatchRouterInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + vault: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + permit2: alloy_sol_types::private::Address, + routerVersion: alloy_sol_types::private::String, + ) -> impl ::core::future::Future>> + { + BalancerV3BatchRouterInstance::::deploy( + __provider, + vault, + weth, + permit2, + routerVersion, + ) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + vault: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + permit2: alloy_sol_types::private::Address, + routerVersion: alloy_sol_types::private::String, + ) -> alloy_contract::RawCallBuilder { + BalancerV3BatchRouterInstance::::deploy_builder( + __provider, + vault, + weth, + permit2, + routerVersion, + ) + } + /**A [`BalancerV3BatchRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BalancerV3BatchRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancerV3BatchRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancerV3BatchRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancerV3BatchRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancerV3BatchRouterInstance + { + /**Creates a new wrapper around an on-chain [`BalancerV3BatchRouter`](self) contract instance. + + See the [wrapper's documentation](`BalancerV3BatchRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + vault: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + permit2: alloy_sol_types::private::Address, + routerVersion: alloy_sol_types::private::String, + ) -> alloy_contract::Result> { + let call_builder = + Self::deploy_builder(__provider, vault, weth, permit2, routerVersion); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + vault: alloy_sol_types::private::Address, + weth: alloy_sol_types::private::Address, + permit2: alloy_sol_types::private::Address, + routerVersion: alloy_sol_types::private::String, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + vault, + weth, + permit2, + routerVersion, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancerV3BatchRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancerV3BatchRouterInstance { + BalancerV3BatchRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancerV3BatchRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`querySwapExactIn`] function. + pub fn querySwapExactIn( + &self, + paths: alloy_sol_types::private::Vec< + ::RustType, + >, + sender: alloy_sol_types::private::Address, + userData: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, querySwapExactInCall, N> { + self.call_builder(&querySwapExactInCall { + paths, + sender, + userData, + }) + } + + ///Creates a new call builder for the [`querySwapExactOut`] function. + pub fn querySwapExactOut( + &self, + paths: alloy_sol_types::private::Vec< + ::RustType, + >, + sender: alloy_sol_types::private::Address, + userData: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, querySwapExactOutCall, N> { + self.call_builder(&querySwapExactOutCall { + paths, + sender, + userData, + }) + } + + ///Creates a new call builder for the [`swapExactIn`] function. + pub fn swapExactIn( + &self, + paths: alloy_sol_types::private::Vec< + ::RustType, + >, + deadline: alloy_sol_types::private::primitives::aliases::U256, + wethIsEth: bool, + userData: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, swapExactInCall, N> { + self.call_builder(&swapExactInCall { + paths, + deadline, + wethIsEth, + userData, + }) + } + + ///Creates a new call builder for the [`swapExactOut`] function. + pub fn swapExactOut( + &self, + paths: alloy_sol_types::private::Vec< + ::RustType, + >, + deadline: alloy_sol_types::private::primitives::aliases::U256, + wethIsEth: bool, + userData: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, swapExactOutCall, N> { + self.call_builder(&swapExactOutCall { + paths, + deadline, + wethIsEth, + userData, + }) + } + + ///Creates a new call builder for the [`version`] function. + pub fn version(&self) -> alloy_contract::SolCallBuilder<&P, versionCall, N> { + self.call_builder(&versionCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancerV3BatchRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = + BalancerV3BatchRouter::BalancerV3BatchRouterInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1"), + Some(21339510u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E"), + Some(133969588u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b"), + Some(37377506u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x85a80afee867aDf27B50BdB7b76DA70f1E853062"), + Some(25347205u64), + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x85a80afee867aDf27B50BdB7b76DA70f1E853062"), + Some(782312u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E"), + Some(297828544u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xc9b36096f5201ea332Db35d6D195774ea0D5988f"), + Some(59965747u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xC85b652685567C1B074e8c0D4389f83a2E458b1C"), + Some(7219301u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/balances/Cargo.toml b/contracts/generated/contracts-generated/balances/Cargo.toml new file mode 100644 index 0000000000..11c7a8266d --- /dev/null +++ b/contracts/generated/contracts-generated/balances/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-balances" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/balances/src/lib.rs b/contracts/generated/contracts-generated/balances/src/lib.rs new file mode 100644 index 0000000000..0c4f3080f2 --- /dev/null +++ b/contracts/generated/contracts-generated/balances/src/lib.rs @@ -0,0 +1,1278 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface Balances { + struct Contracts { + address settlement; + address vaultRelayer; + address vault; + } + struct Interaction { + address target; + uint256 value; + bytes callData; + } + + function balance(Contracts memory contracts, address trader, address token, uint256 amount, bytes32 source, Interaction[] memory interactions) external returns (uint256 tokenBalance, uint256 allowance, uint256 effectiveBalance, bool canTransfer, bytes memory transferRevertReason); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "balance", + "inputs": [ + { + "name": "contracts", + "type": "tuple", + "internalType": "struct Balances.Contracts", + "components": [ + { + "name": "settlement", + "type": "address", + "internalType": "contract ISettlement" + }, + { + "name": "vaultRelayer", + "type": "address", + "internalType": "contract IVaultRelayer" + }, + { + "name": "vault", + "type": "address", + "internalType": "contract IVault" + } + ] + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "source", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "interactions", + "type": "tuple[]", + "internalType": "struct Interaction[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "tokenBalance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "allowance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "effectiveBalance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "canTransfer", + "type": "bool", + "internalType": "bool" + }, + { + "name": "transferRevertReason", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Balances { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b50610ef28061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063f88cf6db1461002d575b5f5ffd5b61004061003b366004610abe565b61005a565b604051610051959493929190610b83565b60405180910390f35b5f5f5f5f606061006b8c88886107b0565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc988036101c6576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa1580156100fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101209190610c0a565b60208d01516040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e8116600483015291821660248201529196508b169063dd62ed3e906044015b602060405180830381865afa15801561019b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101bf9190610c0a565b9350610604565b7fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328803610389576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa158015610257573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027b9190610c0a565b6040808e015160208f015191517ffec90d7200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8f811660048301529283166024820152929750169063fec90d7290604401602060405180830381865afa1580156102f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061031d9190610c21565b610327575f6101bf565b60408c81015190517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301529182166024820152908b169063dd62ed3e90604401610180565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce880361059d576040805160018082528183019092525f91602080830190803683370190505090508a815f815181106103e4576103e4610c47565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040808f015190517f0f5a6efa000000000000000000000000000000000000000000000000000000008152911690630f5a6efa9061044b908f908590600401610c74565b5f60405180830381865afa158015610465573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104aa9190810190610ced565b5f815181106104bb576104bb610c47565b602002602001015195508c6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728d8f602001516040518363ffffffff1660e01b815260040161052a92919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b602060405180830381865afa158015610545573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105699190610c21565b610573575f610595565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b945050610604565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c696420746f6b656e20736f7572636500000000000000000000000060448201526064015b60405180910390fd5b838511156106125783610614565b845b6040805160018082528183019092529194505f9190816020015b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161062e57905050905060405180608001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b5f036106d157856106d3565b8b5b81526020018a815250815f815181106106ee576106ee610c47565b60200260200101819052508c6020015173ffffffffffffffffffffffffffffffffffffffff16637d10d11f826040518263ffffffff1660e01b81526004016107369190610d99565b5f604051808303815f87803b15801561074d575f5ffd5b505af192505050801561075e575060015b61079b573d80801561078b576040519150601f19603f3d011682016040523d82523d5f602084013e610790565b606091505b505f935091506107a0565b600192505b5097509750975097509792505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e746578740000000000000060448201526064016105fb565b5f5b81811015610997575f83838381811061084d5761084d610c47565b905060200281019061085f9190610e2d565b61086d906020810190610e69565b90505f84848481811061088257610882610c47565b90506020028101906108949190610e2d565b602001359050365f8686868181106108ae576108ae610c47565b90506020028101906108c09190610e2d565b6108ce906040810190610e84565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361096b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e000000000060448201526064016105fb565b604051818382375f5f838387895af1610986573d5f5f3e3d5ffd5b505060019093019250610832915050565b50505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156109ed576109ed61099d565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a3a57610a3a61099d565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610a63575f5ffd5b50565b8035610a7181610a42565b919050565b5f5f83601f840112610a86575f5ffd5b50813567ffffffffffffffff811115610a9d575f5ffd5b6020830191508360208260051b8501011115610ab7575f5ffd5b9250929050565b5f5f5f5f5f5f5f878903610100811215610ad6575f5ffd5b6060811215610ae3575f5ffd5b50610aec6109ca565b8835610af781610a42565b81526020890135610b0781610a42565b60208201526040890135610b1a81610a42565b60408201529650610b2d60608901610a66565b9550610b3b60808901610a66565b945060a0880135935060c0880135925060e088013567ffffffffffffffff811115610b64575f5ffd5b610b708a828b01610a76565b989b979a50959850939692959293505050565b858152846020820152836040820152821515606082015260a060808201525f82518060a08401525f5b81811015610bc957602081860181015160c0868401015201610bac565b505f60c0828501015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509695505050505050565b5f60208284031215610c1a575f5ffd5b5051919050565b5f60208284031215610c31575f5ffd5b81518015158114610c40575f5ffd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040820173ffffffffffffffffffffffffffffffffffffffff85168352604060208401528084518083526060850191506020860192505f5b81811015610ce157835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101610cad565b50909695505050505050565b5f60208284031215610cfd575f5ffd5b815167ffffffffffffffff811115610d13575f5ffd5b8201601f81018413610d23575f5ffd5b805167ffffffffffffffff811115610d3d57610d3d61099d565b8060051b610d4d602082016109f3565b91825260208184018101929081019087841115610d68575f5ffd5b6020850194505b83851015610d8e57845180835260209586019590935090910190610d6f565b979650505050505050565b602080825282518282018190525f918401906040840190835b81811015610e2257835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff6020820151166020850152604081015160408501526060810151606085015250608083019250602084019350600181019050610db2565b509095945050505050565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610e5f575f5ffd5b9190910192915050565b5f60208284031215610e79575f5ffd5b8135610c4081610a42565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610eb7575f5ffd5b83018035915067ffffffffffffffff821115610ed1575f5ffd5b602001915036819003821315610ab7575f5ffdfea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x0E\xF2\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c\xF8\x8C\xF6\xDB\x14a\0-W[__\xFD[a\0@a\0;6`\x04a\n\xBEV[a\0ZV[`@Qa\0Q\x95\x94\x93\x92\x91\x90a\x0B\x83V[`@Q\x80\x91\x03\x90\xF3[____``a\0k\x8C\x88\x88a\x07\xB0V[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x88\x03a\x01\xC6W`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8C\x81\x16`\x04\x83\x01R\x8B\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xFCW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01 \x91\x90a\x0C\nV[` \x8D\x01Q`@Q\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8E\x81\x16`\x04\x83\x01R\x91\x82\x16`$\x82\x01R\x91\x96P\x8B\x16\x90c\xDDb\xED>\x90`D\x01[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\x9BW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xBF\x91\x90a\x0C\nV[\x93Pa\x06\x04V[\x7F\xAB\xEE;s7:\xCDX:\x13\t$\xAA\xD6\xDC8\xCF\xDCD\xBA\x05U\xBA\x94\xCE/\xF69\x80\xEA\x062\x88\x03a\x03\x89W`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8C\x81\x16`\x04\x83\x01R\x8B\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02WW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x02{\x91\x90a\x0C\nV[`@\x80\x8E\x01Q` \x8F\x01Q\x91Q\x7F\xFE\xC9\rr\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8F\x81\x16`\x04\x83\x01R\x92\x83\x16`$\x82\x01R\x92\x97P\x16\x90c\xFE\xC9\rr\x90`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\xF9W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03\x1D\x91\x90a\x0C!V[a\x03'W_a\x01\xBFV[`@\x8C\x81\x01Q\x90Q\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8D\x81\x16`\x04\x83\x01R\x91\x82\x16`$\x82\x01R\x90\x8B\x16\x90c\xDDb\xED>\x90`D\x01a\x01\x80V[\x7FJ\xC9\x9A\xCE\x14\xEE\n^\xF92\xDC`\x9D\xF0\x94:\xB7\xAC\x16\xB7X64a/\x8D\xC3ZB\x89\xA6\xCE\x88\x03a\x05\x9DW`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R_\x91` \x80\x83\x01\x90\x806\x837\x01\x90PP\x90P\x8A\x81_\x81Q\x81\x10a\x03\xE4Wa\x03\xE4a\x0CGV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16` \x91\x82\x02\x92\x90\x92\x01\x01R`@\x80\x8F\x01Q\x90Q\x7F\x0FZn\xFA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16\x90c\x0FZn\xFA\x90a\x04K\x90\x8F\x90\x85\x90`\x04\x01a\x0CtV[_`@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x04eW=__>=_\xFD[PPPP`@Q=_\x82>`\x1F=\x90\x81\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x82\x01`@Ra\x04\xAA\x91\x90\x81\x01\x90a\x0C\xEDV[_\x81Q\x81\x10a\x04\xBBWa\x04\xBBa\x0CGV[` \x02` \x01\x01Q\x95P\x8C`@\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xFE\xC9\rr\x8D\x8F` \x01Q`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x05*\x92\x91\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16\x81R\x91\x16` \x82\x01R`@\x01\x90V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05EW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05i\x91\x90a\x0C!V[a\x05sW_a\x05\x95V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF[\x94PPa\x06\x04V[`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7Finvalid token source\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x83\x85\x11\x15a\x06\x12W\x83a\x06\x14V[\x84[`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R\x91\x94P_\x91\x90\x81` \x01[`@\x80Q`\x80\x81\x01\x82R_\x80\x82R` \x80\x83\x01\x82\x90R\x92\x82\x01\x81\x90R``\x82\x01R\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x01\x91\x01\x81a\x06.W\x90PP\x90P`@Q\x80`\x80\x01`@R\x80\x8Ds\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8B_\x03a\x06\xD1W\x85a\x06\xD3V[\x8B[\x81R` \x01\x8A\x81RP\x81_\x81Q\x81\x10a\x06\xEEWa\x06\xEEa\x0CGV[` \x02` \x01\x01\x81\x90RP\x8C` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c}\x10\xD1\x1F\x82`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x076\x91\x90a\r\x99V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x07MW__\xFD[PZ\xF1\x92PPP\x80\x15a\x07^WP`\x01[a\x07\x9BW=\x80\x80\x15a\x07\x8BW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x07\x90V[``\x91P[P_\x93P\x91Pa\x07\xA0V[`\x01\x92P[P\x97P\x97P\x97P\x97P\x97\x92PPPV[\x82Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x160\x14a\x080W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7Fincorrect calling context\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x05\xFBV[_[\x81\x81\x10\x15a\t\x97W_\x83\x83\x83\x81\x81\x10a\x08MWa\x08Ma\x0CGV[\x90P` \x02\x81\x01\x90a\x08_\x91\x90a\x0E-V[a\x08m\x90` \x81\x01\x90a\x0EiV[\x90P_\x84\x84\x84\x81\x81\x10a\x08\x82Wa\x08\x82a\x0CGV[\x90P` \x02\x81\x01\x90a\x08\x94\x91\x90a\x0E-V[` \x015\x90P6_\x86\x86\x86\x81\x81\x10a\x08\xAEWa\x08\xAEa\x0CGV[\x90P` \x02\x81\x01\x90a\x08\xC0\x91\x90a\x0E-V[a\x08\xCE\x90`@\x81\x01\x90a\x0E\x84V[\x91P\x91P\x87` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03a\tkW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FGPv2: forbidden interaction\0\0\0\0\0`D\x82\x01R`d\x01a\x05\xFBV[`@Q\x81\x83\x827__\x83\x83\x87\x89Z\xF1a\t\x86W=__>=_\xFD[PP`\x01\x90\x93\x01\x92Pa\x082\x91PPV[PPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\t\xEDWa\t\xEDa\t\x9DV[`@R\x90V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\n:Wa\n:a\t\x9DV[`@R\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\ncW__\xFD[PV[\x805a\nq\x81a\nBV[\x91\x90PV[__\x83`\x1F\x84\x01\x12a\n\x86W__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\x9DW__\xFD[` \x83\x01\x91P\x83` \x82`\x05\x1B\x85\x01\x01\x11\x15a\n\xB7W__\xFD[\x92P\x92\x90PV[_______\x87\x89\x03a\x01\0\x81\x12\x15a\n\xD6W__\xFD[``\x81\x12\x15a\n\xE3W__\xFD[Pa\n\xECa\t\xCAV[\x885a\n\xF7\x81a\nBV[\x81R` \x89\x015a\x0B\x07\x81a\nBV[` \x82\x01R`@\x89\x015a\x0B\x1A\x81a\nBV[`@\x82\x01R\x96Pa\x0B-``\x89\x01a\nfV[\x95Pa\x0B;`\x80\x89\x01a\nfV[\x94P`\xA0\x88\x015\x93P`\xC0\x88\x015\x92P`\xE0\x88\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x0BdW__\xFD[a\x0Bp\x8A\x82\x8B\x01a\nvV[\x98\x9B\x97\x9AP\x95\x98P\x93\x96\x92\x95\x92\x93PPPV[\x85\x81R\x84` \x82\x01R\x83`@\x82\x01R\x82\x15\x15``\x82\x01R`\xA0`\x80\x82\x01R_\x82Q\x80`\xA0\x84\x01R_[\x81\x81\x10\x15a\x0B\xC9W` \x81\x86\x01\x81\x01Q`\xC0\x86\x84\x01\x01R\x01a\x0B\xACV[P_`\xC0\x82\x85\x01\x01R`\xC0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x84\x01\x01\x91PP\x96\x95PPPPPPV[_` \x82\x84\x03\x12\x15a\x0C\x1AW__\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a\x0C1W__\xFD[\x81Q\x80\x15\x15\x81\x14a\x0C@W__\xFD[\x93\x92PPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[_`@\x82\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x83R`@` \x84\x01R\x80\x84Q\x80\x83R``\x85\x01\x91P` \x86\x01\x92P_[\x81\x81\x10\x15a\x0C\xE1W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83R` \x93\x84\x01\x93\x90\x92\x01\x91`\x01\x01a\x0C\xADV[P\x90\x96\x95PPPPPPV[_` \x82\x84\x03\x12\x15a\x0C\xFDW__\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r\x13W__\xFD[\x82\x01`\x1F\x81\x01\x84\x13a\r#W__\xFD[\x80Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r=Wa\r=a\t\x9DV[\x80`\x05\x1Ba\rM` \x82\x01a\t\xF3V[\x91\x82R` \x81\x84\x01\x81\x01\x92\x90\x81\x01\x90\x87\x84\x11\x15a\rhW__\xFD[` \x85\x01\x94P[\x83\x85\x10\x15a\r\x8EW\x84Q\x80\x83R` \x95\x86\x01\x95\x90\x93P\x90\x91\x01\x90a\roV[\x97\x96PPPPPPPV[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R_\x91\x84\x01\x90`@\x84\x01\x90\x83[\x81\x81\x10\x15a\x0E\"W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81Q\x16\x84Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x82\x01Q\x16` \x85\x01R`@\x81\x01Q`@\x85\x01R``\x81\x01Q``\x85\x01RP`\x80\x83\x01\x92P` \x84\x01\x93P`\x01\x81\x01\x90Pa\r\xB2V[P\x90\x95\x94PPPPPV[_\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xA1\x836\x03\x01\x81\x12a\x0E_W__\xFD[\x91\x90\x91\x01\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x0EyW__\xFD[\x815a\x0C@\x81a\nBV[__\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x0E\xB7W__\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x0E\xD1W__\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\n\xB7W__\xFD\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063f88cf6db1461002d575b5f5ffd5b61004061003b366004610abe565b61005a565b604051610051959493929190610b83565b60405180910390f35b5f5f5f5f606061006b8c88886107b0565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc988036101c6576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa1580156100fc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101209190610c0a565b60208d01516040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e8116600483015291821660248201529196508b169063dd62ed3e906044015b602060405180830381865afa15801561019b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101bf9190610c0a565b9350610604565b7fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328803610389576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528b16906370a0823190602401602060405180830381865afa158015610257573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027b9190610c0a565b6040808e015160208f015191517ffec90d7200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8f811660048301529283166024820152929750169063fec90d7290604401602060405180830381865afa1580156102f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061031d9190610c21565b610327575f6101bf565b60408c81015190517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d811660048301529182166024820152908b169063dd62ed3e90604401610180565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce880361059d576040805160018082528183019092525f91602080830190803683370190505090508a815f815181106103e4576103e4610c47565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040808f015190517f0f5a6efa000000000000000000000000000000000000000000000000000000008152911690630f5a6efa9061044b908f908590600401610c74565b5f60405180830381865afa158015610465573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104aa9190810190610ced565b5f815181106104bb576104bb610c47565b602002602001015195508c6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728d8f602001516040518363ffffffff1660e01b815260040161052a92919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b602060405180830381865afa158015610545573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105699190610c21565b610573575f610595565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b945050610604565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c696420746f6b656e20736f7572636500000000000000000000000060448201526064015b60405180910390fd5b838511156106125783610614565b845b6040805160018082528183019092529194505f9190816020015b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161062e57905050905060405180608001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b5f036106d157856106d3565b8b5b81526020018a815250815f815181106106ee576106ee610c47565b60200260200101819052508c6020015173ffffffffffffffffffffffffffffffffffffffff16637d10d11f826040518263ffffffff1660e01b81526004016107369190610d99565b5f604051808303815f87803b15801561074d575f5ffd5b505af192505050801561075e575060015b61079b573d80801561078b576040519150601f19603f3d011682016040523d82523d5f602084013e610790565b606091505b505f935091506107a0565b600192505b5097509750975097509792505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e746578740000000000000060448201526064016105fb565b5f5b81811015610997575f83838381811061084d5761084d610c47565b905060200281019061085f9190610e2d565b61086d906020810190610e69565b90505f84848481811061088257610882610c47565b90506020028101906108949190610e2d565b602001359050365f8686868181106108ae576108ae610c47565b90506020028101906108c09190610e2d565b6108ce906040810190610e84565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361096b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e000000000060448201526064016105fb565b604051818382375f5f838387895af1610986573d5f5f3e3d5ffd5b505060019093019250610832915050565b50505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156109ed576109ed61099d565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a3a57610a3a61099d565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610a63575f5ffd5b50565b8035610a7181610a42565b919050565b5f5f83601f840112610a86575f5ffd5b50813567ffffffffffffffff811115610a9d575f5ffd5b6020830191508360208260051b8501011115610ab7575f5ffd5b9250929050565b5f5f5f5f5f5f5f878903610100811215610ad6575f5ffd5b6060811215610ae3575f5ffd5b50610aec6109ca565b8835610af781610a42565b81526020890135610b0781610a42565b60208201526040890135610b1a81610a42565b60408201529650610b2d60608901610a66565b9550610b3b60808901610a66565b945060a0880135935060c0880135925060e088013567ffffffffffffffff811115610b64575f5ffd5b610b708a828b01610a76565b989b979a50959850939692959293505050565b858152846020820152836040820152821515606082015260a060808201525f82518060a08401525f5b81811015610bc957602081860181015160c0868401015201610bac565b505f60c0828501015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509695505050505050565b5f60208284031215610c1a575f5ffd5b5051919050565b5f60208284031215610c31575f5ffd5b81518015158114610c40575f5ffd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040820173ffffffffffffffffffffffffffffffffffffffff85168352604060208401528084518083526060850191506020860192505f5b81811015610ce157835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101610cad565b50909695505050505050565b5f60208284031215610cfd575f5ffd5b815167ffffffffffffffff811115610d13575f5ffd5b8201601f81018413610d23575f5ffd5b805167ffffffffffffffff811115610d3d57610d3d61099d565b8060051b610d4d602082016109f3565b91825260208184018101929081019087841115610d68575f5ffd5b6020850194505b83851015610d8e57845180835260209586019590935090910190610d6f565b979650505050505050565b602080825282518282018190525f918401906040840190835b81811015610e2257835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff6020820151166020850152604081015160408501526060810151606085015250608083019250602084019350600181019050610db2565b509095945050505050565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610e5f575f5ffd5b9190910192915050565b5f60208284031215610e79575f5ffd5b8135610c4081610a42565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610eb7575f5ffd5b83018035915067ffffffffffffffff821115610ed1575f5ffd5b602001915036819003821315610ab7575f5ffdfea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c\xF8\x8C\xF6\xDB\x14a\0-W[__\xFD[a\0@a\0;6`\x04a\n\xBEV[a\0ZV[`@Qa\0Q\x95\x94\x93\x92\x91\x90a\x0B\x83V[`@Q\x80\x91\x03\x90\xF3[____``a\0k\x8C\x88\x88a\x07\xB0V[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x88\x03a\x01\xC6W`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8C\x81\x16`\x04\x83\x01R\x8B\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xFCW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01 \x91\x90a\x0C\nV[` \x8D\x01Q`@Q\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8E\x81\x16`\x04\x83\x01R\x91\x82\x16`$\x82\x01R\x91\x96P\x8B\x16\x90c\xDDb\xED>\x90`D\x01[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\x9BW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xBF\x91\x90a\x0C\nV[\x93Pa\x06\x04V[\x7F\xAB\xEE;s7:\xCDX:\x13\t$\xAA\xD6\xDC8\xCF\xDCD\xBA\x05U\xBA\x94\xCE/\xF69\x80\xEA\x062\x88\x03a\x03\x89W`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8C\x81\x16`\x04\x83\x01R\x8B\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02WW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x02{\x91\x90a\x0C\nV[`@\x80\x8E\x01Q` \x8F\x01Q\x91Q\x7F\xFE\xC9\rr\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8F\x81\x16`\x04\x83\x01R\x92\x83\x16`$\x82\x01R\x92\x97P\x16\x90c\xFE\xC9\rr\x90`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\xF9W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03\x1D\x91\x90a\x0C!V[a\x03'W_a\x01\xBFV[`@\x8C\x81\x01Q\x90Q\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8D\x81\x16`\x04\x83\x01R\x91\x82\x16`$\x82\x01R\x90\x8B\x16\x90c\xDDb\xED>\x90`D\x01a\x01\x80V[\x7FJ\xC9\x9A\xCE\x14\xEE\n^\xF92\xDC`\x9D\xF0\x94:\xB7\xAC\x16\xB7X64a/\x8D\xC3ZB\x89\xA6\xCE\x88\x03a\x05\x9DW`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R_\x91` \x80\x83\x01\x90\x806\x837\x01\x90PP\x90P\x8A\x81_\x81Q\x81\x10a\x03\xE4Wa\x03\xE4a\x0CGV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16` \x91\x82\x02\x92\x90\x92\x01\x01R`@\x80\x8F\x01Q\x90Q\x7F\x0FZn\xFA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16\x90c\x0FZn\xFA\x90a\x04K\x90\x8F\x90\x85\x90`\x04\x01a\x0CtV[_`@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x04eW=__>=_\xFD[PPPP`@Q=_\x82>`\x1F=\x90\x81\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x82\x01`@Ra\x04\xAA\x91\x90\x81\x01\x90a\x0C\xEDV[_\x81Q\x81\x10a\x04\xBBWa\x04\xBBa\x0CGV[` \x02` \x01\x01Q\x95P\x8C`@\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xFE\xC9\rr\x8D\x8F` \x01Q`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x05*\x92\x91\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16\x81R\x91\x16` \x82\x01R`@\x01\x90V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05EW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05i\x91\x90a\x0C!V[a\x05sW_a\x05\x95V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF[\x94PPa\x06\x04V[`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7Finvalid token source\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x83\x85\x11\x15a\x06\x12W\x83a\x06\x14V[\x84[`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R\x91\x94P_\x91\x90\x81` \x01[`@\x80Q`\x80\x81\x01\x82R_\x80\x82R` \x80\x83\x01\x82\x90R\x92\x82\x01\x81\x90R``\x82\x01R\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x01\x91\x01\x81a\x06.W\x90PP\x90P`@Q\x80`\x80\x01`@R\x80\x8Ds\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8B_\x03a\x06\xD1W\x85a\x06\xD3V[\x8B[\x81R` \x01\x8A\x81RP\x81_\x81Q\x81\x10a\x06\xEEWa\x06\xEEa\x0CGV[` \x02` \x01\x01\x81\x90RP\x8C` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c}\x10\xD1\x1F\x82`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x076\x91\x90a\r\x99V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x07MW__\xFD[PZ\xF1\x92PPP\x80\x15a\x07^WP`\x01[a\x07\x9BW=\x80\x80\x15a\x07\x8BW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x07\x90V[``\x91P[P_\x93P\x91Pa\x07\xA0V[`\x01\x92P[P\x97P\x97P\x97P\x97P\x97\x92PPPV[\x82Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x160\x14a\x080W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7Fincorrect calling context\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x05\xFBV[_[\x81\x81\x10\x15a\t\x97W_\x83\x83\x83\x81\x81\x10a\x08MWa\x08Ma\x0CGV[\x90P` \x02\x81\x01\x90a\x08_\x91\x90a\x0E-V[a\x08m\x90` \x81\x01\x90a\x0EiV[\x90P_\x84\x84\x84\x81\x81\x10a\x08\x82Wa\x08\x82a\x0CGV[\x90P` \x02\x81\x01\x90a\x08\x94\x91\x90a\x0E-V[` \x015\x90P6_\x86\x86\x86\x81\x81\x10a\x08\xAEWa\x08\xAEa\x0CGV[\x90P` \x02\x81\x01\x90a\x08\xC0\x91\x90a\x0E-V[a\x08\xCE\x90`@\x81\x01\x90a\x0E\x84V[\x91P\x91P\x87` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03a\tkW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FGPv2: forbidden interaction\0\0\0\0\0`D\x82\x01R`d\x01a\x05\xFBV[`@Q\x81\x83\x827__\x83\x83\x87\x89Z\xF1a\t\x86W=__>=_\xFD[PP`\x01\x90\x93\x01\x92Pa\x082\x91PPV[PPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\t\xEDWa\t\xEDa\t\x9DV[`@R\x90V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\n:Wa\n:a\t\x9DV[`@R\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\ncW__\xFD[PV[\x805a\nq\x81a\nBV[\x91\x90PV[__\x83`\x1F\x84\x01\x12a\n\x86W__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\x9DW__\xFD[` \x83\x01\x91P\x83` \x82`\x05\x1B\x85\x01\x01\x11\x15a\n\xB7W__\xFD[\x92P\x92\x90PV[_______\x87\x89\x03a\x01\0\x81\x12\x15a\n\xD6W__\xFD[``\x81\x12\x15a\n\xE3W__\xFD[Pa\n\xECa\t\xCAV[\x885a\n\xF7\x81a\nBV[\x81R` \x89\x015a\x0B\x07\x81a\nBV[` \x82\x01R`@\x89\x015a\x0B\x1A\x81a\nBV[`@\x82\x01R\x96Pa\x0B-``\x89\x01a\nfV[\x95Pa\x0B;`\x80\x89\x01a\nfV[\x94P`\xA0\x88\x015\x93P`\xC0\x88\x015\x92P`\xE0\x88\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x0BdW__\xFD[a\x0Bp\x8A\x82\x8B\x01a\nvV[\x98\x9B\x97\x9AP\x95\x98P\x93\x96\x92\x95\x92\x93PPPV[\x85\x81R\x84` \x82\x01R\x83`@\x82\x01R\x82\x15\x15``\x82\x01R`\xA0`\x80\x82\x01R_\x82Q\x80`\xA0\x84\x01R_[\x81\x81\x10\x15a\x0B\xC9W` \x81\x86\x01\x81\x01Q`\xC0\x86\x84\x01\x01R\x01a\x0B\xACV[P_`\xC0\x82\x85\x01\x01R`\xC0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x84\x01\x01\x91PP\x96\x95PPPPPPV[_` \x82\x84\x03\x12\x15a\x0C\x1AW__\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a\x0C1W__\xFD[\x81Q\x80\x15\x15\x81\x14a\x0C@W__\xFD[\x93\x92PPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[_`@\x82\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x83R`@` \x84\x01R\x80\x84Q\x80\x83R``\x85\x01\x91P` \x86\x01\x92P_[\x81\x81\x10\x15a\x0C\xE1W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83R` \x93\x84\x01\x93\x90\x92\x01\x91`\x01\x01a\x0C\xADV[P\x90\x96\x95PPPPPPV[_` \x82\x84\x03\x12\x15a\x0C\xFDW__\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r\x13W__\xFD[\x82\x01`\x1F\x81\x01\x84\x13a\r#W__\xFD[\x80Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r=Wa\r=a\t\x9DV[\x80`\x05\x1Ba\rM` \x82\x01a\t\xF3V[\x91\x82R` \x81\x84\x01\x81\x01\x92\x90\x81\x01\x90\x87\x84\x11\x15a\rhW__\xFD[` \x85\x01\x94P[\x83\x85\x10\x15a\r\x8EW\x84Q\x80\x83R` \x95\x86\x01\x95\x90\x93P\x90\x91\x01\x90a\roV[\x97\x96PPPPPPPV[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R_\x91\x84\x01\x90`@\x84\x01\x90\x83[\x81\x81\x10\x15a\x0E\"W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81Q\x16\x84Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x82\x01Q\x16` \x85\x01R`@\x81\x01Q`@\x85\x01R``\x81\x01Q``\x85\x01RP`\x80\x83\x01\x92P` \x84\x01\x93P`\x01\x81\x01\x90Pa\r\xB2V[P\x90\x95\x94PPPPPV[_\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xA1\x836\x03\x01\x81\x12a\x0E_W__\xFD[\x91\x90\x91\x01\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x0EyW__\xFD[\x815a\x0C@\x81a\nBV[__\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x0E\xB7W__\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x0E\xD1W__\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\n\xB7W__\xFD\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Contracts { address settlement; address vaultRelayer; address vault; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Contracts { + #[allow(missing_docs)] + pub settlement: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub vaultRelayer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub vault: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Contracts) -> Self { + (value.settlement, value.vaultRelayer, value.vault) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Contracts { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + settlement: tuple.0, + vaultRelayer: tuple.1, + vault: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Contracts { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Contracts { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.settlement, + ), + ::tokenize( + &self.vaultRelayer, + ), + ::tokenize( + &self.vault, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Contracts { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Contracts { + const NAME: &'static str = "Contracts"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Contracts(address settlement,address vaultRelayer,address vault)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.settlement, + ) + .0, + ::eip712_data_word( + &self.vaultRelayer, + ) + .0, + ::eip712_data_word( + &self.vault, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Contracts { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.settlement, + ) + + ::topic_preimage_length( + &rust.vaultRelayer, + ) + + ::topic_preimage_length( + &rust.vault, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.settlement, + out, + ); + ::encode_topic_preimage( + &rust.vaultRelayer, + out, + ); + ::encode_topic_preimage( + &rust.vault, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Interaction { address target; uint256 value; bytes callData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Interaction { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub callData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Interaction) -> Self { + (value.target, value.value, value.callData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Interaction { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + value: tuple.1, + callData: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Interaction { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Interaction { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.target, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.callData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Interaction { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Interaction { + const NAME: &'static str = "Interaction"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Interaction(address target,uint256 value,bytes callData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.target, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.value) + .0, + ::eip712_data_word( + &self.callData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Interaction { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.target, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.value) + + ::topic_preimage_length( + &rust.callData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.target, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.value, + out, + ); + ::encode_topic_preimage( + &rust.callData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balance((address,address,address),address,address,uint256,bytes32,(address,uint256,bytes)[])` and selector `0xf88cf6db`. + ```solidity + function balance(Contracts memory contracts, address trader, address token, uint256 amount, bytes32 source, Interaction[] memory interactions) external returns (uint256 tokenBalance, uint256 allowance, uint256 effectiveBalance, bool canTransfer, bytes memory transferRevertReason); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceCall { + #[allow(missing_docs)] + pub contracts: ::RustType, + #[allow(missing_docs)] + pub trader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub source: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub interactions: + alloy_sol_types::private::Vec<::RustType>, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balance((address,address,address),address,address,uint256,bytes32, + /// (address,uint256,bytes)[])`](balanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceReturn { + #[allow(missing_docs)] + pub tokenBalance: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub allowance: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub effectiveBalance: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub canTransfer: bool, + #[allow(missing_docs)] + pub transferRevertReason: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + Contracts, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Array, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Vec<::RustType>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceCall) -> Self { + ( + value.contracts, + value.trader, + value.token, + value.amount, + value.source, + value.interactions, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + contracts: tuple.0, + trader: tuple.1, + token: tuple.2, + amount: tuple.3, + source: tuple.4, + interactions: tuple.5, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + bool, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceReturn) -> Self { + ( + value.tokenBalance, + value.allowance, + value.effectiveBalance, + value.canTransfer, + value.transferRevertReason, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenBalance: tuple.0, + allowance: tuple.1, + effectiveBalance: tuple.2, + canTransfer: tuple.3, + transferRevertReason: tuple.4, + } + } + } + } + impl balanceReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.tokenBalance, + ), + as alloy_sol_types::SolType>::tokenize( + &self.allowance, + ), + as alloy_sol_types::SolType>::tokenize( + &self.effectiveBalance, + ), + ::tokenize( + &self.canTransfer, + ), + ::tokenize( + &self.transferRevertReason, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceCall { + type Parameters<'a> = ( + Contracts, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Array, + ); + type Return = balanceReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Bytes, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 140u8, 246u8, 219u8]; + const SIGNATURE: &'static str = "balance((address,address,address),address,address,\ + uint256,bytes32,(address,uint256,bytes)[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize(&self.contracts), + ::tokenize( + &self.trader, + ), + ::tokenize( + &self.token, + ), + as alloy_sol_types::SolType>::tokenize(&self.amount), + as alloy_sol_types::SolType>::tokenize(&self.source), + as alloy_sol_types::SolType>::tokenize(&self.interactions), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + balanceReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`Balances`](self) function calls. + #[derive(Clone)] + pub enum BalancesCalls { + #[allow(missing_docs)] + balance(balanceCall), + } + impl BalancesCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[248u8, 140u8, 246u8, 219u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(balance)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BalancesCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 288usize; + const NAME: &'static str = "BalancesCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::balance(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[{ + fn balance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BalancesCalls::balance) + } + balance + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[{ + fn balance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BalancesCalls::balance) + } + balance + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::balance(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::balance(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Balances`](self) contract instance. + + See the [wrapper's documentation](`BalancesInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BalancesInstance { + BalancesInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + BalancesInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + BalancesInstance::::deploy_builder(__provider) + } + /**A [`Balances`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Balances`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BalancesInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BalancesInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BalancesInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BalancesInstance + { + /**Creates a new wrapper around an on-chain [`Balances`](self) contract instance. + + See the [wrapper's documentation](`BalancesInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BalancesInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BalancesInstance { + BalancesInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BalancesInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`balance`] function. + pub fn balance( + &self, + contracts: ::RustType, + trader: alloy_sol_types::private::Address, + token: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + source: alloy_sol_types::private::FixedBytes<32>, + interactions: alloy_sol_types::private::Vec< + ::RustType, + >, + ) -> alloy_contract::SolCallBuilder<&P, balanceCall, N> { + self.call_builder(&balanceCall { + contracts, + trader, + token, + amount, + source, + interactions, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BalancesInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = Balances::BalancesInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x88b4B74082BffB2976C306CB3f7E9093AE48B94F"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/baoswaprouter/Cargo.toml b/contracts/generated/contracts-generated/baoswaprouter/Cargo.toml new file mode 100644 index 0000000000..cbff1c8f69 --- /dev/null +++ b/contracts/generated/contracts-generated/baoswaprouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-baoswaprouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/baoswaprouter/src/lib.rs b/contracts/generated/contracts-generated/baoswaprouter/src/lib.rs new file mode 100644 index 0000000000..6e40aa5724 --- /dev/null +++ b/contracts/generated/contracts-generated/baoswaprouter/src/lib.rs @@ -0,0 +1,1578 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface BaoswapRouter { + function WETH() external pure returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external pure returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod BaoswapRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`BaoswapRouter`](self) function calls. + #[derive(Clone)] + pub enum BaoswapRouterCalls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl BaoswapRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for BaoswapRouterCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "BaoswapRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(BaoswapRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BaoswapRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BaoswapRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BaoswapRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(BaoswapRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BaoswapRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BaoswapRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BaoswapRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(BaoswapRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(BaoswapRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`BaoswapRouter`](self) contract instance. + + See the [wrapper's documentation](`BaoswapRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> BaoswapRouterInstance { + BaoswapRouterInstance::::new(address, __provider) + } + /**A [`BaoswapRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`BaoswapRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct BaoswapRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for BaoswapRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("BaoswapRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + BaoswapRouterInstance + { + /**Creates a new wrapper around an on-chain [`BaoswapRouter`](self) contract instance. + + See the [wrapper's documentation](`BaoswapRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl BaoswapRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> BaoswapRouterInstance { + BaoswapRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + BaoswapRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + BaoswapRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = BaoswapRouter::BaoswapRouterInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 100u64 => Some(( + ::alloy_primitives::address!("0x6093AeBAC87d62b1A5a4cEec91204e35020E38bE"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/chainalysisoracle/Cargo.toml b/contracts/generated/contracts-generated/chainalysisoracle/Cargo.toml new file mode 100644 index 0000000000..9d645d896d --- /dev/null +++ b/contracts/generated/contracts-generated/chainalysisoracle/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-chainalysisoracle" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/chainalysisoracle/src/lib.rs b/contracts/generated/contracts-generated/chainalysisoracle/src/lib.rs new file mode 100644 index 0000000000..525e28a420 --- /dev/null +++ b/contracts/generated/contracts-generated/chainalysisoracle/src/lib.rs @@ -0,0 +1,1800 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface ChainalysisOracle { + event NonSanctionedAddress(address indexed addr); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event SanctionedAddress(address indexed addr); + event SanctionedAddressesAdded(address[] addrs); + event SanctionedAddressesRemoved(address[] addrs); + + constructor(); + + function isSanctioned(address addr) external view returns (bool); + function name() external pure returns (string memory); + function owner() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isSanctioned", + "inputs": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "NonSanctionedAddress", + "inputs": [ + { + "name": "addr", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SanctionedAddress", + "inputs": [ + { + "name": "addr", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SanctionedAddressesAdded", + "inputs": [ + { + "name": "addrs", + "type": "address[]", + "indexed": false, + "internalType": "address[]" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SanctionedAddressesRemoved", + "inputs": [ + { + "name": "addrs", + "type": "address[]", + "indexed": false, + "internalType": "address[]" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ChainalysisOracle { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `NonSanctionedAddress(address)` and selector `0xd595018321fcb8c2bcbf5bfe4b27d74bea505825f7d195abe8517f94a065539c`. + ```solidity + event NonSanctionedAddress(address indexed addr); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct NonSanctionedAddress { + #[allow(missing_docs)] + pub addr: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for NonSanctionedAddress { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "NonSanctionedAddress(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 213u8, 149u8, 1u8, 131u8, 33u8, 252u8, 184u8, 194u8, 188u8, 191u8, 91u8, 254u8, + 75u8, 39u8, 215u8, 75u8, 234u8, 80u8, 88u8, 37u8, 247u8, 209u8, 149u8, 171u8, + 232u8, 81u8, 127u8, 148u8, 160u8, 101u8, 83u8, 156u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { addr: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.addr.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.addr, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for NonSanctionedAddress { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&NonSanctionedAddress> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &NonSanctionedAddress) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OwnershipTransferred(address,address)` and selector `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0`. + ```solidity + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OwnershipTransferred { + #[allow(missing_docs)] + pub previousOwner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub newOwner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OwnershipTransferred { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OwnershipTransferred(address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 139u8, 224u8, 7u8, 156u8, 83u8, 22u8, 89u8, 20u8, 19u8, 68u8, 205u8, 31u8, + 208u8, 164u8, 242u8, 132u8, 25u8, 73u8, 127u8, 151u8, 34u8, 163u8, 218u8, + 175u8, 227u8, 180u8, 24u8, 111u8, 107u8, 100u8, 87u8, 224u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + previousOwner: topics.1, + newOwner: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.previousOwner.clone(), + self.newOwner.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.previousOwner, + ); + out[2usize] = ::encode_topic( + &self.newOwner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OwnershipTransferred { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OwnershipTransferred> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OwnershipTransferred) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SanctionedAddress(address)` and selector `0x8027911123971054d93579ebea046c8461473fa4d2e510b9b49eed3bed3270e0`. + ```solidity + event SanctionedAddress(address indexed addr); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SanctionedAddress { + #[allow(missing_docs)] + pub addr: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SanctionedAddress { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SanctionedAddress(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 128u8, 39u8, 145u8, 17u8, 35u8, 151u8, 16u8, 84u8, 217u8, 53u8, 121u8, 235u8, + 234u8, 4u8, 108u8, 132u8, 97u8, 71u8, 63u8, 164u8, 210u8, 229u8, 16u8, 185u8, + 180u8, 158u8, 237u8, 59u8, 237u8, 50u8, 112u8, 224u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { addr: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.addr.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.addr, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SanctionedAddress { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SanctionedAddress> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SanctionedAddress) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SanctionedAddressesAdded(address[])` and selector `0x2596d7dd6966c5673f9c06ddb0564c4f0e6d8d206ea075b83ad9ddd71a4fb927`. + ```solidity + event SanctionedAddressesAdded(address[] addrs); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SanctionedAddressesAdded { + #[allow(missing_docs)] + pub addrs: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SanctionedAddressesAdded { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = + (alloy_sol_types::sol_data::Array,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SanctionedAddressesAdded(address[])"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 37u8, 150u8, 215u8, 221u8, 105u8, 102u8, 197u8, 103u8, 63u8, 156u8, 6u8, 221u8, + 176u8, 86u8, 76u8, 79u8, 14u8, 109u8, 141u8, 32u8, 110u8, 160u8, 117u8, 184u8, + 58u8, 217u8, 221u8, 215u8, 26u8, 79u8, 185u8, 39u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { addrs: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( as alloy_sol_types::SolType>::tokenize( + &self.addrs + ),) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SanctionedAddressesAdded { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SanctionedAddressesAdded> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SanctionedAddressesAdded) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SanctionedAddressesRemoved(address[])` and selector `0x32aab684eee99db715515d1a9987a8fe33bb6341b0e35e60db7eab48a08f9a3a`. + ```solidity + event SanctionedAddressesRemoved(address[] addrs); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SanctionedAddressesRemoved { + #[allow(missing_docs)] + pub addrs: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SanctionedAddressesRemoved { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = + (alloy_sol_types::sol_data::Array,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SanctionedAddressesRemoved(address[])"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 50u8, 170u8, 182u8, 132u8, 238u8, 233u8, 157u8, 183u8, 21u8, 81u8, 93u8, 26u8, + 153u8, 135u8, 168u8, 254u8, 51u8, 187u8, 99u8, 65u8, 176u8, 227u8, 94u8, 96u8, + 219u8, 126u8, 171u8, 72u8, 160u8, 143u8, 154u8, 58u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { addrs: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( as alloy_sol_types::SolType>::tokenize( + &self.addrs + ),) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SanctionedAddressesRemoved { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SanctionedAddressesRemoved> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SanctionedAddressesRemoved) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall {} + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isSanctioned(address)` and selector `0xdf592f7d`. + ```solidity + function isSanctioned(address addr) external view returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isSanctionedCall { + #[allow(missing_docs)] + pub addr: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isSanctioned(address)`](isSanctionedCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isSanctionedReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isSanctionedCall) -> Self { + (value.addr,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isSanctionedCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { addr: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isSanctionedReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isSanctionedReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isSanctionedCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [223u8, 89u8, 47u8, 125u8]; + const SIGNATURE: &'static str = "isSanctioned(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.addr, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isSanctionedReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isSanctionedReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external pure returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `owner()` and selector `0x8da5cb5b`. + ```solidity + function owner() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`owner()`](ownerCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for ownerCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [141u8, 165u8, 203u8, 91u8]; + const SIGNATURE: &'static str = "owner()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: ownerReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: ownerReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`ChainalysisOracle`](self) function calls. + #[derive(Clone)] + pub enum ChainalysisOracleCalls { + #[allow(missing_docs)] + isSanctioned(isSanctionedCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + owner(ownerCall), + } + impl ChainalysisOracleCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [141u8, 165u8, 203u8, 91u8], + [223u8, 89u8, 47u8, 125u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(owner), + ::core::stringify!(isSanctioned), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for ChainalysisOracleCalls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "ChainalysisOracleCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::isSanctioned(_) => ::SELECTOR, + Self::name(_) => ::SELECTOR, + Self::owner(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ChainalysisOracleCalls::name) + } + name + }, + { + fn owner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ChainalysisOracleCalls::owner) + } + owner + }, + { + fn isSanctioned( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(ChainalysisOracleCalls::isSanctioned) + } + isSanctioned + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + ChainalysisOracleCalls, + >] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ChainalysisOracleCalls::name) + } + name + }, + { + fn owner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ChainalysisOracleCalls::owner) + } + owner + }, + { + fn isSanctioned( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(ChainalysisOracleCalls::isSanctioned) + } + isSanctioned + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::isSanctioned(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::owner(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::isSanctioned(inner) => { + ::abi_encode_raw(inner, out) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::owner(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`ChainalysisOracle`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum ChainalysisOracleEvents { + #[allow(missing_docs)] + NonSanctionedAddress(NonSanctionedAddress), + #[allow(missing_docs)] + OwnershipTransferred(OwnershipTransferred), + #[allow(missing_docs)] + SanctionedAddress(SanctionedAddress), + #[allow(missing_docs)] + SanctionedAddressesAdded(SanctionedAddressesAdded), + #[allow(missing_docs)] + SanctionedAddressesRemoved(SanctionedAddressesRemoved), + } + impl ChainalysisOracleEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 37u8, 150u8, 215u8, 221u8, 105u8, 102u8, 197u8, 103u8, 63u8, 156u8, 6u8, 221u8, + 176u8, 86u8, 76u8, 79u8, 14u8, 109u8, 141u8, 32u8, 110u8, 160u8, 117u8, 184u8, + 58u8, 217u8, 221u8, 215u8, 26u8, 79u8, 185u8, 39u8, + ], + [ + 50u8, 170u8, 182u8, 132u8, 238u8, 233u8, 157u8, 183u8, 21u8, 81u8, 93u8, 26u8, + 153u8, 135u8, 168u8, 254u8, 51u8, 187u8, 99u8, 65u8, 176u8, 227u8, 94u8, 96u8, + 219u8, 126u8, 171u8, 72u8, 160u8, 143u8, 154u8, 58u8, + ], + [ + 128u8, 39u8, 145u8, 17u8, 35u8, 151u8, 16u8, 84u8, 217u8, 53u8, 121u8, 235u8, + 234u8, 4u8, 108u8, 132u8, 97u8, 71u8, 63u8, 164u8, 210u8, 229u8, 16u8, 185u8, + 180u8, 158u8, 237u8, 59u8, 237u8, 50u8, 112u8, 224u8, + ], + [ + 139u8, 224u8, 7u8, 156u8, 83u8, 22u8, 89u8, 20u8, 19u8, 68u8, 205u8, 31u8, 208u8, + 164u8, 242u8, 132u8, 25u8, 73u8, 127u8, 151u8, 34u8, 163u8, 218u8, 175u8, 227u8, + 180u8, 24u8, 111u8, 107u8, 100u8, 87u8, 224u8, + ], + [ + 213u8, 149u8, 1u8, 131u8, 33u8, 252u8, 184u8, 194u8, 188u8, 191u8, 91u8, 254u8, + 75u8, 39u8, 215u8, 75u8, 234u8, 80u8, 88u8, 37u8, 247u8, 209u8, 149u8, 171u8, + 232u8, 81u8, 127u8, 148u8, 160u8, 101u8, 83u8, 156u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(SanctionedAddressesAdded), + ::core::stringify!(SanctionedAddressesRemoved), + ::core::stringify!(SanctionedAddress), + ::core::stringify!(OwnershipTransferred), + ::core::stringify!(NonSanctionedAddress), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for ChainalysisOracleEvents { + const COUNT: usize = 5usize; + const NAME: &'static str = "ChainalysisOracleEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::NonSanctionedAddress) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::OwnershipTransferred) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::SanctionedAddress) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::SanctionedAddressesAdded) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::SanctionedAddressesRemoved) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ChainalysisOracleEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::NonSanctionedAddress(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OwnershipTransferred(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SanctionedAddress(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SanctionedAddressesAdded(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SanctionedAddressesRemoved(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::NonSanctionedAddress(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OwnershipTransferred(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SanctionedAddress(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SanctionedAddressesAdded(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SanctionedAddressesRemoved(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ChainalysisOracle`](self) contract instance. + + See the [wrapper's documentation](`ChainalysisOracleInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ChainalysisOracleInstance { + ChainalysisOracleInstance::::new(address, __provider) + } + /**A [`ChainalysisOracle`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ChainalysisOracle`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ChainalysisOracleInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ChainalysisOracleInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ChainalysisOracleInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ChainalysisOracleInstance + { + /**Creates a new wrapper around an on-chain [`ChainalysisOracle`](self) contract instance. + + See the [wrapper's documentation](`ChainalysisOracleInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ChainalysisOracleInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ChainalysisOracleInstance { + ChainalysisOracleInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ChainalysisOracleInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`isSanctioned`] function. + pub fn isSanctioned( + &self, + addr: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, isSanctionedCall, N> { + self.call_builder(&isSanctionedCall { addr }) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`owner`] function. + pub fn owner(&self) -> alloy_contract::SolCallBuilder<&P, ownerCall, N> { + self.call_builder(&ownerCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ChainalysisOracleInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`NonSanctionedAddress`] event. + pub fn NonSanctionedAddress_filter( + &self, + ) -> alloy_contract::Event<&P, NonSanctionedAddress, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OwnershipTransferred`] event. + pub fn OwnershipTransferred_filter( + &self, + ) -> alloy_contract::Event<&P, OwnershipTransferred, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SanctionedAddress`] event. + pub fn SanctionedAddress_filter(&self) -> alloy_contract::Event<&P, SanctionedAddress, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SanctionedAddressesAdded`] + /// event. + pub fn SanctionedAddressesAdded_filter( + &self, + ) -> alloy_contract::Event<&P, SanctionedAddressesAdded, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SanctionedAddressesRemoved`] + /// event. + pub fn SanctionedAddressesRemoved_filter( + &self, + ) -> alloy_contract::Event<&P, SanctionedAddressesRemoved, N> { + self.event_filter::() + } + } +} +pub type Instance = ChainalysisOracle::ChainalysisOracleInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x3A91A31cB3dC49b4db9Ce721F50a9D076c8D739B"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/counter/Cargo.toml b/contracts/generated/contracts-generated/counter/Cargo.toml new file mode 100644 index 0000000000..0a64b45896 --- /dev/null +++ b/contracts/generated/contracts-generated/counter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-counter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/counter/src/lib.rs b/contracts/generated/contracts-generated/counter/src/lib.rs new file mode 100644 index 0000000000..4815a41f7f --- /dev/null +++ b/contracts/generated/contracts-generated/counter/src/lib.rs @@ -0,0 +1,952 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface Counter { + function counters(string memory) external view returns (uint256); + function incrementCounter(string memory key) external; + function setCounterToBalance(string memory key, address token, address owner) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "counters", + "inputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "incrementCounter", + "inputs": [ + { + "name": "key", + "type": "string", + "internalType": "string" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setCounterToBalance", + "inputs": [ + { + "name": "key", + "type": "string", + "internalType": "string" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Counter { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b506103cd8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80630931831e1461004357806357cedf40146100585780639424c8c814610094575b5f5ffd5b6100566100513660046102ab565b6100a7565b005b610082610066366004610305565b80516020818301810180515f8252928201919093012091525481565b60405190815260200160405180910390f35b6100566100a2366004610305565b610159565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301528316906370a0823190602401602060405180830381865afa158015610111573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610135919061033f565b5f846040516101449190610356565b90815260405190819003602001902055505050565b60015f8260405161016a9190610356565b90815260200160405180910390205f8282546101869190610382565b909155505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126101ca575f5ffd5b813567ffffffffffffffff8111156101e4576101e461018e565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156102505761025061018e565b604052818152838201602001851015610267575f5ffd5b816020850160208301375f918101602001919091529392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146102a6575f5ffd5b919050565b5f5f5f606084860312156102bd575f5ffd5b833567ffffffffffffffff8111156102d3575f5ffd5b6102df868287016101bb565b9350506102ee60208501610283565b91506102fc60408501610283565b90509250925092565b5f60208284031215610315575f5ffd5b813567ffffffffffffffff81111561032b575f5ffd5b610337848285016101bb565b949350505050565b5f6020828403121561034f575f5ffd5b5051919050565b5f82515f5b81811015610375576020818601810151858301520161035b565b505f920191825250919050565b808201808211156103ba577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x03\xCD\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0?W_5`\xE0\x1C\x80c\t1\x83\x1E\x14a\0CW\x80cW\xCE\xDF@\x14a\0XW\x80c\x94$\xC8\xC8\x14a\0\x94W[__\xFD[a\0Va\0Q6`\x04a\x02\xABV[a\0\xA7V[\0[a\0\x82a\0f6`\x04a\x03\x05V[\x80Q` \x81\x83\x01\x81\x01\x80Q_\x82R\x92\x82\x01\x91\x90\x93\x01 \x91RT\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0Va\0\xA26`\x04a\x03\x05V[a\x01YV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x81\x16`\x04\x83\x01R\x83\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\x11W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x015\x91\x90a\x03?V[_\x84`@Qa\x01D\x91\x90a\x03VV[\x90\x81R`@Q\x90\x81\x90\x03` \x01\x90 UPPPV[`\x01_\x82`@Qa\x01j\x91\x90a\x03VV[\x90\x81R` \x01`@Q\x80\x91\x03\x90 _\x82\x82Ta\x01\x86\x91\x90a\x03\x82V[\x90\x91UPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[_\x82`\x1F\x83\x01\x12a\x01\xCAW__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x01\xE4Wa\x01\xE4a\x01\x8EV[`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`?\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x85\x01\x16\x01\x16\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x02PWa\x02Pa\x01\x8EV[`@R\x81\x81R\x83\x82\x01` \x01\x85\x10\x15a\x02gW__\xFD[\x81` \x85\x01` \x83\x017_\x91\x81\x01` \x01\x91\x90\x91R\x93\x92PPPV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02\xA6W__\xFD[\x91\x90PV[___``\x84\x86\x03\x12\x15a\x02\xBDW__\xFD[\x835g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x02\xD3W__\xFD[a\x02\xDF\x86\x82\x87\x01a\x01\xBBV[\x93PPa\x02\xEE` \x85\x01a\x02\x83V[\x91Pa\x02\xFC`@\x85\x01a\x02\x83V[\x90P\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x03\x15W__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x03+W__\xFD[a\x037\x84\x82\x85\x01a\x01\xBBV[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a\x03OW__\xFD[PQ\x91\x90PV[_\x82Q_[\x81\x81\x10\x15a\x03uW` \x81\x86\x01\x81\x01Q\x85\x83\x01R\x01a\x03[V[P_\x92\x01\x91\x82RP\x91\x90PV[\x80\x82\x01\x80\x82\x11\x15a\x03\xBAW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x92\x91PPV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80630931831e1461004357806357cedf40146100585780639424c8c814610094575b5f5ffd5b6100566100513660046102ab565b6100a7565b005b610082610066366004610305565b80516020818301810180515f8252928201919093012091525481565b60405190815260200160405180910390f35b6100566100a2366004610305565b610159565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301528316906370a0823190602401602060405180830381865afa158015610111573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610135919061033f565b5f846040516101449190610356565b90815260405190819003602001902055505050565b60015f8260405161016a9190610356565b90815260200160405180910390205f8282546101869190610382565b909155505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126101ca575f5ffd5b813567ffffffffffffffff8111156101e4576101e461018e565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156102505761025061018e565b604052818152838201602001851015610267575f5ffd5b816020850160208301375f918101602001919091529392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146102a6575f5ffd5b919050565b5f5f5f606084860312156102bd575f5ffd5b833567ffffffffffffffff8111156102d3575f5ffd5b6102df868287016101bb565b9350506102ee60208501610283565b91506102fc60408501610283565b90509250925092565b5f60208284031215610315575f5ffd5b813567ffffffffffffffff81111561032b575f5ffd5b610337848285016101bb565b949350505050565b5f6020828403121561034f575f5ffd5b5051919050565b5f82515f5b81811015610375576020818601810151858301520161035b565b505f920191825250919050565b808201808211156103ba577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0?W_5`\xE0\x1C\x80c\t1\x83\x1E\x14a\0CW\x80cW\xCE\xDF@\x14a\0XW\x80c\x94$\xC8\xC8\x14a\0\x94W[__\xFD[a\0Va\0Q6`\x04a\x02\xABV[a\0\xA7V[\0[a\0\x82a\0f6`\x04a\x03\x05V[\x80Q` \x81\x83\x01\x81\x01\x80Q_\x82R\x92\x82\x01\x91\x90\x93\x01 \x91RT\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0Va\0\xA26`\x04a\x03\x05V[a\x01YV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x81\x16`\x04\x83\x01R\x83\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\x11W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x015\x91\x90a\x03?V[_\x84`@Qa\x01D\x91\x90a\x03VV[\x90\x81R`@Q\x90\x81\x90\x03` \x01\x90 UPPPV[`\x01_\x82`@Qa\x01j\x91\x90a\x03VV[\x90\x81R` \x01`@Q\x80\x91\x03\x90 _\x82\x82Ta\x01\x86\x91\x90a\x03\x82V[\x90\x91UPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[_\x82`\x1F\x83\x01\x12a\x01\xCAW__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x01\xE4Wa\x01\xE4a\x01\x8EV[`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`?\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x85\x01\x16\x01\x16\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x02PWa\x02Pa\x01\x8EV[`@R\x81\x81R\x83\x82\x01` \x01\x85\x10\x15a\x02gW__\xFD[\x81` \x85\x01` \x83\x017_\x91\x81\x01` \x01\x91\x90\x91R\x93\x92PPPV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02\xA6W__\xFD[\x91\x90PV[___``\x84\x86\x03\x12\x15a\x02\xBDW__\xFD[\x835g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x02\xD3W__\xFD[a\x02\xDF\x86\x82\x87\x01a\x01\xBBV[\x93PPa\x02\xEE` \x85\x01a\x02\x83V[\x91Pa\x02\xFC`@\x85\x01a\x02\x83V[\x90P\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x03\x15W__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x03+W__\xFD[a\x037\x84\x82\x85\x01a\x01\xBBV[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a\x03OW__\xFD[PQ\x91\x90PV[_\x82Q_[\x81\x81\x10\x15a\x03uW` \x81\x86\x01\x81\x01Q\x85\x83\x01R\x01a\x03[V[P_\x92\x01\x91\x82RP\x91\x90PV[\x80\x82\x01\x80\x82\x11\x15a\x03\xBAW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x92\x91PPV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `counters(string)` and selector `0x57cedf40`. + ```solidity + function counters(string memory) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct countersCall(pub alloy_sol_types::private::String); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`counters(string)`](countersCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct countersReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: countersCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for countersCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: countersReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for countersReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for countersCall { + type Parameters<'a> = (alloy_sol_types::sol_data::String,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [87u8, 206u8, 223u8, 64u8]; + const SIGNATURE: &'static str = "counters(string)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: countersReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: countersReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `incrementCounter(string)` and selector `0x9424c8c8`. + ```solidity + function incrementCounter(string memory key) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct incrementCounterCall { + #[allow(missing_docs)] + pub key: alloy_sol_types::private::String, + } + ///Container type for the return parameters of the + /// [`incrementCounter(string)`](incrementCounterCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct incrementCounterReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: incrementCounterCall) -> Self { + (value.key,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for incrementCounterCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { key: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: incrementCounterReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for incrementCounterReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl incrementCounterReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for incrementCounterCall { + type Parameters<'a> = (alloy_sol_types::sol_data::String,); + type Return = incrementCounterReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [148u8, 36u8, 200u8, 200u8]; + const SIGNATURE: &'static str = "incrementCounter(string)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.key, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + incrementCounterReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `setCounterToBalance(string,address,address)` and selector `0x0931831e`. + ```solidity + function setCounterToBalance(string memory key, address token, address owner) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setCounterToBalanceCall { + #[allow(missing_docs)] + pub key: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`setCounterToBalance(string,address,address)`](setCounterToBalanceCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setCounterToBalanceReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setCounterToBalanceCall) -> Self { + (value.key, value.token, value.owner) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setCounterToBalanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + key: tuple.0, + token: tuple.1, + owner: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setCounterToBalanceReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setCounterToBalanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl setCounterToBalanceReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> + { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for setCounterToBalanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = setCounterToBalanceReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 49u8, 131u8, 30u8]; + const SIGNATURE: &'static str = "setCounterToBalance(string,address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.key, + ), + ::tokenize( + &self.token, + ), + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + setCounterToBalanceReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`Counter`](self) function calls. + #[derive(Clone)] + pub enum CounterCalls { + #[allow(missing_docs)] + counters(countersCall), + #[allow(missing_docs)] + incrementCounter(incrementCounterCall), + #[allow(missing_docs)] + setCounterToBalance(setCounterToBalanceCall), + } + impl CounterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [9u8, 49u8, 131u8, 30u8], + [87u8, 206u8, 223u8, 64u8], + [148u8, 36u8, 200u8, 200u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(setCounterToBalance), + ::core::stringify!(counters), + ::core::stringify!(incrementCounter), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CounterCalls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 64usize; + const NAME: &'static str = "CounterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::counters(_) => ::SELECTOR, + Self::incrementCounter(_) => { + ::SELECTOR + } + Self::setCounterToBalance(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn setCounterToBalance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CounterCalls::setCounterToBalance) + } + setCounterToBalance + }, + { + fn counters(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CounterCalls::counters) + } + counters + }, + { + fn incrementCounter(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CounterCalls::incrementCounter) + } + incrementCounter + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn setCounterToBalance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CounterCalls::setCounterToBalance) + } + setCounterToBalance + }, + { + fn counters(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CounterCalls::counters) + } + counters + }, + { + fn incrementCounter(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CounterCalls::incrementCounter) + } + incrementCounter + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::counters(inner) => { + ::abi_encoded_size(inner) + } + Self::incrementCounter(inner) => { + ::abi_encoded_size(inner) + } + Self::setCounterToBalance(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::counters(inner) => { + ::abi_encode_raw(inner, out) + } + Self::incrementCounter(inner) => { + ::abi_encode_raw(inner, out) + } + Self::setCounterToBalance(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Counter`](self) contract instance. + + See the [wrapper's documentation](`CounterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CounterInstance { + CounterInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + CounterInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + CounterInstance::::deploy_builder(__provider) + } + /**A [`Counter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Counter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CounterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CounterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CounterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CounterInstance + { + /**Creates a new wrapper around an on-chain [`Counter`](self) contract instance. + + See the [wrapper's documentation](`CounterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CounterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CounterInstance { + CounterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CounterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`counters`] function. + pub fn counters( + &self, + _0: alloy_sol_types::private::String, + ) -> alloy_contract::SolCallBuilder<&P, countersCall, N> { + self.call_builder(&countersCall(_0)) + } + + ///Creates a new call builder for the [`incrementCounter`] function. + pub fn incrementCounter( + &self, + key: alloy_sol_types::private::String, + ) -> alloy_contract::SolCallBuilder<&P, incrementCounterCall, N> { + self.call_builder(&incrementCounterCall { key }) + } + + ///Creates a new call builder for the [`setCounterToBalance`] function. + pub fn setCounterToBalance( + &self, + key: alloy_sol_types::private::String, + token: alloy_sol_types::private::Address, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, setCounterToBalanceCall, N> { + self.call_builder(&setCounterToBalanceCall { key, token, owner }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CounterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = Counter::CounterInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/cowamm/Cargo.toml b/contracts/generated/contracts-generated/cowamm/Cargo.toml new file mode 100644 index 0000000000..5d4ed709e9 --- /dev/null +++ b/contracts/generated/contracts-generated/cowamm/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowamm" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowamm/src/lib.rs b/contracts/generated/contracts-generated/cowamm/src/lib.rs new file mode 100644 index 0000000000..455d577e4b --- /dev/null +++ b/contracts/generated/contracts-generated/cowamm/src/lib.rs @@ -0,0 +1,4430 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library ConstantProduct { + struct TradingParams { uint256 minTradedToken0; address priceOracle; bytes priceOracleData; bytes32 appData; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ConstantProduct { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct TradingParams { uint256 minTradedToken0; address priceOracle; bytes priceOracleData; bytes32 appData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct TradingParams { + #[allow(missing_docs)] + pub minTradedToken0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub priceOracle: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub priceOracleData: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: TradingParams) -> Self { + ( + value.minTradedToken0, + value.priceOracle, + value.priceOracleData, + value.appData, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for TradingParams { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + minTradedToken0: tuple.0, + priceOracle: tuple.1, + priceOracleData: tuple.2, + appData: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for TradingParams { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for TradingParams { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.minTradedToken0), + ::tokenize( + &self.priceOracle, + ), + ::tokenize( + &self.priceOracleData, + ), + as alloy_sol_types::SolType>::tokenize(&self.appData), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for TradingParams { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for TradingParams { + const NAME: &'static str = "TradingParams"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "TradingParams(uint256 minTradedToken0,address priceOracle,bytes \ + priceOracleData,bytes32 appData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word( + &self.minTradedToken0, + ) + .0, + ::eip712_data_word( + &self.priceOracle, + ) + .0, + ::eip712_data_word( + &self.priceOracleData, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.appData) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for TradingParams { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.minTradedToken0, + ) + + ::topic_preimage_length( + &rust.priceOracle, + ) + + ::topic_preimage_length( + &rust.priceOracleData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.appData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.minTradedToken0, + out, + ); + ::encode_topic_preimage( + &rust.priceOracle, + out, + ); + ::encode_topic_preimage( + &rust.priceOracleData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.appData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ConstantProduct`](self) contract instance. + + See the [wrapper's documentation](`ConstantProductInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ConstantProductInstance { + ConstantProductInstance::::new(address, __provider) + } + /**A [`ConstantProduct`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ConstantProduct`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ConstantProductInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ConstantProductInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ConstantProductInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ConstantProductInstance + { + /**Creates a new wrapper around an on-chain [`ConstantProduct`](self) contract instance. + + See the [wrapper's documentation](`ConstantProductInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ConstantProductInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ConstantProductInstance { + ConstantProductInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ConstantProductInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ConstantProductInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Order { + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Order { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub sellToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub buyToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub validTo: u32, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub kind: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub partiallyFillable: bool, + #[allow(missing_docs)] + pub sellTokenBalance: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub buyTokenBalance: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u32, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::FixedBytes<32>, + bool, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + ( + value.sellToken, + value.buyToken, + value.receiver, + value.sellAmount, + value.buyAmount, + value.validTo, + value.appData, + value.feeAmount, + value.kind, + value.partiallyFillable, + value.sellTokenBalance, + value.buyTokenBalance, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sellToken: tuple.0, + buyToken: tuple.1, + receiver: tuple.2, + sellAmount: tuple.3, + buyAmount: tuple.4, + validTo: tuple.5, + appData: tuple.6, + feeAmount: tuple.7, + kind: tuple.8, + partiallyFillable: tuple.9, + sellTokenBalance: tuple.10, + buyTokenBalance: tuple.11, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.sellToken, + ), + ::tokenize( + &self.buyToken, + ), + ::tokenize( + &self.receiver, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellAmount), + as alloy_sol_types::SolType>::tokenize(&self.buyAmount), + as alloy_sol_types::SolType>::tokenize(&self.validTo), + as alloy_sol_types::SolType>::tokenize(&self.appData), + as alloy_sol_types::SolType>::tokenize(&self.feeAmount), + as alloy_sol_types::SolType>::tokenize(&self.kind), + ::tokenize( + &self.partiallyFillable, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellTokenBalance), + as alloy_sol_types::SolType>::tokenize(&self.buyTokenBalance), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address sellToken,address buyToken,address receiver,uint256 \ + sellAmount,uint256 buyAmount,uint32 validTo,bytes32 appData,uint256 \ + feeAmount,bytes32 kind,bool partiallyFillable,bytes32 \ + sellTokenBalance,bytes32 buyTokenBalance)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.sellToken, + ) + .0, + ::eip712_data_word( + &self.buyToken, + ) + .0, + ::eip712_data_word( + &self.receiver, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.sellAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.buyAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.validTo) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.appData) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.feeAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.kind) + .0, + ::eip712_data_word( + &self.partiallyFillable, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.sellTokenBalance, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.buyTokenBalance, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.sellToken, + ) + + ::topic_preimage_length( + &rust.buyToken, + ) + + ::topic_preimage_length( + &rust.receiver, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.validTo, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.appData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.feeAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.kind) + + ::topic_preimage_length( + &rust.partiallyFillable, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellTokenBalance, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyTokenBalance, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.sellToken, + out, + ); + ::encode_topic_preimage( + &rust.buyToken, + out, + ); + ::encode_topic_preimage( + &rust.receiver, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.validTo, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.appData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.feeAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.kind, + out, + ); + ::encode_topic_preimage( + &rust.partiallyFillable, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellTokenBalance, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyTokenBalance, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2OrderInstance { + GPv2OrderInstance::::new(address, __provider) + } + /**A [`GPv2Order`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Order`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2OrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2OrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2OrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2OrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2OrderInstance { + GPv2OrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library ConstantProduct { + struct TradingParams { + uint256 minTradedToken0; + address priceOracle; + bytes priceOracleData; + bytes32 appData; + } +} + +library GPv2Order { + struct Data { + address sellToken; + address buyToken; + address receiver; + uint256 sellAmount; + uint256 buyAmount; + uint32 validTo; + bytes32 appData; + uint256 feeAmount; + bytes32 kind; + bool partiallyFillable; + bytes32 sellTokenBalance; + bytes32 buyTokenBalance; + } +} + +interface CowAmm { + error CommitOutsideOfSettlement(); + error OnlyManagerCanCall(); + error OrderDoesNotMatchCommitmentHash(); + error OrderDoesNotMatchDefaultTradeableOrder(); + error OrderDoesNotMatchMessageHash(); + error OrderNotValid(string); + error PollTryAtBlock(uint256 blockNumber, string message); + error TradingParamsDoNotMatchHash(); + + event TradingDisabled(); + event TradingEnabled(bytes32 indexed hash, ConstantProduct.TradingParams params); + + constructor(address _solutionSettler, address _token0, address _token1); + + function commit(bytes32 orderHash) external; + function hash(ConstantProduct.TradingParams memory tradingParams) external pure returns (bytes32); + function isValidSignature(bytes32 _hash, bytes memory signature) external view returns (bytes4); + function manager() external view returns (address); + function token0() external view returns (address); + function token1() external view returns (address); + function verify(ConstantProduct.TradingParams memory tradingParams, GPv2Order.Data memory order) external view; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_solutionSettler", + "type": "address", + "internalType": "contract ISettlement" + }, + { + "name": "_token0", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "_token1", + "type": "address", + "internalType": "contract IERC20" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "commit", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hash", + "inputs": [ + { + "name": "tradingParams", + "type": "tuple", + "internalType": "struct ConstantProduct.TradingParams", + "components": [ + { + "name": "minTradedToken0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceOracle", + "type": "address", + "internalType": "contract IPriceOracle" + }, + { + "name": "priceOracleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "_hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "manager", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "token0", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IERC20" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "token1", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IERC20" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "verify", + "inputs": [ + { + "name": "tradingParams", + "type": "tuple", + "internalType": "struct ConstantProduct.TradingParams", + "components": [ + { + "name": "minTradedToken0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceOracle", + "type": "address", + "internalType": "contract IPriceOracle" + }, + { + "name": "priceOracleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "order", + "type": "tuple", + "internalType": "struct GPv2Order.Data", + "components": [ + { + "name": "sellToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "kind", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sellTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "buyTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "event", + "name": "TradingDisabled", + "inputs": [], + "anonymous": false + }, + { + "type": "event", + "name": "TradingEnabled", + "inputs": [ + { + "name": "hash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "params", + "type": "tuple", + "indexed": false, + "internalType": "struct ConstantProduct.TradingParams", + "components": [ + { + "name": "minTradedToken0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceOracle", + "type": "address", + "internalType": "contract IPriceOracle" + }, + { + "name": "priceOracleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "CommitOutsideOfSettlement", + "inputs": [] + }, + { + "type": "error", + "name": "OnlyManagerCanCall", + "inputs": [] + }, + { + "type": "error", + "name": "OrderDoesNotMatchCommitmentHash", + "inputs": [] + }, + { + "type": "error", + "name": "OrderDoesNotMatchDefaultTradeableOrder", + "inputs": [] + }, + { + "type": "error", + "name": "OrderDoesNotMatchMessageHash", + "inputs": [] + }, + { + "type": "error", + "name": "OrderNotValid", + "inputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "PollTryAtBlock", + "inputs": [ + { + "name": "blockNumber", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "message", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "TradingParamsDoNotMatchHash", + "inputs": [] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CowAmm { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x610120604052348015610010575f80fd5b5060405161267838038061267883398101604081905261002f9161052f565b6001600160a01b03831660808190526040805163f698da2560e01b8152905163f698da259160048082019260209290919082900301815f875af1158015610078573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061009c9190610579565b610100526100aa823361015f565b6100b4813361015f565b336001600160a01b031660e0816001600160a01b0316815250505f836001600160a01b0316639b552cc26040518163ffffffff1660e01b81526004016020604051808303815f875af115801561010c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101309190610590565b905061013c838261015f565b610146828261015f565b506001600160a01b0391821660a0521660c0525061061c565b6101746001600160a01b038316825f19610178565b5050565b8015806101f05750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156101ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ee9190610579565b155b6102675760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526102bd9185916102c216565b505050565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908201525f9061030e906001600160a01b03851690849061038d565b905080515f148061032e57508080602001905181019061032e91906105b2565b6102bd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161025e565b606061039b84845f856103a3565b949350505050565b6060824710156104045760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161025e565b5f80866001600160a01b0316858760405161041f91906105d1565b5f6040518083038185875af1925050503d805f8114610459576040519150601f19603f3d011682016040523d82523d5f602084013e61045e565b606091505b5090925090506104708783838761047b565b979650505050505050565b606083156104e95782515f036104e2576001600160a01b0385163b6104e25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161025e565b508161039b565b61039b83838151156104fe5781518083602001fd5b8060405162461bcd60e51b815260040161025e91906105e7565b6001600160a01b038116811461052c575f80fd5b50565b5f805f60608486031215610541575f80fd5b835161054c81610518565b602085015190935061055d81610518565b604085015190925061056e81610518565b809150509250925092565b5f60208284031215610589575f80fd5b5051919050565b5f602082840312156105a0575f80fd5b81516105ab81610518565b9392505050565b5f602082840312156105c2575f80fd5b815180151581146105ab575f80fd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b60805160a05160c05160e05161010051611fbd6106bb5f395f81816102db015261042b01525f8181610236015281816104d90152610bf901525f81816102b40152818161059901528181610d5c01528181610ebf01528181610f8e015261100d01525f81816101380152818161057701528181610d3b01528181610e2801528181610f6b015261103001525f818161032201526112140152611fbd5ff3fe608060405234801561000f575f80fd5b506004361061012f575f3560e01c8063b09aaaca116100ad578063e3e6f5b21161007d578063eec50b9711610063578063eec50b9714610344578063f14fcbc81461034c578063ff2dbc9814610203575f80fd5b8063e3e6f5b2146102fd578063e516715b1461031d575f80fd5b8063b09aaaca14610289578063c5f3d2541461029c578063d21220a7146102af578063d25e0cb6146102d6575f80fd5b80631c7de94111610102578063481c6a75116100e8578063481c6a7514610231578063981a160b14610258578063a029a8d414610276575f80fd5b80631c7de941146102035780633e706e321461020a575f80fd5b80630dfe1681146101335780631303a484146101845780631626ba7e146101b557806317700f01146101f9575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c5b60405190815260200161017b565b6101c86101c33660046116bf565b61035f565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161017b565b6102016104d7565b005b6101a75f81565b6101a77f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b59381565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b61026161012c81565b60405163ffffffff909116815260200161017b565b6102016102843660046119ee565b610573565b6101a7610297366004611a3b565b610bc8565b6102016102aa366004611a75565b610bf7565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a77f000000000000000000000000000000000000000000000000000000000000000081565b61031061030b366004611a3b565b610cb7565b60405161017b9190611aac565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a75f5481565b61020161035a366004611b9a565b6111fc565b5f808061036e84860186611bb1565b915091505f5461037d82610bc8565b146103b4576040517ff1a6789000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020868114610494576040517f593fcacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049f818385611291565b6104a98284610573565b507f1626ba7e00000000000000000000000000000000000000000000000000000000925050505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610546576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8080556040517fbcb8b8fbdea8aa6dc4ae41213e4da81e605a3d1a56ed851b9355182321c091909190a1565b80517f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff808416911614610677578073ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff1614610675576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642073656c6c20746f6b656e000000000000000000000000000060448201526064015b60405180910390fd5b905b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156106e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107059190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610772573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107969190611bff565b90508273ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff1614610831576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c69642062757920746f6b656e000000000000000000000000000000604482015260640161066c565b604085015173ffffffffffffffffffffffffffffffffffffffff16156108b3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7265636569766572206d757374206265207a65726f2061646472657373000000604482015260640161066c565b6108bf61012c42611c43565b8560a0015163ffffffff161115610932576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f76616c696469747920746f6f2066617220696e20746865206675747572650000604482015260640161066c565b85606001518560c00151146109a3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420617070446174610000000000000000000000000000000000604482015260640161066c565b60e085015115610a0f576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f66656520616d6f756e74206d757374206265207a65726f000000000000000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610160015114610a9d576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f627579546f6b656e42616c616e6365206d757374206265206572633230000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610140015114610b2b576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656c6c546f6b656e42616c616e6365206d7573742062652065726332300000604482015260640161066c565b6060850151610b3a9082611c56565b60808601516060870151610b4e9085611c6d565b610b589190611c56565b1015610bc0576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f726563656976656420616d6f756e7420746f6f206c6f77000000000000000000604482015260640161066c565b505050505050565b5f81604051602001610bda9190611ccc565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c66576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610c7361029783611d27565b9050805f81905550807f510e4a4f76907c2d6158b343f7c4f2f597df385b727c26e9ef90e75093ace19a83604051610cab9190611d79565b60405180910390a25050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091525f80836020015173ffffffffffffffffffffffffffffffffffffffff1663355efdd97f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087604001516040518463ffffffff1660e01b8152600401610d9e93929190611e3a565b6040805180830381865afa158015610db8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ddc9190611e72565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291935091505f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610e6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e919190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3d9190611bff565b90925090505f80808080610f518888611c56565b90505f610f5e8a88611c56565b90505f8282101561100b577f000000000000000000000000000000000000000000000000000000000000000096507f00000000000000000000000000000000000000000000000000000000000000009550610fd6610fbd60028b611ec1565b610fd184610fcc8e6002611c56565b611346565b61137e565b945061100185610fe6818d611c56565b610ff09085611c43565b610ffa8c8f611c56565b60016113cb565b9350849050611098565b7f000000000000000000000000000000000000000000000000000000000000000096507f0000000000000000000000000000000000000000000000000000000000000000955061106e61105f60028a611ec1565b610fd185610fcc8f6002611c56565b94506110928561107e818e611c56565b6110889086611c43565b610ffa8b8e611c56565b93508390505b8c518110156110df576110df6040518060400160405280601781526020017f74726164656420616d6f756e7420746f6f20736d616c6c000000000000000000815250611426565b6040518061018001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200161115661012c611466565b63ffffffff1681526020018e6060015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98152509b505050505050505050505050919050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461126b576040517fbf84897700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935d50565b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c8381146113405780156112f2576040517fdafbdd1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112fc84610cb7565b90506113088382611487565b61133e576040517fd9ff24c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50505050565b5f82156113735781611359600185611c6d565b6113639190611ec1565b61136e906001611c43565b611375565b5f5b90505b92915050565b5f818310156113c5576113c56040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250611426565b50900390565b5f806113d8868686611599565b905060018360028111156113ee576113ee611ed4565b14801561140a57505f848061140557611405611e94565b868809115b1561141d5761141a600182611c43565b90505b95945050505050565b611431436001611c43565b816040517f1fe8506e00000000000000000000000000000000000000000000000000000000815260040161066c929190611f01565b5f81806114738142611f19565b61147d9190611f3b565b6113789190611f63565b5f80825f015173ffffffffffffffffffffffffffffffffffffffff16845f015173ffffffffffffffffffffffffffffffffffffffff161490505f836020015173ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161490505f846060015186606001511490505f856080015187608001511490505f8660a0015163ffffffff168860a0015163ffffffff161490505f8761010001518961010001511490505f88610120015115158a6101200151151514905086801561155e5750855b80156115675750845b80156115705750835b80156115795750825b80156115825750815b801561158b5750805b9a9950505050505050505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f036115ef578382816115e5576115e5611e94565b04925050506104d0565b808411611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161066c565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f805f604084860312156116d1575f80fd5b83359250602084013567ffffffffffffffff808211156116ef575f80fd5b818601915086601f830112611702575f80fd5b813581811115611710575f80fd5b876020828501011115611721575f80fd5b6020830194508093505050509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561178457611784611734565b60405290565b604051610180810167ffffffffffffffff8111828210171561178457611784611734565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117f5576117f5611734565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461181e575f80fd5b50565b5f60808284031215611831575f80fd5b611839611761565b90508135815260208083013561184e816117fd565b82820152604083013567ffffffffffffffff8082111561186c575f80fd5b818501915085601f83011261187f575f80fd5b81358181111561189157611891611734565b6118c1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016117ae565b915080825286848285010111156118d6575f80fd5b80848401858401375f848284010152508060408501525050506060820135606082015292915050565b803561190a816117fd565b919050565b803563ffffffff8116811461190a575f80fd5b8035801515811461190a575f80fd5b5f6101808284031215611942575f80fd5b61194a61178a565b9050611955826118ff565b8152611963602083016118ff565b6020820152611974604083016118ff565b6040820152606082013560608201526080820135608082015261199960a0830161190f565b60a082015260c082013560c082015260e082013560e08201526101008083013581830152506101206119cc818401611922565b9082015261014082810135908201526101609182013591810191909152919050565b5f806101a08385031215611a00575f80fd5b823567ffffffffffffffff811115611a16575f80fd5b611a2285828601611821565b925050611a328460208501611931565b90509250929050565b5f60208284031215611a4b575f80fd5b813567ffffffffffffffff811115611a61575f80fd5b611a6d84828501611821565b949350505050565b5f60208284031215611a85575f80fd5b813567ffffffffffffffff811115611a9b575f80fd5b8201608081850312156104d0575f80fd5b815173ffffffffffffffffffffffffffffffffffffffff16815261018081016020830151611af2602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151611b1a604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606083015160608301526080830151608083015260a0830151611b4660a084018263ffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b7b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f60208284031215611baa575f80fd5b5035919050565b5f806101a08385031215611bc3575f80fd5b611bcd8484611931565b915061018083013567ffffffffffffffff811115611be9575f80fd5b611bf585828601611821565b9150509250929050565b5f60208284031215611c0f575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561137857611378611c16565b808202811582820484141761137857611378611c16565b8181038181111561137857611378611c16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081528151602082015273ffffffffffffffffffffffffffffffffffffffff60208301511660408201525f604083015160806060840152611d1160a0840182611c80565b9050606084015160808401528091505092915050565b5f6113783683611821565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152813560208201525f6020830135611d93816117fd565b73ffffffffffffffffffffffffffffffffffffffff811660408401525060408301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611de4575f80fd5b830160208101903567ffffffffffffffff811115611e00575f80fd5b803603821315611e0e575f80fd5b60806060850152611e2360a085018284611d32565b915050606084013560808401528091505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff80861683528085166020840152506060604083015261141d6060830184611c80565b5f8060408385031215611e83575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82611ecf57611ecf611e94565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f611a6d6040830184611c80565b5f63ffffffff80841680611f2f57611f2f611e94565b92169190910492915050565b63ffffffff818116838216028082169190828114611f5b57611f5b611c16565b505092915050565b63ffffffff818116838216019080821115611f8057611f80611c16565b509291505056fea2646970667358221220e3fb228b525d90b942c7e58fe2e2034a17bd258c082fd47740e764a7be45bac664736f6c63430008190033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01 `@R4\x80\x15a\0\x10W_\x80\xFD[P`@Qa&x8\x03\x80a&x\x839\x81\x01`@\x81\x90Ra\0/\x91a\x05/V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\x80\x81\x90R`@\x80Qc\xF6\x98\xDA%`\xE0\x1B\x81R\x90Qc\xF6\x98\xDA%\x91`\x04\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81_\x87Z\xF1\x15\x80\x15a\0xW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\x9C\x91\x90a\x05yV[a\x01\0Ra\0\xAA\x823a\x01_V[a\0\xB4\x813a\x01_V[3`\x01`\x01`\xA0\x1B\x03\x16`\xE0\x81`\x01`\x01`\xA0\x1B\x03\x16\x81RPP_\x83`\x01`\x01`\xA0\x1B\x03\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81_\x87Z\xF1\x15\x80\x15a\x01\x0CW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x010\x91\x90a\x05\x90V[\x90Pa\x01<\x83\x82a\x01_V[a\x01F\x82\x82a\x01_V[P`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\xA0R\x16`\xC0RPa\x06\x1CV[a\x01t`\x01`\x01`\xA0\x1B\x03\x83\x16\x82_\x19a\x01xV[PPV[\x80\x15\x80a\x01\xF0WP`@Qcn\xB1v\x9F`\xE1\x1B\x81R0`\x04\x82\x01R`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`$\x83\x01R\x84\x16\x90c\xDDb\xED>\x90`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xCAW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xEE\x91\x90a\x05yV[\x15[a\x02gW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`6`$\x82\x01R\x7FSafeERC20: approve from non-zero`D\x82\x01R\x7F to non-zero allowance\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x84\x16`$\x82\x01R`D\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`d\x90\x91\x01\x90\x91R` \x81\x01\x80Q`\x01`\x01`\xE0\x1B\x03\x90\x81\x16c\t^\xA7\xB3`\xE0\x1B\x17\x90\x91Ra\x02\xBD\x91\x85\x91a\x02\xC2\x16V[PPPV[`@\x80Q\x80\x82\x01\x90\x91R` \x80\x82R\x7FSafeERC20: low-level call failed\x90\x82\x01R_\x90a\x03\x0E\x90`\x01`\x01`\xA0\x1B\x03\x85\x16\x90\x84\x90a\x03\x8DV[\x90P\x80Q_\x14\x80a\x03.WP\x80\x80` \x01\x90Q\x81\x01\x90a\x03.\x91\x90a\x05\xB2V[a\x02\xBDW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`*`$\x82\x01R\x7FSafeERC20: ERC20 operation did n`D\x82\x01Ri\x1B\xDD\x08\x1C\xDDX\xD8\xD9YY`\xB2\x1B`d\x82\x01R`\x84\x01a\x02^V[``a\x03\x9B\x84\x84_\x85a\x03\xA3V[\x94\x93PPPPV[``\x82G\x10\x15a\x04\x04W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FAddress: insufficient balance fo`D\x82\x01Re\x1C\x88\x18\xD8[\x1B`\xD2\x1B`d\x82\x01R`\x84\x01a\x02^V[_\x80\x86`\x01`\x01`\xA0\x1B\x03\x16\x85\x87`@Qa\x04\x1F\x91\x90a\x05\xD1V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x04YW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x04^V[``\x91P[P\x90\x92P\x90Pa\x04p\x87\x83\x83\x87a\x04{V[\x97\x96PPPPPPPV[``\x83\x15a\x04\xE9W\x82Q_\x03a\x04\xE2W`\x01`\x01`\xA0\x1B\x03\x85\x16;a\x04\xE2W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FAddress: call to non-contract\0\0\0`D\x82\x01R`d\x01a\x02^V[P\x81a\x03\x9BV[a\x03\x9B\x83\x83\x81Q\x15a\x04\xFEW\x81Q\x80\x83` \x01\xFD[\x80`@QbF\x1B\xCD`\xE5\x1B\x81R`\x04\x01a\x02^\x91\x90a\x05\xE7V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05,W_\x80\xFD[PV[_\x80_``\x84\x86\x03\x12\x15a\x05AW_\x80\xFD[\x83Qa\x05L\x81a\x05\x18V[` \x85\x01Q\x90\x93Pa\x05]\x81a\x05\x18V[`@\x85\x01Q\x90\x92Pa\x05n\x81a\x05\x18V[\x80\x91PP\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x05\x89W_\x80\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a\x05\xA0W_\x80\xFD[\x81Qa\x05\xAB\x81a\x05\x18V[\x93\x92PPPV[_` \x82\x84\x03\x12\x15a\x05\xC2W_\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x05\xABW_\x80\xFD[_\x82Q\x80` \x85\x01\x84^_\x92\x01\x91\x82RP\x91\x90PV[` \x81R_\x82Q\x80` \x84\x01R\x80` \x85\x01`@\x85\x01^_`@\x82\x85\x01\x01R`@`\x1F\x19`\x1F\x83\x01\x16\x84\x01\x01\x91PP\x92\x91PPV[`\x80Q`\xA0Q`\xC0Q`\xE0Qa\x01\0Qa\x1F\xBDa\x06\xBB_9_\x81\x81a\x02\xDB\x01Ra\x04+\x01R_\x81\x81a\x026\x01R\x81\x81a\x04\xD9\x01Ra\x0B\xF9\x01R_\x81\x81a\x02\xB4\x01R\x81\x81a\x05\x99\x01R\x81\x81a\r\\\x01R\x81\x81a\x0E\xBF\x01R\x81\x81a\x0F\x8E\x01Ra\x10\r\x01R_\x81\x81a\x018\x01R\x81\x81a\x05w\x01R\x81\x81a\r;\x01R\x81\x81a\x0E(\x01R\x81\x81a\x0Fk\x01Ra\x100\x01R_\x81\x81a\x03\"\x01Ra\x12\x14\x01Ra\x1F\xBD_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\x01/W_5`\xE0\x1C\x80c\xB0\x9A\xAA\xCA\x11a\0\xADW\x80c\xE3\xE6\xF5\xB2\x11a\0}W\x80c\xEE\xC5\x0B\x97\x11a\0cW\x80c\xEE\xC5\x0B\x97\x14a\x03DW\x80c\xF1O\xCB\xC8\x14a\x03LW\x80c\xFF-\xBC\x98\x14a\x02\x03W_\x80\xFD[\x80c\xE3\xE6\xF5\xB2\x14a\x02\xFDW\x80c\xE5\x16q[\x14a\x03\x1DW_\x80\xFD[\x80c\xB0\x9A\xAA\xCA\x14a\x02\x89W\x80c\xC5\xF3\xD2T\x14a\x02\x9CW\x80c\xD2\x12 \xA7\x14a\x02\xAFW\x80c\xD2^\x0C\xB6\x14a\x02\xD6W_\x80\xFD[\x80c\x1C}\xE9A\x11a\x01\x02W\x80cH\x1Cju\x11a\0\xE8W\x80cH\x1Cju\x14a\x021W\x80c\x98\x1A\x16\x0B\x14a\x02XW\x80c\xA0)\xA8\xD4\x14a\x02vW_\x80\xFD[\x80c\x1C}\xE9A\x14a\x02\x03W\x80c>pn2\x14a\x02\nW_\x80\xFD[\x80c\r\xFE\x16\x81\x14a\x013W\x80c\x13\x03\xA4\x84\x14a\x01\x84W\x80c\x16&\xBA~\x14a\x01\xB5W\x80c\x17p\x0F\x01\x14a\x01\xF9W[_\x80\xFD[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\[`@Q\x90\x81R` \x01a\x01{V[a\x01\xC8a\x01\xC36`\x04a\x16\xBFV[a\x03_V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x04\xD7V[\0[a\x01\xA7_\x81V[a\x01\xA7\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\x81V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x02aa\x01,\x81V[`@Qc\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x02\x846`\x04a\x19\xEEV[a\x05sV[a\x01\xA7a\x02\x976`\x04a\x1A;V[a\x0B\xC8V[a\x02\x01a\x02\xAA6`\x04a\x1AuV[a\x0B\xF7V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x03\x10a\x03\x0B6`\x04a\x1A;V[a\x0C\xB7V[`@Qa\x01{\x91\x90a\x1A\xACV[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7_T\x81V[a\x02\x01a\x03Z6`\x04a\x1B\x9AV[a\x11\xFCV[_\x80\x80a\x03n\x84\x86\x01\x86a\x1B\xB1V[\x91P\x91P_Ta\x03}\x82a\x0B\xC8V[\x14a\x03\xB4W`@Q\x7F\xF1\xA6x\x90\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x82\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x02\x82\x01R`\"\x81\x01\x91\x90\x91R`B\x90 \x86\x81\x14a\x04\x94W`@Q\x7FY?\xCA\xCD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x04\x9F\x81\x83\x85a\x12\x91V[a\x04\xA9\x82\x84a\x05sV[P\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92PPP[\x93\x92PPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x05FW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80\x80U`@Q\x7F\xBC\xB8\xB8\xFB\xDE\xA8\xAAm\xC4\xAEA!>M\xA8\x1E`Z=\x1AV\xED\x85\x1B\x93U\x18#!\xC0\x91\x90\x91\x90\xA1V[\x80Q\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16\x91\x16\x14a\x06wW\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x06uW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x12`$\x82\x01R\x7Finvalid sell token\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x90[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x06\xE1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x05\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90\x91P_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x07rW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x96\x91\x90a\x1B\xFFV[\x90P\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x081W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7Finvalid buy token\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`@\x85\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x15a\x08\xB3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7Freceiver must be zero address\0\0\0`D\x82\x01R`d\x01a\x06lV[a\x08\xBFa\x01,Ba\x1CCV[\x85`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x11\x15a\t2W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7Fvalidity too far in the future\0\0`D\x82\x01R`d\x01a\x06lV[\x85``\x01Q\x85`\xC0\x01Q\x14a\t\xA3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x0F`$\x82\x01R\x7Finvalid appData\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`\xE0\x85\x01Q\x15a\n\x0FW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Ffee amount must be zero\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01`\x01Q\x14a\n\x9DW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FbuyTokenBalance must be erc20\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01@\x01Q\x14a\x0B+W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FsellTokenBalance must be erc20\0\0`D\x82\x01R`d\x01a\x06lV[``\x85\x01Qa\x0B:\x90\x82a\x1CVV[`\x80\x86\x01Q``\x87\x01Qa\x0BN\x90\x85a\x1CmV[a\x0BX\x91\x90a\x1CVV[\x10\x15a\x0B\xC0W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Freceived amount too low\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[PPPPPPV[_\x81`@Q` \x01a\x0B\xDA\x91\x90a\x1C\xCCV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x0CfW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x0Csa\x02\x97\x83a\x1D'V[\x90P\x80_\x81\x90UP\x80\x7FQ\x0EJOv\x90|-aX\xB3C\xF7\xC4\xF2\xF5\x97\xDF8[r|&\xE9\xEF\x90\xE7P\x93\xAC\xE1\x9A\x83`@Qa\x0C\xAB\x91\x90a\x1DyV[`@Q\x80\x91\x03\x90\xA2PPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R_\x80\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c5^\xFD\xD9\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87`@\x01Q`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\r\x9E\x93\x92\x91\x90a\x1E:V[`@\x80Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\r\xB8W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\r\xDC\x91\x90a\x1ErV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x91\x93P\x91P_\x90\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0EmW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0E\x91\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0F\x19W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0F=\x91\x90a\x1B\xFFV[\x90\x92P\x90P_\x80\x80\x80\x80a\x0FQ\x88\x88a\x1CVV[\x90P_a\x0F^\x8A\x88a\x1CVV[\x90P_\x82\x82\x10\x15a\x10\x0BW\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x0F\xD6a\x0F\xBD`\x02\x8Ba\x1E\xC1V[a\x0F\xD1\x84a\x0F\xCC\x8E`\x02a\x1CVV[a\x13FV[a\x13~V[\x94Pa\x10\x01\x85a\x0F\xE6\x81\x8Da\x1CVV[a\x0F\xF0\x90\x85a\x1CCV[a\x0F\xFA\x8C\x8Fa\x1CVV[`\x01a\x13\xCBV[\x93P\x84\x90Pa\x10\x98V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x10na\x10_`\x02\x8Aa\x1E\xC1V[a\x0F\xD1\x85a\x0F\xCC\x8F`\x02a\x1CVV[\x94Pa\x10\x92\x85a\x10~\x81\x8Ea\x1CVV[a\x10\x88\x90\x86a\x1CCV[a\x0F\xFA\x8B\x8Ea\x1CVV[\x93P\x83\x90P[\x8CQ\x81\x10\x15a\x10\xDFWa\x10\xDF`@Q\x80`@\x01`@R\x80`\x17\x81R` \x01\x7Ftraded amount too small\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[`@Q\x80a\x01\x80\x01`@R\x80\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86\x81R` \x01\x85\x81R` \x01a\x11Va\x01,a\x14fV[c\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8E``\x01Q\x81R` \x01_\x81R` \x01\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x81R` \x01`\x01\x15\x15\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81RP\x9BPPPPPPPPPPPP\x91\x90PV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x12kW`@Q\x7F\xBF\x84\x89w\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x80\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93]PV[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\\x83\x81\x14a\x13@W\x80\x15a\x12\xF2W`@Q\x7F\xDA\xFB\xDD\x1F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x12\xFC\x84a\x0C\xB7V[\x90Pa\x13\x08\x83\x82a\x14\x87V[a\x13>W`@Q\x7F\xD9\xFF$\xC7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P[PPPPV[_\x82\x15a\x13sW\x81a\x13Y`\x01\x85a\x1CmV[a\x13c\x91\x90a\x1E\xC1V[a\x13n\x90`\x01a\x1CCV[a\x13uV[_[\x90P[\x92\x91PPV[_\x81\x83\x10\x15a\x13\xC5Wa\x13\xC5`@Q\x80`@\x01`@R\x80`\x15\x81R` \x01\x7Fsubtraction underflow\0\0\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[P\x90\x03\x90V[_\x80a\x13\xD8\x86\x86\x86a\x15\x99V[\x90P`\x01\x83`\x02\x81\x11\x15a\x13\xEEWa\x13\xEEa\x1E\xD4V[\x14\x80\x15a\x14\nWP_\x84\x80a\x14\x05Wa\x14\x05a\x1E\x94V[\x86\x88\t\x11[\x15a\x14\x1DWa\x14\x1A`\x01\x82a\x1CCV[\x90P[\x95\x94PPPPPV[a\x141C`\x01a\x1CCV[\x81`@Q\x7F\x1F\xE8Pn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x06l\x92\x91\x90a\x1F\x01V[_\x81\x80a\x14s\x81Ba\x1F\x19V[a\x14}\x91\x90a\x1F;V[a\x13x\x91\x90a\x1FcV[_\x80\x82_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x84``\x01Q\x86``\x01Q\x14\x90P_\x85`\x80\x01Q\x87`\x80\x01Q\x14\x90P_\x86`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x88`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x14\x90P_\x87a\x01\0\x01Q\x89a\x01\0\x01Q\x14\x90P_\x88a\x01 \x01Q\x15\x15\x8Aa\x01 \x01Q\x15\x15\x14\x90P\x86\x80\x15a\x15^WP\x85[\x80\x15a\x15gWP\x84[\x80\x15a\x15pWP\x83[\x80\x15a\x15yWP\x82[\x80\x15a\x15\x82WP\x81[\x80\x15a\x15\x8BWP\x80[\x9A\x99PPPPPPPPPPV[_\x80\x80\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x87\t\x85\x87\x02\x92P\x82\x81\x10\x83\x82\x03\x03\x91PP\x80_\x03a\x15\xEFW\x83\x82\x81a\x15\xE5Wa\x15\xE5a\x1E\x94V[\x04\x92PPPa\x04\xD0V[\x80\x84\x11a\x16XW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FMath: mulDiv overflow\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[_\x84\x86\x88\t`\x02`\x01\x87\x19\x81\x01\x88\x16\x97\x88\x90\x04`\x03\x81\x02\x83\x18\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x90\x81\x02\x90\x92\x03\x90\x91\x02_\x88\x90\x03\x88\x90\x04\x90\x91\x01\x85\x83\x11\x90\x94\x03\x93\x90\x93\x02\x93\x03\x94\x90\x94\x04\x91\x90\x91\x17\x02\x94\x93PPPPV[_\x80_`@\x84\x86\x03\x12\x15a\x16\xD1W_\x80\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x16\xEFW_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a\x17\x02W_\x80\xFD[\x815\x81\x81\x11\x15a\x17\x10W_\x80\xFD[\x87` \x82\x85\x01\x01\x11\x15a\x17!W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@R\x90V[`@Qa\x01\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\xF5Wa\x17\xF5a\x174V[`@R\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x18\x1EW_\x80\xFD[PV[_`\x80\x82\x84\x03\x12\x15a\x181W_\x80\xFD[a\x189a\x17aV[\x90P\x815\x81R` \x80\x83\x015a\x18N\x81a\x17\xFDV[\x82\x82\x01R`@\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x18lW_\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x18\x7FW_\x80\xFD[\x815\x81\x81\x11\x15a\x18\x91Wa\x18\x91a\x174V[a\x18\xC1\x84\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x17\xAEV[\x91P\x80\x82R\x86\x84\x82\x85\x01\x01\x11\x15a\x18\xD6W_\x80\xFD[\x80\x84\x84\x01\x85\x84\x017_\x84\x82\x84\x01\x01RP\x80`@\x85\x01RPPP``\x82\x015``\x82\x01R\x92\x91PPV[\x805a\x19\n\x81a\x17\xFDV[\x91\x90PV[\x805c\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x19\nW_\x80\xFD[\x805\x80\x15\x15\x81\x14a\x19\nW_\x80\xFD[_a\x01\x80\x82\x84\x03\x12\x15a\x19BW_\x80\xFD[a\x19Ja\x17\x8AV[\x90Pa\x19U\x82a\x18\xFFV[\x81Ra\x19c` \x83\x01a\x18\xFFV[` \x82\x01Ra\x19t`@\x83\x01a\x18\xFFV[`@\x82\x01R``\x82\x015``\x82\x01R`\x80\x82\x015`\x80\x82\x01Ra\x19\x99`\xA0\x83\x01a\x19\x0FV[`\xA0\x82\x01R`\xC0\x82\x015`\xC0\x82\x01R`\xE0\x82\x015`\xE0\x82\x01Ra\x01\0\x80\x83\x015\x81\x83\x01RPa\x01 a\x19\xCC\x81\x84\x01a\x19\"V[\x90\x82\x01Ra\x01@\x82\x81\x015\x90\x82\x01Ra\x01`\x91\x82\x015\x91\x81\x01\x91\x90\x91R\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1A\0W_\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x16W_\x80\xFD[a\x1A\"\x85\x82\x86\x01a\x18!V[\x92PPa\x1A2\x84` \x85\x01a\x191V[\x90P\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1AKW_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1AaW_\x80\xFD[a\x1Am\x84\x82\x85\x01a\x18!V[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a\x1A\x85W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x9BW_\x80\xFD[\x82\x01`\x80\x81\x85\x03\x12\x15a\x04\xD0W_\x80\xFD[\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81Ra\x01\x80\x81\x01` \x83\x01Qa\x1A\xF2` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x83\x01Qa\x1B\x1A`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x83\x01Q``\x83\x01R`\x80\x83\x01Q`\x80\x83\x01R`\xA0\x83\x01Qa\x1BF`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x83\x01Q`\xC0\x83\x01R`\xE0\x83\x01Q`\xE0\x83\x01Ra\x01\0\x80\x84\x01Q\x81\x84\x01RPa\x01 \x80\x84\x01Qa\x1B{\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x83\x81\x01Q\x90\x83\x01Ra\x01`\x92\x83\x01Q\x92\x90\x91\x01\x91\x90\x91R\x90V[_` \x82\x84\x03\x12\x15a\x1B\xAAW_\x80\xFD[P5\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1B\xC3W_\x80\xFD[a\x1B\xCD\x84\x84a\x191V[\x91Pa\x01\x80\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1B\xE9W_\x80\xFD[a\x1B\xF5\x85\x82\x86\x01a\x18!V[\x91PP\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1C\x0FW_\x80\xFD[PQ\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x01\x80\x82\x11\x15a\x13xWa\x13xa\x1C\x16V[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\x13xWa\x13xa\x1C\x16V[\x81\x81\x03\x81\x81\x11\x15a\x13xWa\x13xa\x1C\x16V[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[` \x81R\x81Q` \x82\x01Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x83\x01Q\x16`@\x82\x01R_`@\x83\x01Q`\x80``\x84\x01Ra\x1D\x11`\xA0\x84\x01\x82a\x1C\x80V[\x90P``\x84\x01Q`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_a\x13x6\x83a\x18!V[\x81\x83R\x81\x81` \x85\x017P_` \x82\x84\x01\x01R_` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x84\x01\x01\x90P\x92\x91PPV[` \x81R\x815` \x82\x01R_` \x83\x015a\x1D\x93\x81a\x17\xFDV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`@\x84\x01RP`@\x83\x015\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x1D\xE4W_\x80\xFD[\x83\x01` \x81\x01\x905g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1E\0W_\x80\xFD[\x806\x03\x82\x13\x15a\x1E\x0EW_\x80\xFD[`\x80``\x85\x01Ra\x1E#`\xA0\x85\x01\x82\x84a\x1D2V[\x91PP``\x84\x015`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x86\x16\x83R\x80\x85\x16` \x84\x01RP```@\x83\x01Ra\x14\x1D``\x83\x01\x84a\x1C\x80V[_\x80`@\x83\x85\x03\x12\x15a\x1E\x83W_\x80\xFD[PP\x80Q` \x90\x91\x01Q\x90\x92\x90\x91PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_\x82a\x1E\xCFWa\x1E\xCFa\x1E\x94V[P\x04\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x82\x81R`@` \x82\x01R_a\x1Am`@\x83\x01\x84a\x1C\x80V[_c\xFF\xFF\xFF\xFF\x80\x84\x16\x80a\x1F/Wa\x1F/a\x1E\x94V[\x92\x16\x91\x90\x91\x04\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x02\x80\x82\x16\x91\x90\x82\x81\x14a\x1F[Wa\x1F[a\x1C\x16V[PP\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x01\x90\x80\x82\x11\x15a\x1F\x80Wa\x1F\x80a\x1C\x16V[P\x92\x91PPV\xFE\xA2dipfsX\"\x12 \xE3\xFB\"\x8BR]\x90\xB9B\xC7\xE5\x8F\xE2\xE2\x03J\x17\xBD%\x8C\x08/\xD4w@\xE7d\xA7\xBEE\xBA\xC6dsolcC\0\x08\x19\x003", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f80fd5b506004361061012f575f3560e01c8063b09aaaca116100ad578063e3e6f5b21161007d578063eec50b9711610063578063eec50b9714610344578063f14fcbc81461034c578063ff2dbc9814610203575f80fd5b8063e3e6f5b2146102fd578063e516715b1461031d575f80fd5b8063b09aaaca14610289578063c5f3d2541461029c578063d21220a7146102af578063d25e0cb6146102d6575f80fd5b80631c7de94111610102578063481c6a75116100e8578063481c6a7514610231578063981a160b14610258578063a029a8d414610276575f80fd5b80631c7de941146102035780633e706e321461020a575f80fd5b80630dfe1681146101335780631303a484146101845780631626ba7e146101b557806317700f01146101f9575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c5b60405190815260200161017b565b6101c86101c33660046116bf565b61035f565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161017b565b6102016104d7565b005b6101a75f81565b6101a77f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b59381565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b61026161012c81565b60405163ffffffff909116815260200161017b565b6102016102843660046119ee565b610573565b6101a7610297366004611a3b565b610bc8565b6102016102aa366004611a75565b610bf7565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a77f000000000000000000000000000000000000000000000000000000000000000081565b61031061030b366004611a3b565b610cb7565b60405161017b9190611aac565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a75f5481565b61020161035a366004611b9a565b6111fc565b5f808061036e84860186611bb1565b915091505f5461037d82610bc8565b146103b4576040517ff1a6789000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020868114610494576040517f593fcacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049f818385611291565b6104a98284610573565b507f1626ba7e00000000000000000000000000000000000000000000000000000000925050505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610546576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8080556040517fbcb8b8fbdea8aa6dc4ae41213e4da81e605a3d1a56ed851b9355182321c091909190a1565b80517f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff808416911614610677578073ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff1614610675576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642073656c6c20746f6b656e000000000000000000000000000060448201526064015b60405180910390fd5b905b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156106e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107059190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610772573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107969190611bff565b90508273ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff1614610831576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c69642062757920746f6b656e000000000000000000000000000000604482015260640161066c565b604085015173ffffffffffffffffffffffffffffffffffffffff16156108b3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7265636569766572206d757374206265207a65726f2061646472657373000000604482015260640161066c565b6108bf61012c42611c43565b8560a0015163ffffffff161115610932576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f76616c696469747920746f6f2066617220696e20746865206675747572650000604482015260640161066c565b85606001518560c00151146109a3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420617070446174610000000000000000000000000000000000604482015260640161066c565b60e085015115610a0f576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f66656520616d6f756e74206d757374206265207a65726f000000000000000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610160015114610a9d576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f627579546f6b656e42616c616e6365206d757374206265206572633230000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610140015114610b2b576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656c6c546f6b656e42616c616e6365206d7573742062652065726332300000604482015260640161066c565b6060850151610b3a9082611c56565b60808601516060870151610b4e9085611c6d565b610b589190611c56565b1015610bc0576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f726563656976656420616d6f756e7420746f6f206c6f77000000000000000000604482015260640161066c565b505050505050565b5f81604051602001610bda9190611ccc565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c66576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610c7361029783611d27565b9050805f81905550807f510e4a4f76907c2d6158b343f7c4f2f597df385b727c26e9ef90e75093ace19a83604051610cab9190611d79565b60405180910390a25050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091525f80836020015173ffffffffffffffffffffffffffffffffffffffff1663355efdd97f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087604001516040518463ffffffff1660e01b8152600401610d9e93929190611e3a565b6040805180830381865afa158015610db8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ddc9190611e72565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291935091505f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610e6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e919190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3d9190611bff565b90925090505f80808080610f518888611c56565b90505f610f5e8a88611c56565b90505f8282101561100b577f000000000000000000000000000000000000000000000000000000000000000096507f00000000000000000000000000000000000000000000000000000000000000009550610fd6610fbd60028b611ec1565b610fd184610fcc8e6002611c56565b611346565b61137e565b945061100185610fe6818d611c56565b610ff09085611c43565b610ffa8c8f611c56565b60016113cb565b9350849050611098565b7f000000000000000000000000000000000000000000000000000000000000000096507f0000000000000000000000000000000000000000000000000000000000000000955061106e61105f60028a611ec1565b610fd185610fcc8f6002611c56565b94506110928561107e818e611c56565b6110889086611c43565b610ffa8b8e611c56565b93508390505b8c518110156110df576110df6040518060400160405280601781526020017f74726164656420616d6f756e7420746f6f20736d616c6c000000000000000000815250611426565b6040518061018001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200161115661012c611466565b63ffffffff1681526020018e6060015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98152509b505050505050505050505050919050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461126b576040517fbf84897700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935d50565b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c8381146113405780156112f2576040517fdafbdd1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112fc84610cb7565b90506113088382611487565b61133e576040517fd9ff24c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50505050565b5f82156113735781611359600185611c6d565b6113639190611ec1565b61136e906001611c43565b611375565b5f5b90505b92915050565b5f818310156113c5576113c56040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250611426565b50900390565b5f806113d8868686611599565b905060018360028111156113ee576113ee611ed4565b14801561140a57505f848061140557611405611e94565b868809115b1561141d5761141a600182611c43565b90505b95945050505050565b611431436001611c43565b816040517f1fe8506e00000000000000000000000000000000000000000000000000000000815260040161066c929190611f01565b5f81806114738142611f19565b61147d9190611f3b565b6113789190611f63565b5f80825f015173ffffffffffffffffffffffffffffffffffffffff16845f015173ffffffffffffffffffffffffffffffffffffffff161490505f836020015173ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161490505f846060015186606001511490505f856080015187608001511490505f8660a0015163ffffffff168860a0015163ffffffff161490505f8761010001518961010001511490505f88610120015115158a6101200151151514905086801561155e5750855b80156115675750845b80156115705750835b80156115795750825b80156115825750815b801561158b5750805b9a9950505050505050505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f036115ef578382816115e5576115e5611e94565b04925050506104d0565b808411611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161066c565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f805f604084860312156116d1575f80fd5b83359250602084013567ffffffffffffffff808211156116ef575f80fd5b818601915086601f830112611702575f80fd5b813581811115611710575f80fd5b876020828501011115611721575f80fd5b6020830194508093505050509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561178457611784611734565b60405290565b604051610180810167ffffffffffffffff8111828210171561178457611784611734565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117f5576117f5611734565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461181e575f80fd5b50565b5f60808284031215611831575f80fd5b611839611761565b90508135815260208083013561184e816117fd565b82820152604083013567ffffffffffffffff8082111561186c575f80fd5b818501915085601f83011261187f575f80fd5b81358181111561189157611891611734565b6118c1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016117ae565b915080825286848285010111156118d6575f80fd5b80848401858401375f848284010152508060408501525050506060820135606082015292915050565b803561190a816117fd565b919050565b803563ffffffff8116811461190a575f80fd5b8035801515811461190a575f80fd5b5f6101808284031215611942575f80fd5b61194a61178a565b9050611955826118ff565b8152611963602083016118ff565b6020820152611974604083016118ff565b6040820152606082013560608201526080820135608082015261199960a0830161190f565b60a082015260c082013560c082015260e082013560e08201526101008083013581830152506101206119cc818401611922565b9082015261014082810135908201526101609182013591810191909152919050565b5f806101a08385031215611a00575f80fd5b823567ffffffffffffffff811115611a16575f80fd5b611a2285828601611821565b925050611a328460208501611931565b90509250929050565b5f60208284031215611a4b575f80fd5b813567ffffffffffffffff811115611a61575f80fd5b611a6d84828501611821565b949350505050565b5f60208284031215611a85575f80fd5b813567ffffffffffffffff811115611a9b575f80fd5b8201608081850312156104d0575f80fd5b815173ffffffffffffffffffffffffffffffffffffffff16815261018081016020830151611af2602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151611b1a604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606083015160608301526080830151608083015260a0830151611b4660a084018263ffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b7b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f60208284031215611baa575f80fd5b5035919050565b5f806101a08385031215611bc3575f80fd5b611bcd8484611931565b915061018083013567ffffffffffffffff811115611be9575f80fd5b611bf585828601611821565b9150509250929050565b5f60208284031215611c0f575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561137857611378611c16565b808202811582820484141761137857611378611c16565b8181038181111561137857611378611c16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081528151602082015273ffffffffffffffffffffffffffffffffffffffff60208301511660408201525f604083015160806060840152611d1160a0840182611c80565b9050606084015160808401528091505092915050565b5f6113783683611821565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152813560208201525f6020830135611d93816117fd565b73ffffffffffffffffffffffffffffffffffffffff811660408401525060408301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611de4575f80fd5b830160208101903567ffffffffffffffff811115611e00575f80fd5b803603821315611e0e575f80fd5b60806060850152611e2360a085018284611d32565b915050606084013560808401528091505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff80861683528085166020840152506060604083015261141d6060830184611c80565b5f8060408385031215611e83575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82611ecf57611ecf611e94565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f611a6d6040830184611c80565b5f63ffffffff80841680611f2f57611f2f611e94565b92169190910492915050565b63ffffffff818116838216028082169190828114611f5b57611f5b611c16565b505092915050565b63ffffffff818116838216019080821115611f8057611f80611c16565b509291505056fea2646970667358221220e3fb228b525d90b942c7e58fe2e2034a17bd258c082fd47740e764a7be45bac664736f6c63430008190033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\x01/W_5`\xE0\x1C\x80c\xB0\x9A\xAA\xCA\x11a\0\xADW\x80c\xE3\xE6\xF5\xB2\x11a\0}W\x80c\xEE\xC5\x0B\x97\x11a\0cW\x80c\xEE\xC5\x0B\x97\x14a\x03DW\x80c\xF1O\xCB\xC8\x14a\x03LW\x80c\xFF-\xBC\x98\x14a\x02\x03W_\x80\xFD[\x80c\xE3\xE6\xF5\xB2\x14a\x02\xFDW\x80c\xE5\x16q[\x14a\x03\x1DW_\x80\xFD[\x80c\xB0\x9A\xAA\xCA\x14a\x02\x89W\x80c\xC5\xF3\xD2T\x14a\x02\x9CW\x80c\xD2\x12 \xA7\x14a\x02\xAFW\x80c\xD2^\x0C\xB6\x14a\x02\xD6W_\x80\xFD[\x80c\x1C}\xE9A\x11a\x01\x02W\x80cH\x1Cju\x11a\0\xE8W\x80cH\x1Cju\x14a\x021W\x80c\x98\x1A\x16\x0B\x14a\x02XW\x80c\xA0)\xA8\xD4\x14a\x02vW_\x80\xFD[\x80c\x1C}\xE9A\x14a\x02\x03W\x80c>pn2\x14a\x02\nW_\x80\xFD[\x80c\r\xFE\x16\x81\x14a\x013W\x80c\x13\x03\xA4\x84\x14a\x01\x84W\x80c\x16&\xBA~\x14a\x01\xB5W\x80c\x17p\x0F\x01\x14a\x01\xF9W[_\x80\xFD[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\[`@Q\x90\x81R` \x01a\x01{V[a\x01\xC8a\x01\xC36`\x04a\x16\xBFV[a\x03_V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x04\xD7V[\0[a\x01\xA7_\x81V[a\x01\xA7\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\x81V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x02aa\x01,\x81V[`@Qc\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x02\x846`\x04a\x19\xEEV[a\x05sV[a\x01\xA7a\x02\x976`\x04a\x1A;V[a\x0B\xC8V[a\x02\x01a\x02\xAA6`\x04a\x1AuV[a\x0B\xF7V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x03\x10a\x03\x0B6`\x04a\x1A;V[a\x0C\xB7V[`@Qa\x01{\x91\x90a\x1A\xACV[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7_T\x81V[a\x02\x01a\x03Z6`\x04a\x1B\x9AV[a\x11\xFCV[_\x80\x80a\x03n\x84\x86\x01\x86a\x1B\xB1V[\x91P\x91P_Ta\x03}\x82a\x0B\xC8V[\x14a\x03\xB4W`@Q\x7F\xF1\xA6x\x90\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x82\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x02\x82\x01R`\"\x81\x01\x91\x90\x91R`B\x90 \x86\x81\x14a\x04\x94W`@Q\x7FY?\xCA\xCD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x04\x9F\x81\x83\x85a\x12\x91V[a\x04\xA9\x82\x84a\x05sV[P\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92PPP[\x93\x92PPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x05FW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80\x80U`@Q\x7F\xBC\xB8\xB8\xFB\xDE\xA8\xAAm\xC4\xAEA!>M\xA8\x1E`Z=\x1AV\xED\x85\x1B\x93U\x18#!\xC0\x91\x90\x91\x90\xA1V[\x80Q\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16\x91\x16\x14a\x06wW\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x06uW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x12`$\x82\x01R\x7Finvalid sell token\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x90[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x06\xE1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x05\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90\x91P_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x07rW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x96\x91\x90a\x1B\xFFV[\x90P\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x081W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7Finvalid buy token\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`@\x85\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x15a\x08\xB3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7Freceiver must be zero address\0\0\0`D\x82\x01R`d\x01a\x06lV[a\x08\xBFa\x01,Ba\x1CCV[\x85`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x11\x15a\t2W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7Fvalidity too far in the future\0\0`D\x82\x01R`d\x01a\x06lV[\x85``\x01Q\x85`\xC0\x01Q\x14a\t\xA3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x0F`$\x82\x01R\x7Finvalid appData\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`\xE0\x85\x01Q\x15a\n\x0FW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Ffee amount must be zero\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01`\x01Q\x14a\n\x9DW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FbuyTokenBalance must be erc20\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01@\x01Q\x14a\x0B+W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FsellTokenBalance must be erc20\0\0`D\x82\x01R`d\x01a\x06lV[``\x85\x01Qa\x0B:\x90\x82a\x1CVV[`\x80\x86\x01Q``\x87\x01Qa\x0BN\x90\x85a\x1CmV[a\x0BX\x91\x90a\x1CVV[\x10\x15a\x0B\xC0W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Freceived amount too low\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[PPPPPPV[_\x81`@Q` \x01a\x0B\xDA\x91\x90a\x1C\xCCV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x0CfW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x0Csa\x02\x97\x83a\x1D'V[\x90P\x80_\x81\x90UP\x80\x7FQ\x0EJOv\x90|-aX\xB3C\xF7\xC4\xF2\xF5\x97\xDF8[r|&\xE9\xEF\x90\xE7P\x93\xAC\xE1\x9A\x83`@Qa\x0C\xAB\x91\x90a\x1DyV[`@Q\x80\x91\x03\x90\xA2PPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R_\x80\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c5^\xFD\xD9\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87`@\x01Q`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\r\x9E\x93\x92\x91\x90a\x1E:V[`@\x80Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\r\xB8W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\r\xDC\x91\x90a\x1ErV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x91\x93P\x91P_\x90\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0EmW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0E\x91\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0F\x19W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0F=\x91\x90a\x1B\xFFV[\x90\x92P\x90P_\x80\x80\x80\x80a\x0FQ\x88\x88a\x1CVV[\x90P_a\x0F^\x8A\x88a\x1CVV[\x90P_\x82\x82\x10\x15a\x10\x0BW\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x0F\xD6a\x0F\xBD`\x02\x8Ba\x1E\xC1V[a\x0F\xD1\x84a\x0F\xCC\x8E`\x02a\x1CVV[a\x13FV[a\x13~V[\x94Pa\x10\x01\x85a\x0F\xE6\x81\x8Da\x1CVV[a\x0F\xF0\x90\x85a\x1CCV[a\x0F\xFA\x8C\x8Fa\x1CVV[`\x01a\x13\xCBV[\x93P\x84\x90Pa\x10\x98V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x10na\x10_`\x02\x8Aa\x1E\xC1V[a\x0F\xD1\x85a\x0F\xCC\x8F`\x02a\x1CVV[\x94Pa\x10\x92\x85a\x10~\x81\x8Ea\x1CVV[a\x10\x88\x90\x86a\x1CCV[a\x0F\xFA\x8B\x8Ea\x1CVV[\x93P\x83\x90P[\x8CQ\x81\x10\x15a\x10\xDFWa\x10\xDF`@Q\x80`@\x01`@R\x80`\x17\x81R` \x01\x7Ftraded amount too small\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[`@Q\x80a\x01\x80\x01`@R\x80\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86\x81R` \x01\x85\x81R` \x01a\x11Va\x01,a\x14fV[c\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8E``\x01Q\x81R` \x01_\x81R` \x01\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x81R` \x01`\x01\x15\x15\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81RP\x9BPPPPPPPPPPPP\x91\x90PV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x12kW`@Q\x7F\xBF\x84\x89w\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x80\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93]PV[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\\x83\x81\x14a\x13@W\x80\x15a\x12\xF2W`@Q\x7F\xDA\xFB\xDD\x1F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x12\xFC\x84a\x0C\xB7V[\x90Pa\x13\x08\x83\x82a\x14\x87V[a\x13>W`@Q\x7F\xD9\xFF$\xC7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P[PPPPV[_\x82\x15a\x13sW\x81a\x13Y`\x01\x85a\x1CmV[a\x13c\x91\x90a\x1E\xC1V[a\x13n\x90`\x01a\x1CCV[a\x13uV[_[\x90P[\x92\x91PPV[_\x81\x83\x10\x15a\x13\xC5Wa\x13\xC5`@Q\x80`@\x01`@R\x80`\x15\x81R` \x01\x7Fsubtraction underflow\0\0\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[P\x90\x03\x90V[_\x80a\x13\xD8\x86\x86\x86a\x15\x99V[\x90P`\x01\x83`\x02\x81\x11\x15a\x13\xEEWa\x13\xEEa\x1E\xD4V[\x14\x80\x15a\x14\nWP_\x84\x80a\x14\x05Wa\x14\x05a\x1E\x94V[\x86\x88\t\x11[\x15a\x14\x1DWa\x14\x1A`\x01\x82a\x1CCV[\x90P[\x95\x94PPPPPV[a\x141C`\x01a\x1CCV[\x81`@Q\x7F\x1F\xE8Pn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x06l\x92\x91\x90a\x1F\x01V[_\x81\x80a\x14s\x81Ba\x1F\x19V[a\x14}\x91\x90a\x1F;V[a\x13x\x91\x90a\x1FcV[_\x80\x82_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x84``\x01Q\x86``\x01Q\x14\x90P_\x85`\x80\x01Q\x87`\x80\x01Q\x14\x90P_\x86`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x88`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x14\x90P_\x87a\x01\0\x01Q\x89a\x01\0\x01Q\x14\x90P_\x88a\x01 \x01Q\x15\x15\x8Aa\x01 \x01Q\x15\x15\x14\x90P\x86\x80\x15a\x15^WP\x85[\x80\x15a\x15gWP\x84[\x80\x15a\x15pWP\x83[\x80\x15a\x15yWP\x82[\x80\x15a\x15\x82WP\x81[\x80\x15a\x15\x8BWP\x80[\x9A\x99PPPPPPPPPPV[_\x80\x80\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x87\t\x85\x87\x02\x92P\x82\x81\x10\x83\x82\x03\x03\x91PP\x80_\x03a\x15\xEFW\x83\x82\x81a\x15\xE5Wa\x15\xE5a\x1E\x94V[\x04\x92PPPa\x04\xD0V[\x80\x84\x11a\x16XW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FMath: mulDiv overflow\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[_\x84\x86\x88\t`\x02`\x01\x87\x19\x81\x01\x88\x16\x97\x88\x90\x04`\x03\x81\x02\x83\x18\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x90\x81\x02\x90\x92\x03\x90\x91\x02_\x88\x90\x03\x88\x90\x04\x90\x91\x01\x85\x83\x11\x90\x94\x03\x93\x90\x93\x02\x93\x03\x94\x90\x94\x04\x91\x90\x91\x17\x02\x94\x93PPPPV[_\x80_`@\x84\x86\x03\x12\x15a\x16\xD1W_\x80\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x16\xEFW_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a\x17\x02W_\x80\xFD[\x815\x81\x81\x11\x15a\x17\x10W_\x80\xFD[\x87` \x82\x85\x01\x01\x11\x15a\x17!W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@R\x90V[`@Qa\x01\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\xF5Wa\x17\xF5a\x174V[`@R\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x18\x1EW_\x80\xFD[PV[_`\x80\x82\x84\x03\x12\x15a\x181W_\x80\xFD[a\x189a\x17aV[\x90P\x815\x81R` \x80\x83\x015a\x18N\x81a\x17\xFDV[\x82\x82\x01R`@\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x18lW_\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x18\x7FW_\x80\xFD[\x815\x81\x81\x11\x15a\x18\x91Wa\x18\x91a\x174V[a\x18\xC1\x84\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x17\xAEV[\x91P\x80\x82R\x86\x84\x82\x85\x01\x01\x11\x15a\x18\xD6W_\x80\xFD[\x80\x84\x84\x01\x85\x84\x017_\x84\x82\x84\x01\x01RP\x80`@\x85\x01RPPP``\x82\x015``\x82\x01R\x92\x91PPV[\x805a\x19\n\x81a\x17\xFDV[\x91\x90PV[\x805c\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x19\nW_\x80\xFD[\x805\x80\x15\x15\x81\x14a\x19\nW_\x80\xFD[_a\x01\x80\x82\x84\x03\x12\x15a\x19BW_\x80\xFD[a\x19Ja\x17\x8AV[\x90Pa\x19U\x82a\x18\xFFV[\x81Ra\x19c` \x83\x01a\x18\xFFV[` \x82\x01Ra\x19t`@\x83\x01a\x18\xFFV[`@\x82\x01R``\x82\x015``\x82\x01R`\x80\x82\x015`\x80\x82\x01Ra\x19\x99`\xA0\x83\x01a\x19\x0FV[`\xA0\x82\x01R`\xC0\x82\x015`\xC0\x82\x01R`\xE0\x82\x015`\xE0\x82\x01Ra\x01\0\x80\x83\x015\x81\x83\x01RPa\x01 a\x19\xCC\x81\x84\x01a\x19\"V[\x90\x82\x01Ra\x01@\x82\x81\x015\x90\x82\x01Ra\x01`\x91\x82\x015\x91\x81\x01\x91\x90\x91R\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1A\0W_\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x16W_\x80\xFD[a\x1A\"\x85\x82\x86\x01a\x18!V[\x92PPa\x1A2\x84` \x85\x01a\x191V[\x90P\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1AKW_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1AaW_\x80\xFD[a\x1Am\x84\x82\x85\x01a\x18!V[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a\x1A\x85W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x9BW_\x80\xFD[\x82\x01`\x80\x81\x85\x03\x12\x15a\x04\xD0W_\x80\xFD[\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81Ra\x01\x80\x81\x01` \x83\x01Qa\x1A\xF2` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x83\x01Qa\x1B\x1A`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x83\x01Q``\x83\x01R`\x80\x83\x01Q`\x80\x83\x01R`\xA0\x83\x01Qa\x1BF`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x83\x01Q`\xC0\x83\x01R`\xE0\x83\x01Q`\xE0\x83\x01Ra\x01\0\x80\x84\x01Q\x81\x84\x01RPa\x01 \x80\x84\x01Qa\x1B{\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x83\x81\x01Q\x90\x83\x01Ra\x01`\x92\x83\x01Q\x92\x90\x91\x01\x91\x90\x91R\x90V[_` \x82\x84\x03\x12\x15a\x1B\xAAW_\x80\xFD[P5\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1B\xC3W_\x80\xFD[a\x1B\xCD\x84\x84a\x191V[\x91Pa\x01\x80\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1B\xE9W_\x80\xFD[a\x1B\xF5\x85\x82\x86\x01a\x18!V[\x91PP\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1C\x0FW_\x80\xFD[PQ\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x01\x80\x82\x11\x15a\x13xWa\x13xa\x1C\x16V[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\x13xWa\x13xa\x1C\x16V[\x81\x81\x03\x81\x81\x11\x15a\x13xWa\x13xa\x1C\x16V[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[` \x81R\x81Q` \x82\x01Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x83\x01Q\x16`@\x82\x01R_`@\x83\x01Q`\x80``\x84\x01Ra\x1D\x11`\xA0\x84\x01\x82a\x1C\x80V[\x90P``\x84\x01Q`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_a\x13x6\x83a\x18!V[\x81\x83R\x81\x81` \x85\x017P_` \x82\x84\x01\x01R_` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x84\x01\x01\x90P\x92\x91PPV[` \x81R\x815` \x82\x01R_` \x83\x015a\x1D\x93\x81a\x17\xFDV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`@\x84\x01RP`@\x83\x015\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x1D\xE4W_\x80\xFD[\x83\x01` \x81\x01\x905g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1E\0W_\x80\xFD[\x806\x03\x82\x13\x15a\x1E\x0EW_\x80\xFD[`\x80``\x85\x01Ra\x1E#`\xA0\x85\x01\x82\x84a\x1D2V[\x91PP``\x84\x015`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x86\x16\x83R\x80\x85\x16` \x84\x01RP```@\x83\x01Ra\x14\x1D``\x83\x01\x84a\x1C\x80V[_\x80`@\x83\x85\x03\x12\x15a\x1E\x83W_\x80\xFD[PP\x80Q` \x90\x91\x01Q\x90\x92\x90\x91PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_\x82a\x1E\xCFWa\x1E\xCFa\x1E\x94V[P\x04\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x82\x81R`@` \x82\x01R_a\x1Am`@\x83\x01\x84a\x1C\x80V[_c\xFF\xFF\xFF\xFF\x80\x84\x16\x80a\x1F/Wa\x1F/a\x1E\x94V[\x92\x16\x91\x90\x91\x04\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x02\x80\x82\x16\x91\x90\x82\x81\x14a\x1F[Wa\x1F[a\x1C\x16V[PP\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x01\x90\x80\x82\x11\x15a\x1F\x80Wa\x1F\x80a\x1C\x16V[P\x92\x91PPV\xFE\xA2dipfsX\"\x12 \xE3\xFB\"\x8BR]\x90\xB9B\xC7\xE5\x8F\xE2\xE2\x03J\x17\xBD%\x8C\x08/\xD4w@\xE7d\xA7\xBEE\xBA\xC6dsolcC\0\x08\x19\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `CommitOutsideOfSettlement()` and selector `0xbf848977`. + ```solidity + error CommitOutsideOfSettlement(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct CommitOutsideOfSettlement; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: CommitOutsideOfSettlement) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for CommitOutsideOfSettlement { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for CommitOutsideOfSettlement { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [191u8, 132u8, 137u8, 119u8]; + const SIGNATURE: &'static str = "CommitOutsideOfSettlement()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OnlyManagerCanCall()` and selector `0xf87d0d16`. + ```solidity + error OnlyManagerCanCall(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OnlyManagerCanCall; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OnlyManagerCanCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OnlyManagerCanCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OnlyManagerCanCall { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 125u8, 13u8, 22u8]; + const SIGNATURE: &'static str = "OnlyManagerCanCall()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderDoesNotMatchCommitmentHash()` and selector `0xdafbdd1f`. + ```solidity + error OrderDoesNotMatchCommitmentHash(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderDoesNotMatchCommitmentHash; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderDoesNotMatchCommitmentHash) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderDoesNotMatchCommitmentHash { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderDoesNotMatchCommitmentHash { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [218u8, 251u8, 221u8, 31u8]; + const SIGNATURE: &'static str = "OrderDoesNotMatchCommitmentHash()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderDoesNotMatchDefaultTradeableOrder()` and selector `0xd9ff24c7`. + ```solidity + error OrderDoesNotMatchDefaultTradeableOrder(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderDoesNotMatchDefaultTradeableOrder; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderDoesNotMatchDefaultTradeableOrder) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderDoesNotMatchDefaultTradeableOrder { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderDoesNotMatchDefaultTradeableOrder { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [217u8, 255u8, 36u8, 199u8]; + const SIGNATURE: &'static str = "OrderDoesNotMatchDefaultTradeableOrder()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderDoesNotMatchMessageHash()` and selector `0x593fcacd`. + ```solidity + error OrderDoesNotMatchMessageHash(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderDoesNotMatchMessageHash; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderDoesNotMatchMessageHash) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderDoesNotMatchMessageHash { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderDoesNotMatchMessageHash { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [89u8, 63u8, 202u8, 205u8]; + const SIGNATURE: &'static str = "OrderDoesNotMatchMessageHash()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderNotValid(string)` and selector `0xc8fc2725`. + ```solidity + error OrderNotValid(string); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderNotValid(pub alloy_sol_types::private::String); + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderNotValid) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderNotValid { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderNotValid { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [200u8, 252u8, 39u8, 37u8]; + const SIGNATURE: &'static str = "OrderNotValid(string)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `PollTryAtBlock(uint256,string)` and selector `0x1fe8506e`. + ```solidity + error PollTryAtBlock(uint256 blockNumber, string message); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PollTryAtBlock { + #[allow(missing_docs)] + pub blockNumber: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub message: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: PollTryAtBlock) -> Self { + (value.blockNumber, value.message) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for PollTryAtBlock { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + blockNumber: tuple.0, + message: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for PollTryAtBlock { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [31u8, 232u8, 80u8, 110u8]; + const SIGNATURE: &'static str = "PollTryAtBlock(uint256,string)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.blockNumber, + ), + ::tokenize( + &self.message, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `TradingParamsDoNotMatchHash()` and selector `0xf1a67890`. + ```solidity + error TradingParamsDoNotMatchHash(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct TradingParamsDoNotMatchHash; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: TradingParamsDoNotMatchHash) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for TradingParamsDoNotMatchHash { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for TradingParamsDoNotMatchHash { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [241u8, 166u8, 120u8, 144u8]; + const SIGNATURE: &'static str = "TradingParamsDoNotMatchHash()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TradingDisabled()` and selector `0xbcb8b8fbdea8aa6dc4ae41213e4da81e605a3d1a56ed851b9355182321c09190`. + ```solidity + event TradingDisabled(); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TradingDisabled; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TradingDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "TradingDisabled()"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 188u8, 184u8, 184u8, 251u8, 222u8, 168u8, 170u8, 109u8, 196u8, 174u8, 65u8, + 33u8, 62u8, 77u8, 168u8, 30u8, 96u8, 90u8, 61u8, 26u8, 86u8, 237u8, 133u8, + 27u8, 147u8, 85u8, 24u8, 35u8, 33u8, 192u8, 145u8, 144u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self {} + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TradingDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TradingDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TradingDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TradingEnabled(bytes32,(uint256,address,bytes,bytes32))` and selector `0x510e4a4f76907c2d6158b343f7c4f2f597df385b727c26e9ef90e75093ace19a`. + ```solidity + event TradingEnabled(bytes32 indexed hash, ConstantProduct.TradingParams params); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TradingEnabled { + #[allow(missing_docs)] + pub hash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub params: ::RustType, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TradingEnabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (ConstantProduct::TradingParams,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "TradingEnabled(bytes32,(uint256,address,bytes,bytes32))"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 81u8, 14u8, 74u8, 79u8, 118u8, 144u8, 124u8, 45u8, 97u8, 88u8, 179u8, 67u8, + 247u8, 196u8, 242u8, 245u8, 151u8, 223u8, 56u8, 91u8, 114u8, 124u8, 38u8, + 233u8, 239u8, 144u8, 231u8, 80u8, 147u8, 172u8, 225u8, 154u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + hash: topics.1, + params: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.params, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.hash.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.hash); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TradingEnabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TradingEnabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TradingEnabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address _solutionSettler, address _token0, address _token1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _solutionSettler: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _token0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _token1: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._solutionSettler, value._token0, value._token1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _solutionSettler: tuple.0, + _token0: tuple.1, + _token1: tuple.2, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._solutionSettler, + ), + ::tokenize( + &self._token0, + ), + ::tokenize( + &self._token1, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `commit(bytes32)` and selector `0xf14fcbc8`. + ```solidity + function commit(bytes32 orderHash) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct commitCall { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`commit(bytes32)`](commitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct commitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: commitCall) -> Self { + (value.orderHash,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for commitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { orderHash: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: commitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for commitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl commitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for commitCall { + type Parameters<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Return = commitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [241u8, 79u8, 203u8, 200u8]; + const SIGNATURE: &'static str = "commit(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + commitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `hash((uint256,address,bytes,bytes32))` and selector `0xb09aaaca`. + ```solidity + function hash(ConstantProduct.TradingParams memory tradingParams) external pure returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct hashCall { + #[allow(missing_docs)] + pub tradingParams: ::RustType, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`hash((uint256,address,bytes,bytes32))`](hashCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct hashReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (ConstantProduct::TradingParams,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: hashCall) -> Self { + (value.tradingParams,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for hashCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tradingParams: tuple.0, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: hashReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for hashReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for hashCall { + type Parameters<'a> = (ConstantProduct::TradingParams,); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [176u8, 154u8, 170u8, 202u8]; + const SIGNATURE: &'static str = "hash((uint256,address,bytes,bytes32))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tradingParams, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: hashReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: hashReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes32,bytes)` and selector `0x1626ba7e`. + ```solidity + function isValidSignature(bytes32 _hash, bytes memory signature) external view returns (bytes4); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureCall { + #[allow(missing_docs)] + pub _hash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub signature: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes32,bytes)`](isValidSignatureCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureCall) -> Self { + (value._hash, value.signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _hash: tuple.0, + signature: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignatureCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 38u8, 186u8, 126u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes32,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self._hash), + ::tokenize( + &self.signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `manager()` and selector `0x481c6a75`. + ```solidity + function manager() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct managerCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`manager()`](managerCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct managerReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: managerCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for managerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: managerReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for managerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for managerCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [72u8, 28u8, 106u8, 117u8]; + const SIGNATURE: &'static str = "manager()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: managerReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: managerReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token0()` and selector `0x0dfe1681`. + ```solidity + function token0() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token0()`](token0Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token0Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [13u8, 254u8, 22u8, 129u8]; + const SIGNATURE: &'static str = "token0()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token0Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token0Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token1()` and selector `0xd21220a7`. + ```solidity + function token1() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token1()`](token1Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token1Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [210u8, 18u8, 32u8, 167u8]; + const SIGNATURE: &'static str = "token1()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token1Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token1Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `verify((uint256,address,bytes,bytes32),(address,address,address,uint256,uint256,uint32,bytes32,uint256,bytes32,bool,bytes32,bytes32))` and selector `0xa029a8d4`. + ```solidity + function verify(ConstantProduct.TradingParams memory tradingParams, GPv2Order.Data memory order) external view; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct verifyCall { + #[allow(missing_docs)] + pub tradingParams: ::RustType, + #[allow(missing_docs)] + pub order: ::RustType, + } + ///Container type for the return parameters of the + /// [`verify((uint256,address,bytes,bytes32),(address,address,address, + /// uint256,uint256,uint32,bytes32,uint256,bytes32,bool,bytes32, + /// bytes32))`](verifyCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct verifyReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (ConstantProduct::TradingParams, GPv2Order::Data); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: verifyCall) -> Self { + (value.tradingParams, value.order) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for verifyCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tradingParams: tuple.0, + order: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: verifyReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for verifyReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl verifyReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for verifyCall { + type Parameters<'a> = (ConstantProduct::TradingParams, GPv2Order::Data); + type Return = verifyReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [160u8, 41u8, 168u8, 212u8]; + const SIGNATURE: &'static str = "verify((uint256,address,bytes,bytes32),(address,\ + address,address,uint256,uint256,uint32,bytes32,\ + uint256,bytes32,bool,bytes32,bytes32))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tradingParams, + ), + ::tokenize(&self.order), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + verifyReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`CowAmm`](self) function calls. + #[derive(Clone)] + pub enum CowAmmCalls { + #[allow(missing_docs)] + commit(commitCall), + #[allow(missing_docs)] + hash(hashCall), + #[allow(missing_docs)] + isValidSignature(isValidSignatureCall), + #[allow(missing_docs)] + manager(managerCall), + #[allow(missing_docs)] + token0(token0Call), + #[allow(missing_docs)] + token1(token1Call), + #[allow(missing_docs)] + verify(verifyCall), + } + impl CowAmmCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [13u8, 254u8, 22u8, 129u8], + [22u8, 38u8, 186u8, 126u8], + [72u8, 28u8, 106u8, 117u8], + [160u8, 41u8, 168u8, 212u8], + [176u8, 154u8, 170u8, 202u8], + [210u8, 18u8, 32u8, 167u8], + [241u8, 79u8, 203u8, 200u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(token0), + ::core::stringify!(isValidSignature), + ::core::stringify!(manager), + ::core::stringify!(verify), + ::core::stringify!(hash), + ::core::stringify!(token1), + ::core::stringify!(commit), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowAmmCalls { + const COUNT: usize = 7usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CowAmmCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::commit(_) => ::SELECTOR, + Self::hash(_) => ::SELECTOR, + Self::isValidSignature(_) => { + ::SELECTOR + } + Self::manager(_) => ::SELECTOR, + Self::token0(_) => ::SELECTOR, + Self::token1(_) => ::SELECTOR, + Self::verify(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmCalls::token0) + } + token0 + }, + { + fn isValidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmCalls::isValidSignature) + } + isValidSignature + }, + { + fn manager(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmCalls::manager) + } + manager + }, + { + fn verify(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmCalls::verify) + } + verify + }, + { + fn hash(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmCalls::hash) + } + hash + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmCalls::token1) + } + token1 + }, + { + fn commit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmCalls::commit) + } + commit + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmCalls::token0) + } + token0 + }, + { + fn isValidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmCalls::isValidSignature) + } + isValidSignature + }, + { + fn manager(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmCalls::manager) + } + manager + }, + { + fn verify(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmCalls::verify) + } + verify + }, + { + fn hash(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmCalls::hash) + } + hash + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmCalls::token1) + } + token1 + }, + { + fn commit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmCalls::commit) + } + commit + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::commit(inner) => { + ::abi_encoded_size(inner) + } + Self::hash(inner) => { + ::abi_encoded_size(inner) + } + Self::isValidSignature(inner) => { + ::abi_encoded_size(inner) + } + Self::manager(inner) => { + ::abi_encoded_size(inner) + } + Self::token0(inner) => { + ::abi_encoded_size(inner) + } + Self::token1(inner) => { + ::abi_encoded_size(inner) + } + Self::verify(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::commit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::hash(inner) => { + ::abi_encode_raw(inner, out) + } + Self::isValidSignature(inner) => { + ::abi_encode_raw(inner, out) + } + Self::manager(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token0(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token1(inner) => { + ::abi_encode_raw(inner, out) + } + Self::verify(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CowAmm`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowAmmErrors { + #[allow(missing_docs)] + CommitOutsideOfSettlement(CommitOutsideOfSettlement), + #[allow(missing_docs)] + OnlyManagerCanCall(OnlyManagerCanCall), + #[allow(missing_docs)] + OrderDoesNotMatchCommitmentHash(OrderDoesNotMatchCommitmentHash), + #[allow(missing_docs)] + OrderDoesNotMatchDefaultTradeableOrder(OrderDoesNotMatchDefaultTradeableOrder), + #[allow(missing_docs)] + OrderDoesNotMatchMessageHash(OrderDoesNotMatchMessageHash), + #[allow(missing_docs)] + OrderNotValid(OrderNotValid), + #[allow(missing_docs)] + PollTryAtBlock(PollTryAtBlock), + #[allow(missing_docs)] + TradingParamsDoNotMatchHash(TradingParamsDoNotMatchHash), + } + impl CowAmmErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [31u8, 232u8, 80u8, 110u8], + [89u8, 63u8, 202u8, 205u8], + [191u8, 132u8, 137u8, 119u8], + [200u8, 252u8, 39u8, 37u8], + [217u8, 255u8, 36u8, 199u8], + [218u8, 251u8, 221u8, 31u8], + [241u8, 166u8, 120u8, 144u8], + [248u8, 125u8, 13u8, 22u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(PollTryAtBlock), + ::core::stringify!(OrderDoesNotMatchMessageHash), + ::core::stringify!(CommitOutsideOfSettlement), + ::core::stringify!(OrderNotValid), + ::core::stringify!(OrderDoesNotMatchDefaultTradeableOrder), + ::core::stringify!(OrderDoesNotMatchCommitmentHash), + ::core::stringify!(TradingParamsDoNotMatchHash), + ::core::stringify!(OnlyManagerCanCall), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowAmmErrors { + const COUNT: usize = 8usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CowAmmErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::CommitOutsideOfSettlement(_) => { + ::SELECTOR + } + Self::OnlyManagerCanCall(_) => { + ::SELECTOR + } + Self::OrderDoesNotMatchCommitmentHash(_) => { + ::SELECTOR + } + Self::OrderDoesNotMatchDefaultTradeableOrder(_) => { + ::SELECTOR + } + Self::OrderDoesNotMatchMessageHash(_) => { + ::SELECTOR + } + Self::OrderNotValid(_) => ::SELECTOR, + Self::PollTryAtBlock(_) => ::SELECTOR, + Self::TradingParamsDoNotMatchHash(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn PollTryAtBlock(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmErrors::PollTryAtBlock) + } + PollTryAtBlock + }, + { + fn OrderDoesNotMatchMessageHash( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CowAmmErrors::OrderDoesNotMatchMessageHash) + } + OrderDoesNotMatchMessageHash + }, + { + fn CommitOutsideOfSettlement( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CowAmmErrors::CommitOutsideOfSettlement) + } + CommitOutsideOfSettlement + }, + { + fn OrderNotValid(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmErrors::OrderNotValid) + } + OrderNotValid + }, + { + fn OrderDoesNotMatchDefaultTradeableOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CowAmmErrors::OrderDoesNotMatchDefaultTradeableOrder) + } + OrderDoesNotMatchDefaultTradeableOrder + }, + { + fn OrderDoesNotMatchCommitmentHash( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CowAmmErrors::OrderDoesNotMatchCommitmentHash) + } + OrderDoesNotMatchCommitmentHash + }, + { + fn TradingParamsDoNotMatchHash( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CowAmmErrors::TradingParamsDoNotMatchHash) + } + TradingParamsDoNotMatchHash + }, + { + fn OnlyManagerCanCall(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmErrors::OnlyManagerCanCall) + } + OnlyManagerCanCall + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn PollTryAtBlock(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmErrors::PollTryAtBlock) + } + PollTryAtBlock + }, + { + fn OrderDoesNotMatchMessageHash( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmErrors::OrderDoesNotMatchMessageHash) + } + OrderDoesNotMatchMessageHash + }, + { + fn CommitOutsideOfSettlement( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmErrors::CommitOutsideOfSettlement) + } + CommitOutsideOfSettlement + }, + { + fn OrderNotValid(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmErrors::OrderNotValid) + } + OrderNotValid + }, + { + fn OrderDoesNotMatchDefaultTradeableOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmErrors::OrderDoesNotMatchDefaultTradeableOrder) + } + OrderDoesNotMatchDefaultTradeableOrder + }, + { + fn OrderDoesNotMatchCommitmentHash( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmErrors::OrderDoesNotMatchCommitmentHash) + } + OrderDoesNotMatchCommitmentHash + }, + { + fn TradingParamsDoNotMatchHash( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmErrors::TradingParamsDoNotMatchHash) + } + TradingParamsDoNotMatchHash + }, + { + fn OnlyManagerCanCall(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmErrors::OnlyManagerCanCall) + } + OnlyManagerCanCall + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::CommitOutsideOfSettlement(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::OnlyManagerCanCall(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::OrderDoesNotMatchCommitmentHash(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::OrderDoesNotMatchDefaultTradeableOrder(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::OrderDoesNotMatchMessageHash(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::OrderNotValid(inner) => { + ::abi_encoded_size(inner) + } + Self::PollTryAtBlock(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::TradingParamsDoNotMatchHash(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::CommitOutsideOfSettlement(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::OnlyManagerCanCall(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::OrderDoesNotMatchCommitmentHash(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::OrderDoesNotMatchDefaultTradeableOrder(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::OrderDoesNotMatchMessageHash(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::OrderNotValid(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::PollTryAtBlock(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::TradingParamsDoNotMatchHash(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + } + } + } + ///Container for all the [`CowAmm`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowAmmEvents { + #[allow(missing_docs)] + TradingDisabled(TradingDisabled), + #[allow(missing_docs)] + TradingEnabled(TradingEnabled), + } + impl CowAmmEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 81u8, 14u8, 74u8, 79u8, 118u8, 144u8, 124u8, 45u8, 97u8, 88u8, 179u8, 67u8, 247u8, + 196u8, 242u8, 245u8, 151u8, 223u8, 56u8, 91u8, 114u8, 124u8, 38u8, 233u8, 239u8, + 144u8, 231u8, 80u8, 147u8, 172u8, 225u8, 154u8, + ], + [ + 188u8, 184u8, 184u8, 251u8, 222u8, 168u8, 170u8, 109u8, 196u8, 174u8, 65u8, 33u8, + 62u8, 77u8, 168u8, 30u8, 96u8, 90u8, 61u8, 26u8, 86u8, 237u8, 133u8, 27u8, 147u8, + 85u8, 24u8, 35u8, 33u8, 192u8, 145u8, 144u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(TradingEnabled), + ::core::stringify!(TradingDisabled), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for CowAmmEvents { + const COUNT: usize = 2usize; + const NAME: &'static str = "CowAmmEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::TradingDisabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::TradingEnabled) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for CowAmmEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::TradingDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::TradingEnabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::TradingDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TradingEnabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CowAmm`](self) contract instance. + + See the [wrapper's documentation](`CowAmmInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CowAmmInstance { + CowAmmInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _solutionSettler: alloy_sol_types::private::Address, + _token0: alloy_sol_types::private::Address, + _token1: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> { + CowAmmInstance::::deploy(__provider, _solutionSettler, _token0, _token1) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _solutionSettler: alloy_sol_types::private::Address, + _token0: alloy_sol_types::private::Address, + _token1: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + CowAmmInstance::::deploy_builder(__provider, _solutionSettler, _token0, _token1) + } + /**A [`CowAmm`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CowAmm`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CowAmmInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CowAmmInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CowAmmInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CowAmmInstance + { + /**Creates a new wrapper around an on-chain [`CowAmm`](self) contract instance. + + See the [wrapper's documentation](`CowAmmInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _solutionSettler: alloy_sol_types::private::Address, + _token0: alloy_sol_types::private::Address, + _token1: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, _solutionSettler, _token0, _token1); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _solutionSettler: alloy_sol_types::private::Address, + _token0: alloy_sol_types::private::Address, + _token1: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + _solutionSettler, + _token0, + _token1, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CowAmmInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CowAmmInstance { + CowAmmInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CowAmmInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`commit`] function. + pub fn commit( + &self, + orderHash: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, commitCall, N> { + self.call_builder(&commitCall { orderHash }) + } + + ///Creates a new call builder for the [`hash`] function. + pub fn hash( + &self, + tradingParams: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, hashCall, N> { + self.call_builder(&hashCall { tradingParams }) + } + + ///Creates a new call builder for the [`isValidSignature`] function. + pub fn isValidSignature( + &self, + _hash: alloy_sol_types::private::FixedBytes<32>, + signature: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignatureCall, N> { + self.call_builder(&isValidSignatureCall { _hash, signature }) + } + + ///Creates a new call builder for the [`manager`] function. + pub fn manager(&self) -> alloy_contract::SolCallBuilder<&P, managerCall, N> { + self.call_builder(&managerCall) + } + + ///Creates a new call builder for the [`token0`] function. + pub fn token0(&self) -> alloy_contract::SolCallBuilder<&P, token0Call, N> { + self.call_builder(&token0Call) + } + + ///Creates a new call builder for the [`token1`] function. + pub fn token1(&self) -> alloy_contract::SolCallBuilder<&P, token1Call, N> { + self.call_builder(&token1Call) + } + + ///Creates a new call builder for the [`verify`] function. + pub fn verify( + &self, + tradingParams: ::RustType, + order: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, verifyCall, N> { + self.call_builder(&verifyCall { + tradingParams, + order, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CowAmmInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`TradingDisabled`] event. + pub fn TradingDisabled_filter(&self) -> alloy_contract::Event<&P, TradingDisabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TradingEnabled`] event. + pub fn TradingEnabled_filter(&self) -> alloy_contract::Event<&P, TradingEnabled, N> { + self.event_filter::() + } + } +} +pub type Instance = CowAmm::CowAmmInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/cowammconstantproductfactory/Cargo.toml b/contracts/generated/contracts-generated/cowammconstantproductfactory/Cargo.toml new file mode 100644 index 0000000000..f5e1521cc8 --- /dev/null +++ b/contracts/generated/contracts-generated/cowammconstantproductfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowammconstantproductfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowammconstantproductfactory/src/lib.rs b/contracts/generated/contracts-generated/cowammconstantproductfactory/src/lib.rs new file mode 100644 index 0000000000..ea4a654388 --- /dev/null +++ b/contracts/generated/contracts-generated/cowammconstantproductfactory/src/lib.rs @@ -0,0 +1,3081 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library IConditionalOrder { + struct ConditionalOrderParams { address handler; bytes32 salt; bytes staticInput; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IConditionalOrder { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct ConditionalOrderParams { address handler; bytes32 salt; bytes staticInput; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ConditionalOrderParams { + #[allow(missing_docs)] + pub handler: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub salt: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub staticInput: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ConditionalOrderParams) -> Self { + (value.handler, value.salt, value.staticInput) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ConditionalOrderParams { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + handler: tuple.0, + salt: tuple.1, + staticInput: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for ConditionalOrderParams { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for ConditionalOrderParams { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.handler, + ), + as alloy_sol_types::SolType>::tokenize(&self.salt), + ::tokenize( + &self.staticInput, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for ConditionalOrderParams { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for ConditionalOrderParams { + const NAME: &'static str = "ConditionalOrderParams"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "ConditionalOrderParams(address handler,bytes32 salt,bytes staticInput)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.handler, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.salt) + .0, + ::eip712_data_word( + &self.staticInput, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for ConditionalOrderParams { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.handler, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.salt) + + ::topic_preimage_length( + &rust.staticInput, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.handler, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.salt, + out, + ); + ::encode_topic_preimage( + &rust.staticInput, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IConditionalOrder`](self) contract instance. + + See the [wrapper's documentation](`IConditionalOrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IConditionalOrderInstance { + IConditionalOrderInstance::::new(address, __provider) + } + /**A [`IConditionalOrder`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IConditionalOrder`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IConditionalOrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IConditionalOrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IConditionalOrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IConditionalOrderInstance + { + /**Creates a new wrapper around an on-chain [`IConditionalOrder`](self) contract instance. + + See the [wrapper's documentation](`IConditionalOrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IConditionalOrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IConditionalOrderInstance { + IConditionalOrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IConditionalOrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IConditionalOrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library IConditionalOrder { + struct ConditionalOrderParams { + address handler; + bytes32 salt; + bytes staticInput; + } +} + +interface CowAmmConstantProductFactory { + error OnlyOwnerCanCall(address owner); + error OrderNotValid(string); + + event ConditionalOrderCreated(address indexed owner, IConditionalOrder.ConditionalOrderParams params); + event Deployed(address indexed amm, address indexed owner, address token0, address token1); + event TradingDisabled(address indexed amm); + + constructor(address _settler); + + function ammDeterministicAddress(address ammOwner, address token0, address token1) external view returns (address); + function create(address token0, uint256 amount0, address token1, uint256 amount1, uint256 minTradedToken0, address priceOracle, bytes memory priceOracleData, bytes32 appData) external returns (address amm); + function deposit(address amm, uint256 amount0, uint256 amount1) external; + function owner(address) external view returns (address); + function withdraw(address amm, uint256 amount0, uint256 amount1) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_settler", + "type": "address", + "internalType": "contract ISettlement" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "ammDeterministicAddress", + "inputs": [ + { + "name": "ammOwner", + "type": "address", + "internalType": "address" + }, + { + "name": "token0", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "token1", + "type": "address", + "internalType": "contract IERC20" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "create", + "inputs": [ + { + "name": "token0", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "token1", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minTradedToken0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "priceOracle", + "type": "address", + "internalType": "contract IPriceOracle" + }, + { + "name": "priceOracleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "deposit", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" + }, + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "owner", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ConstantProduct" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "withdraw", + "inputs": [ + { + "name": "amm", + "type": "address", + "internalType": "contract ConstantProduct" + }, + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ConditionalOrderCreated", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "params", + "type": "tuple", + "indexed": false, + "internalType": "struct IConditionalOrder.ConditionalOrderParams", + "components": [ + { + "name": "handler", + "type": "address", + "internalType": "contract IConditionalOrder" + }, + { + "name": "salt", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "staticInput", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Deployed", + "inputs": [ + { + "name": "amm", + "type": "address", + "indexed": true, + "internalType": "contract ConstantProduct" + }, + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token0", + "type": "address", + "indexed": false, + "internalType": "contract IERC20" + }, + { + "name": "token1", + "type": "address", + "indexed": false, + "internalType": "contract IERC20" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TradingDisabled", + "inputs": [ + { + "name": "amm", + "type": "address", + "indexed": true, + "internalType": "contract ConstantProduct" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "OnlyOwnerCanCall", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OrderNotValid", + "inputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CowAmmConstantProductFactory { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60a0604052348015600e575f80fd5b506040516141b33803806141b3833981016040819052602b91603b565b6001600160a01b03166080526066565b5f60208284031215604a575f80fd5b81516001600160a01b0381168114605f575f80fd5b9392505050565b60805161412761008c5f395f8181610189015281816102a801526108c401526141275ff3fe608060405234801561000f575f80fd5b506004361061009f575f3560e01c806337ebdf5011610072578063666e1b3911610058578063666e1b391461014f578063ab221a7614610184578063b5c5f672146101ab575f80fd5b806337ebdf50146101295780635b5d9ee61461013c575f80fd5b80630efe6a8b146100a357806322b155c6146100b857806326e0a196146100f55780632791056514610116575b5f80fd5b6100b66100b13660046111ea565b6101be565b005b6100cb6100c6366004611261565b6102a3565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101086101033660046112fb565b61045f565b6040516100ec9291906114fd565b6100b6610124366004611527565b610797565b6100cb610137366004611549565b61082f565b6100b661014a366004611591565b610a01565b6100cb61015d366004611527565b5f6020819052908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6100cb7f000000000000000000000000000000000000000000000000000000000000000081565b6100b66101b93660046111ea565b610b17565b61024f3384848673ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102319190611617565b73ffffffffffffffffffffffffffffffffffffffff16929190610c46565b61029e3384838673ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b505050565b5f33807f00000000000000000000000000000000000000000000000000000000000000008c8b6040516102d5906111b9565b73ffffffffffffffffffffffffffffffffffffffff9384168152918316602083015290911660408201526060018190604051809103905ff590508015801561031f573d5f803e3d5ffd5b506040805173ffffffffffffffffffffffffffffffffffffffff8e811682528c81166020830152929450828416928516917f6707255b2c5ca81220b2f3e408a269cb83baa6aa7e5e37aa1756883a6cdf06f1910160405180910390a373ffffffffffffffffffffffffffffffffffffffff8281165f90815260208190526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790556103d8828b8a6101be565b5f60405180608001604052808981526020018873ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050509082525060200185905290506104508382610cdb565b50509998505050505050505050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526060306104cf6020890189611527565b73ffffffffffffffffffffffffffffffffffffffff1614610551576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e206f6e6c792068616e646c65206f776e206f726465727300000000000060448201526064015b60405180910390fd5b5f61055f6040890189611632565b81019061056c919061175c565b90508873ffffffffffffffffffffffffffffffffffffffff1663eec50b976040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105db919061185a565b6040517fb09aaaca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b169063b09aaaca9061062d9085906004016118c3565b602060405180830381865afa158015610648573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061066c919061185a565b146106d3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f696e76616c69642074726164696e6720706172616d65746572730000000000006044820152606401610548565b6040517fe3e6f5b200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a169063e3e6f5b2906107259084906004016118c3565b61018060405180830381865afa158015610741573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061076591906118f7565b9250828160405160200161077a9291906119b3565b604051602081830303815290604052915050965096945050505050565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526020819052604090205482911633146108225773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b61082b82610e05565b5050565b5f807fff000000000000000000000000000000000000000000000000000000000000003073ffffffffffffffffffffffffffffffffffffffff8716604051610879602082016111b9565b8181037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09081018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166020840152808b169183019190915288166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261093a92916020016119eb565b604051602081830303815290604052805190602001206040516020016109c294939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830152603582015260550190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052805160209091012095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8087165f908152602081905260409020548791163314610a8c5773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b5f60405180608001604052808881526020018773ffffffffffffffffffffffffffffffffffffffff16815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506020018490529050610b0388610e05565b610b0d8882610cdb565b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8084165f908152602081905260409020548491163314610ba25773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b610bf18433858773ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b610c408433848773ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b50505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610c40908590610ea3565b6040517fc5f3d25400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063c5f3d25490610d2d9084906004016118c3565b5f604051808303815f87803b158015610d44575f80fd5b505af1158015610d56573d5f803e3d5ffd5b5050604080516060810182523081525f6020808301829052835191955073ffffffffffffffffffffffffffffffffffffffff881694507f2cceac5555b0ca45a3744ced542f54b56ad2eb45e521962372eef212a2cbf36193830191610dbd918891016118c3565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915251610df891906119ff565b60405180910390a2505050565b8073ffffffffffffffffffffffffffffffffffffffff166317700f016040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610e4a575f80fd5b505af1158015610e5c573d5f803e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff841692507fc75bf4f03c02fab9414a7d7a54048c0486722bc72f33ad924709a0593608ad2791505f90a250565b5f610f04826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610fb09092919063ffffffff16565b905080515f1480610f24575080806020019051810190610f249190611a43565b61029e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610548565b6060610fbe84845f85610fc6565b949350505050565b606082471015611058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610548565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516110809190611a5c565b5f6040518083038185875af1925050503d805f81146110ba576040519150601f19603f3d011682016040523d82523d5f602084013e6110bf565b606091505b50915091506110d0878383876110db565b979650505050505050565b606083156111705782515f036111695773ffffffffffffffffffffffffffffffffffffffff85163b611169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610548565b5081610fbe565b610fbe83838151156111855781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105489190611a67565b61267880611a7a83390190565b73ffffffffffffffffffffffffffffffffffffffff811681146111e7575f80fd5b50565b5f805f606084860312156111fc575f80fd5b8335611207816111c6565b95602085013595506040909401359392505050565b5f8083601f84011261122c575f80fd5b50813567ffffffffffffffff811115611243575f80fd5b60208301915083602082850101111561125a575f80fd5b9250929050565b5f805f805f805f805f6101008a8c03121561127a575f80fd5b8935611285816111c6565b985060208a0135975060408a013561129c816111c6565b965060608a0135955060808a0135945060a08a01356112ba816111c6565b935060c08a013567ffffffffffffffff8111156112d5575f80fd5b6112e18c828d0161121c565b9a9d999c50979a9699959894979660e00135949350505050565b5f805f805f8060808789031215611310575f80fd5b863561131b816111c6565b9550602087013567ffffffffffffffff80821115611337575f80fd5b908801906060828b03121561134a575f80fd5b9095506040880135908082111561135f575f80fd5b61136b8a838b0161121c565b90965094506060890135915080821115611383575f80fd5b818901915089601f830112611396575f80fd5b8135818111156113a4575f80fd5b8a60208260051b85010111156113b8575f80fd5b6020830194508093505050509295509295509295565b805173ffffffffffffffffffffffffffffffffffffffff168252602081015161140f602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151611437604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608301526080810151608083015260a081015161146360a084018263ffffffff169052565b5060c081015160c083015260e081015160e0830152610100808201518184015250610120808201516114988285018215159052565b5050610140818101519083015261016090810151910152565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b5f6101a061150b83866113ce565b8061018084015261151e818401856114b1565b95945050505050565b5f60208284031215611537575f80fd5b8135611542816111c6565b9392505050565b5f805f6060848603121561155b575f80fd5b8335611566816111c6565b92506020840135611576816111c6565b91506040840135611586816111c6565b809150509250925092565b5f805f805f8060a087890312156115a6575f80fd5b86356115b1816111c6565b95506020870135945060408701356115c8816111c6565b9350606087013567ffffffffffffffff8111156115e3575f80fd5b6115ef89828a0161121c565b979a9699509497949695608090950135949350505050565b8051611612816111c6565b919050565b5f60208284031215611627575f80fd5b8151611542816111c6565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611665575f80fd5b83018035915067ffffffffffffffff82111561167f575f80fd5b60200191503681900382131561125a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156116e3576116e3611693565b60405290565b604051610180810167ffffffffffffffff811182821017156116e3576116e3611693565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561175457611754611693565b604052919050565b5f602080838503121561176d575f80fd5b823567ffffffffffffffff80821115611784575f80fd5b9084019060808287031215611797575f80fd5b61179f6116c0565b82358152838301356117b0816111c6565b818501526040830135828111156117c5575f80fd5b8301601f810188136117d5575f80fd5b8035838111156117e7576117e7611693565b611817867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161170d565b9350808452888682840101111561182c575f80fd5b80868301878601375f8682860101525050816040820152606083013560608201528094505050505092915050565b5f6020828403121561186a575f80fd5b5051919050565b8051825273ffffffffffffffffffffffffffffffffffffffff60208201511660208301525f6040820151608060408501526118af60808501826114b1565b606093840151949093019390935250919050565b602081525f6115426020830184611871565b805163ffffffff81168114611612575f80fd5b80518015158114611612575f80fd5b5f6101808284031215611908575f80fd5b6119106116e9565b61191983611607565b815261192760208401611607565b602082015261193860408401611607565b6040820152606083015160608201526080830151608082015261195d60a084016118d5565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206119908185016118e8565b908201526101408381015190820152610160928301519281019290925250919050565b5f6101a06119c183866113ce565b8061018084015261151e81840185611871565b5f81518060208401855e5f93019283525090919050565b5f610fbe6119f983866119d4565b846119d4565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201525f6040830151606080840152610fbe60808401826114b1565b5f60208284031215611a53575f80fd5b611542826118e8565b5f61154282846119d4565b602081525f61154260208301846114b156fe610120604052348015610010575f80fd5b5060405161267838038061267883398101604081905261002f9161052f565b6001600160a01b03831660808190526040805163f698da2560e01b8152905163f698da259160048082019260209290919082900301815f875af1158015610078573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061009c9190610579565b610100526100aa823361015f565b6100b4813361015f565b336001600160a01b031660e0816001600160a01b0316815250505f836001600160a01b0316639b552cc26040518163ffffffff1660e01b81526004016020604051808303815f875af115801561010c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101309190610590565b905061013c838261015f565b610146828261015f565b506001600160a01b0391821660a0521660c0525061061c565b6101746001600160a01b038316825f19610178565b5050565b8015806101f05750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156101ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ee9190610579565b155b6102675760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526102bd9185916102c216565b505050565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908201525f9061030e906001600160a01b03851690849061038d565b905080515f148061032e57508080602001905181019061032e91906105b2565b6102bd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161025e565b606061039b84845f856103a3565b949350505050565b6060824710156104045760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161025e565b5f80866001600160a01b0316858760405161041f91906105d1565b5f6040518083038185875af1925050503d805f8114610459576040519150601f19603f3d011682016040523d82523d5f602084013e61045e565b606091505b5090925090506104708783838761047b565b979650505050505050565b606083156104e95782515f036104e2576001600160a01b0385163b6104e25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161025e565b508161039b565b61039b83838151156104fe5781518083602001fd5b8060405162461bcd60e51b815260040161025e91906105e7565b6001600160a01b038116811461052c575f80fd5b50565b5f805f60608486031215610541575f80fd5b835161054c81610518565b602085015190935061055d81610518565b604085015190925061056e81610518565b809150509250925092565b5f60208284031215610589575f80fd5b5051919050565b5f602082840312156105a0575f80fd5b81516105ab81610518565b9392505050565b5f602082840312156105c2575f80fd5b815180151581146105ab575f80fd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b60805160a05160c05160e05161010051611fbd6106bb5f395f81816102db015261042b01525f8181610236015281816104d90152610bf901525f81816102b40152818161059901528181610d5c01528181610ebf01528181610f8e015261100d01525f81816101380152818161057701528181610d3b01528181610e2801528181610f6b015261103001525f818161032201526112140152611fbd5ff3fe608060405234801561000f575f80fd5b506004361061012f575f3560e01c8063b09aaaca116100ad578063e3e6f5b21161007d578063eec50b9711610063578063eec50b9714610344578063f14fcbc81461034c578063ff2dbc9814610203575f80fd5b8063e3e6f5b2146102fd578063e516715b1461031d575f80fd5b8063b09aaaca14610289578063c5f3d2541461029c578063d21220a7146102af578063d25e0cb6146102d6575f80fd5b80631c7de94111610102578063481c6a75116100e8578063481c6a7514610231578063981a160b14610258578063a029a8d414610276575f80fd5b80631c7de941146102035780633e706e321461020a575f80fd5b80630dfe1681146101335780631303a484146101845780631626ba7e146101b557806317700f01146101f9575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c5b60405190815260200161017b565b6101c86101c33660046116bf565b61035f565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161017b565b6102016104d7565b005b6101a75f81565b6101a77f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b59381565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b61026161012c81565b60405163ffffffff909116815260200161017b565b6102016102843660046119ee565b610573565b6101a7610297366004611a3b565b610bc8565b6102016102aa366004611a75565b610bf7565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a77f000000000000000000000000000000000000000000000000000000000000000081565b61031061030b366004611a3b565b610cb7565b60405161017b9190611aac565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a75f5481565b61020161035a366004611b9a565b6111fc565b5f808061036e84860186611bb1565b915091505f5461037d82610bc8565b146103b4576040517ff1a6789000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020868114610494576040517f593fcacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049f818385611291565b6104a98284610573565b507f1626ba7e00000000000000000000000000000000000000000000000000000000925050505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610546576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8080556040517fbcb8b8fbdea8aa6dc4ae41213e4da81e605a3d1a56ed851b9355182321c091909190a1565b80517f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff808416911614610677578073ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff1614610675576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642073656c6c20746f6b656e000000000000000000000000000060448201526064015b60405180910390fd5b905b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156106e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107059190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610772573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107969190611bff565b90508273ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff1614610831576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c69642062757920746f6b656e000000000000000000000000000000604482015260640161066c565b604085015173ffffffffffffffffffffffffffffffffffffffff16156108b3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7265636569766572206d757374206265207a65726f2061646472657373000000604482015260640161066c565b6108bf61012c42611c43565b8560a0015163ffffffff161115610932576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f76616c696469747920746f6f2066617220696e20746865206675747572650000604482015260640161066c565b85606001518560c00151146109a3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420617070446174610000000000000000000000000000000000604482015260640161066c565b60e085015115610a0f576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f66656520616d6f756e74206d757374206265207a65726f000000000000000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610160015114610a9d576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f627579546f6b656e42616c616e6365206d757374206265206572633230000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610140015114610b2b576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656c6c546f6b656e42616c616e6365206d7573742062652065726332300000604482015260640161066c565b6060850151610b3a9082611c56565b60808601516060870151610b4e9085611c6d565b610b589190611c56565b1015610bc0576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f726563656976656420616d6f756e7420746f6f206c6f77000000000000000000604482015260640161066c565b505050505050565b5f81604051602001610bda9190611ccc565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c66576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610c7361029783611d27565b9050805f81905550807f510e4a4f76907c2d6158b343f7c4f2f597df385b727c26e9ef90e75093ace19a83604051610cab9190611d79565b60405180910390a25050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091525f80836020015173ffffffffffffffffffffffffffffffffffffffff1663355efdd97f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087604001516040518463ffffffff1660e01b8152600401610d9e93929190611e3a565b6040805180830381865afa158015610db8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ddc9190611e72565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291935091505f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610e6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e919190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3d9190611bff565b90925090505f80808080610f518888611c56565b90505f610f5e8a88611c56565b90505f8282101561100b577f000000000000000000000000000000000000000000000000000000000000000096507f00000000000000000000000000000000000000000000000000000000000000009550610fd6610fbd60028b611ec1565b610fd184610fcc8e6002611c56565b611346565b61137e565b945061100185610fe6818d611c56565b610ff09085611c43565b610ffa8c8f611c56565b60016113cb565b9350849050611098565b7f000000000000000000000000000000000000000000000000000000000000000096507f0000000000000000000000000000000000000000000000000000000000000000955061106e61105f60028a611ec1565b610fd185610fcc8f6002611c56565b94506110928561107e818e611c56565b6110889086611c43565b610ffa8b8e611c56565b93508390505b8c518110156110df576110df6040518060400160405280601781526020017f74726164656420616d6f756e7420746f6f20736d616c6c000000000000000000815250611426565b6040518061018001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200161115661012c611466565b63ffffffff1681526020018e6060015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98152509b505050505050505050505050919050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461126b576040517fbf84897700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935d50565b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c8381146113405780156112f2576040517fdafbdd1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112fc84610cb7565b90506113088382611487565b61133e576040517fd9ff24c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50505050565b5f82156113735781611359600185611c6d565b6113639190611ec1565b61136e906001611c43565b611375565b5f5b90505b92915050565b5f818310156113c5576113c56040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250611426565b50900390565b5f806113d8868686611599565b905060018360028111156113ee576113ee611ed4565b14801561140a57505f848061140557611405611e94565b868809115b1561141d5761141a600182611c43565b90505b95945050505050565b611431436001611c43565b816040517f1fe8506e00000000000000000000000000000000000000000000000000000000815260040161066c929190611f01565b5f81806114738142611f19565b61147d9190611f3b565b6113789190611f63565b5f80825f015173ffffffffffffffffffffffffffffffffffffffff16845f015173ffffffffffffffffffffffffffffffffffffffff161490505f836020015173ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161490505f846060015186606001511490505f856080015187608001511490505f8660a0015163ffffffff168860a0015163ffffffff161490505f8761010001518961010001511490505f88610120015115158a6101200151151514905086801561155e5750855b80156115675750845b80156115705750835b80156115795750825b80156115825750815b801561158b5750805b9a9950505050505050505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f036115ef578382816115e5576115e5611e94565b04925050506104d0565b808411611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161066c565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f805f604084860312156116d1575f80fd5b83359250602084013567ffffffffffffffff808211156116ef575f80fd5b818601915086601f830112611702575f80fd5b813581811115611710575f80fd5b876020828501011115611721575f80fd5b6020830194508093505050509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561178457611784611734565b60405290565b604051610180810167ffffffffffffffff8111828210171561178457611784611734565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117f5576117f5611734565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461181e575f80fd5b50565b5f60808284031215611831575f80fd5b611839611761565b90508135815260208083013561184e816117fd565b82820152604083013567ffffffffffffffff8082111561186c575f80fd5b818501915085601f83011261187f575f80fd5b81358181111561189157611891611734565b6118c1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016117ae565b915080825286848285010111156118d6575f80fd5b80848401858401375f848284010152508060408501525050506060820135606082015292915050565b803561190a816117fd565b919050565b803563ffffffff8116811461190a575f80fd5b8035801515811461190a575f80fd5b5f6101808284031215611942575f80fd5b61194a61178a565b9050611955826118ff565b8152611963602083016118ff565b6020820152611974604083016118ff565b6040820152606082013560608201526080820135608082015261199960a0830161190f565b60a082015260c082013560c082015260e082013560e08201526101008083013581830152506101206119cc818401611922565b9082015261014082810135908201526101609182013591810191909152919050565b5f806101a08385031215611a00575f80fd5b823567ffffffffffffffff811115611a16575f80fd5b611a2285828601611821565b925050611a328460208501611931565b90509250929050565b5f60208284031215611a4b575f80fd5b813567ffffffffffffffff811115611a61575f80fd5b611a6d84828501611821565b949350505050565b5f60208284031215611a85575f80fd5b813567ffffffffffffffff811115611a9b575f80fd5b8201608081850312156104d0575f80fd5b815173ffffffffffffffffffffffffffffffffffffffff16815261018081016020830151611af2602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151611b1a604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606083015160608301526080830151608083015260a0830151611b4660a084018263ffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b7b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f60208284031215611baa575f80fd5b5035919050565b5f806101a08385031215611bc3575f80fd5b611bcd8484611931565b915061018083013567ffffffffffffffff811115611be9575f80fd5b611bf585828601611821565b9150509250929050565b5f60208284031215611c0f575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561137857611378611c16565b808202811582820484141761137857611378611c16565b8181038181111561137857611378611c16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081528151602082015273ffffffffffffffffffffffffffffffffffffffff60208301511660408201525f604083015160806060840152611d1160a0840182611c80565b9050606084015160808401528091505092915050565b5f6113783683611821565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152813560208201525f6020830135611d93816117fd565b73ffffffffffffffffffffffffffffffffffffffff811660408401525060408301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611de4575f80fd5b830160208101903567ffffffffffffffff811115611e00575f80fd5b803603821315611e0e575f80fd5b60806060850152611e2360a085018284611d32565b915050606084013560808401528091505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff80861683528085166020840152506060604083015261141d6060830184611c80565b5f8060408385031215611e83575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82611ecf57611ecf611e94565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f611a6d6040830184611c80565b5f63ffffffff80841680611f2f57611f2f611e94565b92169190910492915050565b63ffffffff818116838216028082169190828114611f5b57611f5b611c16565b505092915050565b63ffffffff818116838216019080821115611f8057611f80611c16565b509291505056fea2646970667358221220e3fb228b525d90b942c7e58fe2e2034a17bd258c082fd47740e764a7be45bac664736f6c63430008190033a26469706673582212201190cf42f989cee23f12597c8c1e9daab6d8c816513349c3ce7fd229cae5b0ff64736f6c63430008190033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xA0`@R4\x80\x15`\x0EW_\x80\xFD[P`@QaA\xB38\x03\x80aA\xB3\x839\x81\x01`@\x81\x90R`+\x91`;V[`\x01`\x01`\xA0\x1B\x03\x16`\x80R`fV[_` \x82\x84\x03\x12\x15`JW_\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14`_W_\x80\xFD[\x93\x92PPPV[`\x80QaA'a\0\x8C_9_\x81\x81a\x01\x89\x01R\x81\x81a\x02\xA8\x01Ra\x08\xC4\x01RaA'_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\0\x9FW_5`\xE0\x1C\x80c7\xEB\xDFP\x11a\0rW\x80cfn\x1B9\x11a\0XW\x80cfn\x1B9\x14a\x01OW\x80c\xAB\"\x1Av\x14a\x01\x84W\x80c\xB5\xC5\xF6r\x14a\x01\xABW_\x80\xFD[\x80c7\xEB\xDFP\x14a\x01)W\x80c[]\x9E\xE6\x14a\x01=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x021\x91\x90a\x16\x17V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x92\x91\x90a\x0CFV[a\x02\x9E3\x84\x83\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\rW=_\x80>=_\xFD[PPPV[_3\x80\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8C\x8B`@Qa\x02\xD5\x90a\x11\xB9V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x93\x84\x16\x81R\x91\x83\x16` \x83\x01R\x90\x91\x16`@\x82\x01R``\x01\x81\x90`@Q\x80\x91\x03\x90_\xF5\x90P\x80\x15\x80\x15a\x03\x1FW=_\x80>=_\xFD[P`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8E\x81\x16\x82R\x8C\x81\x16` \x83\x01R\x92\x94P\x82\x84\x16\x92\x85\x16\x91\x7Fg\x07%[,\\\xA8\x12 \xB2\xF3\xE4\x08\xA2i\xCB\x83\xBA\xA6\xAA~^7\xAA\x17V\x88:l\xDF\x06\xF1\x91\x01`@Q\x80\x91\x03\x90\xA3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x81\x16_\x90\x81R` \x81\x90R`@\x90 \x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x91\x83\x16\x91\x90\x91\x17\x90Ua\x03\xD8\x82\x8B\x8Aa\x01\xBEV[_`@Q\x80`\x80\x01`@R\x80\x89\x81R` \x01\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x87\x87\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x91\x90\x91RPPP\x90\x82RP` \x01\x85\x90R\x90Pa\x04P\x83\x82a\x0C\xDBV[PP\x99\x98PPPPPPPPPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R``0a\x04\xCF` \x89\x01\x89a\x15'V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x05QW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7Fcan only handle own orders\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[_a\x05_`@\x89\x01\x89a\x162V[\x81\x01\x90a\x05l\x91\x90a\x17\\V[\x90P\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xEE\xC5\x0B\x97`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05\xB7W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05\xDB\x91\x90a\x18ZV[`@Q\x7F\xB0\x9A\xAA\xCA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8B\x16\x90c\xB0\x9A\xAA\xCA\x90a\x06-\x90\x85\x90`\x04\x01a\x18\xC3V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x06HW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x06l\x91\x90a\x18ZV[\x14a\x06\xD3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7Finvalid trading parameters\0\0\0\0\0\0`D\x82\x01R`d\x01a\x05HV[`@Q\x7F\xE3\xE6\xF5\xB2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8A\x16\x90c\xE3\xE6\xF5\xB2\x90a\x07%\x90\x84\x90`\x04\x01a\x18\xC3V[a\x01\x80`@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x07AW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07e\x91\x90a\x18\xF7V[\x92P\x82\x81`@Q` \x01a\x07z\x92\x91\x90a\x19\xB3V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x91PP\x96P\x96\x94PPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16_\x90\x81R` \x81\x90R`@\x90 T\x82\x91\x163\x14a\x08\"Ws\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x81\x16_\x90\x81R` \x81\x90R`@\x90\x81\x90 T\x90Q\x7Fh\xBA\xFF\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16`\x04\x82\x01R`$\x01a\x05HV[a\x08+\x82a\x0E\x05V[PPV[_\x80\x7F\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x16`@Qa\x08y` \x82\x01a\x11\xB9V[\x81\x81\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x81\x01\x83R`\x1F\x90\x91\x01\x16`@\x81\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16` \x84\x01R\x80\x8B\x16\x91\x83\x01\x91\x90\x91R\x88\x16``\x82\x01R`\x80\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x90\x82\x90Ra\t:\x92\x91` \x01a\x19\xEBV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `@Q` \x01a\t\xC2\x94\x93\x92\x91\x90\x7F\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x94\x90\x94\x16\x84R``\x92\x90\x92\x1B\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x16`\x01\x84\x01R`\x15\x83\x01R`5\x82\x01R`U\x01\x90V[`@\x80Q\x80\x83\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01\x81R\x91\x90R\x80Q` \x90\x91\x01 \x95\x94PPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x87\x16_\x90\x81R` \x81\x90R`@\x90 T\x87\x91\x163\x14a\n\x8CWs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x81\x16_\x90\x81R` \x81\x90R`@\x90\x81\x90 T\x90Q\x7Fh\xBA\xFF\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16`\x04\x82\x01R`$\x01a\x05HV[_`@Q\x80`\x80\x01`@R\x80\x88\x81R` \x01\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86\x86\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x91\x90\x91RPPP\x90\x82RP` \x01\x84\x90R\x90Pa\x0B\x03\x88a\x0E\x05V[a\x0B\r\x88\x82a\x0C\xDBV[PPPPPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16_\x90\x81R` \x81\x90R`@\x90 T\x84\x91\x163\x14a\x0B\xA2Ws\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x81\x16_\x90\x81R` \x81\x90R`@\x90\x81\x90 T\x90Q\x7Fh\xBA\xFF\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16`\x04\x82\x01R`$\x01a\x05HV[a\x0B\xF1\x843\x85\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\r\xFE\x16\x81`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\rW=_\x80>=_\xFD[a\x0C@\x843\x84\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\rW=_\x80>=_\xFD[PPPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`$\x83\x01R\x84\x16`D\x82\x01R`d\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`\x84\x90\x91\x01\x90\x91R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F#\xB8r\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90Ra\x0C@\x90\x85\x90a\x0E\xA3V[`@Q\x7F\xC5\xF3\xD2T\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x90c\xC5\xF3\xD2T\x90a\r-\x90\x84\x90`\x04\x01a\x18\xC3V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\rDW_\x80\xFD[PZ\xF1\x15\x80\x15a\rVW=_\x80>=_\xFD[PP`@\x80Q``\x81\x01\x82R0\x81R_` \x80\x83\x01\x82\x90R\x83Q\x91\x95Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x88\x16\x94P\x7F,\xCE\xACUU\xB0\xCAE\xA3tL\xEDT/T\xB5j\xD2\xEBE\xE5!\x96#r\xEE\xF2\x12\xA2\xCB\xF3a\x93\x83\x01\x91a\r\xBD\x91\x88\x91\x01a\x18\xC3V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x81R\x91RQa\r\xF8\x91\x90a\x19\xFFV[`@Q\x80\x91\x03\x90\xA2PPPV[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x17p\x0F\x01`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x0EJW_\x80\xFD[PZ\xF1\x15\x80\x15a\x0E\\W=_\x80>=_\xFD[PP`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x92P\x7F\xC7[\xF4\xF0<\x02\xFA\xB9AJ}zT\x04\x8C\x04\x86r+\xC7/3\xAD\x92G\t\xA0Y6\x08\xAD'\x91P_\x90\xA2PV[_a\x0F\x04\x82`@Q\x80`@\x01`@R\x80` \x81R` \x01\x7FSafeERC20: low-level call failed\x81RP\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x0F\xB0\x90\x92\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90P\x80Q_\x14\x80a\x0F$WP\x80\x80` \x01\x90Q\x81\x01\x90a\x0F$\x91\x90a\x1ACV[a\x02\x9EW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`*`$\x82\x01R\x7FSafeERC20: ERC20 operation did n`D\x82\x01R\x7Fot succeed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05HV[``a\x0F\xBE\x84\x84_\x85a\x0F\xC6V[\x94\x93PPPPV[``\x82G\x10\x15a\x10XW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FAddress: insufficient balance fo`D\x82\x01R\x7Fr call\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05HV[_\x80\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85\x87`@Qa\x10\x80\x91\x90a\x1A\\V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x10\xBAW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x10\xBFV[``\x91P[P\x91P\x91Pa\x10\xD0\x87\x83\x83\x87a\x10\xDBV[\x97\x96PPPPPPPV[``\x83\x15a\x11pW\x82Q_\x03a\x11iWs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16;a\x11iW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FAddress: call to non-contract\0\0\0`D\x82\x01R`d\x01a\x05HV[P\x81a\x0F\xBEV[a\x0F\xBE\x83\x83\x81Q\x15a\x11\x85W\x81Q\x80\x83` \x01\xFD[\x80`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x05H\x91\x90a\x1AgV[a&x\x80a\x1Az\x839\x01\x90V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x11\xE7W_\x80\xFD[PV[_\x80_``\x84\x86\x03\x12\x15a\x11\xFCW_\x80\xFD[\x835a\x12\x07\x81a\x11\xC6V[\x95` \x85\x015\x95P`@\x90\x94\x015\x93\x92PPPV[_\x80\x83`\x1F\x84\x01\x12a\x12,W_\x80\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x12CW_\x80\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\x12ZW_\x80\xFD[\x92P\x92\x90PV[_\x80_\x80_\x80_\x80_a\x01\0\x8A\x8C\x03\x12\x15a\x12zW_\x80\xFD[\x895a\x12\x85\x81a\x11\xC6V[\x98P` \x8A\x015\x97P`@\x8A\x015a\x12\x9C\x81a\x11\xC6V[\x96P``\x8A\x015\x95P`\x80\x8A\x015\x94P`\xA0\x8A\x015a\x12\xBA\x81a\x11\xC6V[\x93P`\xC0\x8A\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x12\xD5W_\x80\xFD[a\x12\xE1\x8C\x82\x8D\x01a\x12\x1CV[\x9A\x9D\x99\x9CP\x97\x9A\x96\x99\x95\x98\x94\x97\x96`\xE0\x015\x94\x93PPPPV[_\x80_\x80_\x80`\x80\x87\x89\x03\x12\x15a\x13\x10W_\x80\xFD[\x865a\x13\x1B\x81a\x11\xC6V[\x95P` \x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x137W_\x80\xFD[\x90\x88\x01\x90``\x82\x8B\x03\x12\x15a\x13JW_\x80\xFD[\x90\x95P`@\x88\x015\x90\x80\x82\x11\x15a\x13_W_\x80\xFD[a\x13k\x8A\x83\x8B\x01a\x12\x1CV[\x90\x96P\x94P``\x89\x015\x91P\x80\x82\x11\x15a\x13\x83W_\x80\xFD[\x81\x89\x01\x91P\x89`\x1F\x83\x01\x12a\x13\x96W_\x80\xFD[\x815\x81\x81\x11\x15a\x13\xA4W_\x80\xFD[\x8A` \x82`\x05\x1B\x85\x01\x01\x11\x15a\x13\xB8W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92\x95P\x92\x95P\x92\x95V[\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82R` \x81\x01Qa\x14\x0F` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x81\x01Qa\x147`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x81\x01Q``\x83\x01R`\x80\x81\x01Q`\x80\x83\x01R`\xA0\x81\x01Qa\x14c`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x81\x01Q`\xC0\x83\x01R`\xE0\x81\x01Q`\xE0\x83\x01Ra\x01\0\x80\x82\x01Q\x81\x84\x01RPa\x01 \x80\x82\x01Qa\x14\x98\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x81\x81\x01Q\x90\x83\x01Ra\x01`\x90\x81\x01Q\x91\x01RV[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[_a\x01\xA0a\x15\x0B\x83\x86a\x13\xCEV[\x80a\x01\x80\x84\x01Ra\x15\x1E\x81\x84\x01\x85a\x14\xB1V[\x95\x94PPPPPV[_` \x82\x84\x03\x12\x15a\x157W_\x80\xFD[\x815a\x15B\x81a\x11\xC6V[\x93\x92PPPV[_\x80_``\x84\x86\x03\x12\x15a\x15[W_\x80\xFD[\x835a\x15f\x81a\x11\xC6V[\x92P` \x84\x015a\x15v\x81a\x11\xC6V[\x91P`@\x84\x015a\x15\x86\x81a\x11\xC6V[\x80\x91PP\x92P\x92P\x92V[_\x80_\x80_\x80`\xA0\x87\x89\x03\x12\x15a\x15\xA6W_\x80\xFD[\x865a\x15\xB1\x81a\x11\xC6V[\x95P` \x87\x015\x94P`@\x87\x015a\x15\xC8\x81a\x11\xC6V[\x93P``\x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x15\xE3W_\x80\xFD[a\x15\xEF\x89\x82\x8A\x01a\x12\x1CV[\x97\x9A\x96\x99P\x94\x97\x94\x96\x95`\x80\x90\x95\x015\x94\x93PPPPV[\x80Qa\x16\x12\x81a\x11\xC6V[\x91\x90PV[_` \x82\x84\x03\x12\x15a\x16'W_\x80\xFD[\x81Qa\x15B\x81a\x11\xC6V[_\x80\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x16eW_\x80\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x16\x7FW_\x80\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\x12ZW_\x80\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x16\xE3Wa\x16\xE3a\x16\x93V[`@R\x90V[`@Qa\x01\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x16\xE3Wa\x16\xE3a\x16\x93V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17TWa\x17Ta\x16\x93V[`@R\x91\x90PV[_` \x80\x83\x85\x03\x12\x15a\x17mW_\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x17\x84W_\x80\xFD[\x90\x84\x01\x90`\x80\x82\x87\x03\x12\x15a\x17\x97W_\x80\xFD[a\x17\x9Fa\x16\xC0V[\x825\x81R\x83\x83\x015a\x17\xB0\x81a\x11\xC6V[\x81\x85\x01R`@\x83\x015\x82\x81\x11\x15a\x17\xC5W_\x80\xFD[\x83\x01`\x1F\x81\x01\x88\x13a\x17\xD5W_\x80\xFD[\x805\x83\x81\x11\x15a\x17\xE7Wa\x17\xE7a\x16\x93V[a\x18\x17\x86\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x17\rV[\x93P\x80\x84R\x88\x86\x82\x84\x01\x01\x11\x15a\x18,W_\x80\xFD[\x80\x86\x83\x01\x87\x86\x017_\x86\x82\x86\x01\x01RPP\x81`@\x82\x01R``\x83\x015``\x82\x01R\x80\x94PPPPP\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x18jW_\x80\xFD[PQ\x91\x90PV[\x80Q\x82Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x82\x01Q\x16` \x83\x01R_`@\x82\x01Q`\x80`@\x85\x01Ra\x18\xAF`\x80\x85\x01\x82a\x14\xB1V[``\x93\x84\x01Q\x94\x90\x93\x01\x93\x90\x93RP\x91\x90PV[` \x81R_a\x15B` \x83\x01\x84a\x18qV[\x80Qc\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x16\x12W_\x80\xFD[\x80Q\x80\x15\x15\x81\x14a\x16\x12W_\x80\xFD[_a\x01\x80\x82\x84\x03\x12\x15a\x19\x08W_\x80\xFD[a\x19\x10a\x16\xE9V[a\x19\x19\x83a\x16\x07V[\x81Ra\x19'` \x84\x01a\x16\x07V[` \x82\x01Ra\x198`@\x84\x01a\x16\x07V[`@\x82\x01R``\x83\x01Q``\x82\x01R`\x80\x83\x01Q`\x80\x82\x01Ra\x19]`\xA0\x84\x01a\x18\xD5V[`\xA0\x82\x01R`\xC0\x83\x01Q`\xC0\x82\x01R`\xE0\x83\x01Q`\xE0\x82\x01Ra\x01\0\x80\x84\x01Q\x81\x83\x01RPa\x01 a\x19\x90\x81\x85\x01a\x18\xE8V[\x90\x82\x01Ra\x01@\x83\x81\x01Q\x90\x82\x01Ra\x01`\x92\x83\x01Q\x92\x81\x01\x92\x90\x92RP\x91\x90PV[_a\x01\xA0a\x19\xC1\x83\x86a\x13\xCEV[\x80a\x01\x80\x84\x01Ra\x15\x1E\x81\x84\x01\x85a\x18qV[_\x81Q\x80` \x84\x01\x85^_\x93\x01\x92\x83RP\x90\x91\x90PV[_a\x0F\xBEa\x19\xF9\x83\x86a\x19\xD4V[\x84a\x19\xD4V[` \x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82Q\x16` \x82\x01R` \x82\x01Q`@\x82\x01R_`@\x83\x01Q``\x80\x84\x01Ra\x0F\xBE`\x80\x84\x01\x82a\x14\xB1V[_` \x82\x84\x03\x12\x15a\x1ASW_\x80\xFD[a\x15B\x82a\x18\xE8V[_a\x15B\x82\x84a\x19\xD4V[` \x81R_a\x15B` \x83\x01\x84a\x14\xB1V\xFEa\x01 `@R4\x80\x15a\0\x10W_\x80\xFD[P`@Qa&x8\x03\x80a&x\x839\x81\x01`@\x81\x90Ra\0/\x91a\x05/V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\x80\x81\x90R`@\x80Qc\xF6\x98\xDA%`\xE0\x1B\x81R\x90Qc\xF6\x98\xDA%\x91`\x04\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81_\x87Z\xF1\x15\x80\x15a\0xW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\x9C\x91\x90a\x05yV[a\x01\0Ra\0\xAA\x823a\x01_V[a\0\xB4\x813a\x01_V[3`\x01`\x01`\xA0\x1B\x03\x16`\xE0\x81`\x01`\x01`\xA0\x1B\x03\x16\x81RPP_\x83`\x01`\x01`\xA0\x1B\x03\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81_\x87Z\xF1\x15\x80\x15a\x01\x0CW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x010\x91\x90a\x05\x90V[\x90Pa\x01<\x83\x82a\x01_V[a\x01F\x82\x82a\x01_V[P`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\xA0R\x16`\xC0RPa\x06\x1CV[a\x01t`\x01`\x01`\xA0\x1B\x03\x83\x16\x82_\x19a\x01xV[PPV[\x80\x15\x80a\x01\xF0WP`@Qcn\xB1v\x9F`\xE1\x1B\x81R0`\x04\x82\x01R`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`$\x83\x01R\x84\x16\x90c\xDDb\xED>\x90`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xCAW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xEE\x91\x90a\x05yV[\x15[a\x02gW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`6`$\x82\x01R\x7FSafeERC20: approve from non-zero`D\x82\x01R\x7F to non-zero allowance\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x84\x16`$\x82\x01R`D\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`d\x90\x91\x01\x90\x91R` \x81\x01\x80Q`\x01`\x01`\xE0\x1B\x03\x90\x81\x16c\t^\xA7\xB3`\xE0\x1B\x17\x90\x91Ra\x02\xBD\x91\x85\x91a\x02\xC2\x16V[PPPV[`@\x80Q\x80\x82\x01\x90\x91R` \x80\x82R\x7FSafeERC20: low-level call failed\x90\x82\x01R_\x90a\x03\x0E\x90`\x01`\x01`\xA0\x1B\x03\x85\x16\x90\x84\x90a\x03\x8DV[\x90P\x80Q_\x14\x80a\x03.WP\x80\x80` \x01\x90Q\x81\x01\x90a\x03.\x91\x90a\x05\xB2V[a\x02\xBDW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`*`$\x82\x01R\x7FSafeERC20: ERC20 operation did n`D\x82\x01Ri\x1B\xDD\x08\x1C\xDDX\xD8\xD9YY`\xB2\x1B`d\x82\x01R`\x84\x01a\x02^V[``a\x03\x9B\x84\x84_\x85a\x03\xA3V[\x94\x93PPPPV[``\x82G\x10\x15a\x04\x04W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FAddress: insufficient balance fo`D\x82\x01Re\x1C\x88\x18\xD8[\x1B`\xD2\x1B`d\x82\x01R`\x84\x01a\x02^V[_\x80\x86`\x01`\x01`\xA0\x1B\x03\x16\x85\x87`@Qa\x04\x1F\x91\x90a\x05\xD1V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x04YW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x04^V[``\x91P[P\x90\x92P\x90Pa\x04p\x87\x83\x83\x87a\x04{V[\x97\x96PPPPPPPV[``\x83\x15a\x04\xE9W\x82Q_\x03a\x04\xE2W`\x01`\x01`\xA0\x1B\x03\x85\x16;a\x04\xE2W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FAddress: call to non-contract\0\0\0`D\x82\x01R`d\x01a\x02^V[P\x81a\x03\x9BV[a\x03\x9B\x83\x83\x81Q\x15a\x04\xFEW\x81Q\x80\x83` \x01\xFD[\x80`@QbF\x1B\xCD`\xE5\x1B\x81R`\x04\x01a\x02^\x91\x90a\x05\xE7V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05,W_\x80\xFD[PV[_\x80_``\x84\x86\x03\x12\x15a\x05AW_\x80\xFD[\x83Qa\x05L\x81a\x05\x18V[` \x85\x01Q\x90\x93Pa\x05]\x81a\x05\x18V[`@\x85\x01Q\x90\x92Pa\x05n\x81a\x05\x18V[\x80\x91PP\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x05\x89W_\x80\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a\x05\xA0W_\x80\xFD[\x81Qa\x05\xAB\x81a\x05\x18V[\x93\x92PPPV[_` \x82\x84\x03\x12\x15a\x05\xC2W_\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x05\xABW_\x80\xFD[_\x82Q\x80` \x85\x01\x84^_\x92\x01\x91\x82RP\x91\x90PV[` \x81R_\x82Q\x80` \x84\x01R\x80` \x85\x01`@\x85\x01^_`@\x82\x85\x01\x01R`@`\x1F\x19`\x1F\x83\x01\x16\x84\x01\x01\x91PP\x92\x91PPV[`\x80Q`\xA0Q`\xC0Q`\xE0Qa\x01\0Qa\x1F\xBDa\x06\xBB_9_\x81\x81a\x02\xDB\x01Ra\x04+\x01R_\x81\x81a\x026\x01R\x81\x81a\x04\xD9\x01Ra\x0B\xF9\x01R_\x81\x81a\x02\xB4\x01R\x81\x81a\x05\x99\x01R\x81\x81a\r\\\x01R\x81\x81a\x0E\xBF\x01R\x81\x81a\x0F\x8E\x01Ra\x10\r\x01R_\x81\x81a\x018\x01R\x81\x81a\x05w\x01R\x81\x81a\r;\x01R\x81\x81a\x0E(\x01R\x81\x81a\x0Fk\x01Ra\x100\x01R_\x81\x81a\x03\"\x01Ra\x12\x14\x01Ra\x1F\xBD_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\x01/W_5`\xE0\x1C\x80c\xB0\x9A\xAA\xCA\x11a\0\xADW\x80c\xE3\xE6\xF5\xB2\x11a\0}W\x80c\xEE\xC5\x0B\x97\x11a\0cW\x80c\xEE\xC5\x0B\x97\x14a\x03DW\x80c\xF1O\xCB\xC8\x14a\x03LW\x80c\xFF-\xBC\x98\x14a\x02\x03W_\x80\xFD[\x80c\xE3\xE6\xF5\xB2\x14a\x02\xFDW\x80c\xE5\x16q[\x14a\x03\x1DW_\x80\xFD[\x80c\xB0\x9A\xAA\xCA\x14a\x02\x89W\x80c\xC5\xF3\xD2T\x14a\x02\x9CW\x80c\xD2\x12 \xA7\x14a\x02\xAFW\x80c\xD2^\x0C\xB6\x14a\x02\xD6W_\x80\xFD[\x80c\x1C}\xE9A\x11a\x01\x02W\x80cH\x1Cju\x11a\0\xE8W\x80cH\x1Cju\x14a\x021W\x80c\x98\x1A\x16\x0B\x14a\x02XW\x80c\xA0)\xA8\xD4\x14a\x02vW_\x80\xFD[\x80c\x1C}\xE9A\x14a\x02\x03W\x80c>pn2\x14a\x02\nW_\x80\xFD[\x80c\r\xFE\x16\x81\x14a\x013W\x80c\x13\x03\xA4\x84\x14a\x01\x84W\x80c\x16&\xBA~\x14a\x01\xB5W\x80c\x17p\x0F\x01\x14a\x01\xF9W[_\x80\xFD[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\[`@Q\x90\x81R` \x01a\x01{V[a\x01\xC8a\x01\xC36`\x04a\x16\xBFV[a\x03_V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x04\xD7V[\0[a\x01\xA7_\x81V[a\x01\xA7\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\x81V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x02aa\x01,\x81V[`@Qc\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x02\x846`\x04a\x19\xEEV[a\x05sV[a\x01\xA7a\x02\x976`\x04a\x1A;V[a\x0B\xC8V[a\x02\x01a\x02\xAA6`\x04a\x1AuV[a\x0B\xF7V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x03\x10a\x03\x0B6`\x04a\x1A;V[a\x0C\xB7V[`@Qa\x01{\x91\x90a\x1A\xACV[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7_T\x81V[a\x02\x01a\x03Z6`\x04a\x1B\x9AV[a\x11\xFCV[_\x80\x80a\x03n\x84\x86\x01\x86a\x1B\xB1V[\x91P\x91P_Ta\x03}\x82a\x0B\xC8V[\x14a\x03\xB4W`@Q\x7F\xF1\xA6x\x90\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x82\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x02\x82\x01R`\"\x81\x01\x91\x90\x91R`B\x90 \x86\x81\x14a\x04\x94W`@Q\x7FY?\xCA\xCD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x04\x9F\x81\x83\x85a\x12\x91V[a\x04\xA9\x82\x84a\x05sV[P\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92PPP[\x93\x92PPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x05FW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80\x80U`@Q\x7F\xBC\xB8\xB8\xFB\xDE\xA8\xAAm\xC4\xAEA!>M\xA8\x1E`Z=\x1AV\xED\x85\x1B\x93U\x18#!\xC0\x91\x90\x91\x90\xA1V[\x80Q\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16\x91\x16\x14a\x06wW\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x06uW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x12`$\x82\x01R\x7Finvalid sell token\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x90[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x06\xE1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x05\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90\x91P_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x07rW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x96\x91\x90a\x1B\xFFV[\x90P\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x081W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7Finvalid buy token\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`@\x85\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x15a\x08\xB3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7Freceiver must be zero address\0\0\0`D\x82\x01R`d\x01a\x06lV[a\x08\xBFa\x01,Ba\x1CCV[\x85`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x11\x15a\t2W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7Fvalidity too far in the future\0\0`D\x82\x01R`d\x01a\x06lV[\x85``\x01Q\x85`\xC0\x01Q\x14a\t\xA3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x0F`$\x82\x01R\x7Finvalid appData\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`\xE0\x85\x01Q\x15a\n\x0FW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Ffee amount must be zero\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01`\x01Q\x14a\n\x9DW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FbuyTokenBalance must be erc20\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01@\x01Q\x14a\x0B+W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FsellTokenBalance must be erc20\0\0`D\x82\x01R`d\x01a\x06lV[``\x85\x01Qa\x0B:\x90\x82a\x1CVV[`\x80\x86\x01Q``\x87\x01Qa\x0BN\x90\x85a\x1CmV[a\x0BX\x91\x90a\x1CVV[\x10\x15a\x0B\xC0W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Freceived amount too low\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[PPPPPPV[_\x81`@Q` \x01a\x0B\xDA\x91\x90a\x1C\xCCV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x0CfW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x0Csa\x02\x97\x83a\x1D'V[\x90P\x80_\x81\x90UP\x80\x7FQ\x0EJOv\x90|-aX\xB3C\xF7\xC4\xF2\xF5\x97\xDF8[r|&\xE9\xEF\x90\xE7P\x93\xAC\xE1\x9A\x83`@Qa\x0C\xAB\x91\x90a\x1DyV[`@Q\x80\x91\x03\x90\xA2PPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R_\x80\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c5^\xFD\xD9\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87`@\x01Q`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\r\x9E\x93\x92\x91\x90a\x1E:V[`@\x80Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\r\xB8W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\r\xDC\x91\x90a\x1ErV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x91\x93P\x91P_\x90\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0EmW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0E\x91\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0F\x19W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0F=\x91\x90a\x1B\xFFV[\x90\x92P\x90P_\x80\x80\x80\x80a\x0FQ\x88\x88a\x1CVV[\x90P_a\x0F^\x8A\x88a\x1CVV[\x90P_\x82\x82\x10\x15a\x10\x0BW\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x0F\xD6a\x0F\xBD`\x02\x8Ba\x1E\xC1V[a\x0F\xD1\x84a\x0F\xCC\x8E`\x02a\x1CVV[a\x13FV[a\x13~V[\x94Pa\x10\x01\x85a\x0F\xE6\x81\x8Da\x1CVV[a\x0F\xF0\x90\x85a\x1CCV[a\x0F\xFA\x8C\x8Fa\x1CVV[`\x01a\x13\xCBV[\x93P\x84\x90Pa\x10\x98V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x10na\x10_`\x02\x8Aa\x1E\xC1V[a\x0F\xD1\x85a\x0F\xCC\x8F`\x02a\x1CVV[\x94Pa\x10\x92\x85a\x10~\x81\x8Ea\x1CVV[a\x10\x88\x90\x86a\x1CCV[a\x0F\xFA\x8B\x8Ea\x1CVV[\x93P\x83\x90P[\x8CQ\x81\x10\x15a\x10\xDFWa\x10\xDF`@Q\x80`@\x01`@R\x80`\x17\x81R` \x01\x7Ftraded amount too small\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[`@Q\x80a\x01\x80\x01`@R\x80\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86\x81R` \x01\x85\x81R` \x01a\x11Va\x01,a\x14fV[c\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8E``\x01Q\x81R` \x01_\x81R` \x01\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x81R` \x01`\x01\x15\x15\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81RP\x9BPPPPPPPPPPPP\x91\x90PV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x12kW`@Q\x7F\xBF\x84\x89w\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x80\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93]PV[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\\x83\x81\x14a\x13@W\x80\x15a\x12\xF2W`@Q\x7F\xDA\xFB\xDD\x1F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x12\xFC\x84a\x0C\xB7V[\x90Pa\x13\x08\x83\x82a\x14\x87V[a\x13>W`@Q\x7F\xD9\xFF$\xC7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P[PPPPV[_\x82\x15a\x13sW\x81a\x13Y`\x01\x85a\x1CmV[a\x13c\x91\x90a\x1E\xC1V[a\x13n\x90`\x01a\x1CCV[a\x13uV[_[\x90P[\x92\x91PPV[_\x81\x83\x10\x15a\x13\xC5Wa\x13\xC5`@Q\x80`@\x01`@R\x80`\x15\x81R` \x01\x7Fsubtraction underflow\0\0\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[P\x90\x03\x90V[_\x80a\x13\xD8\x86\x86\x86a\x15\x99V[\x90P`\x01\x83`\x02\x81\x11\x15a\x13\xEEWa\x13\xEEa\x1E\xD4V[\x14\x80\x15a\x14\nWP_\x84\x80a\x14\x05Wa\x14\x05a\x1E\x94V[\x86\x88\t\x11[\x15a\x14\x1DWa\x14\x1A`\x01\x82a\x1CCV[\x90P[\x95\x94PPPPPV[a\x141C`\x01a\x1CCV[\x81`@Q\x7F\x1F\xE8Pn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x06l\x92\x91\x90a\x1F\x01V[_\x81\x80a\x14s\x81Ba\x1F\x19V[a\x14}\x91\x90a\x1F;V[a\x13x\x91\x90a\x1FcV[_\x80\x82_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x84``\x01Q\x86``\x01Q\x14\x90P_\x85`\x80\x01Q\x87`\x80\x01Q\x14\x90P_\x86`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x88`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x14\x90P_\x87a\x01\0\x01Q\x89a\x01\0\x01Q\x14\x90P_\x88a\x01 \x01Q\x15\x15\x8Aa\x01 \x01Q\x15\x15\x14\x90P\x86\x80\x15a\x15^WP\x85[\x80\x15a\x15gWP\x84[\x80\x15a\x15pWP\x83[\x80\x15a\x15yWP\x82[\x80\x15a\x15\x82WP\x81[\x80\x15a\x15\x8BWP\x80[\x9A\x99PPPPPPPPPPV[_\x80\x80\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x87\t\x85\x87\x02\x92P\x82\x81\x10\x83\x82\x03\x03\x91PP\x80_\x03a\x15\xEFW\x83\x82\x81a\x15\xE5Wa\x15\xE5a\x1E\x94V[\x04\x92PPPa\x04\xD0V[\x80\x84\x11a\x16XW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FMath: mulDiv overflow\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[_\x84\x86\x88\t`\x02`\x01\x87\x19\x81\x01\x88\x16\x97\x88\x90\x04`\x03\x81\x02\x83\x18\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x90\x81\x02\x90\x92\x03\x90\x91\x02_\x88\x90\x03\x88\x90\x04\x90\x91\x01\x85\x83\x11\x90\x94\x03\x93\x90\x93\x02\x93\x03\x94\x90\x94\x04\x91\x90\x91\x17\x02\x94\x93PPPPV[_\x80_`@\x84\x86\x03\x12\x15a\x16\xD1W_\x80\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x16\xEFW_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a\x17\x02W_\x80\xFD[\x815\x81\x81\x11\x15a\x17\x10W_\x80\xFD[\x87` \x82\x85\x01\x01\x11\x15a\x17!W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@R\x90V[`@Qa\x01\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\xF5Wa\x17\xF5a\x174V[`@R\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x18\x1EW_\x80\xFD[PV[_`\x80\x82\x84\x03\x12\x15a\x181W_\x80\xFD[a\x189a\x17aV[\x90P\x815\x81R` \x80\x83\x015a\x18N\x81a\x17\xFDV[\x82\x82\x01R`@\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x18lW_\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x18\x7FW_\x80\xFD[\x815\x81\x81\x11\x15a\x18\x91Wa\x18\x91a\x174V[a\x18\xC1\x84\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x17\xAEV[\x91P\x80\x82R\x86\x84\x82\x85\x01\x01\x11\x15a\x18\xD6W_\x80\xFD[\x80\x84\x84\x01\x85\x84\x017_\x84\x82\x84\x01\x01RP\x80`@\x85\x01RPPP``\x82\x015``\x82\x01R\x92\x91PPV[\x805a\x19\n\x81a\x17\xFDV[\x91\x90PV[\x805c\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x19\nW_\x80\xFD[\x805\x80\x15\x15\x81\x14a\x19\nW_\x80\xFD[_a\x01\x80\x82\x84\x03\x12\x15a\x19BW_\x80\xFD[a\x19Ja\x17\x8AV[\x90Pa\x19U\x82a\x18\xFFV[\x81Ra\x19c` \x83\x01a\x18\xFFV[` \x82\x01Ra\x19t`@\x83\x01a\x18\xFFV[`@\x82\x01R``\x82\x015``\x82\x01R`\x80\x82\x015`\x80\x82\x01Ra\x19\x99`\xA0\x83\x01a\x19\x0FV[`\xA0\x82\x01R`\xC0\x82\x015`\xC0\x82\x01R`\xE0\x82\x015`\xE0\x82\x01Ra\x01\0\x80\x83\x015\x81\x83\x01RPa\x01 a\x19\xCC\x81\x84\x01a\x19\"V[\x90\x82\x01Ra\x01@\x82\x81\x015\x90\x82\x01Ra\x01`\x91\x82\x015\x91\x81\x01\x91\x90\x91R\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1A\0W_\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x16W_\x80\xFD[a\x1A\"\x85\x82\x86\x01a\x18!V[\x92PPa\x1A2\x84` \x85\x01a\x191V[\x90P\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1AKW_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1AaW_\x80\xFD[a\x1Am\x84\x82\x85\x01a\x18!V[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a\x1A\x85W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x9BW_\x80\xFD[\x82\x01`\x80\x81\x85\x03\x12\x15a\x04\xD0W_\x80\xFD[\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81Ra\x01\x80\x81\x01` \x83\x01Qa\x1A\xF2` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x83\x01Qa\x1B\x1A`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x83\x01Q``\x83\x01R`\x80\x83\x01Q`\x80\x83\x01R`\xA0\x83\x01Qa\x1BF`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x83\x01Q`\xC0\x83\x01R`\xE0\x83\x01Q`\xE0\x83\x01Ra\x01\0\x80\x84\x01Q\x81\x84\x01RPa\x01 \x80\x84\x01Qa\x1B{\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x83\x81\x01Q\x90\x83\x01Ra\x01`\x92\x83\x01Q\x92\x90\x91\x01\x91\x90\x91R\x90V[_` \x82\x84\x03\x12\x15a\x1B\xAAW_\x80\xFD[P5\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1B\xC3W_\x80\xFD[a\x1B\xCD\x84\x84a\x191V[\x91Pa\x01\x80\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1B\xE9W_\x80\xFD[a\x1B\xF5\x85\x82\x86\x01a\x18!V[\x91PP\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1C\x0FW_\x80\xFD[PQ\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x01\x80\x82\x11\x15a\x13xWa\x13xa\x1C\x16V[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\x13xWa\x13xa\x1C\x16V[\x81\x81\x03\x81\x81\x11\x15a\x13xWa\x13xa\x1C\x16V[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[` \x81R\x81Q` \x82\x01Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x83\x01Q\x16`@\x82\x01R_`@\x83\x01Q`\x80``\x84\x01Ra\x1D\x11`\xA0\x84\x01\x82a\x1C\x80V[\x90P``\x84\x01Q`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_a\x13x6\x83a\x18!V[\x81\x83R\x81\x81` \x85\x017P_` \x82\x84\x01\x01R_` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x84\x01\x01\x90P\x92\x91PPV[` \x81R\x815` \x82\x01R_` \x83\x015a\x1D\x93\x81a\x17\xFDV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`@\x84\x01RP`@\x83\x015\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x1D\xE4W_\x80\xFD[\x83\x01` \x81\x01\x905g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1E\0W_\x80\xFD[\x806\x03\x82\x13\x15a\x1E\x0EW_\x80\xFD[`\x80``\x85\x01Ra\x1E#`\xA0\x85\x01\x82\x84a\x1D2V[\x91PP``\x84\x015`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x86\x16\x83R\x80\x85\x16` \x84\x01RP```@\x83\x01Ra\x14\x1D``\x83\x01\x84a\x1C\x80V[_\x80`@\x83\x85\x03\x12\x15a\x1E\x83W_\x80\xFD[PP\x80Q` \x90\x91\x01Q\x90\x92\x90\x91PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_\x82a\x1E\xCFWa\x1E\xCFa\x1E\x94V[P\x04\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x82\x81R`@` \x82\x01R_a\x1Am`@\x83\x01\x84a\x1C\x80V[_c\xFF\xFF\xFF\xFF\x80\x84\x16\x80a\x1F/Wa\x1F/a\x1E\x94V[\x92\x16\x91\x90\x91\x04\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x02\x80\x82\x16\x91\x90\x82\x81\x14a\x1F[Wa\x1F[a\x1C\x16V[PP\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x01\x90\x80\x82\x11\x15a\x1F\x80Wa\x1F\x80a\x1C\x16V[P\x92\x91PPV\xFE\xA2dipfsX\"\x12 \xE3\xFB\"\x8BR]\x90\xB9B\xC7\xE5\x8F\xE2\xE2\x03J\x17\xBD%\x8C\x08/\xD4w@\xE7d\xA7\xBEE\xBA\xC6dsolcC\0\x08\x19\x003\xA2dipfsX\"\x12 \x11\x90\xCFB\xF9\x89\xCE\xE2?\x12Y|\x8C\x1E\x9D\xAA\xB6\xD8\xC8\x16Q3I\xC3\xCE\x7F\xD2)\xCA\xE5\xB0\xFFdsolcC\0\x08\x19\x003", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f80fd5b506004361061009f575f3560e01c806337ebdf5011610072578063666e1b3911610058578063666e1b391461014f578063ab221a7614610184578063b5c5f672146101ab575f80fd5b806337ebdf50146101295780635b5d9ee61461013c575f80fd5b80630efe6a8b146100a357806322b155c6146100b857806326e0a196146100f55780632791056514610116575b5f80fd5b6100b66100b13660046111ea565b6101be565b005b6100cb6100c6366004611261565b6102a3565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101086101033660046112fb565b61045f565b6040516100ec9291906114fd565b6100b6610124366004611527565b610797565b6100cb610137366004611549565b61082f565b6100b661014a366004611591565b610a01565b6100cb61015d366004611527565b5f6020819052908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6100cb7f000000000000000000000000000000000000000000000000000000000000000081565b6100b66101b93660046111ea565b610b17565b61024f3384848673ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102319190611617565b73ffffffffffffffffffffffffffffffffffffffff16929190610c46565b61029e3384838673ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b505050565b5f33807f00000000000000000000000000000000000000000000000000000000000000008c8b6040516102d5906111b9565b73ffffffffffffffffffffffffffffffffffffffff9384168152918316602083015290911660408201526060018190604051809103905ff590508015801561031f573d5f803e3d5ffd5b506040805173ffffffffffffffffffffffffffffffffffffffff8e811682528c81166020830152929450828416928516917f6707255b2c5ca81220b2f3e408a269cb83baa6aa7e5e37aa1756883a6cdf06f1910160405180910390a373ffffffffffffffffffffffffffffffffffffffff8281165f90815260208190526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790556103d8828b8a6101be565b5f60405180608001604052808981526020018873ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050509082525060200185905290506104508382610cdb565b50509998505050505050505050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526060306104cf6020890189611527565b73ffffffffffffffffffffffffffffffffffffffff1614610551576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e206f6e6c792068616e646c65206f776e206f726465727300000000000060448201526064015b60405180910390fd5b5f61055f6040890189611632565b81019061056c919061175c565b90508873ffffffffffffffffffffffffffffffffffffffff1663eec50b976040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105db919061185a565b6040517fb09aaaca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b169063b09aaaca9061062d9085906004016118c3565b602060405180830381865afa158015610648573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061066c919061185a565b146106d3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f696e76616c69642074726164696e6720706172616d65746572730000000000006044820152606401610548565b6040517fe3e6f5b200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a169063e3e6f5b2906107259084906004016118c3565b61018060405180830381865afa158015610741573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061076591906118f7565b9250828160405160200161077a9291906119b3565b604051602081830303815290604052915050965096945050505050565b73ffffffffffffffffffffffffffffffffffffffff8082165f9081526020819052604090205482911633146108225773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b61082b82610e05565b5050565b5f807fff000000000000000000000000000000000000000000000000000000000000003073ffffffffffffffffffffffffffffffffffffffff8716604051610879602082016111b9565b8181037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09081018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166020840152808b169183019190915288166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261093a92916020016119eb565b604051602081830303815290604052805190602001206040516020016109c294939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830152603582015260550190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052805160209091012095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8087165f908152602081905260409020548791163314610a8c5773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b5f60405180608001604052808881526020018773ffffffffffffffffffffffffffffffffffffffff16815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506020018490529050610b0388610e05565b610b0d8882610cdb565b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8084165f908152602081905260409020548491163314610ba25773ffffffffffffffffffffffffffffffffffffffff8181165f90815260208190526040908190205490517f68bafff800000000000000000000000000000000000000000000000000000000815291166004820152602401610548565b610bf18433858773ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b610c408433848773ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d5f803e3d5ffd5b50505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610c40908590610ea3565b6040517fc5f3d25400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063c5f3d25490610d2d9084906004016118c3565b5f604051808303815f87803b158015610d44575f80fd5b505af1158015610d56573d5f803e3d5ffd5b5050604080516060810182523081525f6020808301829052835191955073ffffffffffffffffffffffffffffffffffffffff881694507f2cceac5555b0ca45a3744ced542f54b56ad2eb45e521962372eef212a2cbf36193830191610dbd918891016118c3565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915251610df891906119ff565b60405180910390a2505050565b8073ffffffffffffffffffffffffffffffffffffffff166317700f016040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610e4a575f80fd5b505af1158015610e5c573d5f803e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff841692507fc75bf4f03c02fab9414a7d7a54048c0486722bc72f33ad924709a0593608ad2791505f90a250565b5f610f04826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610fb09092919063ffffffff16565b905080515f1480610f24575080806020019051810190610f249190611a43565b61029e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610548565b6060610fbe84845f85610fc6565b949350505050565b606082471015611058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610548565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516110809190611a5c565b5f6040518083038185875af1925050503d805f81146110ba576040519150601f19603f3d011682016040523d82523d5f602084013e6110bf565b606091505b50915091506110d0878383876110db565b979650505050505050565b606083156111705782515f036111695773ffffffffffffffffffffffffffffffffffffffff85163b611169576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610548565b5081610fbe565b610fbe83838151156111855781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105489190611a67565b61267880611a7a83390190565b73ffffffffffffffffffffffffffffffffffffffff811681146111e7575f80fd5b50565b5f805f606084860312156111fc575f80fd5b8335611207816111c6565b95602085013595506040909401359392505050565b5f8083601f84011261122c575f80fd5b50813567ffffffffffffffff811115611243575f80fd5b60208301915083602082850101111561125a575f80fd5b9250929050565b5f805f805f805f805f6101008a8c03121561127a575f80fd5b8935611285816111c6565b985060208a0135975060408a013561129c816111c6565b965060608a0135955060808a0135945060a08a01356112ba816111c6565b935060c08a013567ffffffffffffffff8111156112d5575f80fd5b6112e18c828d0161121c565b9a9d999c50979a9699959894979660e00135949350505050565b5f805f805f8060808789031215611310575f80fd5b863561131b816111c6565b9550602087013567ffffffffffffffff80821115611337575f80fd5b908801906060828b03121561134a575f80fd5b9095506040880135908082111561135f575f80fd5b61136b8a838b0161121c565b90965094506060890135915080821115611383575f80fd5b818901915089601f830112611396575f80fd5b8135818111156113a4575f80fd5b8a60208260051b85010111156113b8575f80fd5b6020830194508093505050509295509295509295565b805173ffffffffffffffffffffffffffffffffffffffff168252602081015161140f602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151611437604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608301526080810151608083015260a081015161146360a084018263ffffffff169052565b5060c081015160c083015260e081015160e0830152610100808201518184015250610120808201516114988285018215159052565b5050610140818101519083015261016090810151910152565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b5f6101a061150b83866113ce565b8061018084015261151e818401856114b1565b95945050505050565b5f60208284031215611537575f80fd5b8135611542816111c6565b9392505050565b5f805f6060848603121561155b575f80fd5b8335611566816111c6565b92506020840135611576816111c6565b91506040840135611586816111c6565b809150509250925092565b5f805f805f8060a087890312156115a6575f80fd5b86356115b1816111c6565b95506020870135945060408701356115c8816111c6565b9350606087013567ffffffffffffffff8111156115e3575f80fd5b6115ef89828a0161121c565b979a9699509497949695608090950135949350505050565b8051611612816111c6565b919050565b5f60208284031215611627575f80fd5b8151611542816111c6565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611665575f80fd5b83018035915067ffffffffffffffff82111561167f575f80fd5b60200191503681900382131561125a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156116e3576116e3611693565b60405290565b604051610180810167ffffffffffffffff811182821017156116e3576116e3611693565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561175457611754611693565b604052919050565b5f602080838503121561176d575f80fd5b823567ffffffffffffffff80821115611784575f80fd5b9084019060808287031215611797575f80fd5b61179f6116c0565b82358152838301356117b0816111c6565b818501526040830135828111156117c5575f80fd5b8301601f810188136117d5575f80fd5b8035838111156117e7576117e7611693565b611817867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161170d565b9350808452888682840101111561182c575f80fd5b80868301878601375f8682860101525050816040820152606083013560608201528094505050505092915050565b5f6020828403121561186a575f80fd5b5051919050565b8051825273ffffffffffffffffffffffffffffffffffffffff60208201511660208301525f6040820151608060408501526118af60808501826114b1565b606093840151949093019390935250919050565b602081525f6115426020830184611871565b805163ffffffff81168114611612575f80fd5b80518015158114611612575f80fd5b5f6101808284031215611908575f80fd5b6119106116e9565b61191983611607565b815261192760208401611607565b602082015261193860408401611607565b6040820152606083015160608201526080830151608082015261195d60a084016118d5565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206119908185016118e8565b908201526101408381015190820152610160928301519281019290925250919050565b5f6101a06119c183866113ce565b8061018084015261151e81840185611871565b5f81518060208401855e5f93019283525090919050565b5f610fbe6119f983866119d4565b846119d4565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201525f6040830151606080840152610fbe60808401826114b1565b5f60208284031215611a53575f80fd5b611542826118e8565b5f61154282846119d4565b602081525f61154260208301846114b156fe610120604052348015610010575f80fd5b5060405161267838038061267883398101604081905261002f9161052f565b6001600160a01b03831660808190526040805163f698da2560e01b8152905163f698da259160048082019260209290919082900301815f875af1158015610078573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061009c9190610579565b610100526100aa823361015f565b6100b4813361015f565b336001600160a01b031660e0816001600160a01b0316815250505f836001600160a01b0316639b552cc26040518163ffffffff1660e01b81526004016020604051808303815f875af115801561010c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101309190610590565b905061013c838261015f565b610146828261015f565b506001600160a01b0391821660a0521660c0525061061c565b6101746001600160a01b038316825f19610178565b5050565b8015806101f05750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156101ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ee9190610579565b155b6102675760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526102bd9185916102c216565b505050565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908201525f9061030e906001600160a01b03851690849061038d565b905080515f148061032e57508080602001905181019061032e91906105b2565b6102bd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161025e565b606061039b84845f856103a3565b949350505050565b6060824710156104045760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161025e565b5f80866001600160a01b0316858760405161041f91906105d1565b5f6040518083038185875af1925050503d805f8114610459576040519150601f19603f3d011682016040523d82523d5f602084013e61045e565b606091505b5090925090506104708783838761047b565b979650505050505050565b606083156104e95782515f036104e2576001600160a01b0385163b6104e25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161025e565b508161039b565b61039b83838151156104fe5781518083602001fd5b8060405162461bcd60e51b815260040161025e91906105e7565b6001600160a01b038116811461052c575f80fd5b50565b5f805f60608486031215610541575f80fd5b835161054c81610518565b602085015190935061055d81610518565b604085015190925061056e81610518565b809150509250925092565b5f60208284031215610589575f80fd5b5051919050565b5f602082840312156105a0575f80fd5b81516105ab81610518565b9392505050565b5f602082840312156105c2575f80fd5b815180151581146105ab575f80fd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b60805160a05160c05160e05161010051611fbd6106bb5f395f81816102db015261042b01525f8181610236015281816104d90152610bf901525f81816102b40152818161059901528181610d5c01528181610ebf01528181610f8e015261100d01525f81816101380152818161057701528181610d3b01528181610e2801528181610f6b015261103001525f818161032201526112140152611fbd5ff3fe608060405234801561000f575f80fd5b506004361061012f575f3560e01c8063b09aaaca116100ad578063e3e6f5b21161007d578063eec50b9711610063578063eec50b9714610344578063f14fcbc81461034c578063ff2dbc9814610203575f80fd5b8063e3e6f5b2146102fd578063e516715b1461031d575f80fd5b8063b09aaaca14610289578063c5f3d2541461029c578063d21220a7146102af578063d25e0cb6146102d6575f80fd5b80631c7de94111610102578063481c6a75116100e8578063481c6a7514610231578063981a160b14610258578063a029a8d414610276575f80fd5b80631c7de941146102035780633e706e321461020a575f80fd5b80630dfe1681146101335780631303a484146101845780631626ba7e146101b557806317700f01146101f9575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c5b60405190815260200161017b565b6101c86101c33660046116bf565b61035f565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161017b565b6102016104d7565b005b6101a75f81565b6101a77f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b59381565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b61026161012c81565b60405163ffffffff909116815260200161017b565b6102016102843660046119ee565b610573565b6101a7610297366004611a3b565b610bc8565b6102016102aa366004611a75565b610bf7565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a77f000000000000000000000000000000000000000000000000000000000000000081565b61031061030b366004611a3b565b610cb7565b60405161017b9190611aac565b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b6101a75f5481565b61020161035a366004611b9a565b6111fc565b5f808061036e84860186611bb1565b915091505f5461037d82610bc8565b146103b4576040517ff1a6789000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020868114610494576040517f593fcacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049f818385611291565b6104a98284610573565b507f1626ba7e00000000000000000000000000000000000000000000000000000000925050505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610546576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8080556040517fbcb8b8fbdea8aa6dc4ae41213e4da81e605a3d1a56ed851b9355182321c091909190a1565b80517f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff808416911614610677578073ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff1614610675576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c69642073656c6c20746f6b656e000000000000000000000000000060448201526064015b60405180910390fd5b905b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156106e1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107059190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610772573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107969190611bff565b90508273ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff1614610831576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c69642062757920746f6b656e000000000000000000000000000000604482015260640161066c565b604085015173ffffffffffffffffffffffffffffffffffffffff16156108b3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7265636569766572206d757374206265207a65726f2061646472657373000000604482015260640161066c565b6108bf61012c42611c43565b8560a0015163ffffffff161115610932576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f76616c696469747920746f6f2066617220696e20746865206675747572650000604482015260640161066c565b85606001518560c00151146109a3576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c696420617070446174610000000000000000000000000000000000604482015260640161066c565b60e085015115610a0f576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f66656520616d6f756e74206d757374206265207a65726f000000000000000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610160015114610a9d576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f627579546f6b656e42616c616e6365206d757374206265206572633230000000604482015260640161066c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc985610140015114610b2b576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f73656c6c546f6b656e42616c616e6365206d7573742062652065726332300000604482015260640161066c565b6060850151610b3a9082611c56565b60808601516060870151610b4e9085611c6d565b610b589190611c56565b1015610bc0576040517fc8fc272500000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f726563656976656420616d6f756e7420746f6f206c6f77000000000000000000604482015260640161066c565b505050505050565b5f81604051602001610bda9190611ccc565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c66576040517ff87d0d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610c7361029783611d27565b9050805f81905550807f510e4a4f76907c2d6158b343f7c4f2f597df385b727c26e9ef90e75093ace19a83604051610cab9190611d79565b60405180910390a25050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091525f80836020015173ffffffffffffffffffffffffffffffffffffffff1663355efdd97f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087604001516040518463ffffffff1660e01b8152600401610d9e93929190611e3a565b6040805180830381865afa158015610db8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ddc9190611e72565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291935091505f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610e6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e919190611bff565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3d9190611bff565b90925090505f80808080610f518888611c56565b90505f610f5e8a88611c56565b90505f8282101561100b577f000000000000000000000000000000000000000000000000000000000000000096507f00000000000000000000000000000000000000000000000000000000000000009550610fd6610fbd60028b611ec1565b610fd184610fcc8e6002611c56565b611346565b61137e565b945061100185610fe6818d611c56565b610ff09085611c43565b610ffa8c8f611c56565b60016113cb565b9350849050611098565b7f000000000000000000000000000000000000000000000000000000000000000096507f0000000000000000000000000000000000000000000000000000000000000000955061106e61105f60028a611ec1565b610fd185610fcc8f6002611c56565b94506110928561107e818e611c56565b6110889086611c43565b610ffa8b8e611c56565b93508390505b8c518110156110df576110df6040518060400160405280601781526020017f74726164656420616d6f756e7420746f6f20736d616c6c000000000000000000815250611426565b6040518061018001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200161115661012c611466565b63ffffffff1681526020018e6060015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98152509b505050505050505050505050919050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461126b576040517fbf84897700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935d50565b7f6c3c90245457060f6517787b2c4b8cf500ca889d2304af02043bd5b513e3b5935c8381146113405780156112f2576040517fdafbdd1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112fc84610cb7565b90506113088382611487565b61133e576040517fd9ff24c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b50505050565b5f82156113735781611359600185611c6d565b6113639190611ec1565b61136e906001611c43565b611375565b5f5b90505b92915050565b5f818310156113c5576113c56040518060400160405280601581526020017f7375627472616374696f6e20756e646572666c6f770000000000000000000000815250611426565b50900390565b5f806113d8868686611599565b905060018360028111156113ee576113ee611ed4565b14801561140a57505f848061140557611405611e94565b868809115b1561141d5761141a600182611c43565b90505b95945050505050565b611431436001611c43565b816040517f1fe8506e00000000000000000000000000000000000000000000000000000000815260040161066c929190611f01565b5f81806114738142611f19565b61147d9190611f3b565b6113789190611f63565b5f80825f015173ffffffffffffffffffffffffffffffffffffffff16845f015173ffffffffffffffffffffffffffffffffffffffff161490505f836020015173ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161490505f846060015186606001511490505f856080015187608001511490505f8660a0015163ffffffff168860a0015163ffffffff161490505f8761010001518961010001511490505f88610120015115158a6101200151151514905086801561155e5750855b80156115675750845b80156115705750835b80156115795750825b80156115825750815b801561158b5750805b9a9950505050505050505050565b5f80807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050805f036115ef578382816115e5576115e5611e94565b04925050506104d0565b808411611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161066c565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f805f604084860312156116d1575f80fd5b83359250602084013567ffffffffffffffff808211156116ef575f80fd5b818601915086601f830112611702575f80fd5b813581811115611710575f80fd5b876020828501011115611721575f80fd5b6020830194508093505050509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561178457611784611734565b60405290565b604051610180810167ffffffffffffffff8111828210171561178457611784611734565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117f5576117f5611734565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461181e575f80fd5b50565b5f60808284031215611831575f80fd5b611839611761565b90508135815260208083013561184e816117fd565b82820152604083013567ffffffffffffffff8082111561186c575f80fd5b818501915085601f83011261187f575f80fd5b81358181111561189157611891611734565b6118c1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016117ae565b915080825286848285010111156118d6575f80fd5b80848401858401375f848284010152508060408501525050506060820135606082015292915050565b803561190a816117fd565b919050565b803563ffffffff8116811461190a575f80fd5b8035801515811461190a575f80fd5b5f6101808284031215611942575f80fd5b61194a61178a565b9050611955826118ff565b8152611963602083016118ff565b6020820152611974604083016118ff565b6040820152606082013560608201526080820135608082015261199960a0830161190f565b60a082015260c082013560c082015260e082013560e08201526101008083013581830152506101206119cc818401611922565b9082015261014082810135908201526101609182013591810191909152919050565b5f806101a08385031215611a00575f80fd5b823567ffffffffffffffff811115611a16575f80fd5b611a2285828601611821565b925050611a328460208501611931565b90509250929050565b5f60208284031215611a4b575f80fd5b813567ffffffffffffffff811115611a61575f80fd5b611a6d84828501611821565b949350505050565b5f60208284031215611a85575f80fd5b813567ffffffffffffffff811115611a9b575f80fd5b8201608081850312156104d0575f80fd5b815173ffffffffffffffffffffffffffffffffffffffff16815261018081016020830151611af2602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151611b1a604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606083015160608301526080830151608083015260a0830151611b4660a084018263ffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b7b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f60208284031215611baa575f80fd5b5035919050565b5f806101a08385031215611bc3575f80fd5b611bcd8484611931565b915061018083013567ffffffffffffffff811115611be9575f80fd5b611bf585828601611821565b9150509250929050565b5f60208284031215611c0f575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561137857611378611c16565b808202811582820484141761137857611378611c16565b8181038181111561137857611378611c16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081528151602082015273ffffffffffffffffffffffffffffffffffffffff60208301511660408201525f604083015160806060840152611d1160a0840182611c80565b9050606084015160808401528091505092915050565b5f6113783683611821565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152813560208201525f6020830135611d93816117fd565b73ffffffffffffffffffffffffffffffffffffffff811660408401525060408301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611de4575f80fd5b830160208101903567ffffffffffffffff811115611e00575f80fd5b803603821315611e0e575f80fd5b60806060850152611e2360a085018284611d32565b915050606084013560808401528091505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff80861683528085166020840152506060604083015261141d6060830184611c80565b5f8060408385031215611e83575f80fd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82611ecf57611ecf611e94565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f611a6d6040830184611c80565b5f63ffffffff80841680611f2f57611f2f611e94565b92169190910492915050565b63ffffffff818116838216028082169190828114611f5b57611f5b611c16565b505092915050565b63ffffffff818116838216019080821115611f8057611f80611c16565b509291505056fea2646970667358221220e3fb228b525d90b942c7e58fe2e2034a17bd258c082fd47740e764a7be45bac664736f6c63430008190033a26469706673582212201190cf42f989cee23f12597c8c1e9daab6d8c816513349c3ce7fd229cae5b0ff64736f6c63430008190033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\0\x9FW_5`\xE0\x1C\x80c7\xEB\xDFP\x11a\0rW\x80cfn\x1B9\x11a\0XW\x80cfn\x1B9\x14a\x01OW\x80c\xAB\"\x1Av\x14a\x01\x84W\x80c\xB5\xC5\xF6r\x14a\x01\xABW_\x80\xFD[\x80c7\xEB\xDFP\x14a\x01)W\x80c[]\x9E\xE6\x14a\x01=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x021\x91\x90a\x16\x17V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x92\x91\x90a\x0CFV[a\x02\x9E3\x84\x83\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\rW=_\x80>=_\xFD[PPPV[_3\x80\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8C\x8B`@Qa\x02\xD5\x90a\x11\xB9V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x93\x84\x16\x81R\x91\x83\x16` \x83\x01R\x90\x91\x16`@\x82\x01R``\x01\x81\x90`@Q\x80\x91\x03\x90_\xF5\x90P\x80\x15\x80\x15a\x03\x1FW=_\x80>=_\xFD[P`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8E\x81\x16\x82R\x8C\x81\x16` \x83\x01R\x92\x94P\x82\x84\x16\x92\x85\x16\x91\x7Fg\x07%[,\\\xA8\x12 \xB2\xF3\xE4\x08\xA2i\xCB\x83\xBA\xA6\xAA~^7\xAA\x17V\x88:l\xDF\x06\xF1\x91\x01`@Q\x80\x91\x03\x90\xA3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x81\x16_\x90\x81R` \x81\x90R`@\x90 \x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x91\x83\x16\x91\x90\x91\x17\x90Ua\x03\xD8\x82\x8B\x8Aa\x01\xBEV[_`@Q\x80`\x80\x01`@R\x80\x89\x81R` \x01\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x87\x87\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x91\x90\x91RPPP\x90\x82RP` \x01\x85\x90R\x90Pa\x04P\x83\x82a\x0C\xDBV[PP\x99\x98PPPPPPPPPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R``0a\x04\xCF` \x89\x01\x89a\x15'V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x05QW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7Fcan only handle own orders\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[_a\x05_`@\x89\x01\x89a\x162V[\x81\x01\x90a\x05l\x91\x90a\x17\\V[\x90P\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xEE\xC5\x0B\x97`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05\xB7W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05\xDB\x91\x90a\x18ZV[`@Q\x7F\xB0\x9A\xAA\xCA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8B\x16\x90c\xB0\x9A\xAA\xCA\x90a\x06-\x90\x85\x90`\x04\x01a\x18\xC3V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x06HW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x06l\x91\x90a\x18ZV[\x14a\x06\xD3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7Finvalid trading parameters\0\0\0\0\0\0`D\x82\x01R`d\x01a\x05HV[`@Q\x7F\xE3\xE6\xF5\xB2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8A\x16\x90c\xE3\xE6\xF5\xB2\x90a\x07%\x90\x84\x90`\x04\x01a\x18\xC3V[a\x01\x80`@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x07AW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07e\x91\x90a\x18\xF7V[\x92P\x82\x81`@Q` \x01a\x07z\x92\x91\x90a\x19\xB3V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x91PP\x96P\x96\x94PPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16_\x90\x81R` \x81\x90R`@\x90 T\x82\x91\x163\x14a\x08\"Ws\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x81\x16_\x90\x81R` \x81\x90R`@\x90\x81\x90 T\x90Q\x7Fh\xBA\xFF\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16`\x04\x82\x01R`$\x01a\x05HV[a\x08+\x82a\x0E\x05V[PPV[_\x80\x7F\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x16`@Qa\x08y` \x82\x01a\x11\xB9V[\x81\x81\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x81\x01\x83R`\x1F\x90\x91\x01\x16`@\x81\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16` \x84\x01R\x80\x8B\x16\x91\x83\x01\x91\x90\x91R\x88\x16``\x82\x01R`\x80\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x90\x82\x90Ra\t:\x92\x91` \x01a\x19\xEBV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `@Q` \x01a\t\xC2\x94\x93\x92\x91\x90\x7F\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x94\x90\x94\x16\x84R``\x92\x90\x92\x1B\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x16`\x01\x84\x01R`\x15\x83\x01R`5\x82\x01R`U\x01\x90V[`@\x80Q\x80\x83\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01\x81R\x91\x90R\x80Q` \x90\x91\x01 \x95\x94PPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x87\x16_\x90\x81R` \x81\x90R`@\x90 T\x87\x91\x163\x14a\n\x8CWs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x81\x16_\x90\x81R` \x81\x90R`@\x90\x81\x90 T\x90Q\x7Fh\xBA\xFF\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16`\x04\x82\x01R`$\x01a\x05HV[_`@Q\x80`\x80\x01`@R\x80\x88\x81R` \x01\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86\x86\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x91\x90\x91RPPP\x90\x82RP` \x01\x84\x90R\x90Pa\x0B\x03\x88a\x0E\x05V[a\x0B\r\x88\x82a\x0C\xDBV[PPPPPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16_\x90\x81R` \x81\x90R`@\x90 T\x84\x91\x163\x14a\x0B\xA2Ws\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x81\x16_\x90\x81R` \x81\x90R`@\x90\x81\x90 T\x90Q\x7Fh\xBA\xFF\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x16`\x04\x82\x01R`$\x01a\x05HV[a\x0B\xF1\x843\x85\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\r\xFE\x16\x81`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\rW=_\x80>=_\xFD[a\x0C@\x843\x84\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\rW=_\x80>=_\xFD[PPPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`$\x83\x01R\x84\x16`D\x82\x01R`d\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`\x84\x90\x91\x01\x90\x91R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F#\xB8r\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90Ra\x0C@\x90\x85\x90a\x0E\xA3V[`@Q\x7F\xC5\xF3\xD2T\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x90c\xC5\xF3\xD2T\x90a\r-\x90\x84\x90`\x04\x01a\x18\xC3V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\rDW_\x80\xFD[PZ\xF1\x15\x80\x15a\rVW=_\x80>=_\xFD[PP`@\x80Q``\x81\x01\x82R0\x81R_` \x80\x83\x01\x82\x90R\x83Q\x91\x95Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x88\x16\x94P\x7F,\xCE\xACUU\xB0\xCAE\xA3tL\xEDT/T\xB5j\xD2\xEBE\xE5!\x96#r\xEE\xF2\x12\xA2\xCB\xF3a\x93\x83\x01\x91a\r\xBD\x91\x88\x91\x01a\x18\xC3V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x81R\x91RQa\r\xF8\x91\x90a\x19\xFFV[`@Q\x80\x91\x03\x90\xA2PPPV[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x17p\x0F\x01`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x0EJW_\x80\xFD[PZ\xF1\x15\x80\x15a\x0E\\W=_\x80>=_\xFD[PP`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x92P\x7F\xC7[\xF4\xF0<\x02\xFA\xB9AJ}zT\x04\x8C\x04\x86r+\xC7/3\xAD\x92G\t\xA0Y6\x08\xAD'\x91P_\x90\xA2PV[_a\x0F\x04\x82`@Q\x80`@\x01`@R\x80` \x81R` \x01\x7FSafeERC20: low-level call failed\x81RP\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x0F\xB0\x90\x92\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90P\x80Q_\x14\x80a\x0F$WP\x80\x80` \x01\x90Q\x81\x01\x90a\x0F$\x91\x90a\x1ACV[a\x02\x9EW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`*`$\x82\x01R\x7FSafeERC20: ERC20 operation did n`D\x82\x01R\x7Fot succeed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05HV[``a\x0F\xBE\x84\x84_\x85a\x0F\xC6V[\x94\x93PPPPV[``\x82G\x10\x15a\x10XW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FAddress: insufficient balance fo`D\x82\x01R\x7Fr call\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05HV[_\x80\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85\x87`@Qa\x10\x80\x91\x90a\x1A\\V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x10\xBAW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x10\xBFV[``\x91P[P\x91P\x91Pa\x10\xD0\x87\x83\x83\x87a\x10\xDBV[\x97\x96PPPPPPPV[``\x83\x15a\x11pW\x82Q_\x03a\x11iWs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16;a\x11iW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FAddress: call to non-contract\0\0\0`D\x82\x01R`d\x01a\x05HV[P\x81a\x0F\xBEV[a\x0F\xBE\x83\x83\x81Q\x15a\x11\x85W\x81Q\x80\x83` \x01\xFD[\x80`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x05H\x91\x90a\x1AgV[a&x\x80a\x1Az\x839\x01\x90V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x11\xE7W_\x80\xFD[PV[_\x80_``\x84\x86\x03\x12\x15a\x11\xFCW_\x80\xFD[\x835a\x12\x07\x81a\x11\xC6V[\x95` \x85\x015\x95P`@\x90\x94\x015\x93\x92PPPV[_\x80\x83`\x1F\x84\x01\x12a\x12,W_\x80\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x12CW_\x80\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\x12ZW_\x80\xFD[\x92P\x92\x90PV[_\x80_\x80_\x80_\x80_a\x01\0\x8A\x8C\x03\x12\x15a\x12zW_\x80\xFD[\x895a\x12\x85\x81a\x11\xC6V[\x98P` \x8A\x015\x97P`@\x8A\x015a\x12\x9C\x81a\x11\xC6V[\x96P``\x8A\x015\x95P`\x80\x8A\x015\x94P`\xA0\x8A\x015a\x12\xBA\x81a\x11\xC6V[\x93P`\xC0\x8A\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x12\xD5W_\x80\xFD[a\x12\xE1\x8C\x82\x8D\x01a\x12\x1CV[\x9A\x9D\x99\x9CP\x97\x9A\x96\x99\x95\x98\x94\x97\x96`\xE0\x015\x94\x93PPPPV[_\x80_\x80_\x80`\x80\x87\x89\x03\x12\x15a\x13\x10W_\x80\xFD[\x865a\x13\x1B\x81a\x11\xC6V[\x95P` \x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x137W_\x80\xFD[\x90\x88\x01\x90``\x82\x8B\x03\x12\x15a\x13JW_\x80\xFD[\x90\x95P`@\x88\x015\x90\x80\x82\x11\x15a\x13_W_\x80\xFD[a\x13k\x8A\x83\x8B\x01a\x12\x1CV[\x90\x96P\x94P``\x89\x015\x91P\x80\x82\x11\x15a\x13\x83W_\x80\xFD[\x81\x89\x01\x91P\x89`\x1F\x83\x01\x12a\x13\x96W_\x80\xFD[\x815\x81\x81\x11\x15a\x13\xA4W_\x80\xFD[\x8A` \x82`\x05\x1B\x85\x01\x01\x11\x15a\x13\xB8W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92\x95P\x92\x95P\x92\x95V[\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82R` \x81\x01Qa\x14\x0F` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x81\x01Qa\x147`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x81\x01Q``\x83\x01R`\x80\x81\x01Q`\x80\x83\x01R`\xA0\x81\x01Qa\x14c`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x81\x01Q`\xC0\x83\x01R`\xE0\x81\x01Q`\xE0\x83\x01Ra\x01\0\x80\x82\x01Q\x81\x84\x01RPa\x01 \x80\x82\x01Qa\x14\x98\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x81\x81\x01Q\x90\x83\x01Ra\x01`\x90\x81\x01Q\x91\x01RV[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[_a\x01\xA0a\x15\x0B\x83\x86a\x13\xCEV[\x80a\x01\x80\x84\x01Ra\x15\x1E\x81\x84\x01\x85a\x14\xB1V[\x95\x94PPPPPV[_` \x82\x84\x03\x12\x15a\x157W_\x80\xFD[\x815a\x15B\x81a\x11\xC6V[\x93\x92PPPV[_\x80_``\x84\x86\x03\x12\x15a\x15[W_\x80\xFD[\x835a\x15f\x81a\x11\xC6V[\x92P` \x84\x015a\x15v\x81a\x11\xC6V[\x91P`@\x84\x015a\x15\x86\x81a\x11\xC6V[\x80\x91PP\x92P\x92P\x92V[_\x80_\x80_\x80`\xA0\x87\x89\x03\x12\x15a\x15\xA6W_\x80\xFD[\x865a\x15\xB1\x81a\x11\xC6V[\x95P` \x87\x015\x94P`@\x87\x015a\x15\xC8\x81a\x11\xC6V[\x93P``\x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x15\xE3W_\x80\xFD[a\x15\xEF\x89\x82\x8A\x01a\x12\x1CV[\x97\x9A\x96\x99P\x94\x97\x94\x96\x95`\x80\x90\x95\x015\x94\x93PPPPV[\x80Qa\x16\x12\x81a\x11\xC6V[\x91\x90PV[_` \x82\x84\x03\x12\x15a\x16'W_\x80\xFD[\x81Qa\x15B\x81a\x11\xC6V[_\x80\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x16eW_\x80\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x16\x7FW_\x80\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\x12ZW_\x80\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x16\xE3Wa\x16\xE3a\x16\x93V[`@R\x90V[`@Qa\x01\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x16\xE3Wa\x16\xE3a\x16\x93V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17TWa\x17Ta\x16\x93V[`@R\x91\x90PV[_` \x80\x83\x85\x03\x12\x15a\x17mW_\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x17\x84W_\x80\xFD[\x90\x84\x01\x90`\x80\x82\x87\x03\x12\x15a\x17\x97W_\x80\xFD[a\x17\x9Fa\x16\xC0V[\x825\x81R\x83\x83\x015a\x17\xB0\x81a\x11\xC6V[\x81\x85\x01R`@\x83\x015\x82\x81\x11\x15a\x17\xC5W_\x80\xFD[\x83\x01`\x1F\x81\x01\x88\x13a\x17\xD5W_\x80\xFD[\x805\x83\x81\x11\x15a\x17\xE7Wa\x17\xE7a\x16\x93V[a\x18\x17\x86\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x17\rV[\x93P\x80\x84R\x88\x86\x82\x84\x01\x01\x11\x15a\x18,W_\x80\xFD[\x80\x86\x83\x01\x87\x86\x017_\x86\x82\x86\x01\x01RPP\x81`@\x82\x01R``\x83\x015``\x82\x01R\x80\x94PPPPP\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x18jW_\x80\xFD[PQ\x91\x90PV[\x80Q\x82Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x82\x01Q\x16` \x83\x01R_`@\x82\x01Q`\x80`@\x85\x01Ra\x18\xAF`\x80\x85\x01\x82a\x14\xB1V[``\x93\x84\x01Q\x94\x90\x93\x01\x93\x90\x93RP\x91\x90PV[` \x81R_a\x15B` \x83\x01\x84a\x18qV[\x80Qc\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x16\x12W_\x80\xFD[\x80Q\x80\x15\x15\x81\x14a\x16\x12W_\x80\xFD[_a\x01\x80\x82\x84\x03\x12\x15a\x19\x08W_\x80\xFD[a\x19\x10a\x16\xE9V[a\x19\x19\x83a\x16\x07V[\x81Ra\x19'` \x84\x01a\x16\x07V[` \x82\x01Ra\x198`@\x84\x01a\x16\x07V[`@\x82\x01R``\x83\x01Q``\x82\x01R`\x80\x83\x01Q`\x80\x82\x01Ra\x19]`\xA0\x84\x01a\x18\xD5V[`\xA0\x82\x01R`\xC0\x83\x01Q`\xC0\x82\x01R`\xE0\x83\x01Q`\xE0\x82\x01Ra\x01\0\x80\x84\x01Q\x81\x83\x01RPa\x01 a\x19\x90\x81\x85\x01a\x18\xE8V[\x90\x82\x01Ra\x01@\x83\x81\x01Q\x90\x82\x01Ra\x01`\x92\x83\x01Q\x92\x81\x01\x92\x90\x92RP\x91\x90PV[_a\x01\xA0a\x19\xC1\x83\x86a\x13\xCEV[\x80a\x01\x80\x84\x01Ra\x15\x1E\x81\x84\x01\x85a\x18qV[_\x81Q\x80` \x84\x01\x85^_\x93\x01\x92\x83RP\x90\x91\x90PV[_a\x0F\xBEa\x19\xF9\x83\x86a\x19\xD4V[\x84a\x19\xD4V[` \x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82Q\x16` \x82\x01R` \x82\x01Q`@\x82\x01R_`@\x83\x01Q``\x80\x84\x01Ra\x0F\xBE`\x80\x84\x01\x82a\x14\xB1V[_` \x82\x84\x03\x12\x15a\x1ASW_\x80\xFD[a\x15B\x82a\x18\xE8V[_a\x15B\x82\x84a\x19\xD4V[` \x81R_a\x15B` \x83\x01\x84a\x14\xB1V\xFEa\x01 `@R4\x80\x15a\0\x10W_\x80\xFD[P`@Qa&x8\x03\x80a&x\x839\x81\x01`@\x81\x90Ra\0/\x91a\x05/V[`\x01`\x01`\xA0\x1B\x03\x83\x16`\x80\x81\x90R`@\x80Qc\xF6\x98\xDA%`\xE0\x1B\x81R\x90Qc\xF6\x98\xDA%\x91`\x04\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81_\x87Z\xF1\x15\x80\x15a\0xW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\x9C\x91\x90a\x05yV[a\x01\0Ra\0\xAA\x823a\x01_V[a\0\xB4\x813a\x01_V[3`\x01`\x01`\xA0\x1B\x03\x16`\xE0\x81`\x01`\x01`\xA0\x1B\x03\x16\x81RPP_\x83`\x01`\x01`\xA0\x1B\x03\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81_\x87Z\xF1\x15\x80\x15a\x01\x0CW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x010\x91\x90a\x05\x90V[\x90Pa\x01<\x83\x82a\x01_V[a\x01F\x82\x82a\x01_V[P`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\xA0R\x16`\xC0RPa\x06\x1CV[a\x01t`\x01`\x01`\xA0\x1B\x03\x83\x16\x82_\x19a\x01xV[PPV[\x80\x15\x80a\x01\xF0WP`@Qcn\xB1v\x9F`\xE1\x1B\x81R0`\x04\x82\x01R`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`$\x83\x01R\x84\x16\x90c\xDDb\xED>\x90`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xCAW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xEE\x91\x90a\x05yV[\x15[a\x02gW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`6`$\x82\x01R\x7FSafeERC20: approve from non-zero`D\x82\x01R\x7F to non-zero allowance\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x84\x16`$\x82\x01R`D\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`d\x90\x91\x01\x90\x91R` \x81\x01\x80Q`\x01`\x01`\xE0\x1B\x03\x90\x81\x16c\t^\xA7\xB3`\xE0\x1B\x17\x90\x91Ra\x02\xBD\x91\x85\x91a\x02\xC2\x16V[PPPV[`@\x80Q\x80\x82\x01\x90\x91R` \x80\x82R\x7FSafeERC20: low-level call failed\x90\x82\x01R_\x90a\x03\x0E\x90`\x01`\x01`\xA0\x1B\x03\x85\x16\x90\x84\x90a\x03\x8DV[\x90P\x80Q_\x14\x80a\x03.WP\x80\x80` \x01\x90Q\x81\x01\x90a\x03.\x91\x90a\x05\xB2V[a\x02\xBDW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`*`$\x82\x01R\x7FSafeERC20: ERC20 operation did n`D\x82\x01Ri\x1B\xDD\x08\x1C\xDDX\xD8\xD9YY`\xB2\x1B`d\x82\x01R`\x84\x01a\x02^V[``a\x03\x9B\x84\x84_\x85a\x03\xA3V[\x94\x93PPPPV[``\x82G\x10\x15a\x04\x04W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FAddress: insufficient balance fo`D\x82\x01Re\x1C\x88\x18\xD8[\x1B`\xD2\x1B`d\x82\x01R`\x84\x01a\x02^V[_\x80\x86`\x01`\x01`\xA0\x1B\x03\x16\x85\x87`@Qa\x04\x1F\x91\x90a\x05\xD1V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x04YW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x04^V[``\x91P[P\x90\x92P\x90Pa\x04p\x87\x83\x83\x87a\x04{V[\x97\x96PPPPPPPV[``\x83\x15a\x04\xE9W\x82Q_\x03a\x04\xE2W`\x01`\x01`\xA0\x1B\x03\x85\x16;a\x04\xE2W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FAddress: call to non-contract\0\0\0`D\x82\x01R`d\x01a\x02^V[P\x81a\x03\x9BV[a\x03\x9B\x83\x83\x81Q\x15a\x04\xFEW\x81Q\x80\x83` \x01\xFD[\x80`@QbF\x1B\xCD`\xE5\x1B\x81R`\x04\x01a\x02^\x91\x90a\x05\xE7V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05,W_\x80\xFD[PV[_\x80_``\x84\x86\x03\x12\x15a\x05AW_\x80\xFD[\x83Qa\x05L\x81a\x05\x18V[` \x85\x01Q\x90\x93Pa\x05]\x81a\x05\x18V[`@\x85\x01Q\x90\x92Pa\x05n\x81a\x05\x18V[\x80\x91PP\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x05\x89W_\x80\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a\x05\xA0W_\x80\xFD[\x81Qa\x05\xAB\x81a\x05\x18V[\x93\x92PPPV[_` \x82\x84\x03\x12\x15a\x05\xC2W_\x80\xFD[\x81Q\x80\x15\x15\x81\x14a\x05\xABW_\x80\xFD[_\x82Q\x80` \x85\x01\x84^_\x92\x01\x91\x82RP\x91\x90PV[` \x81R_\x82Q\x80` \x84\x01R\x80` \x85\x01`@\x85\x01^_`@\x82\x85\x01\x01R`@`\x1F\x19`\x1F\x83\x01\x16\x84\x01\x01\x91PP\x92\x91PPV[`\x80Q`\xA0Q`\xC0Q`\xE0Qa\x01\0Qa\x1F\xBDa\x06\xBB_9_\x81\x81a\x02\xDB\x01Ra\x04+\x01R_\x81\x81a\x026\x01R\x81\x81a\x04\xD9\x01Ra\x0B\xF9\x01R_\x81\x81a\x02\xB4\x01R\x81\x81a\x05\x99\x01R\x81\x81a\r\\\x01R\x81\x81a\x0E\xBF\x01R\x81\x81a\x0F\x8E\x01Ra\x10\r\x01R_\x81\x81a\x018\x01R\x81\x81a\x05w\x01R\x81\x81a\r;\x01R\x81\x81a\x0E(\x01R\x81\x81a\x0Fk\x01Ra\x100\x01R_\x81\x81a\x03\"\x01Ra\x12\x14\x01Ra\x1F\xBD_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\x01/W_5`\xE0\x1C\x80c\xB0\x9A\xAA\xCA\x11a\0\xADW\x80c\xE3\xE6\xF5\xB2\x11a\0}W\x80c\xEE\xC5\x0B\x97\x11a\0cW\x80c\xEE\xC5\x0B\x97\x14a\x03DW\x80c\xF1O\xCB\xC8\x14a\x03LW\x80c\xFF-\xBC\x98\x14a\x02\x03W_\x80\xFD[\x80c\xE3\xE6\xF5\xB2\x14a\x02\xFDW\x80c\xE5\x16q[\x14a\x03\x1DW_\x80\xFD[\x80c\xB0\x9A\xAA\xCA\x14a\x02\x89W\x80c\xC5\xF3\xD2T\x14a\x02\x9CW\x80c\xD2\x12 \xA7\x14a\x02\xAFW\x80c\xD2^\x0C\xB6\x14a\x02\xD6W_\x80\xFD[\x80c\x1C}\xE9A\x11a\x01\x02W\x80cH\x1Cju\x11a\0\xE8W\x80cH\x1Cju\x14a\x021W\x80c\x98\x1A\x16\x0B\x14a\x02XW\x80c\xA0)\xA8\xD4\x14a\x02vW_\x80\xFD[\x80c\x1C}\xE9A\x14a\x02\x03W\x80c>pn2\x14a\x02\nW_\x80\xFD[\x80c\r\xFE\x16\x81\x14a\x013W\x80c\x13\x03\xA4\x84\x14a\x01\x84W\x80c\x16&\xBA~\x14a\x01\xB5W\x80c\x17p\x0F\x01\x14a\x01\xF9W[_\x80\xFD[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\[`@Q\x90\x81R` \x01a\x01{V[a\x01\xC8a\x01\xC36`\x04a\x16\xBFV[a\x03_V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x04\xD7V[\0[a\x01\xA7_\x81V[a\x01\xA7\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\x81V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x02aa\x01,\x81V[`@Qc\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x01{V[a\x02\x01a\x02\x846`\x04a\x19\xEEV[a\x05sV[a\x01\xA7a\x02\x976`\x04a\x1A;V[a\x0B\xC8V[a\x02\x01a\x02\xAA6`\x04a\x1AuV[a\x0B\xF7V[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x03\x10a\x03\x0B6`\x04a\x1A;V[a\x0C\xB7V[`@Qa\x01{\x91\x90a\x1A\xACV[a\x01Z\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[a\x01\xA7_T\x81V[a\x02\x01a\x03Z6`\x04a\x1B\x9AV[a\x11\xFCV[_\x80\x80a\x03n\x84\x86\x01\x86a\x1B\xB1V[\x91P\x91P_Ta\x03}\x82a\x0B\xC8V[\x14a\x03\xB4W`@Q\x7F\xF1\xA6x\x90\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x82\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x02\x82\x01R`\"\x81\x01\x91\x90\x91R`B\x90 \x86\x81\x14a\x04\x94W`@Q\x7FY?\xCA\xCD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x04\x9F\x81\x83\x85a\x12\x91V[a\x04\xA9\x82\x84a\x05sV[P\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x92PPP[\x93\x92PPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x05FW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80\x80U`@Q\x7F\xBC\xB8\xB8\xFB\xDE\xA8\xAAm\xC4\xAEA!>M\xA8\x1E`Z=\x1AV\xED\x85\x1B\x93U\x18#!\xC0\x91\x90\x91\x90\xA1V[\x80Q\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16\x91\x16\x14a\x06wW\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x06uW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x12`$\x82\x01R\x7Finvalid sell token\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x90[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x06\xE1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x05\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90\x91P_\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x07rW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x96\x91\x90a\x1B\xFFV[\x90P\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x081W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7Finvalid buy token\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`@\x85\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x15a\x08\xB3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7Freceiver must be zero address\0\0\0`D\x82\x01R`d\x01a\x06lV[a\x08\xBFa\x01,Ba\x1CCV[\x85`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x11\x15a\t2W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7Fvalidity too far in the future\0\0`D\x82\x01R`d\x01a\x06lV[\x85``\x01Q\x85`\xC0\x01Q\x14a\t\xA3W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x0F`$\x82\x01R\x7Finvalid appData\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[`\xE0\x85\x01Q\x15a\n\x0FW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Ffee amount must be zero\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01`\x01Q\x14a\n\x9DW`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FbuyTokenBalance must be erc20\0\0\0`D\x82\x01R`d\x01a\x06lV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x85a\x01@\x01Q\x14a\x0B+W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FsellTokenBalance must be erc20\0\0`D\x82\x01R`d\x01a\x06lV[``\x85\x01Qa\x0B:\x90\x82a\x1CVV[`\x80\x86\x01Q``\x87\x01Qa\x0BN\x90\x85a\x1CmV[a\x0BX\x91\x90a\x1CVV[\x10\x15a\x0B\xC0W`@Q\x7F\xC8\xFC'%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7Freceived amount too low\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[PPPPPPV[_\x81`@Q` \x01a\x0B\xDA\x91\x90a\x1C\xCCV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x0CfW`@Q\x7F\xF8}\r\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x0Csa\x02\x97\x83a\x1D'V[\x90P\x80_\x81\x90UP\x80\x7FQ\x0EJOv\x90|-aX\xB3C\xF7\xC4\xF2\xF5\x97\xDF8[r|&\xE9\xEF\x90\xE7P\x93\xAC\xE1\x9A\x83`@Qa\x0C\xAB\x91\x90a\x1DyV[`@Q\x80\x91\x03\x90\xA2PPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R_\x80\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c5^\xFD\xD9\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87`@\x01Q`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\r\x9E\x93\x92\x91\x90a\x1E:V[`@\x80Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\r\xB8W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\r\xDC\x91\x90a\x1ErV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x91\x93P\x91P_\x90\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0EmW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0E\x91\x91\x90a\x1B\xFFV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0F\x19W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0F=\x91\x90a\x1B\xFFV[\x90\x92P\x90P_\x80\x80\x80\x80a\x0FQ\x88\x88a\x1CVV[\x90P_a\x0F^\x8A\x88a\x1CVV[\x90P_\x82\x82\x10\x15a\x10\x0BW\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x0F\xD6a\x0F\xBD`\x02\x8Ba\x1E\xC1V[a\x0F\xD1\x84a\x0F\xCC\x8E`\x02a\x1CVV[a\x13FV[a\x13~V[\x94Pa\x10\x01\x85a\x0F\xE6\x81\x8Da\x1CVV[a\x0F\xF0\x90\x85a\x1CCV[a\x0F\xFA\x8C\x8Fa\x1CVV[`\x01a\x13\xCBV[\x93P\x84\x90Pa\x10\x98V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x95Pa\x10na\x10_`\x02\x8Aa\x1E\xC1V[a\x0F\xD1\x85a\x0F\xCC\x8F`\x02a\x1CVV[\x94Pa\x10\x92\x85a\x10~\x81\x8Ea\x1CVV[a\x10\x88\x90\x86a\x1CCV[a\x0F\xFA\x8B\x8Ea\x1CVV[\x93P\x83\x90P[\x8CQ\x81\x10\x15a\x10\xDFWa\x10\xDF`@Q\x80`@\x01`@R\x80`\x17\x81R` \x01\x7Ftraded amount too small\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[`@Q\x80a\x01\x80\x01`@R\x80\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86\x81R` \x01\x85\x81R` \x01a\x11Va\x01,a\x14fV[c\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8E``\x01Q\x81R` \x01_\x81R` \x01\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x81R` \x01`\x01\x15\x15\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81RP\x9BPPPPPPPPPPPP\x91\x90PV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x12kW`@Q\x7F\xBF\x84\x89w\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x80\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93]PV[\x7Fl<\x90$TW\x06\x0Fe\x17x{,K\x8C\xF5\0\xCA\x88\x9D#\x04\xAF\x02\x04;\xD5\xB5\x13\xE3\xB5\x93\\\x83\x81\x14a\x13@W\x80\x15a\x12\xF2W`@Q\x7F\xDA\xFB\xDD\x1F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x12\xFC\x84a\x0C\xB7V[\x90Pa\x13\x08\x83\x82a\x14\x87V[a\x13>W`@Q\x7F\xD9\xFF$\xC7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P[PPPPV[_\x82\x15a\x13sW\x81a\x13Y`\x01\x85a\x1CmV[a\x13c\x91\x90a\x1E\xC1V[a\x13n\x90`\x01a\x1CCV[a\x13uV[_[\x90P[\x92\x91PPV[_\x81\x83\x10\x15a\x13\xC5Wa\x13\xC5`@Q\x80`@\x01`@R\x80`\x15\x81R` \x01\x7Fsubtraction underflow\0\0\0\0\0\0\0\0\0\0\0\x81RPa\x14&V[P\x90\x03\x90V[_\x80a\x13\xD8\x86\x86\x86a\x15\x99V[\x90P`\x01\x83`\x02\x81\x11\x15a\x13\xEEWa\x13\xEEa\x1E\xD4V[\x14\x80\x15a\x14\nWP_\x84\x80a\x14\x05Wa\x14\x05a\x1E\x94V[\x86\x88\t\x11[\x15a\x14\x1DWa\x14\x1A`\x01\x82a\x1CCV[\x90P[\x95\x94PPPPPV[a\x141C`\x01a\x1CCV[\x81`@Q\x7F\x1F\xE8Pn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x06l\x92\x91\x90a\x1F\x01V[_\x81\x80a\x14s\x81Ba\x1F\x19V[a\x14}\x91\x90a\x1F;V[a\x13x\x91\x90a\x1FcV[_\x80\x82_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x83` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_\x84``\x01Q\x86``\x01Q\x14\x90P_\x85`\x80\x01Q\x87`\x80\x01Q\x14\x90P_\x86`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x88`\xA0\x01Qc\xFF\xFF\xFF\xFF\x16\x14\x90P_\x87a\x01\0\x01Q\x89a\x01\0\x01Q\x14\x90P_\x88a\x01 \x01Q\x15\x15\x8Aa\x01 \x01Q\x15\x15\x14\x90P\x86\x80\x15a\x15^WP\x85[\x80\x15a\x15gWP\x84[\x80\x15a\x15pWP\x83[\x80\x15a\x15yWP\x82[\x80\x15a\x15\x82WP\x81[\x80\x15a\x15\x8BWP\x80[\x9A\x99PPPPPPPPPPV[_\x80\x80\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x87\t\x85\x87\x02\x92P\x82\x81\x10\x83\x82\x03\x03\x91PP\x80_\x03a\x15\xEFW\x83\x82\x81a\x15\xE5Wa\x15\xE5a\x1E\x94V[\x04\x92PPPa\x04\xD0V[\x80\x84\x11a\x16XW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FMath: mulDiv overflow\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06lV[_\x84\x86\x88\t`\x02`\x01\x87\x19\x81\x01\x88\x16\x97\x88\x90\x04`\x03\x81\x02\x83\x18\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x80\x82\x02\x84\x03\x02\x90\x81\x02\x90\x92\x03\x90\x91\x02_\x88\x90\x03\x88\x90\x04\x90\x91\x01\x85\x83\x11\x90\x94\x03\x93\x90\x93\x02\x93\x03\x94\x90\x94\x04\x91\x90\x91\x17\x02\x94\x93PPPPV[_\x80_`@\x84\x86\x03\x12\x15a\x16\xD1W_\x80\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x16\xEFW_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a\x17\x02W_\x80\xFD[\x815\x81\x81\x11\x15a\x17\x10W_\x80\xFD[\x87` \x82\x85\x01\x01\x11\x15a\x17!W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@R\x90V[`@Qa\x01\x80\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\x84Wa\x17\x84a\x174V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x17\xF5Wa\x17\xF5a\x174V[`@R\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x18\x1EW_\x80\xFD[PV[_`\x80\x82\x84\x03\x12\x15a\x181W_\x80\xFD[a\x189a\x17aV[\x90P\x815\x81R` \x80\x83\x015a\x18N\x81a\x17\xFDV[\x82\x82\x01R`@\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x18lW_\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x18\x7FW_\x80\xFD[\x815\x81\x81\x11\x15a\x18\x91Wa\x18\x91a\x174V[a\x18\xC1\x84\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x17\xAEV[\x91P\x80\x82R\x86\x84\x82\x85\x01\x01\x11\x15a\x18\xD6W_\x80\xFD[\x80\x84\x84\x01\x85\x84\x017_\x84\x82\x84\x01\x01RP\x80`@\x85\x01RPPP``\x82\x015``\x82\x01R\x92\x91PPV[\x805a\x19\n\x81a\x17\xFDV[\x91\x90PV[\x805c\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x19\nW_\x80\xFD[\x805\x80\x15\x15\x81\x14a\x19\nW_\x80\xFD[_a\x01\x80\x82\x84\x03\x12\x15a\x19BW_\x80\xFD[a\x19Ja\x17\x8AV[\x90Pa\x19U\x82a\x18\xFFV[\x81Ra\x19c` \x83\x01a\x18\xFFV[` \x82\x01Ra\x19t`@\x83\x01a\x18\xFFV[`@\x82\x01R``\x82\x015``\x82\x01R`\x80\x82\x015`\x80\x82\x01Ra\x19\x99`\xA0\x83\x01a\x19\x0FV[`\xA0\x82\x01R`\xC0\x82\x015`\xC0\x82\x01R`\xE0\x82\x015`\xE0\x82\x01Ra\x01\0\x80\x83\x015\x81\x83\x01RPa\x01 a\x19\xCC\x81\x84\x01a\x19\"V[\x90\x82\x01Ra\x01@\x82\x81\x015\x90\x82\x01Ra\x01`\x91\x82\x015\x91\x81\x01\x91\x90\x91R\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1A\0W_\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x16W_\x80\xFD[a\x1A\"\x85\x82\x86\x01a\x18!V[\x92PPa\x1A2\x84` \x85\x01a\x191V[\x90P\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1AKW_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1AaW_\x80\xFD[a\x1Am\x84\x82\x85\x01a\x18!V[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a\x1A\x85W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1A\x9BW_\x80\xFD[\x82\x01`\x80\x81\x85\x03\x12\x15a\x04\xD0W_\x80\xFD[\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81Ra\x01\x80\x81\x01` \x83\x01Qa\x1A\xF2` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x83\x01Qa\x1B\x1A`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x83\x01Q``\x83\x01R`\x80\x83\x01Q`\x80\x83\x01R`\xA0\x83\x01Qa\x1BF`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x83\x01Q`\xC0\x83\x01R`\xE0\x83\x01Q`\xE0\x83\x01Ra\x01\0\x80\x84\x01Q\x81\x84\x01RPa\x01 \x80\x84\x01Qa\x1B{\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x83\x81\x01Q\x90\x83\x01Ra\x01`\x92\x83\x01Q\x92\x90\x91\x01\x91\x90\x91R\x90V[_` \x82\x84\x03\x12\x15a\x1B\xAAW_\x80\xFD[P5\x91\x90PV[_\x80a\x01\xA0\x83\x85\x03\x12\x15a\x1B\xC3W_\x80\xFD[a\x1B\xCD\x84\x84a\x191V[\x91Pa\x01\x80\x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1B\xE9W_\x80\xFD[a\x1B\xF5\x85\x82\x86\x01a\x18!V[\x91PP\x92P\x92\x90PV[_` \x82\x84\x03\x12\x15a\x1C\x0FW_\x80\xFD[PQ\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x01\x80\x82\x11\x15a\x13xWa\x13xa\x1C\x16V[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\x13xWa\x13xa\x1C\x16V[\x81\x81\x03\x81\x81\x11\x15a\x13xWa\x13xa\x1C\x16V[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[` \x81R\x81Q` \x82\x01Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x83\x01Q\x16`@\x82\x01R_`@\x83\x01Q`\x80``\x84\x01Ra\x1D\x11`\xA0\x84\x01\x82a\x1C\x80V[\x90P``\x84\x01Q`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_a\x13x6\x83a\x18!V[\x81\x83R\x81\x81` \x85\x017P_` \x82\x84\x01\x01R_` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x84\x01\x01\x90P\x92\x91PPV[` \x81R\x815` \x82\x01R_` \x83\x015a\x1D\x93\x81a\x17\xFDV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`@\x84\x01RP`@\x83\x015\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x1D\xE4W_\x80\xFD[\x83\x01` \x81\x01\x905g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x1E\0W_\x80\xFD[\x806\x03\x82\x13\x15a\x1E\x0EW_\x80\xFD[`\x80``\x85\x01Ra\x1E#`\xA0\x85\x01\x82\x84a\x1D2V[\x91PP``\x84\x015`\x80\x84\x01R\x80\x91PP\x92\x91PPV[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x86\x16\x83R\x80\x85\x16` \x84\x01RP```@\x83\x01Ra\x14\x1D``\x83\x01\x84a\x1C\x80V[_\x80`@\x83\x85\x03\x12\x15a\x1E\x83W_\x80\xFD[PP\x80Q` \x90\x91\x01Q\x90\x92\x90\x91PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_\x82a\x1E\xCFWa\x1E\xCFa\x1E\x94V[P\x04\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x82\x81R`@` \x82\x01R_a\x1Am`@\x83\x01\x84a\x1C\x80V[_c\xFF\xFF\xFF\xFF\x80\x84\x16\x80a\x1F/Wa\x1F/a\x1E\x94V[\x92\x16\x91\x90\x91\x04\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x02\x80\x82\x16\x91\x90\x82\x81\x14a\x1F[Wa\x1F[a\x1C\x16V[PP\x92\x91PPV[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x01\x90\x80\x82\x11\x15a\x1F\x80Wa\x1F\x80a\x1C\x16V[P\x92\x91PPV\xFE\xA2dipfsX\"\x12 \xE3\xFB\"\x8BR]\x90\xB9B\xC7\xE5\x8F\xE2\xE2\x03J\x17\xBD%\x8C\x08/\xD4w@\xE7d\xA7\xBEE\xBA\xC6dsolcC\0\x08\x19\x003\xA2dipfsX\"\x12 \x11\x90\xCFB\xF9\x89\xCE\xE2?\x12Y|\x8C\x1E\x9D\xAA\xB6\xD8\xC8\x16Q3I\xC3\xCE\x7F\xD2)\xCA\xE5\xB0\xFFdsolcC\0\x08\x19\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OnlyOwnerCanCall(address)` and selector `0x68bafff8`. + ```solidity + error OnlyOwnerCanCall(address owner); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OnlyOwnerCanCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OnlyOwnerCanCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OnlyOwnerCanCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OnlyOwnerCanCall { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [104u8, 186u8, 255u8, 248u8]; + const SIGNATURE: &'static str = "OnlyOwnerCanCall(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderNotValid(string)` and selector `0xc8fc2725`. + ```solidity + error OrderNotValid(string); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderNotValid(pub alloy_sol_types::private::String); + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderNotValid) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderNotValid { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderNotValid { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [200u8, 252u8, 39u8, 37u8]; + const SIGNATURE: &'static str = "OrderNotValid(string)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ConditionalOrderCreated(address,(address,bytes32,bytes))` and selector `0x2cceac5555b0ca45a3744ced542f54b56ad2eb45e521962372eef212a2cbf361`. + ```solidity + event ConditionalOrderCreated(address indexed owner, IConditionalOrder.ConditionalOrderParams params); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ConditionalOrderCreated { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub params: + ::RustType, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ConditionalOrderCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (IConditionalOrder::ConditionalOrderParams,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "ConditionalOrderCreated(address,(address,bytes32,bytes))"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 44u8, 206u8, 172u8, 85u8, 85u8, 176u8, 202u8, 69u8, 163u8, 116u8, 76u8, 237u8, + 84u8, 47u8, 84u8, 181u8, 106u8, 210u8, 235u8, 69u8, 229u8, 33u8, 150u8, 35u8, + 114u8, 238u8, 242u8, 18u8, 162u8, 203u8, 243u8, 97u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + params: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.params, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.owner.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ConditionalOrderCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ConditionalOrderCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ConditionalOrderCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Deployed(address,address,address,address)` and selector `0x6707255b2c5ca81220b2f3e408a269cb83baa6aa7e5e37aa1756883a6cdf06f1`. + ```solidity + event Deployed(address indexed amm, address indexed owner, address token0, address token1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Deployed { + #[allow(missing_docs)] + pub amm: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token1: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Deployed { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Deployed(address,address,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 103u8, 7u8, 37u8, 91u8, 44u8, 92u8, 168u8, 18u8, 32u8, 178u8, 243u8, 228u8, + 8u8, 162u8, 105u8, 203u8, 131u8, 186u8, 166u8, 170u8, 126u8, 94u8, 55u8, 170u8, + 23u8, 86u8, 136u8, 58u8, 108u8, 223u8, 6u8, 241u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + amm: topics.1, + owner: topics.2, + token0: data.0, + token1: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.token0, + ), + ::tokenize( + &self.token1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.amm.clone(), + self.owner.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.amm, + ); + out[2usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Deployed { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Deployed> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Deployed) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TradingDisabled(address)` and selector `0xc75bf4f03c02fab9414a7d7a54048c0486722bc72f33ad924709a0593608ad27`. + ```solidity + event TradingDisabled(address indexed amm); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TradingDisabled { + #[allow(missing_docs)] + pub amm: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TradingDisabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "TradingDisabled(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 199u8, 91u8, 244u8, 240u8, 60u8, 2u8, 250u8, 185u8, 65u8, 74u8, 125u8, 122u8, + 84u8, 4u8, 140u8, 4u8, 134u8, 114u8, 43u8, 199u8, 47u8, 51u8, 173u8, 146u8, + 71u8, 9u8, 160u8, 89u8, 54u8, 8u8, 173u8, 39u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { amm: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.amm.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.amm, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TradingDisabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TradingDisabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TradingDisabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address _settler); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _settler: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._settler,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _settler: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._settler, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `ammDeterministicAddress(address,address,address)` and selector `0x37ebdf50`. + ```solidity + function ammDeterministicAddress(address ammOwner, address token0, address token1) external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ammDeterministicAddressCall { + #[allow(missing_docs)] + pub ammOwner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token1: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`ammDeterministicAddress(address,address, + /// address)`](ammDeterministicAddressCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ammDeterministicAddressReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ammDeterministicAddressCall) -> Self { + (value.ammOwner, value.token0, value.token1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ammDeterministicAddressCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + ammOwner: tuple.0, + token0: tuple.1, + token1: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ammDeterministicAddressReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ammDeterministicAddressReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for ammDeterministicAddressCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [55u8, 235u8, 223u8, 80u8]; + const SIGNATURE: &'static str = "ammDeterministicAddress(address,address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.ammOwner, + ), + ::tokenize( + &self.token0, + ), + ::tokenize( + &self.token1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: ammDeterministicAddressReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: ammDeterministicAddressReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `create(address,uint256,address,uint256,uint256,address,bytes,bytes32)` and selector `0x22b155c6`. + ```solidity + function create(address token0, uint256 amount0, address token1, uint256 amount1, uint256 minTradedToken0, address priceOracle, bytes memory priceOracleData, bytes32 appData) external returns (address amm); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createCall { + #[allow(missing_docs)] + pub token0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub token1: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub minTradedToken0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub priceOracle: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub priceOracleData: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`create(address,uint256,address,uint256,uint256,address,bytes, + /// bytes32)`](createCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createReturn { + #[allow(missing_docs)] + pub amm: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createCall) -> Self { + ( + value.token0, + value.amount0, + value.token1, + value.amount1, + value.minTradedToken0, + value.priceOracle, + value.priceOracleData, + value.appData, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + token0: tuple.0, + amount0: tuple.1, + token1: tuple.2, + amount1: tuple.3, + minTradedToken0: tuple.4, + priceOracle: tuple.5, + priceOracleData: tuple.6, + appData: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createReturn) -> Self { + (value.amm,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amm: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [34u8, 177u8, 85u8, 198u8]; + const SIGNATURE: &'static str = + "create(address,uint256,address,uint256,uint256,address,bytes,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.token0, + ), + as alloy_sol_types::SolType>::tokenize(&self.amount0), + ::tokenize( + &self.token1, + ), + as alloy_sol_types::SolType>::tokenize(&self.amount1), + as alloy_sol_types::SolType>::tokenize(&self.minTradedToken0), + ::tokenize( + &self.priceOracle, + ), + ::tokenize( + &self.priceOracleData, + ), + as alloy_sol_types::SolType>::tokenize(&self.appData), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createReturn = r.into(); + r.amm + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createReturn = r.into(); + r.amm + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `deposit(address,uint256,uint256)` and selector `0x0efe6a8b`. + ```solidity + function deposit(address amm, uint256 amount0, uint256 amount1) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct depositCall { + #[allow(missing_docs)] + pub amm: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`deposit(address,uint256,uint256)`](depositCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct depositReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: depositCall) -> Self { + (value.amm, value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for depositCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amm: tuple.0, + amount0: tuple.1, + amount1: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: depositReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for depositReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl depositReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for depositCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = depositReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [14u8, 254u8, 106u8, 139u8]; + const SIGNATURE: &'static str = "deposit(address,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.amm, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + depositReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `owner(address)` and selector `0x666e1b39`. + ```solidity + function owner(address) external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerCall(pub alloy_sol_types::private::Address); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`owner(address)`](ownerCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for ownerCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [102u8, 110u8, 27u8, 57u8]; + const SIGNATURE: &'static str = "owner(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: ownerReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: ownerReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `withdraw(address,uint256,uint256)` and selector `0xb5c5f672`. + ```solidity + function withdraw(address amm, uint256 amount0, uint256 amount1) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct withdrawCall { + #[allow(missing_docs)] + pub amm: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`withdraw(address,uint256,uint256)`](withdrawCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct withdrawReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: withdrawCall) -> Self { + (value.amm, value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for withdrawCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amm: tuple.0, + amount0: tuple.1, + amount1: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: withdrawReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for withdrawReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl withdrawReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for withdrawCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = withdrawReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [181u8, 197u8, 246u8, 114u8]; + const SIGNATURE: &'static str = "withdraw(address,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.amm, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + withdrawReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`CowAmmConstantProductFactory`](self) function + /// calls. + #[derive(Clone)] + pub enum CowAmmConstantProductFactoryCalls { + #[allow(missing_docs)] + ammDeterministicAddress(ammDeterministicAddressCall), + #[allow(missing_docs)] + create(createCall), + #[allow(missing_docs)] + deposit(depositCall), + #[allow(missing_docs)] + owner(ownerCall), + #[allow(missing_docs)] + withdraw(withdrawCall), + } + impl CowAmmConstantProductFactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [14u8, 254u8, 106u8, 139u8], + [34u8, 177u8, 85u8, 198u8], + [55u8, 235u8, 223u8, 80u8], + [102u8, 110u8, 27u8, 57u8], + [181u8, 197u8, 246u8, 114u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(deposit), + ::core::stringify!(create), + ::core::stringify!(ammDeterministicAddress), + ::core::stringify!(owner), + ::core::stringify!(withdraw), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowAmmConstantProductFactoryCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 32usize; + const NAME: &'static str = "CowAmmConstantProductFactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::ammDeterministicAddress(_) => { + ::SELECTOR + } + Self::create(_) => ::SELECTOR, + Self::deposit(_) => ::SELECTOR, + Self::owner(_) => ::SELECTOR, + Self::withdraw(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowAmmConstantProductFactoryCalls, + >] = &[ + { + fn deposit( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowAmmConstantProductFactoryCalls::deposit) + } + deposit + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowAmmConstantProductFactoryCalls::create) + } + create + }, + { + fn ammDeterministicAddress( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw( + data, + ) + .map(CowAmmConstantProductFactoryCalls::ammDeterministicAddress) + } + ammDeterministicAddress + }, + { + fn owner( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowAmmConstantProductFactoryCalls::owner) + } + owner + }, + { + fn withdraw( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowAmmConstantProductFactoryCalls::withdraw) + } + withdraw + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowAmmConstantProductFactoryCalls, + >] = &[ + { + fn deposit( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(CowAmmConstantProductFactoryCalls::deposit) + } + deposit + }, + { + fn create( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(CowAmmConstantProductFactoryCalls::create) + } + create + }, + { + fn ammDeterministicAddress( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + CowAmmConstantProductFactoryCalls::ammDeterministicAddress, + ) + } + ammDeterministicAddress + }, + { + fn owner( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(CowAmmConstantProductFactoryCalls::owner) + } + owner + }, + { + fn withdraw( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(CowAmmConstantProductFactoryCalls::withdraw) + } + withdraw + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::ammDeterministicAddress(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::create(inner) => { + ::abi_encoded_size(inner) + } + Self::deposit(inner) => { + ::abi_encoded_size(inner) + } + Self::owner(inner) => { + ::abi_encoded_size(inner) + } + Self::withdraw(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::ammDeterministicAddress(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::create(inner) => { + ::abi_encode_raw(inner, out) + } + Self::deposit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::owner(inner) => { + ::abi_encode_raw(inner, out) + } + Self::withdraw(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CowAmmConstantProductFactory`](self) custom + /// errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowAmmConstantProductFactoryErrors { + #[allow(missing_docs)] + OnlyOwnerCanCall(OnlyOwnerCanCall), + #[allow(missing_docs)] + OrderNotValid(OrderNotValid), + } + impl CowAmmConstantProductFactoryErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[104u8, 186u8, 255u8, 248u8], [200u8, 252u8, 39u8, 37u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(OnlyOwnerCanCall), + ::core::stringify!(OrderNotValid), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowAmmConstantProductFactoryErrors { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 32usize; + const NAME: &'static str = "CowAmmConstantProductFactoryErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::OnlyOwnerCanCall(_) => { + ::SELECTOR + } + Self::OrderNotValid(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowAmmConstantProductFactoryErrors, + >] = &[ + { + fn OnlyOwnerCanCall( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowAmmConstantProductFactoryErrors::OnlyOwnerCanCall) + } + OnlyOwnerCanCall + }, + { + fn OrderNotValid( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowAmmConstantProductFactoryErrors::OrderNotValid) + } + OrderNotValid + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowAmmConstantProductFactoryErrors, + >] = &[ + { + fn OnlyOwnerCanCall( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmConstantProductFactoryErrors::OnlyOwnerCanCall) + } + OnlyOwnerCanCall + }, + { + fn OrderNotValid( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(CowAmmConstantProductFactoryErrors::OrderNotValid) + } + OrderNotValid + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::OnlyOwnerCanCall(inner) => { + ::abi_encoded_size(inner) + } + Self::OrderNotValid(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::OnlyOwnerCanCall(inner) => { + ::abi_encode_raw(inner, out) + } + Self::OrderNotValid(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CowAmmConstantProductFactory`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowAmmConstantProductFactoryEvents { + #[allow(missing_docs)] + ConditionalOrderCreated(ConditionalOrderCreated), + #[allow(missing_docs)] + Deployed(Deployed), + #[allow(missing_docs)] + TradingDisabled(TradingDisabled), + } + impl CowAmmConstantProductFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 44u8, 206u8, 172u8, 85u8, 85u8, 176u8, 202u8, 69u8, 163u8, 116u8, 76u8, 237u8, + 84u8, 47u8, 84u8, 181u8, 106u8, 210u8, 235u8, 69u8, 229u8, 33u8, 150u8, 35u8, + 114u8, 238u8, 242u8, 18u8, 162u8, 203u8, 243u8, 97u8, + ], + [ + 103u8, 7u8, 37u8, 91u8, 44u8, 92u8, 168u8, 18u8, 32u8, 178u8, 243u8, 228u8, 8u8, + 162u8, 105u8, 203u8, 131u8, 186u8, 166u8, 170u8, 126u8, 94u8, 55u8, 170u8, 23u8, + 86u8, 136u8, 58u8, 108u8, 223u8, 6u8, 241u8, + ], + [ + 199u8, 91u8, 244u8, 240u8, 60u8, 2u8, 250u8, 185u8, 65u8, 74u8, 125u8, 122u8, 84u8, + 4u8, 140u8, 4u8, 134u8, 114u8, 43u8, 199u8, 47u8, 51u8, 173u8, 146u8, 71u8, 9u8, + 160u8, 89u8, 54u8, 8u8, 173u8, 39u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(ConditionalOrderCreated), + ::core::stringify!(Deployed), + ::core::stringify!(TradingDisabled), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for CowAmmConstantProductFactoryEvents { + const COUNT: usize = 3usize; + const NAME: &'static str = "CowAmmConstantProductFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ConditionalOrderCreated) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Deployed) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::TradingDisabled) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for CowAmmConstantProductFactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::ConditionalOrderCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Deployed(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::TradingDisabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::ConditionalOrderCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Deployed(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TradingDisabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CowAmmConstantProductFactory`](self) contract instance. + + See the [wrapper's documentation](`CowAmmConstantProductFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CowAmmConstantProductFactoryInstance { + CowAmmConstantProductFactoryInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _settler: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + CowAmmConstantProductFactoryInstance::::deploy(__provider, _settler) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _settler: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + CowAmmConstantProductFactoryInstance::::deploy_builder(__provider, _settler) + } + /**A [`CowAmmConstantProductFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CowAmmConstantProductFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CowAmmConstantProductFactoryInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CowAmmConstantProductFactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CowAmmConstantProductFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CowAmmConstantProductFactoryInstance + { + /**Creates a new wrapper around an on-chain [`CowAmmConstantProductFactory`](self) contract instance. + + See the [wrapper's documentation](`CowAmmConstantProductFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _settler: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, _settler); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _settler: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { _settler })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CowAmmConstantProductFactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CowAmmConstantProductFactoryInstance { + CowAmmConstantProductFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CowAmmConstantProductFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`ammDeterministicAddress`] + /// function. + pub fn ammDeterministicAddress( + &self, + ammOwner: alloy_sol_types::private::Address, + token0: alloy_sol_types::private::Address, + token1: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, ammDeterministicAddressCall, N> { + self.call_builder(&ammDeterministicAddressCall { + ammOwner, + token0, + token1, + }) + } + + ///Creates a new call builder for the [`create`] function. + pub fn create( + &self, + token0: alloy_sol_types::private::Address, + amount0: alloy_sol_types::private::primitives::aliases::U256, + token1: alloy_sol_types::private::Address, + amount1: alloy_sol_types::private::primitives::aliases::U256, + minTradedToken0: alloy_sol_types::private::primitives::aliases::U256, + priceOracle: alloy_sol_types::private::Address, + priceOracleData: alloy_sol_types::private::Bytes, + appData: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, createCall, N> { + self.call_builder(&createCall { + token0, + amount0, + token1, + amount1, + minTradedToken0, + priceOracle, + priceOracleData, + appData, + }) + } + + ///Creates a new call builder for the [`deposit`] function. + pub fn deposit( + &self, + amm: alloy_sol_types::private::Address, + amount0: alloy_sol_types::private::primitives::aliases::U256, + amount1: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, depositCall, N> { + self.call_builder(&depositCall { + amm, + amount0, + amount1, + }) + } + + ///Creates a new call builder for the [`owner`] function. + pub fn owner( + &self, + _0: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, ownerCall, N> { + self.call_builder(&ownerCall(_0)) + } + + ///Creates a new call builder for the [`withdraw`] function. + pub fn withdraw( + &self, + amm: alloy_sol_types::private::Address, + amount0: alloy_sol_types::private::primitives::aliases::U256, + amount1: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, withdrawCall, N> { + self.call_builder(&withdrawCall { + amm, + amount0, + amount1, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CowAmmConstantProductFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`ConditionalOrderCreated`] + /// event. + pub fn ConditionalOrderCreated_filter( + &self, + ) -> alloy_contract::Event<&P, ConditionalOrderCreated, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Deployed`] event. + pub fn Deployed_filter(&self) -> alloy_contract::Event<&P, Deployed, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TradingDisabled`] event. + pub fn TradingDisabled_filter(&self) -> alloy_contract::Event<&P, TradingDisabled, N> { + self.event_filter::() + } + } +} +pub type Instance = CowAmmConstantProductFactory::CowAmmConstantProductFactoryInstance< + ::alloy_provider::DynProvider, +>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x40664207e3375FB4b733d4743CE9b159331fd034"), + Some(19861952u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xdb1cba3a87f2db53b6e1e6af48e28ed877592ec0"), + Some(33874317u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xb808e8183e3a72d196457d127c7fd4befa0d7fd3"), + Some(5874562u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/cowammfactorygetter/Cargo.toml b/contracts/generated/contracts-generated/cowammfactorygetter/Cargo.toml new file mode 100644 index 0000000000..f70f9f2106 --- /dev/null +++ b/contracts/generated/contracts-generated/cowammfactorygetter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowammfactorygetter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowammfactorygetter/src/lib.rs b/contracts/generated/contracts-generated/cowammfactorygetter/src/lib.rs new file mode 100644 index 0000000000..c3dbb5b91f --- /dev/null +++ b/contracts/generated/contracts-generated/cowammfactorygetter/src/lib.rs @@ -0,0 +1,441 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface CowAmmFactoryGetter { + function FACTORY() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "FACTORY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CowAmmFactoryGetter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `FACTORY()` and selector `0x2dd31000`. + ```solidity + function FACTORY() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct FACTORYCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`FACTORY()`](FACTORYCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct FACTORYReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: FACTORYCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for FACTORYCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: FACTORYReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for FACTORYReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for FACTORYCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [45u8, 211u8, 16u8, 0u8]; + const SIGNATURE: &'static str = "FACTORY()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: FACTORYReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: FACTORYReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`CowAmmFactoryGetter`](self) function calls. + #[derive(Clone)] + pub enum CowAmmFactoryGetterCalls { + #[allow(missing_docs)] + FACTORY(FACTORYCall), + } + impl CowAmmFactoryGetterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[45u8, 211u8, 16u8, 0u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(FACTORY)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowAmmFactoryGetterCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CowAmmFactoryGetterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::FACTORY(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[{ + fn FACTORY(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmFactoryGetterCalls::FACTORY) + } + FACTORY + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowAmmFactoryGetterCalls, + >] = &[{ + fn FACTORY(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmFactoryGetterCalls::FACTORY) + } + FACTORY + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::FACTORY(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::FACTORY(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CowAmmFactoryGetter`](self) contract instance. + + See the [wrapper's documentation](`CowAmmFactoryGetterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CowAmmFactoryGetterInstance { + CowAmmFactoryGetterInstance::::new(address, __provider) + } + /**A [`CowAmmFactoryGetter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CowAmmFactoryGetter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CowAmmFactoryGetterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CowAmmFactoryGetterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CowAmmFactoryGetterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CowAmmFactoryGetterInstance + { + /**Creates a new wrapper around an on-chain [`CowAmmFactoryGetter`](self) contract instance. + + See the [wrapper's documentation](`CowAmmFactoryGetterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CowAmmFactoryGetterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CowAmmFactoryGetterInstance { + CowAmmFactoryGetterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CowAmmFactoryGetterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`FACTORY`] function. + pub fn FACTORY(&self) -> alloy_contract::SolCallBuilder<&P, FACTORYCall, N> { + self.call_builder(&FACTORYCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CowAmmFactoryGetterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = CowAmmFactoryGetter::CowAmmFactoryGetterInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/cowammlegacyhelper/Cargo.toml b/contracts/generated/contracts-generated/cowammlegacyhelper/Cargo.toml new file mode 100644 index 0000000000..39331d874d --- /dev/null +++ b/contracts/generated/contracts-generated/cowammlegacyhelper/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowammlegacyhelper" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowammlegacyhelper/src/lib.rs b/contracts/generated/contracts-generated/cowammlegacyhelper/src/lib.rs new file mode 100644 index 0000000000..e0d8676626 --- /dev/null +++ b/contracts/generated/contracts-generated/cowammlegacyhelper/src/lib.rs @@ -0,0 +1,3196 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Interaction { + struct Data { address target; uint256 value; bytes callData; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Interaction { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address target; uint256 value; bytes callData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub callData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + (value.target, value.value, value.callData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + value: tuple.1, + callData: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.target, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.callData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address target,uint256 value,bytes callData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.target, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.value) + .0, + ::eip712_data_word( + &self.callData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.target, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.value) + + ::topic_preimage_length( + &rust.callData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.target, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.value, + out, + ); + ::encode_topic_preimage( + &rust.callData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Interaction`](self) contract instance. + + See the [wrapper's documentation](`GPv2InteractionInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2InteractionInstance { + GPv2InteractionInstance::::new(address, __provider) + } + /**A [`GPv2Interaction`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Interaction`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2InteractionInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2InteractionInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2InteractionInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Interaction`](self) contract instance. + + See the [wrapper's documentation](`GPv2InteractionInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2InteractionInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2InteractionInstance { + GPv2InteractionInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Order { + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Order { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub sellToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub buyToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub validTo: u32, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub kind: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub partiallyFillable: bool, + #[allow(missing_docs)] + pub sellTokenBalance: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub buyTokenBalance: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u32, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::FixedBytes<32>, + bool, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + ( + value.sellToken, + value.buyToken, + value.receiver, + value.sellAmount, + value.buyAmount, + value.validTo, + value.appData, + value.feeAmount, + value.kind, + value.partiallyFillable, + value.sellTokenBalance, + value.buyTokenBalance, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sellToken: tuple.0, + buyToken: tuple.1, + receiver: tuple.2, + sellAmount: tuple.3, + buyAmount: tuple.4, + validTo: tuple.5, + appData: tuple.6, + feeAmount: tuple.7, + kind: tuple.8, + partiallyFillable: tuple.9, + sellTokenBalance: tuple.10, + buyTokenBalance: tuple.11, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.sellToken, + ), + ::tokenize( + &self.buyToken, + ), + ::tokenize( + &self.receiver, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellAmount), + as alloy_sol_types::SolType>::tokenize(&self.buyAmount), + as alloy_sol_types::SolType>::tokenize(&self.validTo), + as alloy_sol_types::SolType>::tokenize(&self.appData), + as alloy_sol_types::SolType>::tokenize(&self.feeAmount), + as alloy_sol_types::SolType>::tokenize(&self.kind), + ::tokenize( + &self.partiallyFillable, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellTokenBalance), + as alloy_sol_types::SolType>::tokenize(&self.buyTokenBalance), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address sellToken,address buyToken,address receiver,uint256 \ + sellAmount,uint256 buyAmount,uint32 validTo,bytes32 appData,uint256 \ + feeAmount,bytes32 kind,bool partiallyFillable,bytes32 \ + sellTokenBalance,bytes32 buyTokenBalance)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.sellToken, + ) + .0, + ::eip712_data_word( + &self.buyToken, + ) + .0, + ::eip712_data_word( + &self.receiver, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.sellAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.buyAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.validTo) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.appData) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.feeAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.kind) + .0, + ::eip712_data_word( + &self.partiallyFillable, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.sellTokenBalance, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.buyTokenBalance, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.sellToken, + ) + + ::topic_preimage_length( + &rust.buyToken, + ) + + ::topic_preimage_length( + &rust.receiver, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.validTo, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.appData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.feeAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.kind) + + ::topic_preimage_length( + &rust.partiallyFillable, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellTokenBalance, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyTokenBalance, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.sellToken, + out, + ); + ::encode_topic_preimage( + &rust.buyToken, + out, + ); + ::encode_topic_preimage( + &rust.receiver, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.validTo, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.appData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.feeAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.kind, + out, + ); + ::encode_topic_preimage( + &rust.partiallyFillable, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellTokenBalance, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyTokenBalance, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2OrderInstance { + GPv2OrderInstance::::new(address, __provider) + } + /**A [`GPv2Order`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Order`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2OrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2OrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2OrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2OrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2OrderInstance { + GPv2OrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library GPv2Interaction { + struct Data { + address target; + uint256 value; + bytes callData; + } +} + +library GPv2Order { + struct Data { + address sellToken; + address buyToken; + address receiver; + uint256 sellAmount; + uint256 buyAmount; + uint32 validTo; + bytes32 appData; + uint256 feeAmount; + bytes32 kind; + bool partiallyFillable; + bytes32 sellTokenBalance; + bytes32 buyTokenBalance; + } +} + +interface CowAmmLegacyHelper { + error InvalidArrayLength(); + error MathOverflowedMulDiv(); + error NoOrder(); + error PoolDoesNotExist(); + error PoolIsClosed(); + error PoolIsPaused(); + + event COWAMMPoolCreated(address indexed amm); + + constructor(); + + function factory() external view returns (address); + function order(address pool, uint256[] memory prices) external view returns (GPv2Order.Data memory _order, GPv2Interaction.Data[] memory preInteractions, GPv2Interaction.Data[] memory postInteractions, bytes memory sig); + function tokens(address pool) external view returns (address[] memory _tokens); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "order", + "inputs": [ + { + "name": "pool", + "type": "address", + "internalType": "address" + }, + { + "name": "prices", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [ + { + "name": "_order", + "type": "tuple", + "internalType": "struct GPv2Order.Data", + "components": [ + { + "name": "sellToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "kind", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sellTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "buyTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "preInteractions", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "postInteractions", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "sig", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "tokens", + "inputs": [ + { + "name": "pool", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "_tokens", + "type": "address[]", + "internalType": "address[]" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "COWAMMPoolCreated", + "inputs": [ + { + "name": "amm", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "InvalidArrayLength", + "inputs": [] + }, + { + "type": "error", + "name": "MathOverflowedMulDiv", + "inputs": [] + }, + { + "type": "error", + "name": "NoOrder", + "inputs": [] + }, + { + "type": "error", + "name": "PoolDoesNotExist", + "inputs": [] + }, + { + "type": "error", + "name": "PoolIsClosed", + "inputs": [] + }, + { + "type": "error", + "name": "PoolIsPaused", + "inputs": [] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CowAmmLegacyHelper { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561000f575f80fd5b5061001861001d565b6102ff565b46600181900361011257610044739941fd7db2003308e7ee17b04400012278f12ac66102c9565b61006173b3bf81714f704720dcb0351ff0d42eca61b069fc6102c9565b61007e73301076c36e034948a747bb61bab9cd03f62672e36102c9565b61009b73027e1cbf2c299cba5eb8a2584910d04f1a8aa4036102c9565b6100b873beef5afe88ef73337e5070ab2855d37dbf5493a46102c9565b6100d573c6b13d5e662fa0458f03995bcb824a1934aa895f6102c9565b6100f273d7cb8cc1b56356bb7b78d02e785ead28e21586606102c9565b61010f73079c868f97aed8e0d03f11e1529c3b056ff21cea6102c9565b50565b8060640361010f5761013773bc6159fd429be18206e60b3bb01d7289f905511b6102c9565b61015473e5d1aa8565f5dbfc06cde20dfd76b4c7c6d43bd56102c9565b610171739d8570ef9a519ca81daec35212f435d9843ba5646102c9565b61018e73d97c31e53f16f495715ce71e12e11b9545eedd8b6102c9565b6101ab73ff1bd3d570e3544c183ba77f5a4d3cc742c8d2b36102c9565b6101c873209d269dfd66b9cec764de7eb6fefc24f75bdd486102c9565b6101e573c37575ad8efe530fd8a79aeb0087e5872a24dabc6102c9565b610202731c7828dadade12a848f36be8e2d3146462abff686102c9565b61021f73aba5294bba7d3635c2a3e44d0e87ea7f58898fb76102c9565b61023c736eb7be972aebb6be2d9acf437cb412c0abee912b6102c9565b61025973c4d09969aad7f252c75dd352bbbd719e34ed06ad6102c9565b61027673a25af86a5dbea45e9fd70c1879489f63d081ad446102c9565b6102937357492cb6c8ee2998e9d83ddc8c713e781ffe548e6102c9565b6102b073c33e3ec14556a8e71be3097fe2dc8c0b9119c8976102c9565b61010f7377472826875953374ed3084c31a483f827987f145b6040516001600160a01b038216907f0d03834d0d86c7f57e877af40e26f176dc31bd637535d4ba153d1ac9de88a7ea905f90a250565b6156848061030c5f395ff3fe608060405234801561000f575f80fd5b506004361061006f575f3560e01c80632aec79a01161004d5780632aec79a0146100de578063c45a0155146100f1578063e48603391461011e575f80fd5b806310029daa14610073578063215702561461009b57806327242c9b146100bb575b5f80fd5b610086610081366004612462565b61013e565b60405190151581526020015b60405180910390f35b6100ae6100a9366004612462565b61050c565b60405161009291906124c9565b6100ce6100c93660046124db565b610cc6565b60405161009294939291906126e9565b6100866100ec366004612462565b61132d565b6100f9611340565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610092565b61013161012c366004612462565b611410565b6040516100929190612734565b6040517f5624b25b0000000000000000000000000000000000000000000000000000000081527f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d56004820152600160248201525f90819073ffffffffffffffffffffffffffffffffffffffff841690635624b25b906044015f60405180830381865afa1580156101d0573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610215919081019061288a565b80602001905181019061022891906128c4565b90505f732f55e8b20d0b9fefa187aa7d00b6cbe563605bf573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161490505f73fdafc9d1902f4e0b84f65f49f244b32b31013b7473ffffffffffffffffffffffffffffffffffffffff16732f55e8b20d0b9fefa187aa7d00b6cbe563605bf573ffffffffffffffffffffffffffffffffffffffff166351cad5ee87739008d19f58aabd9ed0d60971565aa8510560ab4173ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034e91906128df565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401602060405180830381865afa1580156103ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103de91906128c4565b73ffffffffffffffffffffffffffffffffffffffff161490505f6104018661050c565b80602001905181019061041491906128f6565b90505f73fdafc9d1902f4e0b84f65f49f244b32b31013b7473ffffffffffffffffffffffffffffffffffffffff16636108c532888460405160200161045991906129cf565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b81526004016104ad92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b602060405180830381865afa1580156104c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104ec91906129e1565b90508380156104f85750825b80156105015750805b979650505050505050565b60604660018190036107bd5773ffffffffffffffffffffffffffffffffffffffff8316739941fd7db2003308e7ee17b04400012278f12ac60361056c57604051806101e001604052806101c0815260200161482f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673b3bf81714f704720dcb0351ff0d42eca61b069fc036105c057604051806101e001604052806101c081526020016150ef6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673301076c36e034948a747bb61bab9cd03f62672e30361061457604051806101e001604052806101c0815260200161364f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673027e1cbf2c299cba5eb8a2584910d04f1a8aa4030361066857604051806101e001604052806101c08152602001612d2f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673beef5afe88ef73337e5070ab2855d37dbf5493a4036106bc57604051806101e001604052806101c081526020016142ef6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c6b13d5e662fa0458f03995bcb824a1934aa895f0361071057604051806101e001604052806101c0815260200161412f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673d7cb8cc1b56356bb7b78d02e785ead28e21586600361076457604051806101e001604052806101c081526020016139cf6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673079c868f97aed8e0d03f11e1529c3b056ff21cea036107b857604051806101e001604052806101c081526020016149ef6101c091399392505050565b610cb1565b80606403610cb15773ffffffffffffffffffffffffffffffffffffffff831673bc6159fd429be18206e60b3bb01d7289f905511b0361081957604051806101e001604052806101c08152602001612eef6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673e5d1aa8565f5dbfc06cde20dfd76b4c7c6d43bd50361086d57604051806101e001604052806101c0815260200161466f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff8316739d8570ef9a519ca81daec35212f435d9843ba564036108c157604051806101e001604052806101c08152602001614baf6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673d97c31e53f16f495715ce71e12e11b9545eedd8b036109155760405180610240016040528061022081526020016130af61022091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673ff1bd3d570e3544c183ba77f5a4d3cc742c8d2b30361096957604051806101e001604052806101c0815260200161548f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673209d269dfd66b9cec764de7eb6fefc24f75bdd48036109bd57604051806101e001604052806101c08152602001614f2f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c37575ad8efe530fd8a79aeb0087e5872a24dabc03610a1157604051806101e001604052806101c0815260200161348f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff8316731c7828dadade12a848f36be8e2d3146462abff6803610a6557604051806101e001604052806101c08152602001613f6f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673aba5294bba7d3635c2a3e44d0e87ea7f58898fb703610ab957604051806101e001604052806101c08152602001614d6f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff8316736eb7be972aebb6be2d9acf437cb412c0abee912b03610b0d57604051806101e001604052806101c081526020016132cf6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c4d09969aad7f252c75dd352bbbd719e34ed06ad03610b61576040518061024001604052806102208152602001613d4f61022091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673a25af86a5dbea45e9fd70c1879489f63d081ad4403610bb557604051806101e001604052806101c081526020016144af6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff83167357492cb6c8ee2998e9d83ddc8c713e781ffe548e03610c09576040518061020001604052806101e081526020016152af6101e091399392505050565b73ffffffffffffffffffffffffffffffffffffffff831673c33e3ec14556a8e71be3097fe2dc8c0b9119c89703610c5d57604051806101e001604052806101c0815260200161380f6101c091399392505050565b73ffffffffffffffffffffffffffffffffffffffff83167377472826875953374ed3084c31a483f827987f1403610cb157604051806101e001604052806101c08152602001613b8f6101c091399392505050565b505060408051602081019091525f8152919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526060808060028514610d64576040517f9d89020a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060610d6f8861132d565b6112e957610d7c88611696565b610de7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f506f6f6c206973206e6f74206120436f5720414d4d000000000000000000000060448201526064015b60405180910390fd5b5f8873ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e5591906128c4565b90505f8973ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ea1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ec591906128c4565b90508973ffffffffffffffffffffffffffffffffffffffff16634ada218b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f10573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3491906129e1565b15155f03610f6e576040517f21081abf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110816040518060c001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018b8b6001818110610fe357610fe3612a00565b9050602002013581526020018b8b5f81811061100157611001612a00565b9050602002013581526020018c73ffffffffffffffffffffffffffffffffffffffff16636dbc88136040518163ffffffff1660e01b8152600401602060405180830381865afa158015611056573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061107a91906128df565b905261174e565b9650866040516020016110949190612a2d565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815260018084528383019092529450816020015b60408051606080820183525f8083526020830152918101919091528152602001906001900390816110d157905050955060405180606001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020015f815260200161123b739008d19f58aabd9ed0d60971565aa8510560ab4173ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa15801561118e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111b291906128df565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08b0180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60405160240161124d91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff14fcbc8000000000000000000000000000000000000000000000000000000001790529052865187905f906112d7576112d7612a00565b602002602001018190525050506112ff565b6112f4888888611ad6565b929750909550935090505b8781604051602001611312929190612a3c565b60405160208183030381529060405291505093509350935093565b5f806113388361050c565b511192915050565b5f46600181900361136657738deed8ed7c5fcb55884f13f121654bb4bb7c843791505090565b8060640361138957732af6c59fc957d4a45ddbbd927fa30f7c5051f58391505090565b8062aa36a7036113ae5773bd18758055dbe3ed37a2471394559ae97a5da5c091505090565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e737570706f7274656420636861696e0000000000000000000000000000006044820152606401610dde565b60408051600280825260608083018452926020830190803683370190505090506114398261132d565b6115b5578173ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611486573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114aa91906128c4565b815f815181106114bc576114bc612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561153f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061156391906128c4565b8160018151811061157657611576612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050919050565b5f6115bf8361215f565b509050805f815181106115d4576115d4612a00565b6020026020010151825f815181106115ee576115ee612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508060018151811061163b5761163b612a00565b60200260200101518260018151811061165657611656612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505050919050565b5f806116a0611340565b6040517f666e1b3900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152919091169063666e1b3990602401602060405180830381865afa15801561170c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061173091906128c4565b73ffffffffffffffffffffffffffffffffffffffff16141592915050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152602082015182516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201525f92839216906370a0823190602401602060405180830381865afa158015611822573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061184691906128df565b604085810151865191517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529116906370a0823190602401602060405180830381865afa1580156118b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118db91906128df565b915091505f805f805f8860800151876118f49190612aae565b90505f8960600151876119079190612aae565b90508181101561196d578960200151955089604001519450611939818b6080015160026119349190612aae565b61227b565b61194460028a612af2565b61194e9190612b05565b9350611966848861195f828c612b05565b60016122cb565b92506119b9565b8960400151955089602001519450611990828b6060015160026119349190612aae565b61199b600289612af2565b6119a59190612b05565b93506119b6848961195f828b612b05565b92505b6040518061018001604052808773ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff16815260200185815260200184815260200161012c42611a339190612b18565b63ffffffff1681526020018b60a0015181526020015f81526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020016001151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981525098505050505050505050919050565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526060806060611b448761013e565b611b7a576040517fefc869b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b858961215f565b915091505f8160400151806020019051810190611ba29190612b3c565b9050611c836040518060c001604052808c73ffffffffffffffffffffffffffffffffffffffff168152602001855f81518110611be057611be0612a00565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16815260200185600181518110611c1657611c16612a00565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018b8b6001818110611c4c57611c4c612a00565b9050602002013581526020018b8b5f818110611c6a57611c6a612a00565b9050602002013581526020018360a0015181525061174e565b96505f739008d19f58aabd9ed0d60971565aa8510560ab4173ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ce3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d0791906128df565b9050807fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48989604051602001611d3c9190612a2d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181525f60608401818152608085018452845260208085018a9052835180820185529182528484019190915291519092611da092909101612bf4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611dde94939291602401612c9d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f5fd7e97d000000000000000000000000000000000000000000000000000000001790528151600180825281840190935292975082015b60408051606080820183525f808352602083015291810191909152815260200190600190039081611e685790505060408051606081018252855173ffffffffffffffffffffffffffffffffffffffff1681525f602082015291985081018c611f558b857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60405173ffffffffffffffffffffffffffffffffffffffff90921660248301526044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30f73c99000000000000000000000000000000000000000000000000000000001790529052875188905f9061200757612007612a00565b602090810291909101015260408051600180825281830190925290816020015b60408051606080820183525f8083526020830152918101919091528152602001906001900390816120275790505095506040518060600160405280845f015173ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020018c5f801b6040516024016120bd92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30f73c99000000000000000000000000000000000000000000000000000000001790529052865187905f9061214757612147612a00565b60200260200101819052505050505093509350935093565b60408051606081810183525f80835260208301529181018290526121828361050c565b80602001905181019061219591906128f6565b90505f81604001518060200190518101906121b09190612b3c565b6040805160028082526060820183529293509190602083019080368337019050509250805f0151835f815181106121e9576121e9612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080602001518360018151811061223b5761223b612a00565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505050915091565b5f815f036122945761228d8284612af2565b90506122c5565b82156122c057816122a6600185612b05565b6122b09190612af2565b6122bb906001612ccd565b6122c2565b5f5b90505b92915050565b5f806122d886868661231a565b90506122e383612412565b80156122fe57505f84806122f9576122f9612ac5565b868809115b156123115761230e600182612ccd565b90505b95945050505050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f0361236d5783828161236357612363612ac5565b049250505061240b565b8084116123a6576040517f227bc15300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b5f600282600381111561242757612427612ce0565b6124319190612d0d565b60ff166001149050919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461245f575f80fd5b50565b5f60208284031215612472575f80fd5b813561240b8161243e565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6122c2602083018461247d565b5f805f604084860312156124ed575f80fd5b83356124f88161243e565b9250602084013567ffffffffffffffff80821115612514575f80fd5b818601915086601f830112612527575f80fd5b813581811115612535575f80fd5b8760208260051b8501011115612549575f80fd5b6020830194508093505050509250925092565b805173ffffffffffffffffffffffffffffffffffffffff168252602081015161259d602084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408101516125c5604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608301526080810151608083015260a08101516125f160a084018263ffffffff169052565b5060c081015160c083015260e081015160e0830152610100808201518184015250610120808201516126268285018215159052565b5050610140818101519083015261016090810151910152565b5f82825180855260208086019550808260051b8401018186015f5b848110156126dc578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00189528151805173ffffffffffffffffffffffffffffffffffffffff16845284810151858501526040908101516060918501829052906126c88186018361247d565b9a86019a945050509083019060010161265a565b5090979650505050505050565b5f6101e06126f7838861255c565b8061018084015261270a8184018761263f565b90508281036101a084015261271f818661263f565b90508281036101c0840152610501818561247d565b602080825282518282018190525f9190848201906040850190845b8181101561278157835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161274f565b50909695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160c0810167ffffffffffffffff811182821017156127dd576127dd61278d565b60405290565b5f82601f8301126127f2575f80fd5b815167ffffffffffffffff8082111561280d5761280d61278d565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156128535761285361278d565b8160405283815286602085880101111561286b575f80fd5b8360208701602083015e5f602085830101528094505050505092915050565b5f6020828403121561289a575f80fd5b815167ffffffffffffffff8111156128b0575f80fd5b6128bc848285016127e3565b949350505050565b5f602082840312156128d4575f80fd5b815161240b8161243e565b5f602082840312156128ef575f80fd5b5051919050565b5f60208284031215612906575f80fd5b815167ffffffffffffffff8082111561291d575f80fd5b9083019060608286031215612930575f80fd5b60405160608101818110838211171561294b5761294b61278d565b60405282516129598161243e565b815260208381015190820152604083015182811115612976575f80fd5b612982878286016127e3565b60408301525095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8151168252602081015160208301525f6040820151606060408501526128bc606085018261247d565b602081525f6122c26020830184612991565b5f602082840312156129f1575f80fd5b8151801515811461240b575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b61018081016122c5828461255c565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008360601b1681525f82518060208501601485015e5f92016014019182525092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820281158282048414176122c5576122c5612a81565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82612b0057612b00612ac5565b500490565b818103818111156122c5576122c5612a81565b63ffffffff818116838216019080821115612b3557612b35612a81565b5092915050565b5f60208284031215612b4c575f80fd5b815167ffffffffffffffff80821115612b63575f80fd5b9083019060c08286031215612b76575f80fd5b612b7e6127ba565b8251612b898161243e565b81526020830151612b998161243e565b6020820152604083810151908201526060830151612bb68161243e565b6060820152608083015182811115612bcc575f80fd5b612bd8878286016127e3565b60808301525060a083015160a082015280935050505092915050565b602080825282516060838301528051608084018190525f9291820190839060a08601905b80831015612c385783518252928401926001929092019190840190612c18565b508387015193507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0925082868203016040870152612c768185612991565b93505050604085015181858403016060860152612c93838261247d565b9695505050505050565b848152836020820152608060408201525f612cbb608083018561247d565b8281036060840152610501818561247d565b808201808211156122c5576122c5612a81565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60ff831680612d1f57612d1f612ac5565b8060ff8416069150509291505056fe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424dac5a0e756ac88c1d3a4c41900d977fe93c2d34fc95a00ca3e84eb4c6b50faf949000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000005afe3855358e112b5647b952709e6165e1c1eeee000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000200000000000000000000000002e7e978da0c53404a8cf66ed4ba2c7706c07b62a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851d85c99996d84d25387bc0d01e50e3ea814f64e7e04a3b949a571789e196c5a910000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006a023ccd1ff6f2045c3309768ead9e68f978f6e1000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000000000000000000000000000000affd9fdeb8e08000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020a99fd9950b5d5dceeaf4939e221dca8ca9b938ab0001000000000000000000250000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85178a729ee3008c7d48832d02267b72e5f34ada8f554a6731a368f01590ed71b34000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cb444e90d8198415266c6a2724b7900fb12fc56e000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d0000000000000000000000000000000000000000000000008156197a5425c0c8000000000000000000000000bd91a72dc3d9b5d9b16ee8638da1fc65311bd90a00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000080000000000000000000000000ab70bcb260073d036d1660201e9d5405f5829b7a000000000000000000000000678df3415fc31947da4324ec63212874be5a82f8000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a8512e31981e34960969eb549f5e826cf77f655e72b03603ad574a79fd015f4de4de0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea6000000000000000000000000af204776c7245bf4147c2612bf6e5972ee483701000000000000000000000000000000000000000000000000000a16c95a4d2e3c000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c0ce9e05c2aee5f22f9941c4cd1f1a1d13194b109779422d5ad9a980157bd0f1640000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f90002000000000000000000630000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851a2029fbb545978d05378b6df19e3754fe5ed2d0ba1e051027503934372f7beb20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb000000000000000000000000177127622c4a00f3d409b75571e12cb3c8973d3c0000000000000000000000000000000000000000000000000052ba9efc38441a000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c89000000000000000000000000000000000000000000000000000000000000002021d4c792ea7e38e0d0819c2011a2b1cb7252bd9900020000000000000000001e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424daca44b6a304baa16d11b6db07066c1276b1273ee3f94590bbd03201a61882af9a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000098cb76000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85159457ac6201da7713efecd84618c7a168e88b9cb7d1c0db128af1efe0a08bbb10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea6000000000000000000000000af204776c7245bf4147c2612bf6e5972ee483701000000000000000000000000000000000000000000000000000a17273fc14b64000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f9000200000000000000000063000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da80ba533f014ef4238ab7ad203c0aeacbf30a71c0346140db77c43ae3121afadd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000aea46a60368a7bd060eec7df8cba43b7ef41ad85000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000336632e53c8ecf04000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000200000000000000000000000004042a04c54ef133ac2a3c93db69d43c6c02a330b0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851d67c9fb87045e07da94c81de035b5c7f435cd46568fca02aa35d709bbc9e21fa0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008e5bbbb09ed1ebde8674cda39a0c169401db4252000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000e089049027b95c2745d1a954bc1d245352d884e900000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000200000000000000000000000008db8870ca4b8ac188c4d1a014f34a381ae27e1c20000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851209c17d9ebe3ac7352795f7f8b3d14d253d92430831d3b2c3965f9a578da7618000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d0000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea60000000000000000000000000000000000000000000000008aa3a52815262f58000000000000000000000000bd91a72dc3d9b5d9b16ee8638da1fc65311bd90a00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000064ac007ff665cf8d0d3af5e0ad1c26a3f853ea000000000000000000000000a767f745331d267c7751297d982b050c93985627000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85105416460deb76d57af601be17e777b93592d8d4d4a4096c57876a91c84f418080000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb000000000000000000000000ce11e14225575945b8e6dc0d4f2dd4c570f79d9f000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000009634ca647474b6b78d3382331a77cd00a8a940da00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da932542294ff270a8bbdbe1fb921de3d09c9749dc35627361fc17c44b9b026b810000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008390a1da07e376ef7add4be859ba74fb83aa02d5000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000aec1c94998000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c89000000000000000000000000000000000000000000000000000000000000002000000000000000000000000069c66beafb06674db41b22cfc50c34a93b8d82a2000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000def1ca1fb7fbcdc777520aa7f396b4e015f497ab000000000000000000000000000000000000000000000000025bf6196bd10000000000000000000000000000ad37fe3ddedf8cdee1022da1b17412cfb649559600000000000000000000000000000000000000000000000000000000000000c0d661a16b0e85eadb705cf5158132b5dd1ebc0a49929ef68097698d15e2a4e3b40000000000000000000000000000000000000000000000000000000000000020de8c195aa41c11a0c4787372defbbddaa31306d20002000000000000000001810000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851560d33bcc26b7f10765f8ae10b1abc4ed265ba0c7a1f9948d06de97c31044aee0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004d18815d14fe5c3304e87b3fa18318baa5c238200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a9b2234773cc6a4f3a34a770c52c931cba5c24b20002000000000000000000870000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851437a72b19b25e8b62fdfb81146ec83c66462138d3d9e08998594853566fa9add000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000177127622c4a00f3d409b75571e12cb3c8973d3c0000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea600000000000000000000000000000000000000000000000146e114355e0f6088000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000204cdabe9e07ca393943acfb9286bbbd0d0a310ff600020000000000000000005c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da559d5fda20be80608e4d5ea1b41e6b9330efca7934beb094281dd4d8f4889374000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000079ef7f110fdfae4000000000000000000000000ad37fe3ddedf8cdee1022da1b17412cfb649559600000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020e99481dc77691d8e2456e5f3f61c1810adfc1503000200000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424da56871afb17e444c418900f6db3e1ade07d49eadea1accf03fcebc0a6e7e4b653000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b2617246d0c6c0087f18703d576831899ca94f01000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000048bcb79dba2b56b90000000000000000000000000573cc0c800048f94e022463b9214d92c2d65e97b00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b36ec83d844c0579ec2493f10b2087e96bb654600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a8511ea56ac96a6369d36ef3fe56ae0ddff8d0cc89e1623095239c5ceed2505aa2810000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb0000000000000000000000006a023ccd1ff6f2045c3309768ead9e68f978f6e1000000000000000000000000000000000000000000000000006b43c27d2e8300000000000000000000000000e089049027b95c2745d1a954bc1d245352d884e900000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c89000000000000000000000000000000000000000000000000000000000000002000000000000000000000000028dbd35fd79f48bfa9444d330d14683e7101d8170000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851d1e868d120e326e5581caa39852bb0da9234a511ed76e6f7a9dcceb0d5f154c70000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea6000000000000000000000000af204776c7245bf4147c2612bf6e5972ee48370100000000000000000000000000000000000000000000000000098e46995425ca000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f90002000000000000000000630000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a851f0e8ec512b2507dae99175a0a4792d8a53e0863fbb5e735a5c993295bbd17f480000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea60000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb00000000000000000000000000000000000000000000000000094f8d9168e271000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c8900000000000000000000000000000000000000000000000000000000000000204683e340a8049261057d5ab1b29c8d840e75695e00020000000000000000005a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000034323b933096534e43958f6c7bf44f2bb59424dad003838829115f5d9ff3ed69c8d2b4b26e10eb1a79331206c28fbb4734390a5e000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000808507121b80c02388fad14726482e061b8da827000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000189b23422a9b84d8000000000000000000000000ad37fe3ddedf8cdee1022da1b17412cfb649559600000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020fd1cf6fd41f229ca86ada0584c63c49c3d66bbc90002000000000000000004380000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a8513956efd63537b00bb3b152d3c4961207b6ca14d6f506c66fc0aef4c8e2e176b5000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cb444e90d8198415266c6a2724b7900fb12fc56e0000000000000000000000009c58bacc331c9aa871afd802db6379a98e80cedb000000000000000000000000000000000000000000000000000000000000004500000000000000000000000015b4c67070d3748b8ec93c8a32f7efe2e8f684c900000000000000000000000000000000000000000000000000000000000000c0056e9806d953dbe2df4352a90ad2c1148c51460e941107f0909fae382b1661cf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000022441d81416430a54336ab28765abd31a792ad37000000000000000000000000ab70bcb260073d036d1660201e9d5405f5829b7a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000b148f40fff05b5ce6b22752cf8e454b556f7a85133f583d55c4509d5e10ebe3c7c69bce17af4c57419d6c9c90c8f588dd3232c0d000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000af204776c7245bf4147c2612bf6e5972ee4837010000000000000000000000006c76971f98945ae98dd7d4dfca8711ebea946ea600000000000000000000000000000000000000000000000410d586a20a4c0000000000000000000000000000d3a84895080609e1163c80b2bd65736db1b86bec00000000000000000000000000000000000000000000000000000000000000c04d821ddc9d656177dad4d5c2f76a4bff2ed514ff69fa4aa4fd869d6e98d55c890000000000000000000000000000000000000000000000000000000000000020bc2acf5e821c5c9f8667a36bb1131dad26ed64f9000200000000000000000063a2646970667358221220c3b6b701e7d5db53232efcebe1fe1bdd40a35653449ba7cd10551b9e5bf6a94a64736f6c63430008190033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[Pa\0\x18a\0\x1DV[a\x02\xFFV[F`\x01\x81\x90\x03a\x01\x12Wa\0Ds\x99A\xFD}\xB2\x003\x08\xE7\xEE\x17\xB0D\0\x01\"x\xF1*\xC6a\x02\xC9V[a\0as\xB3\xBF\x81qOpG \xDC\xB05\x1F\xF0\xD4.\xCAa\xB0i\xFCa\x02\xC9V[a\0~s0\x10v\xC3n\x03IH\xA7G\xBBa\xBA\xB9\xCD\x03\xF6&r\xE3a\x02\xC9V[a\0\x9Bs\x02~\x1C\xBF,)\x9C\xBA^\xB8\xA2XI\x10\xD0O\x1A\x8A\xA4\x03a\x02\xC9V[a\0\xB8s\xBE\xEFZ\xFE\x88\xEFs3~Pp\xAB(U\xD3}\xBFT\x93\xA4a\x02\xC9V[a\0\xD5s\xC6\xB1=^f/\xA0E\x8F\x03\x99[\xCB\x82J\x194\xAA\x89_a\x02\xC9V[a\0\xF2s\xD7\xCB\x8C\xC1\xB5cV\xBB{x\xD0.x^\xAD(\xE2\x15\x86`a\x02\xC9V[a\x01\x0Fs\x07\x9C\x86\x8F\x97\xAE\xD8\xE0\xD0?\x11\xE1R\x9C;\x05o\xF2\x1C\xEAa\x02\xC9V[PV[\x80`d\x03a\x01\x0FWa\x017s\xBCaY\xFDB\x9B\xE1\x82\x06\xE6\x0B;\xB0\x1Dr\x89\xF9\x05Q\x1Ba\x02\xC9V[a\x01Ts\xE5\xD1\xAA\x85e\xF5\xDB\xFC\x06\xCD\xE2\r\xFDv\xB4\xC7\xC6\xD4;\xD5a\x02\xC9V[a\x01qs\x9D\x85p\xEF\x9AQ\x9C\xA8\x1D\xAE\xC3R\x12\xF45\xD9\x84;\xA5da\x02\xC9V[a\x01\x8Es\xD9|1\xE5?\x16\xF4\x95q\\\xE7\x1E\x12\xE1\x1B\x95E\xEE\xDD\x8Ba\x02\xC9V[a\x01\xABs\xFF\x1B\xD3\xD5p\xE3TL\x18;\xA7\x7FZM<\xC7B\xC8\xD2\xB3a\x02\xC9V[a\x01\xC8s \x9D&\x9D\xFDf\xB9\xCE\xC7d\xDE~\xB6\xFE\xFC$\xF7[\xDDHa\x02\xC9V[a\x01\xE5s\xC3uu\xAD\x8E\xFES\x0F\xD8\xA7\x9A\xEB\0\x87\xE5\x87*$\xDA\xBCa\x02\xC9V[a\x02\x02s\x1Cx(\xDA\xDA\xDE\x12\xA8H\xF3k\xE8\xE2\xD3\x14db\xAB\xFFha\x02\xC9V[a\x02\x1Fs\xAB\xA5)K\xBA}65\xC2\xA3\xE4M\x0E\x87\xEA\x7FX\x89\x8F\xB7a\x02\xC9V[a\x02x\x1F\xFET\x8Ea\x02\xC9V[a\x02\xB0s\xC3>>\xC1EV\xA8\xE7\x1B\xE3\t\x7F\xE2\xDC\x8C\x0B\x91\x19\xC8\x97a\x02\xC9V[a\x01\x0FswG(&\x87YS7N\xD3\x08L1\xA4\x83\xF8'\x98\x7F\x14[`@Q`\x01`\x01`\xA0\x1B\x03\x82\x16\x90\x7F\r\x03\x83M\r\x86\xC7\xF5~\x87z\xF4\x0E&\xF1v\xDC1\xBDcu5\xD4\xBA\x15=\x1A\xC9\xDE\x88\xA7\xEA\x90_\x90\xA2PV[aV\x84\x80a\x03\x0C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\0oW_5`\xE0\x1C\x80c*\xECy\xA0\x11a\0MW\x80c*\xECy\xA0\x14a\0\xDEW\x80c\xC4Z\x01U\x14a\0\xF1W\x80c\xE4\x86\x039\x14a\x01\x1EW_\x80\xFD[\x80c\x10\x02\x9D\xAA\x14a\0sW\x80c!W\x02V\x14a\0\x9BW\x80c'$,\x9B\x14a\0\xBBW[_\x80\xFD[a\0\x86a\0\x816`\x04a$bV[a\x01>V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[a\0\xAEa\0\xA96`\x04a$bV[a\x05\x0CV[`@Qa\0\x92\x91\x90a$\xC9V[a\0\xCEa\0\xC96`\x04a$\xDBV[a\x0C\xC6V[`@Qa\0\x92\x94\x93\x92\x91\x90a&\xE9V[a\0\x86a\0\xEC6`\x04a$bV[a\x13-V[a\0\xF9a\x13@V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\0\x92V[a\x011a\x01,6`\x04a$bV[a\x14\x10V[`@Qa\0\x92\x91\x90a'4V[`@Q\x7FV$\xB2[\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7Fl\x9AlJ9(N7\xED\x1C\xF5=3uw\xD1B\x12\xA4\x87\x0F\xB9v\xA46li;\x93\x99\x18\xD5`\x04\x82\x01R`\x01`$\x82\x01R_\x90\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cV$\xB2[\x90`D\x01_`@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xD0W=_\x80>=_\xFD[PPPP`@Q=_\x82>`\x1F=\x90\x81\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x82\x01`@Ra\x02\x15\x91\x90\x81\x01\x90a(\x8AV[\x80` \x01\x90Q\x81\x01\x90a\x02(\x91\x90a(\xC4V[\x90P_s/U\xE8\xB2\r\x0B\x9F\xEF\xA1\x87\xAA}\0\xB6\xCB\xE5c`[\xF5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_s\xFD\xAF\xC9\xD1\x90/N\x0B\x84\xF6_I\xF2D\xB3+1\x01;ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s/U\xE8\xB2\r\x0B\x9F\xEF\xA1\x87\xAA}\0\xB6\xCB\xE5c`[\xF5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cQ\xCA\xD5\xEE\x87s\x90\x08\xD1\x9FX\xAA\xBD\x9E\xD0\xD6\tqVZ\xA8Q\x05`\xABAs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xF6\x98\xDA%`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03*W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03N\x91\x90a(\xDFV[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x85\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16`\x04\x83\x01R`$\x82\x01R`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03\xBAW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03\xDE\x91\x90a(\xC4V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_a\x04\x01\x86a\x05\x0CV[\x80` \x01\x90Q\x81\x01\x90a\x04\x14\x91\x90a(\xF6V[\x90P_s\xFD\xAF\xC9\xD1\x90/N\x0B\x84\xF6_I\xF2D\xB3+1\x01;ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16ca\x08\xC52\x88\x84`@Q` \x01a\x04Y\x91\x90a)\xCFV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x04\xAD\x92\x91\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x82R` \x82\x01R`@\x01\x90V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x04\xC8W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x04\xEC\x91\x90a)\xE1V[\x90P\x83\x80\x15a\x04\xF8WP\x82[\x80\x15a\x05\x01WP\x80[\x97\x96PPPPPPPV[``F`\x01\x81\x90\x03a\x07\xBDWs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x99A\xFD}\xB2\x003\x08\xE7\xEE\x17\xB0D\0\x01\"x\xF1*\xC6\x03a\x05lW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aH/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xB3\xBF\x81qOpG \xDC\xB05\x1F\xF0\xD4.\xCAa\xB0i\xFC\x03a\x05\xC0W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aP\xEFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s0\x10v\xC3n\x03IH\xA7G\xBBa\xBA\xB9\xCD\x03\xF6&r\xE3\x03a\x06\x14W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a6Oa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x02~\x1C\xBF,)\x9C\xBA^\xB8\xA2XI\x10\xD0O\x1A\x8A\xA4\x03\x03a\x06hW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a-/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xBE\xEFZ\xFE\x88\xEFs3~Pp\xAB(U\xD3}\xBFT\x93\xA4\x03a\x06\xBCW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aB\xEFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC6\xB1=^f/\xA0E\x8F\x03\x99[\xCB\x82J\x194\xAA\x89_\x03a\x07\x10W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aA/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xD7\xCB\x8C\xC1\xB5cV\xBB{x\xD0.x^\xAD(\xE2\x15\x86`\x03a\x07dW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a9\xCFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x07\x9C\x86\x8F\x97\xAE\xD8\xE0\xD0?\x11\xE1R\x9C;\x05o\xF2\x1C\xEA\x03a\x07\xB8W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aI\xEFa\x01\xC0\x919\x93\x92PPPV[a\x0C\xB1V[\x80`d\x03a\x0C\xB1Ws\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xBCaY\xFDB\x9B\xE1\x82\x06\xE6\x0B;\xB0\x1Dr\x89\xF9\x05Q\x1B\x03a\x08\x19W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a.\xEFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xE5\xD1\xAA\x85e\xF5\xDB\xFC\x06\xCD\xE2\r\xFDv\xB4\xC7\xC6\xD4;\xD5\x03a\x08mW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aFoa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x9D\x85p\xEF\x9AQ\x9C\xA8\x1D\xAE\xC3R\x12\xF45\xD9\x84;\xA5d\x03a\x08\xC1W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aK\xAFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xD9|1\xE5?\x16\xF4\x95q\\\xE7\x1E\x12\xE1\x1B\x95E\xEE\xDD\x8B\x03a\t\x15W`@Q\x80a\x02@\x01`@R\x80a\x02 \x81R` \x01a0\xAFa\x02 \x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xFF\x1B\xD3\xD5p\xE3TL\x18;\xA7\x7FZM<\xC7B\xC8\xD2\xB3\x03a\tiW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aT\x8Fa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s \x9D&\x9D\xFDf\xB9\xCE\xC7d\xDE~\xB6\xFE\xFC$\xF7[\xDDH\x03a\t\xBDW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aO/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC3uu\xAD\x8E\xFES\x0F\xD8\xA7\x9A\xEB\0\x87\xE5\x87*$\xDA\xBC\x03a\n\x11W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a4\x8Fa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x1Cx(\xDA\xDA\xDE\x12\xA8H\xF3k\xE8\xE2\xD3\x14db\xAB\xFFh\x03a\neW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a?oa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xAB\xA5)K\xBA}65\xC2\xA3\xE4M\x0E\x87\xEA\x7FX\x89\x8F\xB7\x03a\n\xB9W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aMoa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16sn\xB7\xBE\x97*\xEB\xB6\xBE-\x9A\xCFC|\xB4\x12\xC0\xAB\xEE\x91+\x03a\x0B\rW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a2\xCFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC4\xD0\x99i\xAA\xD7\xF2R\xC7]\xD3R\xBB\xBDq\x9E4\xED\x06\xAD\x03a\x0BaW`@Q\x80a\x02@\x01`@R\x80a\x02 \x81R` \x01a=Oa\x02 \x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xA2Z\xF8j]\xBE\xA4^\x9F\xD7\x0C\x18yH\x9Fc\xD0\x81\xADD\x03a\x0B\xB5W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aD\xAFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16sWI,\xB6\xC8\xEE)\x98\xE9\xD8=\xDC\x8Cq>x\x1F\xFET\x8E\x03a\x0C\tW`@Q\x80a\x02\0\x01`@R\x80a\x01\xE0\x81R` \x01aR\xAFa\x01\xE0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC3>>\xC1EV\xA8\xE7\x1B\xE3\t\x7F\xE2\xDC\x8C\x0B\x91\x19\xC8\x97\x03a\x0C]W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a8\x0Fa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16swG(&\x87YS7N\xD3\x08L1\xA4\x83\xF8'\x98\x7F\x14\x03a\x0C\xB1W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a;\x8Fa\x01\xC0\x919\x93\x92PPPV[PP`@\x80Q` \x81\x01\x90\x91R_\x81R\x91\x90PV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R``\x80\x80`\x02\x85\x14a\rdW`@Q\x7F\x9D\x89\x02\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[``a\ro\x88a\x13-V[a\x12\xE9Wa\r|\x88a\x16\x96V[a\r\xE7W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FPool is not a CoW AMM\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[_\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\r\xFE\x16\x81`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0E1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0EU\x91\x90a(\xC4V[\x90P_\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0E\xA1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0E\xC5\x91\x90a(\xC4V[\x90P\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cJ\xDA!\x8B`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0F\x10W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0F4\x91\x90a)\xE1V[\x15\x15_\x03a\x0FnW`@Q\x7F!\x08\x1A\xBF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x10\x81`@Q\x80`\xC0\x01`@R\x80\x8Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8B\x8B`\x01\x81\x81\x10a\x0F\xE3Wa\x0F\xE3a*\0V[\x90P` \x02\x015\x81R` \x01\x8B\x8B_\x81\x81\x10a\x10\x01Wa\x10\x01a*\0V[\x90P` \x02\x015\x81R` \x01\x8Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cm\xBC\x88\x13`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x10VW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x10z\x91\x90a(\xDFV[\x90Ra\x17NV[\x96P\x86`@Q` \x01a\x10\x94\x91\x90a*-V[`@\x80Q\x80\x83\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01\x81R`\x01\x80\x84R\x83\x83\x01\x90\x92R\x94P\x81` \x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x10\xD1W\x90PP\x95P`@Q\x80``\x01`@R\x80\x8Bs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01a\x12;s\x90\x08\xD1\x9FX\xAA\xBD\x9E\xD0\xD6\tqVZ\xA8Q\x05`\xABAs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xF6\x98\xDA%`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x11\x8EW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x11\xB2\x91\x90a(\xDFV[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x8B\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x90 \x90V[`@Q`$\x01a\x12M\x91\x81R` \x01\x90V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xF1O\xCB\xC8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90R\x86Q\x87\x90_\x90a\x12\xD7Wa\x12\xD7a*\0V[` \x02` \x01\x01\x81\x90RPPPa\x12\xFFV[a\x12\xF4\x88\x88\x88a\x1A\xD6V[\x92\x97P\x90\x95P\x93P\x90P[\x87\x81`@Q` \x01a\x13\x12\x92\x91\x90a*=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x14\xAA\x91\x90a(\xC4V[\x81_\x81Q\x81\x10a\x14\xBCWa\x14\xBCa*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x15?W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x15c\x91\x90a(\xC4V[\x81`\x01\x81Q\x81\x10a\x15vWa\x15va*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP\x91\x90PV[_a\x15\xBF\x83a!_V[P\x90P\x80_\x81Q\x81\x10a\x15\xD4Wa\x15\xD4a*\0V[` \x02` \x01\x01Q\x82_\x81Q\x81\x10a\x15\xEEWa\x15\xEEa*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP\x80`\x01\x81Q\x81\x10a\x16;Wa\x16;a*\0V[` \x02` \x01\x01Q\x82`\x01\x81Q\x81\x10a\x16VWa\x16Va*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPPP\x91\x90PV[_\x80a\x16\xA0a\x13@V[`@Q\x7Ffn\x1B9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`\x04\x83\x01R\x91\x90\x91\x16\x90cfn\x1B9\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x17\x0CW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x170\x91\x90a(\xC4V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x92\x91PPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R` \x82\x01Q\x82Q`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16`\x04\x82\x01R_\x92\x83\x92\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x18\"W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x18F\x91\x90a(\xDFV[`@\x85\x81\x01Q\x86Q\x91Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16`\x04\x82\x01R\x91\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x18\xB7W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x18\xDB\x91\x90a(\xDFV[\x91P\x91P_\x80_\x80_\x88`\x80\x01Q\x87a\x18\xF4\x91\x90a*\xAEV[\x90P_\x89``\x01Q\x87a\x19\x07\x91\x90a*\xAEV[\x90P\x81\x81\x10\x15a\x19mW\x89` \x01Q\x95P\x89`@\x01Q\x94Pa\x199\x81\x8B`\x80\x01Q`\x02a\x194\x91\x90a*\xAEV[a\"{V[a\x19D`\x02\x8Aa*\xF2V[a\x19N\x91\x90a+\x05V[\x93Pa\x19f\x84\x88a\x19_\x82\x8Ca+\x05V[`\x01a\"\xCBV[\x92Pa\x19\xB9V[\x89`@\x01Q\x95P\x89` \x01Q\x94Pa\x19\x90\x82\x8B``\x01Q`\x02a\x194\x91\x90a*\xAEV[a\x19\x9B`\x02\x89a*\xF2V[a\x19\xA5\x91\x90a+\x05V[\x93Pa\x19\xB6\x84\x89a\x19_\x82\x8Ba+\x05V[\x92P[`@Q\x80a\x01\x80\x01`@R\x80\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x85\x81R` \x01\x84\x81R` \x01a\x01,Ba\x1A3\x91\x90a+\x18V[c\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8B`\xA0\x01Q\x81R` \x01_\x81R` \x01\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x81R` \x01`\x01\x15\x15\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81RP\x98PPPPPPPPP\x91\x90PV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R``\x80``a\x1BD\x87a\x01>V[a\x1BzW`@Q\x7F\xEF\xC8i\xB4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80a\x1B\x85\x89a!_V[\x91P\x91P_\x81`@\x01Q\x80` \x01\x90Q\x81\x01\x90a\x1B\xA2\x91\x90a+=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x1D\x07\x91\x90a(\xDFV[\x90P\x80\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x89`@Q` \x01a\x1D<\x91\x90a*-V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R_``\x84\x01\x81\x81R`\x80\x85\x01\x84R\x84R` \x80\x85\x01\x8A\x90R\x83Q\x80\x82\x01\x85R\x91\x82R\x84\x84\x01\x91\x90\x91R\x91Q\x90\x92a\x1D\xA0\x92\x90\x91\x01a+\xF4V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x90\x82\x90Ra\x1D\xDE\x94\x93\x92\x91`$\x01a,\x9DV[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x81R` \x80\x83\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F_\xD7\xE9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x81Q`\x01\x80\x82R\x81\x84\x01\x90\x93R\x92\x97P\x82\x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x1EhW\x90PP`@\x80Q``\x81\x01\x82R\x85Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R_` \x82\x01R\x91\x98P\x81\x01\x8Ca\x1FU\x8B\x85\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x91\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x90 \x90V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16`$\x83\x01R`D\x82\x01R`d\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F0\xF7<\x99\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90R\x87Q\x88\x90_\x90a \x07Wa \x07a*\0V[` \x90\x81\x02\x91\x90\x91\x01\x01R`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R\x90\x81` \x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a 'W\x90PP\x95P`@Q\x80``\x01`@R\x80\x84_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01\x8C_\x80\x1B`@Q`$\x01a \xBD\x92\x91\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x82R` \x82\x01R`@\x01\x90V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F0\xF7<\x99\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90R\x86Q\x87\x90_\x90a!GWa!Ga*\0V[` \x02` \x01\x01\x81\x90RPPPPP\x93P\x93P\x93P\x93V[`@\x80Q``\x81\x81\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x82\x90Ra!\x82\x83a\x05\x0CV[\x80` \x01\x90Q\x81\x01\x90a!\x95\x91\x90a(\xF6V[\x90P_\x81`@\x01Q\x80` \x01\x90Q\x81\x01\x90a!\xB0\x91\x90a+V[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[` \x81R_a\"\xC2` \x83\x01\x84a$}V[_\x80_`@\x84\x86\x03\x12\x15a$\xEDW_\x80\xFD[\x835a$\xF8\x81a$>V[\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a%\x14W_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a%'W_\x80\xFD[\x815\x81\x81\x11\x15a%5W_\x80\xFD[\x87` \x82`\x05\x1B\x85\x01\x01\x11\x15a%IW_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82R` \x81\x01Qa%\x9D` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x81\x01Qa%\xC5`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x81\x01Q``\x83\x01R`\x80\x81\x01Q`\x80\x83\x01R`\xA0\x81\x01Qa%\xF1`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x81\x01Q`\xC0\x83\x01R`\xE0\x81\x01Q`\xE0\x83\x01Ra\x01\0\x80\x82\x01Q\x81\x84\x01RPa\x01 \x80\x82\x01Qa&&\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x81\x81\x01Q\x90\x83\x01Ra\x01`\x90\x81\x01Q\x91\x01RV[_\x82\x82Q\x80\x85R` \x80\x86\x01\x95P\x80\x82`\x05\x1B\x84\x01\x01\x81\x86\x01_[\x84\x81\x10\x15a&\xDCW\x85\x83\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01\x89R\x81Q\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84R\x84\x81\x01Q\x85\x85\x01R`@\x90\x81\x01Q``\x91\x85\x01\x82\x90R\x90a&\xC8\x81\x86\x01\x83a$}V[\x9A\x86\x01\x9A\x94PPP\x90\x83\x01\x90`\x01\x01a&ZV[P\x90\x97\x96PPPPPPPV[_a\x01\xE0a&\xF7\x83\x88a%\\V[\x80a\x01\x80\x84\x01Ra'\n\x81\x84\x01\x87a&?V[\x90P\x82\x81\x03a\x01\xA0\x84\x01Ra'\x1F\x81\x86a&?V[\x90P\x82\x81\x03a\x01\xC0\x84\x01Ra\x05\x01\x81\x85a$}V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R_\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a'\x81W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83R\x92\x84\x01\x92\x91\x84\x01\x91`\x01\x01a'OV[P\x90\x96\x95PPPPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\xC0\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a'\xDDWa'\xDDa'\x8DV[`@R\x90V[_\x82`\x1F\x83\x01\x12a'\xF2W_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a(\rWa(\ra'\x8DV[`@Q`\x1F\x83\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x81\x16`?\x01\x16\x81\x01\x90\x82\x82\x11\x81\x83\x10\x17\x15a(SWa(Sa'\x8DV[\x81`@R\x83\x81R\x86` \x85\x88\x01\x01\x11\x15a(kW_\x80\xFD[\x83` \x87\x01` \x83\x01^_` \x85\x83\x01\x01R\x80\x94PPPPP\x92\x91PPV[_` \x82\x84\x03\x12\x15a(\x9AW_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a(\xB0W_\x80\xFD[a(\xBC\x84\x82\x85\x01a'\xE3V[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a(\xD4W_\x80\xFD[\x81Qa$\x0B\x81a$>V[_` \x82\x84\x03\x12\x15a(\xEFW_\x80\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a)\x06W_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a)\x1DW_\x80\xFD[\x90\x83\x01\x90``\x82\x86\x03\x12\x15a)0W_\x80\xFD[`@Q``\x81\x01\x81\x81\x10\x83\x82\x11\x17\x15a)KWa)Ka'\x8DV[`@R\x82Qa)Y\x81a$>V[\x81R` \x83\x81\x01Q\x90\x82\x01R`@\x83\x01Q\x82\x81\x11\x15a)vW_\x80\xFD[a)\x82\x87\x82\x86\x01a'\xE3V[`@\x83\x01RP\x95\x94PPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81Q\x16\x82R` \x81\x01Q` \x83\x01R_`@\x82\x01Q```@\x85\x01Ra(\xBC``\x85\x01\x82a$}V[` \x81R_a\"\xC2` \x83\x01\x84a)\x91V[_` \x82\x84\x03\x12\x15a)\xF1W_\x80\xFD[\x81Q\x80\x15\x15\x81\x14a$\x0BW_\x80\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[a\x01\x80\x81\x01a\"\xC5\x82\x84a%\\V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x83``\x1B\x16\x81R_\x82Q\x80` \x85\x01`\x14\x85\x01^_\x92\x01`\x14\x01\x91\x82RP\x92\x91PPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\"\xC5Wa\"\xC5a*\x81V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_\x82a+\0Wa+\0a*\xC5V[P\x04\x90V[\x81\x81\x03\x81\x81\x11\x15a\"\xC5Wa\"\xC5a*\x81V[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x01\x90\x80\x82\x11\x15a+5Wa+5a*\x81V[P\x92\x91PPV[_` \x82\x84\x03\x12\x15a+LW_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a+cW_\x80\xFD[\x90\x83\x01\x90`\xC0\x82\x86\x03\x12\x15a+vW_\x80\xFD[a+~a'\xBAV[\x82Qa+\x89\x81a$>V[\x81R` \x83\x01Qa+\x99\x81a$>V[` \x82\x01R`@\x83\x81\x01Q\x90\x82\x01R``\x83\x01Qa+\xB6\x81a$>V[``\x82\x01R`\x80\x83\x01Q\x82\x81\x11\x15a+\xCCW_\x80\xFD[a+\xD8\x87\x82\x86\x01a'\xE3V[`\x80\x83\x01RP`\xA0\x83\x01Q`\xA0\x82\x01R\x80\x93PPPP\x92\x91PPV[` \x80\x82R\x82Q``\x83\x83\x01R\x80Q`\x80\x84\x01\x81\x90R_\x92\x91\x82\x01\x90\x83\x90`\xA0\x86\x01\x90[\x80\x83\x10\x15a,8W\x83Q\x82R\x92\x84\x01\x92`\x01\x92\x90\x92\x01\x91\x90\x84\x01\x90a,\x18V[P\x83\x87\x01Q\x93P\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x92P\x82\x86\x82\x03\x01`@\x87\x01Ra,v\x81\x85a)\x91V[\x93PPP`@\x85\x01Q\x81\x85\x84\x03\x01``\x86\x01Ra,\x93\x83\x82a$}V[\x96\x95PPPPPPV[\x84\x81R\x83` \x82\x01R`\x80`@\x82\x01R_a,\xBB`\x80\x83\x01\x85a$}V[\x82\x81\x03``\x84\x01Ra\x05\x01\x81\x85a$}V[\x80\x82\x01\x80\x82\x11\x15a\"\xC5Wa\"\xC5a*\x81V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[_`\xFF\x83\x16\x80a-\x1FWa-\x1Fa*\xC5V[\x80`\xFF\x84\x16\x06\x91PP\x92\x91PPV\xFE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\xC5\xA0\xE7V\xAC\x88\xC1\xD3\xA4\xC4\x19\0\xD9w\xFE\x93\xC2\xD3O\xC9Z\0\xCA>\x84\xEBLkP\xFA\xF9I\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\xA8\x14\xF6N~\x04\xA3\xB9I\xA5qx\x9E\x19lZ\x91\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0j\x02<\xCD\x1F\xF6\xF2\x04\\3\tv\x8E\xAD\x9Eh\xF9x\xF6\xE1\0\0\0\0\0\0\0\0\0\0\0\0\xE9\x1D\x15>\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\n\xFF\xD9\xFD\xEB\x8E\x08\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xA9\x9F\xD9\x95\x0B]]\xCE\xEA\xF4\x93\x9E\"\x1D\xCA\x8C\xA9\xB98\xAB\0\x01\0\0\0\0\0\0\0\0\0%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Qx\xA7)\xEE0\x08\xC7\xD4\x882\xD0\"g\xB7._4\xAD\xA8\xF5T\xA6s\x1A6\x8F\x01Y\x0E\xD7\x1B4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xCBDN\x90\xD8\x19\x84\x15&lj'$\xB7\x90\x0F\xB1/\xC5n\0\0\0\0\0\0\0\0\0\0\0\0\xE9\x1D\x15>\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V\x19zT%\xC0\xC8\0\0\0\0\0\0\0\0\0\0\0\0\xBD\x91\xA7-\xC3\xD9\xB5\xD9\xB1n\xE8c\x8D\xA1\xFCe1\x1B\xD9\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\xABp\xBC\xB2`\x07=\x03m\x16` \x1E\x9DT\x05\xF5\x82\x9Bz\0\0\0\0\0\0\0\0\0\0\0\0g\x8D\xF3A_\xC3\x19G\xDAC$\xECc!(t\xBEZ\x82\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01Q\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q.1\x98\x1E4\x96\ti\xEBT\x9F^\x82l\xF7\x7Fe^r\xB06\x03\xADWJy\xFD\x01_M\xE4\xDE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\xAF Gv\xC7$[\xF4\x14|&\x12\xBFnYr\xEEH7\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\n\x16\xC9ZM.<\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0\xCE\x9E\x05\xC2\xAE\xE5\xF2/\x99A\xC4\xCD\x1F\x1A\x1D\x13\x19K\x10\x97yB-Z\xD9\xA9\x80\x15{\xD0\xF1d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xBC*\xCF^\x82\x1C\\\x9F\x86g\xA3k\xB1\x13\x1D\xAD&\xEDd\xF9\0\x02\0\0\0\0\0\0\0\0\0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\xA2\x02\x9F\xBBTYx\xD0Sx\xB6\xDF\x19\xE3uO\xE5\xED-\x0B\xA1\xE0Q\x02u\x03\x93Cr\xF7\xBE\xB2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x9CX\xBA\xCC3\x1C\x9A\xA8q\xAF\xD8\x02\xDBcy\xA9\x8E\x80\xCE\xDB\0\0\0\0\0\0\0\0\0\0\0\0\x17q'b,J\0\xF3\xD4\t\xB7Uq\xE1,\xB3\xC8\x97=<\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0R\xBA\x9E\xFC8D\x1A\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 !\xD4\xC7\x92\xEA~8\xE0\xD0\x81\x9C \x11\xA2\xB1\xCBrR\xBD\x99\0\x02\0\0\0\0\0\0\0\0\0\x1E\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\xCAD\xB6\xA3\x04\xBA\xA1m\x11\xB6\xDB\x07\x06l\x12v\xB1'>\xE3\xF9E\x90\xBB\xD02\x01\xA6\x18\x82\xAF\x9A\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xA0\xB8i\x91\xC6!\x8B6\xC1\xD1\x9DJ.\x9E\xB0\xCE6\x06\xEBH\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\xFE\xCD\x84a\x8Cz\x16\x8E\x88\xB9\xCB}\x1C\r\xB1(\xAF\x1E\xFE\n\x08\xBB\xB1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\xAF Gv\xC7$[\xF4\x14|&\x12\xBFnYr\xEEH7\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\n\x17'?\xC1Kd\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xBC*\xCF^\x82\x1C\\\x9F\x86g\xA3k\xB1\x13\x1D\xAD&\xEDd\xF9\0\x02\0\0\0\0\0\0\0\0\0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\x80\xBAS?\x01N\xF4#\x8A\xB7\xAD <\n\xEA\xCB\xF3\nq\xC04a@\xDBw\xC4:\xE3\x12\x1A\xFA\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xAE\xA4j`6\x8A{\xD0`\xEE\xC7\xDF\x8C\xBAC\xB7\xEFA\xAD\x85\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'\x10\0\0\0\0\0\0\0\0\0\0\0\0\xE0\x89\x04\x90'\xB9\\'E\xD1\xA9T\xBC\x1D$SR\xD8\x84\xE9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x8D\xB8\x87\x0C\xA4\xB8\xAC\x18\x8CM\x1A\x01O4\xA3\x81\xAE'\xE1\xC2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q \x9C\x17\xD9\xEB\xE3\xACsRy_\x7F\x8B=\x14\xD2S\xD9$0\x83\x1D;,9e\xF9\xA5x\xDAv\x18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xE9\x1D\x15>\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8A\xA3\xA5(\x15&/X\0\0\0\0\0\0\0\0\0\0\0\0\xBD\x91\xA7-\xC3\xD9\xB5\xD9\xB1n\xE8c\x8D\xA1\xFCe1\x1B\xD9\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\0d\xAC\0\x7F\xF6e\xCF\x8D\r:\xF5\xE0\xAD\x1C&\xA3\xF8S\xEA\0\0\0\0\0\0\0\0\0\0\0\0\xA7g\xF7E3\x1D&|wQ)}\x98+\x05\x0C\x93\x98V'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01Q\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\x05Ad`\xDE\xB7mW\xAF`\x1B\xE1~w{\x93Y-\x8DMJ@\x96\xC5xv\xA9\x1C\x84\xF4\x18\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x9CX\xBA\xCC3\x1C\x9A\xA8q\xAF\xD8\x02\xDBcy\xA9\x8E\x80\xCE\xDB\0\0\0\0\0\0\0\0\0\0\0\0\xCE\x11\xE1B%WYE\xB8\xE6\xDC\rO-\xD4\xC5p\xF7\x9D\x9F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0#\x86\xF2o\xC1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x964\xCAdtt\xB6\xB7\x8D3\x823\x1Aw\xCD\0\xA8\xA9@\xDA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\x93%B)O\xF2p\xA8\xBB\xDB\xE1\xFB\x92\x1D\xE3\xD0\x9C\x97I\xDC5bsa\xFC\x17\xC4K\x9B\x02k\x81\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x83\x90\xA1\xDA\x07\xE3v\xEFz\xDDK\xE8Y\xBAt\xFB\x83\xAA\x02\xD5\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\x82d\xEC\xF9\x86\xCA\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08q\x01\xD8\x17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\xD1\xE8h\xD1 \xE3&\xE5X\x1C\xAA9\x85+\xB0\xDA\x924\xA5\x11\xEDv\xE6\xF7\xA9\xDC\xCE\xB0\xD5\xF1T\xC7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\xAF Gv\xC7$[\xF4\x14|&\x12\xBFnYr\xEEH7\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\t\x8EF\x99T%\xCA\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xBC*\xCF^\x82\x1C\\\x9F\x86g\xA3k\xB1\x13\x1D\xAD&\xEDd\xF9\0\x02\0\0\0\0\0\0\0\0\0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\xF0\xE8\xECQ+%\x07\xDA\xE9\x91u\xA0\xA4y-\x8AS\xE0\x86?\xBB^sZ\\\x992\x95\xBB\xD1\x7FH\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\x9CX\xBA\xCC3\x1C\x9A\xA8q\xAF\xD8\x02\xDBcy\xA9\x8E\x80\xCE\xDB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\tO\x8D\x91h\xE2q\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 F\x83\xE3@\xA8\x04\x92a\x05}Z\xB1\xB2\x9C\x8D\x84\x0Eui^\0\x02\0\0\0\0\0\0\0\0\0Z\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\xD0\x03\x83\x88)\x11_]\x9F\xF3\xEDi\xC8\xD2\xB4\xB2n\x10\xEB\x1Ay3\x12\x06\xC2\x8F\xBBG49\n^\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x80\x85\x07\x12\x1B\x80\xC0#\x88\xFA\xD1G&H.\x06\x1B\x8D\xA8'\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[a\0\xAEa\0\xA96`\x04a$bV[a\x05\x0CV[`@Qa\0\x92\x91\x90a$\xC9V[a\0\xCEa\0\xC96`\x04a$\xDBV[a\x0C\xC6V[`@Qa\0\x92\x94\x93\x92\x91\x90a&\xE9V[a\0\x86a\0\xEC6`\x04a$bV[a\x13-V[a\0\xF9a\x13@V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\0\x92V[a\x011a\x01,6`\x04a$bV[a\x14\x10V[`@Qa\0\x92\x91\x90a'4V[`@Q\x7FV$\xB2[\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7Fl\x9AlJ9(N7\xED\x1C\xF5=3uw\xD1B\x12\xA4\x87\x0F\xB9v\xA46li;\x93\x99\x18\xD5`\x04\x82\x01R`\x01`$\x82\x01R_\x90\x81\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90cV$\xB2[\x90`D\x01_`@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xD0W=_\x80>=_\xFD[PPPP`@Q=_\x82>`\x1F=\x90\x81\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x82\x01`@Ra\x02\x15\x91\x90\x81\x01\x90a(\x8AV[\x80` \x01\x90Q\x81\x01\x90a\x02(\x91\x90a(\xC4V[\x90P_s/U\xE8\xB2\r\x0B\x9F\xEF\xA1\x87\xAA}\0\xB6\xCB\xE5c`[\xF5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_s\xFD\xAF\xC9\xD1\x90/N\x0B\x84\xF6_I\xF2D\xB3+1\x01;ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s/U\xE8\xB2\r\x0B\x9F\xEF\xA1\x87\xAA}\0\xB6\xCB\xE5c`[\xF5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cQ\xCA\xD5\xEE\x87s\x90\x08\xD1\x9FX\xAA\xBD\x9E\xD0\xD6\tqVZ\xA8Q\x05`\xABAs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xF6\x98\xDA%`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03*W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03N\x91\x90a(\xDFV[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x85\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16`\x04\x83\x01R`$\x82\x01R`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03\xBAW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03\xDE\x91\x90a(\xC4V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x90P_a\x04\x01\x86a\x05\x0CV[\x80` \x01\x90Q\x81\x01\x90a\x04\x14\x91\x90a(\xF6V[\x90P_s\xFD\xAF\xC9\xD1\x90/N\x0B\x84\xF6_I\xF2D\xB3+1\x01;ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16ca\x08\xC52\x88\x84`@Q` \x01a\x04Y\x91\x90a)\xCFV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x04\xAD\x92\x91\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x82R` \x82\x01R`@\x01\x90V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x04\xC8W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x04\xEC\x91\x90a)\xE1V[\x90P\x83\x80\x15a\x04\xF8WP\x82[\x80\x15a\x05\x01WP\x80[\x97\x96PPPPPPPV[``F`\x01\x81\x90\x03a\x07\xBDWs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x99A\xFD}\xB2\x003\x08\xE7\xEE\x17\xB0D\0\x01\"x\xF1*\xC6\x03a\x05lW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aH/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xB3\xBF\x81qOpG \xDC\xB05\x1F\xF0\xD4.\xCAa\xB0i\xFC\x03a\x05\xC0W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aP\xEFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s0\x10v\xC3n\x03IH\xA7G\xBBa\xBA\xB9\xCD\x03\xF6&r\xE3\x03a\x06\x14W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a6Oa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x02~\x1C\xBF,)\x9C\xBA^\xB8\xA2XI\x10\xD0O\x1A\x8A\xA4\x03\x03a\x06hW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a-/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xBE\xEFZ\xFE\x88\xEFs3~Pp\xAB(U\xD3}\xBFT\x93\xA4\x03a\x06\xBCW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aB\xEFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC6\xB1=^f/\xA0E\x8F\x03\x99[\xCB\x82J\x194\xAA\x89_\x03a\x07\x10W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aA/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xD7\xCB\x8C\xC1\xB5cV\xBB{x\xD0.x^\xAD(\xE2\x15\x86`\x03a\x07dW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a9\xCFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x07\x9C\x86\x8F\x97\xAE\xD8\xE0\xD0?\x11\xE1R\x9C;\x05o\xF2\x1C\xEA\x03a\x07\xB8W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aI\xEFa\x01\xC0\x919\x93\x92PPPV[a\x0C\xB1V[\x80`d\x03a\x0C\xB1Ws\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xBCaY\xFDB\x9B\xE1\x82\x06\xE6\x0B;\xB0\x1Dr\x89\xF9\x05Q\x1B\x03a\x08\x19W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a.\xEFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xE5\xD1\xAA\x85e\xF5\xDB\xFC\x06\xCD\xE2\r\xFDv\xB4\xC7\xC6\xD4;\xD5\x03a\x08mW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aFoa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x9D\x85p\xEF\x9AQ\x9C\xA8\x1D\xAE\xC3R\x12\xF45\xD9\x84;\xA5d\x03a\x08\xC1W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aK\xAFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xD9|1\xE5?\x16\xF4\x95q\\\xE7\x1E\x12\xE1\x1B\x95E\xEE\xDD\x8B\x03a\t\x15W`@Q\x80a\x02@\x01`@R\x80a\x02 \x81R` \x01a0\xAFa\x02 \x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xFF\x1B\xD3\xD5p\xE3TL\x18;\xA7\x7FZM<\xC7B\xC8\xD2\xB3\x03a\tiW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aT\x8Fa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s \x9D&\x9D\xFDf\xB9\xCE\xC7d\xDE~\xB6\xFE\xFC$\xF7[\xDDH\x03a\t\xBDW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aO/a\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC3uu\xAD\x8E\xFES\x0F\xD8\xA7\x9A\xEB\0\x87\xE5\x87*$\xDA\xBC\x03a\n\x11W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a4\x8Fa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\x1Cx(\xDA\xDA\xDE\x12\xA8H\xF3k\xE8\xE2\xD3\x14db\xAB\xFFh\x03a\neW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a?oa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xAB\xA5)K\xBA}65\xC2\xA3\xE4M\x0E\x87\xEA\x7FX\x89\x8F\xB7\x03a\n\xB9W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aMoa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16sn\xB7\xBE\x97*\xEB\xB6\xBE-\x9A\xCFC|\xB4\x12\xC0\xAB\xEE\x91+\x03a\x0B\rW`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a2\xCFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC4\xD0\x99i\xAA\xD7\xF2R\xC7]\xD3R\xBB\xBDq\x9E4\xED\x06\xAD\x03a\x0BaW`@Q\x80a\x02@\x01`@R\x80a\x02 \x81R` \x01a=Oa\x02 \x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xA2Z\xF8j]\xBE\xA4^\x9F\xD7\x0C\x18yH\x9Fc\xD0\x81\xADD\x03a\x0B\xB5W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01aD\xAFa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16sWI,\xB6\xC8\xEE)\x98\xE9\xD8=\xDC\x8Cq>x\x1F\xFET\x8E\x03a\x0C\tW`@Q\x80a\x02\0\x01`@R\x80a\x01\xE0\x81R` \x01aR\xAFa\x01\xE0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16s\xC3>>\xC1EV\xA8\xE7\x1B\xE3\t\x7F\xE2\xDC\x8C\x0B\x91\x19\xC8\x97\x03a\x0C]W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a8\x0Fa\x01\xC0\x919\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16swG(&\x87YS7N\xD3\x08L1\xA4\x83\xF8'\x98\x7F\x14\x03a\x0C\xB1W`@Q\x80a\x01\xE0\x01`@R\x80a\x01\xC0\x81R` \x01a;\x8Fa\x01\xC0\x919\x93\x92PPPV[PP`@\x80Q` \x81\x01\x90\x91R_\x81R\x91\x90PV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R``\x80\x80`\x02\x85\x14a\rdW`@Q\x7F\x9D\x89\x02\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[``a\ro\x88a\x13-V[a\x12\xE9Wa\r|\x88a\x16\x96V[a\r\xE7W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FPool is not a CoW AMM\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[_\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\r\xFE\x16\x81`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0E1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0EU\x91\x90a(\xC4V[\x90P_\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0E\xA1W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0E\xC5\x91\x90a(\xC4V[\x90P\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cJ\xDA!\x8B`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0F\x10W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0F4\x91\x90a)\xE1V[\x15\x15_\x03a\x0FnW`@Q\x7F!\x08\x1A\xBF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x10\x81`@Q\x80`\xC0\x01`@R\x80\x8Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8B\x8B`\x01\x81\x81\x10a\x0F\xE3Wa\x0F\xE3a*\0V[\x90P` \x02\x015\x81R` \x01\x8B\x8B_\x81\x81\x10a\x10\x01Wa\x10\x01a*\0V[\x90P` \x02\x015\x81R` \x01\x8Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cm\xBC\x88\x13`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x10VW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x10z\x91\x90a(\xDFV[\x90Ra\x17NV[\x96P\x86`@Q` \x01a\x10\x94\x91\x90a*-V[`@\x80Q\x80\x83\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01\x81R`\x01\x80\x84R\x83\x83\x01\x90\x92R\x94P\x81` \x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x10\xD1W\x90PP\x95P`@Q\x80``\x01`@R\x80\x8Bs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01a\x12;s\x90\x08\xD1\x9FX\xAA\xBD\x9E\xD0\xD6\tqVZ\xA8Q\x05`\xABAs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xF6\x98\xDA%`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x11\x8EW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x11\xB2\x91\x90a(\xDFV[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x8B\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x90 \x90V[`@Q`$\x01a\x12M\x91\x81R` \x01\x90V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xF1O\xCB\xC8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90R\x86Q\x87\x90_\x90a\x12\xD7Wa\x12\xD7a*\0V[` \x02` \x01\x01\x81\x90RPPPa\x12\xFFV[a\x12\xF4\x88\x88\x88a\x1A\xD6V[\x92\x97P\x90\x95P\x93P\x90P[\x87\x81`@Q` \x01a\x13\x12\x92\x91\x90a*=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x14\xAA\x91\x90a(\xC4V[\x81_\x81Q\x81\x10a\x14\xBCWa\x14\xBCa*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x15?W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x15c\x91\x90a(\xC4V[\x81`\x01\x81Q\x81\x10a\x15vWa\x15va*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP\x91\x90PV[_a\x15\xBF\x83a!_V[P\x90P\x80_\x81Q\x81\x10a\x15\xD4Wa\x15\xD4a*\0V[` \x02` \x01\x01Q\x82_\x81Q\x81\x10a\x15\xEEWa\x15\xEEa*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP\x80`\x01\x81Q\x81\x10a\x16;Wa\x16;a*\0V[` \x02` \x01\x01Q\x82`\x01\x81Q\x81\x10a\x16VWa\x16Va*\0V[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPPP\x91\x90PV[_\x80a\x16\xA0a\x13@V[`@Q\x7Ffn\x1B9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`\x04\x83\x01R\x91\x90\x91\x16\x90cfn\x1B9\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x17\x0CW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x170\x91\x90a(\xC4V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x92\x91PPV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R` \x82\x01Q\x82Q`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16`\x04\x82\x01R_\x92\x83\x92\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x18\"W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x18F\x91\x90a(\xDFV[`@\x85\x81\x01Q\x86Q\x91Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16`\x04\x82\x01R\x91\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x18\xB7W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x18\xDB\x91\x90a(\xDFV[\x91P\x91P_\x80_\x80_\x88`\x80\x01Q\x87a\x18\xF4\x91\x90a*\xAEV[\x90P_\x89``\x01Q\x87a\x19\x07\x91\x90a*\xAEV[\x90P\x81\x81\x10\x15a\x19mW\x89` \x01Q\x95P\x89`@\x01Q\x94Pa\x199\x81\x8B`\x80\x01Q`\x02a\x194\x91\x90a*\xAEV[a\"{V[a\x19D`\x02\x8Aa*\xF2V[a\x19N\x91\x90a+\x05V[\x93Pa\x19f\x84\x88a\x19_\x82\x8Ca+\x05V[`\x01a\"\xCBV[\x92Pa\x19\xB9V[\x89`@\x01Q\x95P\x89` \x01Q\x94Pa\x19\x90\x82\x8B``\x01Q`\x02a\x194\x91\x90a*\xAEV[a\x19\x9B`\x02\x89a*\xF2V[a\x19\xA5\x91\x90a+\x05V[\x93Pa\x19\xB6\x84\x89a\x19_\x82\x8Ba+\x05V[\x92P[`@Q\x80a\x01\x80\x01`@R\x80\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x85\x81R` \x01\x84\x81R` \x01a\x01,Ba\x1A3\x91\x90a+\x18V[c\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8B`\xA0\x01Q\x81R` \x01_\x81R` \x01\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x81R` \x01`\x01\x15\x15\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81RP\x98PPPPPPPPP\x91\x90PV[`@\x80Qa\x01\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R``\x80``a\x1BD\x87a\x01>V[a\x1BzW`@Q\x7F\xEF\xC8i\xB4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80a\x1B\x85\x89a!_V[\x91P\x91P_\x81`@\x01Q\x80` \x01\x90Q\x81\x01\x90a\x1B\xA2\x91\x90a+=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x1D\x07\x91\x90a(\xDFV[\x90P\x80\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x89`@Q` \x01a\x1D<\x91\x90a*-V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R_``\x84\x01\x81\x81R`\x80\x85\x01\x84R\x84R` \x80\x85\x01\x8A\x90R\x83Q\x80\x82\x01\x85R\x91\x82R\x84\x84\x01\x91\x90\x91R\x91Q\x90\x92a\x1D\xA0\x92\x90\x91\x01a+\xF4V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x90\x82\x90Ra\x1D\xDE\x94\x93\x92\x91`$\x01a,\x9DV[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x81R` \x80\x83\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F_\xD7\xE9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x81Q`\x01\x80\x82R\x81\x84\x01\x90\x93R\x92\x97P\x82\x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x1EhW\x90PP`@\x80Q``\x81\x01\x82R\x85Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R_` \x82\x01R\x91\x98P\x81\x01\x8Ca\x1FU\x8B\x85\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x91\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x90 \x90V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16`$\x83\x01R`D\x82\x01R`d\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F0\xF7<\x99\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90R\x87Q\x88\x90_\x90a \x07Wa \x07a*\0V[` \x90\x81\x02\x91\x90\x91\x01\x01R`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R\x90\x81` \x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a 'W\x90PP\x95P`@Q\x80``\x01`@R\x80\x84_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01\x8C_\x80\x1B`@Q`$\x01a \xBD\x92\x91\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x82R` \x82\x01R`@\x01\x90V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F0\xF7<\x99\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90R\x86Q\x87\x90_\x90a!GWa!Ga*\0V[` \x02` \x01\x01\x81\x90RPPPPP\x93P\x93P\x93P\x93V[`@\x80Q``\x81\x81\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x82\x90Ra!\x82\x83a\x05\x0CV[\x80` \x01\x90Q\x81\x01\x90a!\x95\x91\x90a(\xF6V[\x90P_\x81`@\x01Q\x80` \x01\x90Q\x81\x01\x90a!\xB0\x91\x90a+V[_\x81Q\x80\x84R\x80` \x84\x01` \x86\x01^_` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[` \x81R_a\"\xC2` \x83\x01\x84a$}V[_\x80_`@\x84\x86\x03\x12\x15a$\xEDW_\x80\xFD[\x835a$\xF8\x81a$>V[\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a%\x14W_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a%'W_\x80\xFD[\x815\x81\x81\x11\x15a%5W_\x80\xFD[\x87` \x82`\x05\x1B\x85\x01\x01\x11\x15a%IW_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82R` \x81\x01Qa%\x9D` \x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x81\x01Qa%\xC5`@\x84\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x81\x01Q``\x83\x01R`\x80\x81\x01Q`\x80\x83\x01R`\xA0\x81\x01Qa%\xF1`\xA0\x84\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x81\x01Q`\xC0\x83\x01R`\xE0\x81\x01Q`\xE0\x83\x01Ra\x01\0\x80\x82\x01Q\x81\x84\x01RPa\x01 \x80\x82\x01Qa&&\x82\x85\x01\x82\x15\x15\x90RV[PPa\x01@\x81\x81\x01Q\x90\x83\x01Ra\x01`\x90\x81\x01Q\x91\x01RV[_\x82\x82Q\x80\x85R` \x80\x86\x01\x95P\x80\x82`\x05\x1B\x84\x01\x01\x81\x86\x01_[\x84\x81\x10\x15a&\xDCW\x85\x83\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01\x89R\x81Q\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84R\x84\x81\x01Q\x85\x85\x01R`@\x90\x81\x01Q``\x91\x85\x01\x82\x90R\x90a&\xC8\x81\x86\x01\x83a$}V[\x9A\x86\x01\x9A\x94PPP\x90\x83\x01\x90`\x01\x01a&ZV[P\x90\x97\x96PPPPPPPV[_a\x01\xE0a&\xF7\x83\x88a%\\V[\x80a\x01\x80\x84\x01Ra'\n\x81\x84\x01\x87a&?V[\x90P\x82\x81\x03a\x01\xA0\x84\x01Ra'\x1F\x81\x86a&?V[\x90P\x82\x81\x03a\x01\xC0\x84\x01Ra\x05\x01\x81\x85a$}V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R_\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a'\x81W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83R\x92\x84\x01\x92\x91\x84\x01\x91`\x01\x01a'OV[P\x90\x96\x95PPPPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@Q`\xC0\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a'\xDDWa'\xDDa'\x8DV[`@R\x90V[_\x82`\x1F\x83\x01\x12a'\xF2W_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a(\rWa(\ra'\x8DV[`@Q`\x1F\x83\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x81\x16`?\x01\x16\x81\x01\x90\x82\x82\x11\x81\x83\x10\x17\x15a(SWa(Sa'\x8DV[\x81`@R\x83\x81R\x86` \x85\x88\x01\x01\x11\x15a(kW_\x80\xFD[\x83` \x87\x01` \x83\x01^_` \x85\x83\x01\x01R\x80\x94PPPPP\x92\x91PPV[_` \x82\x84\x03\x12\x15a(\x9AW_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a(\xB0W_\x80\xFD[a(\xBC\x84\x82\x85\x01a'\xE3V[\x94\x93PPPPV[_` \x82\x84\x03\x12\x15a(\xD4W_\x80\xFD[\x81Qa$\x0B\x81a$>V[_` \x82\x84\x03\x12\x15a(\xEFW_\x80\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a)\x06W_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a)\x1DW_\x80\xFD[\x90\x83\x01\x90``\x82\x86\x03\x12\x15a)0W_\x80\xFD[`@Q``\x81\x01\x81\x81\x10\x83\x82\x11\x17\x15a)KWa)Ka'\x8DV[`@R\x82Qa)Y\x81a$>V[\x81R` \x83\x81\x01Q\x90\x82\x01R`@\x83\x01Q\x82\x81\x11\x15a)vW_\x80\xFD[a)\x82\x87\x82\x86\x01a'\xE3V[`@\x83\x01RP\x95\x94PPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81Q\x16\x82R` \x81\x01Q` \x83\x01R_`@\x82\x01Q```@\x85\x01Ra(\xBC``\x85\x01\x82a$}V[` \x81R_a\"\xC2` \x83\x01\x84a)\x91V[_` \x82\x84\x03\x12\x15a)\xF1W_\x80\xFD[\x81Q\x80\x15\x15\x81\x14a$\x0BW_\x80\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[a\x01\x80\x81\x01a\"\xC5\x82\x84a%\\V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x83``\x1B\x16\x81R_\x82Q\x80` \x85\x01`\x14\x85\x01^_\x92\x01`\x14\x01\x91\x82RP\x92\x91PPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\"\xC5Wa\"\xC5a*\x81V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_\x82a+\0Wa+\0a*\xC5V[P\x04\x90V[\x81\x81\x03\x81\x81\x11\x15a\"\xC5Wa\"\xC5a*\x81V[c\xFF\xFF\xFF\xFF\x81\x81\x16\x83\x82\x16\x01\x90\x80\x82\x11\x15a+5Wa+5a*\x81V[P\x92\x91PPV[_` \x82\x84\x03\x12\x15a+LW_\x80\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a+cW_\x80\xFD[\x90\x83\x01\x90`\xC0\x82\x86\x03\x12\x15a+vW_\x80\xFD[a+~a'\xBAV[\x82Qa+\x89\x81a$>V[\x81R` \x83\x01Qa+\x99\x81a$>V[` \x82\x01R`@\x83\x81\x01Q\x90\x82\x01R``\x83\x01Qa+\xB6\x81a$>V[``\x82\x01R`\x80\x83\x01Q\x82\x81\x11\x15a+\xCCW_\x80\xFD[a+\xD8\x87\x82\x86\x01a'\xE3V[`\x80\x83\x01RP`\xA0\x83\x01Q`\xA0\x82\x01R\x80\x93PPPP\x92\x91PPV[` \x80\x82R\x82Q``\x83\x83\x01R\x80Q`\x80\x84\x01\x81\x90R_\x92\x91\x82\x01\x90\x83\x90`\xA0\x86\x01\x90[\x80\x83\x10\x15a,8W\x83Q\x82R\x92\x84\x01\x92`\x01\x92\x90\x92\x01\x91\x90\x84\x01\x90a,\x18V[P\x83\x87\x01Q\x93P\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x92P\x82\x86\x82\x03\x01`@\x87\x01Ra,v\x81\x85a)\x91V[\x93PPP`@\x85\x01Q\x81\x85\x84\x03\x01``\x86\x01Ra,\x93\x83\x82a$}V[\x96\x95PPPPPPV[\x84\x81R\x83` \x82\x01R`\x80`@\x82\x01R_a,\xBB`\x80\x83\x01\x85a$}V[\x82\x81\x03``\x84\x01Ra\x05\x01\x81\x85a$}V[\x80\x82\x01\x80\x82\x11\x15a\"\xC5Wa\"\xC5a*\x81V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[_`\xFF\x83\x16\x80a-\x1FWa-\x1Fa*\xC5V[\x80`\xFF\x84\x16\x06\x91PP\x92\x91PPV\xFE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\xC5\xA0\xE7V\xAC\x88\xC1\xD3\xA4\xC4\x19\0\xD9w\xFE\x93\xC2\xD3O\xC9Z\0\xCA>\x84\xEBLkP\xFA\xF9I\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\xA8\x14\xF6N~\x04\xA3\xB9I\xA5qx\x9E\x19lZ\x91\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0j\x02<\xCD\x1F\xF6\xF2\x04\\3\tv\x8E\xAD\x9Eh\xF9x\xF6\xE1\0\0\0\0\0\0\0\0\0\0\0\0\xE9\x1D\x15>\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\n\xFF\xD9\xFD\xEB\x8E\x08\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xA9\x9F\xD9\x95\x0B]]\xCE\xEA\xF4\x93\x9E\"\x1D\xCA\x8C\xA9\xB98\xAB\0\x01\0\0\0\0\0\0\0\0\0%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Qx\xA7)\xEE0\x08\xC7\xD4\x882\xD0\"g\xB7._4\xAD\xA8\xF5T\xA6s\x1A6\x8F\x01Y\x0E\xD7\x1B4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xCBDN\x90\xD8\x19\x84\x15&lj'$\xB7\x90\x0F\xB1/\xC5n\0\0\0\0\0\0\0\0\0\0\0\0\xE9\x1D\x15>\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V\x19zT%\xC0\xC8\0\0\0\0\0\0\0\0\0\0\0\0\xBD\x91\xA7-\xC3\xD9\xB5\xD9\xB1n\xE8c\x8D\xA1\xFCe1\x1B\xD9\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\xABp\xBC\xB2`\x07=\x03m\x16` \x1E\x9DT\x05\xF5\x82\x9Bz\0\0\0\0\0\0\0\0\0\0\0\0g\x8D\xF3A_\xC3\x19G\xDAC$\xECc!(t\xBEZ\x82\xF8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01Q\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q.1\x98\x1E4\x96\ti\xEBT\x9F^\x82l\xF7\x7Fe^r\xB06\x03\xADWJy\xFD\x01_M\xE4\xDE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\xAF Gv\xC7$[\xF4\x14|&\x12\xBFnYr\xEEH7\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\n\x16\xC9ZM.<\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0\xCE\x9E\x05\xC2\xAE\xE5\xF2/\x99A\xC4\xCD\x1F\x1A\x1D\x13\x19K\x10\x97yB-Z\xD9\xA9\x80\x15{\xD0\xF1d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xBC*\xCF^\x82\x1C\\\x9F\x86g\xA3k\xB1\x13\x1D\xAD&\xEDd\xF9\0\x02\0\0\0\0\0\0\0\0\0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\xA2\x02\x9F\xBBTYx\xD0Sx\xB6\xDF\x19\xE3uO\xE5\xED-\x0B\xA1\xE0Q\x02u\x03\x93Cr\xF7\xBE\xB2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x9CX\xBA\xCC3\x1C\x9A\xA8q\xAF\xD8\x02\xDBcy\xA9\x8E\x80\xCE\xDB\0\0\0\0\0\0\0\0\0\0\0\0\x17q'b,J\0\xF3\xD4\t\xB7Uq\xE1,\xB3\xC8\x97=<\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0R\xBA\x9E\xFC8D\x1A\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 !\xD4\xC7\x92\xEA~8\xE0\xD0\x81\x9C \x11\xA2\xB1\xCBrR\xBD\x99\0\x02\0\0\0\0\0\0\0\0\0\x1E\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\xCAD\xB6\xA3\x04\xBA\xA1m\x11\xB6\xDB\x07\x06l\x12v\xB1'>\xE3\xF9E\x90\xBB\xD02\x01\xA6\x18\x82\xAF\x9A\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xA0\xB8i\x91\xC6!\x8B6\xC1\xD1\x9DJ.\x9E\xB0\xCE6\x06\xEBH\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\xFE\xCD\x84a\x8Cz\x16\x8E\x88\xB9\xCB}\x1C\r\xB1(\xAF\x1E\xFE\n\x08\xBB\xB1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\xAF Gv\xC7$[\xF4\x14|&\x12\xBFnYr\xEEH7\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\n\x17'?\xC1Kd\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xBC*\xCF^\x82\x1C\\\x9F\x86g\xA3k\xB1\x13\x1D\xAD&\xEDd\xF9\0\x02\0\0\0\0\0\0\0\0\0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\x80\xBAS?\x01N\xF4#\x8A\xB7\xAD <\n\xEA\xCB\xF3\nq\xC04a@\xDBw\xC4:\xE3\x12\x1A\xFA\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xAE\xA4j`6\x8A{\xD0`\xEE\xC7\xDF\x8C\xBAC\xB7\xEFA\xAD\x85\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'\x10\0\0\0\0\0\0\0\0\0\0\0\0\xE0\x89\x04\x90'\xB9\\'E\xD1\xA9T\xBC\x1D$SR\xD8\x84\xE9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x8D\xB8\x87\x0C\xA4\xB8\xAC\x18\x8CM\x1A\x01O4\xA3\x81\xAE'\xE1\xC2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q \x9C\x17\xD9\xEB\xE3\xACsRy_\x7F\x8B=\x14\xD2S\xD9$0\x83\x1D;,9e\xF9\xA5x\xDAv\x18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xE9\x1D\x15>\x0BAQ\x8A,\xE8\xDD=yD\xFA\x864c\xA9}\0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8A\xA3\xA5(\x15&/X\0\0\0\0\0\0\0\0\0\0\0\0\xBD\x91\xA7-\xC3\xD9\xB5\xD9\xB1n\xE8c\x8D\xA1\xFCe1\x1B\xD9\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\0d\xAC\0\x7F\xF6e\xCF\x8D\r:\xF5\xE0\xAD\x1C&\xA3\xF8S\xEA\0\0\0\0\0\0\0\0\0\0\0\0\xA7g\xF7E3\x1D&|wQ)}\x98+\x05\x0C\x93\x98V'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01Q\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\x05Ad`\xDE\xB7mW\xAF`\x1B\xE1~w{\x93Y-\x8DMJ@\x96\xC5xv\xA9\x1C\x84\xF4\x18\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x9CX\xBA\xCC3\x1C\x9A\xA8q\xAF\xD8\x02\xDBcy\xA9\x8E\x80\xCE\xDB\0\0\0\0\0\0\0\0\0\0\0\0\xCE\x11\xE1B%WYE\xB8\xE6\xDC\rO-\xD4\xC5p\xF7\x9D\x9F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0#\x86\xF2o\xC1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x964\xCAdtt\xB6\xB7\x8D3\x823\x1Aw\xCD\0\xA8\xA9@\xDA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\x93%B)O\xF2p\xA8\xBB\xDB\xE1\xFB\x92\x1D\xE3\xD0\x9C\x97I\xDC5bsa\xFC\x17\xC4K\x9B\x02k\x81\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x83\x90\xA1\xDA\x07\xE3v\xEFz\xDDK\xE8Y\xBAt\xFB\x83\xAA\x02\xD5\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08\x82d\xEC\xF9\x86\xCA\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08q\x01\xD8\x17\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\xD1\xE8h\xD1 \xE3&\xE5X\x1C\xAA9\x85+\xB0\xDA\x924\xA5\x11\xEDv\xE6\xF7\xA9\xDC\xCE\xB0\xD5\xF1T\xC7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\xAF Gv\xC7$[\xF4\x14|&\x12\xBFnYr\xEEH7\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\t\x8EF\x99T%\xCA\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \xBC*\xCF^\x82\x1C\\\x9F\x86g\xA3k\xB1\x13\x1D\xAD&\xEDd\xF9\0\x02\0\0\0\0\0\0\0\0\0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\xB1H\xF4\x0F\xFF\x05\xB5\xCEk\"u,\xF8\xE4T\xB5V\xF7\xA8Q\xF0\xE8\xECQ+%\x07\xDA\xE9\x91u\xA0\xA4y-\x8AS\xE0\x86?\xBB^sZ\\\x992\x95\xBB\xD1\x7FH\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0lv\x97\x1F\x98\x94Z\xE9\x8D\xD7\xD4\xDF\xCA\x87\x11\xEB\xEA\x94n\xA6\0\0\0\0\0\0\0\0\0\0\0\0\x9CX\xBA\xCC3\x1C\x9A\xA8q\xAF\xD8\x02\xDBcy\xA9\x8E\x80\xCE\xDB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\tO\x8D\x91h\xE2q\0\0\0\0\0\0\0\0\0\0\0\0\xD3\xA8H\x95\x08\x06\t\xE1\x16<\x80\xB2\xBDesm\xB1\xB8k\xEC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xC0M\x82\x1D\xDC\x9Deaw\xDA\xD4\xD5\xC2\xF7jK\xFF.\xD5\x14\xFFi\xFAJ\xA4\xFD\x86\x9Dn\x98\xD5\\\x89\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 F\x83\xE3@\xA8\x04\x92a\x05}Z\xB1\xB2\x9C\x8D\x84\x0Eui^\0\x02\0\0\0\0\0\0\0\0\0Z\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\x0042;\x930\x96SNC\x95\x8Fl{\xF4O+\xB5\x94$\xDA\xD0\x03\x83\x88)\x11_]\x9F\xF3\xEDi\xC8\xD2\xB4\xB2n\x10\xEB\x1Ay3\x12\x06\xC2\x8F\xBBG49\n^\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\x80\x85\x07\x12\x1B\x80\xC0#\x88\xFA\xD1G&H.\x06\x1B\x8D\xA8'\0\0\0\0\0\0\0\0\0\0\0\0\xC0*\xAA9\xB2#\xFE\x8D\n\x0E\\O'\xEA\xD9\x08 = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidArrayLength) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidArrayLength { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidArrayLength { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [157u8, 137u8, 2u8, 10u8]; + const SIGNATURE: &'static str = "InvalidArrayLength()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `MathOverflowedMulDiv()` and selector `0x227bc153`. + ```solidity + error MathOverflowedMulDiv(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct MathOverflowedMulDiv; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: MathOverflowedMulDiv) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for MathOverflowedMulDiv { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for MathOverflowedMulDiv { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [34u8, 123u8, 193u8, 83u8]; + const SIGNATURE: &'static str = "MathOverflowedMulDiv()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `NoOrder()` and selector `0x19aad573`. + ```solidity + error NoOrder(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NoOrder; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NoOrder) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NoOrder { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for NoOrder { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [25u8, 170u8, 213u8, 115u8]; + const SIGNATURE: &'static str = "NoOrder()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `PoolDoesNotExist()` and selector `0x9c8787c0`. + ```solidity + error PoolDoesNotExist(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PoolDoesNotExist; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: PoolDoesNotExist) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for PoolDoesNotExist { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for PoolDoesNotExist { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [156u8, 135u8, 135u8, 192u8]; + const SIGNATURE: &'static str = "PoolDoesNotExist()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `PoolIsClosed()` and selector `0xefc869b4`. + ```solidity + error PoolIsClosed(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PoolIsClosed; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: PoolIsClosed) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for PoolIsClosed { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for PoolIsClosed { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [239u8, 200u8, 105u8, 180u8]; + const SIGNATURE: &'static str = "PoolIsClosed()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `PoolIsPaused()` and selector `0x21081abf`. + ```solidity + error PoolIsPaused(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PoolIsPaused; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: PoolIsPaused) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for PoolIsPaused { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for PoolIsPaused { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [33u8, 8u8, 26u8, 191u8]; + const SIGNATURE: &'static str = "PoolIsPaused()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `COWAMMPoolCreated(address)` and selector `0x0d03834d0d86c7f57e877af40e26f176dc31bd637535d4ba153d1ac9de88a7ea`. + ```solidity + event COWAMMPoolCreated(address indexed amm); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct COWAMMPoolCreated { + #[allow(missing_docs)] + pub amm: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for COWAMMPoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "COWAMMPoolCreated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 13u8, 3u8, 131u8, 77u8, 13u8, 134u8, 199u8, 245u8, 126u8, 135u8, 122u8, 244u8, + 14u8, 38u8, 241u8, 118u8, 220u8, 49u8, 189u8, 99u8, 117u8, 53u8, 212u8, 186u8, + 21u8, 61u8, 26u8, 201u8, 222u8, 136u8, 167u8, 234u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { amm: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.amm.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.amm, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for COWAMMPoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&COWAMMPoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &COWAMMPoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall {} + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `order(address,uint256[])` and selector `0x27242c9b`. + ```solidity + function order(address pool, uint256[] memory prices) external view returns (GPv2Order.Data memory _order, GPv2Interaction.Data[] memory preInteractions, GPv2Interaction.Data[] memory postInteractions, bytes memory sig); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct orderCall { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub prices: + alloy_sol_types::private::Vec, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`order(address,uint256[])`](orderCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct orderReturn { + #[allow(missing_docs)] + pub _order: ::RustType, + #[allow(missing_docs)] + pub preInteractions: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub postInteractions: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub sig: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: orderCall) -> Self { + (value.pool, value.prices) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for orderCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + pool: tuple.0, + prices: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + GPv2Order::Data, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: orderReturn) -> Self { + ( + value._order, + value.preInteractions, + value.postInteractions, + value.sig, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for orderReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _order: tuple.0, + preInteractions: tuple.1, + postInteractions: tuple.2, + sig: tuple.3, + } + } + } + } + impl orderReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self._order, + ), + as alloy_sol_types::SolType>::tokenize(&self.preInteractions), + as alloy_sol_types::SolType>::tokenize(&self.postInteractions), + ::tokenize( + &self.sig, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for orderCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array>, + ); + type Return = orderReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + GPv2Order::Data, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Bytes, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [39u8, 36u8, 44u8, 155u8]; + const SIGNATURE: &'static str = "order(address,uint256[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.pool, + ), + , + > as alloy_sol_types::SolType>::tokenize(&self.prices), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + orderReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `tokens(address)` and selector `0xe4860339`. + ```solidity + function tokens(address pool) external view returns (address[] memory _tokens); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct tokensCall { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`tokens(address)`](tokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct tokensReturn { + #[allow(missing_docs)] + pub _tokens: alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: tokensCall) -> Self { + (value.pool,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for tokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { pool: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (alloy_sol_types::private::Vec,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: tokensReturn) -> Self { + (value._tokens,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for tokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _tokens: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for tokensCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [228u8, 134u8, 3u8, 57u8]; + const SIGNATURE: &'static str = "tokens(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.pool, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: tokensReturn = r.into(); + r._tokens + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: tokensReturn = r.into(); + r._tokens + }) + } + } + }; + ///Container for all the [`CowAmmLegacyHelper`](self) function calls. + #[derive(Clone)] + pub enum CowAmmLegacyHelperCalls { + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + order(orderCall), + #[allow(missing_docs)] + tokens(tokensCall), + } + impl CowAmmLegacyHelperCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [39u8, 36u8, 44u8, 155u8], + [196u8, 90u8, 1u8, 85u8], + [228u8, 134u8, 3u8, 57u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(order), + ::core::stringify!(factory), + ::core::stringify!(tokens), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowAmmLegacyHelperCalls { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CowAmmLegacyHelperCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::factory(_) => ::SELECTOR, + Self::order(_) => ::SELECTOR, + Self::tokens(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn order(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperCalls::order) + } + order + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperCalls::factory) + } + factory + }, + { + fn tokens(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperCalls::tokens) + } + tokens + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowAmmLegacyHelperCalls, + >] = &[ + { + fn order(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmLegacyHelperCalls::order) + } + order + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmLegacyHelperCalls::factory) + } + factory + }, + { + fn tokens(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmLegacyHelperCalls::tokens) + } + tokens + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::order(inner) => { + ::abi_encoded_size(inner) + } + Self::tokens(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::order(inner) => { + ::abi_encode_raw(inner, out) + } + Self::tokens(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CowAmmLegacyHelper`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowAmmLegacyHelperErrors { + #[allow(missing_docs)] + InvalidArrayLength(InvalidArrayLength), + #[allow(missing_docs)] + MathOverflowedMulDiv(MathOverflowedMulDiv), + #[allow(missing_docs)] + NoOrder(NoOrder), + #[allow(missing_docs)] + PoolDoesNotExist(PoolDoesNotExist), + #[allow(missing_docs)] + PoolIsClosed(PoolIsClosed), + #[allow(missing_docs)] + PoolIsPaused(PoolIsPaused), + } + impl CowAmmLegacyHelperErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [25u8, 170u8, 213u8, 115u8], + [33u8, 8u8, 26u8, 191u8], + [34u8, 123u8, 193u8, 83u8], + [156u8, 135u8, 135u8, 192u8], + [157u8, 137u8, 2u8, 10u8], + [239u8, 200u8, 105u8, 180u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(NoOrder), + ::core::stringify!(PoolIsPaused), + ::core::stringify!(MathOverflowedMulDiv), + ::core::stringify!(PoolDoesNotExist), + ::core::stringify!(InvalidArrayLength), + ::core::stringify!(PoolIsClosed), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowAmmLegacyHelperErrors { + const COUNT: usize = 6usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CowAmmLegacyHelperErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::InvalidArrayLength(_) => { + ::SELECTOR + } + Self::MathOverflowedMulDiv(_) => { + ::SELECTOR + } + Self::NoOrder(_) => ::SELECTOR, + Self::PoolDoesNotExist(_) => { + ::SELECTOR + } + Self::PoolIsClosed(_) => ::SELECTOR, + Self::PoolIsPaused(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn NoOrder(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperErrors::NoOrder) + } + NoOrder + }, + { + fn PoolIsPaused( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperErrors::PoolIsPaused) + } + PoolIsPaused + }, + { + fn MathOverflowedMulDiv( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperErrors::MathOverflowedMulDiv) + } + MathOverflowedMulDiv + }, + { + fn PoolDoesNotExist( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperErrors::PoolDoesNotExist) + } + PoolDoesNotExist + }, + { + fn InvalidArrayLength( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperErrors::InvalidArrayLength) + } + InvalidArrayLength + }, + { + fn PoolIsClosed( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowAmmLegacyHelperErrors::PoolIsClosed) + } + PoolIsClosed + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowAmmLegacyHelperErrors, + >] = &[ + { + fn NoOrder(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmLegacyHelperErrors::NoOrder) + } + NoOrder + }, + { + fn PoolIsPaused( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmLegacyHelperErrors::PoolIsPaused) + } + PoolIsPaused + }, + { + fn MathOverflowedMulDiv( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmLegacyHelperErrors::MathOverflowedMulDiv) + } + MathOverflowedMulDiv + }, + { + fn PoolDoesNotExist( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmLegacyHelperErrors::PoolDoesNotExist) + } + PoolDoesNotExist + }, + { + fn InvalidArrayLength( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowAmmLegacyHelperErrors::InvalidArrayLength) + } + InvalidArrayLength + }, + { + fn PoolIsClosed( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowAmmLegacyHelperErrors::PoolIsClosed) + } + PoolIsClosed + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::InvalidArrayLength(inner) => { + ::abi_encoded_size(inner) + } + Self::MathOverflowedMulDiv(inner) => { + ::abi_encoded_size(inner) + } + Self::NoOrder(inner) => { + ::abi_encoded_size(inner) + } + Self::PoolDoesNotExist(inner) => { + ::abi_encoded_size(inner) + } + Self::PoolIsClosed(inner) => { + ::abi_encoded_size(inner) + } + Self::PoolIsPaused(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::InvalidArrayLength(inner) => { + ::abi_encode_raw(inner, out) + } + Self::MathOverflowedMulDiv(inner) => { + ::abi_encode_raw(inner, out) + } + Self::NoOrder(inner) => { + ::abi_encode_raw(inner, out) + } + Self::PoolDoesNotExist(inner) => { + ::abi_encode_raw(inner, out) + } + Self::PoolIsClosed(inner) => { + ::abi_encode_raw(inner, out) + } + Self::PoolIsPaused(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CowAmmLegacyHelper`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowAmmLegacyHelperEvents { + #[allow(missing_docs)] + COWAMMPoolCreated(COWAMMPoolCreated), + } + impl CowAmmLegacyHelperEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 13u8, 3u8, 131u8, 77u8, 13u8, 134u8, 199u8, 245u8, 126u8, 135u8, 122u8, 244u8, 14u8, + 38u8, 241u8, 118u8, 220u8, 49u8, 189u8, 99u8, 117u8, 53u8, 212u8, 186u8, 21u8, 61u8, + 26u8, 201u8, 222u8, 136u8, 167u8, 234u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(COWAMMPoolCreated)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for CowAmmLegacyHelperEvents { + const COUNT: usize = 1usize; + const NAME: &'static str = "CowAmmLegacyHelperEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::COWAMMPoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for CowAmmLegacyHelperEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::COWAMMPoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::COWAMMPoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CowAmmLegacyHelper`](self) contract instance. + + See the [wrapper's documentation](`CowAmmLegacyHelperInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CowAmmLegacyHelperInstance { + CowAmmLegacyHelperInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> + { + CowAmmLegacyHelperInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + CowAmmLegacyHelperInstance::::deploy_builder(__provider) + } + /**A [`CowAmmLegacyHelper`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CowAmmLegacyHelper`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CowAmmLegacyHelperInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CowAmmLegacyHelperInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CowAmmLegacyHelperInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CowAmmLegacyHelperInstance + { + /**Creates a new wrapper around an on-chain [`CowAmmLegacyHelper`](self) contract instance. + + See the [wrapper's documentation](`CowAmmLegacyHelperInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CowAmmLegacyHelperInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CowAmmLegacyHelperInstance { + CowAmmLegacyHelperInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CowAmmLegacyHelperInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`order`] function. + pub fn order( + &self, + pool: alloy_sol_types::private::Address, + prices: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + ) -> alloy_contract::SolCallBuilder<&P, orderCall, N> { + self.call_builder(&orderCall { pool, prices }) + } + + ///Creates a new call builder for the [`tokens`] function. + pub fn tokens( + &self, + pool: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, tokensCall, N> { + self.call_builder(&tokensCall { pool }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CowAmmLegacyHelperInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`COWAMMPoolCreated`] event. + pub fn COWAMMPoolCreated_filter(&self) -> alloy_contract::Event<&P, COWAMMPoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = CowAmmLegacyHelper::CowAmmLegacyHelperInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x3705ceee5eaa561e3157cf92641ce28c45a3999c"), + Some(20332745u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xd9ec06b001957498ab1bc716145515d1d0e30ffb"), + Some(35026999u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/cowammuniswapv2priceoracle/Cargo.toml b/contracts/generated/contracts-generated/cowammuniswapv2priceoracle/Cargo.toml new file mode 100644 index 0000000000..aba73a2198 --- /dev/null +++ b/contracts/generated/contracts-generated/cowammuniswapv2priceoracle/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowammuniswapv2priceoracle" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowammuniswapv2priceoracle/src/lib.rs b/contracts/generated/contracts-generated/cowammuniswapv2priceoracle/src/lib.rs new file mode 100644 index 0000000000..b7847d6413 --- /dev/null +++ b/contracts/generated/contracts-generated/cowammuniswapv2priceoracle/src/lib.rs @@ -0,0 +1,230 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface CowAmmUniswapV2PriceOracle {} +``` + +...which was generated by the following JSON ABI: +```json +[] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CowAmmUniswapV2PriceOracle { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f80fd5b506105468061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063355efdd91461002d575b5f80fd5b61004061003b366004610386565b610059565b6040805192835260208301919091520160405180910390f35b5f808061006884860186610411565b9050805f015173ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156100b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100da91906104a2565b826dffffffffffffffffffffffffffff169250816dffffffffffffffffffffffffffff1691505080935081945050505f815f015173ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610156573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061017a91906104ee565b90505f825f015173ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ed91906104ee565b90508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff160361022757929392905b8173ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff16146102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e300000000000000000000060448201526064015b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e310000000000000000000060448201526064016102b8565b50505094509492505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610383575f80fd5b50565b5f805f8060608587031215610399575f80fd5b84356103a481610362565b935060208501356103b481610362565b9250604085013567ffffffffffffffff808211156103d0575f80fd5b818701915087601f8301126103e3575f80fd5b8135818111156103f1575f80fd5b886020828501011115610402575f80fd5b95989497505060200194505050565b5f60208284031215610421575f80fd5b6040516020810181811067ffffffffffffffff82111715610469577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604052823561047781610362565b81529392505050565b80516dffffffffffffffffffffffffffff8116811461049d575f80fd5b919050565b5f805f606084860312156104b4575f80fd5b6104bd84610480565b92506104cb60208501610480565b9150604084015163ffffffff811681146104e3575f80fd5b809150509250925092565b5f602082840312156104fe575f80fd5b815161050981610362565b939250505056fea26469706673582212201fe6ad4d6b89d204db5394bdedef23d10ed8c7e4f83be4c5fe14dcc09470223464736f6c63430008190033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW_\x80\xFD[Pa\x05F\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c5^\xFD\xD9\x14a\0-W[_\x80\xFD[a\0@a\0;6`\x04a\x03\x86V[a\0YV[`@\x80Q\x92\x83R` \x83\x01\x91\x90\x91R\x01`@Q\x80\x91\x03\x90\xF3[_\x80\x80a\0h\x84\x86\x01\x86a\x04\x11V[\x90P\x80_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\t\x02\xF1\xAC`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01```@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xB6W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xDA\x91\x90a\x04\xA2V[\x82m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x92P\x81m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91PP\x80\x93P\x81\x94PPP_\x81_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\r\xFE\x16\x81`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01VW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01z\x91\x90a\x04\xEEV[\x90P_\x82_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xC9W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xED\x91\x90a\x04\xEEV[\x90P\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03a\x02'W\x92\x93\x92\x90[\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x02\xC1W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7Foracle: invalid token0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x03VW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7Foracle: invalid token1\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x02\xB8V[PPP\x94P\x94\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x03\x83W_\x80\xFD[PV[_\x80_\x80``\x85\x87\x03\x12\x15a\x03\x99W_\x80\xFD[\x845a\x03\xA4\x81a\x03bV[\x93P` \x85\x015a\x03\xB4\x81a\x03bV[\x92P`@\x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x03\xD0W_\x80\xFD[\x81\x87\x01\x91P\x87`\x1F\x83\x01\x12a\x03\xE3W_\x80\xFD[\x815\x81\x81\x11\x15a\x03\xF1W_\x80\xFD[\x88` \x82\x85\x01\x01\x11\x15a\x04\x02W_\x80\xFD[\x95\x98\x94\x97PP` \x01\x94PPPV[_` \x82\x84\x03\x12\x15a\x04!W_\x80\xFD[`@Q` \x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04iW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@R\x825a\x04w\x81a\x03bV[\x81R\x93\x92PPPV[\x80Qm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x04\x9DW_\x80\xFD[\x91\x90PV[_\x80_``\x84\x86\x03\x12\x15a\x04\xB4W_\x80\xFD[a\x04\xBD\x84a\x04\x80V[\x92Pa\x04\xCB` \x85\x01a\x04\x80V[\x91P`@\x84\x01Qc\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x04\xE3W_\x80\xFD[\x80\x91PP\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x04\xFEW_\x80\xFD[\x81Qa\x05\t\x81a\x03bV[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 \x1F\xE6\xADMk\x89\xD2\x04\xDBS\x94\xBD\xED\xEF#\xD1\x0E\xD8\xC7\xE4\xF8;\xE4\xC5\xFE\x14\xDC\xC0\x94p\"4dsolcC\0\x08\x19\x003", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063355efdd91461002d575b5f80fd5b61004061003b366004610386565b610059565b6040805192835260208301919091520160405180910390f35b5f808061006884860186610411565b9050805f015173ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156100b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100da91906104a2565b826dffffffffffffffffffffffffffff169250816dffffffffffffffffffffffffffff1691505080935081945050505f815f015173ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015610156573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061017a91906104ee565b90505f825f015173ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101ed91906104ee565b90508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff160361022757929392905b8173ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff16146102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e300000000000000000000060448201526064015b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6f7261636c653a20696e76616c696420746f6b656e310000000000000000000060448201526064016102b8565b50505094509492505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610383575f80fd5b50565b5f805f8060608587031215610399575f80fd5b84356103a481610362565b935060208501356103b481610362565b9250604085013567ffffffffffffffff808211156103d0575f80fd5b818701915087601f8301126103e3575f80fd5b8135818111156103f1575f80fd5b886020828501011115610402575f80fd5b95989497505060200194505050565b5f60208284031215610421575f80fd5b6040516020810181811067ffffffffffffffff82111715610469577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604052823561047781610362565b81529392505050565b80516dffffffffffffffffffffffffffff8116811461049d575f80fd5b919050565b5f805f606084860312156104b4575f80fd5b6104bd84610480565b92506104cb60208501610480565b9150604084015163ffffffff811681146104e3575f80fd5b809150509250925092565b5f602082840312156104fe575f80fd5b815161050981610362565b939250505056fea26469706673582212201fe6ad4d6b89d204db5394bdedef23d10ed8c7e4f83be4c5fe14dcc09470223464736f6c63430008190033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c5^\xFD\xD9\x14a\0-W[_\x80\xFD[a\0@a\0;6`\x04a\x03\x86V[a\0YV[`@\x80Q\x92\x83R` \x83\x01\x91\x90\x91R\x01`@Q\x80\x91\x03\x90\xF3[_\x80\x80a\0h\x84\x86\x01\x86a\x04\x11V[\x90P\x80_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\t\x02\xF1\xAC`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01```@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xB6W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xDA\x91\x90a\x04\xA2V[\x82m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x92P\x81m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91PP\x80\x93P\x81\x94PPP_\x81_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\r\xFE\x16\x81`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01VW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01z\x91\x90a\x04\xEEV[\x90P_\x82_\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD2\x12 \xA7`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xC9W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xED\x91\x90a\x04\xEEV[\x90P\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03a\x02'W\x92\x93\x92\x90[\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x02\xC1W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7Foracle: invalid token0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x03VW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7Foracle: invalid token1\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x02\xB8V[PPP\x94P\x94\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x03\x83W_\x80\xFD[PV[_\x80_\x80``\x85\x87\x03\x12\x15a\x03\x99W_\x80\xFD[\x845a\x03\xA4\x81a\x03bV[\x93P` \x85\x015a\x03\xB4\x81a\x03bV[\x92P`@\x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x03\xD0W_\x80\xFD[\x81\x87\x01\x91P\x87`\x1F\x83\x01\x12a\x03\xE3W_\x80\xFD[\x815\x81\x81\x11\x15a\x03\xF1W_\x80\xFD[\x88` \x82\x85\x01\x01\x11\x15a\x04\x02W_\x80\xFD[\x95\x98\x94\x97PP` \x01\x94PPPV[_` \x82\x84\x03\x12\x15a\x04!W_\x80\xFD[`@Q` \x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04iW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@R\x825a\x04w\x81a\x03bV[\x81R\x93\x92PPPV[\x80Qm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x04\x9DW_\x80\xFD[\x91\x90PV[_\x80_``\x84\x86\x03\x12\x15a\x04\xB4W_\x80\xFD[a\x04\xBD\x84a\x04\x80V[\x92Pa\x04\xCB` \x85\x01a\x04\x80V[\x91P`@\x84\x01Qc\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x04\xE3W_\x80\xFD[\x80\x91PP\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x04\xFEW_\x80\xFD[\x81Qa\x05\t\x81a\x03bV[\x93\x92PPPV\xFE\xA2dipfsX\"\x12 \x1F\xE6\xADMk\x89\xD2\x04\xDBS\x94\xBD\xED\xEF#\xD1\x0E\xD8\xC7\xE4\xF8;\xE4\xC5\xFE\x14\xDC\xC0\x94p\"4dsolcC\0\x08\x19\x003", + ); + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CowAmmUniswapV2PriceOracle`](self) contract instance. + + See the [wrapper's documentation](`CowAmmUniswapV2PriceOracleInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CowAmmUniswapV2PriceOracleInstance { + CowAmmUniswapV2PriceOracleInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + CowAmmUniswapV2PriceOracleInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + CowAmmUniswapV2PriceOracleInstance::::deploy_builder(__provider) + } + /**A [`CowAmmUniswapV2PriceOracle`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CowAmmUniswapV2PriceOracle`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CowAmmUniswapV2PriceOracleInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CowAmmUniswapV2PriceOracleInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CowAmmUniswapV2PriceOracleInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CowAmmUniswapV2PriceOracleInstance + { + /**Creates a new wrapper around an on-chain [`CowAmmUniswapV2PriceOracle`](self) contract instance. + + See the [wrapper's documentation](`CowAmmUniswapV2PriceOracleInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CowAmmUniswapV2PriceOracleInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CowAmmUniswapV2PriceOracleInstance { + CowAmmUniswapV2PriceOracleInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CowAmmUniswapV2PriceOracleInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CowAmmUniswapV2PriceOracleInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = + CowAmmUniswapV2PriceOracle::CowAmmUniswapV2PriceOracleInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/cowprotocoltoken/Cargo.toml b/contracts/generated/contracts-generated/cowprotocoltoken/Cargo.toml new file mode 100644 index 0000000000..2ef10310c4 --- /dev/null +++ b/contracts/generated/contracts-generated/cowprotocoltoken/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowprotocoltoken" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowprotocoltoken/src/lib.rs b/contracts/generated/contracts-generated/cowprotocoltoken/src/lib.rs new file mode 100644 index 0000000000..784f5bd013 --- /dev/null +++ b/contracts/generated/contracts-generated/cowprotocoltoken/src/lib.rs @@ -0,0 +1,4183 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface CowProtocolToken { + error AlreadyInflated(); + error ExceedingMintCap(); + error OnlyCowDao(); + + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 value); + + constructor(address initialTokenHolder, address cowDao, uint256 totalSupply); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external view returns (uint8); + function mint(address target, uint256 amount) external; + function name() external view returns (string memory); + function nonces(address owner) external view returns (uint256); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function simulateDelegatecall(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); + function symbol() external view returns (string memory); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "initialTokenHolder", + "type": "address", + "internalType": "address" + }, + { + "name": "cowDao", + "type": "address", + "internalType": "address" + }, + { + "name": "totalSupply", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "simulateDelegatecall", + "inputs": [ + { + "name": "targetContract", + "type": "address", + "internalType": "address" + }, + { + "name": "calldataPayload", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "response", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AlreadyInflated", + "inputs": [] + }, + { + "type": "error", + "name": "ExceedingMintCap", + "inputs": [] + }, + { + "type": "error", + "name": "OnlyCowDao", + "inputs": [] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CowProtocolToken { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6101806040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c96101405260006006553480156200003c57600080fd5b5060405162002122380380620021228339810160408190526200005f916200035f565b8282826040518060400160405280601281526020017121b7ab90283937ba37b1b7b6102a37b5b2b760711b81525060405180604001604052806003815260200162434f5760e81b8152508180604051806040016040528060018152602001603160f81b81525084848160039080519060200190620000df9291906200029c565b508051620000f59060049060208401906200029c565b5050825160209384012082519284019290922060e08390526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818901819052818301979097526060810194909452608080850193909352308483018190528151808603909301835260c09485019091528151919096012090529290925261012052506200019590508584620001b4565b5050506001600160a01b03166101605250504260065550620004049050565b6001600160a01b0382166200020f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b8060026000828254620002239190620003a0565b90915550506001600160a01b0382166000908152602081905260408120805483929062000252908490620003a0565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b828054620002aa90620003c7565b90600052602060002090601f016020900481019282620002ce576000855562000319565b82601f10620002e957805160ff191683800117855562000319565b8280016001018555821562000319579182015b8281111562000319578251825591602001919060010190620002fc565b50620003279291506200032b565b5090565b5b808211156200032757600081556001016200032c565b80516001600160a01b03811681146200035a57600080fd5b919050565b6000806000606084860312156200037557600080fd5b620003808462000342565b9250620003906020850162000342565b9150604084015190509250925092565b60008219821115620003c257634e487b7160e01b600052601160045260246000fd5b500190565b600181811c90821680620003dc57607f821691505b60208210811415620003fe57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e05161010051610120516101405161016051611cb1620004716000396000818161033a01526105a10152600061096401526000611135015260006111840152600061115f015260006110b8015260006110e20152600061110c0152611cb16000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c806370a08231116100d8578063cd42dcbe1161008c578063e2d5148911610066578063e2d5148914610335578063f84436bd14610381578063fde9e07a1461039457600080fd5b8063cd42dcbe146102d1578063d505accf146102dc578063dd62ed3e146102ef57600080fd5b806395d89b41116100bd57806395d89b41146102a3578063a457c2d7146102ab578063a9059cbb146102be57600080fd5b806370a082311461025a5780637ecebe001461029057600080fd5b80633644e5151161013a57806343218e191161011457806343218e191461022c5780635624b25b1461023f5780635862bf3d1461025257600080fd5b80633644e515146101fc578063395093511461020457806340c10f191461021757600080fd5b806318160ddd1161016b57806318160ddd146101c857806323b872dd146101da578063313ce567146101ed57600080fd5b806306fdde0314610187578063095ea7b3146101a5575b600080fd5b61018f61039d565b60405161019c91906117aa565b60405180910390f35b6101b86101b33660046117ed565b61042f565b604051901515815260200161019c565b6002545b60405190815260200161019c565b6101b86101e8366004611817565b610446565b6040516012815260200161019c565b6101cc610531565b6101b86102123660046117ed565b610540565b61022a6102253660046117ed565b610589565b005b61018f61023a366004611882565b6106af565b61018f61024d366004611962565b610751565b6101cc600381565b6101cc610268366004611984565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101cc61029e366004611984565b6107d7565b61018f610802565b6101b86102b93660046117ed565b610811565b6101b86102cc3660046117ed565b6108e9565b6101cc6301e1338081565b61022a6102ea36600461199f565b6108f6565b6101cc6102fd366004611a12565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b61035c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61018f61038f366004611882565b610ab5565b6101cc60065481565b6060600380546103ac90611a45565b80601f01602080910402602001604051908101604052809291908181526020018280546103d890611a45565b80156104255780601f106103fa57610100808354040283529160200191610425565b820191906000526020600020905b81548152906001019060200180831161040857829003601f168201915b5050505050905090565b600061043c338484610c36565b5060015b92915050565b6000610453848484610de9565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482811015610519576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206160448201527f6c6c6f77616e636500000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6105268533858403610c36565b506001949350505050565b600061053b61109e565b905090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161043c918590610584908690611ac2565b610c36565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105f8576040517ffe72c36e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064600361060560025490565b61060f9190611ada565b6106199190611b17565b811115610652576040517f2c6af20800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426301e133806006546106659190611ac2565b111561069d576040517f7b06471500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426006556106ab82826111d2565b5050565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040516106d89190611b52565b600060405180830381855af49150503d8060008114610713576040519150601f19603f3d011682016040523d82523d6000602084013e610718565b606091505b5060405190935090915061074a906107369084908490602001611b6e565b6040516020818303038152906040526112f2565b5092915050565b60606000610760836020611ada565b67ffffffffffffffff81111561077857610778611853565b6040519080825280601f01601f1916602001820160405280156107a2576020820181803683370190505b50905060005b838110156107cf5784810154602080830284010152806107c781611b96565b9150506107a8565b509392505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260056020526040812054610440565b6060600480546103ac90611a45565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156108d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610510565b6108df3385858403610c36565b5060019392505050565b600061043c338484610de9565b83421115610960576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610510565b60007f000000000000000000000000000000000000000000000000000000000000000088888861098f8c6112fa565b60408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060006109f78261132f565b90506000610a0782878787611398565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610510565b610aa98a8a8a610c36565b50505050505050505050565b606060006343218e1960e01b8484604051602401610ad4929190611bcf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290519091503090610b63908390611b52565b6000604051808303816000865af19150503d8060008114610ba0576040519150601f19603f3d011682016040523d82523d6000602084013e610ba5565b606091505b5090508092505060008260018451610bbd9190611c06565b81518110610bcd57610bcd611c1d565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b149050610c188360018551610c149190611c06565b9052565b8015610c25575050610440565b610c2e836112f2565b505092915050565b73ffffffffffffffffffffffffffffffffffffffff8316610cd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff8216610d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316610e8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff8216610f2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610fe5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610510565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220858503905591851681529081208054849290611029908490611ac2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161108f91815260200190565b60405180910390a35b50505050565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801561110457507f000000000000000000000000000000000000000000000000000000000000000046145b1561112e57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b73ffffffffffffffffffffffffffffffffffffffff821661124f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610510565b80600260008282546112619190611ac2565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260408120805483929061129b908490611ac2565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b805160208201fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526005602052604090208054600181018255905b50919050565b600061044061133c61109e565b836040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006113a9878787876113c0565b915091506113b6816114d8565b5095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156113f757506000905060036114cf565b8460ff16601b1415801561140f57508460ff16601c14155b1561142057506000905060046114cf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611474573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166114c8576000600192509250506114cf565b9150600090505b94509492505050565b60008160048111156114ec576114ec611c4c565b14156114f55750565b600181600481111561150957611509611c4c565b1415611571576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610510565b600281600481111561158557611585611c4c565b14156115ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610510565b600381600481111561160157611601611c4c565b141561168f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610510565b60048160048111156116a3576116a3611c4c565b1415611731576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610510565b50565b60005b8381101561174f578181015183820152602001611737565b838111156110985750506000910152565b60008151808452611778816020860160208601611734565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006117bd6020830184611760565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146117e857600080fd5b919050565b6000806040838503121561180057600080fd5b611809836117c4565b946020939093013593505050565b60008060006060848603121561182c57600080fd5b611835846117c4565b9250611843602085016117c4565b9150604084013590509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561189557600080fd5b61189e836117c4565b9150602083013567ffffffffffffffff808211156118bb57600080fd5b818501915085601f8301126118cf57600080fd5b8135818111156118e1576118e1611853565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561192757611927611853565b8160405282815288602084870101111561194057600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000806040838503121561197557600080fd5b50508035926020909101359150565b60006020828403121561199657600080fd5b6117bd826117c4565b600080600080600080600060e0888a0312156119ba57600080fd5b6119c3886117c4565b96506119d1602089016117c4565b95506040880135945060608801359350608088013560ff811681146119f557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611a2557600080fd5b611a2e836117c4565b9150611a3c602084016117c4565b90509250929050565b600181811c90821680611a5957607f821691505b60208210811415611329577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611ad557611ad5611a93565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611b1257611b12611a93565b500290565b600082611b4d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008251611b64818460208701611734565b9190910192915050565b60008351611b80818460208801611734565b92151560f81b9190920190815260010192915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611bc857611bc8611a93565b5060010190565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000611bfe6040830184611760565b949350505050565b600082821015611c1857611c18611a93565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220530954a1b40a0e3c6d45330c16c5bf384a847ba06bf8ebbb9afdfb09ada68c0b64736f6c634300080a0033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01\x80`@R\x7Fnq\xED\xAE\x12\xB1\xB9\x7FM\x1F`7\x0F\xEF\x10\x10_\xA2\xFA\xAE\x01&\x11J\x16\x9Cd\x84]a&\xC9a\x01@R`\0`\x06U4\x80\x15b\0\0\x14a\x02\xEFW`\0\x80\xFD[\x80c\x95\xD8\x9BA\x11a\0\xBDW\x80c\x95\xD8\x9BA\x14a\x02\xA3W\x80c\xA4W\xC2\xD7\x14a\x02\xABW\x80c\xA9\x05\x9C\xBB\x14a\x02\xBEW`\0\x80\xFD[\x80cp\xA0\x821\x14a\x02ZW\x80c~\xCE\xBE\0\x14a\x02\x90W`\0\x80\xFD[\x80c6D\xE5\x15\x11a\x01:W\x80cC!\x8E\x19\x11a\x01\x14W\x80cC!\x8E\x19\x14a\x02,W\x80cV$\xB2[\x14a\x02?W\x80cXb\xBF=\x14a\x02RW`\0\x80\xFD[\x80c6D\xE5\x15\x14a\x01\xFCW\x80c9P\x93Q\x14a\x02\x04W\x80c@\xC1\x0F\x19\x14a\x02\x17W`\0\x80\xFD[\x80c\x18\x16\r\xDD\x11a\x01kW\x80c\x18\x16\r\xDD\x14a\x01\xC8W\x80c#\xB8r\xDD\x14a\x01\xDAW\x80c1<\xE5g\x14a\x01\xEDW`\0\x80\xFD[\x80c\x06\xFD\xDE\x03\x14a\x01\x87W\x80c\t^\xA7\xB3\x14a\x01\xA5W[`\0\x80\xFD[a\x01\x8Fa\x03\x9DV[`@Qa\x01\x9C\x91\x90a\x17\xAAV[`@Q\x80\x91\x03\x90\xF3[a\x01\xB8a\x01\xB36`\x04a\x17\xEDV[a\x04/V[`@Q\x90\x15\x15\x81R` \x01a\x01\x9CV[`\x02T[`@Q\x90\x81R` \x01a\x01\x9CV[a\x01\xB8a\x01\xE86`\x04a\x18\x17V[a\x04FV[`@Q`\x12\x81R` \x01a\x01\x9CV[a\x01\xCCa\x051V[a\x01\xB8a\x02\x126`\x04a\x17\xEDV[a\x05@V[a\x02*a\x02%6`\x04a\x17\xEDV[a\x05\x89V[\0[a\x01\x8Fa\x02:6`\x04a\x18\x82V[a\x06\xAFV[a\x01\x8Fa\x02M6`\x04a\x19bV[a\x07QV[a\x01\xCC`\x03\x81V[a\x01\xCCa\x02h6`\x04a\x19\x84V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\0\x90\x81R` \x81\x90R`@\x90 T\x90V[a\x01\xCCa\x02\x9E6`\x04a\x19\x84V[a\x07\xD7V[a\x01\x8Fa\x08\x02V[a\x01\xB8a\x02\xB96`\x04a\x17\xEDV[a\x08\x11V[a\x01\xB8a\x02\xCC6`\x04a\x17\xEDV[a\x08\xE9V[a\x01\xCCc\x01\xE13\x80\x81V[a\x02*a\x02\xEA6`\x04a\x19\x9FV[a\x08\xF6V[a\x01\xCCa\x02\xFD6`\x04a\x1A\x12V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 \x93\x90\x94\x16\x82R\x91\x90\x91R T\x90V[a\x03\\\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x01\x9CV[a\x01\x8Fa\x03\x8F6`\x04a\x18\x82V[a\n\xB5V[a\x01\xCC`\x06T\x81V[```\x03\x80Ta\x03\xAC\x90a\x1AEV[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x03\xD8\x90a\x1AEV[\x80\x15a\x04%W\x80`\x1F\x10a\x03\xFAWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x04%V[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x04\x08W\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x90P\x90V[`\0a\x04<3\x84\x84a\x0C6V[P`\x01[\x92\x91PPV[`\0a\x04S\x84\x84\x84a\r\xE9V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 3\x84R\x90\x91R\x90 T\x82\x81\x10\x15a\x05\x19W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`(`$\x82\x01R\x7FERC20: transfer amount exceeds a`D\x82\x01R\x7Fllowance\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[a\x05&\x853\x85\x84\x03a\x0C6V[P`\x01\x94\x93PPPPV[`\0a\x05;a\x10\x9EV[\x90P\x90V[3`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x16\x84R\x90\x91R\x81 T\x90\x91a\x04<\x91\x85\x90a\x05\x84\x90\x86\x90a\x1A\xC2V[a\x0C6V[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x05\xF8W`@Q\x7F\xFEr\xC3n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`d`\x03a\x06\x05`\x02T\x90V[a\x06\x0F\x91\x90a\x1A\xDAV[a\x06\x19\x91\x90a\x1B\x17V[\x81\x11\x15a\x06RW`@Q\x7F,j\xF2\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[Bc\x01\xE13\x80`\x06Ta\x06e\x91\x90a\x1A\xC2V[\x11\x15a\x06\x9DW`@Q\x7F{\x06G\x15\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[B`\x06Ua\x06\xAB\x82\x82a\x11\xD2V[PPV[```\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83`@Qa\x06\xD8\x91\x90a\x1BRV[`\0`@Q\x80\x83\x03\x81\x85Z\xF4\x91PP=\x80`\0\x81\x14a\x07\x13W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x07\x18V[``\x91P[P`@Q\x90\x93P\x90\x91Pa\x07J\x90a\x076\x90\x84\x90\x84\x90` \x01a\x1BnV[`@Q` \x81\x83\x03\x03\x81R\x90`@Ra\x12\xF2V[P\x92\x91PPV[```\0a\x07`\x83` a\x1A\xDAV[g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x07xWa\x07xa\x18SV[`@Q\x90\x80\x82R\x80`\x1F\x01`\x1F\x19\x16` \x01\x82\x01`@R\x80\x15a\x07\xA2W` \x82\x01\x81\x806\x837\x01\x90P[P\x90P`\0[\x83\x81\x10\x15a\x07\xCFW\x84\x81\x01T` \x80\x83\x02\x84\x01\x01R\x80a\x07\xC7\x81a\x1B\x96V[\x91PPa\x07\xA8V[P\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`\0\x90\x81R`\x05` R`@\x81 Ta\x04@V[```\x04\x80Ta\x03\xAC\x90a\x1AEV[3`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x16\x84R\x90\x91R\x81 T\x82\x81\x10\x15a\x08\xD2W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`%`$\x82\x01R\x7FERC20: decreased allowance below`D\x82\x01R\x7F zero\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[a\x08\xDF3\x85\x85\x84\x03a\x0C6V[P`\x01\x93\x92PPPV[`\0a\x04<3\x84\x84a\r\xE9V[\x83B\x11\x15a\t`W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FERC20Permit: expired deadline\0\0\0`D\x82\x01R`d\x01a\x05\x10V[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\x88\x88a\t\x8F\x8Ca\x12\xFAV[`@\x80Q` \x81\x01\x96\x90\x96Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x94\x85\x16\x90\x86\x01R\x92\x90\x91\x16``\x84\x01R`\x80\x83\x01R`\xA0\x82\x01R`\xC0\x81\x01\x86\x90R`\xE0\x01`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0a\t\xF7\x82a\x13/V[\x90P`\0a\n\x07\x82\x87\x87\x87a\x13\x98V[\x90P\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\n\x9EW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FERC20Permit: invalid signature\0\0`D\x82\x01R`d\x01a\x05\x10V[a\n\xA9\x8A\x8A\x8Aa\x0C6V[PPPPPPPPPPV[```\0cC!\x8E\x19`\xE0\x1B\x84\x84`@Q`$\x01a\n\xD4\x92\x91\x90a\x1B\xCFV[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x81R` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x94\x16\x93\x90\x93\x17\x90\x92R\x90Q\x90\x91P0\x90a\x0Bc\x90\x83\x90a\x1BRV[`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x0B\xA0W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x0B\xA5V[``\x91P[P\x90P\x80\x92PP`\0\x82`\x01\x84Qa\x0B\xBD\x91\x90a\x1C\x06V[\x81Q\x81\x10a\x0B\xCDWa\x0B\xCDa\x1C\x1DV[` \x01\x01Q`\xF8\x1C`\xF8\x1B~\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16`\x01`\xF8\x1B\x14\x90Pa\x0C\x18\x83`\x01\x85Qa\x0C\x14\x91\x90a\x1C\x06V[\x90RV[\x80\x15a\x0C%WPPa\x04@V[a\x0C.\x83a\x12\xF2V[PP\x92\x91PPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16a\x0C\xD8W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`$\x80\x82\x01R\x7FERC20: approve from the zero add`D\x82\x01R\x7Fress\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16a\r{W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\"`$\x82\x01R\x7FERC20: approve to the zero addre`D\x82\x01R\x7Fss\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x81\x16`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 \x94\x87\x16\x80\x84R\x94\x82R\x91\x82\x90 \x85\x90U\x90Q\x84\x81R\x7F\x8C[\xE1\xE5\xEB\xEC}[\xD1OqB}\x1E\x84\xF3\xDD\x03\x14\xC0\xF7\xB2)\x1E[ \n\xC8\xC7\xC3\xB9%\x91\x01`@Q\x80\x91\x03\x90\xA3PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16a\x0E\x8CW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`%`$\x82\x01R\x7FERC20: transfer from the zero ad`D\x82\x01R\x7Fdress\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16a\x0F/W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`#`$\x82\x01R\x7FERC20: transfer to the zero addr`D\x82\x01R\x7Fess\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 T\x81\x81\x10\x15a\x0F\xE5W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FERC20: transfer amount exceeds b`D\x82\x01R\x7Falance\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x85\x16`\0\x90\x81R` \x81\x90R`@\x80\x82 \x85\x85\x03\x90U\x91\x85\x16\x81R\x90\x81 \x80T\x84\x92\x90a\x10)\x90\x84\x90a\x1A\xC2V[\x92PP\x81\x90UP\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x84`@Qa\x10\x8F\x91\x81R` \x01\x90V[`@Q\x80\x91\x03\x90\xA3[PPPPV[`\x000s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14\x80\x15a\x11\x04WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0F\x14[\x15a\x11.WP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[P`@\x80Q\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0` \x80\x83\x01\x91\x90\x91R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x84\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0``\x83\x01RF`\x80\x83\x01R0`\xA0\x80\x84\x01\x91\x90\x91R\x83Q\x80\x84\x03\x90\x91\x01\x81R`\xC0\x90\x92\x01\x90\x92R\x80Q\x91\x01 \x90V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16a\x12OW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1F`$\x82\x01R\x7FERC20: mint to the zero address\0`D\x82\x01R`d\x01a\x05\x10V[\x80`\x02`\0\x82\x82Ta\x12a\x91\x90a\x1A\xC2V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16`\0\x90\x81R` \x81\x90R`@\x81 \x80T\x83\x92\x90a\x12\x9B\x90\x84\x90a\x1A\xC2V[\x90\x91UPP`@Q\x81\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x90`\0\x90\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x90` \x01`@Q\x80\x91\x03\x90\xA3PPV[\x80Q` \x82\x01\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`\0\x90\x81R`\x05` R`@\x90 \x80T`\x01\x81\x01\x82U\x90[P\x91\x90PV[`\0a\x04@a\x13=`\0\xFD[PP`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01Q\x91PPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16a\x14\xC8W`\0`\x01\x92P\x92PPa\x14\xCFV[\x91P`\0\x90P[\x94P\x94\x92PPPV[`\0\x81`\x04\x81\x11\x15a\x14\xECWa\x14\xECa\x1CLV[\x14\x15a\x14\xF5WPV[`\x01\x81`\x04\x81\x11\x15a\x15\tWa\x15\ta\x1CLV[\x14\x15a\x15qW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FECDSA: invalid signature\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x05\x10V[`\x02\x81`\x04\x81\x11\x15a\x15\x85Wa\x15\x85a\x1CLV[\x14\x15a\x15\xEDW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1F`$\x82\x01R\x7FECDSA: invalid signature length\0`D\x82\x01R`d\x01a\x05\x10V[`\x03\x81`\x04\x81\x11\x15a\x16\x01Wa\x16\x01a\x1CLV[\x14\x15a\x16\x8FW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\"`$\x82\x01R\x7FECDSA: invalid signature 's' val`D\x82\x01R\x7Fue\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[`\x04\x81`\x04\x81\x11\x15a\x16\xA3Wa\x16\xA3a\x1CLV[\x14\x15a\x171W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\"`$\x82\x01R\x7FECDSA: invalid signature 'v' val`D\x82\x01R\x7Fue\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x05\x10V[PV[`\0[\x83\x81\x10\x15a\x17OW\x81\x81\x01Q\x83\x82\x01R` \x01a\x177V[\x83\x81\x11\x15a\x10\x98WPP`\0\x91\x01RV[`\0\x81Q\x80\x84Ra\x17x\x81` \x86\x01` \x86\x01a\x174V[`\x1F\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x92\x90\x92\x01` \x01\x92\x91PPV[` \x81R`\0a\x17\xBD` \x83\x01\x84a\x17`V[\x93\x92PPPV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x17\xE8W`\0\x80\xFD[\x91\x90PV[`\0\x80`@\x83\x85\x03\x12\x15a\x18\0W`\0\x80\xFD[a\x18\t\x83a\x17\xC4V[\x94` \x93\x90\x93\x015\x93PPPV[`\0\x80`\0``\x84\x86\x03\x12\x15a\x18,W`\0\x80\xFD[a\x185\x84a\x17\xC4V[\x92Pa\x18C` \x85\x01a\x17\xC4V[\x91P`@\x84\x015\x90P\x92P\x92P\x92V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`A`\x04R`$`\0\xFD[`\0\x80`@\x83\x85\x03\x12\x15a\x18\x95W`\0\x80\xFD[a\x18\x9E\x83a\x17\xC4V[\x91P` \x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x18\xBBW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x18\xCFW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x18\xE1Wa\x18\xE1a\x18SV[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x81\x16`?\x01\x16\x81\x01\x90\x83\x82\x11\x81\x83\x10\x17\x15a\x19'Wa\x19'a\x18SV[\x81`@R\x82\x81R\x88` \x84\x87\x01\x01\x11\x15a\x19@W`\0\x80\xFD[\x82` \x86\x01` \x83\x017`\0` \x84\x83\x01\x01R\x80\x95PPPPPP\x92P\x92\x90PV[`\0\x80`@\x83\x85\x03\x12\x15a\x19uW`\0\x80\xFD[PP\x805\x92` \x90\x91\x015\x91PV[`\0` \x82\x84\x03\x12\x15a\x19\x96W`\0\x80\xFD[a\x17\xBD\x82a\x17\xC4V[`\0\x80`\0\x80`\0\x80`\0`\xE0\x88\x8A\x03\x12\x15a\x19\xBAW`\0\x80\xFD[a\x19\xC3\x88a\x17\xC4V[\x96Pa\x19\xD1` \x89\x01a\x17\xC4V[\x95P`@\x88\x015\x94P``\x88\x015\x93P`\x80\x88\x015`\xFF\x81\x16\x81\x14a\x19\xF5W`\0\x80\xFD[\x96\x99\x95\x98P\x93\x96\x92\x95\x94`\xA0\x84\x015\x94P`\xC0\x90\x93\x015\x92\x91PPV[`\0\x80`@\x83\x85\x03\x12\x15a\x1A%W`\0\x80\xFD[a\x1A.\x83a\x17\xC4V[\x91Pa\x1A<` \x84\x01a\x17\xC4V[\x90P\x92P\x92\x90PV[`\x01\x81\x81\x1C\x90\x82\x16\x80a\x1AYW`\x7F\x82\x16\x91P[` \x82\x10\x81\x14\x15a\x13)W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\"`\x04R`$`\0\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x11`\x04R`$`\0\xFD[`\0\x82\x19\x82\x11\x15a\x1A\xD5Wa\x1A\xD5a\x1A\x93V[P\x01\x90V[`\0\x81\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x04\x83\x11\x82\x15\x15\x16\x15a\x1B\x12Wa\x1B\x12a\x1A\x93V[P\x02\x90V[`\0\x82a\x1BMW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x12`\x04R`$`\0\xFD[P\x04\x90V[`\0\x82Qa\x1Bd\x81\x84` \x87\x01a\x174V[\x91\x90\x91\x01\x92\x91PPV[`\0\x83Qa\x1B\x80\x81\x84` \x88\x01a\x174V[\x92\x15\x15`\xF8\x1B\x91\x90\x92\x01\x90\x81R`\x01\x01\x92\x91PPV[`\0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x14\x15a\x1B\xC8Wa\x1B\xC8a\x1A\x93V[P`\x01\x01\x90V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x81R`@` \x82\x01R`\0a\x1B\xFE`@\x83\x01\x84a\x17`V[\x94\x93PPPPV[`\0\x82\x82\x10\x15a\x1C\x18Wa\x1C\x18a\x1A\x93V[P\x03\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`2`\x04R`$`\0\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`!`\x04R`$`\0\xFD\xFE\xA2dipfsX\"\x12 S\tT\xA1\xB4\n\x0E = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: AlreadyInflated) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for AlreadyInflated { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for AlreadyInflated { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [123u8, 6u8, 71u8, 21u8]; + const SIGNATURE: &'static str = "AlreadyInflated()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ExceedingMintCap()` and selector `0x2c6af208`. + ```solidity + error ExceedingMintCap(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ExceedingMintCap; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ExceedingMintCap) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ExceedingMintCap { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ExceedingMintCap { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [44u8, 106u8, 242u8, 8u8]; + const SIGNATURE: &'static str = "ExceedingMintCap()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OnlyCowDao()` and selector `0xfe72c36e`. + ```solidity + error OnlyCowDao(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OnlyCowDao; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OnlyCowDao) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OnlyCowDao { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OnlyCowDao { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [254u8, 114u8, 195u8, 110u8]; + const SIGNATURE: &'static str = "OnlyCowDao()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address initialTokenHolder, address cowDao, uint256 totalSupply); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub initialTokenHolder: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub cowDao: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub totalSupply: alloy_sol_types::private::primitives::aliases::U256, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.initialTokenHolder, value.cowDao, value.totalSupply) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + initialTokenHolder: tuple.0, + cowDao: tuple.1, + totalSupply: tuple.2, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.initialTokenHolder, + ), + ::tokenize( + &self.cowDao, + ), + as alloy_sol_types::SolType>::tokenize( + &self.totalSupply, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external view returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address,uint256)` and selector `0x40c10f19`. + ```solidity + function mint(address target, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`mint(address,uint256)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + (value.target, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl mintReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = mintReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [64u8, 193u8, 15u8, 25u8]; + const SIGNATURE: &'static str = "mint(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.target, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + mintReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `simulateDelegatecall(address,bytes)` and selector `0xf84436bd`. + ```solidity + function simulateDelegatecall(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateDelegatecallCall { + #[allow(missing_docs)] + pub targetContract: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub calldataPayload: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`simulateDelegatecall(address,bytes)`](simulateDelegatecallCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateDelegatecallReturn { + #[allow(missing_docs)] + pub response: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateDelegatecallCall) -> Self { + (value.targetContract, value.calldataPayload) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateDelegatecallCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + targetContract: tuple.0, + calldataPayload: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Bytes,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateDelegatecallReturn) -> Self { + (value.response,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateDelegatecallReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { response: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for simulateDelegatecallCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::Bytes; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 68u8, 54u8, 189u8]; + const SIGNATURE: &'static str = "simulateDelegatecall(address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.targetContract, + ), + ::tokenize( + &self.calldataPayload, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: simulateDelegatecallReturn = r.into(); + r.response + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: simulateDelegatecallReturn = r.into(); + r.response + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`CowProtocolToken`](self) function calls. + #[derive(Clone)] + pub enum CowProtocolTokenCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + simulateDelegatecall(simulateDelegatecallCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl CowProtocolTokenCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [64u8, 193u8, 15u8, 25u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + [248u8, 68u8, 54u8, 189u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(mint), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ::core::stringify!(simulateDelegatecall), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowProtocolTokenCalls { + const COUNT: usize = 13usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CowProtocolTokenCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::simulateDelegatecall(_) => { + ::SELECTOR + } + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::allowance) + } + allowance + }, + { + fn simulateDelegatecall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CowProtocolTokenCalls::simulateDelegatecall) + } + simulateDelegatecall + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowProtocolTokenCalls, + >] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowProtocolTokenCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowProtocolTokenCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::nonces) + } + nonces + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::transfer) + } + transfer + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenCalls::allowance) + } + allowance + }, + { + fn simulateDelegatecall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowProtocolTokenCalls::simulateDelegatecall) + } + simulateDelegatecall + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::simulateDelegatecall(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::simulateDelegatecall(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CowProtocolToken`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowProtocolTokenErrors { + #[allow(missing_docs)] + AlreadyInflated(AlreadyInflated), + #[allow(missing_docs)] + ExceedingMintCap(ExceedingMintCap), + #[allow(missing_docs)] + OnlyCowDao(OnlyCowDao), + } + impl CowProtocolTokenErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [44u8, 106u8, 242u8, 8u8], + [123u8, 6u8, 71u8, 21u8], + [254u8, 114u8, 195u8, 110u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(ExceedingMintCap), + ::core::stringify!(AlreadyInflated), + ::core::stringify!(OnlyCowDao), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CowProtocolTokenErrors { + const COUNT: usize = 3usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CowProtocolTokenErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::AlreadyInflated(_) => { + ::SELECTOR + } + Self::ExceedingMintCap(_) => { + ::SELECTOR + } + Self::OnlyCowDao(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[ + { + fn ExceedingMintCap( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowProtocolTokenErrors::ExceedingMintCap) + } + ExceedingMintCap + }, + { + fn AlreadyInflated( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowProtocolTokenErrors::AlreadyInflated) + } + AlreadyInflated + }, + { + fn OnlyCowDao( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(CowProtocolTokenErrors::OnlyCowDao) + } + OnlyCowDao + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + CowProtocolTokenErrors, + >] = &[ + { + fn ExceedingMintCap( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowProtocolTokenErrors::ExceedingMintCap) + } + ExceedingMintCap + }, + { + fn AlreadyInflated( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CowProtocolTokenErrors::AlreadyInflated) + } + AlreadyInflated + }, + { + fn OnlyCowDao(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CowProtocolTokenErrors::OnlyCowDao) + } + OnlyCowDao + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::AlreadyInflated(inner) => { + ::abi_encoded_size(inner) + } + Self::ExceedingMintCap(inner) => { + ::abi_encoded_size(inner) + } + Self::OnlyCowDao(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::AlreadyInflated(inner) => { + ::abi_encode_raw(inner, out) + } + Self::ExceedingMintCap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::OnlyCowDao(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CowProtocolToken`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CowProtocolTokenEvents { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl CowProtocolTokenEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = + &[::core::stringify!(Approval), ::core::stringify!(Transfer)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for CowProtocolTokenEvents { + const COUNT: usize = 2usize; + const NAME: &'static str = "CowProtocolTokenEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for CowProtocolTokenEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CowProtocolToken`](self) contract instance. + + See the [wrapper's documentation](`CowProtocolTokenInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CowProtocolTokenInstance { + CowProtocolTokenInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + initialTokenHolder: alloy_sol_types::private::Address, + cowDao: alloy_sol_types::private::Address, + totalSupply: alloy_sol_types::private::primitives::aliases::U256, + ) -> impl ::core::future::Future>> + { + CowProtocolTokenInstance::::deploy( + __provider, + initialTokenHolder, + cowDao, + totalSupply, + ) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + initialTokenHolder: alloy_sol_types::private::Address, + cowDao: alloy_sol_types::private::Address, + totalSupply: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::RawCallBuilder { + CowProtocolTokenInstance::::deploy_builder( + __provider, + initialTokenHolder, + cowDao, + totalSupply, + ) + } + /**A [`CowProtocolToken`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CowProtocolToken`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CowProtocolTokenInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CowProtocolTokenInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CowProtocolTokenInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CowProtocolTokenInstance + { + /**Creates a new wrapper around an on-chain [`CowProtocolToken`](self) contract instance. + + See the [wrapper's documentation](`CowProtocolTokenInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + initialTokenHolder: alloy_sol_types::private::Address, + cowDao: alloy_sol_types::private::Address, + totalSupply: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::Result> { + let call_builder = + Self::deploy_builder(__provider, initialTokenHolder, cowDao, totalSupply); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + initialTokenHolder: alloy_sol_types::private::Address, + cowDao: alloy_sol_types::private::Address, + totalSupply: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + initialTokenHolder, + cowDao, + totalSupply, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CowProtocolTokenInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CowProtocolTokenInstance { + CowProtocolTokenInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CowProtocolTokenInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + target: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { target, amount }) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`simulateDelegatecall`] + /// function. + pub fn simulateDelegatecall( + &self, + targetContract: alloy_sol_types::private::Address, + calldataPayload: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, simulateDelegatecallCall, N> { + self.call_builder(&simulateDelegatecallCall { + targetContract, + calldataPayload, + }) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CowProtocolTokenInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = CowProtocolToken::CowProtocolTokenInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x177127622c4A00F3d409B75571e12cB3c8973d3c"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0xc694a91e6b071bF030A18BD3053A7fE09B6DaE69"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xcb8b5CD20BdCaea9a010aC1F8d835824F5C87A04"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x0625aFB445C3B6B7B929342a04A22599fd5dBB59"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/cowswapethflow/Cargo.toml b/contracts/generated/contracts-generated/cowswapethflow/Cargo.toml new file mode 100644 index 0000000000..a0532ea4de --- /dev/null +++ b/contracts/generated/contracts-generated/cowswapethflow/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowswapethflow" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowswapethflow/src/lib.rs b/contracts/generated/contracts-generated/cowswapethflow/src/lib.rs new file mode 100644 index 0000000000..272812c50a --- /dev/null +++ b/contracts/generated/contracts-generated/cowswapethflow/src/lib.rs @@ -0,0 +1,5329 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library EthFlowOrder { + struct Data { address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; bytes32 appData; uint256 feeAmount; uint32 validTo; bool partiallyFillable; int64 quoteId; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod EthFlowOrder { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; bytes32 appData; uint256 feeAmount; uint32 validTo; bool partiallyFillable; int64 quoteId; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub buyToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub validTo: u32, + #[allow(missing_docs)] + pub partiallyFillable: bool, + #[allow(missing_docs)] + pub quoteId: i64, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Int<64>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + u32, + bool, + i64, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + ( + value.buyToken, + value.receiver, + value.sellAmount, + value.buyAmount, + value.appData, + value.feeAmount, + value.validTo, + value.partiallyFillable, + value.quoteId, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + buyToken: tuple.0, + receiver: tuple.1, + sellAmount: tuple.2, + buyAmount: tuple.3, + appData: tuple.4, + feeAmount: tuple.5, + validTo: tuple.6, + partiallyFillable: tuple.7, + quoteId: tuple.8, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.buyToken, + ), + ::tokenize( + &self.receiver, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellAmount), + as alloy_sol_types::SolType>::tokenize(&self.buyAmount), + as alloy_sol_types::SolType>::tokenize(&self.appData), + as alloy_sol_types::SolType>::tokenize(&self.feeAmount), + as alloy_sol_types::SolType>::tokenize(&self.validTo), + ::tokenize( + &self.partiallyFillable, + ), + as alloy_sol_types::SolType>::tokenize(&self.quoteId), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address buyToken,address receiver,uint256 sellAmount,uint256 \ + buyAmount,bytes32 appData,uint256 feeAmount,uint32 validTo,bool \ + partiallyFillable,int64 quoteId)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.buyToken, + ) + .0, + ::eip712_data_word( + &self.receiver, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.sellAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.buyAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.appData) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.feeAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.validTo) + .0, + ::eip712_data_word( + &self.partiallyFillable, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.quoteId) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.buyToken, + ) + + ::topic_preimage_length( + &rust.receiver, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.appData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.feeAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.validTo, + ) + + ::topic_preimage_length( + &rust.partiallyFillable, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.quoteId, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.buyToken, + out, + ); + ::encode_topic_preimage( + &rust.receiver, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.appData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.feeAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.validTo, + out, + ); + ::encode_topic_preimage( + &rust.partiallyFillable, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.quoteId, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`EthFlowOrder`](self) contract instance. + + See the [wrapper's documentation](`EthFlowOrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> EthFlowOrderInstance { + EthFlowOrderInstance::::new(address, __provider) + } + /**A [`EthFlowOrder`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`EthFlowOrder`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct EthFlowOrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for EthFlowOrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("EthFlowOrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + EthFlowOrderInstance + { + /**Creates a new wrapper around an on-chain [`EthFlowOrder`](self) contract instance. + + See the [wrapper's documentation](`EthFlowOrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl EthFlowOrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> EthFlowOrderInstance { + EthFlowOrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + EthFlowOrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + EthFlowOrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Order { + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Order { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub sellToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub buyToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub validTo: u32, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub kind: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub partiallyFillable: bool, + #[allow(missing_docs)] + pub sellTokenBalance: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub buyTokenBalance: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u32, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::FixedBytes<32>, + bool, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + ( + value.sellToken, + value.buyToken, + value.receiver, + value.sellAmount, + value.buyAmount, + value.validTo, + value.appData, + value.feeAmount, + value.kind, + value.partiallyFillable, + value.sellTokenBalance, + value.buyTokenBalance, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sellToken: tuple.0, + buyToken: tuple.1, + receiver: tuple.2, + sellAmount: tuple.3, + buyAmount: tuple.4, + validTo: tuple.5, + appData: tuple.6, + feeAmount: tuple.7, + kind: tuple.8, + partiallyFillable: tuple.9, + sellTokenBalance: tuple.10, + buyTokenBalance: tuple.11, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.sellToken, + ), + ::tokenize( + &self.buyToken, + ), + ::tokenize( + &self.receiver, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellAmount), + as alloy_sol_types::SolType>::tokenize(&self.buyAmount), + as alloy_sol_types::SolType>::tokenize(&self.validTo), + as alloy_sol_types::SolType>::tokenize(&self.appData), + as alloy_sol_types::SolType>::tokenize(&self.feeAmount), + as alloy_sol_types::SolType>::tokenize(&self.kind), + ::tokenize( + &self.partiallyFillable, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellTokenBalance), + as alloy_sol_types::SolType>::tokenize(&self.buyTokenBalance), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address sellToken,address buyToken,address receiver,uint256 \ + sellAmount,uint256 buyAmount,uint32 validTo,bytes32 appData,uint256 \ + feeAmount,bytes32 kind,bool partiallyFillable,bytes32 \ + sellTokenBalance,bytes32 buyTokenBalance)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.sellToken, + ) + .0, + ::eip712_data_word( + &self.buyToken, + ) + .0, + ::eip712_data_word( + &self.receiver, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.sellAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.buyAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.validTo) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.appData) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.feeAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.kind) + .0, + ::eip712_data_word( + &self.partiallyFillable, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.sellTokenBalance, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.buyTokenBalance, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.sellToken, + ) + + ::topic_preimage_length( + &rust.buyToken, + ) + + ::topic_preimage_length( + &rust.receiver, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.validTo, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.appData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.feeAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.kind) + + ::topic_preimage_length( + &rust.partiallyFillable, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellTokenBalance, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyTokenBalance, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.sellToken, + out, + ); + ::encode_topic_preimage( + &rust.buyToken, + out, + ); + ::encode_topic_preimage( + &rust.receiver, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.validTo, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.appData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.feeAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.kind, + out, + ); + ::encode_topic_preimage( + &rust.partiallyFillable, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellTokenBalance, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyTokenBalance, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2OrderInstance { + GPv2OrderInstance::::new(address, __provider) + } + /**A [`GPv2Order`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Order`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2OrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2OrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2OrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2OrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2OrderInstance { + GPv2OrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library ICoWSwapOnchainOrders { + type OnchainSigningScheme is uint8; + struct OnchainSignature { OnchainSigningScheme scheme; bytes data; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ICoWSwapOnchainOrders { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OnchainSigningScheme(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl OnchainSigningScheme { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for OnchainSigningScheme { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: OnchainSigningScheme) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for OnchainSigningScheme { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for OnchainSigningScheme { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct OnchainSignature { OnchainSigningScheme scheme; bytes data; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OnchainSignature { + #[allow(missing_docs)] + pub scheme: ::RustType, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (OnchainSigningScheme, alloy_sol_types::sol_data::Bytes); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OnchainSignature) -> Self { + (value.scheme, value.data) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OnchainSignature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + scheme: tuple.0, + data: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for OnchainSignature { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for OnchainSignature { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize(&self.scheme), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for OnchainSignature { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for OnchainSignature { + const NAME: &'static str = "OnchainSignature"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed("OnchainSignature(uint8 scheme,bytes data)") + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.scheme, + ) + .0, + ::eip712_data_word( + &self.data, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for OnchainSignature { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.scheme, + ) + + ::topic_preimage_length( + &rust.data, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.scheme, + out, + ); + ::encode_topic_preimage( + &rust.data, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ICoWSwapOnchainOrders`](self) contract instance. + + See the [wrapper's documentation](`ICoWSwapOnchainOrdersInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ICoWSwapOnchainOrdersInstance { + ICoWSwapOnchainOrdersInstance::::new(address, __provider) + } + /**A [`ICoWSwapOnchainOrders`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ICoWSwapOnchainOrders`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ICoWSwapOnchainOrdersInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ICoWSwapOnchainOrdersInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ICoWSwapOnchainOrdersInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ICoWSwapOnchainOrdersInstance + { + /**Creates a new wrapper around an on-chain [`ICoWSwapOnchainOrders`](self) contract instance. + + See the [wrapper's documentation](`ICoWSwapOnchainOrdersInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ICoWSwapOnchainOrdersInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ICoWSwapOnchainOrdersInstance { + ICoWSwapOnchainOrdersInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ICoWSwapOnchainOrdersInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ICoWSwapOnchainOrdersInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library EthFlowOrder { + struct Data { + address buyToken; + address receiver; + uint256 sellAmount; + uint256 buyAmount; + bytes32 appData; + uint256 feeAmount; + uint32 validTo; + bool partiallyFillable; + int64 quoteId; + } +} + +library GPv2Order { + struct Data { + address sellToken; + address buyToken; + address receiver; + uint256 sellAmount; + uint256 buyAmount; + uint32 validTo; + bytes32 appData; + uint256 feeAmount; + bytes32 kind; + bool partiallyFillable; + bytes32 sellTokenBalance; + bytes32 buyTokenBalance; + } +} + +library ICoWSwapOnchainOrders { + type OnchainSigningScheme is uint8; + struct OnchainSignature { + OnchainSigningScheme scheme; + bytes data; + } +} + +interface CoWSwapEthFlow { + error EthTransferFailed(); + error IncorrectEthAmount(); + error NotAllowedToInvalidateOrder(bytes32 orderHash); + error NotAllowedZeroSellAmount(); + error OrderIsAlreadyExpired(); + error OrderIsAlreadyOwned(bytes32 orderHash); + error ReceiverMustBeSet(); + + event OrderInvalidation(bytes orderUid); + event OrderPlacement(address indexed sender, GPv2Order.Data order, ICoWSwapOnchainOrders.OnchainSignature signature, bytes data); + event OrderRefund(bytes orderUid, address indexed refunder); + + constructor(address _cowSwapSettlement, address _wrappedNativeToken); + + receive() external payable; + + function createOrder(EthFlowOrder.Data memory order) external payable returns (bytes32 orderHash); + function invalidateOrder(EthFlowOrder.Data memory order) external; + function invalidateOrdersIgnoringNotAllowed(EthFlowOrder.Data[] memory orderArray) external; + function isValidSignature(bytes32 orderHash, bytes memory) external view returns (bytes4); + function orders(bytes32) external view returns (address owner, uint32 validTo); + function unwrap(uint256 amount) external; + function wrap(uint256 amount) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_cowSwapSettlement", + "type": "address", + "internalType": "contract ICoWSwapSettlement" + }, + { + "name": "_wrappedNativeToken", + "type": "address", + "internalType": "contract IWrappedNativeToken" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "createOrder", + "inputs": [ + { + "name": "order", + "type": "tuple", + "internalType": "struct EthFlowOrder.Data", + "components": [ + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "quoteId", + "type": "int64", + "internalType": "int64" + } + ] + } + ], + "outputs": [ + { + "name": "orderHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "invalidateOrder", + "inputs": [ + { + "name": "order", + "type": "tuple", + "internalType": "struct EthFlowOrder.Data", + "components": [ + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "quoteId", + "type": "int64", + "internalType": "int64" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "invalidateOrdersIgnoringNotAllowed", + "inputs": [ + { + "name": "orderArray", + "type": "tuple[]", + "internalType": "struct EthFlowOrder.Data[]", + "components": [ + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "quoteId", + "type": "int64", + "internalType": "int64" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "orders", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unwrap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "wrap", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "OrderInvalidation", + "inputs": [ + { + "name": "orderUid", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OrderPlacement", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "order", + "type": "tuple", + "indexed": false, + "internalType": "struct GPv2Order.Data", + "components": [ + { + "name": "sellToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "kind", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sellTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "buyTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "signature", + "type": "tuple", + "indexed": false, + "internalType": "struct ICoWSwapOnchainOrders.OnchainSignature", + "components": [ + { + "name": "scheme", + "type": "uint8", + "internalType": "enum ICoWSwapOnchainOrders.OnchainSigningScheme" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OrderRefund", + "inputs": [ + { + "name": "orderUid", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "refunder", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "EthTransferFailed", + "inputs": [] + }, + { + "type": "error", + "name": "IncorrectEthAmount", + "inputs": [] + }, + { + "type": "error", + "name": "NotAllowedToInvalidateOrder", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "NotAllowedZeroSellAmount", + "inputs": [] + }, + { + "type": "error", + "name": "OrderIsAlreadyExpired", + "inputs": [] + }, + { + "type": "error", + "name": "OrderIsAlreadyOwned", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "ReceiverMustBeSet", + "inputs": [] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CoWSwapEthFlow { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60e06040523480156200001157600080fd5b5060405162001b2a38038062001b2a83398101604081905262000034916200021e565b816200004b816200015260201b6200089b1760201c565b608052506001600160a01b0380831660a081905290821660c081905260408051634daa966160e11b81529051919263095ea7b3929091639b552cc291600480830192602092919082900301816000875af1158015620000ae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000d491906200025d565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260001960248201526044016020604051808303816000875af115801562000123573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000149919062000284565b505050620002a8565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c918101919091527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf606082015246608082018190526001600160a01b03831660a083015260009160c00160405160208183030381529060405280519060200120915050919050565b6001600160a01b03811681146200021b57600080fd5b50565b600080604083850312156200023257600080fd5b82516200023f8162000205565b6020840151909250620002528162000205565b809150509250929050565b6000602082840312156200027057600080fd5b81516200027d8162000205565b9392505050565b6000602082840312156200029757600080fd5b815180151581146200027d57600080fd5b60805160a05160c0516118216200030960003960008181610129015281816105ff015281816107ad0152818161082501528181610c3301526110310152600081816102ce0152610f4b015260008181610bf70152610cd901526118216000f3fe6080604052600436106100b55760003560e01c80637bc41b9611610069578063de0e9a3e1161004e578063de0e9a3e1461027c578063ea598cb01461029c578063ec30bb88146102bc57600080fd5b80637bc41b96146101c85780639c3f1e90146101e857600080fd5b8063322bba211161009a578063322bba21146101705780634c84c1c8146101915780634cb76498146101a857600080fd5b80631626ba7e146100c157806317fcb39b1461011757600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc36600461126e565b6102f0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010e565b61018361017e36600461132b565b6103de565b60405190815260200161010e565b34801561019d57600080fd5b506101a6610720565b005b3480156101b457600080fd5b506101a66101c3366004611344565b61072b565b3480156101d457600080fd5b506101a66101e336600461132b565b610770565b3480156101f457600080fd5b5061024b6102033660046113ba565b60006020819052908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900463ffffffff1682565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835263ffffffff90911660208301520161010e565b34801561028857600080fd5b506101a66102973660046113ba565b61077e565b3480156102a857600080fd5b506101a66102b73660046113ba565b610821565b3480156102c857600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b60008281526020818152604080832081518083019092525473ffffffffffffffffffffffffffffffffffffffff81168083527401000000000000000000000000000000000000000090910463ffffffff1692820192909252901580159061036f5750805173ffffffffffffffffffffffffffffffffffffffff90811614155b8015610385575042816020015163ffffffff1610155b156103b357507f1626ba7e0000000000000000000000000000000000000000000000000000000090506103d8565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b92915050565b60006103f260a08301356040840135611402565b341461042a576040517f8b6ebb4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160400135600003610468576040517feaec5c9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4261047960e0840160c0850161142e565b63ffffffff1610156104b7576040517f89bb260100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152338152600090602081016104db60e0860160c0870161142e565b63ffffffff169052604080518082019091529091506000908082815260200130604051602001610536919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905290529050600061057c61012086016101008701611462565b6020808501516040516105c393920160c09290921b825260e01b7fffffffff00000000000000000000000000000000000000000000000000000000166008820152600c0190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052835190915061063a906106337f000000000000000000000000000000000000000000000000000000000000000061062d368a90038a018a6114b1565b9061095b565b8484610b2a565b60008181526020819052604090205490945073ffffffffffffffffffffffffffffffffffffffff16156106a1576040517f56a1d2b2000000000000000000000000000000000000000000000000000000008152600481018590526024015b60405180910390fd5b505060008281526020818152604090912082518154929093015163ffffffff1674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff90931692909217179055919050565b61072947610821565b565b60005b8181101561076b5761075983838381811061074b5761074b61154b565b905061012002016000610c2c565b806107638161157a565b91505061072e565b505050565b61077b816001610c2c565b50565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561080657600080fd5b505af115801561081a573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461081a576040519150601f19603f3d011682016040523d82523d6000602084013e61081a565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c918101919091527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf6060820152466080820181905273ffffffffffffffffffffffffffffffffffffffff831660a083015260009160c00160405160208183030381529060405280519060200120915050919050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201529083015173ffffffffffffffffffffffffffffffffffffffff16610a0a576040517fefc9ccdf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518061018001604052808373ffffffffffffffffffffffffffffffffffffffff168152602001846000015173ffffffffffffffffffffffffffffffffffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015181526020018460600151815260200163ffffffff80168152602001846080015181526020018460a0015181526020017ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677581526020018460e00151151581526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981526020017f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9815250905092915050565b60008473ffffffffffffffffffffffffffffffffffffffff167fcf5f9de2984132265203b5c335b25727702ca77262ff622e136baa7362bf1da9858585604051610b7693929190611676565b60405180910390a25050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f190100000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006002820152602281019190915260429020919050565b6000610c617f000000000000000000000000000000000000000000000000000000000000000061062d368690038601866114b1565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604080517f190100000000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600282015260228101929092526042909120600081815260208181529083902083518085019094525473ffffffffffffffffffffffffffffffffffffffff8082168086527401000000000000000000000000000000000000000090920463ffffffff1692850183905294955091934290911015911480610d8d5750815173ffffffffffffffffffffffffffffffffffffffff16155b80610db75750808015610db75750815173ffffffffffffffffffffffffffffffffffffffff163314155b15610dff578415610df7576040517ff8cc70ce00000000000000000000000000000000000000000000000000000000815260048101849052602401610698565b505050505050565b60008381526020818152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff1790558051603880825260608201909252918201818036833750505060a0860151909150610e7a90829086903090611149565b8115610ebc577fb8bad102ac8bbacfef31ff1c906ec6d951c230b4dce750bb0376b812ad35852a81604051610eaf9190611790565b60405180910390a1610f0b565b3373ffffffffffffffffffffffffffffffffffffffff167f195271068a288191e4b265c641a56b9832919f69e9e7d6c2f31ba40278aeb85a82604051610f029190611790565b60405180910390a25b6040517f2479fb6e00000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690632479fb6e90610f80908590600401611790565b6020604051808303816000875af1158015610f9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc391906117a3565b90506000808760600151838960e001510281610fe157610fe16117bc565b048860e00151039050808389606001510301915050804710156110a4576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815247820360048201819052907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561108a57600080fd5b505af115801561109e573d6000803e3d6000fd5b50505050505b845160405160009173ffffffffffffffffffffffffffffffffffffffff169083908381818185875af1925050503d80600081146110fd576040519150601f19603f3d011682016040523d82523d6000602084013e611102565b606091505b505090508061113d576040517f6d963f8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050505050565b60388451146111b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f77000000000000006044820152606401610698565b60388401526034830152602090910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611219576112196111c6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611266576112666111c6565b604052919050565b6000806040838503121561128157600080fd5b8235915060208084013567ffffffffffffffff808211156112a157600080fd5b818601915086601f8301126112b557600080fd5b8135818111156112c7576112c76111c6565b6112f7847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161121f565b9150808252878482850101111561130d57600080fd5b80848401858401376000848284010152508093505050509250929050565b6000610120828403121561133e57600080fd5b50919050565b6000806020838503121561135757600080fd5b823567ffffffffffffffff8082111561136f57600080fd5b818501915085601f83011261138357600080fd5b81358181111561139257600080fd5b866020610120830285010111156113a857600080fd5b60209290920196919550909350505050565b6000602082840312156113cc57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156103d8576103d86113d3565b803563ffffffff8116811461142957600080fd5b919050565b60006020828403121561144057600080fd5b61144982611415565b9392505050565b8035600781900b811461142957600080fd5b60006020828403121561147457600080fd5b61144982611450565b803573ffffffffffffffffffffffffffffffffffffffff8116811461142957600080fd5b8035801515811461142957600080fd5b600061012082840312156114c457600080fd5b6114cc6111f5565b6114d58361147d565b81526114e36020840161147d565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015261151c60c08401611415565b60c082015261152d60e084016114a1565b60e0820152610100611540818501611450565b908201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036115ab576115ab6113d3565b5060010190565b6000815180845260005b818110156115d8576020818501810151868301820152016115bc565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6000815160028110611651577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8084525060208201516040602085015261166e60408501826115b2565b949350505050565b835173ffffffffffffffffffffffffffffffffffffffff16815260006101c060208601516116bc602085018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408601516116e4604085018273ffffffffffffffffffffffffffffffffffffffff169052565b50606086015160608401526080860151608084015260a086015161171060a085018263ffffffff169052565b5060c086015160c084015260e086015160e0840152610100808701518185015250610120808701516117458286018215159052565b505061014086810151908401526101608087015190840152610180830181905261177181840186611616565b90508281036101a084015261178681856115b2565b9695505050505050565b60208152600061144960208301846115b2565b6000602082840312156117b557600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220d3219a243fb3b7683c6c6a0918144885c8551f0fd87b19a0e7355ed3d10e937064736f6c63430008100033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xE0`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`@Qb\0\x1B*8\x03\x80b\0\x1B*\x839\x81\x01`@\x81\x90Rb\0\x004\x91b\0\x02\x1EV[\x81b\0\0K\x81b\0\x01R` \x1Bb\0\x08\x9B\x17` \x1CV[`\x80RP`\x01`\x01`\xA0\x1B\x03\x80\x83\x16`\xA0\x81\x90R\x90\x82\x16`\xC0\x81\x90R`@\x80QcM\xAA\x96a`\xE1\x1B\x81R\x90Q\x91\x92c\t^\xA7\xB3\x92\x90\x91c\x9BU,\xC2\x91`\x04\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81`\0\x87Z\xF1\x15\x80\x15b\0\0\xAEW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90b\0\0\xD4\x91\x90b\0\x02]V[`@Q`\x01`\x01`\xE0\x1B\x03\x19`\xE0\x84\x90\x1B\x16\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`\0\x19`$\x82\x01R`D\x01` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15b\0\x01#W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90b\0\x01I\x91\x90b\0\x02\x84V[PPPb\0\x02\xA8V[`@\x80Q\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0F` \x82\x01R\x7Fl\x85\xC03~\xBA\x16a2\x7F\x94\xF3\xBFF\xC8\xA7\xF91\x1AV?M\\\x94\x83bV\x7F]\x8E\xD6\x0C\x91\x81\x01\x91\x90\x91R\x7F\xF9Dk\x8E\x93}\x86\xF0\xBC\x87\xCA\xC79#I\x16\x92\xB1#\xCA_\x87a\x90\x84\x94p7X j\xDF``\x82\x01RF`\x80\x82\x01\x81\x90R`\x01`\x01`\xA0\x1B\x03\x83\x16`\xA0\x83\x01R`\0\x91`\xC0\x01`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x91PP\x91\x90PV[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x02\x1BW`\0\x80\xFD[PV[`\0\x80`@\x83\x85\x03\x12\x15b\0\x022W`\0\x80\xFD[\x82Qb\0\x02?\x81b\0\x02\x05V[` \x84\x01Q\x90\x92Pb\0\x02R\x81b\0\x02\x05V[\x80\x91PP\x92P\x92\x90PV[`\0` \x82\x84\x03\x12\x15b\0\x02pW`\0\x80\xFD[\x81Qb\0\x02}\x81b\0\x02\x05V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15b\0\x02\x97W`\0\x80\xFD[\x81Q\x80\x15\x15\x81\x14b\0\x02}W`\0\x80\xFD[`\x80Q`\xA0Q`\xC0Qa\x18!b\0\x03\t`\09`\0\x81\x81a\x01)\x01R\x81\x81a\x05\xFF\x01R\x81\x81a\x07\xAD\x01R\x81\x81a\x08%\x01R\x81\x81a\x0C3\x01Ra\x101\x01R`\0\x81\x81a\x02\xCE\x01Ra\x0FK\x01R`\0\x81\x81a\x0B\xF7\x01Ra\x0C\xD9\x01Ra\x18!`\0\xF3\xFE`\x80`@R`\x046\x10a\0\xB5W`\x005`\xE0\x1C\x80c{\xC4\x1B\x96\x11a\0iW\x80c\xDE\x0E\x9A>\x11a\0NW\x80c\xDE\x0E\x9A>\x14a\x02|W\x80c\xEAY\x8C\xB0\x14a\x02\x9CW\x80c\xEC0\xBB\x88\x14a\x02\xBCW`\0\x80\xFD[\x80c{\xC4\x1B\x96\x14a\x01\xC8W\x80c\x9C?\x1E\x90\x14a\x01\xE8W`\0\x80\xFD[\x80c2+\xBA!\x11a\0\x9AW\x80c2+\xBA!\x14a\x01pW\x80cL\x84\xC1\xC8\x14a\x01\x91W\x80cL\xB7d\x98\x14a\x01\xA8W`\0\x80\xFD[\x80c\x16&\xBA~\x14a\0\xC1W\x80c\x17\xFC\xB3\x9B\x14a\x01\x17W`\0\x80\xFD[6a\0\xBCW\0[`\0\x80\xFD[4\x80\x15a\0\xCDW`\0\x80\xFD[Pa\0\xE1a\0\xDC6`\x04a\x12nV[a\x02\xF0V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x01#W`\0\x80\xFD[Pa\x01K\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x01\x0EV[a\x01\x83a\x01~6`\x04a\x13+V[a\x03\xDEV[`@Q\x90\x81R` \x01a\x01\x0EV[4\x80\x15a\x01\x9DW`\0\x80\xFD[Pa\x01\xA6a\x07 V[\0[4\x80\x15a\x01\xB4W`\0\x80\xFD[Pa\x01\xA6a\x01\xC36`\x04a\x13DV[a\x07+V[4\x80\x15a\x01\xD4W`\0\x80\xFD[Pa\x01\xA6a\x01\xE36`\x04a\x13+V[a\x07pV[4\x80\x15a\x01\xF4W`\0\x80\xFD[Pa\x02Ka\x02\x036`\x04a\x13\xBAV[`\0` \x81\x90R\x90\x81R`@\x90 Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x90t\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04c\xFF\xFF\xFF\xFF\x16\x82V[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x93\x16\x83Rc\xFF\xFF\xFF\xFF\x90\x91\x16` \x83\x01R\x01a\x01\x0EV[4\x80\x15a\x02\x88W`\0\x80\xFD[Pa\x01\xA6a\x02\x976`\x04a\x13\xBAV[a\x07~V[4\x80\x15a\x02\xA8W`\0\x80\xFD[Pa\x01\xA6a\x02\xB76`\x04a\x13\xBAV[a\x08!V[4\x80\x15a\x02\xC8W`\0\x80\xFD[Pa\x01K\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`\0\x82\x81R` \x81\x81R`@\x80\x83 \x81Q\x80\x83\x01\x90\x92RTs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x80\x83Rt\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x04c\xFF\xFF\xFF\xFF\x16\x92\x82\x01\x92\x90\x92R\x90\x15\x80\x15\x90a\x03oWP\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x14\x15[\x80\x15a\x03\x85WPB\x81` \x01Qc\xFF\xFF\xFF\xFF\x16\x10\x15[\x15a\x03\xB3WP\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90Pa\x03\xD8V[P\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90P[\x92\x91PPV[`\0a\x03\xF2`\xA0\x83\x015`@\x84\x015a\x14\x02V[4\x14a\x04*W`@Q\x7F\x8Bn\xBBM\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x81`@\x015`\0\x03a\x04hW`@Q\x7F\xEA\xEC\\\x9D\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[Ba\x04y`\xE0\x84\x01`\xC0\x85\x01a\x14.V[c\xFF\xFF\xFF\xFF\x16\x10\x15a\x04\xB7W`@Q\x7F\x89\xBB&\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@\x80Q\x80\x82\x01\x90\x91R3\x81R`\0\x90` \x81\x01a\x04\xDB`\xE0\x86\x01`\xC0\x87\x01a\x14.V[c\xFF\xFF\xFF\xFF\x16\x90R`@\x80Q\x80\x82\x01\x90\x91R\x90\x91P`\0\x90\x80\x82\x81R` \x010`@Q` \x01a\x056\x91\x90``\x91\x90\x91\x1B\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x16\x81R`\x14\x01\x90V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R\x90R\x90P`\0a\x05|a\x01 \x86\x01a\x01\0\x87\x01a\x14bV[` \x80\x85\x01Q`@Qa\x05\xC3\x93\x92\x01`\xC0\x92\x90\x92\x1B\x82R`\xE0\x1B\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16`\x08\x82\x01R`\x0C\x01\x90V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R\x83Q\x90\x91Pa\x06:\x90a\x063\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06-6\x8A\x90\x03\x8A\x01\x8Aa\x14\xB1V[\x90a\t[V[\x84\x84a\x0B*V[`\0\x81\x81R` \x81\x90R`@\x90 T\x90\x94Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x15a\x06\xA1W`@Q\x7FV\xA1\xD2\xB2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x85\x90R`$\x01[`@Q\x80\x91\x03\x90\xFD[PP`\0\x82\x81R` \x81\x81R`@\x90\x91 \x82Q\x81T\x92\x90\x93\x01Qc\xFF\xFF\xFF\xFF\x16t\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x92\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x93\x16\x92\x90\x92\x17\x17\x90U\x91\x90PV[a\x07)Ga\x08!V[V[`\0[\x81\x81\x10\x15a\x07kWa\x07Y\x83\x83\x83\x81\x81\x10a\x07KWa\x07Ka\x15KV[\x90Pa\x01 \x02\x01`\0a\x0C,V[\x80a\x07c\x81a\x15zV[\x91PPa\x07.V[PPPV[a\x07{\x81`\x01a\x0C,V[PV[`@Q\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x82\x90R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90c.\x1A}M\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x08\x06W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x08\x1AW=`\0\x80>=`\0\xFD[PPPPPV[`\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82`@Q`\0`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a\x08\x1AW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x08\x1AV[`@\x80Q\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0F` \x82\x01R\x7Fl\x85\xC03~\xBA\x16a2\x7F\x94\xF3\xBFF\xC8\xA7\xF91\x1AV?M\\\x94\x83bV\x7F]\x8E\xD6\x0C\x91\x81\x01\x91\x90\x91R\x7F\xF9Dk\x8E\x93}\x86\xF0\xBC\x87\xCA\xC79#I\x16\x92\xB1#\xCA_\x87a\x90\x84\x94p7X j\xDF``\x82\x01RF`\x80\x82\x01\x81\x90Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16`\xA0\x83\x01R`\0\x91`\xC0\x01`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x91PP\x91\x90PV[`@\x80Qa\x01\x80\x81\x01\x82R`\0\x80\x82R` \x80\x83\x01\x82\x90R\x92\x82\x01\x81\x90R``\x82\x01\x81\x90R`\x80\x82\x01\x81\x90R`\xA0\x82\x01\x81\x90R`\xC0\x82\x01\x81\x90R`\xE0\x82\x01\x81\x90Ra\x01\0\x82\x01\x81\x90Ra\x01 \x82\x01\x81\x90Ra\x01@\x82\x01\x81\x90Ra\x01`\x82\x01R\x90\x83\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\n\nW`@Q\x7F\xEF\xC9\xCC\xDF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@Q\x80a\x01\x80\x01`@R\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x84`\0\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x84` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x84`@\x01Q\x81R` \x01\x84``\x01Q\x81R` \x01c\xFF\xFF\xFF\xFF\x80\x16\x81R` \x01\x84`\x80\x01Q\x81R` \x01\x84`\xA0\x01Q\x81R` \x01\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x81R` \x01\x84`\xE0\x01Q\x15\x15\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81R` \x01\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81RP\x90P\x92\x91PPV[`\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xCF_\x9D\xE2\x98A2&R\x03\xB5\xC35\xB2W'p,\xA7rb\xFFb.\x13k\xAAsb\xBF\x1D\xA9\x85\x85\x85`@Qa\x0Bv\x93\x92\x91\x90a\x16vV[`@Q\x80\x91\x03\x90\xA2PPP\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x02\x82\x01R`\"\x81\x01\x91\x90\x91R`B\x90 \x91\x90PV[`\0a\x0Ca\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x06-6\x86\x90\x03\x86\x01\x86a\x14\xB1V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x01\x80Q\x7F\xD5\xA2[\xA2\xE9p\x94\xAD}\x83\xDC(\xA6W-\xA7\x97\xD6\xB3\xE7\xFCfc\xBD\x93\xEF\xB7\x89\xFC\x17\xE4\x89\x82Ra\x01\xA0\x82 \x91R`@\x80Q\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x02\x82\x01R`\"\x81\x01\x92\x90\x92R`B\x90\x91 `\0\x81\x81R` \x81\x81R\x90\x83\x90 \x83Q\x80\x85\x01\x90\x94RTs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16\x80\x86Rt\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x92\x04c\xFF\xFF\xFF\xFF\x16\x92\x85\x01\x83\x90R\x94\x95P\x91\x93B\x90\x91\x10\x15\x91\x14\x80a\r\x8DWP\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x15[\x80a\r\xB7WP\x80\x80\x15a\r\xB7WP\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14\x15[\x15a\r\xFFW\x84\x15a\r\xF7W`@Q\x7F\xF8\xCCp\xCE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x84\x90R`$\x01a\x06\x98V[PPPPPPV[`\0\x83\x81R` \x81\x81R`@\x80\x83 \x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x17\x90U\x80Q`8\x80\x82R``\x82\x01\x90\x92R\x91\x82\x01\x81\x806\x837PPP`\xA0\x86\x01Q\x90\x91Pa\x0Ez\x90\x82\x90\x86\x900\x90a\x11IV[\x81\x15a\x0E\xBCW\x7F\xB8\xBA\xD1\x02\xAC\x8B\xBA\xCF\xEF1\xFF\x1C\x90n\xC6\xD9Q\xC20\xB4\xDC\xE7P\xBB\x03v\xB8\x12\xAD5\x85*\x81`@Qa\x0E\xAF\x91\x90a\x17\x90V[`@Q\x80\x91\x03\x90\xA1a\x0F\x0BV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x19Rq\x06\x8A(\x81\x91\xE4\xB2e\xC6A\xA5k\x982\x91\x9Fi\xE9\xE7\xD6\xC2\xF3\x1B\xA4\x02x\xAE\xB8Z\x82`@Qa\x0F\x02\x91\x90a\x17\x90V[`@Q\x80\x91\x03\x90\xA2[`@Q\x7F$y\xFBn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\0\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90c$y\xFBn\x90a\x0F\x80\x90\x85\x90`\x04\x01a\x17\x90V[` `@Q\x80\x83\x03\x81`\0\x87Z\xF1\x15\x80\x15a\x0F\x9FW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0F\xC3\x91\x90a\x17\xA3V[\x90P`\0\x80\x87``\x01Q\x83\x89`\xE0\x01Q\x02\x81a\x0F\xE1Wa\x0F\xE1a\x17\xBCV[\x04\x88`\xE0\x01Q\x03\x90P\x80\x83\x89``\x01Q\x03\x01\x91PP\x80G\x10\x15a\x10\xA4W`@Q\x7F.\x1A}M\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RG\x82\x03`\x04\x82\x01\x81\x90R\x90\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90c.\x1A}M\x90`$\x01`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x10\x8AW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x10\x9EW=`\0\x80>=`\0\xFD[PPPPP[\x84Q`@Q`\0\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x83\x90\x83\x81\x81\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a\x10\xFDW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x11\x02V[``\x91P[PP\x90P\x80a\x11=W`@Q\x7Fm\x96?\x88\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[PPPPPPPPPPV[`8\x84Q\x14a\x11\xB4W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FGPv2: uid buffer overflow\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x06\x98V[`8\x84\x01R`4\x83\x01R` \x90\x91\x01RV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`A`\x04R`$`\0\xFD[`@Qa\x01 \x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x12\x19Wa\x12\x19a\x11\xC6V[`@R\x90V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x12fWa\x12fa\x11\xC6V[`@R\x91\x90PV[`\0\x80`@\x83\x85\x03\x12\x15a\x12\x81W`\0\x80\xFD[\x825\x91P` \x80\x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x12\xA1W`\0\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a\x12\xB5W`\0\x80\xFD[\x815\x81\x81\x11\x15a\x12\xC7Wa\x12\xC7a\x11\xC6V[a\x12\xF7\x84\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x12\x1FV[\x91P\x80\x82R\x87\x84\x82\x85\x01\x01\x11\x15a\x13\rW`\0\x80\xFD[\x80\x84\x84\x01\x85\x84\x017`\0\x84\x82\x84\x01\x01RP\x80\x93PPPP\x92P\x92\x90PV[`\0a\x01 \x82\x84\x03\x12\x15a\x13>W`\0\x80\xFD[P\x91\x90PV[`\0\x80` \x83\x85\x03\x12\x15a\x13WW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x13oW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x13\x83W`\0\x80\xFD[\x815\x81\x81\x11\x15a\x13\x92W`\0\x80\xFD[\x86` a\x01 \x83\x02\x85\x01\x01\x11\x15a\x13\xA8W`\0\x80\xFD[` \x92\x90\x92\x01\x96\x91\x95P\x90\x93PPPPV[`\0` \x82\x84\x03\x12\x15a\x13\xCCW`\0\x80\xFD[P5\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x11`\x04R`$`\0\xFD[\x80\x82\x01\x80\x82\x11\x15a\x03\xD8Wa\x03\xD8a\x13\xD3V[\x805c\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x14)W`\0\x80\xFD[\x91\x90PV[`\0` \x82\x84\x03\x12\x15a\x14@W`\0\x80\xFD[a\x14I\x82a\x14\x15V[\x93\x92PPPV[\x805`\x07\x81\x90\x0B\x81\x14a\x14)W`\0\x80\xFD[`\0` \x82\x84\x03\x12\x15a\x14tW`\0\x80\xFD[a\x14I\x82a\x14PV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x14)W`\0\x80\xFD[\x805\x80\x15\x15\x81\x14a\x14)W`\0\x80\xFD[`\0a\x01 \x82\x84\x03\x12\x15a\x14\xC4W`\0\x80\xFD[a\x14\xCCa\x11\xF5V[a\x14\xD5\x83a\x14}V[\x81Ra\x14\xE3` \x84\x01a\x14}V[` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01R`\x80\x83\x015`\x80\x82\x01R`\xA0\x83\x015`\xA0\x82\x01Ra\x15\x1C`\xC0\x84\x01a\x14\x15V[`\xC0\x82\x01Ra\x15-`\xE0\x84\x01a\x14\xA1V[`\xE0\x82\x01Ra\x01\0a\x15@\x81\x85\x01a\x14PV[\x90\x82\x01R\x93\x92PPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`2`\x04R`$`\0\xFD[`\0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x03a\x15\xABWa\x15\xABa\x13\xD3V[P`\x01\x01\x90V[`\0\x81Q\x80\x84R`\0[\x81\x81\x10\x15a\x15\xD8W` \x81\x85\x01\x81\x01Q\x86\x83\x01\x82\x01R\x01a\x15\xBCV[P`\0` \x82\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x85\x01\x01\x91PP\x92\x91PPV[`\0\x81Q`\x02\x81\x10a\x16QW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`!`\x04R`$`\0\xFD[\x80\x84RP` \x82\x01Q`@` \x85\x01Ra\x16n`@\x85\x01\x82a\x15\xB2V[\x94\x93PPPPV[\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R`\0a\x01\xC0` \x86\x01Qa\x16\xBC` \x85\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P`@\x86\x01Qa\x16\xE4`@\x85\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x86\x01Q``\x84\x01R`\x80\x86\x01Q`\x80\x84\x01R`\xA0\x86\x01Qa\x17\x10`\xA0\x85\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x86\x01Q`\xC0\x84\x01R`\xE0\x86\x01Q`\xE0\x84\x01Ra\x01\0\x80\x87\x01Q\x81\x85\x01RPa\x01 \x80\x87\x01Qa\x17E\x82\x86\x01\x82\x15\x15\x90RV[PPa\x01@\x86\x81\x01Q\x90\x84\x01Ra\x01`\x80\x87\x01Q\x90\x84\x01Ra\x01\x80\x83\x01\x81\x90Ra\x17q\x81\x84\x01\x86a\x16\x16V[\x90P\x82\x81\x03a\x01\xA0\x84\x01Ra\x17\x86\x81\x85a\x15\xB2V[\x96\x95PPPPPPV[` \x81R`\0a\x14I` \x83\x01\x84a\x15\xB2V[`\0` \x82\x84\x03\x12\x15a\x17\xB5W`\0\x80\xFD[PQ\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R`\x12`\x04R`$`\0\xFD\xFE\xA2dipfsX\"\x12 \xD3!\x9A$?\xB3\xB7h = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: EthTransferFailed) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for EthTransferFailed { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for EthTransferFailed { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [109u8, 150u8, 63u8, 136u8]; + const SIGNATURE: &'static str = "EthTransferFailed()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `IncorrectEthAmount()` and selector `0x8b6ebb4d`. + ```solidity + error IncorrectEthAmount(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct IncorrectEthAmount; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: IncorrectEthAmount) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for IncorrectEthAmount { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for IncorrectEthAmount { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [139u8, 110u8, 187u8, 77u8]; + const SIGNATURE: &'static str = "IncorrectEthAmount()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `NotAllowedToInvalidateOrder(bytes32)` and selector `0xf8cc70ce`. + ```solidity + error NotAllowedToInvalidateOrder(bytes32 orderHash); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NotAllowedToInvalidateOrder { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NotAllowedToInvalidateOrder) -> Self { + (value.orderHash,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NotAllowedToInvalidateOrder { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { orderHash: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for NotAllowedToInvalidateOrder { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 204u8, 112u8, 206u8]; + const SIGNATURE: &'static str = "NotAllowedToInvalidateOrder(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `NotAllowedZeroSellAmount()` and selector `0xeaec5c9d`. + ```solidity + error NotAllowedZeroSellAmount(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NotAllowedZeroSellAmount; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NotAllowedZeroSellAmount) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NotAllowedZeroSellAmount { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for NotAllowedZeroSellAmount { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [234u8, 236u8, 92u8, 157u8]; + const SIGNATURE: &'static str = "NotAllowedZeroSellAmount()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderIsAlreadyExpired()` and selector `0x89bb2601`. + ```solidity + error OrderIsAlreadyExpired(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderIsAlreadyExpired; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderIsAlreadyExpired) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderIsAlreadyExpired { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderIsAlreadyExpired { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [137u8, 187u8, 38u8, 1u8]; + const SIGNATURE: &'static str = "OrderIsAlreadyExpired()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderIsAlreadyOwned(bytes32)` and selector `0x56a1d2b2`. + ```solidity + error OrderIsAlreadyOwned(bytes32 orderHash); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderIsAlreadyOwned { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderIsAlreadyOwned) -> Self { + (value.orderHash,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderIsAlreadyOwned { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { orderHash: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderIsAlreadyOwned { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [86u8, 161u8, 210u8, 178u8]; + const SIGNATURE: &'static str = "OrderIsAlreadyOwned(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ReceiverMustBeSet()` and selector `0xefc9ccdf`. + ```solidity + error ReceiverMustBeSet(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ReceiverMustBeSet; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ReceiverMustBeSet) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ReceiverMustBeSet { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ReceiverMustBeSet { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [239u8, 201u8, 204u8, 223u8]; + const SIGNATURE: &'static str = "ReceiverMustBeSet()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OrderInvalidation(bytes)` and selector `0xb8bad102ac8bbacfef31ff1c906ec6d951c230b4dce750bb0376b812ad35852a`. + ```solidity + event OrderInvalidation(bytes orderUid); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderInvalidation { + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderInvalidation { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderInvalidation(bytes)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 184u8, 186u8, 209u8, 2u8, 172u8, 139u8, 186u8, 207u8, 239u8, 49u8, 255u8, 28u8, + 144u8, 110u8, 198u8, 217u8, 81u8, 194u8, 48u8, 180u8, 220u8, 231u8, 80u8, + 187u8, 3u8, 118u8, 184u8, 18u8, 173u8, 53u8, 133u8, 42u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { orderUid: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.orderUid, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderInvalidation { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderInvalidation> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderInvalidation) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive()] + /**Event with signature `OrderPlacement(address,(address,address,address,uint256,uint256,uint32,bytes32,uint256,bytes32,bool,bytes32,bytes32),(uint8,bytes),bytes)` and selector `0xcf5f9de2984132265203b5c335b25727702ca77262ff622e136baa7362bf1da9`. + ```solidity + event OrderPlacement(address indexed sender, GPv2Order.Data order, ICoWSwapOnchainOrders.OnchainSignature signature, bytes data); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderPlacement { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub order: ::RustType, + #[allow(missing_docs)] + pub signature: + ::RustType, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderPlacement { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + GPv2Order::Data, + ICoWSwapOnchainOrders::OnchainSignature, + alloy_sol_types::sol_data::Bytes, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderPlacement(address,(address,address,address,\ + uint256,uint256,uint32,bytes32,uint256,bytes32,bool,\ + bytes32,bytes32),(uint8,bytes),bytes)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 207u8, 95u8, 157u8, 226u8, 152u8, 65u8, 50u8, 38u8, 82u8, 3u8, 181u8, 195u8, + 53u8, 178u8, 87u8, 39u8, 112u8, 44u8, 167u8, 114u8, 98u8, 255u8, 98u8, 46u8, + 19u8, 107u8, 170u8, 115u8, 98u8, 191u8, 29u8, 169u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + order: data.0, + signature: data.1, + data: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize(&self.order), + ::tokenize( + &self.signature, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.sender.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderPlacement { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderPlacement> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderPlacement) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OrderRefund(bytes,address)` and selector `0x195271068a288191e4b265c641a56b9832919f69e9e7d6c2f31ba40278aeb85a`. + ```solidity + event OrderRefund(bytes orderUid, address indexed refunder); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderRefund { + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub refunder: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderRefund { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderRefund(bytes,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 25u8, 82u8, 113u8, 6u8, 138u8, 40u8, 129u8, 145u8, 228u8, 178u8, 101u8, 198u8, + 65u8, 165u8, 107u8, 152u8, 50u8, 145u8, 159u8, 105u8, 233u8, 231u8, 214u8, + 194u8, 243u8, 27u8, 164u8, 2u8, 120u8, 174u8, 184u8, 90u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + orderUid: data.0, + refunder: topics.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.orderUid, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.refunder.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.refunder, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderRefund { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderRefund> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderRefund) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address _cowSwapSettlement, address _wrappedNativeToken); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _cowSwapSettlement: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _wrappedNativeToken: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._cowSwapSettlement, value._wrappedNativeToken) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _cowSwapSettlement: tuple.0, + _wrappedNativeToken: tuple.1, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._cowSwapSettlement, + ), + ::tokenize( + &self._wrappedNativeToken, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `createOrder((address,address,uint256,uint256,bytes32,uint256,uint32,bool,int64))` and selector `0x322bba21`. + ```solidity + function createOrder(EthFlowOrder.Data memory order) external payable returns (bytes32 orderHash); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createOrderCall { + #[allow(missing_docs)] + pub order: ::RustType, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`createOrder((address,address,uint256,uint256,bytes32,uint256,uint32, + /// bool,int64))`](createOrderCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createOrderReturn { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (EthFlowOrder::Data,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createOrderCall) -> Self { + (value.order,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createOrderCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { order: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createOrderReturn) -> Self { + (value.orderHash,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createOrderReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { orderHash: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createOrderCall { + type Parameters<'a> = (EthFlowOrder::Data,); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [50u8, 43u8, 186u8, 33u8]; + const SIGNATURE: &'static str = + "createOrder((address,address,uint256,uint256,bytes32,uint256,uint32,bool,int64))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + (::tokenize( + &self.order, + ),) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createOrderReturn = r.into(); + r.orderHash + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createOrderReturn = r.into(); + r.orderHash + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `invalidateOrder((address,address,uint256,uint256,bytes32,uint256,uint32,bool,int64))` and selector `0x7bc41b96`. + ```solidity + function invalidateOrder(EthFlowOrder.Data memory order) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct invalidateOrderCall { + #[allow(missing_docs)] + pub order: ::RustType, + } + ///Container type for the return parameters of the + /// [`invalidateOrder((address,address,uint256,uint256,bytes32,uint256, + /// uint32,bool,int64))`](invalidateOrderCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct invalidateOrderReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (EthFlowOrder::Data,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: invalidateOrderCall) -> Self { + (value.order,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for invalidateOrderCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { order: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: invalidateOrderReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for invalidateOrderReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl invalidateOrderReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for invalidateOrderCall { + type Parameters<'a> = (EthFlowOrder::Data,); + type Return = invalidateOrderReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [123u8, 196u8, 27u8, 150u8]; + const SIGNATURE: &'static str = "invalidateOrder((address,address,uint256,uint256,\ + bytes32,uint256,uint32,bool,int64))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + (::tokenize( + &self.order, + ),) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + invalidateOrderReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `invalidateOrdersIgnoringNotAllowed((address,address,uint256,uint256,bytes32,uint256,uint32,bool,int64)[])` and selector `0x4cb76498`. + ```solidity + function invalidateOrdersIgnoringNotAllowed(EthFlowOrder.Data[] memory orderArray) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct invalidateOrdersIgnoringNotAllowedCall { + #[allow(missing_docs)] + pub orderArray: alloy_sol_types::private::Vec< + ::RustType, + >, + } + ///Container type for the return parameters of the + /// [`invalidateOrdersIgnoringNotAllowed((address,address,uint256,uint256, + /// bytes32,uint256,uint32,bool, + /// int64)[])`](invalidateOrdersIgnoringNotAllowedCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct invalidateOrdersIgnoringNotAllowedReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Array,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: invalidateOrdersIgnoringNotAllowedCall) -> Self { + (value.orderArray,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for invalidateOrdersIgnoringNotAllowedCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + orderArray: tuple.0, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: invalidateOrdersIgnoringNotAllowedReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for invalidateOrdersIgnoringNotAllowedReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl invalidateOrdersIgnoringNotAllowedReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> + { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for invalidateOrdersIgnoringNotAllowedCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Array,); + type Return = invalidateOrdersIgnoringNotAllowedReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [76u8, 183u8, 100u8, 152u8]; + const SIGNATURE: &'static str = "invalidateOrdersIgnoringNotAllowed((address,address,\ + uint256,uint256,bytes32,uint256,uint32,bool,int64)[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderArray), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + invalidateOrdersIgnoringNotAllowedReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes32,bytes)` and selector `0x1626ba7e`. + ```solidity + function isValidSignature(bytes32 orderHash, bytes memory) external view returns (bytes4); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureCall { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes32,bytes)`](isValidSignatureCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureCall) -> Self { + (value.orderHash, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + orderHash: tuple.0, + _1: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignatureCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 38u8, 186u8, 126u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes32,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ::tokenize( + &self._1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `orders(bytes32)` and selector `0x9c3f1e90`. + ```solidity + function orders(bytes32) external view returns (address owner, uint32 validTo); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ordersCall(pub alloy_sol_types::private::FixedBytes<32>); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`orders(bytes32)`](ordersCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ordersReturn { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub validTo: u32, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ordersCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ordersCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address, u32); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ordersReturn) -> Self { + (value.owner, value.validTo) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ordersReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + validTo: tuple.1, + } + } + } + } + impl ordersReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + ::tokenize( + &self.owner, + ), + as alloy_sol_types::SolType>::tokenize( + &self.validTo, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for ordersCall { + type Parameters<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Return = ordersReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<32>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [156u8, 63u8, 30u8, 144u8]; + const SIGNATURE: &'static str = "orders(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.0), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ordersReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `unwrap(uint256)` and selector `0xde0e9a3e`. + ```solidity + function unwrap(uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct unwrapCall { + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`unwrap(uint256)`](unwrapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct unwrapReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: unwrapCall) -> Self { + (value.amount,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for unwrapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amount: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: unwrapReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for unwrapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl unwrapReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for unwrapCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Return = unwrapReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [222u8, 14u8, 154u8, 62u8]; + const SIGNATURE: &'static str = "unwrap(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + unwrapReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `wrap(uint256)` and selector `0xea598cb0`. + ```solidity + function wrap(uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct wrapCall { + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`wrap(uint256)`](wrapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct wrapReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: wrapCall) -> Self { + (value.amount,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for wrapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amount: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: wrapReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for wrapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl wrapReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for wrapCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Return = wrapReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [234u8, 89u8, 140u8, 176u8]; + const SIGNATURE: &'static str = "wrap(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + wrapReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`CoWSwapEthFlow`](self) function calls. + #[derive(Clone)] + pub enum CoWSwapEthFlowCalls { + #[allow(missing_docs)] + createOrder(createOrderCall), + #[allow(missing_docs)] + invalidateOrder(invalidateOrderCall), + #[allow(missing_docs)] + invalidateOrdersIgnoringNotAllowed(invalidateOrdersIgnoringNotAllowedCall), + #[allow(missing_docs)] + isValidSignature(isValidSignatureCall), + #[allow(missing_docs)] + orders(ordersCall), + #[allow(missing_docs)] + unwrap(unwrapCall), + #[allow(missing_docs)] + wrap(wrapCall), + } + impl CoWSwapEthFlowCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [22u8, 38u8, 186u8, 126u8], + [50u8, 43u8, 186u8, 33u8], + [76u8, 183u8, 100u8, 152u8], + [123u8, 196u8, 27u8, 150u8], + [156u8, 63u8, 30u8, 144u8], + [222u8, 14u8, 154u8, 62u8], + [234u8, 89u8, 140u8, 176u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(isValidSignature), + ::core::stringify!(createOrder), + ::core::stringify!(invalidateOrdersIgnoringNotAllowed), + ::core::stringify!(invalidateOrder), + ::core::stringify!(orders), + ::core::stringify!(unwrap), + ::core::stringify!(wrap), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CoWSwapEthFlowCalls { + const COUNT: usize = 7usize; + const MIN_DATA_LENGTH: usize = 32usize; + const NAME: &'static str = "CoWSwapEthFlowCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::createOrder(_) => ::SELECTOR, + Self::invalidateOrder(_) => { + ::SELECTOR + } + Self::invalidateOrdersIgnoringNotAllowed(_) => { + ::SELECTOR + } + Self::isValidSignature(_) => { + ::SELECTOR + } + Self::orders(_) => ::SELECTOR, + Self::unwrap(_) => ::SELECTOR, + Self::wrap(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn isValidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowCalls::isValidSignature) + } + isValidSignature + }, + { + fn createOrder(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowCalls::createOrder) + } + createOrder + }, + { + fn invalidateOrdersIgnoringNotAllowed( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CoWSwapEthFlowCalls::invalidateOrdersIgnoringNotAllowed) + } + invalidateOrdersIgnoringNotAllowed + }, + { + fn invalidateOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowCalls::invalidateOrder) + } + invalidateOrder + }, + { + fn orders(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowCalls::orders) + } + orders + }, + { + fn unwrap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowCalls::unwrap) + } + unwrap + }, + { + fn wrap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowCalls::wrap) + } + wrap + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn isValidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowCalls::isValidSignature) + } + isValidSignature + }, + { + fn createOrder(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CoWSwapEthFlowCalls::createOrder) + } + createOrder + }, + { + fn invalidateOrdersIgnoringNotAllowed( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowCalls::invalidateOrdersIgnoringNotAllowed) + } + invalidateOrdersIgnoringNotAllowed + }, + { + fn invalidateOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowCalls::invalidateOrder) + } + invalidateOrder + }, + { + fn orders(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CoWSwapEthFlowCalls::orders) + } + orders + }, + { + fn unwrap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CoWSwapEthFlowCalls::unwrap) + } + unwrap + }, + { + fn wrap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(CoWSwapEthFlowCalls::wrap) + } + wrap + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::createOrder(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::invalidateOrder(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::invalidateOrdersIgnoringNotAllowed(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::isValidSignature(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::orders(inner) => { + ::abi_encoded_size(inner) + } + Self::unwrap(inner) => { + ::abi_encoded_size(inner) + } + Self::wrap(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::createOrder(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::invalidateOrder(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::invalidateOrdersIgnoringNotAllowed(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::isValidSignature(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::orders(inner) => { + ::abi_encode_raw(inner, out) + } + Self::unwrap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::wrap(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CoWSwapEthFlow`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum CoWSwapEthFlowErrors { + #[allow(missing_docs)] + EthTransferFailed(EthTransferFailed), + #[allow(missing_docs)] + IncorrectEthAmount(IncorrectEthAmount), + #[allow(missing_docs)] + NotAllowedToInvalidateOrder(NotAllowedToInvalidateOrder), + #[allow(missing_docs)] + NotAllowedZeroSellAmount(NotAllowedZeroSellAmount), + #[allow(missing_docs)] + OrderIsAlreadyExpired(OrderIsAlreadyExpired), + #[allow(missing_docs)] + OrderIsAlreadyOwned(OrderIsAlreadyOwned), + #[allow(missing_docs)] + ReceiverMustBeSet(ReceiverMustBeSet), + } + impl CoWSwapEthFlowErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [86u8, 161u8, 210u8, 178u8], + [109u8, 150u8, 63u8, 136u8], + [137u8, 187u8, 38u8, 1u8], + [139u8, 110u8, 187u8, 77u8], + [234u8, 236u8, 92u8, 157u8], + [239u8, 201u8, 204u8, 223u8], + [248u8, 204u8, 112u8, 206u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(OrderIsAlreadyOwned), + ::core::stringify!(EthTransferFailed), + ::core::stringify!(OrderIsAlreadyExpired), + ::core::stringify!(IncorrectEthAmount), + ::core::stringify!(NotAllowedZeroSellAmount), + ::core::stringify!(ReceiverMustBeSet), + ::core::stringify!(NotAllowedToInvalidateOrder), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for CoWSwapEthFlowErrors { + const COUNT: usize = 7usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "CoWSwapEthFlowErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::EthTransferFailed(_) => { + ::SELECTOR + } + Self::IncorrectEthAmount(_) => { + ::SELECTOR + } + Self::NotAllowedToInvalidateOrder(_) => { + ::SELECTOR + } + Self::NotAllowedZeroSellAmount(_) => { + ::SELECTOR + } + Self::OrderIsAlreadyExpired(_) => { + ::SELECTOR + } + Self::OrderIsAlreadyOwned(_) => { + ::SELECTOR + } + Self::ReceiverMustBeSet(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn OrderIsAlreadyOwned( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowErrors::OrderIsAlreadyOwned) + } + OrderIsAlreadyOwned + }, + { + fn EthTransferFailed( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowErrors::EthTransferFailed) + } + EthTransferFailed + }, + { + fn OrderIsAlreadyExpired( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowErrors::OrderIsAlreadyExpired) + } + OrderIsAlreadyExpired + }, + { + fn IncorrectEthAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowErrors::IncorrectEthAmount) + } + IncorrectEthAmount + }, + { + fn NotAllowedZeroSellAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CoWSwapEthFlowErrors::NotAllowedZeroSellAmount) + } + NotAllowedZeroSellAmount + }, + { + fn ReceiverMustBeSet( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(CoWSwapEthFlowErrors::ReceiverMustBeSet) + } + ReceiverMustBeSet + }, + { + fn NotAllowedToInvalidateOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(CoWSwapEthFlowErrors::NotAllowedToInvalidateOrder) + } + NotAllowedToInvalidateOrder + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn OrderIsAlreadyOwned( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowErrors::OrderIsAlreadyOwned) + } + OrderIsAlreadyOwned + }, + { + fn EthTransferFailed( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowErrors::EthTransferFailed) + } + EthTransferFailed + }, + { + fn OrderIsAlreadyExpired( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowErrors::OrderIsAlreadyExpired) + } + OrderIsAlreadyExpired + }, + { + fn IncorrectEthAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowErrors::IncorrectEthAmount) + } + IncorrectEthAmount + }, + { + fn NotAllowedZeroSellAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowErrors::NotAllowedZeroSellAmount) + } + NotAllowedZeroSellAmount + }, + { + fn ReceiverMustBeSet( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowErrors::ReceiverMustBeSet) + } + ReceiverMustBeSet + }, + { + fn NotAllowedToInvalidateOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(CoWSwapEthFlowErrors::NotAllowedToInvalidateOrder) + } + NotAllowedToInvalidateOrder + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::EthTransferFailed(inner) => { + ::abi_encoded_size(inner) + } + Self::IncorrectEthAmount(inner) => { + ::abi_encoded_size(inner) + } + Self::NotAllowedToInvalidateOrder(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::NotAllowedZeroSellAmount(inner) => { + ::abi_encoded_size(inner) + } + Self::OrderIsAlreadyExpired(inner) => { + ::abi_encoded_size(inner) + } + Self::OrderIsAlreadyOwned(inner) => { + ::abi_encoded_size(inner) + } + Self::ReceiverMustBeSet(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::EthTransferFailed(inner) => { + ::abi_encode_raw(inner, out) + } + Self::IncorrectEthAmount(inner) => { + ::abi_encode_raw(inner, out) + } + Self::NotAllowedToInvalidateOrder(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::NotAllowedZeroSellAmount(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::OrderIsAlreadyExpired(inner) => { + ::abi_encode_raw(inner, out) + } + Self::OrderIsAlreadyOwned(inner) => { + ::abi_encode_raw(inner, out) + } + Self::ReceiverMustBeSet(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`CoWSwapEthFlow`](self) events. + #[derive(Clone)] + pub enum CoWSwapEthFlowEvents { + #[allow(missing_docs)] + OrderInvalidation(OrderInvalidation), + #[allow(missing_docs)] + OrderPlacement(OrderPlacement), + #[allow(missing_docs)] + OrderRefund(OrderRefund), + } + impl CoWSwapEthFlowEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 25u8, 82u8, 113u8, 6u8, 138u8, 40u8, 129u8, 145u8, 228u8, 178u8, 101u8, 198u8, + 65u8, 165u8, 107u8, 152u8, 50u8, 145u8, 159u8, 105u8, 233u8, 231u8, 214u8, 194u8, + 243u8, 27u8, 164u8, 2u8, 120u8, 174u8, 184u8, 90u8, + ], + [ + 184u8, 186u8, 209u8, 2u8, 172u8, 139u8, 186u8, 207u8, 239u8, 49u8, 255u8, 28u8, + 144u8, 110u8, 198u8, 217u8, 81u8, 194u8, 48u8, 180u8, 220u8, 231u8, 80u8, 187u8, + 3u8, 118u8, 184u8, 18u8, 173u8, 53u8, 133u8, 42u8, + ], + [ + 207u8, 95u8, 157u8, 226u8, 152u8, 65u8, 50u8, 38u8, 82u8, 3u8, 181u8, 195u8, 53u8, + 178u8, 87u8, 39u8, 112u8, 44u8, 167u8, 114u8, 98u8, 255u8, 98u8, 46u8, 19u8, 107u8, + 170u8, 115u8, 98u8, 191u8, 29u8, 169u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(OrderRefund), + ::core::stringify!(OrderInvalidation), + ::core::stringify!(OrderPlacement), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for CoWSwapEthFlowEvents { + const COUNT: usize = 3usize; + const NAME: &'static str = "CoWSwapEthFlowEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OrderInvalidation) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OrderPlacement) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OrderRefund) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for CoWSwapEthFlowEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::OrderInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OrderPlacement(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OrderRefund(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::OrderInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OrderPlacement(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OrderRefund(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CoWSwapEthFlow`](self) contract instance. + + See the [wrapper's documentation](`CoWSwapEthFlowInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CoWSwapEthFlowInstance { + CoWSwapEthFlowInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _cowSwapSettlement: alloy_sol_types::private::Address, + _wrappedNativeToken: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + CoWSwapEthFlowInstance::::deploy(__provider, _cowSwapSettlement, _wrappedNativeToken) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _cowSwapSettlement: alloy_sol_types::private::Address, + _wrappedNativeToken: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + CoWSwapEthFlowInstance::::deploy_builder( + __provider, + _cowSwapSettlement, + _wrappedNativeToken, + ) + } + /**A [`CoWSwapEthFlow`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CoWSwapEthFlow`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CoWSwapEthFlowInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CoWSwapEthFlowInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CoWSwapEthFlowInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CoWSwapEthFlowInstance + { + /**Creates a new wrapper around an on-chain [`CoWSwapEthFlow`](self) contract instance. + + See the [wrapper's documentation](`CoWSwapEthFlowInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _cowSwapSettlement: alloy_sol_types::private::Address, + _wrappedNativeToken: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = + Self::deploy_builder(__provider, _cowSwapSettlement, _wrappedNativeToken); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _cowSwapSettlement: alloy_sol_types::private::Address, + _wrappedNativeToken: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + _cowSwapSettlement, + _wrappedNativeToken, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CoWSwapEthFlowInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CoWSwapEthFlowInstance { + CoWSwapEthFlowInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CoWSwapEthFlowInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`createOrder`] function. + pub fn createOrder( + &self, + order: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, createOrderCall, N> { + self.call_builder(&createOrderCall { order }) + } + + ///Creates a new call builder for the [`invalidateOrder`] function. + pub fn invalidateOrder( + &self, + order: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, invalidateOrderCall, N> { + self.call_builder(&invalidateOrderCall { order }) + } + + ///Creates a new call builder for the + /// [`invalidateOrdersIgnoringNotAllowed`] function. + pub fn invalidateOrdersIgnoringNotAllowed( + &self, + orderArray: alloy_sol_types::private::Vec< + ::RustType, + >, + ) -> alloy_contract::SolCallBuilder<&P, invalidateOrdersIgnoringNotAllowedCall, N> { + self.call_builder(&invalidateOrdersIgnoringNotAllowedCall { orderArray }) + } + + ///Creates a new call builder for the [`isValidSignature`] function. + pub fn isValidSignature( + &self, + orderHash: alloy_sol_types::private::FixedBytes<32>, + _1: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignatureCall, N> { + self.call_builder(&isValidSignatureCall { orderHash, _1 }) + } + + ///Creates a new call builder for the [`orders`] function. + pub fn orders( + &self, + _0: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, ordersCall, N> { + self.call_builder(&ordersCall(_0)) + } + + ///Creates a new call builder for the [`unwrap`] function. + pub fn unwrap( + &self, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, unwrapCall, N> { + self.call_builder(&unwrapCall { amount }) + } + + ///Creates a new call builder for the [`wrap`] function. + pub fn wrap( + &self, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, wrapCall, N> { + self.call_builder(&wrapCall { amount }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CoWSwapEthFlowInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`OrderInvalidation`] event. + pub fn OrderInvalidation_filter(&self) -> alloy_contract::Event<&P, OrderInvalidation, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OrderPlacement`] event. + pub fn OrderPlacement_filter(&self) -> alloy_contract::Event<&P, OrderPlacement, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OrderRefund`] event. + pub fn OrderRefund_filter(&self) -> alloy_contract::Event<&P, OrderRefund, N> { + self.event_filter::() + } + } +} +pub type Instance = CoWSwapEthFlow::CoWSwapEthFlowInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x40a50cf069e992aa4536211b23f286ef88752187"), + Some(16169866u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), + Some(134607215u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), + Some(48411237u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x40a50cf069e992aa4536211b23f286ef88752187"), + Some(25414331u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), + Some(71296258u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x3C3eA1829891BC9bEC3d06A81d5d169e52a415e3"), + Some(21490258u64), + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), + Some(3521855u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x6DFE75B5ddce1ADE279D4fa6BD6AeF3cBb6f49dB"), + Some(204747458u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), + Some(60496408u64), + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), + Some(24522097u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x0b7795E18767259CC253a2dF471db34c72B49516"), + Some(4718739u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/cowswaponchainorders/Cargo.toml b/contracts/generated/contracts-generated/cowswaponchainorders/Cargo.toml new file mode 100644 index 0000000000..c1b80ba336 --- /dev/null +++ b/contracts/generated/contracts-generated/cowswaponchainorders/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-cowswaponchainorders" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/cowswaponchainorders/src/lib.rs b/contracts/generated/contracts-generated/cowswaponchainorders/src/lib.rs new file mode 100644 index 0000000000..071ff13688 --- /dev/null +++ b/contracts/generated/contracts-generated/cowswaponchainorders/src/lib.rs @@ -0,0 +1,1815 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Order { + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Order { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address sellToken; address buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub sellToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub buyToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub validTo: u32, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub kind: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub partiallyFillable: bool, + #[allow(missing_docs)] + pub sellTokenBalance: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub buyTokenBalance: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u32, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::FixedBytes<32>, + bool, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + ( + value.sellToken, + value.buyToken, + value.receiver, + value.sellAmount, + value.buyAmount, + value.validTo, + value.appData, + value.feeAmount, + value.kind, + value.partiallyFillable, + value.sellTokenBalance, + value.buyTokenBalance, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sellToken: tuple.0, + buyToken: tuple.1, + receiver: tuple.2, + sellAmount: tuple.3, + buyAmount: tuple.4, + validTo: tuple.5, + appData: tuple.6, + feeAmount: tuple.7, + kind: tuple.8, + partiallyFillable: tuple.9, + sellTokenBalance: tuple.10, + buyTokenBalance: tuple.11, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.sellToken, + ), + ::tokenize( + &self.buyToken, + ), + ::tokenize( + &self.receiver, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellAmount), + as alloy_sol_types::SolType>::tokenize(&self.buyAmount), + as alloy_sol_types::SolType>::tokenize(&self.validTo), + as alloy_sol_types::SolType>::tokenize(&self.appData), + as alloy_sol_types::SolType>::tokenize(&self.feeAmount), + as alloy_sol_types::SolType>::tokenize(&self.kind), + ::tokenize( + &self.partiallyFillable, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellTokenBalance), + as alloy_sol_types::SolType>::tokenize(&self.buyTokenBalance), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address sellToken,address buyToken,address receiver,uint256 \ + sellAmount,uint256 buyAmount,uint32 validTo,bytes32 appData,uint256 \ + feeAmount,bytes32 kind,bool partiallyFillable,bytes32 \ + sellTokenBalance,bytes32 buyTokenBalance)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.sellToken, + ) + .0, + ::eip712_data_word( + &self.buyToken, + ) + .0, + ::eip712_data_word( + &self.receiver, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.sellAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.buyAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.validTo) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.appData) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.feeAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.kind) + .0, + ::eip712_data_word( + &self.partiallyFillable, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.sellTokenBalance, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.buyTokenBalance, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.sellToken, + ) + + ::topic_preimage_length( + &rust.buyToken, + ) + + ::topic_preimage_length( + &rust.receiver, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.validTo, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.appData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.feeAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.kind) + + ::topic_preimage_length( + &rust.partiallyFillable, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellTokenBalance, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyTokenBalance, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.sellToken, + out, + ); + ::encode_topic_preimage( + &rust.buyToken, + out, + ); + ::encode_topic_preimage( + &rust.receiver, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.validTo, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.appData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.feeAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.kind, + out, + ); + ::encode_topic_preimage( + &rust.partiallyFillable, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellTokenBalance, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyTokenBalance, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2OrderInstance { + GPv2OrderInstance::::new(address, __provider) + } + /**A [`GPv2Order`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Order`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2OrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2OrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2OrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Order`](self) contract instance. + + See the [wrapper's documentation](`GPv2OrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2OrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2OrderInstance { + GPv2OrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2OrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library ICoWSwapOnchainOrders { + type OnchainSigningScheme is uint8; + struct OnchainSignature { OnchainSigningScheme scheme; bytes data; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ICoWSwapOnchainOrders { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OnchainSigningScheme(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl OnchainSigningScheme { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for OnchainSigningScheme { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: OnchainSigningScheme) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for OnchainSigningScheme { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for OnchainSigningScheme { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct OnchainSignature { OnchainSigningScheme scheme; bytes data; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OnchainSignature { + #[allow(missing_docs)] + pub scheme: ::RustType, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (OnchainSigningScheme, alloy_sol_types::sol_data::Bytes); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OnchainSignature) -> Self { + (value.scheme, value.data) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OnchainSignature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + scheme: tuple.0, + data: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for OnchainSignature { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for OnchainSignature { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize(&self.scheme), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for OnchainSignature { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for OnchainSignature { + const NAME: &'static str = "OnchainSignature"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed("OnchainSignature(uint8 scheme,bytes data)") + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.scheme, + ) + .0, + ::eip712_data_word( + &self.data, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for OnchainSignature { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.scheme, + ) + + ::topic_preimage_length( + &rust.data, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.scheme, + out, + ); + ::encode_topic_preimage( + &rust.data, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ICoWSwapOnchainOrders`](self) contract instance. + + See the [wrapper's documentation](`ICoWSwapOnchainOrdersInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ICoWSwapOnchainOrdersInstance { + ICoWSwapOnchainOrdersInstance::::new(address, __provider) + } + /**A [`ICoWSwapOnchainOrders`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ICoWSwapOnchainOrders`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ICoWSwapOnchainOrdersInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ICoWSwapOnchainOrdersInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ICoWSwapOnchainOrdersInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ICoWSwapOnchainOrdersInstance + { + /**Creates a new wrapper around an on-chain [`ICoWSwapOnchainOrders`](self) contract instance. + + See the [wrapper's documentation](`ICoWSwapOnchainOrdersInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ICoWSwapOnchainOrdersInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ICoWSwapOnchainOrdersInstance { + ICoWSwapOnchainOrdersInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ICoWSwapOnchainOrdersInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ICoWSwapOnchainOrdersInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library GPv2Order { + struct Data { + address sellToken; + address buyToken; + address receiver; + uint256 sellAmount; + uint256 buyAmount; + uint32 validTo; + bytes32 appData; + uint256 feeAmount; + bytes32 kind; + bool partiallyFillable; + bytes32 sellTokenBalance; + bytes32 buyTokenBalance; + } +} + +library ICoWSwapOnchainOrders { + type OnchainSigningScheme is uint8; + struct OnchainSignature { + OnchainSigningScheme scheme; + bytes data; + } +} + +interface CoWSwapOnchainOrders { + event OrderInvalidation(bytes orderUid); + event OrderPlacement(address indexed sender, GPv2Order.Data order, ICoWSwapOnchainOrders.OnchainSignature signature, bytes data); + + constructor(address settlementContractAddress); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "settlementContractAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "OrderInvalidation", + "inputs": [ + { + "name": "orderUid", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OrderPlacement", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "order", + "type": "tuple", + "indexed": false, + "internalType": "struct GPv2Order.Data", + "components": [ + { + "name": "sellToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "buyToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "kind", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "partiallyFillable", + "type": "bool", + "internalType": "bool" + }, + { + "name": "sellTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "buyTokenBalance", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "signature", + "type": "tuple", + "indexed": false, + "internalType": "struct ICoWSwapOnchainOrders.OnchainSignature", + "components": [ + { + "name": "scheme", + "type": "uint8", + "internalType": "enum ICoWSwapOnchainOrders.OnchainSigningScheme" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "data", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod CoWSwapOnchainOrders { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OrderInvalidation(bytes)` and selector `0xb8bad102ac8bbacfef31ff1c906ec6d951c230b4dce750bb0376b812ad35852a`. + ```solidity + event OrderInvalidation(bytes orderUid); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderInvalidation { + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderInvalidation { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderInvalidation(bytes)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 184u8, 186u8, 209u8, 2u8, 172u8, 139u8, 186u8, 207u8, 239u8, 49u8, 255u8, 28u8, + 144u8, 110u8, 198u8, 217u8, 81u8, 194u8, 48u8, 180u8, 220u8, 231u8, 80u8, + 187u8, 3u8, 118u8, 184u8, 18u8, 173u8, 53u8, 133u8, 42u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { orderUid: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.orderUid, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderInvalidation { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderInvalidation> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderInvalidation) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive()] + /**Event with signature `OrderPlacement(address,(address,address,address,uint256,uint256,uint32,bytes32,uint256,bytes32,bool,bytes32,bytes32),(uint8,bytes),bytes)` and selector `0xcf5f9de2984132265203b5c335b25727702ca77262ff622e136baa7362bf1da9`. + ```solidity + event OrderPlacement(address indexed sender, GPv2Order.Data order, ICoWSwapOnchainOrders.OnchainSignature signature, bytes data); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderPlacement { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub order: ::RustType, + #[allow(missing_docs)] + pub signature: + ::RustType, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderPlacement { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + GPv2Order::Data, + ICoWSwapOnchainOrders::OnchainSignature, + alloy_sol_types::sol_data::Bytes, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderPlacement(address,(address,address,address,\ + uint256,uint256,uint32,bytes32,uint256,bytes32,bool,\ + bytes32,bytes32),(uint8,bytes),bytes)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 207u8, 95u8, 157u8, 226u8, 152u8, 65u8, 50u8, 38u8, 82u8, 3u8, 181u8, 195u8, + 53u8, 178u8, 87u8, 39u8, 112u8, 44u8, 167u8, 114u8, 98u8, 255u8, 98u8, 46u8, + 19u8, 107u8, 170u8, 115u8, 98u8, 191u8, 29u8, 169u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + order: data.0, + signature: data.1, + data: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize(&self.order), + ::tokenize( + &self.signature, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.sender.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderPlacement { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderPlacement> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderPlacement) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address settlementContractAddress); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub settlementContractAddress: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.settlementContractAddress,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + settlementContractAddress: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.settlementContractAddress, + ), + ) + } + } + }; + ///Container for all the [`CoWSwapOnchainOrders`](self) events. + #[derive(Clone)] + pub enum CoWSwapOnchainOrdersEvents { + #[allow(missing_docs)] + OrderInvalidation(OrderInvalidation), + #[allow(missing_docs)] + OrderPlacement(OrderPlacement), + } + impl CoWSwapOnchainOrdersEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 184u8, 186u8, 209u8, 2u8, 172u8, 139u8, 186u8, 207u8, 239u8, 49u8, 255u8, 28u8, + 144u8, 110u8, 198u8, 217u8, 81u8, 194u8, 48u8, 180u8, 220u8, 231u8, 80u8, 187u8, + 3u8, 118u8, 184u8, 18u8, 173u8, 53u8, 133u8, 42u8, + ], + [ + 207u8, 95u8, 157u8, 226u8, 152u8, 65u8, 50u8, 38u8, 82u8, 3u8, 181u8, 195u8, 53u8, + 178u8, 87u8, 39u8, 112u8, 44u8, 167u8, 114u8, 98u8, 255u8, 98u8, 46u8, 19u8, 107u8, + 170u8, 115u8, 98u8, 191u8, 29u8, 169u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(OrderInvalidation), + ::core::stringify!(OrderPlacement), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for CoWSwapOnchainOrdersEvents { + const COUNT: usize = 2usize; + const NAME: &'static str = "CoWSwapOnchainOrdersEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OrderInvalidation) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OrderPlacement) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for CoWSwapOnchainOrdersEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::OrderInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OrderPlacement(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::OrderInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OrderPlacement(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`CoWSwapOnchainOrders`](self) contract instance. + + See the [wrapper's documentation](`CoWSwapOnchainOrdersInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> CoWSwapOnchainOrdersInstance { + CoWSwapOnchainOrdersInstance::::new(address, __provider) + } + /**A [`CoWSwapOnchainOrders`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`CoWSwapOnchainOrders`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct CoWSwapOnchainOrdersInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for CoWSwapOnchainOrdersInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("CoWSwapOnchainOrdersInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + CoWSwapOnchainOrdersInstance + { + /**Creates a new wrapper around an on-chain [`CoWSwapOnchainOrders`](self) contract instance. + + See the [wrapper's documentation](`CoWSwapOnchainOrdersInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl CoWSwapOnchainOrdersInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> CoWSwapOnchainOrdersInstance { + CoWSwapOnchainOrdersInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + CoWSwapOnchainOrdersInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + CoWSwapOnchainOrdersInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`OrderInvalidation`] event. + pub fn OrderInvalidation_filter(&self) -> alloy_contract::Event<&P, OrderInvalidation, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OrderPlacement`] event. + pub fn OrderPlacement_filter(&self) -> alloy_contract::Event<&P, OrderPlacement, N> { + self.event_filter::() + } + } +} +pub type Instance = + CoWSwapOnchainOrders::CoWSwapOnchainOrdersInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/erc1271signaturevalidator/Cargo.toml b/contracts/generated/contracts-generated/erc1271signaturevalidator/Cargo.toml new file mode 100644 index 0000000000..06f922ce6f --- /dev/null +++ b/contracts/generated/contracts-generated/erc1271signaturevalidator/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-erc1271signaturevalidator" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/erc1271signaturevalidator/src/lib.rs b/contracts/generated/contracts-generated/erc1271signaturevalidator/src/lib.rs new file mode 100644 index 0000000000..d57519f715 --- /dev/null +++ b/contracts/generated/contracts-generated/erc1271signaturevalidator/src/lib.rs @@ -0,0 +1,497 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface ERC1271SignatureValidator { + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "magicValue", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ERC1271SignatureValidator { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes32,bytes)` and selector `0x1626ba7e`. + ```solidity + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureCall { + #[allow(missing_docs)] + pub hash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub signature: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes32,bytes)`](isValidSignatureCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureReturn { + #[allow(missing_docs)] + pub magicValue: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureCall) -> Self { + (value.hash, value.signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + hash: tuple.0, + signature: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureReturn) -> Self { + (value.magicValue,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + magicValue: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignatureCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 38u8, 186u8, 126u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes32,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.hash), + ::tokenize( + &self.signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignatureReturn = r.into(); + r.magicValue + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignatureReturn = r.into(); + r.magicValue + }) + } + } + }; + ///Container for all the [`ERC1271SignatureValidator`](self) function + /// calls. + #[derive(Clone)] + pub enum ERC1271SignatureValidatorCalls { + #[allow(missing_docs)] + isValidSignature(isValidSignatureCall), + } + impl ERC1271SignatureValidatorCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[22u8, 38u8, 186u8, 126u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(isValidSignature)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for ERC1271SignatureValidatorCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 96usize; + const NAME: &'static str = "ERC1271SignatureValidatorCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::isValidSignature(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + ERC1271SignatureValidatorCalls, + >] = &[{ + fn isValidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC1271SignatureValidatorCalls::isValidSignature) + } + isValidSignature + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + ERC1271SignatureValidatorCalls, + >] = &[{ + fn isValidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(ERC1271SignatureValidatorCalls::isValidSignature) + } + isValidSignature + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::isValidSignature(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::isValidSignature(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ERC1271SignatureValidator`](self) contract instance. + + See the [wrapper's documentation](`ERC1271SignatureValidatorInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ERC1271SignatureValidatorInstance { + ERC1271SignatureValidatorInstance::::new(address, __provider) + } + /**A [`ERC1271SignatureValidator`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ERC1271SignatureValidator`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ERC1271SignatureValidatorInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ERC1271SignatureValidatorInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ERC1271SignatureValidatorInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ERC1271SignatureValidatorInstance + { + /**Creates a new wrapper around an on-chain [`ERC1271SignatureValidator`](self) contract instance. + + See the [wrapper's documentation](`ERC1271SignatureValidatorInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ERC1271SignatureValidatorInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ERC1271SignatureValidatorInstance { + ERC1271SignatureValidatorInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ERC1271SignatureValidatorInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`isValidSignature`] function. + pub fn isValidSignature( + &self, + hash: alloy_sol_types::private::FixedBytes<32>, + signature: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignatureCall, N> { + self.call_builder(&isValidSignatureCall { hash, signature }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ERC1271SignatureValidatorInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = + ERC1271SignatureValidator::ERC1271SignatureValidatorInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/erc20/Cargo.toml b/contracts/generated/contracts-generated/erc20/Cargo.toml new file mode 100644 index 0000000000..43ed4adef2 --- /dev/null +++ b/contracts/generated/contracts-generated/erc20/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-erc20" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/erc20/src/lib.rs b/contracts/generated/contracts-generated/erc20/src/lib.rs new file mode 100644 index 0000000000..3117b2c8ee --- /dev/null +++ b/contracts/generated/contracts-generated/erc20/src/lib.rs @@ -0,0 +1,2427 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface ERC20 { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 value); + + constructor(string name_, string symbol_); + + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function decimals() external view returns (uint8); + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "name_", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol_", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ERC20 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(string name_, string symbol_); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub name_: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub symbol_: alloy_sol_types::private::String, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::String, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.name_, value.symbol_) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + name_: tuple.0, + symbol_: tuple.1, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::String, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.name_, + ), + ::tokenize( + &self.symbol_, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external view returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`ERC20`](self) function calls. + #[derive(Clone)] + pub enum ERC20Calls { + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl ERC20Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [112u8, 160u8, 130u8, 49u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(balanceOf), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for ERC20Calls { + const COUNT: usize = 8usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "ERC20Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::name(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::decimals) + } + decimals + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::balanceOf) + } + balanceOf + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20Calls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20Calls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(ERC20Calls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20Calls::decimals) + } + decimals + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20Calls::balanceOf) + } + balanceOf + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20Calls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20Calls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`ERC20`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum ERC20Events { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl ERC20Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = + &[::core::stringify!(Approval), ::core::stringify!(Transfer)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for ERC20Events { + const COUNT: usize = 2usize; + const NAME: &'static str = "ERC20Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC20Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ERC20`](self) contract instance. + + See the [wrapper's documentation](`ERC20Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ERC20Instance { + ERC20Instance::::new(address, __provider) + } + /**A [`ERC20`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ERC20`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ERC20Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ERC20Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ERC20Instance").field(&self.address).finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ERC20Instance + { + /**Creates a new wrapper around an on-chain [`ERC20`](self) contract instance. + + See the [wrapper's documentation](`ERC20Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ERC20Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ERC20Instance { + ERC20Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ERC20Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ERC20Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = ERC20::ERC20Instance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/erc20mintable/Cargo.toml b/contracts/generated/contracts-generated/erc20mintable/Cargo.toml new file mode 100644 index 0000000000..54d1accfd5 --- /dev/null +++ b/contracts/generated/contracts-generated/erc20mintable/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-erc20mintable" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/erc20mintable/src/lib.rs b/contracts/generated/contracts-generated/erc20mintable/src/lib.rs new file mode 100644 index 0000000000..9491880637 --- /dev/null +++ b/contracts/generated/contracts-generated/erc20mintable/src/lib.rs @@ -0,0 +1,2367 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface ERC20Mintable { + event Approval(address indexed owner, address indexed spender, uint256 value); + event MinterAdded(address indexed account); + event MinterRemoved(address indexed account); + event Transfer(address indexed from, address indexed to, uint256 value); + + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function mint(address account, uint256 amount) external returns (bool); + function transfer(address recipient, uint256 amount) external returns (bool); + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MinterAdded", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MinterRemoved", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ERC20Mintable { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405262000024620000186200002a60201b60201c565b6200003260201b60201c565b62000257565b600033905090565b6200004d8160036200009360201b620012a81790919060201c565b8073ffffffffffffffffffffffffffffffffffffffff167f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f660405160405180910390a250565b620000a582826200017760201b60201c565b1562000119576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650081525060200191505060405180910390fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141562000200576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180620018506022913960400191505060405180910390fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6115e980620002676000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063983b2d5611610071578063983b2d56146102e7578063986502751461032b578063a457c2d714610335578063a9059cbb1461039b578063aa271e1a14610401578063dd62ed3e1461045d576100b4565b8063095ea7b3146100b957806318160ddd1461011f57806323b872dd1461013d57806339509351146101c357806340c10f191461022957806370a082311461028f575b600080fd5b610105600480360360408110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104d5565b604051808215151515815260200191505060405180910390f35b6101276104f3565b6040518082815260200191505060405180910390f35b6101a96004803603606081101561015357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104fd565b604051808215151515815260200191505060405180910390f35b61020f600480360360408110156101d957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105d6565b604051808215151515815260200191505060405180910390f35b6102756004803603604081101561023f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610689565b604051808215151515815260200191505060405180910390f35b6102d1600480360360208110156102a557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610704565b6040518082815260200191505060405180910390f35b610329600480360360208110156102fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061074c565b005b6103336107bd565b005b6103816004803603604081101561034b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506107cf565b604051808215151515815260200191505060405180910390f35b6103e7600480360360408110156103b157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061089c565b604051808215151515815260200191505060405180910390f35b6104436004803603602081101561041757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108ba565b604051808215151515815260200191505060405180910390f35b6104bf6004803603604081101561047357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108d7565b6040518082815260200191505060405180910390f35b60006104e96104e261095e565b8484610966565b6001905092915050565b6000600254905090565b600061050a848484610b5d565b6105cb8461051661095e565b6105c6856040518060600160405280602881526020016114fd60289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061057c61095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b610966565b600190509392505050565b600061067f6105e361095e565b8461067a85600160006105f461095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b610966565b6001905092915050565b600061069b61069661095e565b6108ba565b6106f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806114ac6030913960400191505060405180910390fd5b6106fa8383610f5b565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b61075c61075761095e565b6108ba565b6107b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260308152602001806114ac6030913960400191505060405180910390fd5b6107ba81611116565b50565b6107cd6107c861095e565b611170565b565b60006108926107dc61095e565b8461088d85604051806060016040528060258152602001611590602591396001600061080661095e565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b610966565b6001905092915050565b60006108b06108a961095e565b8484610b5d565b6001905092915050565b60006108d08260036111ca90919063ffffffff16565b9050919050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156109ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602481526020018061156c6024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610a72576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806114646022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610be3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806115476025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610c69576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806114416023913960400191505060405180910390fd5b610cd481604051806060016040528060268152602001611486602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e139092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610d67816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610ec0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610e85578082015181840152602081019050610e6a565b50505050905090810190601f168015610eb25780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610f51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610ffe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b61101381600254610ed390919063ffffffff16565b60028190555061106a816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ed390919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b61112a8160036112a890919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f660405160405180910390a250565b61118481600361138390919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167fe94479a9f7e1952cc78f2d6baab678adc1b772d936c6583def489e524cb6669260405160405180910390a250565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611251576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806115256022913960400191505060405180910390fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6112b282826111ca565b15611325576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650081525060200191505060405180910390fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b61138d82826111ca565b6113e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806114dc6021913960400191505060405180910390fd5b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63654d696e746572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865204d696e74657220726f6c65526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c6545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365526f6c65733a206163636f756e7420697320746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a7231582056e4b738cf76f0838e717d12794ecbbd6278399c81f9192ab9d5f01d5c4c3baf64736f6c63430005100032526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@Rb\0\0$b\0\0\x18b\0\0*` \x1B` \x1CV[b\0\x002` \x1B` \x1CV[b\0\x02WV[`\x003\x90P\x90V[b\0\0M\x81`\x03b\0\0\x93` \x1Bb\0\x12\xA8\x17\x90\x91\x90` \x1CV[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7Fj\xE1r\x83~\xA3\x0B\x80\x1F\xBF\xCD\xD4\x10\x8A\xA1\xD5\xBF\x8F\xF7uDO\xD7\x02V\xB4Nk\xF3\xDF\xC3\xF6`@Q`@Q\x80\x91\x03\x90\xA2PV[b\0\0\xA5\x82\x82b\0\x01w` \x1B` \x1CV[\x15b\0\x01\x19W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x1F\x81R` \x01\x80\x7FRoles: account already has role\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x01\x82`\0\x01`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81`\xFF\x02\x19\x16\x90\x83\x15\x15\x02\x17\x90UPPPV[`\0\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15b\0\x02\0W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\"\x81R` \x01\x80b\0\x18P`\"\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x82`\0\x01`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04`\xFF\x16\x90P\x92\x91PPV[a\x15\xE9\x80b\0\x02g`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\xB4W`\x005`\xE0\x1C\x80c\x98;-V\x11a\0qW\x80c\x98;-V\x14a\x02\xE7W\x80c\x98e\x02u\x14a\x03+W\x80c\xA4W\xC2\xD7\x14a\x035W\x80c\xA9\x05\x9C\xBB\x14a\x03\x9BW\x80c\xAA'\x1E\x1A\x14a\x04\x01W\x80c\xDDb\xED>\x14a\x04]Wa\0\xB4V[\x80c\t^\xA7\xB3\x14a\0\xB9W\x80c\x18\x16\r\xDD\x14a\x01\x1FW\x80c#\xB8r\xDD\x14a\x01=W\x80c9P\x93Q\x14a\x01\xC3W\x80c@\xC1\x0F\x19\x14a\x02)W\x80cp\xA0\x821\x14a\x02\x8FW[`\0\x80\xFD[a\x01\x05`\x04\x806\x03`@\x81\x10\x15a\0\xCFW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x04\xD5V[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x01'a\x04\xF3V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x01\xA9`\x04\x806\x03``\x81\x10\x15a\x01SW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x04\xFDV[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x02\x0F`\x04\x806\x03`@\x81\x10\x15a\x01\xD9W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x05\xD6V[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x02u`\x04\x806\x03`@\x81\x10\x15a\x02?W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x06\x89V[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x02\xD1`\x04\x806\x03` \x81\x10\x15a\x02\xA5W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa\x07\x04V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x03)`\x04\x806\x03` \x81\x10\x15a\x02\xFDW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa\x07LV[\0[a\x033a\x07\xBDV[\0[a\x03\x81`\x04\x806\x03`@\x81\x10\x15a\x03KW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x07\xCFV[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x03\xE7`\x04\x806\x03`@\x81\x10\x15a\x03\xB1W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x08\x9CV[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x04C`\x04\x806\x03` \x81\x10\x15a\x04\x17W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa\x08\xBAV[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x04\xBF`\x04\x806\x03`@\x81\x10\x15a\x04sW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa\x08\xD7V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[`\0a\x04\xE9a\x04\xE2a\t^V[\x84\x84a\tfV[`\x01\x90P\x92\x91PPV[`\0`\x02T\x90P\x90V[`\0a\x05\n\x84\x84\x84a\x0B]V[a\x05\xCB\x84a\x05\x16a\t^V[a\x05\xC6\x85`@Q\x80``\x01`@R\x80`(\x81R` \x01a\x14\xFD`(\x919`\x01`\0\x8Bs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x05|a\t^V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 Ta\x0E\x13\x90\x92\x91\x90c\xFF\xFF\xFF\xFF\x16V[a\tfV[`\x01\x90P\x93\x92PPPV[`\0a\x06\x7Fa\x05\xE3a\t^V[\x84a\x06z\x85`\x01`\0a\x05\xF4a\t^V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 Ta\x0E\xD3\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[a\tfV[`\x01\x90P\x92\x91PPV[`\0a\x06\x9Ba\x06\x96a\t^V[a\x08\xBAV[a\x06\xF0W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`0\x81R` \x01\x80a\x14\xAC`0\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x06\xFA\x83\x83a\x0F[V[`\x01\x90P\x92\x91PPV[`\0\x80`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 T\x90P\x91\x90PV[a\x07\\a\x07Wa\t^V[a\x08\xBAV[a\x07\xB1W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`0\x81R` \x01\x80a\x14\xAC`0\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x07\xBA\x81a\x11\x16V[PV[a\x07\xCDa\x07\xC8a\t^V[a\x11pV[V[`\0a\x08\x92a\x07\xDCa\t^V[\x84a\x08\x8D\x85`@Q\x80``\x01`@R\x80`%\x81R` \x01a\x15\x90`%\x919`\x01`\0a\x08\x06a\t^V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x8As\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 Ta\x0E\x13\x90\x92\x91\x90c\xFF\xFF\xFF\xFF\x16V[a\tfV[`\x01\x90P\x92\x91PPV[`\0a\x08\xB0a\x08\xA9a\t^V[\x84\x84a\x0B]V[`\x01\x90P\x92\x91PPV[`\0a\x08\xD0\x82`\x03a\x11\xCA\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90P\x91\x90PV[`\0`\x01`\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 T\x90P\x92\x91PPV[`\x003\x90P\x90V[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\t\xECW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`$\x81R` \x01\x80a\x15l`$\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\nrW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\"\x81R` \x01\x80a\x14d`\"\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x80`\x01`\0\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 \x81\x90UP\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x8C[\xE1\xE5\xEB\xEC}[\xD1OqB}\x1E\x84\xF3\xDD\x03\x14\xC0\xF7\xB2)\x1E[ \n\xC8\xC7\xC3\xB9%\x83`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA3PPPV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x0B\xE3W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`%\x81R` \x01\x80a\x15G`%\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x0CiW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`#\x81R` \x01\x80a\x14A`#\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x0C\xD4\x81`@Q\x80``\x01`@R\x80`&\x81R` \x01a\x14\x86`&\x919`\0\x80\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 Ta\x0E\x13\x90\x92\x91\x90c\xFF\xFF\xFF\xFF\x16V[`\0\x80\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 \x81\x90UPa\rg\x81`\0\x80\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 Ta\x0E\xD3\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[`\0\x80\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 \x81\x90UP\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x83`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA3PPPV[`\0\x83\x83\x11\x15\x82\x90a\x0E\xC0W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x0E\x85W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x0EjV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x0E\xB2W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xFD[P`\0\x83\x85\x03\x90P\x80\x91PP\x93\x92PPPV[`\0\x80\x82\x84\x01\x90P\x83\x81\x10\x15a\x0FQW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x1B\x81R` \x01\x80\x7FSafeMath: addition overflow\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x80\x91PP\x92\x91PPV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x0F\xFEW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x1F\x81R` \x01\x80\x7FERC20: mint to the zero address\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x10\x13\x81`\x02Ta\x0E\xD3\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[`\x02\x81\x90UPa\x10j\x81`\0\x80\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 Ta\x0E\xD3\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[`\0\x80\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 \x81\x90UP\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x83`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA3PPV[a\x11*\x81`\x03a\x12\xA8\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7Fj\xE1r\x83~\xA3\x0B\x80\x1F\xBF\xCD\xD4\x10\x8A\xA1\xD5\xBF\x8F\xF7uDO\xD7\x02V\xB4Nk\xF3\xDF\xC3\xF6`@Q`@Q\x80\x91\x03\x90\xA2PV[a\x11\x84\x81`\x03a\x13\x83\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xE9Dy\xA9\xF7\xE1\x95,\xC7\x8F-k\xAA\xB6x\xAD\xC1\xB7r\xD96\xC6X=\xEFH\x9ERL\xB6f\x92`@Q`@Q\x80\x91\x03\x90\xA2PV[`\0\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x12QW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\"\x81R` \x01\x80a\x15%`\"\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x82`\0\x01`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04`\xFF\x16\x90P\x92\x91PPV[a\x12\xB2\x82\x82a\x11\xCAV[\x15a\x13%W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x1F\x81R` \x01\x80\x7FRoles: account already has role\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x01\x82`\0\x01`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81`\xFF\x02\x19\x16\x90\x83\x15\x15\x02\x17\x90UPPPV[a\x13\x8D\x82\x82a\x11\xCAV[a\x13\xE2W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`!\x81R` \x01\x80a\x14\xDC`!\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x82`\0\x01`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81`\xFF\x02\x19\x16\x90\x83\x15\x15\x02\x17\x90UPPPV\xFEERC20: transfer to the zero addressERC20: approve to the zero addressERC20: transfer amount exceeds balanceMinterRole: caller does not have the Minter roleRoles: account does not have roleERC20: transfer amount exceeds allowanceRoles: account is the zero addressERC20: transfer from the zero addressERC20: approve from the zero addressERC20: decreased allowance below zero\xA2ebzzr1X V\xE4\xB78\xCFv\xF0\x83\x8Eq}\x12yN\xCB\xBDbx9\x9C\x81\xF9\x19*\xB9\xD5\xF0\x1D\\L;\xAFdsolcC\0\x05\x10\x002Roles: account is the zero address", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `MinterAdded(address)` and selector `0x6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f6`. + ```solidity + event MinterAdded(address indexed account); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct MinterAdded { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for MinterAdded { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "MinterAdded(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 106u8, 225u8, 114u8, 131u8, 126u8, 163u8, 11u8, 128u8, 31u8, 191u8, 205u8, + 212u8, 16u8, 138u8, 161u8, 213u8, 191u8, 143u8, 247u8, 117u8, 68u8, 79u8, + 215u8, 2u8, 86u8, 180u8, 78u8, 107u8, 243u8, 223u8, 195u8, 246u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { account: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.account.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.account, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for MinterAdded { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&MinterAdded> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &MinterAdded) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `MinterRemoved(address)` and selector `0xe94479a9f7e1952cc78f2d6baab678adc1b772d936c6583def489e524cb66692`. + ```solidity + event MinterRemoved(address indexed account); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct MinterRemoved { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for MinterRemoved { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "MinterRemoved(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 233u8, 68u8, 121u8, 169u8, 247u8, 225u8, 149u8, 44u8, 199u8, 143u8, 45u8, + 107u8, 170u8, 182u8, 120u8, 173u8, 193u8, 183u8, 114u8, 217u8, 54u8, 198u8, + 88u8, 61u8, 239u8, 72u8, 158u8, 82u8, 76u8, 182u8, 102u8, 146u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { account: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.account.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.account, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for MinterRemoved { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&MinterRemoved> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &MinterRemoved) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address account) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address,uint256)` and selector `0x40c10f19`. + ```solidity + function mint(address account, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub account: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`mint(address,uint256)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + (value.account, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + account: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [64u8, 193u8, 15u8, 25u8]; + const SIGNATURE: &'static str = "mint(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: mintReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: mintReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.sender, value.recipient, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sender: tuple.0, + recipient: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`ERC20Mintable`](self) function calls. + #[derive(Clone)] + pub enum ERC20MintableCalls { + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl ERC20MintableCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [9u8, 94u8, 167u8, 179u8], + [35u8, 184u8, 114u8, 221u8], + [64u8, 193u8, 15u8, 25u8], + [112u8, 160u8, 130u8, 49u8], + [169u8, 5u8, 156u8, 187u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(approve), + ::core::stringify!(transferFrom), + ::core::stringify!(mint), + ::core::stringify!(balanceOf), + ::core::stringify!(transfer), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for ERC20MintableCalls { + const COUNT: usize = 6usize; + const MIN_DATA_LENGTH: usize = 32usize; + const NAME: &'static str = "ERC20MintableCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20MintableCalls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20MintableCalls::transferFrom) + } + transferFrom + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20MintableCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20MintableCalls::balanceOf) + } + balanceOf + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20MintableCalls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ERC20MintableCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20MintableCalls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(ERC20MintableCalls::transferFrom) + } + transferFrom + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20MintableCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20MintableCalls::balanceOf) + } + balanceOf + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20MintableCalls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ERC20MintableCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`ERC20Mintable`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum ERC20MintableEvents { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + MinterAdded(MinterAdded), + #[allow(missing_docs)] + MinterRemoved(MinterRemoved), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl ERC20MintableEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 106u8, 225u8, 114u8, 131u8, 126u8, 163u8, 11u8, 128u8, 31u8, 191u8, 205u8, 212u8, + 16u8, 138u8, 161u8, 213u8, 191u8, 143u8, 247u8, 117u8, 68u8, 79u8, 215u8, 2u8, + 86u8, 180u8, 78u8, 107u8, 243u8, 223u8, 195u8, 246u8, + ], + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + [ + 233u8, 68u8, 121u8, 169u8, 247u8, 225u8, 149u8, 44u8, 199u8, 143u8, 45u8, 107u8, + 170u8, 182u8, 120u8, 173u8, 193u8, 183u8, 114u8, 217u8, 54u8, 198u8, 88u8, 61u8, + 239u8, 72u8, 158u8, 82u8, 76u8, 182u8, 102u8, 146u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(MinterAdded), + ::core::stringify!(Approval), + ::core::stringify!(Transfer), + ::core::stringify!(MinterRemoved), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for ERC20MintableEvents { + const COUNT: usize = 4usize; + const NAME: &'static str = "ERC20MintableEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::MinterAdded) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::MinterRemoved) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC20MintableEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::MinterAdded(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::MinterRemoved(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::MinterAdded(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::MinterRemoved(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ERC20Mintable`](self) contract instance. + + See the [wrapper's documentation](`ERC20MintableInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ERC20MintableInstance { + ERC20MintableInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> + { + ERC20MintableInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + ERC20MintableInstance::::deploy_builder(__provider) + } + /**A [`ERC20Mintable`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ERC20Mintable`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ERC20MintableInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ERC20MintableInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ERC20MintableInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ERC20MintableInstance + { + /**Creates a new wrapper around an on-chain [`ERC20Mintable`](self) contract instance. + + See the [wrapper's documentation](`ERC20MintableInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ERC20MintableInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ERC20MintableInstance { + ERC20MintableInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ERC20MintableInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + account: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { account, amount }) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { recipient, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + sender: alloy_sol_types::private::Address, + recipient: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + sender, + recipient, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ERC20MintableInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`MinterAdded`] event. + pub fn MinterAdded_filter(&self) -> alloy_contract::Event<&P, MinterAdded, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`MinterRemoved`] event. + pub fn MinterRemoved_filter(&self) -> alloy_contract::Event<&P, MinterRemoved, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = ERC20Mintable::ERC20MintableInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/flashloanrouter/Cargo.toml b/contracts/generated/contracts-generated/flashloanrouter/Cargo.toml new file mode 100644 index 0000000000..ef3d5a05dd --- /dev/null +++ b/contracts/generated/contracts-generated/flashloanrouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-flashloanrouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/flashloanrouter/src/lib.rs b/contracts/generated/contracts-generated/flashloanrouter/src/lib.rs new file mode 100644 index 0000000000..95e0fc81f2 --- /dev/null +++ b/contracts/generated/contracts-generated/flashloanrouter/src/lib.rs @@ -0,0 +1,1352 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library LoanRequest { + struct Data { uint256 amount; address borrower; address lender; address token; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod LoanRequest { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { uint256 amount; address borrower; address lender; address token; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub borrower: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub lender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + (value.amount, value.borrower, value.lender, value.token) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount: tuple.0, + borrower: tuple.1, + lender: tuple.2, + token: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ::tokenize( + &self.borrower, + ), + ::tokenize( + &self.lender, + ), + ::tokenize( + &self.token, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(uint256 amount,address borrower,address lender,address token)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ::eip712_data_word( + &self.borrower, + ) + .0, + ::eip712_data_word( + &self.lender, + ) + .0, + ::eip712_data_word( + &self.token, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + ::topic_preimage_length( + &rust.borrower, + ) + + ::topic_preimage_length( + &rust.lender, + ) + + ::topic_preimage_length( + &rust.token, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + ::encode_topic_preimage( + &rust.borrower, + out, + ); + ::encode_topic_preimage( + &rust.lender, + out, + ); + ::encode_topic_preimage( + &rust.token, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`LoanRequest`](self) contract instance. + + See the [wrapper's documentation](`LoanRequestInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> LoanRequestInstance { + LoanRequestInstance::::new(address, __provider) + } + /**A [`LoanRequest`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`LoanRequest`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct LoanRequestInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for LoanRequestInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("LoanRequestInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + LoanRequestInstance + { + /**Creates a new wrapper around an on-chain [`LoanRequest`](self) contract instance. + + See the [wrapper's documentation](`LoanRequestInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl LoanRequestInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> LoanRequestInstance { + LoanRequestInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + LoanRequestInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + LoanRequestInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library LoanRequest { + struct Data { + uint256 amount; + address borrower; + address lender; + address token; + } +} + +interface FlashLoanRouter { + constructor(address _settlementContract); + + function flashLoanAndSettle(LoanRequest.Data[] memory loans, bytes memory settlement) external; + function settlementContract() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_settlementContract", + "type": "address", + "internalType": "contract ICowSettlement" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "flashLoanAndSettle", + "inputs": [ + { + "name": "loans", + "type": "tuple[]", + "internalType": "struct LoanRequest.Data[]", + "components": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "borrower", + "type": "address", + "internalType": "contract IFlashLoanSolverWrapper" + }, + { + "name": "lender", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "contract IERC20" + } + ] + }, + { + "name": "settlement", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settlementContract", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract ICowSettlement" + } + ], + "stateMutability": "view" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod FlashLoanRouter { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60c06040525f80546001600160a01b031916905534801561001e575f5ffd5b50604051610dc0380380610dc083398101604081905261003d916100d3565b6001600160a01b038116608081905260408051632335c76b60e01b81529051632335c76b9160048082019260209290919082900301815f875af1158015610086573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100aa91906100d3565b6001600160a01b031660a052506100f5565b6001600160a01b03811681146100d0575f5ffd5b50565b5f602082840312156100e3575f5ffd5b81516100ee816100bc565b9392505050565b60805160a051610c9e6101225f395f81816053015261026001525f818160cb01526106410152610c9e5ff3fe608060405234801561000f575f5ffd5b506004361061004a575f3560e01c806302ebcbea1461004e5780630efb1fb61461009e578063e7c438c9146100b3578063ea42418b146100c6575b5f5ffd5b6100757f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b16100ac3660046108b0565b6100ed565b005b6100b16100c13660046109e5565b610232565b6100757f000000000000000000000000000000000000000000000000000000000000000081565b3373ffffffffffffffffffffffffffffffffffffffff5f5c1614610172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4f6e6c792063616c6c61626c6520627920626f72726f7765720000000000000060448201526064015b60405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff16907fffffffffffffffffffffffff0000000000000000000000000000000000000000815c168217905d508051602082012060015c14610226576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f42616420646174612066726f6d20626f72726f776572000000000000000000006044820152606401610169565b61022f81610363565b50565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906302cc250d90602401602060405180830381865afa1580156102ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102de9190610a80565b610344576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4f6e6c792063616c6c61626c65206279206120736f6c766572000000000000006044820152606401610169565b5f6103518585858561048d565b905061035c81610363565b5050505050565b60208101515f0361037f5761022f61037a82610549565b61058b565b5f61038982610731565b60208181015184519185019190912091925090815f805c7fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831617905d50808060015d50604080518082018252606085015173ffffffffffffffffffffffffffffffffffffffff9081168252855160208301528583015192517fe0bbec7700000000000000000000000000000000000000000000000000000000815291929085169163e0bbec779161045991859087908b90600401610aa6565b5f604051808303815f87803b158015610470575f5ffd5b505af1158015610482573d5f5f3e3d5ffd5b505050505050505050565b60606104c461049d605c86610b72565b6104a8846020610b8f565b6104b29190610b8f565b60408051828152918201602001905290565b60208082018681529192506104d99082610b8f565b9050828482376104e98382610b8f565b9050845b801561053f57806104fd81610ba2565b915082905061052c88888481811061051757610517610bd6565b9050608002018261081890919063ffffffff16565b610537605c84610b8f565b9250506104ed565b5050949350505050565b60605f605c610559846020015190565b6105639190610b72565b602084516105719190610c03565b61057b9190610c03565b6020939093019283525090919050565b7f13d79a0b000000000000000000000000000000000000000000000000000000006105b582610867565b7fffffffff00000000000000000000000000000000000000000000000000000000161461063e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c7920736574746c65282920697320616c6c6f77656400000000000000006044820152606401610169565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826040516106849190610c16565b5f604051808303815f865af19150503d805f81146106bd576040519150601f19603f3d011682016040523d82523d5f602084013e6106c2565b606091505b505090508061072d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f536574746c656d656e74207265766572746564000000000000000000000000006044820152606401610169565b5050565b604080516080810182525f8082526020820181905291810182905260608101829052906001610761846020015190565b61076b9190610c03565b90505f605c845161077c9190610c03565b9050602084015f61078d8383610b8f565b905082865283825261080e81604080516080810182525f80825260208201819052918101829052606081019190915250805160148201516028830151603c909301516040805160808101825293845273ffffffffffffffffffffffffffffffffffffffff928316602085015293821693830193909352909116606082015290565b9695505050505050565b80355f61082b6040840160208501610c4d565b90505f61083e6060850160408601610c4d565b90505f6108516080860160608701610c4d565b603c870152506028850152601484015290915250565b5f80602083019050600483511061087d57805191505b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f602082840312156108c0575f5ffd5b813567ffffffffffffffff8111156108d6575f5ffd5b8201601f810184136108e6575f5ffd5b803567ffffffffffffffff81111561090057610900610883565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff8211171561096c5761096c610883565b604052818152828201602001861015610983575f5ffd5b816020840160208301375f91810160200191909152949350505050565b5f5f83601f8401126109b0575f5ffd5b50813567ffffffffffffffff8111156109c7575f5ffd5b6020830191508360208285010111156109de575f5ffd5b9250929050565b5f5f5f5f604085870312156109f8575f5ffd5b843567ffffffffffffffff811115610a0e575f5ffd5b8501601f81018713610a1e575f5ffd5b803567ffffffffffffffff811115610a34575f5ffd5b8760208260071b8401011115610a48575f5ffd5b60209182019550935085013567ffffffffffffffff811115610a68575f5ffd5b610a74878288016109a0565b95989497509550505050565b5f60208284031215610a90575f5ffd5b81518015158114610a9f575f5ffd5b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff84511660208201526020840151604082015282606082015260a060808201525f82518060a0840152806020850160c085015e5f60c0828501015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082028115828204841417610b8957610b89610b45565b92915050565b80820180821115610b8957610b89610b45565b5f81610bb057610bb0610b45565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b81810381811115610b8957610b89610b45565b5f82518060208501845e5f920191825250919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461022f575f5ffd5b5f60208284031215610c5d575f5ffd5b8135610a9f81610c2c56fea264697066735822122040d837bb712363085fa15f0b290e54590843321342f61b2f21d52432d2dc8e7b64736f6c634300081c0033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xC0`@R_\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16\x90U4\x80\x15a\0\x1EW__\xFD[P`@Qa\r\xC08\x03\x80a\r\xC0\x839\x81\x01`@\x81\x90Ra\0=\x91a\0\xD3V[`\x01`\x01`\xA0\x1B\x03\x81\x16`\x80\x81\x90R`@\x80Qc#5\xC7k`\xE0\x1B\x81R\x90Qc#5\xC7k\x91`\x04\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81_\x87Z\xF1\x15\x80\x15a\0\x86W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xAA\x91\x90a\0\xD3V[`\x01`\x01`\xA0\x1B\x03\x16`\xA0RPa\0\xF5V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xD0W__\xFD[PV[_` \x82\x84\x03\x12\x15a\0\xE3W__\xFD[\x81Qa\0\xEE\x81a\0\xBCV[\x93\x92PPPV[`\x80Q`\xA0Qa\x0C\x9Ea\x01\"_9_\x81\x81`S\x01Ra\x02`\x01R_\x81\x81`\xCB\x01Ra\x06A\x01Ra\x0C\x9E_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0JW_5`\xE0\x1C\x80c\x02\xEB\xCB\xEA\x14a\0NW\x80c\x0E\xFB\x1F\xB6\x14a\0\x9EW\x80c\xE7\xC48\xC9\x14a\0\xB3W\x80c\xEABA\x8B\x14a\0\xC6W[__\xFD[a\0u\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\xB1a\0\xAC6`\x04a\x08\xB0V[a\0\xEDV[\0[a\0\xB1a\0\xC16`\x04a\t\xE5V[a\x022V[a\0u\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF_\\\x16\x14a\x01rW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FOnly callable by borrower\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[_\x80Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\\\x16\x82\x17\x90]P\x80Q` \x82\x01 `\x01\\\x14a\x02&W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7FBad data from borrower\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[a\x02/\x81a\x03cV[PV[`@Q\x7F\x02\xCC%\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90c\x02\xCC%\r\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\xBAW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x02\xDE\x91\x90a\n\x80V[a\x03DW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FOnly callable by a solver\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[_a\x03Q\x85\x85\x85\x85a\x04\x8DV[\x90Pa\x03\\\x81a\x03cV[PPPPPV[` \x81\x01Q_\x03a\x03\x7FWa\x02/a\x03z\x82a\x05IV[a\x05\x8BV[_a\x03\x89\x82a\x071V[` \x81\x81\x01Q\x84Q\x91\x85\x01\x91\x90\x91 \x91\x92P\x90\x81_\x80\\\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x17\x90]P\x80\x80`\x01]P`@\x80Q\x80\x82\x01\x82R``\x85\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x82R\x85Q` \x83\x01R\x85\x83\x01Q\x92Q\x7F\xE0\xBB\xECw\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x92\x90\x85\x16\x91c\xE0\xBB\xECw\x91a\x04Y\x91\x85\x90\x87\x90\x8B\x90`\x04\x01a\n\xA6V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x04pW__\xFD[PZ\xF1\x15\x80\x15a\x04\x82W=__>=_\xFD[PPPPPPPPPV[``a\x04\xC4a\x04\x9D`\\\x86a\x0BrV[a\x04\xA8\x84` a\x0B\x8FV[a\x04\xB2\x91\x90a\x0B\x8FV[`@\x80Q\x82\x81R\x91\x82\x01` \x01\x90R\x90V[` \x80\x82\x01\x86\x81R\x91\x92Pa\x04\xD9\x90\x82a\x0B\x8FV[\x90P\x82\x84\x827a\x04\xE9\x83\x82a\x0B\x8FV[\x90P\x84[\x80\x15a\x05?W\x80a\x04\xFD\x81a\x0B\xA2V[\x91P\x82\x90Pa\x05,\x88\x88\x84\x81\x81\x10a\x05\x17Wa\x05\x17a\x0B\xD6V[\x90P`\x80\x02\x01\x82a\x08\x18\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[a\x057`\\\x84a\x0B\x8FV[\x92PPa\x04\xEDV[PP\x94\x93PPPPV[``_`\\a\x05Y\x84` \x01Q\x90V[a\x05c\x91\x90a\x0BrV[` \x84Qa\x05q\x91\x90a\x0C\x03V[a\x05{\x91\x90a\x0C\x03V[` \x93\x90\x93\x01\x92\x83RP\x90\x91\x90PV[\x7F\x13\xD7\x9A\x0B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x05\xB5\x82a\x08gV[\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x06>W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FOnly settle() is allowed\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82`@Qa\x06\x84\x91\x90a\x0C\x16V[_`@Q\x80\x83\x03\x81_\x86Z\xF1\x91PP=\x80_\x81\x14a\x06\xBDW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x06\xC2V[``\x91P[PP\x90P\x80a\x07-W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x13`$\x82\x01R\x7FSettlement reverted\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[PPV[`@\x80Q`\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R\x90`\x01a\x07a\x84` \x01Q\x90V[a\x07k\x91\x90a\x0C\x03V[\x90P_`\\\x84Qa\x07|\x91\x90a\x0C\x03V[\x90P` \x84\x01_a\x07\x8D\x83\x83a\x0B\x8FV[\x90P\x82\x86R\x83\x82Ra\x08\x0E\x81`@\x80Q`\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x91\x90\x91RP\x80Q`\x14\x82\x01Q`(\x83\x01Q`<\x90\x93\x01Q`@\x80Q`\x80\x81\x01\x82R\x93\x84Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16` \x85\x01R\x93\x82\x16\x93\x83\x01\x93\x90\x93R\x90\x91\x16``\x82\x01R\x90V[\x96\x95PPPPPPV[\x805_a\x08+`@\x84\x01` \x85\x01a\x0CMV[\x90P_a\x08>``\x85\x01`@\x86\x01a\x0CMV[\x90P_a\x08Q`\x80\x86\x01``\x87\x01a\x0CMV[`<\x87\x01RP`(\x85\x01R`\x14\x84\x01R\x90\x91RPV[_\x80` \x83\x01\x90P`\x04\x83Q\x10a\x08}W\x80Q\x91P[P\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a\x08\xC0W__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08\xD6W__\xFD[\x82\x01`\x1F\x81\x01\x84\x13a\x08\xE6W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\t\0Wa\t\0a\x08\x83V[`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`?\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x85\x01\x16\x01\x16\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\tlWa\tla\x08\x83V[`@R\x81\x81R\x82\x82\x01` \x01\x86\x10\x15a\t\x83W__\xFD[\x81` \x84\x01` \x83\x017_\x91\x81\x01` \x01\x91\x90\x91R\x94\x93PPPPV[__\x83`\x1F\x84\x01\x12a\t\xB0W__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\t\xC7W__\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\t\xDEW__\xFD[\x92P\x92\x90PV[____`@\x85\x87\x03\x12\x15a\t\xF8W__\xFD[\x845g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\x0EW__\xFD[\x85\x01`\x1F\x81\x01\x87\x13a\n\x1EW__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n4W__\xFD[\x87` \x82`\x07\x1B\x84\x01\x01\x11\x15a\nHW__\xFD[` \x91\x82\x01\x95P\x93P\x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\nhW__\xFD[a\nt\x87\x82\x88\x01a\t\xA0V[\x95\x98\x94\x97P\x95PPPPV[_` \x82\x84\x03\x12\x15a\n\x90W__\xFD[\x81Q\x80\x15\x15\x81\x14a\n\x9FW__\xFD[\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84Q\x16` \x82\x01R` \x84\x01Q`@\x82\x01R\x82``\x82\x01R`\xA0`\x80\x82\x01R_\x82Q\x80`\xA0\x84\x01R\x80` \x85\x01`\xC0\x85\x01^_`\xC0\x82\x85\x01\x01R`\xC0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x84\x01\x01\x91PP\x95\x94PPPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\x0B\x89Wa\x0B\x89a\x0BEV[\x92\x91PPV[\x80\x82\x01\x80\x82\x11\x15a\x0B\x89Wa\x0B\x89a\x0BEV[_\x81a\x0B\xB0Wa\x0B\xB0a\x0BEV[P\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[\x81\x81\x03\x81\x81\x11\x15a\x0B\x89Wa\x0B\x89a\x0BEV[_\x82Q\x80` \x85\x01\x84^_\x92\x01\x91\x82RP\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02/W__\xFD[_` \x82\x84\x03\x12\x15a\x0C]W__\xFD[\x815a\n\x9F\x81a\x0C,V\xFE\xA2dipfsX\"\x12 @\xD87\xBBq#c\x08_\xA1_\x0B)\x0ETY\x08C2\x13B\xF6\x1B/!\xD5$2\xD2\xDC\x8E{dsolcC\0\x08\x1C\x003", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b506004361061004a575f3560e01c806302ebcbea1461004e5780630efb1fb61461009e578063e7c438c9146100b3578063ea42418b146100c6575b5f5ffd5b6100757f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b16100ac3660046108b0565b6100ed565b005b6100b16100c13660046109e5565b610232565b6100757f000000000000000000000000000000000000000000000000000000000000000081565b3373ffffffffffffffffffffffffffffffffffffffff5f5c1614610172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4f6e6c792063616c6c61626c6520627920626f72726f7765720000000000000060448201526064015b60405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff16907fffffffffffffffffffffffff0000000000000000000000000000000000000000815c168217905d508051602082012060015c14610226576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f42616420646174612066726f6d20626f72726f776572000000000000000000006044820152606401610169565b61022f81610363565b50565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906302cc250d90602401602060405180830381865afa1580156102ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102de9190610a80565b610344576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4f6e6c792063616c6c61626c65206279206120736f6c766572000000000000006044820152606401610169565b5f6103518585858561048d565b905061035c81610363565b5050505050565b60208101515f0361037f5761022f61037a82610549565b61058b565b5f61038982610731565b60208181015184519185019190912091925090815f805c7fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831617905d50808060015d50604080518082018252606085015173ffffffffffffffffffffffffffffffffffffffff9081168252855160208301528583015192517fe0bbec7700000000000000000000000000000000000000000000000000000000815291929085169163e0bbec779161045991859087908b90600401610aa6565b5f604051808303815f87803b158015610470575f5ffd5b505af1158015610482573d5f5f3e3d5ffd5b505050505050505050565b60606104c461049d605c86610b72565b6104a8846020610b8f565b6104b29190610b8f565b60408051828152918201602001905290565b60208082018681529192506104d99082610b8f565b9050828482376104e98382610b8f565b9050845b801561053f57806104fd81610ba2565b915082905061052c88888481811061051757610517610bd6565b9050608002018261081890919063ffffffff16565b610537605c84610b8f565b9250506104ed565b5050949350505050565b60605f605c610559846020015190565b6105639190610b72565b602084516105719190610c03565b61057b9190610c03565b6020939093019283525090919050565b7f13d79a0b000000000000000000000000000000000000000000000000000000006105b582610867565b7fffffffff00000000000000000000000000000000000000000000000000000000161461063e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c7920736574746c65282920697320616c6c6f77656400000000000000006044820152606401610169565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826040516106849190610c16565b5f604051808303815f865af19150503d805f81146106bd576040519150601f19603f3d011682016040523d82523d5f602084013e6106c2565b606091505b505090508061072d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f536574746c656d656e74207265766572746564000000000000000000000000006044820152606401610169565b5050565b604080516080810182525f8082526020820181905291810182905260608101829052906001610761846020015190565b61076b9190610c03565b90505f605c845161077c9190610c03565b9050602084015f61078d8383610b8f565b905082865283825261080e81604080516080810182525f80825260208201819052918101829052606081019190915250805160148201516028830151603c909301516040805160808101825293845273ffffffffffffffffffffffffffffffffffffffff928316602085015293821693830193909352909116606082015290565b9695505050505050565b80355f61082b6040840160208501610c4d565b90505f61083e6060850160408601610c4d565b90505f6108516080860160608701610c4d565b603c870152506028850152601484015290915250565b5f80602083019050600483511061087d57805191505b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f602082840312156108c0575f5ffd5b813567ffffffffffffffff8111156108d6575f5ffd5b8201601f810184136108e6575f5ffd5b803567ffffffffffffffff81111561090057610900610883565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff8211171561096c5761096c610883565b604052818152828201602001861015610983575f5ffd5b816020840160208301375f91810160200191909152949350505050565b5f5f83601f8401126109b0575f5ffd5b50813567ffffffffffffffff8111156109c7575f5ffd5b6020830191508360208285010111156109de575f5ffd5b9250929050565b5f5f5f5f604085870312156109f8575f5ffd5b843567ffffffffffffffff811115610a0e575f5ffd5b8501601f81018713610a1e575f5ffd5b803567ffffffffffffffff811115610a34575f5ffd5b8760208260071b8401011115610a48575f5ffd5b60209182019550935085013567ffffffffffffffff811115610a68575f5ffd5b610a74878288016109a0565b95989497509550505050565b5f60208284031215610a90575f5ffd5b81518015158114610a9f575f5ffd5b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff84511660208201526020840151604082015282606082015260a060808201525f82518060a0840152806020850160c085015e5f60c0828501015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082028115828204841417610b8957610b89610b45565b92915050565b80820180821115610b8957610b89610b45565b5f81610bb057610bb0610b45565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b81810381811115610b8957610b89610b45565b5f82518060208501845e5f920191825250919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461022f575f5ffd5b5f60208284031215610c5d575f5ffd5b8135610a9f81610c2c56fea264697066735822122040d837bb712363085fa15f0b290e54590843321342f61b2f21d52432d2dc8e7b64736f6c634300081c0033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0JW_5`\xE0\x1C\x80c\x02\xEB\xCB\xEA\x14a\0NW\x80c\x0E\xFB\x1F\xB6\x14a\0\x9EW\x80c\xE7\xC48\xC9\x14a\0\xB3W\x80c\xEABA\x8B\x14a\0\xC6W[__\xFD[a\0u\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\xB1a\0\xAC6`\x04a\x08\xB0V[a\0\xEDV[\0[a\0\xB1a\0\xC16`\x04a\t\xE5V[a\x022V[a\0u\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF_\\\x16\x14a\x01rW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FOnly callable by borrower\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[_\x80Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\\\x16\x82\x17\x90]P\x80Q` \x82\x01 `\x01\\\x14a\x02&W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7FBad data from borrower\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[a\x02/\x81a\x03cV[PV[`@Q\x7F\x02\xCC%\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90c\x02\xCC%\r\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02\xBAW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x02\xDE\x91\x90a\n\x80V[a\x03DW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FOnly callable by a solver\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[_a\x03Q\x85\x85\x85\x85a\x04\x8DV[\x90Pa\x03\\\x81a\x03cV[PPPPPV[` \x81\x01Q_\x03a\x03\x7FWa\x02/a\x03z\x82a\x05IV[a\x05\x8BV[_a\x03\x89\x82a\x071V[` \x81\x81\x01Q\x84Q\x91\x85\x01\x91\x90\x91 \x91\x92P\x90\x81_\x80\\\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x17\x90]P\x80\x80`\x01]P`@\x80Q\x80\x82\x01\x82R``\x85\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x82R\x85Q` \x83\x01R\x85\x83\x01Q\x92Q\x7F\xE0\xBB\xECw\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x91\x92\x90\x85\x16\x91c\xE0\xBB\xECw\x91a\x04Y\x91\x85\x90\x87\x90\x8B\x90`\x04\x01a\n\xA6V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x04pW__\xFD[PZ\xF1\x15\x80\x15a\x04\x82W=__>=_\xFD[PPPPPPPPPV[``a\x04\xC4a\x04\x9D`\\\x86a\x0BrV[a\x04\xA8\x84` a\x0B\x8FV[a\x04\xB2\x91\x90a\x0B\x8FV[`@\x80Q\x82\x81R\x91\x82\x01` \x01\x90R\x90V[` \x80\x82\x01\x86\x81R\x91\x92Pa\x04\xD9\x90\x82a\x0B\x8FV[\x90P\x82\x84\x827a\x04\xE9\x83\x82a\x0B\x8FV[\x90P\x84[\x80\x15a\x05?W\x80a\x04\xFD\x81a\x0B\xA2V[\x91P\x82\x90Pa\x05,\x88\x88\x84\x81\x81\x10a\x05\x17Wa\x05\x17a\x0B\xD6V[\x90P`\x80\x02\x01\x82a\x08\x18\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[a\x057`\\\x84a\x0B\x8FV[\x92PPa\x04\xEDV[PP\x94\x93PPPPV[``_`\\a\x05Y\x84` \x01Q\x90V[a\x05c\x91\x90a\x0BrV[` \x84Qa\x05q\x91\x90a\x0C\x03V[a\x05{\x91\x90a\x0C\x03V[` \x93\x90\x93\x01\x92\x83RP\x90\x91\x90PV[\x7F\x13\xD7\x9A\x0B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x05\xB5\x82a\x08gV[\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x06>W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FOnly settle() is allowed\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82`@Qa\x06\x84\x91\x90a\x0C\x16V[_`@Q\x80\x83\x03\x81_\x86Z\xF1\x91PP=\x80_\x81\x14a\x06\xBDW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x06\xC2V[``\x91P[PP\x90P\x80a\x07-W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x13`$\x82\x01R\x7FSettlement reverted\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01iV[PPV[`@\x80Q`\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R\x90`\x01a\x07a\x84` \x01Q\x90V[a\x07k\x91\x90a\x0C\x03V[\x90P_`\\\x84Qa\x07|\x91\x90a\x0C\x03V[\x90P` \x84\x01_a\x07\x8D\x83\x83a\x0B\x8FV[\x90P\x82\x86R\x83\x82Ra\x08\x0E\x81`@\x80Q`\x80\x81\x01\x82R_\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x91\x90\x91RP\x80Q`\x14\x82\x01Q`(\x83\x01Q`<\x90\x93\x01Q`@\x80Q`\x80\x81\x01\x82R\x93\x84Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16` \x85\x01R\x93\x82\x16\x93\x83\x01\x93\x90\x93R\x90\x91\x16``\x82\x01R\x90V[\x96\x95PPPPPPV[\x805_a\x08+`@\x84\x01` \x85\x01a\x0CMV[\x90P_a\x08>``\x85\x01`@\x86\x01a\x0CMV[\x90P_a\x08Q`\x80\x86\x01``\x87\x01a\x0CMV[`<\x87\x01RP`(\x85\x01R`\x14\x84\x01R\x90\x91RPV[_\x80` \x83\x01\x90P`\x04\x83Q\x10a\x08}W\x80Q\x91P[P\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a\x08\xC0W__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08\xD6W__\xFD[\x82\x01`\x1F\x81\x01\x84\x13a\x08\xE6W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\t\0Wa\t\0a\x08\x83V[`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`?\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x85\x01\x16\x01\x16\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\tlWa\tla\x08\x83V[`@R\x81\x81R\x82\x82\x01` \x01\x86\x10\x15a\t\x83W__\xFD[\x81` \x84\x01` \x83\x017_\x91\x81\x01` \x01\x91\x90\x91R\x94\x93PPPPV[__\x83`\x1F\x84\x01\x12a\t\xB0W__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\t\xC7W__\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\t\xDEW__\xFD[\x92P\x92\x90PV[____`@\x85\x87\x03\x12\x15a\t\xF8W__\xFD[\x845g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\x0EW__\xFD[\x85\x01`\x1F\x81\x01\x87\x13a\n\x1EW__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n4W__\xFD[\x87` \x82`\x07\x1B\x84\x01\x01\x11\x15a\nHW__\xFD[` \x91\x82\x01\x95P\x93P\x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\nhW__\xFD[a\nt\x87\x82\x88\x01a\t\xA0V[\x95\x98\x94\x97P\x95PPPPV[_` \x82\x84\x03\x12\x15a\n\x90W__\xFD[\x81Q\x80\x15\x15\x81\x14a\n\x9FW__\xFD[\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84Q\x16` \x82\x01R` \x84\x01Q`@\x82\x01R\x82``\x82\x01R`\xA0`\x80\x82\x01R_\x82Q\x80`\xA0\x84\x01R\x80` \x85\x01`\xC0\x85\x01^_`\xC0\x82\x85\x01\x01R`\xC0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x83\x01\x16\x84\x01\x01\x91PP\x95\x94PPPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x80\x82\x02\x81\x15\x82\x82\x04\x84\x14\x17a\x0B\x89Wa\x0B\x89a\x0BEV[\x92\x91PPV[\x80\x82\x01\x80\x82\x11\x15a\x0B\x89Wa\x0B\x89a\x0BEV[_\x81a\x0B\xB0Wa\x0B\xB0a\x0BEV[P\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01\x90V[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[\x81\x81\x03\x81\x81\x11\x15a\x0B\x89Wa\x0B\x89a\x0BEV[_\x82Q\x80` \x85\x01\x84^_\x92\x01\x91\x82RP\x91\x90PV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02/W__\xFD[_` \x82\x84\x03\x12\x15a\x0C]W__\xFD[\x815a\n\x9F\x81a\x0C,V\xFE\xA2dipfsX\"\x12 @\xD87\xBBq#c\x08_\xA1_\x0B)\x0ETY\x08C2\x13B\xF6\x1B/!\xD5$2\xD2\xDC\x8E{dsolcC\0\x08\x1C\x003", + ); + /**Constructor`. + ```solidity + constructor(address _settlementContract); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _settlementContract: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._settlementContract,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _settlementContract: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._settlementContract, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `flashLoanAndSettle((uint256,address,address,address)[],bytes)` and selector `0xe7c438c9`. + ```solidity + function flashLoanAndSettle(LoanRequest.Data[] memory loans, bytes memory settlement) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct flashLoanAndSettleCall { + #[allow(missing_docs)] + pub loans: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub settlement: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`flashLoanAndSettle((uint256,address,address,address)[], + /// bytes)`](flashLoanAndSettleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct flashLoanAndSettleReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: flashLoanAndSettleCall) -> Self { + (value.loans, value.settlement) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for flashLoanAndSettleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + loans: tuple.0, + settlement: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: flashLoanAndSettleReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for flashLoanAndSettleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl flashLoanAndSettleReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for flashLoanAndSettleCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Bytes, + ); + type Return = flashLoanAndSettleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [231u8, 196u8, 56u8, 201u8]; + const SIGNATURE: &'static str = + "flashLoanAndSettle((uint256,address,address,address)[],bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.loans), + ::tokenize( + &self.settlement, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + flashLoanAndSettleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `settlementContract()` and selector `0xea42418b`. + ```solidity + function settlementContract() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settlementContractCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`settlementContract()`](settlementContractCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settlementContractReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settlementContractCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settlementContractCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settlementContractReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settlementContractReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for settlementContractCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [234u8, 66u8, 65u8, 139u8]; + const SIGNATURE: &'static str = "settlementContract()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: settlementContractReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: settlementContractReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`FlashLoanRouter`](self) function calls. + #[derive(Clone)] + pub enum FlashLoanRouterCalls { + #[allow(missing_docs)] + flashLoanAndSettle(flashLoanAndSettleCall), + #[allow(missing_docs)] + settlementContract(settlementContractCall), + } + impl FlashLoanRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[231u8, 196u8, 56u8, 201u8], [234u8, 66u8, 65u8, 139u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(flashLoanAndSettle), + ::core::stringify!(settlementContract), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for FlashLoanRouterCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "FlashLoanRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::flashLoanAndSettle(_) => { + ::SELECTOR + } + Self::settlementContract(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn flashLoanAndSettle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(FlashLoanRouterCalls::flashLoanAndSettle) + } + flashLoanAndSettle + }, + { + fn settlementContract( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(FlashLoanRouterCalls::settlementContract) + } + settlementContract + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn flashLoanAndSettle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(FlashLoanRouterCalls::flashLoanAndSettle) + } + flashLoanAndSettle + }, + { + fn settlementContract( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(FlashLoanRouterCalls::settlementContract) + } + settlementContract + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::flashLoanAndSettle(inner) => { + ::abi_encoded_size(inner) + } + Self::settlementContract(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::flashLoanAndSettle(inner) => { + ::abi_encode_raw(inner, out) + } + Self::settlementContract(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`FlashLoanRouter`](self) contract instance. + + See the [wrapper's documentation](`FlashLoanRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> FlashLoanRouterInstance { + FlashLoanRouterInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _settlementContract: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + FlashLoanRouterInstance::::deploy(__provider, _settlementContract) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _settlementContract: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + FlashLoanRouterInstance::::deploy_builder(__provider, _settlementContract) + } + /**A [`FlashLoanRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`FlashLoanRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct FlashLoanRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for FlashLoanRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("FlashLoanRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + FlashLoanRouterInstance + { + /**Creates a new wrapper around an on-chain [`FlashLoanRouter`](self) contract instance. + + See the [wrapper's documentation](`FlashLoanRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _settlementContract: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, _settlementContract); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _settlementContract: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + _settlementContract, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl FlashLoanRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> FlashLoanRouterInstance { + FlashLoanRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + FlashLoanRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`flashLoanAndSettle`] function. + pub fn flashLoanAndSettle( + &self, + loans: alloy_sol_types::private::Vec< + ::RustType, + >, + settlement: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, flashLoanAndSettleCall, N> { + self.call_builder(&flashLoanAndSettleCall { loans, settlement }) + } + + ///Creates a new call builder for the [`settlementContract`] function. + pub fn settlementContract( + &self, + ) -> alloy_contract::SolCallBuilder<&P, settlementContractCall, N> { + self.call_builder(&settlementContractCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + FlashLoanRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = FlashLoanRouter::FlashLoanRouterInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/gashog/Cargo.toml b/contracts/generated/contracts-generated/gashog/Cargo.toml new file mode 100644 index 0000000000..9e318062b7 --- /dev/null +++ b/contracts/generated/contracts-generated/gashog/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-gashog" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/gashog/src/lib.rs b/contracts/generated/contracts-generated/gashog/src/lib.rs new file mode 100644 index 0000000000..92965c1e03 --- /dev/null +++ b/contracts/generated/contracts-generated/gashog/src/lib.rs @@ -0,0 +1,784 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface GasHog { + function approve(address token, address spender, uint256 amount) external; + function isValidSignature(bytes32 order, bytes memory signature) external view returns (bytes4); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "contract ERC20" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "order", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GasHog { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b506103008061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80631626ba7e14610038578063e1f21c6714610080575b5f5ffd5b61004b6100463660046101c5565b610095565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b61009361008e366004610260565b61013d565b005b5f5f5a90505f6100a78486018661029e565b90507fce7d7369855be79904099402d83db6d6ab8840dcd5c086e062cd1ca0c8111dfc5b815a6100d790856102b5565b1015610106576040805160208101839052016040516020818303038152906040528051906020012090506100cb565b868103610111575f5ffd5b507f1626ba7e000000000000000000000000000000000000000000000000000000009695505050505050565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063095ea7b3906044015f604051808303815f87803b1580156101aa575f5ffd5b505af11580156101bc573d5f5f3e3d5ffd5b50505050505050565b5f5f5f604084860312156101d7575f5ffd5b83359250602084013567ffffffffffffffff8111156101f4575f5ffd5b8401601f81018613610204575f5ffd5b803567ffffffffffffffff81111561021a575f5ffd5b86602082840101111561022b575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461025d575f5ffd5b50565b5f5f5f60608486031215610272575f5ffd5b833561027d8161023c565b9250602084013561028d8161023c565b929592945050506040919091013590565b5f602082840312156102ae575f5ffd5b5035919050565b818103818111156102ed577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x03\0\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80c\x16&\xBA~\x14a\08W\x80c\xE1\xF2\x1Cg\x14a\0\x80W[__\xFD[a\0Ka\0F6`\x04a\x01\xC5V[a\0\x95V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\x93a\0\x8E6`\x04a\x02`V[a\x01=V[\0[__Z\x90P_a\0\xA7\x84\x86\x01\x86a\x02\x9EV[\x90P\x7F\xCE}si\x85[\xE7\x99\x04\t\x94\x02\xD8=\xB6\xD6\xAB\x88@\xDC\xD5\xC0\x86\xE0b\xCD\x1C\xA0\xC8\x11\x1D\xFC[\x81Za\0\xD7\x90\x85a\x02\xB5V[\x10\x15a\x01\x06W`@\x80Q` \x81\x01\x83\x90R\x01`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90Pa\0\xCBV[\x86\x81\x03a\x01\x11W__\xFD[P\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x96\x95PPPPPPV[`@Q\x7F\t^\xA7\xB3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x81\x16`\x04\x83\x01R`$\x82\x01\x83\x90R\x84\x16\x90c\t^\xA7\xB3\x90`D\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x01\xAAW__\xFD[PZ\xF1\x15\x80\x15a\x01\xBCW=__>=_\xFD[PPPPPPPV[___`@\x84\x86\x03\x12\x15a\x01\xD7W__\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x01\xF4W__\xFD[\x84\x01`\x1F\x81\x01\x86\x13a\x02\x04W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x02\x1AW__\xFD[\x86` \x82\x84\x01\x01\x11\x15a\x02+W__\xFD[\x93\x96` \x91\x90\x91\x01\x95P\x92\x93PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02]W__\xFD[PV[___``\x84\x86\x03\x12\x15a\x02rW__\xFD[\x835a\x02}\x81a\x02=_\xFD[PPPPPPPV[___`@\x84\x86\x03\x12\x15a\x01\xD7W__\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x01\xF4W__\xFD[\x84\x01`\x1F\x81\x01\x86\x13a\x02\x04W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x02\x1AW__\xFD[\x86` \x82\x84\x01\x01\x11\x15a\x02+W__\xFD[\x93\x96` \x91\x90\x91\x01\x95P\x92\x93PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02]W__\xFD[PV[___``\x84\x86\x03\x12\x15a\x02rW__\xFD[\x835a\x02}\x81a\x02 = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.token, value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + token: tuple.0, + spender: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl approveReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = approveReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [225u8, 242u8, 28u8, 103u8]; + const SIGNATURE: &'static str = "approve(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.token, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + approveReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes32,bytes)` and selector `0x1626ba7e`. + ```solidity + function isValidSignature(bytes32 order, bytes memory signature) external view returns (bytes4); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureCall { + #[allow(missing_docs)] + pub order: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub signature: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes32,bytes)`](isValidSignatureCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureCall) -> Self { + (value.order, value.signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + order: tuple.0, + signature: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignatureCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 38u8, 186u8, 126u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes32,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.order), + ::tokenize( + &self.signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`GasHog`](self) function calls. + #[derive(Clone)] + pub enum GasHogCalls { + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + isValidSignature(isValidSignatureCall), + } + impl GasHogCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[22u8, 38u8, 186u8, 126u8], [225u8, 242u8, 28u8, 103u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(isValidSignature), + ::core::stringify!(approve), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for GasHogCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 96usize; + const NAME: &'static str = "GasHogCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::approve(_) => ::SELECTOR, + Self::isValidSignature(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn isValidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GasHogCalls::isValidSignature) + } + isValidSignature + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GasHogCalls::approve) + } + approve + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn isValidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GasHogCalls::isValidSignature) + } + isValidSignature + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GasHogCalls::approve) + } + approve + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::isValidSignature(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::isValidSignature(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GasHog`](self) contract instance. + + See the [wrapper's documentation](`GasHogInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GasHogInstance { + GasHogInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + GasHogInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + GasHogInstance::::deploy_builder(__provider) + } + /**A [`GasHog`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GasHog`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GasHogInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GasHogInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GasHogInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GasHogInstance + { + /**Creates a new wrapper around an on-chain [`GasHog`](self) contract instance. + + See the [wrapper's documentation](`GasHogInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GasHogInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GasHogInstance { + GasHogInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GasHogInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + token: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { + token, + spender, + amount, + }) + } + + ///Creates a new call builder for the [`isValidSignature`] function. + pub fn isValidSignature( + &self, + order: alloy_sol_types::private::FixedBytes<32>, + signature: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignatureCall, N> { + self.call_builder(&isValidSignatureCall { order, signature }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GasHogInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = GasHog::GasHogInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/gnosissafe/Cargo.toml b/contracts/generated/contracts-generated/gnosissafe/Cargo.toml new file mode 100644 index 0000000000..cd0a1543ef --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafe/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-gnosissafe" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/gnosissafe/src/lib.rs b/contracts/generated/contracts-generated/gnosissafe/src/lib.rs new file mode 100644 index 0000000000..53fdeadaef --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafe/src/lib.rs @@ -0,0 +1,4298 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library Enum { + type Operation is uint8; +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Enum { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Operation(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl Operation { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for Operation { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: Operation) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Operation { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Operation { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Enum`](self) contract instance. + + See the [wrapper's documentation](`EnumInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> EnumInstance { + EnumInstance::::new(address, __provider) + } + /**A [`Enum`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Enum`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct EnumInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for EnumInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("EnumInstance").field(&self.address).finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + EnumInstance + { + /**Creates a new wrapper around an on-chain [`Enum`](self) contract instance. + + See the [wrapper's documentation](`EnumInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl EnumInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> EnumInstance { + EnumInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + EnumInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + EnumInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library Enum { + type Operation is uint8; +} + +interface GnosisSafe { + event AddedOwner(address owner); + event ApproveHash(bytes32 indexed approvedHash, address indexed owner); + event ChangedFallbackHandler(address handler); + event ChangedGuard(address guard); + event ChangedThreshold(uint256 threshold); + event DisabledModule(address module); + event EnabledModule(address module); + event ExecutionFailure(bytes32 txHash, uint256 payment); + event ExecutionFromModuleFailure(address indexed module); + event ExecutionFromModuleSuccess(address indexed module); + event ExecutionSuccess(bytes32 txHash, uint256 payment); + event RemovedOwner(address owner); + event SafeReceived(address indexed sender, uint256 value); + event SafeSetup(address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler); + event SignMsg(bytes32 indexed msgHash); + + constructor(); + + fallback() external; + + receive() external payable; + + function VERSION() external view returns (string memory); + function domainSeparator() external view returns (bytes32); + function execTransaction(address to, uint256 value, bytes memory data, Enum.Operation operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address payable refundReceiver, bytes memory signatures) external payable returns (bool success); + function nonce() external view returns (uint256); + function setup(address[] memory _owners, uint256 _threshold, address to, bytes memory data, address fallbackHandler, address paymentToken, uint256 payment, address payable paymentReceiver) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "fallback", + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "execTransaction", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "operation", + "type": "uint8", + "internalType": "enum Enum.Operation" + }, + { + "name": "safeTxGas", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "baseGas", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "gasPrice", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "gasToken", + "type": "address", + "internalType": "address" + }, + { + "name": "refundReceiver", + "type": "address", + "internalType": "address payable" + }, + { + "name": "signatures", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "success", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "nonce", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setup", + "inputs": [ + { + "name": "_owners", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "_threshold", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "fallbackHandler", + "type": "address", + "internalType": "address" + }, + { + "name": "paymentToken", + "type": "address", + "internalType": "address" + }, + { + "name": "payment", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "paymentReceiver", + "type": "address", + "internalType": "address payable" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "AddedOwner", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ApproveHash", + "inputs": [ + { + "name": "approvedHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ChangedFallbackHandler", + "inputs": [ + { + "name": "handler", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ChangedGuard", + "inputs": [ + { + "name": "guard", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ChangedThreshold", + "inputs": [ + { + "name": "threshold", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "DisabledModule", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "EnabledModule", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExecutionFailure", + "inputs": [ + { + "name": "txHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "payment", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExecutionFromModuleFailure", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExecutionFromModuleSuccess", + "inputs": [ + { + "name": "module", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ExecutionSuccess", + "inputs": [ + { + "name": "txHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "payment", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RemovedOwner", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SafeReceived", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SafeSetup", + "inputs": [ + { + "name": "initiator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "owners", + "type": "address[]", + "indexed": false, + "internalType": "address[]" + }, + { + "name": "threshold", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "initializer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "fallbackHandler", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SignMsg", + "inputs": [ + { + "name": "msgHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GnosisSafe { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561001057600080fd5b5060016004819055506159ae80620000296000396000f3fe6080604052600436106101dc5760003560e01c8063affed0e011610102578063e19a9dd911610095578063f08a032311610064578063f08a032314611647578063f698da2514611698578063f8dc5dd9146116c3578063ffa1ad741461173e57610231565b8063e19a9dd91461139b578063e318b52b146113ec578063e75235b81461147d578063e86637db146114a857610231565b8063cc2f8452116100d1578063cc2f8452146110e8578063d4d9bdcd146111b5578063d8d11f78146111f0578063e009cfde1461132a57610231565b8063affed0e014610d94578063b4faba0914610dbf578063b63e800d14610ea7578063c4ca3a9c1461101757610231565b80635624b25b1161017a5780636a761202116101495780636a761202146109945780637d83297414610b50578063934f3a1114610bbf578063a0e67e2b14610d2857610231565b80635624b25b146107fb5780635ae6bd37146108b9578063610b592514610908578063694e80c31461095957610231565b80632f54bf6e116101b65780632f54bf6e146104d35780633408e4701461053a578063468721a7146105655780635229073f1461067a57610231565b80630d582f131461029e57806312fb68e0146102f95780632d9ad53d1461046c57610231565b36610231573373ffffffffffffffffffffffffffffffffffffffff167f3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d346040518082815260200191505060405180910390a2005b34801561023d57600080fd5b5060007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b905080548061027257600080f35b36600080373360601b365260008060143601600080855af13d6000803e80610299573d6000fd5b3d6000f35b3480156102aa57600080fd5b506102f7600480360360408110156102c157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506117ce565b005b34801561030557600080fd5b5061046a6004803603608081101561031c57600080fd5b81019080803590602001909291908035906020019064010000000081111561034357600080fd5b82018360208201111561035557600080fd5b8035906020019184600183028401116401000000008311171561037757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803590602001906401000000008111156103da57600080fd5b8201836020820111156103ec57600080fd5b8035906020019184600183028401116401000000008311171561040e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190505050611bbe565b005b34801561047857600080fd5b506104bb6004803603602081101561048f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612440565b60405180821515815260200191505060405180910390f35b3480156104df57600080fd5b50610522600480360360208110156104f657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612512565b60405180821515815260200191505060405180910390f35b34801561054657600080fd5b5061054f6125e4565b6040518082815260200191505060405180910390f35b34801561057157600080fd5b506106626004803603608081101561058857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156105cf57600080fd5b8201836020820111156105e157600080fd5b8035906020019184600183028401116401000000008311171561060357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff1690602001909291905050506125f1565b60405180821515815260200191505060405180910390f35b34801561068657600080fd5b506107776004803603608081101561069d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156106e457600080fd5b8201836020820111156106f657600080fd5b8035906020019184600183028401116401000000008311171561071857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290803560ff1690602001909291905050506127d7565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156107bf5780820151818401526020810190506107a4565b50505050905090810190601f1680156107ec5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561080757600080fd5b5061083e6004803603604081101561081e57600080fd5b81019080803590602001909291908035906020019092919050505061280d565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561087e578082015181840152602081019050610863565b50505050905090810190601f1680156108ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156108c557600080fd5b506108f2600480360360208110156108dc57600080fd5b8101908080359060200190929190505050612894565b6040518082815260200191505060405180910390f35b34801561091457600080fd5b506109576004803603602081101561092b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506128ac565b005b34801561096557600080fd5b506109926004803603602081101561097c57600080fd5b8101908080359060200190929190505050612c3e565b005b610b3860048036036101408110156109ab57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156109f257600080fd5b820183602082011115610a0457600080fd5b80359060200191846001830284011164010000000083111715610a2657600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610ab257600080fd5b820183602082011115610ac457600080fd5b80359060200191846001830284011164010000000083111715610ae657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612d78565b60405180821515815260200191505060405180910390f35b348015610b5c57600080fd5b50610ba960048036036040811015610b7357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506132b5565b6040518082815260200191505060405180910390f35b348015610bcb57600080fd5b50610d2660048036036060811015610be257600080fd5b810190808035906020019092919080359060200190640100000000811115610c0957600080fd5b820183602082011115610c1b57600080fd5b80359060200191846001830284011164010000000083111715610c3d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190640100000000811115610ca057600080fd5b820183602082011115610cb257600080fd5b80359060200191846001830284011164010000000083111715610cd457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506132da565b005b348015610d3457600080fd5b50610d3d613369565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610d80578082015181840152602081019050610d65565b505050509050019250505060405180910390f35b348015610da057600080fd5b50610da9613512565b6040518082815260200191505060405180910390f35b348015610dcb57600080fd5b50610ea560048036036040811015610de257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610e1f57600080fd5b820183602082011115610e3157600080fd5b80359060200191846001830284011164010000000083111715610e5357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050613518565b005b348015610eb357600080fd5b506110156004803603610100811015610ecb57600080fd5b8101908080359060200190640100000000811115610ee857600080fd5b820183602082011115610efa57600080fd5b80359060200191846020830284011164010000000083111715610f1c57600080fd5b909192939192939080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610f6757600080fd5b820183602082011115610f7957600080fd5b80359060200191846001830284011164010000000083111715610f9b57600080fd5b9091929391929390803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061353a565b005b34801561102357600080fd5b506110d26004803603608081101561103a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561108157600080fd5b82018360208201111561109357600080fd5b803590602001918460018302840111640100000000831117156110b557600080fd5b9091929391929390803560ff1690602001909291905050506136f8565b6040518082815260200191505060405180910390f35b3480156110f457600080fd5b506111416004803603604081101561110b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613820565b60405180806020018373ffffffffffffffffffffffffffffffffffffffff168152602001828103825284818151815260200191508051906020019060200280838360005b838110156111a0578082015181840152602081019050611185565b50505050905001935050505060405180910390f35b3480156111c157600080fd5b506111ee600480360360208110156111d857600080fd5b8101908080359060200190929190505050613a12565b005b3480156111fc57600080fd5b50611314600480360361014081101561121457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561125b57600080fd5b82018360208201111561126d57600080fd5b8035906020019184600183028401116401000000008311171561128f57600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050613bb1565b6040518082815260200191505060405180910390f35b34801561133657600080fd5b506113996004803603604081101561134d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613bde565b005b3480156113a757600080fd5b506113ea600480360360208110156113be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613f6f565b005b3480156113f857600080fd5b5061147b6004803603606081101561140f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050613ff3565b005b34801561148957600080fd5b50611492614665565b6040518082815260200191505060405180910390f35b3480156114b457600080fd5b506115cc60048036036101408110156114cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561151357600080fd5b82018360208201111561152557600080fd5b8035906020019184600183028401116401000000008311171561154757600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061466f565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561160c5780820151818401526020810190506115f1565b50505050905090810190601f1680156116395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561165357600080fd5b506116966004803603602081101561166a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050614817565b005b3480156116a457600080fd5b506116ad614878565b6040518082815260200191505060405180910390f35b3480156116cf57600080fd5b5061173c600480360360608110156116e657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506148f6565b005b34801561174a57600080fd5b50611753614d29565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015611793578082015181840152602081019050611778565b50505050905090810190601f1680156117c05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6117d6614d62565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156118405750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561187857503073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b6118ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146119eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506003600081548092919060010191905055507f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2682604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414611bba57611bb981612c3e565b5b5050565b611bd2604182614e0590919063ffffffff16565b82511015611c48576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6000808060008060005b8681101561243457611c648882614e3f565b80945081955082965050505060008460ff16141561206d578260001c9450611c96604188614e0590919063ffffffff16565b8260001c1015611d0e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8751611d2760208460001c614e6e90919063ffffffff16565b1115611d9b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006020838a01015190508851611dd182611dc360208760001c614e6e90919063ffffffff16565b614e6e90919063ffffffff16565b1115611e45576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60606020848b010190506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff166320c13b0b8d846040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b83811015611ee7578082015181840152602081019050611ecc565b50505050905090810190601f168015611f145780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b83811015611f4d578082015181840152602081019050611f32565b50505050905090810190601f168015611f7a5780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b158015611f9957600080fd5b505afa158015611fad573d6000803e3d6000fd5b505050506040513d6020811015611fc357600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612066576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b50506122b2565b60018460ff161415612181578260001c94508473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061210a57506000600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008c81526020019081526020016000205414155b61217c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6122b1565b601e8460ff1611156122495760018a60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012060048603858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015612238573d6000803e3d6000fd5b5050506020604051035194506122b0565b60018a85858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156122a3573d6000803e3d6000fd5b5050506020604051035194505b5b5b8573ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161180156123795750600073ffffffffffffffffffffffffffffffffffffffff16600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b80156123b25750600173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b612424576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330323600000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8495508080600101915050611c52565b50505050505050505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600173ffffffffffffffffffffffffffffffffffffffff161415801561250b5750600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156125dd5750600073ffffffffffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b9050919050565b6000804690508091505090565b6000600173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156126bc5750600073ffffffffffffffffffffffffffffffffffffffff16600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b61272e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61273b858585855a614e8d565b9050801561278b573373ffffffffffffffffffffffffffffffffffffffff167f6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb860405160405180910390a26127cf565b3373ffffffffffffffffffffffffffffffffffffffff167facd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd37560405160405180910390a25b949350505050565b600060606127e7868686866125f1565b915060405160203d0181016040523d81523d6000602083013e8091505094509492505050565b606060006020830267ffffffffffffffff8111801561282b57600080fd5b506040519080825280601f01601f19166020018201604052801561285e5781602001600182028036833780820191505090505b50905060005b8381101561288957808501548060208302602085010152508080600101915050612864565b508091505092915050565b60076020528060005260406000206000915090505481565b6128b4614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561291e5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b612990576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612a91576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f844081604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b612c46614d62565b600354811115612cbe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001811015612d35576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b806004819055507f610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c936004546040518082815260200191505060405180910390a150565b6000806000612d928e8e8e8e8e8e8e8e8e8e60055461466f565b905060056000815480929190600101919050555080805190602001209150612dbb8282866132da565b506000612dc6614ed9565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612fac578073ffffffffffffffffffffffffffffffffffffffff166375f0bb528f8f8f8f8f8f8f8f8f8f8f336040518d63ffffffff1660e01b8152600401808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c8152602001806020018a6001811115612e6957fe5b81526020018981526020018881526020018781526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff168152602001806020018473ffffffffffffffffffffffffffffffffffffffff16815260200183810383528d8d82818152602001925080828437600081840152601f19601f820116905080830192505050838103825285818151815260200191508051906020019080838360005b83811015612f3b578082015181840152602081019050612f20565b50505050905090810190601f168015612f685780820380516001836020036101000a031916815260200191505b509e505050505050505050505050505050600060405180830381600087803b158015612f9357600080fd5b505af1158015612fa7573d6000803e3d6000fd5b505050505b6101f4612fd36109c48b01603f60408d0281612fc457fe5b04614f0a90919063ffffffff16565b015a1015613049576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60005a90506130b28f8f8f8f8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508e60008d146130a7578e6130ad565b6109c45a035b614e8d565b93506130c75a82614f2490919063ffffffff16565b905083806130d6575060008a14155b806130e2575060008814155b613154576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008089111561316e5761316b828b8b8b8b614f44565b90505b84156131b8577f442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e8482604051808381526020018281526020019250505060405180910390a16131f8565b7f23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d238482604051808381526020018281526020019250505060405180910390a15b5050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146132a4578073ffffffffffffffffffffffffffffffffffffffff16639327136883856040518363ffffffff1660e01b815260040180838152602001821515815260200192505050600060405180830381600087803b15801561328b57600080fd5b505af115801561329f573d6000803e3d6000fd5b505050505b50509b9a5050505050505050505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b6000600454905060008111613357576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61336384848484611bbe565b50505050565b6060600060035467ffffffffffffffff8111801561338657600080fd5b506040519080825280602002602001820160405280156133b55781602001602082028036833780820191505090505b50905060008060026000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613509578083838151811061346057fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050818060010192505061341f565b82935050505090565b60055481565b600080825160208401855af4806000523d6020523d600060403e60403d016000fd5b6135858a8a80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508961514a565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146135c3576135c28461564a565b5b6136118787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050615679565b600082111561362b5761362982600060018685614f44565b505b3373ffffffffffffffffffffffffffffffffffffffff167f141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a88b8b8b8b8960405180806020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252878782818152602001925060200280828437600081840152601f19601f820116905080830192505050965050505050505060405180910390a250505050505050505050565b6000805a905061374f878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050865a614e8d565b61375857600080fd5b60005a8203905080604051602001808281526020019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156137e55780820151818401526020810190506137ca565b50505050905090810190601f1680156138125780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b606060008267ffffffffffffffff8111801561383b57600080fd5b5060405190808252806020026020018201604052801561386a5781602001602082028036833780820191505090505b509150600080600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415801561393d5750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561394857508482105b15613a03578084838151811061395a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081806001019250506138d3565b80925081845250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff16600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415613b14576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000838152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16817ff2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c60405160405180910390a350565b6000613bc68c8c8c8c8c8c8c8c8c8c8c61466f565b8051906020012090509b9a5050505050505050505050565b613be6614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015613c505750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b613cc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614613dc2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507faab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace405427681604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b613f77614d62565b60007f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b90508181557f1151116914515bc0891ff9047a6cb32cf902546f83066499bcf8ba33d2353fa282604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a15050565b613ffb614d62565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156140655750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561409d57503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b61410f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614210576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561427a5750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b6142ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146143ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a17f9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea2681604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1505050565b6000600454905090565b606060007fbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d860001b8d8d8d8d60405180838380828437808301925050509250505060405180910390208c8c8c8c8c8c8c604051602001808c81526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a815260200189815260200188600181111561470057fe5b81526020018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019b505050505050505050505050604051602081830303815290604052805190602001209050601960f81b600160f81b61478c614878565b8360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040529150509b9a5050505050505050505050565b61481f614d62565b6148288161564a565b7f5ac6c46c93c8d0e53714ba3b53db3e7c046da994313d7ed0d192028bc7c228b081604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a7946921860001b6148a66125e4565b30604051602001808481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405160208183030381529060405280519060200120905090565b6148fe614d62565b806001600354031015614979576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141580156149e35750600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b614a55576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614614b55576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303500000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360008154809291906001900391905055507ff8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf82604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18060045414614d2457614d2381612c3e565b5b505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614614e03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330333100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b565b600080831415614e185760009050614e39565b6000828402905082848281614e2957fe5b0414614e3457600080fd5b809150505b92915050565b60008060008360410260208101860151925060408101860151915060ff60418201870151169350509250925092565b600080828401905083811015614e8357600080fd5b8091505092915050565b6000600180811115614e9b57fe5b836001811115614ea757fe5b1415614ec0576000808551602087018986f49050614ed0565b600080855160208701888a87f190505b95945050505050565b6000807f4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c860001b9050805491505090565b600081831015614f1a5781614f1c565b825b905092915050565b600082821115614f3357600080fd5b600082840390508091505092915050565b600080600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614614f815782614f83565b325b9050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561509b57614fed3a8610614fca573a614fcc565b855b614fdf888a614e6e90919063ffffffff16565b614e0590919063ffffffff16565b91508073ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050615096576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b615140565b6150c0856150b2888a614e6e90919063ffffffff16565b614e0590919063ffffffff16565b91506150cd8482846158b4565b61513f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330313200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5095945050505050565b6000600454146151c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b8151811115615239576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303100000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60018110156152b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303200000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60006001905060005b83518110156155b65760008482815181106152d057fe5b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156153445750600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561537c57503073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156153b457508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b615426576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303300000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614615527576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475332303400000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b80600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508092505080806001019150506152b9565b506001600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550825160038190555081600481905550505050565b60007f6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d560001b90508181555050565b600073ffffffffffffffffffffffffffffffffffffffff1660016000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461577b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475331303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001806000600173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146158b05761583d8260008360015a614e8d565b6158af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f475330303000000000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b5b5050565b60008063a9059cbb8484604051602401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050602060008251602084016000896127105a03f13d6000811461595b5760208114615963576000935061596e565b81935061596e565b600051158215171593505b505050939250505056fea26469706673582212203874bcf92e1722cc7bfa0cef1a0985cf0dc3485ba0663db3747ccdf1605df53464736f6c63430007060033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x01`\x04\x81\x90UPaY\xAE\x80b\0\0)`\09`\0\xF3\xFE`\x80`@R`\x046\x10a\x01\xDCW`\x005`\xE0\x1C\x80c\xAF\xFE\xD0\xE0\x11a\x01\x02W\x80c\xE1\x9A\x9D\xD9\x11a\0\x95W\x80c\xF0\x8A\x03#\x11a\0dW\x80c\xF0\x8A\x03#\x14a\x16GW\x80c\xF6\x98\xDA%\x14a\x16\x98W\x80c\xF8\xDC]\xD9\x14a\x16\xC3W\x80c\xFF\xA1\xADt\x14a\x17>Wa\x021V[\x80c\xE1\x9A\x9D\xD9\x14a\x13\x9BW\x80c\xE3\x18\xB5+\x14a\x13\xECW\x80c\xE7R5\xB8\x14a\x14}W\x80c\xE8f7\xDB\x14a\x14\xA8Wa\x021V[\x80c\xCC/\x84R\x11a\0\xD1W\x80c\xCC/\x84R\x14a\x10\xE8W\x80c\xD4\xD9\xBD\xCD\x14a\x11\xB5W\x80c\xD8\xD1\x1Fx\x14a\x11\xF0W\x80c\xE0\t\xCF\xDE\x14a\x13*Wa\x021V[\x80c\xAF\xFE\xD0\xE0\x14a\r\x94W\x80c\xB4\xFA\xBA\t\x14a\r\xBFW\x80c\xB6>\x80\r\x14a\x0E\xA7W\x80c\xC4\xCA:\x9C\x14a\x10\x17Wa\x021V[\x80cV$\xB2[\x11a\x01zW\x80cjv\x12\x02\x11a\x01IW\x80cjv\x12\x02\x14a\t\x94W\x80c}\x83)t\x14a\x0BPW\x80c\x93O:\x11\x14a\x0B\xBFW\x80c\xA0\xE6~+\x14a\r(Wa\x021V[\x80cV$\xB2[\x14a\x07\xFBW\x80cZ\xE6\xBD7\x14a\x08\xB9W\x80ca\x0BY%\x14a\t\x08W\x80ciN\x80\xC3\x14a\tYWa\x021V[\x80c/T\xBFn\x11a\x01\xB6W\x80c/T\xBFn\x14a\x04\xD3W\x80c4\x08\xE4p\x14a\x05:W\x80cF\x87!\xA7\x14a\x05eW\x80cR)\x07?\x14a\x06zWa\x021V[\x80c\rX/\x13\x14a\x02\x9EW\x80c\x12\xFBh\xE0\x14a\x02\xF9W\x80c-\x9A\xD5=\x14a\x04lWa\x021V[6a\x021W3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F=\x0C\xE9\xBF\xC3\xED}hb\xDB\xB2\x8B-\xEA\x94V\x1F\xE7\x14\xA1\xB4\xD0\x19\xAA\x8A\xF3\x970\xD1\xAD|=4`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA2\0[4\x80\x15a\x02=W`\0\x80\xFD[P`\0\x7Fl\x9AlJ9(N7\xED\x1C\xF5=3uw\xD1B\x12\xA4\x87\x0F\xB9v\xA46li;\x93\x99\x18\xD5`\0\x1B\x90P\x80T\x80a\x02rW`\0\x80\xF3[6`\0\x8073``\x1B6R`\0\x80`\x146\x01`\0\x80\x85Z\xF1=`\0\x80>\x80a\x02\x99W=`\0\xFD[=`\0\xF3[4\x80\x15a\x02\xAAW`\0\x80\xFD[Pa\x02\xF7`\x04\x806\x03`@\x81\x10\x15a\x02\xC1W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x17\xCEV[\0[4\x80\x15a\x03\x05W`\0\x80\xFD[Pa\x04j`\x04\x806\x03`\x80\x81\x10\x15a\x03\x1CW`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x03CW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x03UW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x03wW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x03\xDAW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x03\xECW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x04\x0EW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x1B\xBEV[\0[4\x80\x15a\x04xW`\0\x80\xFD[Pa\x04\xBB`\x04\x806\x03` \x81\x10\x15a\x04\x8FW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa$@V[`@Q\x80\x82\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x04\xDFW`\0\x80\xFD[Pa\x05\"`\x04\x806\x03` \x81\x10\x15a\x04\xF6W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa%\x12V[`@Q\x80\x82\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x05FW`\0\x80\xFD[Pa\x05Oa%\xE4V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x05qW`\0\x80\xFD[Pa\x06b`\x04\x806\x03`\x80\x81\x10\x15a\x05\x88W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x05\xCFW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x05\xE1W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x06\x03W`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90\x805`\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa%\xF1V[`@Q\x80\x82\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x06\x86W`\0\x80\xFD[Pa\x07w`\x04\x806\x03`\x80\x81\x10\x15a\x06\x9DW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x06\xE4W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x06\xF6W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x07\x18W`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90\x805`\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa'\xD7V[`@Q\x80\x83\x15\x15\x81R` \x01\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x07\xBFW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x07\xA4V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x07\xECW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x93PPPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x08\x07W`\0\x80\xFD[Pa\x08>`\x04\x806\x03`@\x81\x10\x15a\x08\x1EW`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa(\rV[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x08~W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x08cV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x08\xABW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x08\xC5W`\0\x80\xFD[Pa\x08\xF2`\x04\x806\x03` \x81\x10\x15a\x08\xDCW`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90PPPa(\x94V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\t\x14W`\0\x80\xFD[Pa\tW`\x04\x806\x03` \x81\x10\x15a\t+W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa(\xACV[\0[4\x80\x15a\teW`\0\x80\xFD[Pa\t\x92`\x04\x806\x03` \x81\x10\x15a\t|W`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90PPPa,>V[\0[a\x0B8`\x04\x806\x03a\x01@\x81\x10\x15a\t\xABW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\t\xF2W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\n\x04W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\n&W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805`\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\n\xB2W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\n\xC4W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\n\xE6W`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90PPPa-xV[`@Q\x80\x82\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x0B\\W`\0\x80\xFD[Pa\x0B\xA9`\x04\x806\x03`@\x81\x10\x15a\x0BsW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa2\xB5V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x0B\xCBW`\0\x80\xFD[Pa\r&`\x04\x806\x03``\x81\x10\x15a\x0B\xE2W`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x0C\tW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x0C\x1BW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x0C=W`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x0C\xA0W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x0C\xB2W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x0C\xD4W`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90PPPa2\xDAV[\0[4\x80\x15a\r4W`\0\x80\xFD[Pa\r=a3iV[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90` \x02\x80\x83\x83`\0[\x83\x81\x10\x15a\r\x80W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\reV[PPPP\x90P\x01\x92PPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\r\xA0W`\0\x80\xFD[Pa\r\xA9a5\x12V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\r\xCBW`\0\x80\xFD[Pa\x0E\xA5`\x04\x806\x03`@\x81\x10\x15a\r\xE2W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x0E\x1FW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x0E1W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x0ESW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90PPPa5\x18V[\0[4\x80\x15a\x0E\xB3W`\0\x80\xFD[Pa\x10\x15`\x04\x806\x03a\x01\0\x81\x10\x15a\x0E\xCBW`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x0E\xE8W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x0E\xFAW`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x0F\x1CW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x0FgW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x0FyW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x0F\x9BW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa5:V[\0[4\x80\x15a\x10#W`\0\x80\xFD[Pa\x10\xD2`\x04\x806\x03`\x80\x81\x10\x15a\x10:W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x10\x81W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x10\x93W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x10\xB5W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805`\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa6\xF8V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x10\xF4W`\0\x80\xFD[Pa\x11A`\x04\x806\x03`@\x81\x10\x15a\x11\x0BW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa8 V[`@Q\x80\x80` \x01\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81\x03\x82R\x84\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90` \x02\x80\x83\x83`\0[\x83\x81\x10\x15a\x11\xA0W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x11\x85V[PPPP\x90P\x01\x93PPPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x11\xC1W`\0\x80\xFD[Pa\x11\xEE`\x04\x806\x03` \x81\x10\x15a\x11\xD8W`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90PPPa:\x12V[\0[4\x80\x15a\x11\xFCW`\0\x80\xFD[Pa\x13\x14`\x04\x806\x03a\x01@\x81\x10\x15a\x12\x14W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x12[W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x12mW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x12\x8FW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805`\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa;\xB1V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x136W`\0\x80\xFD[Pa\x13\x99`\x04\x806\x03`@\x81\x10\x15a\x13MW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa;\xDEV[\0[4\x80\x15a\x13\xA7W`\0\x80\xFD[Pa\x13\xEA`\x04\x806\x03` \x81\x10\x15a\x13\xBEW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa?oV[\0[4\x80\x15a\x13\xF8W`\0\x80\xFD[Pa\x14{`\x04\x806\x03``\x81\x10\x15a\x14\x0FW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa?\xF3V[\0[4\x80\x15a\x14\x89W`\0\x80\xFD[Pa\x14\x92aFeV[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x14\xB4W`\0\x80\xFD[Pa\x15\xCC`\x04\x806\x03a\x01@\x81\x10\x15a\x14\xCCW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x15\x13W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x15%W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x15GW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805`\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPaFoV[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x16\x0CW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x15\xF1V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x169W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x16SW`\0\x80\xFD[Pa\x16\x96`\x04\x806\x03` \x81\x10\x15a\x16jW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPaH\x17V[\0[4\x80\x15a\x16\xA4W`\0\x80\xFD[Pa\x16\xADaHxV[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x16\xCFW`\0\x80\xFD[Pa\x17<`\x04\x806\x03``\x81\x10\x15a\x16\xE6W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPaH\xF6V[\0[4\x80\x15a\x17JW`\0\x80\xFD[Pa\x17SaM)V[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x17\x93W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x17xV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x17\xC0W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[a\x17\xD6aMbV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15a\x18@WP`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[\x80\x15a\x18xWP0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[a\x18\xEAW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS203\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x19\xEBW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS204\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x02`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP\x81`\x02`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP`\x03`\0\x81T\x80\x92\x91\x90`\x01\x01\x91\x90PUP\x7F\x94e\xFA\x0C\x96,\xC7iX\xE67:\x993&@\x0C\x1C\x94\xF8\xBE/\xE3\xA9R\xAD\xFA\x7F`\xB2\xEA&\x82`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA1\x80`\x04T\x14a\x1B\xBAWa\x1B\xB9\x81a,>V[[PPV[a\x1B\xD2`A\x82aN\x05\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x82Q\x10\x15a\x1CHW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS020\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x80\x80`\0\x80`\0[\x86\x81\x10\x15a$4Wa\x1Cd\x88\x82aN?V[\x80\x94P\x81\x95P\x82\x96PPPP`\0\x84`\xFF\x16\x14\x15a mW\x82`\0\x1C\x94Pa\x1C\x96`A\x88aN\x05\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x82`\0\x1C\x10\x15a\x1D\x0EW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS021\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x87Qa\x1D'` \x84`\0\x1CaNn\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x11\x15a\x1D\x9BW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS022\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0` \x83\x8A\x01\x01Q\x90P\x88Qa\x1D\xD1\x82a\x1D\xC3` \x87`\0\x1CaNn\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[aNn\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x11\x15a\x1EEW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS023\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[``` \x84\x8B\x01\x01\x90Pc \xC1;\x0B`\xE0\x1B{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c \xC1;\x0B\x8D\x84`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x80` \x01\x80` \x01\x83\x81\x03\x83R\x85\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x1E\xE7W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x1E\xCCV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x1F\x14W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x83\x81\x03\x82R\x84\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x1FMW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x1F2V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x1FzW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x94PPPPP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1F\x99W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1F\xADW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x1F\xC3W`\0\x80\xFD[\x81\x01\x90\x80\x80Q\x90` \x01\x90\x92\x91\x90PPP{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x14a fW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS024\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[PPa\"\xB2V[`\x01\x84`\xFF\x16\x14\x15a!\x81W\x82`\0\x1C\x94P\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x80a!\nWP`\0`\x08`\0\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x8C\x81R` \x01\x90\x81R` \x01`\0 T\x14\x15[a!|W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS025\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\"\xB1V[`\x1E\x84`\xFF\x16\x11\x15a\"IW`\x01\x8A`@Q` \x01\x80\x80\x7F\x19Ethereum Signed Message:\n32\0\0\0\0\x81RP`\x1C\x01\x82\x81R` \x01\x91PP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `\x04\x86\x03\x85\x85`@Q`\0\x81R` \x01`@R`@Q\x80\x85\x81R` \x01\x84`\xFF\x16\x81R` \x01\x83\x81R` \x01\x82\x81R` \x01\x94PPPPP` `@Q` \x81\x03\x90\x80\x84\x03\x90\x85Z\xFA\x15\x80\x15a\"8W=`\0\x80>=`\0\xFD[PPP` `@Q\x03Q\x94Pa\"\xB0V[`\x01\x8A\x85\x85\x85`@Q`\0\x81R` \x01`@R`@Q\x80\x85\x81R` \x01\x84`\xFF\x16\x81R` \x01\x83\x81R` \x01\x82\x81R` \x01\x94PPPPP` `@Q` \x81\x03\x90\x80\x84\x03\x90\x85Z\xFA\x15\x80\x15a\"\xA3W=`\0\x80>=`\0\xFD[PPP` `@Q\x03Q\x94P[[[\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x11\x80\x15a#yWP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\0\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[\x80\x15a#\xB2WP`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[a$$W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS026\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x84\x95P\x80\x80`\x01\x01\x91PPa\x1CRV[PPPPPPPPPPV[`\0\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15a%\x0BWP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x01`\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[\x90P\x91\x90PV[`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15a%\xDDWP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[\x90P\x91\x90PV[`\0\x80F\x90P\x80\x91PP\x90V[`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15a&\xBCWP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x01`\x003s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[a'.W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS104\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[a';\x85\x85\x85\x85ZaN\x8DV[\x90P\x80\x15a'\x8BW3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7Fh\x95\xC16d\xAAOg(\x8B%\xD7\xA2\x1Dz\xAA4\x91n5_\xB9\xB6\xFA\xE0\xA19\xA9\x08[\xEC\xB8`@Q`@Q\x80\x91\x03\x90\xA2a'\xCFV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xAC\xD2\xC8p(\x04\x12\x8F\xDB\r\xB2\xBBI\xF6\xD1'\xDD\x01\x81\xC1?\xD4]\xBF\xE1m\xE0\x93\x0E+\xD3u`@Q`@Q\x80\x91\x03\x90\xA2[\x94\x93PPPPV[`\0``a'\xE7\x86\x86\x86\x86a%\xF1V[\x91P`@Q` =\x01\x81\x01`@R=\x81R=`\0` \x83\x01>\x80\x91PP\x94P\x94\x92PPPV[```\0` \x83\x02g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a(+W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80`\x1F\x01`\x1F\x19\x16` \x01\x82\x01`@R\x80\x15a(^W\x81` \x01`\x01\x82\x02\x806\x837\x80\x82\x01\x91PP\x90P[P\x90P`\0[\x83\x81\x10\x15a(\x89W\x80\x85\x01T\x80` \x83\x02` \x85\x01\x01RP\x80\x80`\x01\x01\x91PPa(dV[P\x80\x91PP\x92\x91PPV[`\x07` R\x80`\0R`@`\0 `\0\x91P\x90PT\x81V[a(\xB4aMbV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15a)\x1EWP`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[a)\x90W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS101\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x01`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a*\x91W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS102\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x01`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x01`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP\x80`\x01`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP\x7F\xEC\xDF:>\xFF\xEAW\x83\xA3\xC4\xC2\x14\x0Eguwfd(\xD4N\xD9\xD4t\xA0\xB3\xA4\xC9\x94?\x84@\x81`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA1PV[a,FaMbV[`\x03T\x81\x11\x15a,\xBEW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS201\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x01\x81\x10\x15a-5W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS202\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x80`\x04\x81\x90UP\x7Fa\x0F\x7F\xF2\xB3\x04\xAE\x89\x03\xC3\xDEt\xC6\x0Cj\xB1\xF7\xD6\"k?R\xC5\x16\x19\x05\xBBZ\xD4\x03\x9C\x93`\x04T`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA1PV[`\0\x80`\0a-\x92\x8E\x8E\x8E\x8E\x8E\x8E\x8E\x8E\x8E\x8E`\x05TaFoV[\x90P`\x05`\0\x81T\x80\x92\x91\x90`\x01\x01\x91\x90PUP\x80\x80Q\x90` \x01 \x91Pa-\xBB\x82\x82\x86a2\xDAV[P`\0a-\xC6aN\xD9V[\x90P`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a/\xACW\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cu\xF0\xBBR\x8F\x8F\x8F\x8F\x8F\x8F\x8F\x8F\x8F\x8F\x8F3`@Q\x8Dc\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x8Ds\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8C\x81R` \x01\x80` \x01\x8A`\x01\x81\x11\x15a.iW\xFE[\x81R` \x01\x89\x81R` \x01\x88\x81R` \x01\x87\x81R` \x01\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x80` \x01\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x83\x81\x03\x83R\x8D\x8D\x82\x81\x81R` \x01\x92P\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPP\x83\x81\x03\x82R\x85\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a/;W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa/ V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a/hW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x9EPPPPPPPPPPPPPPP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a/\x93W`\0\x80\xFD[PZ\xF1\x15\x80\x15a/\xA7W=`\0\x80>=`\0\xFD[PPPP[a\x01\xF4a/\xD3a\t\xC4\x8B\x01`?`@\x8D\x02\x81a/\xC4W\xFE[\x04aO\n\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x01Z\x10\x15a0IW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS010\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0Z\x90Pa0\xB2\x8F\x8F\x8F\x8F\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x8E`\0\x8D\x14a0\xA7W\x8Ea0\xADV[a\t\xC4Z\x03[aN\x8DV[\x93Pa0\xC7Z\x82aO$\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90P\x83\x80a0\xD6WP`\0\x8A\x14\x15[\x80a0\xE2WP`\0\x88\x14\x15[a1TW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS013\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x80\x89\x11\x15a1nWa1k\x82\x8B\x8B\x8B\x8BaODV[\x90P[\x84\x15a1\xB8W\x7FD.q_bcF\xE8\xC5C\x81\0-\xA6\x14\xF6+\xEE\x8D'8e5\xB2R\x1E\xC8T\x08\x98Un\x84\x82`@Q\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q\x80\x91\x03\x90\xA1a1\xF8V[\x7F#B\x8B\x18\xAC\xFB>\xA6K\x08\xDC\x0C\x1D)n\xA9\xC0\x97\x02\xC0\x90\x83\xCARr\xE6M\x11[h}#\x84\x82`@Q\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q\x80\x91\x03\x90\xA1[PP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a2\xA4W\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x93'\x13h\x83\x85`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x83\x81R` \x01\x82\x15\x15\x81R` \x01\x92PPP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a2\x8BW`\0\x80\xFD[PZ\xF1\x15\x80\x15a2\x9FW=`\0\x80>=`\0\xFD[PPPP[PP\x9B\x9APPPPPPPPPPPV[`\x08` R\x81`\0R`@`\0 ` R\x80`\0R`@`\0 `\0\x91P\x91PPT\x81V[`\0`\x04T\x90P`\0\x81\x11a3WW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS001\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[a3c\x84\x84\x84\x84a\x1B\xBEV[PPPPV[```\0`\x03Tg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a3\x86W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a3\xB5W\x81` \x01` \x82\x02\x806\x837\x80\x82\x01\x91PP\x90P[P\x90P`\0\x80`\x02`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90P[`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a5\tW\x80\x83\x83\x81Q\x81\x10a4`W\xFE[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP`\x02`\0\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90P\x81\x80`\x01\x01\x92PPa4\x1FV[\x82\x93PPPP\x90V[`\x05T\x81V[`\0\x80\x82Q` \x84\x01\x85Z\xF4\x80`\0R=` R=`\0`@>`@=\x01`\0\xFD[a5\x85\x8A\x8A\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x89aQJV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a5\xC3Wa5\xC2\x84aVJV[[a6\x11\x87\x87\x87\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPPaVyV[`\0\x82\x11\x15a6+Wa6)\x82`\0`\x01\x86\x85aODV[P[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x14\x1D\xF8h\xA63\x1A\xF5(\xE3\x8C\x83\xB7\xAA\x03\xED\xC1\x9B\xE6n7\xAEg\xF9([\xF4\xF8\xE3\xC6\xA1\xA8\x8B\x8B\x8B\x8B\x89`@Q\x80\x80` \x01\x85\x81R` \x01\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81\x03\x82R\x87\x87\x82\x81\x81R` \x01\x92P` \x02\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPP\x96PPPPPPP`@Q\x80\x91\x03\x90\xA2PPPPPPPPPPV[`\0\x80Z\x90Pa7O\x87\x87\x87\x87\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x86ZaN\x8DV[a7XW`\0\x80\xFD[`\0Z\x82\x03\x90P\x80`@Q` \x01\x80\x82\x81R` \x01\x91PP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a7\xE5W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa7\xCAV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a8\x12W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xFD[```\0\x82g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a8;W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a8jW\x81` \x01` \x82\x02\x806\x837\x80\x82\x01\x91PP\x90P[P\x91P`\0\x80`\x01`\0\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90P[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15a9=WP`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[\x80\x15a9HWP\x84\x82\x10[\x15a:\x03W\x80\x84\x83\x81Q\x81\x10a9ZW\xFE[` \x02` \x01\x01\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP`\x01`\0\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90P\x81\x80`\x01\x01\x92PPa8\xD3V[\x80\x92P\x81\x84RPP\x92P\x92\x90PV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\x003s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a;\x14W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS030\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x01`\x08`\x003s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x83\x81R` \x01\x90\x81R` \x01`\0 \x81\x90UP3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81\x7F\xF2\xA0\xEB\x15dr\xD1D\x02U\xB0\xD7\xC1\xE1\x9C\xC0q\x15\xD1\x05\x1F\xE6\x05\xB0\xDC\xE6\x9A\xCF\xEC\x88M\x9C`@Q`@Q\x80\x91\x03\x90\xA3PV[`\0a;\xC6\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8CaFoV[\x80Q\x90` \x01 \x90P\x9B\x9APPPPPPPPPPPV[a;\xE6aMbV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15a|\x04m\xA9\x941=~\xD0\xD1\x92\x02\x8B\xC7\xC2(\xB0\x81`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA1PV[`\0\x7FG\xE7\x954\xA2E\x95.\x8B\x16\x89:3k\x85\xA3\xD9\xEA\x9F\xA8\xC5s\xF3\xD8\x03\xAF\xB9*yF\x92\x18`\0\x1BaH\xA6a%\xE4V[0`@Q` \x01\x80\x84\x81R` \x01\x83\x81R` \x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x93PPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x90V[aH\xFEaMbV[\x80`\x01`\x03T\x03\x10\x15aIyW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS201\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15aI\xE3WP`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[aJUW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS203\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\0\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14aKUW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS205\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x02`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\0\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP`\0`\x02`\0\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP`\x03`\0\x81T\x80\x92\x91\x90`\x01\x90\x03\x91\x90PUP\x7F\xF8\xD4\x9F\xC5)\x81.\x9A|\\P\xE6\x9C \xF0\xDC\xCC\r\xB8\xFA\x95\xC9\x8B\xC5\x8C\xC9\xA4\xF1\xC1)\x9E\xAF\x82`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA1\x80`\x04T\x14aM$WaM#\x81a,>V[[PPPV[`@Q\x80`@\x01`@R\x80`\x05\x81R` \x01\x7F1.3.0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP\x81V[0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14aN\x03W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS031\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[V[`\0\x80\x83\x14\x15aN\x18W`\0\x90PaN9V[`\0\x82\x84\x02\x90P\x82\x84\x82\x81aN)W\xFE[\x04\x14aN4W`\0\x80\xFD[\x80\x91PP[\x92\x91PPV[`\0\x80`\0\x83`A\x02` \x81\x01\x86\x01Q\x92P`@\x81\x01\x86\x01Q\x91P`\xFF`A\x82\x01\x87\x01Q\x16\x93PP\x92P\x92P\x92V[`\0\x80\x82\x84\x01\x90P\x83\x81\x10\x15aN\x83W`\0\x80\xFD[\x80\x91PP\x92\x91PPV[`\0`\x01\x80\x81\x11\x15aN\x9BW\xFE[\x83`\x01\x81\x11\x15aN\xA7W\xFE[\x14\x15aN\xC0W`\0\x80\x85Q` \x87\x01\x89\x86\xF4\x90PaN\xD0V[`\0\x80\x85Q` \x87\x01\x88\x8A\x87\xF1\x90P[\x95\x94PPPPPV[`\0\x80\x7FJ Ob\x0C\x8C\\\xCD\xCA?\xD5M\0;\xAD\xD8[\xA5\0CjC\x1F\x0C\xBD\xA4\xF5X\xC9<4\xC8`\0\x1B\x90P\x80T\x91PP\x90V[`\0\x81\x83\x10\x15aO\x1AW\x81aO\x1CV[\x82[\x90P\x92\x91PPV[`\0\x82\x82\x11\x15aO3W`\0\x80\xFD[`\0\x82\x84\x03\x90P\x80\x91PP\x92\x91PPV[`\0\x80`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14aO\x81W\x82aO\x83V[2[\x90P`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15aP\x9BWaO\xED:\x86\x10aO\xCAW:aO\xCCV[\x85[aO\xDF\x88\x8AaNn\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[aN\x05\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x91P\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x08\xFC\x83\x90\x81\x15\x02\x90`@Q`\0`@Q\x80\x83\x03\x81\x85\x88\x88\xF1\x93PPPPaP\x96W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS011\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[aQ@V[aP\xC0\x85aP\xB2\x88\x8AaNn\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[aN\x05\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x91PaP\xCD\x84\x82\x84aX\xB4V[aQ?W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS012\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[[P\x95\x94PPPPPV[`\0`\x04T\x14aQ\xC2W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x81Q\x81\x11\x15aR9W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS201\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x01\x81\x10\x15aR\xB0W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS202\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0`\x01\x90P`\0[\x83Q\x81\x10\x15aU\xB6W`\0\x84\x82\x81Q\x81\x10aR\xD0W\xFE[` \x02` \x01\x01Q\x90P`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15\x80\x15aSDWP`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[\x80\x15aS|WP0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[\x80\x15aS\xB4WP\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[aT&W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS203\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x02`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14aU'W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS204\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x80`\x02`\0\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP\x80\x92PP\x80\x80`\x01\x01\x91PPaR\xB9V[P`\x01`\x02`\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP\x82Q`\x03\x81\x90UP\x81`\x04\x81\x90UPPPPV[`\0\x7Fl\x9AlJ9(N7\xED\x1C\xF5=3uw\xD1B\x12\xA4\x87\x0F\xB9v\xA46li;\x93\x99\x18\xD5`\0\x1B\x90P\x81\x81UPPV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x01`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14aW{W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS100\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x01\x80`\0`\x01s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14aX\xB0WaX=\x82`\0\x83`\x01ZaN\x8DV[aX\xAFW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x05\x81R` \x01\x80\x7FGS000\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[[PPV[`\0\x80c\xA9\x05\x9C\xBB\x84\x84`@Q`$\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x90`\xE0\x1B` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x81\x83\x16\x17\x83RPPPP\x90P` `\0\x82Q` \x84\x01`\0\x89a'\x10Z\x03\xF1=`\0\x81\x14aY[W` \x81\x14aYcW`\0\x93PaYnV[\x81\x93PaYnV[`\0Q\x15\x82\x15\x17\x15\x93P[PPP\x93\x92PPPV\xFE\xA2dipfsX\"\x12 8t\xBC\xF9.\x17\"\xCC{\xFA\x0C\xEF\x1A\t\x85\xCF\r\xC3H[\xA0f=\xB3t|\xCD\xF1`]\xF54dsolcC\0\x07\x06\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `AddedOwner(address)` and selector `0x9465fa0c962cc76958e6373a993326400c1c94f8be2fe3a952adfa7f60b2ea26`. + ```solidity + event AddedOwner(address owner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct AddedOwner { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for AddedOwner { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "AddedOwner(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 148u8, 101u8, 250u8, 12u8, 150u8, 44u8, 199u8, 105u8, 88u8, 230u8, 55u8, 58u8, + 153u8, 51u8, 38u8, 64u8, 12u8, 28u8, 148u8, 248u8, 190u8, 47u8, 227u8, 169u8, + 82u8, 173u8, 250u8, 127u8, 96u8, 178u8, 234u8, 38u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { owner: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for AddedOwner { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&AddedOwner> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &AddedOwner) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ApproveHash(bytes32,address)` and selector `0xf2a0eb156472d1440255b0d7c1e19cc07115d1051fe605b0dce69acfec884d9c`. + ```solidity + event ApproveHash(bytes32 indexed approvedHash, address indexed owner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ApproveHash { + #[allow(missing_docs)] + pub approvedHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ApproveHash { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ApproveHash(bytes32,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 242u8, 160u8, 235u8, 21u8, 100u8, 114u8, 209u8, 68u8, 2u8, 85u8, 176u8, 215u8, + 193u8, 225u8, 156u8, 192u8, 113u8, 21u8, 209u8, 5u8, 31u8, 230u8, 5u8, 176u8, + 220u8, 230u8, 154u8, 207u8, 236u8, 136u8, 77u8, 156u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + approvedHash: topics.1, + owner: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.approvedHash.clone(), + self.owner.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.approvedHash); + out[2usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ApproveHash { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ApproveHash> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ApproveHash) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ChangedFallbackHandler(address)` and selector `0x5ac6c46c93c8d0e53714ba3b53db3e7c046da994313d7ed0d192028bc7c228b0`. + ```solidity + event ChangedFallbackHandler(address handler); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ChangedFallbackHandler { + #[allow(missing_docs)] + pub handler: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ChangedFallbackHandler { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ChangedFallbackHandler(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 90u8, 198u8, 196u8, 108u8, 147u8, 200u8, 208u8, 229u8, 55u8, 20u8, 186u8, 59u8, + 83u8, 219u8, 62u8, 124u8, 4u8, 109u8, 169u8, 148u8, 49u8, 61u8, 126u8, 208u8, + 209u8, 146u8, 2u8, 139u8, 199u8, 194u8, 40u8, 176u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { handler: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.handler, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ChangedFallbackHandler { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ChangedFallbackHandler> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ChangedFallbackHandler) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ChangedGuard(address)` and selector `0x1151116914515bc0891ff9047a6cb32cf902546f83066499bcf8ba33d2353fa2`. + ```solidity + event ChangedGuard(address guard); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ChangedGuard { + #[allow(missing_docs)] + pub guard: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ChangedGuard { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ChangedGuard(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 17u8, 81u8, 17u8, 105u8, 20u8, 81u8, 91u8, 192u8, 137u8, 31u8, 249u8, 4u8, + 122u8, 108u8, 179u8, 44u8, 249u8, 2u8, 84u8, 111u8, 131u8, 6u8, 100u8, 153u8, + 188u8, 248u8, 186u8, 51u8, 210u8, 53u8, 63u8, 162u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { guard: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.guard, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ChangedGuard { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ChangedGuard> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ChangedGuard) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ChangedThreshold(uint256)` and selector `0x610f7ff2b304ae8903c3de74c60c6ab1f7d6226b3f52c5161905bb5ad4039c93`. + ```solidity + event ChangedThreshold(uint256 threshold); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ChangedThreshold { + #[allow(missing_docs)] + pub threshold: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ChangedThreshold { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ChangedThreshold(uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 97u8, 15u8, 127u8, 242u8, 179u8, 4u8, 174u8, 137u8, 3u8, 195u8, 222u8, 116u8, + 198u8, 12u8, 106u8, 177u8, 247u8, 214u8, 34u8, 107u8, 63u8, 82u8, 197u8, 22u8, + 25u8, 5u8, 187u8, 90u8, 212u8, 3u8, 156u8, 147u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { threshold: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.threshold, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ChangedThreshold { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ChangedThreshold> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ChangedThreshold) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `DisabledModule(address)` and selector `0xaab4fa2b463f581b2b32cb3b7e3b704b9ce37cc209b5fb4d77e593ace4054276`. + ```solidity + event DisabledModule(address module); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct DisabledModule { + #[allow(missing_docs)] + pub module: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for DisabledModule { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "DisabledModule(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 170u8, 180u8, 250u8, 43u8, 70u8, 63u8, 88u8, 27u8, 43u8, 50u8, 203u8, 59u8, + 126u8, 59u8, 112u8, 75u8, 156u8, 227u8, 124u8, 194u8, 9u8, 181u8, 251u8, 77u8, + 119u8, 229u8, 147u8, 172u8, 228u8, 5u8, 66u8, 118u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { module: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.module, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for DisabledModule { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&DisabledModule> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &DisabledModule) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `EnabledModule(address)` and selector `0xecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f8440`. + ```solidity + event EnabledModule(address module); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct EnabledModule { + #[allow(missing_docs)] + pub module: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for EnabledModule { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "EnabledModule(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 236u8, 223u8, 58u8, 62u8, 255u8, 234u8, 87u8, 131u8, 163u8, 196u8, 194u8, 20u8, + 14u8, 103u8, 117u8, 119u8, 102u8, 100u8, 40u8, 212u8, 78u8, 217u8, 212u8, + 116u8, 160u8, 179u8, 164u8, 201u8, 148u8, 63u8, 132u8, 64u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { module: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.module, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for EnabledModule { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&EnabledModule> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &EnabledModule) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ExecutionFailure(bytes32,uint256)` and selector `0x23428b18acfb3ea64b08dc0c1d296ea9c09702c09083ca5272e64d115b687d23`. + ```solidity + event ExecutionFailure(bytes32 txHash, uint256 payment); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ExecutionFailure { + #[allow(missing_docs)] + pub txHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub payment: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ExecutionFailure { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ExecutionFailure(bytes32,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 35u8, 66u8, 139u8, 24u8, 172u8, 251u8, 62u8, 166u8, 75u8, 8u8, 220u8, 12u8, + 29u8, 41u8, 110u8, 169u8, 192u8, 151u8, 2u8, 192u8, 144u8, 131u8, 202u8, 82u8, + 114u8, 230u8, 77u8, 17u8, 91u8, 104u8, 125u8, 35u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + txHash: data.0, + payment: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.txHash), + as alloy_sol_types::SolType>::tokenize(&self.payment), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ExecutionFailure { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ExecutionFailure> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ExecutionFailure) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ExecutionFromModuleFailure(address)` and selector `0xacd2c8702804128fdb0db2bb49f6d127dd0181c13fd45dbfe16de0930e2bd375`. + ```solidity + event ExecutionFromModuleFailure(address indexed module); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ExecutionFromModuleFailure { + #[allow(missing_docs)] + pub module: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ExecutionFromModuleFailure { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ExecutionFromModuleFailure(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 172u8, 210u8, 200u8, 112u8, 40u8, 4u8, 18u8, 143u8, 219u8, 13u8, 178u8, 187u8, + 73u8, 246u8, 209u8, 39u8, 221u8, 1u8, 129u8, 193u8, 63u8, 212u8, 93u8, 191u8, + 225u8, 109u8, 224u8, 147u8, 14u8, 43u8, 211u8, 117u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { module: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.module.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.module, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ExecutionFromModuleFailure { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ExecutionFromModuleFailure> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ExecutionFromModuleFailure) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ExecutionFromModuleSuccess(address)` and selector `0x6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb8`. + ```solidity + event ExecutionFromModuleSuccess(address indexed module); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ExecutionFromModuleSuccess { + #[allow(missing_docs)] + pub module: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ExecutionFromModuleSuccess { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ExecutionFromModuleSuccess(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 104u8, 149u8, 193u8, 54u8, 100u8, 170u8, 79u8, 103u8, 40u8, 139u8, 37u8, 215u8, + 162u8, 29u8, 122u8, 170u8, 52u8, 145u8, 110u8, 53u8, 95u8, 185u8, 182u8, 250u8, + 224u8, 161u8, 57u8, 169u8, 8u8, 91u8, 236u8, 184u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { module: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.module.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.module, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ExecutionFromModuleSuccess { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ExecutionFromModuleSuccess> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ExecutionFromModuleSuccess) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ExecutionSuccess(bytes32,uint256)` and selector `0x442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e`. + ```solidity + event ExecutionSuccess(bytes32 txHash, uint256 payment); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ExecutionSuccess { + #[allow(missing_docs)] + pub txHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub payment: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ExecutionSuccess { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ExecutionSuccess(bytes32,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 68u8, 46u8, 113u8, 95u8, 98u8, 99u8, 70u8, 232u8, 197u8, 67u8, 129u8, 0u8, + 45u8, 166u8, 20u8, 246u8, 43u8, 238u8, 141u8, 39u8, 56u8, 101u8, 53u8, 178u8, + 82u8, 30u8, 200u8, 84u8, 8u8, 152u8, 85u8, 110u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + txHash: data.0, + payment: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.txHash), + as alloy_sol_types::SolType>::tokenize(&self.payment), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ExecutionSuccess { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ExecutionSuccess> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ExecutionSuccess) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `RemovedOwner(address)` and selector `0xf8d49fc529812e9a7c5c50e69c20f0dccc0db8fa95c98bc58cc9a4f1c1299eaf`. + ```solidity + event RemovedOwner(address owner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct RemovedOwner { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RemovedOwner { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "RemovedOwner(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 248u8, 212u8, 159u8, 197u8, 41u8, 129u8, 46u8, 154u8, 124u8, 92u8, 80u8, 230u8, + 156u8, 32u8, 240u8, 220u8, 204u8, 13u8, 184u8, 250u8, 149u8, 201u8, 139u8, + 197u8, 140u8, 201u8, 164u8, 241u8, 193u8, 41u8, 158u8, 175u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { owner: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RemovedOwner { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RemovedOwner> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RemovedOwner) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SafeReceived(address,uint256)` and selector `0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d`. + ```solidity + event SafeReceived(address indexed sender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SafeReceived { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SafeReceived { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SafeReceived(address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 61u8, 12u8, 233u8, 191u8, 195u8, 237u8, 125u8, 104u8, 98u8, 219u8, 178u8, + 139u8, 45u8, 234u8, 148u8, 86u8, 31u8, 231u8, 20u8, 161u8, 180u8, 208u8, 25u8, + 170u8, 138u8, 243u8, 151u8, 48u8, 209u8, 173u8, 124u8, 61u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.sender.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SafeReceived { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SafeReceived> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SafeReceived) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SafeSetup(address,address[],uint256,address,address)` and selector `0x141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a8`. + ```solidity + event SafeSetup(address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SafeSetup { + #[allow(missing_docs)] + pub initiator: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub owners: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub threshold: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub initializer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub fallbackHandler: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SafeSetup { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SafeSetup(address,address[],uint256,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 20u8, 29u8, 248u8, 104u8, 166u8, 51u8, 26u8, 245u8, 40u8, 227u8, 140u8, 131u8, + 183u8, 170u8, 3u8, 237u8, 193u8, 155u8, 230u8, 110u8, 55u8, 174u8, 103u8, + 249u8, 40u8, 91u8, 244u8, 248u8, 227u8, 198u8, 161u8, 168u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + initiator: topics.1, + owners: data.0, + threshold: data.1, + initializer: data.2, + fallbackHandler: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.owners), + as alloy_sol_types::SolType>::tokenize(&self.threshold), + ::tokenize( + &self.initializer, + ), + ::tokenize( + &self.fallbackHandler, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.initiator.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.initiator, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SafeSetup { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SafeSetup> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SafeSetup) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SignMsg(bytes32)` and selector `0xe7f4675038f4f6034dfcbbb24c4dc08e4ebf10eb9d257d3d02c0f38d122ac6e4`. + ```solidity + event SignMsg(bytes32 indexed msgHash); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SignMsg { + #[allow(missing_docs)] + pub msgHash: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SignMsg { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SignMsg(bytes32)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 231u8, 244u8, 103u8, 80u8, 56u8, 244u8, 246u8, 3u8, 77u8, 252u8, 187u8, 178u8, + 76u8, 77u8, 192u8, 142u8, 78u8, 191u8, 16u8, 235u8, 157u8, 37u8, 125u8, 61u8, + 2u8, 192u8, 243u8, 141u8, 18u8, 42u8, 198u8, 228u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { msgHash: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.msgHash.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.msgHash); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SignMsg { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SignMsg> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SignMsg) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall {} + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `VERSION()` and selector `0xffa1ad74`. + ```solidity + function VERSION() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct VERSIONCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`VERSION()`](VERSIONCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct VERSIONReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: VERSIONCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for VERSIONCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: VERSIONReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for VERSIONReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for VERSIONCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [255u8, 161u8, 173u8, 116u8]; + const SIGNATURE: &'static str = "VERSION()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: VERSIONReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: VERSIONReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `domainSeparator()` and selector `0xf698da25`. + ```solidity + function domainSeparator() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct domainSeparatorCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`domainSeparator()`](domainSeparatorCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct domainSeparatorReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: domainSeparatorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for domainSeparatorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: domainSeparatorReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for domainSeparatorReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for domainSeparatorCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [246u8, 152u8, 218u8, 37u8]; + const SIGNATURE: &'static str = "domainSeparator()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: domainSeparatorReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: domainSeparatorReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)` and selector `0x6a761202`. + ```solidity + function execTransaction(address to, uint256 value, bytes memory data, Enum.Operation operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes memory signatures) external payable returns (bool success); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct execTransactionCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub operation: ::RustType, + #[allow(missing_docs)] + pub safeTxGas: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub baseGas: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub gasPrice: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub gasToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub refundReceiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub signatures: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256, + /// address,address,bytes)`](execTransactionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct execTransactionReturn { + #[allow(missing_docs)] + pub success: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + Enum::Operation, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ::RustType, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: execTransactionCall) -> Self { + ( + value.to, + value.value, + value.data, + value.operation, + value.safeTxGas, + value.baseGas, + value.gasPrice, + value.gasToken, + value.refundReceiver, + value.signatures, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for execTransactionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + value: tuple.1, + data: tuple.2, + operation: tuple.3, + safeTxGas: tuple.4, + baseGas: tuple.5, + gasPrice: tuple.6, + gasToken: tuple.7, + refundReceiver: tuple.8, + signatures: tuple.9, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: execTransactionReturn) -> Self { + (value.success,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for execTransactionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { success: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for execTransactionCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + Enum::Operation, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [106u8, 118u8, 18u8, 2u8]; + const SIGNATURE: &'static str = "execTransaction(address,uint256,bytes,uint8,uint256,\ + uint256,uint256,address,address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.data, + ), + ::tokenize(&self.operation), + as alloy_sol_types::SolType>::tokenize( + &self.safeTxGas, + ), + as alloy_sol_types::SolType>::tokenize( + &self.baseGas, + ), + as alloy_sol_types::SolType>::tokenize( + &self.gasPrice, + ), + ::tokenize( + &self.gasToken, + ), + ::tokenize( + &self.refundReceiver, + ), + ::tokenize( + &self.signatures, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: execTransactionReturn = r.into(); + r.success + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: execTransactionReturn = r.into(); + r.success + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonce()` and selector `0xaffed0e0`. + ```solidity + function nonce() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nonceCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`nonce()`](nonceCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nonceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nonceCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nonceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nonceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nonceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nonceCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [175u8, 254u8, 208u8, 224u8]; + const SIGNATURE: &'static str = "nonce()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nonceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nonceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `setup(address[],uint256,address,bytes,address,address,uint256,address)` and selector `0xb63e800d`. + ```solidity + function setup(address[] memory _owners, uint256 _threshold, address to, bytes memory data, address fallbackHandler, address paymentToken, uint256 payment, address paymentReceiver) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setupCall { + #[allow(missing_docs)] + pub _owners: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub _threshold: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub fallbackHandler: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub paymentToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub payment: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub paymentReceiver: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`setup(address[],uint256,address,bytes,address,address,uint256, + /// address)`](setupCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setupReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setupCall) -> Self { + ( + value._owners, + value._threshold, + value.to, + value.data, + value.fallbackHandler, + value.paymentToken, + value.payment, + value.paymentReceiver, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setupCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _owners: tuple.0, + _threshold: tuple.1, + to: tuple.2, + data: tuple.3, + fallbackHandler: tuple.4, + paymentToken: tuple.5, + payment: tuple.6, + paymentReceiver: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setupReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setupReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl setupReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for setupCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type Return = setupReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [182u8, 62u8, 128u8, 13u8]; + const SIGNATURE: &'static str = + "setup(address[],uint256,address,bytes,address,address,uint256,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self._owners), + as alloy_sol_types::SolType>::tokenize(&self._threshold), + ::tokenize( + &self.to, + ), + ::tokenize( + &self.data, + ), + ::tokenize( + &self.fallbackHandler, + ), + ::tokenize( + &self.paymentToken, + ), + as alloy_sol_types::SolType>::tokenize(&self.payment), + ::tokenize( + &self.paymentReceiver, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + setupReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`GnosisSafe`](self) function calls. + #[derive(Clone)] + pub enum GnosisSafeCalls { + #[allow(missing_docs)] + VERSION(VERSIONCall), + #[allow(missing_docs)] + domainSeparator(domainSeparatorCall), + #[allow(missing_docs)] + execTransaction(execTransactionCall), + #[allow(missing_docs)] + nonce(nonceCall), + #[allow(missing_docs)] + setup(setupCall), + } + impl GnosisSafeCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [106u8, 118u8, 18u8, 2u8], + [175u8, 254u8, 208u8, 224u8], + [182u8, 62u8, 128u8, 13u8], + [246u8, 152u8, 218u8, 37u8], + [255u8, 161u8, 173u8, 116u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(execTransaction), + ::core::stringify!(nonce), + ::core::stringify!(setup), + ::core::stringify!(domainSeparator), + ::core::stringify!(VERSION), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for GnosisSafeCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "GnosisSafeCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::VERSION(_) => ::SELECTOR, + Self::domainSeparator(_) => { + ::SELECTOR + } + Self::execTransaction(_) => { + ::SELECTOR + } + Self::nonce(_) => ::SELECTOR, + Self::setup(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn execTransaction(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GnosisSafeCalls::execTransaction) + } + execTransaction + }, + { + fn nonce(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GnosisSafeCalls::nonce) + } + nonce + }, + { + fn setup(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GnosisSafeCalls::setup) + } + setup + }, + { + fn domainSeparator(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GnosisSafeCalls::domainSeparator) + } + domainSeparator + }, + { + fn VERSION(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GnosisSafeCalls::VERSION) + } + VERSION + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn execTransaction(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GnosisSafeCalls::execTransaction) + } + execTransaction + }, + { + fn nonce(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GnosisSafeCalls::nonce) + } + nonce + }, + { + fn setup(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GnosisSafeCalls::setup) + } + setup + }, + { + fn domainSeparator(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GnosisSafeCalls::domainSeparator) + } + domainSeparator + }, + { + fn VERSION(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GnosisSafeCalls::VERSION) + } + VERSION + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::VERSION(inner) => { + ::abi_encoded_size(inner) + } + Self::domainSeparator(inner) => { + ::abi_encoded_size(inner) + } + Self::execTransaction(inner) => { + ::abi_encoded_size(inner) + } + Self::nonce(inner) => { + ::abi_encoded_size(inner) + } + Self::setup(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::VERSION(inner) => { + ::abi_encode_raw(inner, out) + } + Self::domainSeparator(inner) => { + ::abi_encode_raw(inner, out) + } + Self::execTransaction(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonce(inner) => { + ::abi_encode_raw(inner, out) + } + Self::setup(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`GnosisSafe`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum GnosisSafeEvents { + #[allow(missing_docs)] + AddedOwner(AddedOwner), + #[allow(missing_docs)] + ApproveHash(ApproveHash), + #[allow(missing_docs)] + ChangedFallbackHandler(ChangedFallbackHandler), + #[allow(missing_docs)] + ChangedGuard(ChangedGuard), + #[allow(missing_docs)] + ChangedThreshold(ChangedThreshold), + #[allow(missing_docs)] + DisabledModule(DisabledModule), + #[allow(missing_docs)] + EnabledModule(EnabledModule), + #[allow(missing_docs)] + ExecutionFailure(ExecutionFailure), + #[allow(missing_docs)] + ExecutionFromModuleFailure(ExecutionFromModuleFailure), + #[allow(missing_docs)] + ExecutionFromModuleSuccess(ExecutionFromModuleSuccess), + #[allow(missing_docs)] + ExecutionSuccess(ExecutionSuccess), + #[allow(missing_docs)] + RemovedOwner(RemovedOwner), + #[allow(missing_docs)] + SafeReceived(SafeReceived), + #[allow(missing_docs)] + SafeSetup(SafeSetup), + #[allow(missing_docs)] + SignMsg(SignMsg), + } + impl GnosisSafeEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 17u8, 81u8, 17u8, 105u8, 20u8, 81u8, 91u8, 192u8, 137u8, 31u8, 249u8, 4u8, 122u8, + 108u8, 179u8, 44u8, 249u8, 2u8, 84u8, 111u8, 131u8, 6u8, 100u8, 153u8, 188u8, + 248u8, 186u8, 51u8, 210u8, 53u8, 63u8, 162u8, + ], + [ + 20u8, 29u8, 248u8, 104u8, 166u8, 51u8, 26u8, 245u8, 40u8, 227u8, 140u8, 131u8, + 183u8, 170u8, 3u8, 237u8, 193u8, 155u8, 230u8, 110u8, 55u8, 174u8, 103u8, 249u8, + 40u8, 91u8, 244u8, 248u8, 227u8, 198u8, 161u8, 168u8, + ], + [ + 35u8, 66u8, 139u8, 24u8, 172u8, 251u8, 62u8, 166u8, 75u8, 8u8, 220u8, 12u8, 29u8, + 41u8, 110u8, 169u8, 192u8, 151u8, 2u8, 192u8, 144u8, 131u8, 202u8, 82u8, 114u8, + 230u8, 77u8, 17u8, 91u8, 104u8, 125u8, 35u8, + ], + [ + 61u8, 12u8, 233u8, 191u8, 195u8, 237u8, 125u8, 104u8, 98u8, 219u8, 178u8, 139u8, + 45u8, 234u8, 148u8, 86u8, 31u8, 231u8, 20u8, 161u8, 180u8, 208u8, 25u8, 170u8, + 138u8, 243u8, 151u8, 48u8, 209u8, 173u8, 124u8, 61u8, + ], + [ + 68u8, 46u8, 113u8, 95u8, 98u8, 99u8, 70u8, 232u8, 197u8, 67u8, 129u8, 0u8, 45u8, + 166u8, 20u8, 246u8, 43u8, 238u8, 141u8, 39u8, 56u8, 101u8, 53u8, 178u8, 82u8, 30u8, + 200u8, 84u8, 8u8, 152u8, 85u8, 110u8, + ], + [ + 90u8, 198u8, 196u8, 108u8, 147u8, 200u8, 208u8, 229u8, 55u8, 20u8, 186u8, 59u8, + 83u8, 219u8, 62u8, 124u8, 4u8, 109u8, 169u8, 148u8, 49u8, 61u8, 126u8, 208u8, + 209u8, 146u8, 2u8, 139u8, 199u8, 194u8, 40u8, 176u8, + ], + [ + 97u8, 15u8, 127u8, 242u8, 179u8, 4u8, 174u8, 137u8, 3u8, 195u8, 222u8, 116u8, + 198u8, 12u8, 106u8, 177u8, 247u8, 214u8, 34u8, 107u8, 63u8, 82u8, 197u8, 22u8, + 25u8, 5u8, 187u8, 90u8, 212u8, 3u8, 156u8, 147u8, + ], + [ + 104u8, 149u8, 193u8, 54u8, 100u8, 170u8, 79u8, 103u8, 40u8, 139u8, 37u8, 215u8, + 162u8, 29u8, 122u8, 170u8, 52u8, 145u8, 110u8, 53u8, 95u8, 185u8, 182u8, 250u8, + 224u8, 161u8, 57u8, 169u8, 8u8, 91u8, 236u8, 184u8, + ], + [ + 148u8, 101u8, 250u8, 12u8, 150u8, 44u8, 199u8, 105u8, 88u8, 230u8, 55u8, 58u8, + 153u8, 51u8, 38u8, 64u8, 12u8, 28u8, 148u8, 248u8, 190u8, 47u8, 227u8, 169u8, 82u8, + 173u8, 250u8, 127u8, 96u8, 178u8, 234u8, 38u8, + ], + [ + 170u8, 180u8, 250u8, 43u8, 70u8, 63u8, 88u8, 27u8, 43u8, 50u8, 203u8, 59u8, 126u8, + 59u8, 112u8, 75u8, 156u8, 227u8, 124u8, 194u8, 9u8, 181u8, 251u8, 77u8, 119u8, + 229u8, 147u8, 172u8, 228u8, 5u8, 66u8, 118u8, + ], + [ + 172u8, 210u8, 200u8, 112u8, 40u8, 4u8, 18u8, 143u8, 219u8, 13u8, 178u8, 187u8, + 73u8, 246u8, 209u8, 39u8, 221u8, 1u8, 129u8, 193u8, 63u8, 212u8, 93u8, 191u8, + 225u8, 109u8, 224u8, 147u8, 14u8, 43u8, 211u8, 117u8, + ], + [ + 231u8, 244u8, 103u8, 80u8, 56u8, 244u8, 246u8, 3u8, 77u8, 252u8, 187u8, 178u8, + 76u8, 77u8, 192u8, 142u8, 78u8, 191u8, 16u8, 235u8, 157u8, 37u8, 125u8, 61u8, 2u8, + 192u8, 243u8, 141u8, 18u8, 42u8, 198u8, 228u8, + ], + [ + 236u8, 223u8, 58u8, 62u8, 255u8, 234u8, 87u8, 131u8, 163u8, 196u8, 194u8, 20u8, + 14u8, 103u8, 117u8, 119u8, 102u8, 100u8, 40u8, 212u8, 78u8, 217u8, 212u8, 116u8, + 160u8, 179u8, 164u8, 201u8, 148u8, 63u8, 132u8, 64u8, + ], + [ + 242u8, 160u8, 235u8, 21u8, 100u8, 114u8, 209u8, 68u8, 2u8, 85u8, 176u8, 215u8, + 193u8, 225u8, 156u8, 192u8, 113u8, 21u8, 209u8, 5u8, 31u8, 230u8, 5u8, 176u8, + 220u8, 230u8, 154u8, 207u8, 236u8, 136u8, 77u8, 156u8, + ], + [ + 248u8, 212u8, 159u8, 197u8, 41u8, 129u8, 46u8, 154u8, 124u8, 92u8, 80u8, 230u8, + 156u8, 32u8, 240u8, 220u8, 204u8, 13u8, 184u8, 250u8, 149u8, 201u8, 139u8, 197u8, + 140u8, 201u8, 164u8, 241u8, 193u8, 41u8, 158u8, 175u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(ChangedGuard), + ::core::stringify!(SafeSetup), + ::core::stringify!(ExecutionFailure), + ::core::stringify!(SafeReceived), + ::core::stringify!(ExecutionSuccess), + ::core::stringify!(ChangedFallbackHandler), + ::core::stringify!(ChangedThreshold), + ::core::stringify!(ExecutionFromModuleSuccess), + ::core::stringify!(AddedOwner), + ::core::stringify!(DisabledModule), + ::core::stringify!(ExecutionFromModuleFailure), + ::core::stringify!(SignMsg), + ::core::stringify!(EnabledModule), + ::core::stringify!(ApproveHash), + ::core::stringify!(RemovedOwner), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for GnosisSafeEvents { + const COUNT: usize = 15usize; + const NAME: &'static str = "GnosisSafeEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::AddedOwner) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ApproveHash) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ChangedFallbackHandler) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ChangedGuard) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ChangedThreshold) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::DisabledModule) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::EnabledModule) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ExecutionFailure) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ExecutionFromModuleFailure) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ExecutionFromModuleSuccess) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ExecutionSuccess) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::RemovedOwner) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::SafeReceived) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::SafeSetup) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::SignMsg) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for GnosisSafeEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::AddedOwner(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ApproveHash(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ChangedFallbackHandler(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ChangedGuard(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ChangedThreshold(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::DisabledModule(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::EnabledModule(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ExecutionFailure(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ExecutionFromModuleFailure(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ExecutionFromModuleSuccess(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ExecutionSuccess(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::RemovedOwner(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SafeReceived(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SafeSetup(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::SignMsg(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::AddedOwner(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ApproveHash(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ChangedFallbackHandler(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ChangedGuard(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ChangedThreshold(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::DisabledModule(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::EnabledModule(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ExecutionFailure(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ExecutionFromModuleFailure(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ExecutionFromModuleSuccess(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ExecutionSuccess(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::RemovedOwner(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SafeReceived(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SafeSetup(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SignMsg(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GnosisSafe`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GnosisSafeInstance { + GnosisSafeInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> + { + GnosisSafeInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + GnosisSafeInstance::::deploy_builder(__provider) + } + /**A [`GnosisSafe`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GnosisSafe`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GnosisSafeInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GnosisSafeInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GnosisSafeInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GnosisSafeInstance + { + /**Creates a new wrapper around an on-chain [`GnosisSafe`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GnosisSafeInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GnosisSafeInstance { + GnosisSafeInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GnosisSafeInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`VERSION`] function. + pub fn VERSION(&self) -> alloy_contract::SolCallBuilder<&P, VERSIONCall, N> { + self.call_builder(&VERSIONCall) + } + + ///Creates a new call builder for the [`domainSeparator`] function. + pub fn domainSeparator( + &self, + ) -> alloy_contract::SolCallBuilder<&P, domainSeparatorCall, N> { + self.call_builder(&domainSeparatorCall) + } + + ///Creates a new call builder for the [`execTransaction`] function. + pub fn execTransaction( + &self, + to: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + data: alloy_sol_types::private::Bytes, + operation: ::RustType, + safeTxGas: alloy_sol_types::private::primitives::aliases::U256, + baseGas: alloy_sol_types::private::primitives::aliases::U256, + gasPrice: alloy_sol_types::private::primitives::aliases::U256, + gasToken: alloy_sol_types::private::Address, + refundReceiver: alloy_sol_types::private::Address, + signatures: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, execTransactionCall, N> { + self.call_builder(&execTransactionCall { + to, + value, + data, + operation, + safeTxGas, + baseGas, + gasPrice, + gasToken, + refundReceiver, + signatures, + }) + } + + ///Creates a new call builder for the [`nonce`] function. + pub fn nonce(&self) -> alloy_contract::SolCallBuilder<&P, nonceCall, N> { + self.call_builder(&nonceCall) + } + + ///Creates a new call builder for the [`setup`] function. + pub fn setup( + &self, + _owners: alloy_sol_types::private::Vec, + _threshold: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + data: alloy_sol_types::private::Bytes, + fallbackHandler: alloy_sol_types::private::Address, + paymentToken: alloy_sol_types::private::Address, + payment: alloy_sol_types::private::primitives::aliases::U256, + paymentReceiver: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, setupCall, N> { + self.call_builder(&setupCall { + _owners, + _threshold, + to, + data, + fallbackHandler, + paymentToken, + payment, + paymentReceiver, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GnosisSafeInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`AddedOwner`] event. + pub fn AddedOwner_filter(&self) -> alloy_contract::Event<&P, AddedOwner, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ApproveHash`] event. + pub fn ApproveHash_filter(&self) -> alloy_contract::Event<&P, ApproveHash, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ChangedFallbackHandler`] event. + pub fn ChangedFallbackHandler_filter( + &self, + ) -> alloy_contract::Event<&P, ChangedFallbackHandler, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ChangedGuard`] event. + pub fn ChangedGuard_filter(&self) -> alloy_contract::Event<&P, ChangedGuard, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ChangedThreshold`] event. + pub fn ChangedThreshold_filter(&self) -> alloy_contract::Event<&P, ChangedThreshold, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`DisabledModule`] event. + pub fn DisabledModule_filter(&self) -> alloy_contract::Event<&P, DisabledModule, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`EnabledModule`] event. + pub fn EnabledModule_filter(&self) -> alloy_contract::Event<&P, EnabledModule, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ExecutionFailure`] event. + pub fn ExecutionFailure_filter(&self) -> alloy_contract::Event<&P, ExecutionFailure, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ExecutionFromModuleFailure`] + /// event. + pub fn ExecutionFromModuleFailure_filter( + &self, + ) -> alloy_contract::Event<&P, ExecutionFromModuleFailure, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ExecutionFromModuleSuccess`] + /// event. + pub fn ExecutionFromModuleSuccess_filter( + &self, + ) -> alloy_contract::Event<&P, ExecutionFromModuleSuccess, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ExecutionSuccess`] event. + pub fn ExecutionSuccess_filter(&self) -> alloy_contract::Event<&P, ExecutionSuccess, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`RemovedOwner`] event. + pub fn RemovedOwner_filter(&self) -> alloy_contract::Event<&P, RemovedOwner, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SafeReceived`] event. + pub fn SafeReceived_filter(&self) -> alloy_contract::Event<&P, SafeReceived, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SafeSetup`] event. + pub fn SafeSetup_filter(&self) -> alloy_contract::Event<&P, SafeSetup, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SignMsg`] event. + pub fn SignMsg_filter(&self) -> alloy_contract::Event<&P, SignMsg, N> { + self.event_filter::() + } + } +} +pub type Instance = GnosisSafe::GnosisSafeInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/gnosissafecompatibilityfallbackhandler/Cargo.toml b/contracts/generated/contracts-generated/gnosissafecompatibilityfallbackhandler/Cargo.toml new file mode 100644 index 0000000000..d543682cdd --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafecompatibilityfallbackhandler/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-gnosissafecompatibilityfallbackhandler" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/gnosissafecompatibilityfallbackhandler/src/lib.rs b/contracts/generated/contracts-generated/gnosissafecompatibilityfallbackhandler/src/lib.rs new file mode 100644 index 0000000000..ed62c79403 --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafecompatibilityfallbackhandler/src/lib.rs @@ -0,0 +1,1415 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface GnosisSafeCompatibilityFallbackHandler { + function NAME() external view returns (string memory); + function VERSION() external view returns (string memory); + function isValidSignature(bytes32 _dataHash, bytes memory _signature) external view returns (bytes4); + function isValidSignature(bytes memory _data, bytes memory _signature) external view returns (bytes4); + function simulate(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "NAME", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "_dataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "_data", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "_signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "simulate", + "inputs": [ + { + "name": "targetContract", + "type": "address", + "internalType": "address" + }, + { + "name": "calldataPayload", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "response", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GnosisSafeCompatibilityFallbackHandler { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561001057600080fd5b50611574806100206000396000f3fe608060405234801561001057600080fd5b50600436106100ce5760003560e01c80636ac247841161008c578063bc197c8111610066578063bc197c81146107bb578063bd61951d14610951578063f23a6e6114610a63578063ffa1ad7414610b63576100ce565b80636ac24784146105ea578063a3f4df7e146106d9578063b2494df31461075c576100ce565b806223de29146100d357806301ffc9a71461020b5780630a1028c41461026e578063150b7a021461033d5780631626ba7e1461043357806320c13b0b146104e9575b600080fd5b610209600480360360c08110156100e957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561017057600080fd5b82018360208201111561018257600080fd5b803590602001918460018302840111640100000000831117156101a457600080fd5b9091929391929390803590602001906401000000008111156101c557600080fd5b8201836020820111156101d757600080fd5b803590602001918460018302840111640100000000831117156101f957600080fd5b9091929391929390505050610be6565b005b6102566004803603602081101561022157600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169060200190929190505050610bf0565b60405180821515815260200191505060405180910390f35b6103276004803603602081101561028457600080fd5b81019080803590602001906401000000008111156102a157600080fd5b8201836020820111156102b357600080fd5b803590602001918460018302840111640100000000831117156102d557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610d2a565b6040518082815260200191505060405180910390f35b6103fe6004803603608081101561035357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156103ba57600080fd5b8201836020820111156103cc57600080fd5b803590602001918460018302840111640100000000831117156103ee57600080fd5b9091929391929390505050610d3d565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6104b46004803603604081101561044957600080fd5b81019080803590602001909291908035906020019064010000000081111561047057600080fd5b82018360208201111561048257600080fd5b803590602001918460018302840111640100000000831117156104a457600080fd5b9091929391929390505050610d52565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6105b5600480360360408110156104ff57600080fd5b810190808035906020019064010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184600183028401116401000000008311171561055057600080fd5b90919293919293908035906020019064010000000081111561057157600080fd5b82018360208201111561058357600080fd5b803590602001918460018302840111640100000000831117156105a557600080fd5b9091929391929390505050610f0a565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6106c36004803603604081101561060057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561063d57600080fd5b82018360208201111561064f57600080fd5b8035906020019184600183028401116401000000008311171561067157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061115b565b6040518082815260200191505060405180910390f35b6106e16112cd565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610721578082015181840152602081019050610706565b50505050905090810190601f16801561074e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610764611306565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156107a757808201518184015260208101905061078c565b505050509050019250505060405180910390f35b61091c600480360360a08110156107d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561082e57600080fd5b82018360208201111561084057600080fd5b8035906020019184602083028401116401000000008311171561086257600080fd5b90919293919293908035906020019064010000000081111561088357600080fd5b82018360208201111561089557600080fd5b803590602001918460208302840111640100000000831117156108b757600080fd5b9091929391929390803590602001906401000000008111156108d857600080fd5b8201836020820111156108ea57600080fd5b8035906020019184600183028401116401000000008311171561090c57600080fd5b909192939192939050505061146d565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b6109e86004803603604081101561096757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156109a457600080fd5b8201836020820111156109b657600080fd5b803590602001918460018302840111640100000000831117156109d857600080fd5b9091929391929390505050611485565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610a28578082015181840152602081019050610a0d565b50505050905090810190601f168015610a555780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610b2e600480360360a0811015610a7957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610aea57600080fd5b820183602082011115610afc57600080fd5b80359060200191846001830284011164010000000083111715610b1e57600080fd5b90919293919293905050506114ef565b60405180827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b610b6b611505565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610bab578082015181840152602081019050610b90565b50505050905090810190601f168015610bd85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b5050505050505050565b60007f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610cbb57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610d2357507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610d36338361115b565b9050919050565b600063150b7a0260e01b905095945050505050565b60008033905060008173ffffffffffffffffffffffffffffffffffffffff166320c13b0b876040516020018082815260200191505060405160208183030381529060405287876040518463ffffffff1660e01b8152600401808060200180602001838103835286818151815260200191508051906020019080838360005b83811015610deb578082015181840152602081019050610dd0565b50505050905090810190601f168015610e185780820380516001836020036101000a031916815260200191505b508381038252858582818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b158015610e6357600080fd5b505afa158015610e77573d6000803e3d6000fd5b505050506040513d6020811015610e8d57600080fd5b810190808051906020019092919050505090506320c13b0b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610ef657600060e01b610eff565b631626ba7e60e01b5b925050509392505050565b6000803390506000610f608288888080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061115b565b905060008585905014156110755760008273ffffffffffffffffffffffffffffffffffffffff16635ae6bd37836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d6020811015610feb57600080fd5b81019080805190602001909291905050501415611070576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f48617368206e6f7420617070726f76656400000000000000000000000000000081525060200191505060405180910390fd5b611147565b8173ffffffffffffffffffffffffffffffffffffffff1663934f3a1182898989896040518663ffffffff1660e01b81526004018086815260200180602001806020018381038352878782818152602001925080828437600081840152601f19601f8201169050808301925050508381038252858582818152602001925080828437600081840152601f19601f82011690508083019250505097505050505050505060006040518083038186803b15801561112e57600080fd5b505afa158015611142573d6000803e3d6000fd5b505050505b6320c13b0b60e01b92505050949350505050565b6000807f60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca60001b83805190602001206040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050601960f81b600160f81b8573ffffffffffffffffffffffffffffffffffffffff1663f698da256040518163ffffffff1660e01b815260040160206040518083038186803b15801561120957600080fd5b505afa15801561121d573d6000803e3d6000fd5b505050506040513d602081101561123357600080fd5b81019080805190602001909291905050508360405160200180857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152600101847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526001018381526020018281526020019450505050506040516020818303038152906040528051906020012091505092915050565b6040518060400160405280601881526020017f44656661756c742043616c6c6261636b2048616e646c6572000000000000000081525081565b6060600033905060008173ffffffffffffffffffffffffffffffffffffffff1663cc2f84526001600a6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060006040518083038186803b15801561138057600080fd5b505afa158015611394573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060408110156113be57600080fd5b81019080805160405193929190846401000000008211156113de57600080fd5b838201915060208201858111156113f457600080fd5b825186602082028301116401000000008211171561141157600080fd5b8083526020830192505050908051906020019060200280838360005b8381101561144857808201518184015260208101905061142d565b5050505090500160405260200180519060200190929190505050509050809250505090565b600063bc197c8160e01b905098975050505050505050565b60606040517fb4faba09000000000000000000000000000000000000000000000000000000008152600436036004808301376020600036836000335af15060203d036040519250808301604052806020843e6000516114e657825160208401fd5b50509392505050565b600063f23a6e6160e01b90509695505050505050565b6040518060400160405280600581526020017f312e302e300000000000000000000000000000000000000000000000000000008152508156fea26469706673582212204251d58f2a197439239faafa82818b7696d25bb75655794a81cc773a0e39ed2b64736f6c63430007060033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[Pa\x15t\x80a\0 `\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\xCEW`\x005`\xE0\x1C\x80cj\xC2G\x84\x11a\0\x8CW\x80c\xBC\x19|\x81\x11a\0fW\x80c\xBC\x19|\x81\x14a\x07\xBBW\x80c\xBDa\x95\x1D\x14a\tQW\x80c\xF2:na\x14a\ncW\x80c\xFF\xA1\xADt\x14a\x0BcWa\0\xCEV[\x80cj\xC2G\x84\x14a\x05\xEAW\x80c\xA3\xF4\xDF~\x14a\x06\xD9W\x80c\xB2IM\xF3\x14a\x07\\Wa\0\xCEV[\x80b#\xDE)\x14a\0\xD3W\x80c\x01\xFF\xC9\xA7\x14a\x02\x0BW\x80c\n\x10(\xC4\x14a\x02nW\x80c\x15\x0Bz\x02\x14a\x03=W\x80c\x16&\xBA~\x14a\x043W\x80c \xC1;\x0B\x14a\x04\xE9W[`\0\x80\xFD[a\x02\t`\x04\x806\x03`\xC0\x81\x10\x15a\0\xE9W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x01pW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x01\x82W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x01\xA4W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x01\xC5W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x01\xD7W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x01\xF9W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90PPPa\x0B\xE6V[\0[a\x02V`\x04\x806\x03` \x81\x10\x15a\x02!W`\0\x80\xFD[\x81\x01\x90\x80\x805{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x90` \x01\x90\x92\x91\x90PPPa\x0B\xF0V[`@Q\x80\x82\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x03'`\x04\x806\x03` \x81\x10\x15a\x02\x84W`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x02\xA1W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x02\xB3W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x02\xD5W`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90PPPa\r*V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x03\xFE`\x04\x806\x03`\x80\x81\x10\x15a\x03SW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x03\xBAW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x03\xCCW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x03\xEEW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90PPPa\r=V[`@Q\x80\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x04\xB4`\x04\x806\x03`@\x81\x10\x15a\x04IW`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x04pW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x04\x82W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x04\xA4W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90PPPa\rRV[`@Q\x80\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x05\xB5`\x04\x806\x03`@\x81\x10\x15a\x04\xFFW`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x05\x1CW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x05.W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x05PW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x05qW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x05\x83W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x05\xA5W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90PPPa\x0F\nV[`@Q\x80\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x06\xC3`\x04\x806\x03`@\x81\x10\x15a\x06\0W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x06=W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x06OW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x06qW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90PPPa\x11[V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x06\xE1a\x12\xCDV[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x07!W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x07\x06V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x07NW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[a\x07da\x13\x06V[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90` \x02\x80\x83\x83`\0[\x83\x81\x10\x15a\x07\xA7W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x07\x8CV[PPPP\x90P\x01\x92PPP`@Q\x80\x91\x03\x90\xF3[a\t\x1C`\x04\x806\x03`\xA0\x81\x10\x15a\x07\xD1W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x08.W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x08@W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x08bW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x08\x83W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x08\x95W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x08\xB7W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x08\xD8W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x08\xEAW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\t\x0CW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90PPPa\x14mV[`@Q\x80\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\t\xE8`\x04\x806\x03`@\x81\x10\x15a\tgW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\t\xA4W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\t\xB6W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\t\xD8W`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90PPPa\x14\x85V[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\n(W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\n\rV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\nUW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[a\x0B.`\x04\x806\x03`\xA0\x81\x10\x15a\nyW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\n\xEAW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\n\xFCW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x0B\x1EW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90PPPa\x14\xEFV[`@Q\x80\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x0Bka\x15\x05V[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x0B\xABW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x0B\x90V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x0B\xD8W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[PPPPPPPPV[`\0\x7FN#\x12\xE0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x14\x80a\x0C\xBBWP\x7F\x15\x0Bz\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x14[\x80a\r#WP\x7F\x01\xFF\xC9\xA7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x82{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x14[\x90P\x91\x90PV[`\0a\r63\x83a\x11[V[\x90P\x91\x90PV[`\0c\x15\x0Bz\x02`\xE0\x1B\x90P\x95\x94PPPPPV[`\0\x803\x90P`\0\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c \xC1;\x0B\x87`@Q` \x01\x80\x82\x81R` \x01\x91PP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x87\x87`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x80` \x01\x80` \x01\x83\x81\x03\x83R\x86\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\r\xEBW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\r\xD0V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x0E\x18W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x83\x81\x03\x82R\x85\x85\x82\x81\x81R` \x01\x92P\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPP\x95PPPPPP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x0EcW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x0EwW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x0E\x8DW`\0\x80\xFD[\x81\x01\x90\x80\x80Q\x90` \x01\x90\x92\x91\x90PPP\x90Pc \xC1;\x0B`\xE0\x1B{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x14a\x0E\xF6W`\0`\xE0\x1Ba\x0E\xFFV[c\x16&\xBA~`\xE0\x1B[\x92PPP\x93\x92PPPV[`\0\x803\x90P`\0a\x0F`\x82\x88\x88\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPPa\x11[V[\x90P`\0\x85\x85\x90P\x14\x15a\x10uW`\0\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cZ\xE6\xBD7\x83`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x0F\xC1W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x0F\xD5W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x0F\xEBW`\0\x80\xFD[\x81\x01\x90\x80\x80Q\x90` \x01\x90\x92\x91\x90PPP\x14\x15a\x10pW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x11\x81R` \x01\x80\x7FHash not approved\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x11GV[\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x93O:\x11\x82\x89\x89\x89\x89`@Q\x86c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x86\x81R` \x01\x80` \x01\x80` \x01\x83\x81\x03\x83R\x87\x87\x82\x81\x81R` \x01\x92P\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPP\x83\x81\x03\x82R\x85\x85\x82\x81\x81R` \x01\x92P\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPP\x97PPPPPPPP`\0`@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x11.W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x11BW=`\0\x80>=`\0\xFD[PPPP[c \xC1;\x0B`\xE0\x1B\x92PPP\x94\x93PPPPV[`\0\x80\x7F`\xB3\xCB\xF8\xB4\xA2#\xD6\x8Dd\x1B;m\xDF\x9A)\x8E\x7F3q\x0C\xF3\xD3\xA9\xD1\x14kZaP\xFB\xCA`\0\x1B\x83\x80Q\x90` \x01 `@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\x19`\xF8\x1B`\x01`\xF8\x1B\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xF6\x98\xDA%`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x12\tW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x12\x1DW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x123W`\0\x80\xFD[\x81\x01\x90\x80\x80Q\x90` \x01\x90\x92\x91\x90PPP\x83`@Q` \x01\x80\x85~\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81R`\x01\x01\x84~\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16\x81R`\x01\x01\x83\x81R` \x01\x82\x81R` \x01\x94PPPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x91PP\x92\x91PPV[`@Q\x80`@\x01`@R\x80`\x18\x81R` \x01\x7FDefault Callback Handler\0\0\0\0\0\0\0\0\x81RP\x81V[```\x003\x90P`\0\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xCC/\x84R`\x01`\n`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81R` \x01\x92PPP`\0`@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x13\x80W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x13\x94W=`\0\x80>=`\0\xFD[PPPP`@Q=`\0\x82>=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP`@\x81\x10\x15a\x13\xBEW`\0\x80\xFD[\x81\x01\x90\x80\x80Q`@Q\x93\x92\x91\x90\x84d\x01\0\0\0\0\x82\x11\x15a\x13\xDEW`\0\x80\xFD[\x83\x82\x01\x91P` \x82\x01\x85\x81\x11\x15a\x13\xF4W`\0\x80\xFD[\x82Q\x86` \x82\x02\x83\x01\x11d\x01\0\0\0\0\x82\x11\x17\x15a\x14\x11W`\0\x80\xFD[\x80\x83R` \x83\x01\x92PPP\x90\x80Q\x90` \x01\x90` \x02\x80\x83\x83`\0[\x83\x81\x10\x15a\x14HW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x14-V[PPPP\x90P\x01`@R` \x01\x80Q\x90` \x01\x90\x92\x91\x90PPPP\x90P\x80\x92PPP\x90V[`\0c\xBC\x19|\x81`\xE0\x1B\x90P\x98\x97PPPPPPPPV[```@Q\x7F\xB4\xFA\xBA\t\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x046\x03`\x04\x80\x83\x017` `\x006\x83`\x003Z\xF1P` =\x03`@Q\x92P\x80\x83\x01`@R\x80` \x84>`\0Qa\x14\xE6W\x82Q` \x84\x01\xFD[PP\x93\x92PPPV[`\0c\xF2:na`\xE0\x1B\x90P\x96\x95PPPPPPV[`@Q\x80`@\x01`@R\x80`\x05\x81R` \x01\x7F1.0.0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP\x81V\xFE\xA2dipfsX\"\x12 BQ\xD5\x8F*\x19t9#\x9F\xAA\xFA\x82\x81\x8Bv\x96\xD2[\xB7VUyJ\x81\xCCw:\x0E9\xED+dsolcC\0\x07\x06\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `NAME()` and selector `0xa3f4df7e`. + ```solidity + function NAME() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NAMECall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`NAME()`](NAMECall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NAMEReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NAMECall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NAMECall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NAMEReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NAMEReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for NAMECall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [163u8, 244u8, 223u8, 126u8]; + const SIGNATURE: &'static str = "NAME()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: NAMEReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: NAMEReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `VERSION()` and selector `0xffa1ad74`. + ```solidity + function VERSION() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct VERSIONCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`VERSION()`](VERSIONCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct VERSIONReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: VERSIONCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for VERSIONCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: VERSIONReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for VERSIONReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for VERSIONCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [255u8, 161u8, 173u8, 116u8]; + const SIGNATURE: &'static str = "VERSION()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: VERSIONReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: VERSIONReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes32,bytes)` and selector `0x1626ba7e`. + ```solidity + function isValidSignature(bytes32 _dataHash, bytes memory _signature) external view returns (bytes4); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignature_0Call { + #[allow(missing_docs)] + pub _dataHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub _signature: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes32,bytes)`](isValidSignature_0Call) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignature_0Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignature_0Call) -> Self { + (value._dataHash, value._signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignature_0Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _dataHash: tuple.0, + _signature: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignature_0Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignature_0Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignature_0Call { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 38u8, 186u8, 126u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes32,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self._dataHash), + ::tokenize( + &self._signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignature_0Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignature_0Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes,bytes)` and selector `0x20c13b0b`. + ```solidity + function isValidSignature(bytes memory _data, bytes memory _signature) external view returns (bytes4); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignature_1Call { + #[allow(missing_docs)] + pub _data: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub _signature: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes,bytes)`](isValidSignature_1Call) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignature_1Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Bytes, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignature_1Call) -> Self { + (value._data, value._signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignature_1Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _data: tuple.0, + _signature: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignature_1Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignature_1Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignature_1Call { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [32u8, 193u8, 59u8, 11u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._data, + ), + ::tokenize( + &self._signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignature_1Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignature_1Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `simulate(address,bytes)` and selector `0xbd61951d`. + ```solidity + function simulate(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateCall { + #[allow(missing_docs)] + pub targetContract: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub calldataPayload: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`simulate(address,bytes)`](simulateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateReturn { + #[allow(missing_docs)] + pub response: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateCall) -> Self { + (value.targetContract, value.calldataPayload) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + targetContract: tuple.0, + calldataPayload: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Bytes,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateReturn) -> Self { + (value.response,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { response: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for simulateCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::Bytes; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [189u8, 97u8, 149u8, 29u8]; + const SIGNATURE: &'static str = "simulate(address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.targetContract, + ), + ::tokenize( + &self.calldataPayload, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: simulateReturn = r.into(); + r.response + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: simulateReturn = r.into(); + r.response + }) + } + } + }; + ///Container for all the [`GnosisSafeCompatibilityFallbackHandler`](self) + /// function calls. + #[derive(Clone)] + pub enum GnosisSafeCompatibilityFallbackHandlerCalls { + #[allow(missing_docs)] + NAME(NAMECall), + #[allow(missing_docs)] + VERSION(VERSIONCall), + #[allow(missing_docs)] + isValidSignature_0(isValidSignature_0Call), + #[allow(missing_docs)] + isValidSignature_1(isValidSignature_1Call), + #[allow(missing_docs)] + simulate(simulateCall), + } + impl GnosisSafeCompatibilityFallbackHandlerCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [22u8, 38u8, 186u8, 126u8], + [32u8, 193u8, 59u8, 11u8], + [163u8, 244u8, 223u8, 126u8], + [189u8, 97u8, 149u8, 29u8], + [255u8, 161u8, 173u8, 116u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(isValidSignature_0), + ::core::stringify!(isValidSignature_1), + ::core::stringify!(NAME), + ::core::stringify!(simulate), + ::core::stringify!(VERSION), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for GnosisSafeCompatibilityFallbackHandlerCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "GnosisSafeCompatibilityFallbackHandlerCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::NAME(_) => ::SELECTOR, + Self::VERSION(_) => ::SELECTOR, + Self::isValidSignature_0(_) => { + ::SELECTOR + } + Self::isValidSignature_1(_) => { + ::SELECTOR + } + Self::simulate(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + GnosisSafeCompatibilityFallbackHandlerCalls, + >] = &[ + { + fn isValidSignature_0( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::isValidSignature_0) + } + isValidSignature_0 + }, + { + fn isValidSignature_1( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::isValidSignature_1) + } + isValidSignature_1 + }, + { + fn NAME( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::NAME) + } + NAME + }, + { + fn simulate( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::simulate) + } + simulate + }, + { + fn VERSION( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::VERSION) + } + VERSION + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + GnosisSafeCompatibilityFallbackHandlerCalls, + >] = &[ + { + fn isValidSignature_0( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + GnosisSafeCompatibilityFallbackHandlerCalls::isValidSignature_0, + ) + } + isValidSignature_0 + }, + { + fn isValidSignature_1( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map( + GnosisSafeCompatibilityFallbackHandlerCalls::isValidSignature_1, + ) + } + isValidSignature_1 + }, + { + fn NAME( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::NAME) + } + NAME + }, + { + fn simulate( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::simulate) + } + simulate + }, + { + fn VERSION( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(GnosisSafeCompatibilityFallbackHandlerCalls::VERSION) + } + VERSION + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::NAME(inner) => { + ::abi_encoded_size(inner) + } + Self::VERSION(inner) => { + ::abi_encoded_size(inner) + } + Self::isValidSignature_0(inner) => { + ::abi_encoded_size(inner) + } + Self::isValidSignature_1(inner) => { + ::abi_encoded_size(inner) + } + Self::simulate(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::NAME(inner) => { + ::abi_encode_raw(inner, out) + } + Self::VERSION(inner) => { + ::abi_encode_raw(inner, out) + } + Self::isValidSignature_0(inner) => { + ::abi_encode_raw(inner, out) + } + Self::isValidSignature_1(inner) => { + ::abi_encode_raw(inner, out) + } + Self::simulate(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GnosisSafeCompatibilityFallbackHandler`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeCompatibilityFallbackHandlerInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GnosisSafeCompatibilityFallbackHandlerInstance { + GnosisSafeCompatibilityFallbackHandlerInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + GnosisSafeCompatibilityFallbackHandlerInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + GnosisSafeCompatibilityFallbackHandlerInstance::::deploy_builder(__provider) + } + /**A [`GnosisSafeCompatibilityFallbackHandler`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GnosisSafeCompatibilityFallbackHandler`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GnosisSafeCompatibilityFallbackHandlerInstance< + P, + N = alloy_contract::private::Ethereum, + > { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GnosisSafeCompatibilityFallbackHandlerInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GnosisSafeCompatibilityFallbackHandlerInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GnosisSafeCompatibilityFallbackHandlerInstance + { + /**Creates a new wrapper around an on-chain [`GnosisSafeCompatibilityFallbackHandler`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeCompatibilityFallbackHandlerInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GnosisSafeCompatibilityFallbackHandlerInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GnosisSafeCompatibilityFallbackHandlerInstance { + GnosisSafeCompatibilityFallbackHandlerInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GnosisSafeCompatibilityFallbackHandlerInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`NAME`] function. + pub fn NAME(&self) -> alloy_contract::SolCallBuilder<&P, NAMECall, N> { + self.call_builder(&NAMECall) + } + + ///Creates a new call builder for the [`VERSION`] function. + pub fn VERSION(&self) -> alloy_contract::SolCallBuilder<&P, VERSIONCall, N> { + self.call_builder(&VERSIONCall) + } + + ///Creates a new call builder for the [`isValidSignature_0`] function. + pub fn isValidSignature_0( + &self, + _dataHash: alloy_sol_types::private::FixedBytes<32>, + _signature: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignature_0Call, N> { + self.call_builder(&isValidSignature_0Call { + _dataHash, + _signature, + }) + } + + ///Creates a new call builder for the [`isValidSignature_1`] function. + pub fn isValidSignature_1( + &self, + _data: alloy_sol_types::private::Bytes, + _signature: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignature_1Call, N> { + self.call_builder(&isValidSignature_1Call { _data, _signature }) + } + + ///Creates a new call builder for the [`simulate`] function. + pub fn simulate( + &self, + targetContract: alloy_sol_types::private::Address, + calldataPayload: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, simulateCall, N> { + self.call_builder(&simulateCall { + targetContract, + calldataPayload, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GnosisSafeCompatibilityFallbackHandlerInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = + GnosisSafeCompatibilityFallbackHandler::GnosisSafeCompatibilityFallbackHandlerInstance< + ::alloy_provider::DynProvider, + >; diff --git a/contracts/generated/contracts-generated/gnosissafeproxy/Cargo.toml b/contracts/generated/contracts-generated/gnosissafeproxy/Cargo.toml new file mode 100644 index 0000000000..aef25e34bb --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafeproxy/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-gnosissafeproxy" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/gnosissafeproxy/src/lib.rs b/contracts/generated/contracts-generated/gnosissafeproxy/src/lib.rs new file mode 100644 index 0000000000..28b7fbe126 --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafeproxy/src/lib.rs @@ -0,0 +1,317 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface GnosisSafeProxy { + constructor(address _singleton); + + fallback() external payable; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_singleton", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "fallback", + "stateMutability": "payable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GnosisSafeProxy { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x01\xE68\x03\x80a\x01\xE6\x839\x81\x81\x01`@R` \x81\x10\x15a\x003W`\0\x80\xFD[\x81\x01\x90\x80\x80Q\x90` \x01\x90\x92\x91\x90PPP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\0\xCAW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\"\x81R` \x01\x80a\x01\xC4`\"\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x80`\0\x80a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UPP`\xAB\x80a\x01\x19`\09`\0\xF3\xFE`\x80`@Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\0T\x16\x7F\xA6\x19Hn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x005\x14\x15`PW\x80`\0R` `\0\xF3[6`\0\x807`\0\x806`\0\x84Z\xF4=`\0\x80>`\0\x81\x14\x15`pW=`\0\xFD[=`\0\xF3\xFE\xA2dipfsX\"\x12 \xD1B\x92\x974\x96S\xA4\x91\x80v\xD6P3-\xE1\xA1\x06\x8C_>\x07\xC5\xC8#`\xC2ww\x0B\x95RdsolcC\0\x07\x06\x003Invalid singleton address provided", + ); + /**Constructor`. + ```solidity + constructor(address _singleton); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _singleton: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._singleton,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _singleton: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._singleton, + ), + ) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GnosisSafeProxy`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeProxyInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GnosisSafeProxyInstance { + GnosisSafeProxyInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _singleton: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + GnosisSafeProxyInstance::::deploy(__provider, _singleton) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _singleton: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + GnosisSafeProxyInstance::::deploy_builder(__provider, _singleton) + } + /**A [`GnosisSafeProxy`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GnosisSafeProxy`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GnosisSafeProxyInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GnosisSafeProxyInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GnosisSafeProxyInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GnosisSafeProxyInstance + { + /**Creates a new wrapper around an on-chain [`GnosisSafeProxy`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeProxyInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _singleton: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, _singleton); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _singleton: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode( + &constructorCall { _singleton }, + )[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GnosisSafeProxyInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GnosisSafeProxyInstance { + GnosisSafeProxyInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GnosisSafeProxyInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GnosisSafeProxyInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = GnosisSafeProxy::GnosisSafeProxyInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/gnosissafeproxyfactory/Cargo.toml b/contracts/generated/contracts-generated/gnosissafeproxyfactory/Cargo.toml new file mode 100644 index 0000000000..d767974466 --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafeproxyfactory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-gnosissafeproxyfactory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/gnosissafeproxyfactory/src/lib.rs b/contracts/generated/contracts-generated/gnosissafeproxyfactory/src/lib.rs new file mode 100644 index 0000000000..8a43d2404b --- /dev/null +++ b/contracts/generated/contracts-generated/gnosissafeproxyfactory/src/lib.rs @@ -0,0 +1,780 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface GnosisSafeProxyFactory { + event ProxyCreation(address proxy, address singleton); + + function createProxy(address singleton, bytes memory data) external returns (address proxy); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "createProxy", + "inputs": [ + { + "name": "singleton", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "proxy", + "type": "address", + "internalType": "contract GnosisSafeProxy" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ProxyCreation", + "inputs": [ + { + "name": "proxy", + "type": "address", + "indexed": false, + "internalType": "contract GnosisSafeProxy" + }, + { + "name": "singleton", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GnosisSafeProxyFactory { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561001057600080fd5b50610ebe806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80631688f0b9146100675780632500510e1461017657806353e5d9351461024357806361b69abd146102c6578063addacc0f146103cb578063d18af54d1461044e575b600080fd5b61014a6004803603606081101561007d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156100ba57600080fd5b8201836020820111156100cc57600080fd5b803590602001918460018302840111640100000000831117156100ee57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919050505061057d565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102176004803603606081101561018c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156101c957600080fd5b8201836020820111156101db57600080fd5b803590602001918460018302840111640100000000831117156101fd57600080fd5b909192939192939080359060200190929190505050610624565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61024b610751565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561028b578082015181840152602081019050610270565b50505050905090810190601f1680156102b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61039f600480360360408110156102dc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561031957600080fd5b82018360208201111561032b57600080fd5b8035906020019184600183028401116401000000008311171561034d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061077c565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103d3610861565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156104135780820151818401526020810190506103f8565b50505050905090810190601f1680156104405780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6105516004803603608081101561046457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156104a157600080fd5b8201836020820111156104b357600080fd5b803590602001918460018302840111640100000000831117156104d557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061088c565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600061058a848484610a3b565b90506000835111156105b25760008060008551602087016000865af114156105b157600080fd5b5b7f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2358185604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a19392505050565b60006106758585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a3b565b905080604051602001808273ffffffffffffffffffffffffffffffffffffffff1660601b81526014019150506040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156107165780820151818401526020810190506106fb565b50505050905090810190601f1680156107435780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60606040518060200161076390610bde565b6020820181038252601f19601f82011660405250905090565b60008260405161078b90610bde565b808273ffffffffffffffffffffffffffffffffffffffff168152602001915050604051809103906000f0801580156107c7573d6000803e3d6000fd5b5090506000825111156107f05760008060008451602086016000865af114156107ef57600080fd5b5b7f4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e2358184604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a192915050565b60606040518060200161087390610beb565b6020820181038252601f19601f82011660405250905090565b6000808383604051602001808381526020018273ffffffffffffffffffffffffffffffffffffffff1660601b8152601401925050506040516020818303038152906040528051906020012060001c90506108e786868361057d565b9150600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610a32578273ffffffffffffffffffffffffffffffffffffffff16631e52b518838888886040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156109ca5780820151818401526020810190506109af565b50505050905090810190601f1680156109f75780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015610a1957600080fd5b505af1158015610a2d573d6000803e3d6000fd5b505050505b50949350505050565b6000808380519060200120836040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209050600060405180602001610a8890610bde565b6020820181038252601f19601f820116604052508673ffffffffffffffffffffffffffffffffffffffff166040516020018083805190602001908083835b60208310610ae95780518252602082019150602081019050602083039250610ac6565b6001836020036101000a038019825116818451168082178552505050505050905001828152602001925050506040516020818303038152906040529050818151826020016000f59250600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610bd5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f437265617465322063616c6c206661696c65640000000000000000000000000081525060200191505060405180910390fd5b50509392505050565b6101e680610bf883390190565b60ab80610dde8339019056fe608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea2646970667358221220d1429297349653a4918076d650332de1a1068c5f3e07c5c82360c277770b955264736f6c63430007060033a26469706673582212200c75fe2196b9f752c82794253f2ebce0d821afef5997e1d5a35ec316ce592f6664736f6c63430007060033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[Pa\x0E\xBE\x80a\0 `\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0bW`\x005`\xE0\x1C\x80c\x16\x88\xF0\xB9\x14a\0gW\x80c%\0Q\x0E\x14a\x01vW\x80cS\xE5\xD95\x14a\x02CW\x80ca\xB6\x9A\xBD\x14a\x02\xC6W\x80c\xAD\xDA\xCC\x0F\x14a\x03\xCBW\x80c\xD1\x8A\xF5M\x14a\x04NW[`\0\x80\xFD[a\x01J`\x04\x806\x03``\x81\x10\x15a\0}W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\0\xBAW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\0\xCCW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\0\xEEW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x05}V[`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x02\x17`\x04\x806\x03``\x81\x10\x15a\x01\x8CW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x01\xC9W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x01\xDBW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x01\xFDW`\0\x80\xFD[\x90\x91\x92\x93\x91\x92\x93\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x06$V[`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x02Ka\x07QV[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x02\x8BW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x02pV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x02\xB8W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[a\x03\x9F`\x04\x806\x03`@\x81\x10\x15a\x02\xDCW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x03\x19W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x03+W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x03MW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90PPPa\x07|V[`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x03\xD3a\x08aV[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x04\x13W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x03\xF8V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x04@W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[a\x05Q`\x04\x806\x03`\x80\x81\x10\x15a\x04dW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90d\x01\0\0\0\0\x81\x11\x15a\x04\xA1W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x04\xB3W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x04\xD5W`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x91\x92\x91\x92\x90\x805\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa\x08\x8CV[`@Q\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[`\0a\x05\x8A\x84\x84\x84a\n;V[\x90P`\0\x83Q\x11\x15a\x05\xB2W`\0\x80`\0\x85Q` \x87\x01`\0\x86Z\xF1\x14\x15a\x05\xB1W`\0\x80\xFD[[\x7FOQ\xFA\xF6\xC4V\x1F\xF9_\x06vW\xE449\xF0\xF8V\xD9|\x04\xD9\xEC\x90p\xA6\x19\x9A\xD4\x18\xE25\x81\x85`@Q\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x92PPP`@Q\x80\x91\x03\x90\xA1\x93\x92PPPV[`\0a\x06u\x85\x85\x85\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPPPPPP\x84a\n;V[\x90P\x80`@Q` \x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16``\x1B\x81R`\x14\x01\x91PP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x07\x16W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x06\xFBV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x07CW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xFD[```@Q\x80` \x01a\x07c\x90a\x0B\xDEV[` \x82\x01\x81\x03\x82R`\x1F\x19`\x1F\x82\x01\x16`@RP\x90P\x90V[`\0\x82`@Qa\x07\x8B\x90a\x0B\xDEV[\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90`\0\xF0\x80\x15\x80\x15a\x07\xC7W=`\0\x80>=`\0\xFD[P\x90P`\0\x82Q\x11\x15a\x07\xF0W`\0\x80`\0\x84Q` \x86\x01`\0\x86Z\xF1\x14\x15a\x07\xEFW`\0\x80\xFD[[\x7FOQ\xFA\xF6\xC4V\x1F\xF9_\x06vW\xE449\xF0\xF8V\xD9|\x04\xD9\xEC\x90p\xA6\x19\x9A\xD4\x18\xE25\x81\x84`@Q\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x92PPP`@Q\x80\x91\x03\x90\xA1\x92\x91PPV[```@Q\x80` \x01a\x08s\x90a\x0B\xEBV[` \x82\x01\x81\x03\x82R`\x1F\x19`\x1F\x82\x01\x16`@RP\x90P\x90V[`\0\x80\x83\x83`@Q` \x01\x80\x83\x81R` \x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16``\x1B\x81R`\x14\x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `\0\x1C\x90Pa\x08\xE7\x86\x86\x83a\x05}V[\x91P`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\n2W\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x1ER\xB5\x18\x83\x88\x88\x88`@Q\x85c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x80` \x01\x83\x81R` \x01\x82\x81\x03\x82R\x84\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\t\xCAW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\t\xAFV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\t\xF7W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x95PPPPPP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\n\x19W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\n-W=`\0\x80>=`\0\xFD[PPPP[P\x94\x93PPPPV[`\0\x80\x83\x80Q\x90` \x01 \x83`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0`@Q\x80` \x01a\n\x88\x90a\x0B\xDEV[` \x82\x01\x81\x03\x82R`\x1F\x19`\x1F\x82\x01\x16`@RP\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`@Q` \x01\x80\x83\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\n\xE9W\x80Q\x82R` \x82\x01\x91P` \x81\x01\x90P` \x83\x03\x92Pa\n\xC6V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x90P\x81\x81Q\x82` \x01`\0\xF5\x92P`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x0B\xD5W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\x13\x81R` \x01\x80\x7FCreate2 call failed\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP` \x01\x91PP`@Q\x80\x91\x03\x90\xFD[PP\x93\x92PPPV[a\x01\xE6\x80a\x0B\xF8\x839\x01\x90V[`\xAB\x80a\r\xDE\x839\x01\x90V\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x01\xE68\x03\x80a\x01\xE6\x839\x81\x81\x01`@R` \x81\x10\x15a\x003W`\0\x80\xFD[\x81\x01\x90\x80\x80Q\x90` \x01\x90\x92\x91\x90PPP`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\0\xCAW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`\"\x81R` \x01\x80a\x01\xC4`\"\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x80`\0\x80a\x01\0\n\x81T\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x02\x19\x16\x90\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x02\x17\x90UPP`\xAB\x80a\x01\x19`\09`\0\xF3\xFE`\x80`@Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\0T\x16\x7F\xA6\x19Hn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x005\x14\x15`PW\x80`\0R` `\0\xF3[6`\0\x807`\0\x806`\0\x84Z\xF4=`\0\x80>`\0\x81\x14\x15`pW=`\0\xFD[=`\0\xF3\xFE\xA2dipfsX\"\x12 \xD1B\x92\x974\x96S\xA4\x91\x80v\xD6P3-\xE1\xA1\x06\x8C_>\x07\xC5\xC8#`\xC2ww\x0B\x95RdsolcC\0\x07\x06\x003Invalid singleton address provided`\x80`@Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\0T\x16\x7F\xA6\x19Hn\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x005\x14\x15`PW\x80`\0R` `\0\xF3[6`\0\x807`\0\x806`\0\x84Z\xF4=`\0\x80>`\0\x81\x14\x15`pW=`\0\xFD[=`\0\xF3\xFE\xA2dipfsX\"\x12 \xD1B\x92\x974\x96S\xA4\x91\x80v\xD6P3-\xE1\xA1\x06\x8C_>\x07\xC5\xC8#`\xC2ww\x0B\x95RdsolcC\0\x07\x06\x003\xA2dipfsX\"\x12 \x0Cu\xFE!\x96\xB9\xF7R\xC8'\x94%?.\xBC\xE0\xD8!\xAF\xEFY\x97\xE1\xD5\xA3^\xC3\x16\xCEY/fdsolcC\0\x07\x06\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ProxyCreation(address,address)` and selector `0x4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e235`. + ```solidity + event ProxyCreation(address proxy, address singleton); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ProxyCreation { + #[allow(missing_docs)] + pub proxy: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub singleton: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ProxyCreation { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ProxyCreation(address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 79u8, 81u8, 250u8, 246u8, 196u8, 86u8, 31u8, 249u8, 95u8, 6u8, 118u8, 87u8, + 228u8, 52u8, 57u8, 240u8, 248u8, 86u8, 217u8, 124u8, 4u8, 217u8, 236u8, 144u8, + 112u8, 166u8, 25u8, 154u8, 212u8, 24u8, 226u8, 53u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + proxy: data.0, + singleton: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.proxy, + ), + ::tokenize( + &self.singleton, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ProxyCreation { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ProxyCreation> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ProxyCreation) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `createProxy(address,bytes)` and selector `0x61b69abd`. + ```solidity + function createProxy(address singleton, bytes memory data) external returns (address proxy); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createProxyCall { + #[allow(missing_docs)] + pub singleton: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`createProxy(address,bytes)`](createProxyCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createProxyReturn { + #[allow(missing_docs)] + pub proxy: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createProxyCall) -> Self { + (value.singleton, value.data) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createProxyCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + singleton: tuple.0, + data: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createProxyReturn) -> Self { + (value.proxy,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createProxyReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { proxy: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createProxyCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [97u8, 182u8, 154u8, 189u8]; + const SIGNATURE: &'static str = "createProxy(address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.singleton, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createProxyReturn = r.into(); + r.proxy + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createProxyReturn = r.into(); + r.proxy + }) + } + } + }; + ///Container for all the [`GnosisSafeProxyFactory`](self) function calls. + #[derive(Clone)] + pub enum GnosisSafeProxyFactoryCalls { + #[allow(missing_docs)] + createProxy(createProxyCall), + } + impl GnosisSafeProxyFactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[97u8, 182u8, 154u8, 189u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(createProxy)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for GnosisSafeProxyFactoryCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 96usize; + const NAME: &'static str = "GnosisSafeProxyFactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::createProxy(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[{ + fn createProxy( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GnosisSafeProxyFactoryCalls::createProxy) + } + createProxy + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + GnosisSafeProxyFactoryCalls, + >] = &[{ + fn createProxy( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GnosisSafeProxyFactoryCalls::createProxy) + } + createProxy + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::createProxy(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::createProxy(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`GnosisSafeProxyFactory`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum GnosisSafeProxyFactoryEvents { + #[allow(missing_docs)] + ProxyCreation(ProxyCreation), + } + impl GnosisSafeProxyFactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 79u8, 81u8, 250u8, 246u8, 196u8, 86u8, 31u8, 249u8, 95u8, 6u8, 118u8, 87u8, 228u8, + 52u8, 57u8, 240u8, 248u8, 86u8, 217u8, 124u8, 4u8, 217u8, 236u8, 144u8, 112u8, 166u8, + 25u8, 154u8, 212u8, 24u8, 226u8, 53u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(ProxyCreation)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for GnosisSafeProxyFactoryEvents { + const COUNT: usize = 1usize; + const NAME: &'static str = "GnosisSafeProxyFactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ProxyCreation) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for GnosisSafeProxyFactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::ProxyCreation(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::ProxyCreation(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GnosisSafeProxyFactory`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeProxyFactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GnosisSafeProxyFactoryInstance { + GnosisSafeProxyFactoryInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> + { + GnosisSafeProxyFactoryInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + GnosisSafeProxyFactoryInstance::::deploy_builder(__provider) + } + /**A [`GnosisSafeProxyFactory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GnosisSafeProxyFactory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GnosisSafeProxyFactoryInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GnosisSafeProxyFactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GnosisSafeProxyFactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GnosisSafeProxyFactoryInstance + { + /**Creates a new wrapper around an on-chain [`GnosisSafeProxyFactory`](self) contract instance. + + See the [wrapper's documentation](`GnosisSafeProxyFactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GnosisSafeProxyFactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GnosisSafeProxyFactoryInstance { + GnosisSafeProxyFactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GnosisSafeProxyFactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`createProxy`] function. + pub fn createProxy( + &self, + singleton: alloy_sol_types::private::Address, + data: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, createProxyCall, N> { + self.call_builder(&createProxyCall { singleton, data }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GnosisSafeProxyFactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`ProxyCreation`] event. + pub fn ProxyCreation_filter(&self) -> alloy_contract::Event<&P, ProxyCreation, N> { + self.event_filter::() + } + } +} +pub type Instance = + GnosisSafeProxyFactory::GnosisSafeProxyFactoryInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/gpv2allowlistauthentication/Cargo.toml b/contracts/generated/contracts-generated/gpv2allowlistauthentication/Cargo.toml new file mode 100644 index 0000000000..7fc05ddbbd --- /dev/null +++ b/contracts/generated/contracts-generated/gpv2allowlistauthentication/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-gpv2allowlistauthentication" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/gpv2allowlistauthentication/src/lib.rs b/contracts/generated/contracts-generated/gpv2allowlistauthentication/src/lib.rs new file mode 100644 index 0000000000..e3bdd29ab2 --- /dev/null +++ b/contracts/generated/contracts-generated/gpv2allowlistauthentication/src/lib.rs @@ -0,0 +1,2150 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface GPv2AllowListAuthentication { + event ManagerChanged(address newManager, address oldManager); + event SolverAdded(address solver); + event SolverRemoved(address solver); + + function addSolver(address solver) external; + function initializeManager(address manager_) external; + function isSolver(address prospectiveSolver) external view returns (bool); + function manager() external view returns (address); + function removeSolver(address solver) external; + function simulateDelegatecall(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "addSolver", + "inputs": [ + { + "name": "solver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initializeManager", + "inputs": [ + { + "name": "manager_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isSolver", + "inputs": [ + { + "name": "prospectiveSolver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "manager", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "removeSolver", + "inputs": [ + { + "name": "solver", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "simulateDelegatecall", + "inputs": [ + { + "name": "targetContract", + "type": "address", + "internalType": "address" + }, + { + "name": "calldataPayload", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "response", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ManagerChanged", + "inputs": [ + { + "name": "newManager", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "oldManager", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SolverAdded", + "inputs": [ + { + "name": "solver", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SolverRemoved", + "inputs": [ + { + "name": "solver", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2AllowListAuthentication { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561001057600080fd5b50610e10806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80637f7120fe11610076578063d0ebdbe71161005b578063d0ebdbe7146102e3578063ec58f4b814610316578063f84436bd14610349576100a3565b80637f7120fe1461027b5780638fd57b92146102b0576100a3565b806302cc250d146100a857806343218e19146100ef578063481c6a75146102275780635624b25b14610258575b600080fd5b6100db600480360360208110156100be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661040c565b604080519115158252519081900360200190f35b6101b26004803603604081101561010557600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561013d57600080fd5b82018360208201111561014f57600080fd5b8035906020019184600183028401116401000000008311171561017157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610437945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101ec5781810151838201526020016101d4565b50505050905090810190601f1680156102195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61022f6105af565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101b26004803603604081101561026e57600080fd5b50803590602001356105d1565b6102ae6004803603602081101561029157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610647565b005b6102ae600480360360208110156102c657600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166107f8565b6102ae600480360360208110156102f957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610907565b6102ae6004803603602081101561032c57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610a47565b6101b26004803603604081101561035f57600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561039757600080fd5b8201836020820111156103a957600080fd5b803590602001918460018302840111640100000000831117156103cb57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610b5a945050505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205460ff1690565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b602083106104a057805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610463565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114610500576040519150601f19603f3d011682016040523d82523d6000602084013e610505565b606091505b5080935081925050506105a882826040516020018083805190602001908083835b6020831061056357805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610526565b6001836020036101000a03801982511681845116808217855250505050505090500182151560f81b815260010192505050604051602081830303815290604052610da3565b5092915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008260200267ffffffffffffffff811180156105ef57600080fd5b506040519080825280601f01601f19166020018201604052801561061a576020820181803683370190505b50905060005b8381101561063d5784810154602080830284010152600101610620565b5090505b92915050565b600054610100900460ff16806106605750610660610dab565b8061066e575060005460ff16155b6106d957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f496e697469616c697a61626c653a20696e697469616c697a6564000000000000604482015290519081900360640190fd5b600054610100900460ff1615801561073f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff851690810291909117825560408051918252602082019290925281517f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a4350929181900390910190a180156107f457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461088457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f475076323a2063616c6c6572206e6f74206d616e616765720000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811660008181526001602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055815192835290517f640e18a2587e1d83e4fdabf70257d0a800ca4b2c1aaad1dfc485a4ad8bbbd6c69281900390910190a150565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633148061094f575033610937610db1565b73ffffffffffffffffffffffffffffffffffffffff16145b6109ba57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f475076323a206e6f7420617574686f72697a6564000000000000000000000000604482015290519081900360640190fd5b6000805473ffffffffffffffffffffffffffffffffffffffff838116620100008181027fffffffffffffffffffff0000000000000000000000000000000000000000ffff85161790945560408051918252939092041660208201819052825190927f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a4350928290030190a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610ad357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f475076323a2063616c6c6572206e6f74206d616e616765720000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811660008181526001602081815260409283902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909217909155815192835290517f41f9d09dd5159251f8a8e482bbe097b7c01a5e6f70c5a0ddb494906464fc9dd79281900390910190a150565b606060006343218e1960e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610bc4578181015183820152602001610bac565b50505050905090810190601f168015610bf15780820380516001836020036101000a031916815260200191505b50604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909816979097178752518151919750309688965090945084935091508083835b60208310610cc257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c85565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610d24576040519150601f19603f3d011682016040523d82523d6000602084013e610d29565b606091505b50905080925050600082600184510381518110610d4257fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b149050610d85836001855103610dd6565b8015610d92575050610641565b610d9b83610da3565b505092915050565b805160208201fd5b303b1590565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905256fea26469706673582212207106ba36b2d518d89a5ce88705dd7f52d98f3a8c838b8bb7ad9cdaa5b4254ab164736f6c63430007060033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[Pa\x0E\x10\x80a\0 `\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\xA3W`\x005`\xE0\x1C\x80c\x7Fq \xFE\x11a\0vW\x80c\xD0\xEB\xDB\xE7\x11a\0[W\x80c\xD0\xEB\xDB\xE7\x14a\x02\xE3W\x80c\xECX\xF4\xB8\x14a\x03\x16W\x80c\xF8D6\xBD\x14a\x03IWa\0\xA3V[\x80c\x7Fq \xFE\x14a\x02{W\x80c\x8F\xD5{\x92\x14a\x02\xB0Wa\0\xA3V[\x80c\x02\xCC%\r\x14a\0\xA8W\x80cC!\x8E\x19\x14a\0\xEFW\x80cH\x1Cju\x14a\x02'W\x80cV$\xB2[\x14a\x02XW[`\0\x80\xFD[a\0\xDB`\x04\x806\x03` \x81\x10\x15a\0\xBEW`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x04\x0CV[`@\x80Q\x91\x15\x15\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x01\xB2`\x04\x806\x03`@\x81\x10\x15a\x01\x05W`\0\x80\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x825\x16\x91\x90\x81\x01\x90`@\x81\x01` \x82\x015d\x01\0\0\0\0\x81\x11\x15a\x01=W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x01OW`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x01qW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x92\x95Pa\x047\x94PPPPPV[`@\x80Q` \x80\x82R\x83Q\x81\x83\x01R\x83Q\x91\x92\x83\x92\x90\x83\x01\x91\x85\x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x01\xECW\x81\x81\x01Q\x83\x82\x01R` \x01a\x01\xD4V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x02\x19W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[a\x02/a\x05\xAFV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x01\xB2`\x04\x806\x03`@\x81\x10\x15a\x02nW`\0\x80\xFD[P\x805\x90` \x015a\x05\xD1V[a\x02\xAE`\x04\x806\x03` \x81\x10\x15a\x02\x91W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x06GV[\0[a\x02\xAE`\x04\x806\x03` \x81\x10\x15a\x02\xC6W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x07\xF8V[a\x02\xAE`\x04\x806\x03` \x81\x10\x15a\x02\xF9W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\t\x07V[a\x02\xAE`\x04\x806\x03` \x81\x10\x15a\x03,W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\nGV[a\x01\xB2`\x04\x806\x03`@\x81\x10\x15a\x03_W`\0\x80\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x825\x16\x91\x90\x81\x01\x90`@\x81\x01` \x82\x015d\x01\0\0\0\0\x81\x11\x15a\x03\x97W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x03\xA9W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x03\xCBW`\0\x80\xFD[\x91\x90\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x92\x95Pa\x0BZ\x94PPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\0\x90\x81R`\x01` R`@\x90 T`\xFF\x16\x90V[```\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x04\xA0W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x04cV[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81\x85Z\xF4\x91PP=\x80`\0\x81\x14a\x05\0W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x05\x05V[``\x91P[P\x80\x93P\x81\x92PPPa\x05\xA8\x82\x82`@Q` \x01\x80\x83\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x05cW\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x05&V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x82\x15\x15`\xF8\x1B\x81R`\x01\x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@Ra\r\xA3V[P\x92\x91PPV[`\0Tb\x01\0\0\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[```\0\x82` \x02g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x05\xEFW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80`\x1F\x01`\x1F\x19\x16` \x01\x82\x01`@R\x80\x15a\x06\x1AW` \x82\x01\x81\x806\x837\x01\x90P[P\x90P`\0[\x83\x81\x10\x15a\x06=W\x84\x81\x01T` \x80\x83\x02\x84\x01\x01R`\x01\x01a\x06 V[P\x90P[\x92\x91PPV[`\0Ta\x01\0\x90\x04`\xFF\x16\x80a\x06`WPa\x06`a\r\xABV[\x80a\x06nWP`\0T`\xFF\x16\x15[a\x06\xD9W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7FInitializable: initialized\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0Ta\x01\0\x90\x04`\xFF\x16\x15\x80\x15a\x07?W`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\xFF\x90\x91\x16a\x01\0\x17\x16`\x01\x17\x90U[`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\x16b\x01\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x90\x81\x02\x91\x90\x91\x17\x82U`@\x80Q\x91\x82R` \x82\x01\x92\x90\x92R\x81Q\x7F`\\-\xBFv._}`\xA5F\xD4.r\x05\xDC\xB1\xB0\x11\xEB\xC6*asjW\xC9\x08\x9D:CP\x92\x91\x81\x90\x03\x90\x91\x01\x90\xA1\x80\x15a\x07\xF4W`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\xFF\x16\x90U[PPV[`\0Tb\x01\0\0\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x08\x84W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FGPv2: caller not manager\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`\0\x81\x81R`\x01` \x90\x81R`@\x91\x82\x90 \x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x16\x90U\x81Q\x92\x83R\x90Q\x7Fd\x0E\x18\xA2X~\x1D\x83\xE4\xFD\xAB\xF7\x02W\xD0\xA8\0\xCAK,\x1A\xAA\xD1\xDF\xC4\x85\xA4\xAD\x8B\xBB\xD6\xC6\x92\x81\x90\x03\x90\x91\x01\x90\xA1PV[`\0Tb\x01\0\0\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14\x80a\tOWP3a\t7a\r\xB1V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14[a\t\xBAW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7FGPv2: not authorized\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0\x80Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x81\x16b\x01\0\0\x81\x81\x02\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\x85\x16\x17\x90\x94U`@\x80Q\x91\x82R\x93\x90\x92\x04\x16` \x82\x01\x81\x90R\x82Q\x90\x92\x7F`\\-\xBFv._}`\xA5F\xD4.r\x05\xDC\xB1\xB0\x11\xEB\xC6*asjW\xC9\x08\x9D:CP\x92\x82\x90\x03\x01\x90\xA1PPV[`\0Tb\x01\0\0\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\n\xD3W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FGPv2: caller not manager\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`\0\x81\x81R`\x01` \x81\x81R`@\x92\x83\x90 \x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x16\x90\x92\x17\x90\x91U\x81Q\x92\x83R\x90Q\x7FA\xF9\xD0\x9D\xD5\x15\x92Q\xF8\xA8\xE4\x82\xBB\xE0\x97\xB7\xC0\x1A^op\xC5\xA0\xDD\xB4\x94\x90dd\xFC\x9D\xD7\x92\x81\x90\x03\x90\x91\x01\x90\xA1PV[```\0cC!\x8E\x19`\xE0\x1B\x84\x84`@Q`$\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x0B\xC4W\x81\x81\x01Q\x83\x82\x01R` \x01a\x0B\xACV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x0B\xF1W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x81R` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x98\x16\x97\x90\x97\x17\x87RQ\x81Q\x91\x97P0\x96\x88\x96P\x90\x94P\x84\x93P\x91P\x80\x83\x83[` \x83\x10a\x0C\xC2W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x0C\x85V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\r$W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\r)V[``\x91P[P\x90P\x80\x92PP`\0\x82`\x01\x84Q\x03\x81Q\x81\x10a\rBW\xFE[` \x01\x01Q`\xF8\x1C`\xF8\x1B~\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16`\x01`\xF8\x1B\x14\x90Pa\r\x85\x83`\x01\x85Q\x03a\r\xD6V[\x80\x15a\r\x92WPPa\x06AV[a\r\x9B\x83a\r\xA3V[PP\x92\x91PPV[\x80Q` \x82\x01\xFD[0;\x15\x90V[\x7F\xB51'hJV\x8B1s\xAE\x13\xB9\xF8\xA6\x01n$>c\xB6\xE8\xEE\x11x\xD6\xA7\x17\x85\x0B]a\x03T\x90V[\x90RV\xFE\xA2dipfsX\"\x12 q\x06\xBA6\xB2\xD5\x18\xD8\x9A\\\xE8\x87\x05\xDD\x7FR\xD9\x8F:\x8C\x83\x8B\x8B\xB7\xAD\x9C\xDA\xA5\xB4%J\xB1dsolcC\0\x07\x06\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ManagerChanged(address,address)` and selector `0x605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a4350`. + ```solidity + event ManagerChanged(address newManager, address oldManager); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ManagerChanged { + #[allow(missing_docs)] + pub newManager: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub oldManager: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ManagerChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ManagerChanged(address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 96u8, 92u8, 45u8, 191u8, 118u8, 46u8, 95u8, 125u8, 96u8, 165u8, 70u8, 212u8, + 46u8, 114u8, 5u8, 220u8, 177u8, 176u8, 17u8, 235u8, 198u8, 42u8, 97u8, 115u8, + 106u8, 87u8, 201u8, 8u8, 157u8, 58u8, 67u8, 80u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + newManager: data.0, + oldManager: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.newManager, + ), + ::tokenize( + &self.oldManager, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ManagerChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ManagerChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ManagerChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SolverAdded(address)` and selector `0x41f9d09dd5159251f8a8e482bbe097b7c01a5e6f70c5a0ddb494906464fc9dd7`. + ```solidity + event SolverAdded(address solver); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SolverAdded { + #[allow(missing_docs)] + pub solver: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SolverAdded { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SolverAdded(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 65u8, 249u8, 208u8, 157u8, 213u8, 21u8, 146u8, 81u8, 248u8, 168u8, 228u8, + 130u8, 187u8, 224u8, 151u8, 183u8, 192u8, 26u8, 94u8, 111u8, 112u8, 197u8, + 160u8, 221u8, 180u8, 148u8, 144u8, 100u8, 100u8, 252u8, 157u8, 215u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { solver: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.solver, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SolverAdded { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SolverAdded> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SolverAdded) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SolverRemoved(address)` and selector `0x640e18a2587e1d83e4fdabf70257d0a800ca4b2c1aaad1dfc485a4ad8bbbd6c6`. + ```solidity + event SolverRemoved(address solver); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SolverRemoved { + #[allow(missing_docs)] + pub solver: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SolverRemoved { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SolverRemoved(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 100u8, 14u8, 24u8, 162u8, 88u8, 126u8, 29u8, 131u8, 228u8, 253u8, 171u8, 247u8, + 2u8, 87u8, 208u8, 168u8, 0u8, 202u8, 75u8, 44u8, 26u8, 170u8, 209u8, 223u8, + 196u8, 133u8, 164u8, 173u8, 139u8, 187u8, 214u8, 198u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { solver: data.0 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.solver, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SolverRemoved { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SolverRemoved> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SolverRemoved) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addSolver(address)` and selector `0xec58f4b8`. + ```solidity + function addSolver(address solver) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addSolverCall { + #[allow(missing_docs)] + pub solver: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`addSolver(address)`](addSolverCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addSolverReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addSolverCall) -> Self { + (value.solver,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addSolverCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { solver: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addSolverReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addSolverReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl addSolverReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addSolverCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = addSolverReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [236u8, 88u8, 244u8, 184u8]; + const SIGNATURE: &'static str = "addSolver(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.solver, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addSolverReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `initializeManager(address)` and selector `0x7f7120fe`. + ```solidity + function initializeManager(address manager_) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeManagerCall { + #[allow(missing_docs)] + pub manager_: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`initializeManager(address)`](initializeManagerCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeManagerReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeManagerCall) -> Self { + (value.manager_,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeManagerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { manager_: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeManagerReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeManagerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl initializeManagerReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for initializeManagerCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = initializeManagerReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [127u8, 113u8, 32u8, 254u8]; + const SIGNATURE: &'static str = "initializeManager(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.manager_, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + initializeManagerReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isSolver(address)` and selector `0x02cc250d`. + ```solidity + function isSolver(address prospectiveSolver) external view returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isSolverCall { + #[allow(missing_docs)] + pub prospectiveSolver: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isSolver(address)`](isSolverCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isSolverReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isSolverCall) -> Self { + (value.prospectiveSolver,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isSolverCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + prospectiveSolver: tuple.0, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isSolverReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isSolverReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isSolverCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [2u8, 204u8, 37u8, 13u8]; + const SIGNATURE: &'static str = "isSolver(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.prospectiveSolver, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isSolverReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isSolverReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `manager()` and selector `0x481c6a75`. + ```solidity + function manager() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct managerCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`manager()`](managerCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct managerReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: managerCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for managerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: managerReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for managerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for managerCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [72u8, 28u8, 106u8, 117u8]; + const SIGNATURE: &'static str = "manager()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: managerReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: managerReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `removeSolver(address)` and selector `0x8fd57b92`. + ```solidity + function removeSolver(address solver) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct removeSolverCall { + #[allow(missing_docs)] + pub solver: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`removeSolver(address)`](removeSolverCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct removeSolverReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: removeSolverCall) -> Self { + (value.solver,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for removeSolverCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { solver: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: removeSolverReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for removeSolverReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl removeSolverReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for removeSolverCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = removeSolverReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [143u8, 213u8, 123u8, 146u8]; + const SIGNATURE: &'static str = "removeSolver(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.solver, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + removeSolverReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `simulateDelegatecall(address,bytes)` and selector `0xf84436bd`. + ```solidity + function simulateDelegatecall(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateDelegatecallCall { + #[allow(missing_docs)] + pub targetContract: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub calldataPayload: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`simulateDelegatecall(address,bytes)`](simulateDelegatecallCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateDelegatecallReturn { + #[allow(missing_docs)] + pub response: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateDelegatecallCall) -> Self { + (value.targetContract, value.calldataPayload) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateDelegatecallCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + targetContract: tuple.0, + calldataPayload: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Bytes,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateDelegatecallReturn) -> Self { + (value.response,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateDelegatecallReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { response: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for simulateDelegatecallCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::Bytes; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 68u8, 54u8, 189u8]; + const SIGNATURE: &'static str = "simulateDelegatecall(address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.targetContract, + ), + ::tokenize( + &self.calldataPayload, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: simulateDelegatecallReturn = r.into(); + r.response + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: simulateDelegatecallReturn = r.into(); + r.response + }) + } + } + }; + ///Container for all the [`GPv2AllowListAuthentication`](self) function + /// calls. + #[derive(Clone)] + pub enum GPv2AllowListAuthenticationCalls { + #[allow(missing_docs)] + addSolver(addSolverCall), + #[allow(missing_docs)] + initializeManager(initializeManagerCall), + #[allow(missing_docs)] + isSolver(isSolverCall), + #[allow(missing_docs)] + manager(managerCall), + #[allow(missing_docs)] + removeSolver(removeSolverCall), + #[allow(missing_docs)] + simulateDelegatecall(simulateDelegatecallCall), + } + impl GPv2AllowListAuthenticationCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [2u8, 204u8, 37u8, 13u8], + [72u8, 28u8, 106u8, 117u8], + [127u8, 113u8, 32u8, 254u8], + [143u8, 213u8, 123u8, 146u8], + [236u8, 88u8, 244u8, 184u8], + [248u8, 68u8, 54u8, 189u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(isSolver), + ::core::stringify!(manager), + ::core::stringify!(initializeManager), + ::core::stringify!(removeSolver), + ::core::stringify!(addSolver), + ::core::stringify!(simulateDelegatecall), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for GPv2AllowListAuthenticationCalls { + const COUNT: usize = 6usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "GPv2AllowListAuthenticationCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::addSolver(_) => ::SELECTOR, + Self::initializeManager(_) => { + ::SELECTOR + } + Self::isSolver(_) => ::SELECTOR, + Self::manager(_) => ::SELECTOR, + Self::removeSolver(_) => ::SELECTOR, + Self::simulateDelegatecall(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + GPv2AllowListAuthenticationCalls, + >] = &[ + { + fn isSolver( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GPv2AllowListAuthenticationCalls::isSolver) + } + isSolver + }, + { + fn manager( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GPv2AllowListAuthenticationCalls::manager) + } + manager + }, + { + fn initializeManager( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GPv2AllowListAuthenticationCalls::initializeManager) + } + initializeManager + }, + { + fn removeSolver( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GPv2AllowListAuthenticationCalls::removeSolver) + } + removeSolver + }, + { + fn addSolver( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GPv2AllowListAuthenticationCalls::addSolver) + } + addSolver + }, + { + fn simulateDelegatecall( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(GPv2AllowListAuthenticationCalls::simulateDelegatecall) + } + simulateDelegatecall + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + GPv2AllowListAuthenticationCalls, + >] = &[ + { + fn isSolver( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(GPv2AllowListAuthenticationCalls::isSolver) + } + isSolver + }, + { + fn manager( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(GPv2AllowListAuthenticationCalls::manager) + } + manager + }, + { + fn initializeManager( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2AllowListAuthenticationCalls::initializeManager) + } + initializeManager + }, + { + fn removeSolver( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2AllowListAuthenticationCalls::removeSolver) + } + removeSolver + }, + { + fn addSolver( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(GPv2AllowListAuthenticationCalls::addSolver) + } + addSolver + }, + { + fn simulateDelegatecall( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2AllowListAuthenticationCalls::simulateDelegatecall) + } + simulateDelegatecall + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::addSolver(inner) => { + ::abi_encoded_size(inner) + } + Self::initializeManager(inner) => { + ::abi_encoded_size(inner) + } + Self::isSolver(inner) => { + ::abi_encoded_size(inner) + } + Self::manager(inner) => { + ::abi_encoded_size(inner) + } + Self::removeSolver(inner) => { + ::abi_encoded_size(inner) + } + Self::simulateDelegatecall(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::addSolver(inner) => { + ::abi_encode_raw(inner, out) + } + Self::initializeManager(inner) => { + ::abi_encode_raw(inner, out) + } + Self::isSolver(inner) => { + ::abi_encode_raw(inner, out) + } + Self::manager(inner) => { + ::abi_encode_raw(inner, out) + } + Self::removeSolver(inner) => { + ::abi_encode_raw(inner, out) + } + Self::simulateDelegatecall(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + ///Container for all the [`GPv2AllowListAuthentication`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum GPv2AllowListAuthenticationEvents { + #[allow(missing_docs)] + ManagerChanged(ManagerChanged), + #[allow(missing_docs)] + SolverAdded(SolverAdded), + #[allow(missing_docs)] + SolverRemoved(SolverRemoved), + } + impl GPv2AllowListAuthenticationEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 65u8, 249u8, 208u8, 157u8, 213u8, 21u8, 146u8, 81u8, 248u8, 168u8, 228u8, 130u8, + 187u8, 224u8, 151u8, 183u8, 192u8, 26u8, 94u8, 111u8, 112u8, 197u8, 160u8, 221u8, + 180u8, 148u8, 144u8, 100u8, 100u8, 252u8, 157u8, 215u8, + ], + [ + 96u8, 92u8, 45u8, 191u8, 118u8, 46u8, 95u8, 125u8, 96u8, 165u8, 70u8, 212u8, 46u8, + 114u8, 5u8, 220u8, 177u8, 176u8, 17u8, 235u8, 198u8, 42u8, 97u8, 115u8, 106u8, + 87u8, 201u8, 8u8, 157u8, 58u8, 67u8, 80u8, + ], + [ + 100u8, 14u8, 24u8, 162u8, 88u8, 126u8, 29u8, 131u8, 228u8, 253u8, 171u8, 247u8, + 2u8, 87u8, 208u8, 168u8, 0u8, 202u8, 75u8, 44u8, 26u8, 170u8, 209u8, 223u8, 196u8, + 133u8, 164u8, 173u8, 139u8, 187u8, 214u8, 198u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(SolverAdded), + ::core::stringify!(ManagerChanged), + ::core::stringify!(SolverRemoved), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for GPv2AllowListAuthenticationEvents { + const COUNT: usize = 3usize; + const NAME: &'static str = "GPv2AllowListAuthenticationEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ManagerChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::SolverAdded) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::SolverRemoved) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for GPv2AllowListAuthenticationEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::ManagerChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SolverAdded(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::SolverRemoved(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::ManagerChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SolverAdded(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::SolverRemoved(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2AllowListAuthentication`](self) contract instance. + + See the [wrapper's documentation](`GPv2AllowListAuthenticationInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2AllowListAuthenticationInstance { + GPv2AllowListAuthenticationInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + GPv2AllowListAuthenticationInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + GPv2AllowListAuthenticationInstance::::deploy_builder(__provider) + } + /**A [`GPv2AllowListAuthentication`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2AllowListAuthentication`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2AllowListAuthenticationInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2AllowListAuthenticationInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2AllowListAuthenticationInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2AllowListAuthenticationInstance + { + /**Creates a new wrapper around an on-chain [`GPv2AllowListAuthentication`](self) contract instance. + + See the [wrapper's documentation](`GPv2AllowListAuthenticationInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2AllowListAuthenticationInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2AllowListAuthenticationInstance { + GPv2AllowListAuthenticationInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2AllowListAuthenticationInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`addSolver`] function. + pub fn addSolver( + &self, + solver: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, addSolverCall, N> { + self.call_builder(&addSolverCall { solver }) + } + + ///Creates a new call builder for the [`initializeManager`] function. + pub fn initializeManager( + &self, + manager_: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, initializeManagerCall, N> { + self.call_builder(&initializeManagerCall { manager_ }) + } + + ///Creates a new call builder for the [`isSolver`] function. + pub fn isSolver( + &self, + prospectiveSolver: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, isSolverCall, N> { + self.call_builder(&isSolverCall { prospectiveSolver }) + } + + ///Creates a new call builder for the [`manager`] function. + pub fn manager(&self) -> alloy_contract::SolCallBuilder<&P, managerCall, N> { + self.call_builder(&managerCall) + } + + ///Creates a new call builder for the [`removeSolver`] function. + pub fn removeSolver( + &self, + solver: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, removeSolverCall, N> { + self.call_builder(&removeSolverCall { solver }) + } + + ///Creates a new call builder for the [`simulateDelegatecall`] + /// function. + pub fn simulateDelegatecall( + &self, + targetContract: alloy_sol_types::private::Address, + calldataPayload: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, simulateDelegatecallCall, N> { + self.call_builder(&simulateDelegatecallCall { + targetContract, + calldataPayload, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2AllowListAuthenticationInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`ManagerChanged`] event. + pub fn ManagerChanged_filter(&self) -> alloy_contract::Event<&P, ManagerChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SolverAdded`] event. + pub fn SolverAdded_filter(&self) -> alloy_contract::Event<&P, SolverAdded, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SolverRemoved`] event. + pub fn SolverRemoved_filter(&self) -> alloy_contract::Event<&P, SolverRemoved, N> { + self.event_filter::() + } + } +} +pub type Instance = + GPv2AllowListAuthentication::GPv2AllowListAuthenticationInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(12593263u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(134254466u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(48173639u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(16465099u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(45854728u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(21407137u64), + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(3439709u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(204702129u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(59891351u64), + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(34436840u64), + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(24333100u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), + Some(4717469u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/gpv2settlement/Cargo.toml b/contracts/generated/contracts-generated/gpv2settlement/Cargo.toml new file mode 100644 index 0000000000..846c1e3539 --- /dev/null +++ b/contracts/generated/contracts-generated/gpv2settlement/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-gpv2settlement" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/gpv2settlement/src/lib.rs b/contracts/generated/contracts-generated/gpv2settlement/src/lib.rs new file mode 100644 index 0000000000..ca024bc92e --- /dev/null +++ b/contracts/generated/contracts-generated/gpv2settlement/src/lib.rs @@ -0,0 +1,5150 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Interaction { + struct Data { address target; uint256 value; bytes callData; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Interaction { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address target; uint256 value; bytes callData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub callData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + (value.target, value.value, value.callData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + value: tuple.1, + callData: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.target, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.callData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address target,uint256 value,bytes callData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.target, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.value) + .0, + ::eip712_data_word( + &self.callData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.target, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.value) + + ::topic_preimage_length( + &rust.callData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.target, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.value, + out, + ); + ::encode_topic_preimage( + &rust.callData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Interaction`](self) contract instance. + + See the [wrapper's documentation](`GPv2InteractionInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2InteractionInstance { + GPv2InteractionInstance::::new(address, __provider) + } + /**A [`GPv2Interaction`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Interaction`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2InteractionInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2InteractionInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2InteractionInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Interaction`](self) contract instance. + + See the [wrapper's documentation](`GPv2InteractionInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2InteractionInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2InteractionInstance { + GPv2InteractionInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Trade { + struct Data { uint256 sellTokenIndex; uint256 buyTokenIndex; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; uint256 flags; uint256 executedAmount; bytes signature; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Trade { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { uint256 sellTokenIndex; uint256 buyTokenIndex; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; uint256 flags; uint256 executedAmount; bytes signature; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub sellTokenIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyTokenIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub validTo: u32, + #[allow(missing_docs)] + pub appData: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub flags: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub executedAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub signature: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u32, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + ( + value.sellTokenIndex, + value.buyTokenIndex, + value.receiver, + value.sellAmount, + value.buyAmount, + value.validTo, + value.appData, + value.feeAmount, + value.flags, + value.executedAmount, + value.signature, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sellTokenIndex: tuple.0, + buyTokenIndex: tuple.1, + receiver: tuple.2, + sellAmount: tuple.3, + buyAmount: tuple.4, + validTo: tuple.5, + appData: tuple.6, + feeAmount: tuple.7, + flags: tuple.8, + executedAmount: tuple.9, + signature: tuple.10, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.sellTokenIndex), + as alloy_sol_types::SolType>::tokenize(&self.buyTokenIndex), + ::tokenize( + &self.receiver, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellAmount), + as alloy_sol_types::SolType>::tokenize(&self.buyAmount), + as alloy_sol_types::SolType>::tokenize(&self.validTo), + as alloy_sol_types::SolType>::tokenize(&self.appData), + as alloy_sol_types::SolType>::tokenize(&self.feeAmount), + as alloy_sol_types::SolType>::tokenize(&self.flags), + as alloy_sol_types::SolType>::tokenize(&self.executedAmount), + ::tokenize( + &self.signature, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(uint256 sellTokenIndex,uint256 buyTokenIndex,address receiver,uint256 \ + sellAmount,uint256 buyAmount,uint32 validTo,bytes32 appData,uint256 \ + feeAmount,uint256 flags,uint256 executedAmount,bytes signature)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word( + &self.sellTokenIndex, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.buyTokenIndex) + .0, + ::eip712_data_word( + &self.receiver, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.sellAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.buyAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.validTo) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.appData) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.feeAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.flags) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.executedAmount, + ) + .0, + ::eip712_data_word( + &self.signature, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellTokenIndex, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyTokenIndex, + ) + + ::topic_preimage_length( + &rust.receiver, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sellAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.buyAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.validTo, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.appData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.feeAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.flags) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.executedAmount, + ) + + ::topic_preimage_length( + &rust.signature, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellTokenIndex, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyTokenIndex, + out, + ); + ::encode_topic_preimage( + &rust.receiver, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sellAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.buyAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.validTo, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.appData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.feeAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.flags, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.executedAmount, + out, + ); + ::encode_topic_preimage( + &rust.signature, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Trade`](self) contract instance. + + See the [wrapper's documentation](`GPv2TradeInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2TradeInstance { + GPv2TradeInstance::::new(address, __provider) + } + /**A [`GPv2Trade`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Trade`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2TradeInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2TradeInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2TradeInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2TradeInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Trade`](self) contract instance. + + See the [wrapper's documentation](`GPv2TradeInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2TradeInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2TradeInstance { + GPv2TradeInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2TradeInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2TradeInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library IVault { + struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IVault { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct BatchSwapStep { + #[allow(missing_docs)] + pub poolId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub assetInIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub assetOutIndex: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub userData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: BatchSwapStep) -> Self { + ( + value.poolId, + value.assetInIndex, + value.assetOutIndex, + value.amount, + value.userData, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for BatchSwapStep { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + poolId: tuple.0, + assetInIndex: tuple.1, + assetOutIndex: tuple.2, + amount: tuple.3, + userData: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for BatchSwapStep { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for BatchSwapStep { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.poolId), + as alloy_sol_types::SolType>::tokenize(&self.assetInIndex), + as alloy_sol_types::SolType>::tokenize(&self.assetOutIndex), + as alloy_sol_types::SolType>::tokenize(&self.amount), + ::tokenize( + &self.userData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for BatchSwapStep { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for BatchSwapStep { + const NAME: &'static str = "BatchSwapStep"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "BatchSwapStep(bytes32 poolId,uint256 assetInIndex,uint256 \ + assetOutIndex,uint256 amount,bytes userData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word(&self.poolId) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.assetInIndex) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.assetOutIndex) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ::eip712_data_word( + &self.userData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for BatchSwapStep { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.poolId, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.assetInIndex, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.assetOutIndex, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + ::topic_preimage_length( + &rust.userData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.poolId, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.assetInIndex, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.assetOutIndex, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + ::encode_topic_preimage( + &rust.userData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IVault`](self) contract instance. + + See the [wrapper's documentation](`IVaultInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IVaultInstance { + IVaultInstance::::new(address, __provider) + } + /**A [`IVault`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IVault`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IVaultInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IVaultInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IVaultInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /**Creates a new wrapper around an on-chain [`IVault`](self) contract instance. + + See the [wrapper's documentation](`IVaultInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IVaultInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IVaultInstance { + IVaultInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IVaultInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library GPv2Interaction { + struct Data { + address target; + uint256 value; + bytes callData; + } +} + +library GPv2Trade { + struct Data { + uint256 sellTokenIndex; + uint256 buyTokenIndex; + address receiver; + uint256 sellAmount; + uint256 buyAmount; + uint32 validTo; + bytes32 appData; + uint256 feeAmount; + uint256 flags; + uint256 executedAmount; + bytes signature; + } +} + +library IVault { + struct BatchSwapStep { + bytes32 poolId; + uint256 assetInIndex; + uint256 assetOutIndex; + uint256 amount; + bytes userData; + } +} + +interface GPv2Settlement { + event Interaction(address indexed target, uint256 value, bytes4 selector); + event OrderInvalidated(address indexed owner, bytes orderUid); + event PreSignature(address indexed owner, bytes orderUid, bool signed); + event Settlement(address indexed solver); + event Trade(address indexed owner, address sellToken, address buyToken, uint256 sellAmount, uint256 buyAmount, uint256 feeAmount, bytes orderUid); + + constructor(address authenticator_, address vault_); + + receive() external payable; + + function authenticator() external view returns (address); + function domainSeparator() external view returns (bytes32); + function filledAmount(bytes memory) external view returns (uint256); + function invalidateOrder(bytes memory orderUid) external; + function setPreSignature(bytes memory orderUid, bool signed) external; + function settle(address[] memory tokens, uint256[] memory clearingPrices, GPv2Trade.Data[] memory trades, GPv2Interaction.Data[][3] memory interactions) external; + function simulateDelegatecall(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); + function swap(IVault.BatchSwapStep[] memory swaps, address[] memory tokens, GPv2Trade.Data memory trade) external; + function vault() external view returns (address); + function vaultRelayer() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "authenticator_", + "type": "address", + "internalType": "contract GPv2Authentication" + }, + { + "name": "vault_", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "authenticator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract GPv2Authentication" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "filledAmount", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "invalidateOrder", + "inputs": [ + { + "name": "orderUid", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPreSignature", + "inputs": [ + { + "name": "orderUid", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signed", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settle", + "inputs": [ + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "clearingPrices", + "type": "uint256[]", + "internalType": "uint256[]" + }, + { + "name": "trades", + "type": "tuple[]", + "internalType": "struct GPv2Trade.Data[]", + "components": [ + { + "name": "sellTokenIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyTokenIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "flags", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "executedAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "interactions", + "type": "tuple[][3]", + "internalType": "struct GPv2Interaction.Data[][3]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "simulateDelegatecall", + "inputs": [ + { + "name": "targetContract", + "type": "address", + "internalType": "address" + }, + { + "name": "calldataPayload", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "response", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "swaps", + "type": "tuple[]", + "internalType": "struct IVault.BatchSwapStep[]", + "components": [ + { + "name": "poolId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "assetInIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "assetOutIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "userData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "contract IERC20[]" + }, + { + "name": "trade", + "type": "tuple", + "internalType": "struct GPv2Trade.Data", + "components": [ + { + "name": "sellTokenIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyTokenIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "validTo", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "appData", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "flags", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "executedAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "vault", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IVault" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "vaultRelayer", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract GPv2VaultRelayer" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "Interaction", + "inputs": [ + { + "name": "target", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "selector", + "type": "bytes4", + "indexed": false, + "internalType": "bytes4" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OrderInvalidated", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "orderUid", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PreSignature", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "orderUid", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "signed", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Settlement", + "inputs": [ + { + "name": "solver", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Trade", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sellToken", + "type": "address", + "indexed": false, + "internalType": "contract IERC20" + }, + { + "name": "buyToken", + "type": "address", + "indexed": false, + "internalType": "contract IERC20" + }, + { + "name": "sellAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "feeAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "orderUid", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Settlement { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6101006040523480156200001257600080fd5b50604051620053eb380380620053eb83398101604081905262000035916200015b565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c828401527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf606080840191909152466080808501919091523060a08086019190915285518086038201815260c09586019687905280519401939093209052600180556001600160601b031986821b811690925284901b16905281906200010a906200014d565b62000116919062000199565b604051809103906000f08015801562000133573d6000803e3d6000fd5b5060601b6001600160601b03191660e05250620001c69050565b61129e806200414d83390190565b600080604083850312156200016e578182fd5b82516200017b81620001ad565b60208401519092506200018e81620001ad565b809150509250929050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114620001c357600080fd5b50565b60805160a05160601c60c05160601c60e05160601c613f2562000228600039806104c55280610d61528061109052806115f0525080610556528061158b52508061039252806106bc528061099d52508061131e52806123df5250613f256000f3fe6080604052600436106100ec5760003560e01c80639b552cc21161008a578063ed9f35ce11610059578063ed9f35ce14610274578063f698da2514610294578063f84436bd146102a9578063fbfa77cf146102c9576100f3565b80639b552cc2146101ff578063a2a7d51b14610214578063d08d33d114610234578063ec6cb13f14610254576100f3565b80632479fb6e116100c65780632479fb6e1461016557806343218e19146101925780635624b25b146101bf578063845a101f146101df576100f3565b806313d79a0b146100f857806315337bc01461011a5780632335c76b1461013a576100f3565b366100f357005b600080fd5b34801561010457600080fd5b5061011861011336600461322e565b6102de565b005b34801561012657600080fd5b50610118610135366004613441565b6105c1565b34801561014657600080fd5b5061014f6106ba565b60405161015c91906136ee565b60405180910390f35b34801561017157600080fd5b506101856101803660046134ca565b6106de565b60405161015c91906137f0565b34801561019e57600080fd5b506101b26101ad3660046131a0565b6106fb565b60405161015c919061380d565b3480156101cb57600080fd5b506101b26101da3660046134fd565b610873565b3480156101eb57600080fd5b506101186101fa36600461338e565b6108e9565b34801561020b57600080fd5b5061014f61108e565b34801561022057600080fd5b5061011861022f3660046131ee565b6110b2565b34801561024057600080fd5b5061018561024f3660046134ca565b6110fb565b34801561026057600080fd5b5061011861026f366004613475565b611118565b34801561028057600080fd5b5061011861028f3660046131ee565b6112d7565b3480156102a057600080fd5b5061018561131c565b3480156102b557600080fd5b506101b26102c43660046131a0565b611340565b3480156102d557600080fd5b5061014f611589565b6002600154141561035057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906302cc250d906103c79033906004016136ee565b60206040518083038186803b1580156103df57600080fd5b505afa1580156103f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104179190613425565b610456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b60405180910390fd5b6104728160005b60200281019061046d9190613d16565b6115ad565b6000806104838989898989896116ea565b6040517f7d10d11f000000000000000000000000000000000000000000000000000000008152919350915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637d10d11f906104fa90859060040161370f565b600060405180830381600087803b15801561051457600080fd5b505af1158015610528573d6000803e3d6000fd5b5050505061053c8360016003811061045d57fe5b61057c73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001682611851565b61058783600261045d565b60405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a250506001805550505050505050565b60006105cd8383611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff81163314610620576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a1b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600284846040516106539291906136c2565b9081526020016040518091039020819055508073ffffffffffffffffffffffffffffffffffffffff167f875b6cb035bbd4ac6500fabc6d1e4ca5bdc58a3e2b424ccb5c24cdbebeb009a984846040516106ad9291906137f9565b60405180910390a2505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b805160208183018101805160028252928201919093012091525481565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b6020831061076457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610727565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146107c4576040519150601f19603f3d011682016040523d82523d6000602084013e6107c9565b606091505b50809350819250505061086c82826040516020018083805190602001908083835b6020831061082757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107ea565b6001836020036101000a03801982511681845116808217855250505050505090500182151560f81b815260010192505050604051602081830303815290604052611bbd565b5092915050565b606060008260200267ffffffffffffffff8111801561089157600080fd5b506040519080825280601f01601f1916602001820160405280156108bc576020820181803683370190505b50905060005b838110156108df57848101546020808302840101526001016108c2565b5090505b92915050565b6002600154141561095b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906302cc250d906109d29033906004016136ee565b60206040518083038186803b1580156109ea57600080fd5b505afa1580156109fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a229190613425565b610a58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b6000610a62611bc5565b8051909150610a7382868686611bf2565b60007ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677582610100015114610aa8576001610aab565b60005b9050610ab5612f90565b60408085015173ffffffffffffffffffffffffffffffffffffffff90811683526101408501517f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce9081146020850152606080880151909216928401929092526101608501519091149082015260008667ffffffffffffffff81118015610b3a57600080fd5b50604051908082528060200260200182016040528015610b64578160200160208202803683370190505b50610100850151909150610120870135907ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467751415610c30578460800151811015610bda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c41565b610be78560600151611c90565b82886000013581518110610bf757fe5b602002602001018181525050610c0c81611c90565b60000382886020013581518110610c1f57fe5b602002602001018181525050610cc0565b8460600151811115610c6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b9c565b610c7781611c90565b82886000013581518110610c8757fe5b602002602001018181525050610ca08560800151611c90565b60000382886020013581518110610cb357fe5b6020026020010181815250505b610cc8612f90565b8660400151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560000151816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560e0015181604001818152505085610140015181606001818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634817a286878f8f8f8f8b8b8f60a001518b6040518a63ffffffff1660e01b8152600401610dcc99989796959493929190613877565b600060405180830381600087803b158015610de657600080fd5b505af1158015610dfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e4091908101906132ed565b90506000886020015190506000610e6d838c6000013581518110610e6057fe5b6020026020010151611d25565b90506000610e94848d6020013581518110610e8457fe5b6020026020010151600003611d25565b9050600283604051610ea691906136d2565b908152602001604051809103902054600014610eee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b7ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467758a61010001511415610f825789606001518214610f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613ac0565b8960600151600284604051610f6d91906136d2565b90815260405190819003602001902055610fe5565b89608001518114610fbf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613af7565b8960800151600284604051610fd491906136d2565b908152604051908190036020019020555b8a6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc178b600001518c6020015185858f60e001518960405161104596959493929190613820565b60405180910390a260405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a25050600180555050505050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b3033146110eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760008383611d96565b5050565b805160208183018101805160008252928201919093012091525481565b60006111248484611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff811633146111ac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f475076323a2063616e6e6f74207072657369676e206f72646572000000000000604482015290519081900360640190fd5b8115611206577ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c60008585604051808383808284378083019250505092505050908152602001604051809103902081905550611232565b600080858560405180838380828437919091019485525050604051928390036020019092209290925550505b8073ffffffffffffffffffffffffffffffffffffffff167f01bf7c8b0ca55deecbea89d7e58295b7ffbf685fd0d96801034ba8c6ffe1c68d858585604051808060200183151581526020018281038252858582818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a250505050565b303314611310576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760028383611d96565b7f000000000000000000000000000000000000000000000000000000000000000081565b606060006343218e1960e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156113aa578181015183820152602001611392565b50505050905090810190601f1680156113d75780820380516001836020036101000a031916815260200191505b50604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909816979097178752518151919750309688965090945084935091508083835b602083106114a857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161146b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461150a576040519150601f19603f3d011682016040523d82523d6000602084013e61150f565b606091505b5090508092505060008260018451038151811061152857fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b14905061156b836001855103611e46565b80156115785750506108e3565b61158183611bbd565b505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60005b818110156116e557368383838181106115c557fe5b90506020028101906115d79190613dde565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001661161d6020830183613184565b73ffffffffffffffffffffffffffffffffffffffff16141561166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613caf565b61167481611e4a565b6116816020820182613184565b73ffffffffffffffffffffffffffffffffffffffff167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356116c684611ea1565b6040516116d4929190613ce6565b60405180910390a2506001016115b0565b505050565b60608060006116f7611bc5565b90508367ffffffffffffffff8111801561171057600080fd5b5060405190808252806020026020018201604052801561174a57816020015b611737612f90565b81526020019060019003908161172f5790505b5092508367ffffffffffffffff8111801561176457600080fd5b5060405190808252806020026020018201604052801561179e57816020015b61178b612f90565b8152602001906001900390816117835790505b50915060005b8481101561184457368686838181106117b957fe5b90506020028101906117cb9190613e11565b90506117d9838c8c84611bf2565b61183b838a8a84358181106117ea57fe5b905060200201358b8b856020013581811061180157fe5b9050602002013584610120013589878151811061181a57fe5b602002602001015189888151811061182e57fe5b6020026020010151611ecb565b506001016117a4565b5050965096945050505050565b6000815167ffffffffffffffff8111801561186b57600080fd5b506040519080825280602002602001820160405280156118a557816020015b611892612fb7565b81526020019060019003908161188a5790505b5090506000805b8351811015611a935760008482815181106118c357fe5b6020026020010151905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1614156119c7577f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce81606001511415611977576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b2e565b8051604080830151905173ffffffffffffffffffffffffffffffffffffffff9092169181156108fc0291906000818181858888f193505050501580156119c1573d6000803e3d6000fd5b50611a8a565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981606001511415611a2657805160408201516020830151611a219273ffffffffffffffffffffffffffffffffffffffff90911691612216565b611a8a565b6000848480600101955081518110611a3a57fe5b602090810291909101810151600081528382015173ffffffffffffffffffffffffffffffffffffffff90811692820192909252604080850151908201523060608201528351909116608090910152505b506001016118ac565b508015611b2957611aa48282611e46565b6040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851690630e8e3e8490611af690859060040161375d565b600060405180830381600087803b158015611b1057600080fd5b505af1158015611b24573d6000803e3d6000fd5b505050505b50505050565b6000808060388414611ba257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f475076323a20696e76616c696420756964000000000000000000000000000000604482015290519081900360640190fd5b5050823593602084013560601c936034013560e01c92509050565b805160208201fd5b611bcd612fe7565b6040805160388082526060820190925290602082018180368337505050602082015290565b83516000611c02838686856122ee565b9050600080611c1f8484611c1a610140890189613d7b565b6123d6565b91509150611c4282828660a001518b60200151612485909392919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff81166040890152611c688482612507565b73ffffffffffffffffffffffffffffffffffffffff1660609098019790975250505050505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f53616665436173743a20696e74323536206f766572666c6f7700000000000000604482015290519081900360640190fd5b5090565b600080821215611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f53616665436173743a206e6f7420706f73697469766500000000000000000000604482015290519081900360640190fd5b60005b81811015611b2957366000848484818110611db057fe5b9050602002810190611dc29190613d7b565b915091506000611dd28383611b2f565b92505050428163ffffffff1610611e15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c0a565b6000878484604051611e289291906136c2565b90815260405190819003602001902055505060019091019050611d99565b9052565b73ffffffffffffffffffffffffffffffffffffffff8135166020820135366000611e776040860186613d7b565b9150915060405181838237600080838387895af1611e99573d6000803e3d6000fd5b505050505050565b60003681611eb26040850185613d7b565b909250905060048110611ec457813592505b5050919050565b8551602087015160a08201514263ffffffff9091161015611f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a52565b6080820151611f279087612539565b6060830151611f369089612539565b1015611f6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a89565b6000806000807ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775866101000151141561206f5785610120015115611fdb57889350611fd48660600151611fce868960e0015161253990919063ffffffff16565b906125c9565b9150611fea565b856060015193508560e0015191505b611ffe8a611ff8868e612539565b9061264a565b925061202a8460028760405161201491906136d2565b90815260405190819003602001902054906126e8565b9050856060015181111561206a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b612116565b856101200151156120a35788925061209c8660800151611fce858960e0015161253990919063ffffffff16565b91506120b2565b856080015192508560e0015191505b6120c08b611fce858d612539565b93506120d68360028760405161201491906136d2565b90508560800151811115612116576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b61212084836126e8565b93508060028660405161213391906136d2565b9081526020016040518091039020819055508b6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc17876000015188602001518787878b6040516121a196959493929190613820565b60405180910390a250506040808b015173ffffffffffffffffffffffffffffffffffffffff9081168852855181166020808a0191909152888301949094526101408601516060988901529a8701518b16865282850151909a169185019190915297830197909752610160015191015250505050565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff84166004830152602482018390529060008060448382895af1612279573d6000803e3d6000fd5b506122838461275c565b611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f475076323a206661696c6564207472616e736665720000000000000000000000604482015290519081900360640190fd5b6000838386358181106122fd57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168452508490849087013581811061233057fe5b73ffffffffffffffffffffffffffffffffffffffff602091820293909301358316908501525060408087013590911690830152606080860135908301526080808601359083015263ffffffff60a080870135919091169083015260c0808601359083015260e080860135908301526123ac610100860135612826565b61016087019190915261014086019190915290151561012085015261010090930152509392505050565b600080612403867f000000000000000000000000000000000000000000000000000000000000000061297b565b9150600085600381111561241357fe5b141561242b57612424828585612a05565b905061247c565b600185600381111561243957fe5b141561244a57612424828585612a1a565b600285600381111561245857fe5b141561246957612424828585612a82565b6124798285858960a00151612c20565b90505b94509492505050565b60388451146124f557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f7700000000000000604482015290519081900360640190fd5b60388401526034830152602090910152565b604082015160009073ffffffffffffffffffffffffffffffffffffffff166125305750806108e3565b50506040015190565b600082612548575060006108e3565b8282028284828161255557fe5b04146125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f536166654d6174683a206d756c206f766572666c6f7700000000000000000000604482015290519081900360640190fd5b9392505050565b600080821161263957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f536166654d6174683a206469766973696f6e2062792030000000000000000000604482015290519081900360640190fd5b81838161264257fe5b049392505050565b60008082116126ba57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f536166654d6174683a206365696c696e67206469766973696f6e206279203000604482015290519081900360640190fd5b8183816126c357fe5b06156126d05760016126d3565b60005b60ff168284816126df57fe5b04019392505050565b6000828201838110156125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600061279a565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452806024528160445260646000fd5b3d80156127d95760208114612813576127d47f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f612763565b612820565b823b61280a5761280a7f475076323a206e6f74206120636f6e74726163740000000000000000000000006014612763565b60019150612820565b3d6000803e600051151591505b50919050565b6000808080806001861661285c577ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467759450612880565b7f6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc94505b6002861615159350600886166128b8577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9925061290c565b600486166128e8577fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632925061290c565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce92505b6010861661293c577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc99150612960565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce91505b600586901c600381111561297057fe5b905091939590929450565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6000612a12848484612de5565b949350505050565b6000808460405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c01828152602001915050604051602081830303815290604052805190602001209050612a79818585612de5565b95945050505050565b813560601c366000612a978460148188613e68565b604080517f1626ba7e00000000000000000000000000000000000000000000000000000000808252600482018b81526024830193845260448301859052949650929450919273ffffffffffffffffffffffffffffffffffffffff871692631626ba7e928b928892889290606401848480828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201965060209550909350505081840390508186803b158015612b5d57600080fd5b505afa158015612b71573d6000803e3d6000fd5b505050506040513d6020811015612b8757600080fd5b50517fffffffff000000000000000000000000000000000000000000000000000000001614612c1757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a20696e76616c69642065697031323731207369676e617475726500604482015290519081900360640190fd5b50509392505050565b600060148314612c9157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f475076323a206d616c666f726d6564207072657369676e617475726500000000604482015290519081900360640190fd5b506040805160388082526060828101909352853590921c9160009190602082018180368337019050509050612cc881878486612485565b7ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c6000826040518082805190602001908083835b60208310612d3c57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612cff565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390205414612ddc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a206f72646572206e6f74207072657369676e656400000000000000604482015290519081900360640190fd5b50949350505050565b600060418214612e5657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a206d616c666f726d6564206563647361207369676e617475726500604482015290519081900360640190fd5b604080516000815260208181018084528790528286013560f81c82840181905286356060840181905282880135608085018190529451909493919260019260a0808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015612ed9573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff8416612f8657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f475076323a20696e76616c6964206563647361207369676e6174757265000000604482015290519081900360640190fd5b5050509392505050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b6040518060800160405280612ffa613014565b815260606020820181905260006040830181905291015290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b60008083601f840112613089578182fd5b50813567ffffffffffffffff8111156130a0578182fd5b60208301915083602080830285010111156130ba57600080fd5b9250929050565b60008083601f8401126130d2578182fd5b50813567ffffffffffffffff8111156130e9578182fd5b6020830191508360208285010111156130ba57600080fd5b600082601f830112613111578081fd5b813567ffffffffffffffff81111561312557fe5b61315660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613e44565b81815284602083860101111561316a578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215613195578081fd5b81356125c281613ebc565b600080604083850312156131b2578081fd5b82356131bd81613ebc565b9150602083013567ffffffffffffffff8111156131d8578182fd5b6131e485828601613101565b9150509250929050565b60008060208385031215613200578182fd5b823567ffffffffffffffff811115613216578283fd5b61322285828601613078565b90969095509350505050565b60008060008060008060006080888a031215613248578283fd5b873567ffffffffffffffff8082111561325f578485fd5b61326b8b838c01613078565b909950975060208a0135915080821115613283578485fd5b61328f8b838c01613078565b909750955060408a01359150808211156132a7578485fd5b6132b38b838c01613078565b909550935060608a01359150808211156132cb578283fd5b508801606081018a10156132dd578182fd5b8091505092959891949750929550565b600060208083850312156132ff578182fd5b825167ffffffffffffffff80821115613316578384fd5b818501915085601f830112613329578384fd5b81518181111561333557fe5b8381029150613345848301613e44565b8181528481019084860184860187018a101561335f578788fd5b8795505b83861015613381578051835260019590950194918601918601613363565b5098975050505050505050565b6000806000806000606086880312156133a5578081fd5b853567ffffffffffffffff808211156133bc578283fd5b6133c889838a01613078565b909750955060208801359150808211156133e0578283fd5b6133ec89838a01613078565b90955093506040880135915080821115613404578283fd5b5086016101608189031215613417578182fd5b809150509295509295909350565b600060208284031215613436578081fd5b81516125c281613ee1565b60008060208385031215613453578182fd5b823567ffffffffffffffff811115613469578283fd5b613222858286016130c1565b600080600060408486031215613489578081fd5b833567ffffffffffffffff81111561349f578182fd5b6134ab868287016130c1565b90945092505060208401356134bf81613ee1565b809150509250925092565b6000602082840312156134db578081fd5b813567ffffffffffffffff8111156134f1578182fd5b612a1284828501613101565b6000806040838503121561350f578182fd5b50508035926020909101359150565b60008284526020808501945082825b8581101561356857813561354081613ebc565b73ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161352d565b509495945050505050565b6000815180845260208085019450808401835b8381101561356857815187529582019590820190600101613586565b600082845282826020860137806020848601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011685010190509392505050565b60008151808452613602816020860160208601613e90565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8082511683528060208301511660208401525060408101516040830152606081015160608301525050565b73ffffffffffffffffffffffffffffffffffffffff808251168352602082015115156020840152806040830151166040840152506060810151151560608301525050565b63ffffffff169052565b6000828483379101908152919050565b600082516136e4818460208701613e90565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252825182820181905260009190848201906040850190845b818110156137515761373e838551613634565b928401926080929092019160010161372b565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156137e357815180516004811061379057fe5b85528087015173ffffffffffffffffffffffffffffffffffffffff908116888701528682015187870152606080830151821690870152608091820151169085015260a0909301929085019060010161377a565b5091979650505050505050565b90815260200190565b600060208252612a126020830184866135a2565b6000602082526125c260208301846135ea565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015283608083015260c060a083015261386b60c08301846135ea565b98975050505050505050565b60006101a0820160028c1061388857fe5b8b835260206101a081850152818b83526101c0850190506101c0828d0286010192508c845b8d8110156139b6577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe408786030183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618f36030182351261390c578586fd5b8e823501803586528481013585870152604081013560408701526060810135606087015260808101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112613964578788fd5b8101803567ffffffffffffffff81111561397c578889fd5b80360383131561398a578889fd5b60a060808901526139a160a08901828985016135a2565b975050509284019250908301906001016138ad565b5050505082810360408401526139cd81898b61351e565b90506139dc6060840188613674565b82810360e08401526139ee8187613573565b9150506139ff6101008301856136b8565b613a0d610120830184613634565b9a9950505050505050505050565b6020808252601f908201527f475076323a2063616c6c657220646f6573206e6f74206f776e206f7264657200604082015260600190565b60208082526013908201527f475076323a206f72646572206578706972656400000000000000000000000000604082015260600190565b6020808252601f908201527f475076323a206c696d6974207072696365206e6f742072657370656374656400604082015260600190565b6020808252601f908201527f475076323a2073656c6c20616d6f756e74206e6f742072657370656374656400604082015260600190565b6020808252601e908201527f475076323a2062757920616d6f756e74206e6f74207265737065637465640000604082015260600190565b6020808252601e908201527f475076323a20756e737570706f7274656420696e7465726e616c204554480000604082015260600190565b60208082526018908201527f475076323a206e6f7420616e20696e746572616374696f6e0000000000000000604082015260600190565b60208082526014908201527f475076323a206c696d697420746f6f2068696768000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206f726465722066696c6c65640000000000000000000000000000604082015260600190565b60208082526017908201527f475076323a206f72646572207374696c6c2076616c6964000000000000000000604082015260600190565b60208082526013908201527f475076323a206c696d697420746f6f206c6f7700000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206e6f74206120736f6c7665720000000000000000000000000000604082015260600190565b6020808252601b908201527f475076323a20666f7262696464656e20696e746572616374696f6e0000000000604082015260600190565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260400190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613d4a578283fd5b83018035915067ffffffffffffffff821115613d64578283fd5b60209081019250810236038213156130ba57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613daf578283fd5b83018035915067ffffffffffffffff821115613dc9578283fd5b6020019150368190038213156130ba57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126136e4578182fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18336030181126136e4578182fd5b60405181810167ffffffffffffffff81118282101715613e6057fe5b604052919050565b60008085851115613e77578182fd5b83861115613e83578182fd5b5050820193919092039150565b60005b83811015613eab578181015183820152602001613e93565b83811115611b295750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114613ede57600080fd5b50565b8015158114613ede57600080fdfea2646970667358221220de5e493c48a3b42da03a5db89085177b8d8ccec6e9bf6e8e48b3809343624c8f64736f6c6343000706003360c060405234801561001057600080fd5b5060405161129e38038061129e83398101604081905261002f9161004b565b33606090811b6080521b6001600160601b03191660a052610079565b60006020828403121561005c578081fd5b81516001600160a01b0381168114610072578182fd5b9392505050565b60805160601c60a05160601c6111ee6100b060003980610130528061020152806102bd5250806093528061024c52506111ee6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80634817a2861461003b5780637d10d11f14610064575b600080fd5b61004e610049366004610cd9565b610079565b60405161005b9190610eb3565b60405180910390f35b610077610072366004610c69565b610234565b005b60603373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea906110e5565b60405180910390fd5b6040517f945bcec900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063945bcec990610171908c908c908c908c908c908c908c90600401610f59565b600060405180830381600087803b15801561018b57600080fd5b505af115801561019f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526101e59190810190610bd9565b905061022873ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683336102e9565b98975050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146102a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea906110e5565b6102e573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016838333610551565b5050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61030e6040840160208501610bb6565b73ffffffffffffffffffffffffffffffffffffffff16141561035c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea9061111c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9826060013514156103d0576103cb6103986020840184610bb6565b82604085018035906103ad9060208801610bb6565b73ffffffffffffffffffffffffffffffffffffffff16929190610816565b61054c565b604080516001808252818301909252600091816020015b6103ef6109cb565b8152602001906001900390816103e757905050905060008160008151811061041357fe5b602002602001015190507fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea063284606001351461044f576002610452565b60035b8190600381111561045f57fe5b9081600381111561046c57fe5b90525061047f6040850160208601610bb6565b73ffffffffffffffffffffffffffffffffffffffff16602080830191909152604080860135908301526104b490850185610bb6565b73ffffffffffffffffffffffffffffffffffffffff908116606083015283811660808301526040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815290861690630e8e3e8490610517908590600401610ec6565b600060405180830381600087803b15801561053157600080fd5b505af1158015610545573d6000803e3d6000fd5b5050505050505b505050565b60008267ffffffffffffffff8111801561056a57600080fd5b506040519080825280602002602001820160405280156105a457816020015b6105916109cb565b8152602001906001900390816105895790505b5090506000805b8481101561077857368686838181106105c057fe5b60800291909101915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90506105f06040830160208401610bb6565b73ffffffffffffffffffffffffffffffffffffffff16141561063e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea9061111c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9816060013514156106945761068f61067a6020830183610bb6565b86604084018035906103ad9060208701610bb6565b61076f565b60008484806001019550815181106106a857fe5b602002602001015190507fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328260600135146106e45760016106e7565b60035b819060038111156106f457fe5b9081600381111561070157fe5b9052506107146040830160208401610bb6565b73ffffffffffffffffffffffffffffffffffffffff166020808301919091526040808401359083015261074990830183610bb6565b73ffffffffffffffffffffffffffffffffffffffff908116606083015286166080909101525b506001016105ab565b50801561080e5761078982826108fd565b6040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690630e8e3e84906107db908590600401610ec6565b600060405180830381600087803b1580156107f557600080fd5b505af1158015610809573d6000803e3d6000fd5b505050505b505050505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff8581166004840152841660248301526044820183905290600080606483828a5af1610881573d6000803e3d6000fd5b5061088b85610901565b6108f657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a206661696c6564207472616e7366657246726f6d00000000000000604482015290519081900360640190fd5b5050505050565b9052565b600061093f565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452806024528160445260646000fd5b3d801561097e57602081146109b8576109797f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f610908565b6109c5565b823b6109af576109af7f475076323a206e6f74206120636f6e74726163740000000000000000000000006014610908565b600191506109c5565b3d6000803e600051151591505b50919050565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b600082601f830112610a0b578081fd5b81356020610a20610a1b83611175565b611151565b8281528181019085830183850287018401881015610a3c578586fd5b855b85811015610a63578135610a5181611193565b84529284019290840190600101610a3e565b5090979650505050505050565b600082601f830112610a80578081fd5b81356020610a90610a1b83611175565b8281528181019085830183850287018401881015610aac578586fd5b855b85811015610a6357813584529284019290840190600101610aae565b60008083601f840112610adb578182fd5b50813567ffffffffffffffff811115610af2578182fd5b6020830191508360208083028501011115610b0c57600080fd5b9250929050565b80358015158114610b2357600080fd5b919050565b6000608082840312156109c5578081fd5b600060808284031215610b4a578081fd5b6040516080810181811067ffffffffffffffff82111715610b6757fe5b6040529050808235610b7881611193565b8152610b8660208401610b13565b60208201526040830135610b9981611193565b6040820152610baa60608401610b13565b60608201525092915050565b600060208284031215610bc7578081fd5b8135610bd281611193565b9392505050565b60006020808385031215610beb578182fd5b825167ffffffffffffffff811115610c01578283fd5b8301601f81018513610c11578283fd5b8051610c1f610a1b82611175565b8181528381019083850185840285018601891015610c3b578687fd5b8694505b83851015610c5d578051835260019490940193918501918501610c3f565b50979650505050505050565b60008060208385031215610c7b578081fd5b823567ffffffffffffffff80821115610c92578283fd5b818501915085601f830112610ca5578283fd5b813581811115610cb3578384fd5b866020608083028501011115610cc7578384fd5b60209290920196919550909350505050565b6000806000806000806000806101a0898b031215610cf5578384fd5b883560028110610d03578485fd5b9750602089013567ffffffffffffffff80821115610d1f578586fd5b610d2b8c838d01610aca565b909950975060408b0135915080821115610d43578586fd5b610d4f8c838d016109fb565b9650610d5e8c60608d01610b39565b955060e08b0135915080821115610d73578485fd5b50610d808b828c01610a70565b9350506101008901359150610d998a6101208b01610b28565b90509295985092959890939650565b6000815180845260208085019450808401835b83811015610ded57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610dbb565b509495945050505050565b6000815180845260208085019450808401835b83811015610ded57815187529582019590820190600101610e0b565b600082845282826020860137806020848601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011685010190509392505050565b73ffffffffffffffffffffffffffffffffffffffff808251168352602082015115156020840152806040830151166040840152506060810151151560608301525050565b600060208252610bd26020830184610df8565b602080825282518282018190526000919060409081850190868401855b82811015610f4c578151805160048110610ef957fe5b85528087015173ffffffffffffffffffffffffffffffffffffffff908116888701528682015187870152606080830151821690870152608091820151169085015260a09093019290850190600101610ee3565b5091979650505050505050565b600061012080830160028b10610f6b57fe5b8a8452602080850192909252889052610140808401918981028501909101908a845b8b811015611098577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec087850301855281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618e3603018112610fed578687fd5b8d01803585528381013584860152604080820135908601526060808201359086015260a0608080830135368490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe101811261104757898afd5b8301803567ffffffffffffffff81111561105f578a8bfd5b80360385131561106d578a8bfd5b83838a0152611081848a01828a8501610e27565b998801999850505093850193505050600101610f8d565b50505083810360408501526110ad8189610da8565b9150506110bd6060840187610e6f565b82810360e08401526110cf8186610df8565b9150508261010083015298975050505050505050565b60208082526011908201527f475076323a206e6f742063726561746f72000000000000000000000000000000604082015260600190565b6020808252818101527f475076323a2063616e6e6f74207472616e73666572206e617469766520455448604082015260600190565b60405181810167ffffffffffffffff8111828210171561116d57fe5b604052919050565b600067ffffffffffffffff82111561118957fe5b5060209081020190565b73ffffffffffffffffffffffffffffffffffffffff811681146111b557600080fd5b5056fea2646970667358221220364a6941bea69620b7dc3a957d0ab4cbf3bfc459c7ad3924d220620aca9202fc64736f6c63430007060033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01\0`@R4\x80\x15b\0\0\x12W`\0\x80\xFD[P`@Qb\0S\xEB8\x03\x80b\0S\xEB\x839\x81\x01`@\x81\x90Rb\0\x005\x91b\0\x01[V[`@\x80Q\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0F` \x80\x83\x01\x91\x90\x91R\x7Fl\x85\xC03~\xBA\x16a2\x7F\x94\xF3\xBFF\xC8\xA7\xF91\x1AV?M\\\x94\x83bV\x7F]\x8E\xD6\x0C\x82\x84\x01R\x7F\xF9Dk\x8E\x93}\x86\xF0\xBC\x87\xCA\xC79#I\x16\x92\xB1#\xCA_\x87a\x90\x84\x94p7X j\xDF``\x80\x84\x01\x91\x90\x91RF`\x80\x80\x85\x01\x91\x90\x91R0`\xA0\x80\x86\x01\x91\x90\x91R\x85Q\x80\x86\x03\x82\x01\x81R`\xC0\x95\x86\x01\x96\x87\x90R\x80Q\x94\x01\x93\x90\x93 \x90R`\x01\x80U`\x01`\x01``\x1B\x03\x19\x86\x82\x1B\x81\x16\x90\x92R\x84\x90\x1B\x16\x90R\x81\x90b\0\x01\n\x90b\0\x01MV[b\0\x01\x16\x91\x90b\0\x01\x99V[`@Q\x80\x91\x03\x90`\0\xF0\x80\x15\x80\x15b\0\x013W=`\0\x80>=`\0\xFD[P``\x1B`\x01`\x01``\x1B\x03\x19\x16`\xE0RPb\0\x01\xC6\x90PV[a\x12\x9E\x80b\0AM\x839\x01\x90V[`\0\x80`@\x83\x85\x03\x12\x15b\0\x01nW\x81\x82\xFD[\x82Qb\0\x01{\x81b\0\x01\xADV[` \x84\x01Q\x90\x92Pb\0\x01\x8E\x81b\0\x01\xADV[\x80\x91PP\x92P\x92\x90PV[`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x81R` \x01\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x01\xC3W`\0\x80\xFD[PV[`\x80Q`\xA0Q``\x1C`\xC0Q``\x1C`\xE0Q``\x1Ca?%b\0\x02(`\09\x80a\x04\xC5R\x80a\raR\x80a\x10\x90R\x80a\x15\xF0RP\x80a\x05VR\x80a\x15\x8BRP\x80a\x03\x92R\x80a\x06\xBCR\x80a\t\x9DRP\x80a\x13\x1ER\x80a#\xDFRPa?%`\0\xF3\xFE`\x80`@R`\x046\x10a\0\xECW`\x005`\xE0\x1C\x80c\x9BU,\xC2\x11a\0\x8AW\x80c\xED\x9F5\xCE\x11a\0YW\x80c\xED\x9F5\xCE\x14a\x02tW\x80c\xF6\x98\xDA%\x14a\x02\x94W\x80c\xF8D6\xBD\x14a\x02\xA9W\x80c\xFB\xFAw\xCF\x14a\x02\xC9Wa\0\xF3V[\x80c\x9BU,\xC2\x14a\x01\xFFW\x80c\xA2\xA7\xD5\x1B\x14a\x02\x14W\x80c\xD0\x8D3\xD1\x14a\x024W\x80c\xECl\xB1?\x14a\x02TWa\0\xF3V[\x80c$y\xFBn\x11a\0\xC6W\x80c$y\xFBn\x14a\x01eW\x80cC!\x8E\x19\x14a\x01\x92W\x80cV$\xB2[\x14a\x01\xBFW\x80c\x84Z\x10\x1F\x14a\x01\xDFWa\0\xF3V[\x80c\x13\xD7\x9A\x0B\x14a\0\xF8W\x80c\x153{\xC0\x14a\x01\x1AW\x80c#5\xC7k\x14a\x01:Wa\0\xF3V[6a\0\xF3W\0[`\0\x80\xFD[4\x80\x15a\x01\x04W`\0\x80\xFD[Pa\x01\x18a\x01\x136`\x04a2.V[a\x02\xDEV[\0[4\x80\x15a\x01&W`\0\x80\xFD[Pa\x01\x18a\x0156`\x04a4AV[a\x05\xC1V[4\x80\x15a\x01FW`\0\x80\xFD[Pa\x01Oa\x06\xBAV[`@Qa\x01\\\x91\x90a6\xEEV[`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x01qW`\0\x80\xFD[Pa\x01\x85a\x01\x806`\x04a4\xCAV[a\x06\xDEV[`@Qa\x01\\\x91\x90a7\xF0V[4\x80\x15a\x01\x9EW`\0\x80\xFD[Pa\x01\xB2a\x01\xAD6`\x04a1\xA0V[a\x06\xFBV[`@Qa\x01\\\x91\x90a8\rV[4\x80\x15a\x01\xCBW`\0\x80\xFD[Pa\x01\xB2a\x01\xDA6`\x04a4\xFDV[a\x08sV[4\x80\x15a\x01\xEBW`\0\x80\xFD[Pa\x01\x18a\x01\xFA6`\x04a3\x8EV[a\x08\xE9V[4\x80\x15a\x02\x0BW`\0\x80\xFD[Pa\x01Oa\x10\x8EV[4\x80\x15a\x02 W`\0\x80\xFD[Pa\x01\x18a\x02/6`\x04a1\xEEV[a\x10\xB2V[4\x80\x15a\x02@W`\0\x80\xFD[Pa\x01\x85a\x02O6`\x04a4\xCAV[a\x10\xFBV[4\x80\x15a\x02`W`\0\x80\xFD[Pa\x01\x18a\x02o6`\x04a4uV[a\x11\x18V[4\x80\x15a\x02\x80W`\0\x80\xFD[Pa\x01\x18a\x02\x8F6`\x04a1\xEEV[a\x12\xD7V[4\x80\x15a\x02\xA0W`\0\x80\xFD[Pa\x01\x85a\x13\x1CV[4\x80\x15a\x02\xB5W`\0\x80\xFD[Pa\x01\xB2a\x02\xC46`\x04a1\xA0V[a\x13@V[4\x80\x15a\x02\xD5W`\0\x80\xFD[Pa\x01Oa\x15\x89V[`\x02`\x01T\x14\x15a\x03PW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1F`$\x82\x01R\x7FReentrancyGuard: reentrant call\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\x02`\x01U`@Q\x7F\x02\xCC%\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90c\x02\xCC%\r\x90a\x03\xC7\x903\x90`\x04\x01a6\xEEV[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x03\xDFW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x03\xF3W=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x04\x17\x91\x90a4%V[a\x04VW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a=`\0\xFD[PPPPa\x05<\x83`\x01`\x03\x81\x10a\x04]W\xFE[a\x05|s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x82a\x18QV[a\x05\x87\x83`\x02a\x04]V[`@Q3\x90\x7F@3\x8C\xE1\xA7\xC4\x92\x04\xF0\t\x953\xB1\xE9\xA7\xEE\n=&\x1F\x84\x97J\xB7\xAF6\x10[\x8CN\x9D\xB4\x90`\0\x90\xA2PP`\x01\x80UPPPPPPPV[`\0a\x05\xCD\x83\x83a\x1B/V[P\x91PPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x163\x14a\x06 W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a:\x1BV[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`\x02\x84\x84`@Qa\x06S\x92\x91\x90a6\xC2V[\x90\x81R` \x01`@Q\x80\x91\x03\x90 \x81\x90UP\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x87[l\xB05\xBB\xD4\xACe\0\xFA\xBCm\x1EL\xA5\xBD\xC5\x8A>+BL\xCB\\$\xCD\xBE\xBE\xB0\t\xA9\x84\x84`@Qa\x06\xAD\x92\x91\x90a7\xF9V[`@Q\x80\x91\x03\x90\xA2PPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[\x80Q` \x81\x83\x01\x81\x01\x80Q`\x02\x82R\x92\x82\x01\x91\x90\x93\x01 \x91RT\x81V[```\0\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x07dW\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x07'V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81\x85Z\xF4\x91PP=\x80`\0\x81\x14a\x07\xC4W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x07\xC9V[``\x91P[P\x80\x93P\x81\x92PPPa\x08l\x82\x82`@Q` \x01\x80\x83\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x08'W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x07\xEAV[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x82\x15\x15`\xF8\x1B\x81R`\x01\x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@Ra\x1B\xBDV[P\x92\x91PPV[```\0\x82` \x02g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x08\x91W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80`\x1F\x01`\x1F\x19\x16` \x01\x82\x01`@R\x80\x15a\x08\xBCW` \x82\x01\x81\x806\x837\x01\x90P[P\x90P`\0[\x83\x81\x10\x15a\x08\xDFW\x84\x81\x01T` \x80\x83\x02\x84\x01\x01R`\x01\x01a\x08\xC2V[P\x90P[\x92\x91PPV[`\x02`\x01T\x14\x15a\t[W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1F`$\x82\x01R\x7FReentrancyGuard: reentrant call\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\x02`\x01U`@Q\x7F\x02\xCC%\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90c\x02\xCC%\r\x90a\t\xD2\x903\x90`\x04\x01a6\xEEV[` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\t\xEAW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\t\xFEW=`\0\x80>=`\0\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\n\"\x91\x90a4%V[a\nXW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x82a\x01\0\x01Q\x14a\n\xA8W`\x01a\n\xABV[`\0[\x90Pa\n\xB5a/\x90V[`@\x80\x85\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x83Ra\x01@\x85\x01Q\x7FJ\xC9\x9A\xCE\x14\xEE\n^\xF92\xDC`\x9D\xF0\x94:\xB7\xAC\x16\xB7X64a/\x8D\xC3ZB\x89\xA6\xCE\x90\x81\x14` \x85\x01R``\x80\x88\x01Q\x90\x92\x16\x92\x84\x01\x92\x90\x92Ra\x01`\x85\x01Q\x90\x91\x14\x90\x82\x01R`\0\x86g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x0B:W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x0BdW\x81` \x01` \x82\x02\x806\x837\x01\x90P[Pa\x01\0\x85\x01Q\x90\x91Pa\x01 \x87\x015\x90\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x14\x15a\x0C0W\x84`\x80\x01Q\x81\x10\x15a\x0B\xDAW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a=`\0\xFD[PPPP`@Q=`\0\x82>`\x1F=\x90\x81\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x82\x01`@Ra\x0E@\x91\x90\x81\x01\x90a2\xEDV[\x90P`\0\x88` \x01Q\x90P`\0a\x0Em\x83\x8C`\0\x015\x81Q\x81\x10a\x0E`W\xFE[` \x02` \x01\x01Qa\x1D%V[\x90P`\0a\x0E\x94\x84\x8D` \x015\x81Q\x81\x10a\x0E\x84W\xFE[` \x02` \x01\x01Q`\0\x03a\x1D%V[\x90P`\x02\x83`@Qa\x0E\xA6\x91\x90a6\xD2V[\x90\x81R` \x01`@Q\x80\x91\x03\x90 T`\0\x14a\x0E\xEEW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a;\xD3V[\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x8Aa\x01\0\x01Q\x14\x15a\x0F\x82W\x89``\x01Q\x82\x14a\x0FXW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a:\xC0V[\x89``\x01Q`\x02\x84`@Qa\x0Fm\x91\x90a6\xD2V[\x90\x81R`@Q\x90\x81\x90\x03` \x01\x90 Ua\x0F\xE5V[\x89`\x80\x01Q\x81\x14a\x0F\xBFW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a:\xF7V[\x89`\x80\x01Q`\x02\x84`@Qa\x0F\xD4\x91\x90a6\xD2V[\x90\x81R`@Q\x90\x81\x90\x03` \x01\x90 U[\x8A`@\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA0zT:\xB8\xA0\x18\x19\x8E\x99\xCA\x01\x84\xC9?\xE9\x05\ny@\n\nr4A\xF8M\xE1\xD9r\xCC\x17\x8B`\0\x01Q\x8C` \x01Q\x85\x85\x8F`\xE0\x01Q\x89`@Qa\x10E\x96\x95\x94\x93\x92\x91\x90a8 V[`@Q\x80\x91\x03\x90\xA2`@Q3\x90\x7F@3\x8C\xE1\xA7\xC4\x92\x04\xF0\t\x953\xB1\xE9\xA7\xEE\n=&\x1F\x84\x97J\xB7\xAF6\x10[\x8CN\x9D\xB4\x90`\0\x90\xA2PP`\x01\x80UPPPPPPPPPPPPPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[03\x14a\x10\xEBW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a;eV[a\x10\xF7`\0\x83\x83a\x1D\x96V[PPV[\x80Q` \x81\x83\x01\x81\x01\x80Q`\0\x82R\x92\x82\x01\x91\x90\x93\x01 \x91RT\x81V[`\0a\x11$\x84\x84a\x1B/V[P\x91PPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x163\x14a\x11\xACW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7FGPv2: cannot presign order\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x81\x15a\x12\x06W\x7F\xF5\x9C\0\x92\x83\xFF\x87\xAAx ?\xC4\xD9\xC2\xDF\x02^\xE8Q\x13\x0F\xB6\x9C\xC3\xE0h\x94\x1Fk^-o`\0\x1C`\0\x85\x85`@Q\x80\x83\x83\x80\x82\x847\x80\x83\x01\x92PPP\x92PPP\x90\x81R` \x01`@Q\x80\x91\x03\x90 \x81\x90UPa\x122V[`\0\x80\x85\x85`@Q\x80\x83\x83\x80\x82\x847\x91\x90\x91\x01\x94\x85RPP`@Q\x92\x83\x90\x03` \x01\x90\x92 \x92\x90\x92UPP[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x01\xBF|\x8B\x0C\xA5]\xEE\xCB\xEA\x89\xD7\xE5\x82\x95\xB7\xFF\xBFh_\xD0\xD9h\x01\x03K\xA8\xC6\xFF\xE1\xC6\x8D\x85\x85\x85`@Q\x80\x80` \x01\x83\x15\x15\x81R` \x01\x82\x81\x03\x82R\x85\x85\x82\x81\x81R` \x01\x92P\x80\x82\x847`\0\x83\x82\x01R`@Q`\x1F\x90\x91\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x90\x92\x01\x82\x90\x03\x96P\x90\x94PPPPP\xA2PPPPV[03\x14a\x13\x10W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a;eV[a\x10\xF7`\x02\x83\x83a\x1D\x96V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[```\0cC!\x8E\x19`\xE0\x1B\x84\x84`@Q`$\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x13\xAAW\x81\x81\x01Q\x83\x82\x01R` \x01a\x13\x92V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x13\xD7W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x81R` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x98\x16\x97\x90\x97\x17\x87RQ\x81Q\x91\x97P0\x96\x88\x96P\x90\x94P\x84\x93P\x91P\x80\x83\x83[` \x83\x10a\x14\xA8W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x14kV[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a\x15\nW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a\x15\x0FV[``\x91P[P\x90P\x80\x92PP`\0\x82`\x01\x84Q\x03\x81Q\x81\x10a\x15(W\xFE[` \x01\x01Q`\xF8\x1C`\xF8\x1B~\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x19\x16`\x01`\xF8\x1B\x14\x90Pa\x15k\x83`\x01\x85Q\x03a\x1EFV[\x80\x15a\x15xWPPa\x08\xE3V[a\x15\x81\x83a\x1B\xBDV[PP\x92\x91PPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`\0[\x81\x81\x10\x15a\x16\xE5W6\x83\x83\x83\x81\x81\x10a\x15\xC5W\xFE[\x90P` \x02\x81\x01\x90a\x15\xD7\x91\x90a=\xDEV[\x90Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16a\x16\x1D` \x83\x01\x83a1\x84V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x16kW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a<\xAFV[a\x16t\x81a\x1EJV[a\x16\x81` \x82\x01\x82a1\x84V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xED\x99\x82~\xFB7\x01o\"u\xF9\x8CK\xCFq\xC7U\x1Cu\xD5\x9E\x9BE\x0Fy\xFA2\xE6\x0B\xE6r\xC2\x82` \x015a\x16\xC6\x84a\x1E\xA1V[`@Qa\x16\xD4\x92\x91\x90a<\xE6V[`@Q\x80\x91\x03\x90\xA2P`\x01\x01a\x15\xB0V[PPPV[``\x80`\0a\x16\xF7a\x1B\xC5V[\x90P\x83g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x17\x10W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x17JW\x81` \x01[a\x177a/\x90V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x17/W\x90P[P\x92P\x83g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x17dW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x17\x9EW\x81` \x01[a\x17\x8Ba/\x90V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x17\x83W\x90P[P\x91P`\0[\x84\x81\x10\x15a\x18DW6\x86\x86\x83\x81\x81\x10a\x17\xB9W\xFE[\x90P` \x02\x81\x01\x90a\x17\xCB\x91\x90a>\x11V[\x90Pa\x17\xD9\x83\x8C\x8C\x84a\x1B\xF2V[a\x18;\x83\x8A\x8A\x845\x81\x81\x10a\x17\xEAW\xFE[\x90P` \x02\x015\x8B\x8B\x85` \x015\x81\x81\x10a\x18\x01W\xFE[\x90P` \x02\x015\x84a\x01 \x015\x89\x87\x81Q\x81\x10a\x18\x1AW\xFE[` \x02` \x01\x01Q\x89\x88\x81Q\x81\x10a\x18.W\xFE[` \x02` \x01\x01Qa\x1E\xCBV[P`\x01\x01a\x17\xA4V[PP\x96P\x96\x94PPPPPV[`\0\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x18kW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x18\xA5W\x81` \x01[a\x18\x92a/\xB7V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x18\x8AW\x90P[P\x90P`\0\x80[\x83Q\x81\x10\x15a\x1A\x93W`\0\x84\x82\x81Q\x81\x10a\x18\xC3W\xFE[` \x02` \x01\x01Q\x90Ps\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEEs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x19\xC7W\x7FJ\xC9\x9A\xCE\x14\xEE\n^\xF92\xDC`\x9D\xF0\x94:\xB7\xAC\x16\xB7X64a/\x8D\xC3ZB\x89\xA6\xCE\x81``\x01Q\x14\x15a\x19wW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a;.V[\x80Q`@\x80\x83\x01Q\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x91\x81\x15a\x08\xFC\x02\x91\x90`\0\x81\x81\x81\x85\x88\x88\xF1\x93PPPP\x15\x80\x15a\x19\xC1W=`\0\x80>=`\0\xFD[Pa\x1A\x8AV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81``\x01Q\x14\x15a\x1A&W\x80Q`@\x82\x01Q` \x83\x01Qa\x1A!\x92s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x91a\"\x16V[a\x1A\x8AV[`\0\x84\x84\x80`\x01\x01\x95P\x81Q\x81\x10a\x1A:W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`\0\x81R\x83\x82\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x92\x82\x01\x92\x90\x92R`@\x80\x85\x01Q\x90\x82\x01R0``\x82\x01R\x83Q\x90\x91\x16`\x80\x90\x91\x01RP[P`\x01\x01a\x18\xACV[P\x80\x15a\x1B)Wa\x1A\xA4\x82\x82a\x1EFV[`@Q\x7F\x0E\x8E>\x84\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x90c\x0E\x8E>\x84\x90a\x1A\xF6\x90\x85\x90`\x04\x01a7]V[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x1B\x10W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x1B$W=`\0\x80>=`\0\xFD[PPPP[PPPPV[`\0\x80\x80`8\x84\x14a\x1B\xA2W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7FGPv2: invalid uid\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[PP\x825\x93` \x84\x015``\x1C\x93`4\x015`\xE0\x1C\x92P\x90PV[\x80Q` \x82\x01\xFD[a\x1B\xCDa/\xE7V[`@\x80Q`8\x80\x82R``\x82\x01\x90\x92R\x90` \x82\x01\x81\x806\x837PPP` \x82\x01R\x90V[\x83Q`\0a\x1C\x02\x83\x86\x86\x85a\"\xEEV[\x90P`\0\x80a\x1C\x1F\x84\x84a\x1C\x1Aa\x01@\x89\x01\x89a={V[a#\xD6V[\x91P\x91Pa\x1CB\x82\x82\x86`\xA0\x01Q\x8B` \x01Qa$\x85\x90\x93\x92\x91\x90c\xFF\xFF\xFF\xFF\x16V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16`@\x89\x01Ra\x1Ch\x84\x82a%\x07V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16``\x90\x98\x01\x97\x90\x97RPPPPPPPV[`\0\x7F\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x1D!W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FSafeCast: int256 overflow\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[P\x90V[`\0\x80\x82\x12\x15a\x1D!W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7FSafeCast: not positive\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0[\x81\x81\x10\x15a\x1B)W6`\0\x84\x84\x84\x81\x81\x10a\x1D\xB0W\xFE[\x90P` \x02\x81\x01\x90a\x1D\xC2\x91\x90a={V[\x91P\x91P`\0a\x1D\xD2\x83\x83a\x1B/V[\x92PPPB\x81c\xFF\xFF\xFF\xFF\x16\x10a\x1E\x15W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a<\nV[`\0\x87\x84\x84`@Qa\x1E(\x92\x91\x90a6\xC2V[\x90\x81R`@Q\x90\x81\x90\x03` \x01\x90 UPP`\x01\x90\x91\x01\x90Pa\x1D\x99V[\x90RV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16` \x82\x0156`\0a\x1Ew`@\x86\x01\x86a={V[\x91P\x91P`@Q\x81\x83\x827`\0\x80\x83\x83\x87\x89Z\xF1a\x1E\x99W=`\0\x80>=`\0\xFD[PPPPPPV[`\x006\x81a\x1E\xB2`@\x85\x01\x85a={V[\x90\x92P\x90P`\x04\x81\x10a\x1E\xC4W\x815\x92P[PP\x91\x90PV[\x85Q` \x87\x01Q`\xA0\x82\x01QBc\xFF\xFF\xFF\xFF\x90\x91\x16\x10\x15a\x1F\x18W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a:RV[`\x80\x82\x01Qa\x1F'\x90\x87a%9V[``\x83\x01Qa\x1F6\x90\x89a%9V[\x10\x15a\x1FnW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a:\x89V[`\0\x80`\0\x80\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x86a\x01\0\x01Q\x14\x15a oW\x85a\x01 \x01Q\x15a\x1F\xDBW\x88\x93Pa\x1F\xD4\x86``\x01Qa\x1F\xCE\x86\x89`\xE0\x01Qa%9\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x90a%\xC9V[\x91Pa\x1F\xEAV[\x85``\x01Q\x93P\x85`\xE0\x01Q\x91P[a\x1F\xFE\x8Aa\x1F\xF8\x86\x8Ea%9V[\x90a&JV[\x92Pa *\x84`\x02\x87`@Qa \x14\x91\x90a6\xD2V[\x90\x81R`@Q\x90\x81\x90\x03` \x01\x90 T\x90a&\xE8V[\x90P\x85``\x01Q\x81\x11\x15a jW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a;\xD3V[a!\x16V[\x85a\x01 \x01Q\x15a \xA3W\x88\x92Pa \x9C\x86`\x80\x01Qa\x1F\xCE\x85\x89`\xE0\x01Qa%9\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x91Pa \xB2V[\x85`\x80\x01Q\x92P\x85`\xE0\x01Q\x91P[a \xC0\x8Ba\x1F\xCE\x85\x8Da%9V[\x93Pa \xD6\x83`\x02\x87`@Qa \x14\x91\x90a6\xD2V[\x90P\x85`\x80\x01Q\x81\x11\x15a!\x16W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x04M\x90a;\xD3V[a! \x84\x83a&\xE8V[\x93P\x80`\x02\x86`@Qa!3\x91\x90a6\xD2V[\x90\x81R` \x01`@Q\x80\x91\x03\x90 \x81\x90UP\x8B`@\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA0zT:\xB8\xA0\x18\x19\x8E\x99\xCA\x01\x84\xC9?\xE9\x05\ny@\n\nr4A\xF8M\xE1\xD9r\xCC\x17\x87`\0\x01Q\x88` \x01Q\x87\x87\x87\x8B`@Qa!\xA1\x96\x95\x94\x93\x92\x91\x90a8 V[`@Q\x80\x91\x03\x90\xA2PP`@\x80\x8B\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x88R\x85Q\x81\x16` \x80\x8A\x01\x91\x90\x91R\x88\x83\x01\x94\x90\x94Ra\x01@\x86\x01Q``\x98\x89\x01R\x9A\x87\x01Q\x8B\x16\x86R\x82\x85\x01Q\x90\x9A\x16\x91\x85\x01\x91\x90\x91R\x97\x83\x01\x97\x90\x97Ra\x01`\x01Q\x91\x01RPPPPV[`@Q\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x82Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16`\x04\x83\x01R`$\x82\x01\x83\x90R\x90`\0\x80`D\x83\x82\x89Z\xF1a\"yW=`\0\x80>=`\0\xFD[Pa\"\x83\x84a'\\V[a\x1B)W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FGPv2: failed transfer\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0\x83\x83\x865\x81\x81\x10a\"\xFDW\xFE[` \x90\x81\x02\x92\x90\x92\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84RP\x84\x90\x84\x90\x87\x015\x81\x81\x10a#0W\xFE[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF` \x91\x82\x02\x93\x90\x93\x015\x83\x16\x90\x85\x01RP`@\x80\x87\x015\x90\x91\x16\x90\x83\x01R``\x80\x86\x015\x90\x83\x01R`\x80\x80\x86\x015\x90\x83\x01Rc\xFF\xFF\xFF\xFF`\xA0\x80\x87\x015\x91\x90\x91\x16\x90\x83\x01R`\xC0\x80\x86\x015\x90\x83\x01R`\xE0\x80\x86\x015\x90\x83\x01Ra#\xACa\x01\0\x86\x015a(&V[a\x01`\x87\x01\x91\x90\x91Ra\x01@\x86\x01\x91\x90\x91R\x90\x15\x15a\x01 \x85\x01Ra\x01\0\x90\x93\x01RP\x93\x92PPPV[`\0\x80a$\x03\x86\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a){V[\x91P`\0\x85`\x03\x81\x11\x15a$\x13W\xFE[\x14\x15a$+Wa$$\x82\x85\x85a*\x05V[\x90Pa$|V[`\x01\x85`\x03\x81\x11\x15a$9W\xFE[\x14\x15a$JWa$$\x82\x85\x85a*\x1AV[`\x02\x85`\x03\x81\x11\x15a$XW\xFE[\x14\x15a$iWa$$\x82\x85\x85a*\x82V[a$y\x82\x85\x85\x89`\xA0\x01Qa, V[\x90P[\x94P\x94\x92PPPV[`8\x84Q\x14a$\xF5W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FGPv2: uid buffer overflow\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`8\x84\x01R`4\x83\x01R` \x90\x91\x01RV[`@\x82\x01Q`\0\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a%0WP\x80a\x08\xE3V[PP`@\x01Q\x90V[`\0\x82a%HWP`\0a\x08\xE3V[\x82\x82\x02\x82\x84\x82\x81a%UW\xFE[\x04\x14a%\xC2W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7FSafeMath: mul overflow\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x93\x92PPPV[`\0\x80\x82\x11a&9W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FSafeMath: division by 0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x81\x83\x81a&BW\xFE[\x04\x93\x92PPPV[`\0\x80\x82\x11a&\xBAW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1F`$\x82\x01R\x7FSafeMath: ceiling division by 0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x81\x83\x81a&\xC3W\xFE[\x06\x15a&\xD0W`\x01a&\xD3V[`\0[`\xFF\x16\x82\x84\x81a&\xDFW\xFE[\x04\x01\x93\x92PPPV[`\0\x82\x82\x01\x83\x81\x10\x15a%\xC2W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FSafeMath: addition overflow\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0a'\x9AV[\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R` `\x04R\x80`$R\x81`DR`d`\0\xFD[=\x80\x15a'\xD9W` \x81\x14a(\x13Wa'\xD4\x7FGPv2: malformed transfer result\0`\x1Fa'cV[a( V[\x82;a(\nWa(\n\x7FGPv2: not a contract\0\0\0\0\0\0\0\0\0\0\0\0`\x14a'cV[`\x01\x91Pa( V[=`\0\x80>`\0Q\x15\x15\x91P[P\x91\x90PV[`\0\x80\x80\x80\x80`\x01\x86\x16a(\\W\x7F\xF3\xB2wr\x8B?\xEEt\x94\x81\xEB>\x0B;H\x98\r\xBB\xABxe\x8F\xC4\x19\x02\\\xB1n\xEE4gu\x94Pa(\x80V[\x7Fn\xD8\x8E\x86\x8A\xF0\xA1\x98>8\x86\xD5\xF3\xE9Z/\xAF\xBDl4P\xBC\"\x9E'4\"\x83\xDCB\x9C\xCC\x94P[`\x02\x86\x16\x15\x15\x93P`\x08\x86\x16a(\xB8W\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x92Pa)\x0CV[`\x04\x86\x16a(\xE8W\x7F\xAB\xEE;s7:\xCDX:\x13\t$\xAA\xD6\xDC8\xCF\xDCD\xBA\x05U\xBA\x94\xCE/\xF69\x80\xEA\x062\x92Pa)\x0CV[\x7FJ\xC9\x9A\xCE\x14\xEE\n^\xF92\xDC`\x9D\xF0\x94:\xB7\xAC\x16\xB7X64a/\x8D\xC3ZB\x89\xA6\xCE\x92P[`\x10\x86\x16a)hV[`@\x80Q\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x82R`\x04\x82\x01\x8B\x81R`$\x83\x01\x93\x84R`D\x83\x01\x85\x90R\x94\x96P\x92\x94P\x91\x92s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x16\x92c\x16&\xBA~\x92\x8B\x92\x88\x92\x88\x92\x90`d\x01\x84\x84\x80\x82\x847`\0\x83\x82\x01R`@Q`\x1F\x90\x91\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x90\x92\x01\x96P` \x95P\x90\x93PPP\x81\x84\x03\x90P\x81\x86\x80;\x15\x80\x15a+]W`\0\x80\xFD[PZ\xFA\x15\x80\x15a+qW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a+\x87W`\0\x80\xFD[PQ\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a,\x17W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1F`$\x82\x01R\x7FGPv2: invalid eip1271 signature\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[PP\x93\x92PPPV[`\0`\x14\x83\x14a,\x91W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FGPv2: malformed presignature\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[P`@\x80Q`8\x80\x82R``\x82\x81\x01\x90\x93R\x855\x90\x92\x1C\x91`\0\x91\x90` \x82\x01\x81\x806\x837\x01\x90PP\x90Pa,\xC8\x81\x87\x84\x86a$\x85V[\x7F\xF5\x9C\0\x92\x83\xFF\x87\xAAx ?\xC4\xD9\xC2\xDF\x02^\xE8Q\x13\x0F\xB6\x9C\xC3\xE0h\x94\x1Fk^-o`\0\x1C`\0\x82`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a-=`\0\xFD[PP`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01Q\x94PPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16a/\x86W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FGPv2: invalid ecdsa signature\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[PPP\x93\x92PPPV[`@\x80Q`\x80\x81\x01\x82R`\0\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x91\x90\x91R\x90V[`@\x80Q`\xA0\x81\x01\x90\x91R\x80`\0\x81R`\0` \x82\x01\x81\x90R`@\x82\x01\x81\x90R``\x82\x01\x81\x90R`\x80\x90\x91\x01R\x90V[`@Q\x80`\x80\x01`@R\x80a/\xFAa0\x14V[\x81R``` \x82\x01\x81\x90R`\0`@\x83\x01\x81\x90R\x91\x01R\x90V[`@\x80Qa\x01\x80\x81\x01\x82R`\0\x80\x82R` \x82\x01\x81\x90R\x91\x81\x01\x82\x90R``\x81\x01\x82\x90R`\x80\x81\x01\x82\x90R`\xA0\x81\x01\x82\x90R`\xC0\x81\x01\x82\x90R`\xE0\x81\x01\x82\x90Ra\x01\0\x81\x01\x82\x90Ra\x01 \x81\x01\x82\x90Ra\x01@\x81\x01\x82\x90Ra\x01`\x81\x01\x91\x90\x91R\x90V[`\0\x80\x83`\x1F\x84\x01\x12a0\x89W\x81\x82\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a0\xA0W\x81\x82\xFD[` \x83\x01\x91P\x83` \x80\x83\x02\x85\x01\x01\x11\x15a0\xBAW`\0\x80\xFD[\x92P\x92\x90PV[`\0\x80\x83`\x1F\x84\x01\x12a0\xD2W\x81\x82\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a0\xE9W\x81\x82\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a0\xBAW`\0\x80\xFD[`\0\x82`\x1F\x83\x01\x12a1\x11W\x80\x81\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a1%W\xFE[a1V` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a>DV[\x81\x81R\x84` \x83\x86\x01\x01\x11\x15a1jW\x82\x83\xFD[\x81` \x85\x01` \x83\x017\x90\x81\x01` \x01\x91\x90\x91R\x92\x91PPV[`\0` \x82\x84\x03\x12\x15a1\x95W\x80\x81\xFD[\x815a%\xC2\x81a>\xBCV[`\0\x80`@\x83\x85\x03\x12\x15a1\xB2W\x80\x81\xFD[\x825a1\xBD\x81a>\xBCV[\x91P` \x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a1\xD8W\x81\x82\xFD[a1\xE4\x85\x82\x86\x01a1\x01V[\x91PP\x92P\x92\x90PV[`\0\x80` \x83\x85\x03\x12\x15a2\0W\x81\x82\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a2\x16W\x82\x83\xFD[a2\"\x85\x82\x86\x01a0xV[\x90\x96\x90\x95P\x93PPPPV[`\0\x80`\0\x80`\0\x80`\0`\x80\x88\x8A\x03\x12\x15a2HW\x82\x83\xFD[\x875g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a2_W\x84\x85\xFD[a2k\x8B\x83\x8C\x01a0xV[\x90\x99P\x97P` \x8A\x015\x91P\x80\x82\x11\x15a2\x83W\x84\x85\xFD[a2\x8F\x8B\x83\x8C\x01a0xV[\x90\x97P\x95P`@\x8A\x015\x91P\x80\x82\x11\x15a2\xA7W\x84\x85\xFD[a2\xB3\x8B\x83\x8C\x01a0xV[\x90\x95P\x93P``\x8A\x015\x91P\x80\x82\x11\x15a2\xCBW\x82\x83\xFD[P\x88\x01``\x81\x01\x8A\x10\x15a2\xDDW\x81\x82\xFD[\x80\x91PP\x92\x95\x98\x91\x94\x97P\x92\x95PV[`\0` \x80\x83\x85\x03\x12\x15a2\xFFW\x81\x82\xFD[\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a3\x16W\x83\x84\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a3)W\x83\x84\xFD[\x81Q\x81\x81\x11\x15a35W\xFE[\x83\x81\x02\x91Pa3E\x84\x83\x01a>DV[\x81\x81R\x84\x81\x01\x90\x84\x86\x01\x84\x86\x01\x87\x01\x8A\x10\x15a3_W\x87\x88\xFD[\x87\x95P[\x83\x86\x10\x15a3\x81W\x80Q\x83R`\x01\x95\x90\x95\x01\x94\x91\x86\x01\x91\x86\x01a3cV[P\x98\x97PPPPPPPPV[`\0\x80`\0\x80`\0``\x86\x88\x03\x12\x15a3\xA5W\x80\x81\xFD[\x855g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a3\xBCW\x82\x83\xFD[a3\xC8\x89\x83\x8A\x01a0xV[\x90\x97P\x95P` \x88\x015\x91P\x80\x82\x11\x15a3\xE0W\x82\x83\xFD[a3\xEC\x89\x83\x8A\x01a0xV[\x90\x95P\x93P`@\x88\x015\x91P\x80\x82\x11\x15a4\x04W\x82\x83\xFD[P\x86\x01a\x01`\x81\x89\x03\x12\x15a4\x17W\x81\x82\xFD[\x80\x91PP\x92\x95P\x92\x95\x90\x93PV[`\0` \x82\x84\x03\x12\x15a46W\x80\x81\xFD[\x81Qa%\xC2\x81a>\xE1V[`\0\x80` \x83\x85\x03\x12\x15a4SW\x81\x82\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a4iW\x82\x83\xFD[a2\"\x85\x82\x86\x01a0\xC1V[`\0\x80`\0`@\x84\x86\x03\x12\x15a4\x89W\x80\x81\xFD[\x835g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a4\x9FW\x81\x82\xFD[a4\xAB\x86\x82\x87\x01a0\xC1V[\x90\x94P\x92PP` \x84\x015a4\xBF\x81a>\xE1V[\x80\x91PP\x92P\x92P\x92V[`\0` \x82\x84\x03\x12\x15a4\xDBW\x80\x81\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a4\xF1W\x81\x82\xFD[a*\x12\x84\x82\x85\x01a1\x01V[`\0\x80`@\x83\x85\x03\x12\x15a5\x0FW\x81\x82\xFD[PP\x805\x92` \x90\x91\x015\x91PV[`\0\x82\x84R` \x80\x85\x01\x94P\x82\x82[\x85\x81\x10\x15a5hW\x815a5@\x81a>\xBCV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01a5-V[P\x94\x95\x94PPPPPV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15a5hW\x81Q\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01a5\x86V[`\0\x82\x84R\x82\x82` \x86\x017\x80` \x84\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x85\x01\x16\x85\x01\x01\x90P\x93\x92PPPV[`\0\x81Q\x80\x84Ra6\x02\x81` \x86\x01` \x86\x01a>\x90V[`\x1F\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x92\x90\x92\x01` \x01\x92\x91PPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82Q\x16\x83R\x80` \x83\x01Q\x16` \x84\x01RP`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82Q\x16\x83R` \x82\x01Q\x15\x15` \x84\x01R\x80`@\x83\x01Q\x16`@\x84\x01RP``\x81\x01Q\x15\x15``\x83\x01RPPV[c\xFF\xFF\xFF\xFF\x16\x90RV[`\0\x82\x84\x837\x91\x01\x90\x81R\x91\x90PV[`\0\x82Qa6\xE4\x81\x84` \x87\x01a>\x90V[\x91\x90\x91\x01\x92\x91PPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x90\x91\x16\x81R` \x01\x90V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a7QWa7>\x83\x85Qa64V[\x92\x84\x01\x92`\x80\x92\x90\x92\x01\x91`\x01\x01a7+V[P\x90\x96\x95PPPPPPV[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a7\xE3W\x81Q\x80Q`\x04\x81\x10a7\x90W\xFE[\x85R\x80\x87\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x88\x87\x01R\x86\x82\x01Q\x87\x87\x01R``\x80\x83\x01Q\x82\x16\x90\x87\x01R`\x80\x91\x82\x01Q\x16\x90\x85\x01R`\xA0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a7zV[P\x91\x97\x96PPPPPPPV[\x90\x81R` \x01\x90V[`\0` \x82Ra*\x12` \x83\x01\x84\x86a5\xA2V[`\0` \x82Ra%\xC2` \x83\x01\x84a5\xEAV[`\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x89\x16\x83R\x80\x88\x16` \x84\x01RP\x85`@\x83\x01R\x84``\x83\x01R\x83`\x80\x83\x01R`\xC0`\xA0\x83\x01Ra8k`\xC0\x83\x01\x84a5\xEAV[\x98\x97PPPPPPPPV[`\0a\x01\xA0\x82\x01`\x02\x8C\x10a8\x88W\xFE[\x8B\x83R` a\x01\xA0\x81\x85\x01R\x81\x8B\x83Ra\x01\xC0\x85\x01\x90Pa\x01\xC0\x82\x8D\x02\x86\x01\x01\x92P\x8C\x84[\x8D\x81\x10\x15a9\xB6W\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE@\x87\x86\x03\x01\x83R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFa\x8F6\x03\x01\x825\x12a9\x0CW\x85\x86\xFD[\x8E\x825\x01\x805\x86R\x84\x81\x015\x85\x87\x01R`@\x81\x015`@\x87\x01R``\x81\x015``\x87\x01R`\x80\x81\x015\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x826\x03\x01\x81\x12a9dW\x87\x88\xFD[\x81\x01\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a9|W\x88\x89\xFD[\x806\x03\x83\x13\x15a9\x8AW\x88\x89\xFD[`\xA0`\x80\x89\x01Ra9\xA1`\xA0\x89\x01\x82\x89\x85\x01a5\xA2V[\x97PPP\x92\x84\x01\x92P\x90\x83\x01\x90`\x01\x01a8\xADV[PPPP\x82\x81\x03`@\x84\x01Ra9\xCD\x81\x89\x8Ba5\x1EV[\x90Pa9\xDC``\x84\x01\x88a6tV[\x82\x81\x03`\xE0\x84\x01Ra9\xEE\x81\x87a5sV[\x91PPa9\xFFa\x01\0\x83\x01\x85a6\xB8V[a:\ra\x01 \x83\x01\x84a64V[\x9A\x99PPPPPPPPPPV[` \x80\x82R`\x1F\x90\x82\x01R\x7FGPv2: caller does not own order\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x13\x90\x82\x01R\x7FGPv2: order expired\0\0\0\0\0\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x1F\x90\x82\x01R\x7FGPv2: limit price not respected\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x1F\x90\x82\x01R\x7FGPv2: sell amount not respected\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x1E\x90\x82\x01R\x7FGPv2: buy amount not respected\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x1E\x90\x82\x01R\x7FGPv2: unsupported internal ETH\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x18\x90\x82\x01R\x7FGPv2: not an interaction\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x14\x90\x82\x01R\x7FGPv2: limit too high\0\0\0\0\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x12\x90\x82\x01R\x7FGPv2: order filled\0\0\0\0\0\0\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x17\x90\x82\x01R\x7FGPv2: order still valid\0\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x13\x90\x82\x01R\x7FGPv2: limit too low\0\0\0\0\0\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x12\x90\x82\x01R\x7FGPv2: not a solver\0\0\0\0\0\0\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R`\x1B\x90\x82\x01R\x7FGPv2: forbidden interaction\0\0\0\0\0`@\x82\x01R``\x01\x90V[\x91\x82R\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16` \x82\x01R`@\x01\x90V[`\0\x80\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a=JW\x82\x83\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a=dW\x82\x83\xFD[` \x90\x81\x01\x92P\x81\x026\x03\x82\x13\x15a0\xBAW`\0\x80\xFD[`\0\x80\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a=\xAFW\x82\x83\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a=\xC9W\x82\x83\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a0\xBAW`\0\x80\xFD[`\0\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xA1\x836\x03\x01\x81\x12a6\xE4W\x81\x82\xFD[`\0\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xA1\x836\x03\x01\x81\x12a6\xE4W\x81\x82\xFD[`@Q\x81\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a>`W\xFE[`@R\x91\x90PV[`\0\x80\x85\x85\x11\x15a>wW\x81\x82\xFD[\x83\x86\x11\x15a>\x83W\x81\x82\xFD[PP\x82\x01\x93\x91\x90\x92\x03\x91PV[`\0[\x83\x81\x10\x15a>\xABW\x81\x81\x01Q\x83\x82\x01R` \x01a>\x93V[\x83\x81\x11\x15a\x1B)WPP`\0\x91\x01RV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a>\xDEW`\0\x80\xFD[PV[\x80\x15\x15\x81\x14a>\xDEW`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \xDE^I=`\0\xFD[PPPP`@Q=`\0\x82>`\x1F=\x90\x81\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x82\x01`@Ra\x01\xE5\x91\x90\x81\x01\x90a\x0B\xD9V[\x90Pa\x02(s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x833a\x02\xE9V[\x98\x97PPPPPPPPV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x02\xA3W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\0\xEA\x90a\x10\xE5V[a\x02\xE5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x83\x833a\x05QV[PPV[s\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEEa\x03\x0E`@\x84\x01` \x85\x01a\x0B\xB6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x03\\W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\0\xEA\x90a\x11\x1CV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x82``\x015\x14\x15a\x03\xD0Wa\x03\xCBa\x03\x98` \x84\x01\x84a\x0B\xB6V[\x82`@\x85\x01\x805\x90a\x03\xAD\x90` \x88\x01a\x0B\xB6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x92\x91\x90a\x08\x16V[a\x05LV[`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R`\0\x91\x81` \x01[a\x03\xEFa\t\xCBV[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x03\xE7W\x90PP\x90P`\0\x81`\0\x81Q\x81\x10a\x04\x13W\xFE[` \x02` \x01\x01Q\x90P\x7F\xAB\xEE;s7:\xCDX:\x13\t$\xAA\xD6\xDC8\xCF\xDCD\xBA\x05U\xBA\x94\xCE/\xF69\x80\xEA\x062\x84``\x015\x14a\x04OW`\x02a\x04RV[`\x03[\x81\x90`\x03\x81\x11\x15a\x04_W\xFE[\x90\x81`\x03\x81\x11\x15a\x04lW\xFE[\x90RPa\x04\x7F`@\x85\x01` \x86\x01a\x0B\xB6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16` \x80\x83\x01\x91\x90\x91R`@\x80\x86\x015\x90\x83\x01Ra\x04\xB4\x90\x85\x01\x85a\x0B\xB6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16``\x83\x01R\x83\x81\x16`\x80\x83\x01R`@Q\x7F\x0E\x8E>\x84\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R\x90\x86\x16\x90c\x0E\x8E>\x84\x90a\x05\x17\x90\x85\x90`\x04\x01a\x0E\xC6V[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x051W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x05EW=`\0\x80>=`\0\xFD[PPPPPP[PPPV[`\0\x82g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a\x05jW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x05\xA4W\x81` \x01[a\x05\x91a\t\xCBV[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x05\x89W\x90P[P\x90P`\0\x80[\x84\x81\x10\x15a\x07xW6\x86\x86\x83\x81\x81\x10a\x05\xC0W\xFE[`\x80\x02\x91\x90\x91\x01\x91Ps\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\x90Pa\x05\xF0`@\x83\x01` \x84\x01a\x0B\xB6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x06>W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\0\xEA\x90a\x11\x1CV[\x7FZ(\xE96;\xB9B\xB69'\0b\xAAk\xB2\x95\xF44\xBC\xDF\xC4,\x97&{\xF0\x03\xF2r\x06\r\xC9\x81``\x015\x14\x15a\x06\x94Wa\x06\x8Fa\x06z` \x83\x01\x83a\x0B\xB6V[\x86`@\x84\x01\x805\x90a\x03\xAD\x90` \x87\x01a\x0B\xB6V[a\x07oV[`\0\x84\x84\x80`\x01\x01\x95P\x81Q\x81\x10a\x06\xA8W\xFE[` \x02` \x01\x01Q\x90P\x7F\xAB\xEE;s7:\xCDX:\x13\t$\xAA\xD6\xDC8\xCF\xDCD\xBA\x05U\xBA\x94\xCE/\xF69\x80\xEA\x062\x82``\x015\x14a\x06\xE4W`\x01a\x06\xE7V[`\x03[\x81\x90`\x03\x81\x11\x15a\x06\xF4W\xFE[\x90\x81`\x03\x81\x11\x15a\x07\x01W\xFE[\x90RPa\x07\x14`@\x83\x01` \x84\x01a\x0B\xB6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16` \x80\x83\x01\x91\x90\x91R`@\x80\x84\x015\x90\x83\x01Ra\x07I\x90\x83\x01\x83a\x0B\xB6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16``\x83\x01R\x86\x16`\x80\x90\x91\x01R[P`\x01\x01a\x05\xABV[P\x80\x15a\x08\x0EWa\x07\x89\x82\x82a\x08\xFDV[`@Q\x7F\x0E\x8E>\x84\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x16\x90c\x0E\x8E>\x84\x90a\x07\xDB\x90\x85\x90`\x04\x01a\x0E\xC6V[`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x07\xF5W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x08\tW=`\0\x80>=`\0\xFD[PPPP[PPPPPPV[`@Q\x7F#\xB8r\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x82Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`\x04\x84\x01R\x84\x16`$\x83\x01R`D\x82\x01\x83\x90R\x90`\0\x80`d\x83\x82\x8AZ\xF1a\x08\x81W=`\0\x80>=`\0\xFD[Pa\x08\x8B\x85a\t\x01V[a\x08\xF6W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7FGPv2: failed transferFrom\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[PPPPPV[\x90RV[`\0a\t?V[\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\0R` `\x04R\x80`$R\x81`DR`d`\0\xFD[=\x80\x15a\t~W` \x81\x14a\t\xB8Wa\ty\x7FGPv2: malformed transfer result\0`\x1Fa\t\x08V[a\t\xC5V[\x82;a\t\xAFWa\t\xAF\x7FGPv2: not a contract\0\0\0\0\0\0\0\0\0\0\0\0`\x14a\t\x08V[`\x01\x91Pa\t\xC5V[=`\0\x80>`\0Q\x15\x15\x91P[P\x91\x90PV[`@\x80Q`\xA0\x81\x01\x90\x91R\x80`\0\x81R`\0` \x82\x01\x81\x90R`@\x82\x01\x81\x90R``\x82\x01\x81\x90R`\x80\x90\x91\x01R\x90V[`\0\x82`\x1F\x83\x01\x12a\n\x0BW\x80\x81\xFD[\x815` a\n a\n\x1B\x83a\x11uV[a\x11QV[\x82\x81R\x81\x81\x01\x90\x85\x83\x01\x83\x85\x02\x87\x01\x84\x01\x88\x10\x15a\nV[P\x90\x97\x96PPPPPPPV[`\0\x82`\x1F\x83\x01\x12a\n\x80W\x80\x81\xFD[\x815` a\n\x90a\n\x1B\x83a\x11uV[\x82\x81R\x81\x81\x01\x90\x85\x83\x01\x83\x85\x02\x87\x01\x84\x01\x88\x10\x15a\n\xACW\x85\x86\xFD[\x85[\x85\x81\x10\x15a\ncW\x815\x84R\x92\x84\x01\x92\x90\x84\x01\x90`\x01\x01a\n\xAEV[`\0\x80\x83`\x1F\x84\x01\x12a\n\xDBW\x81\x82\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\xF2W\x81\x82\xFD[` \x83\x01\x91P\x83` \x80\x83\x02\x85\x01\x01\x11\x15a\x0B\x0CW`\0\x80\xFD[\x92P\x92\x90PV[\x805\x80\x15\x15\x81\x14a\x0B#W`\0\x80\xFD[\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\t\xC5W\x80\x81\xFD[`\0`\x80\x82\x84\x03\x12\x15a\x0BJW\x80\x81\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x0BgW\xFE[`@R\x90P\x80\x825a\x0Bx\x81a\x11\x93V[\x81Ra\x0B\x86` \x84\x01a\x0B\x13V[` \x82\x01R`@\x83\x015a\x0B\x99\x81a\x11\x93V[`@\x82\x01Ra\x0B\xAA``\x84\x01a\x0B\x13V[``\x82\x01RP\x92\x91PPV[`\0` \x82\x84\x03\x12\x15a\x0B\xC7W\x80\x81\xFD[\x815a\x0B\xD2\x81a\x11\x93V[\x93\x92PPPV[`\0` \x80\x83\x85\x03\x12\x15a\x0B\xEBW\x81\x82\xFD[\x82Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x0C\x01W\x82\x83\xFD[\x83\x01`\x1F\x81\x01\x85\x13a\x0C\x11W\x82\x83\xFD[\x80Qa\x0C\x1Fa\n\x1B\x82a\x11uV[\x81\x81R\x83\x81\x01\x90\x83\x85\x01\x85\x84\x02\x85\x01\x86\x01\x89\x10\x15a\x0C;W\x86\x87\xFD[\x86\x94P[\x83\x85\x10\x15a\x0C]W\x80Q\x83R`\x01\x94\x90\x94\x01\x93\x91\x85\x01\x91\x85\x01a\x0C?V[P\x97\x96PPPPPPPV[`\0\x80` \x83\x85\x03\x12\x15a\x0C{W\x80\x81\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x0C\x92W\x82\x83\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x0C\xA5W\x82\x83\xFD[\x815\x81\x81\x11\x15a\x0C\xB3W\x83\x84\xFD[\x86` `\x80\x83\x02\x85\x01\x01\x11\x15a\x0C\xC7W\x83\x84\xFD[` \x92\x90\x92\x01\x96\x91\x95P\x90\x93PPPPV[`\0\x80`\0\x80`\0\x80`\0\x80a\x01\xA0\x89\x8B\x03\x12\x15a\x0C\xF5W\x83\x84\xFD[\x885`\x02\x81\x10a\r\x03W\x84\x85\xFD[\x97P` \x89\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\r\x1FW\x85\x86\xFD[a\r+\x8C\x83\x8D\x01a\n\xCAV[\x90\x99P\x97P`@\x8B\x015\x91P\x80\x82\x11\x15a\rCW\x85\x86\xFD[a\rO\x8C\x83\x8D\x01a\t\xFBV[\x96Pa\r^\x8C``\x8D\x01a\x0B9V[\x95P`\xE0\x8B\x015\x91P\x80\x82\x11\x15a\rsW\x84\x85\xFD[Pa\r\x80\x8B\x82\x8C\x01a\npV[\x93PPa\x01\0\x89\x015\x91Pa\r\x99\x8Aa\x01 \x8B\x01a\x0B(V[\x90P\x92\x95\x98P\x92\x95\x98\x90\x93\x96PV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15a\r\xEDW\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01a\r\xBBV[P\x94\x95\x94PPPPPV[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P\x80\x84\x01\x83[\x83\x81\x10\x15a\r\xEDW\x81Q\x87R\x95\x82\x01\x95\x90\x82\x01\x90`\x01\x01a\x0E\x0BV[`\0\x82\x84R\x82\x82` \x86\x017\x80` \x84\x86\x01\x01R` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x85\x01\x16\x85\x01\x01\x90P\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82Q\x16\x83R` \x82\x01Q\x15\x15` \x84\x01R\x80`@\x83\x01Q\x16`@\x84\x01RP``\x81\x01Q\x15\x15``\x83\x01RPPV[`\0` \x82Ra\x0B\xD2` \x83\x01\x84a\r\xF8V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a\x0FLW\x81Q\x80Q`\x04\x81\x10a\x0E\xF9W\xFE[\x85R\x80\x87\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x81\x16\x88\x87\x01R\x86\x82\x01Q\x87\x87\x01R``\x80\x83\x01Q\x82\x16\x90\x87\x01R`\x80\x91\x82\x01Q\x16\x90\x85\x01R`\xA0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a\x0E\xE3V[P\x91\x97\x96PPPPPPPV[`\0a\x01 \x80\x83\x01`\x02\x8B\x10a\x0FkW\xFE[\x8A\x84R` \x80\x85\x01\x92\x90\x92R\x88\x90Ra\x01@\x80\x84\x01\x91\x89\x81\x02\x85\x01\x90\x91\x01\x90\x8A\x84[\x8B\x81\x10\x15a\x10\x98W\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xC0\x87\x85\x03\x01\x85R\x815\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFa\x8E6\x03\x01\x81\x12a\x0F\xEDW\x86\x87\xFD[\x8D\x01\x805\x85R\x83\x81\x015\x84\x86\x01R`@\x80\x82\x015\x90\x86\x01R``\x80\x82\x015\x90\x86\x01R`\xA0`\x80\x80\x83\x0156\x84\x90\x03\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x01\x81\x12a\x10GW\x89\x8A\xFD[\x83\x01\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x10_W\x8A\x8B\xFD[\x806\x03\x85\x13\x15a\x10mW\x8A\x8B\xFD[\x83\x83\x8A\x01Ra\x10\x81\x84\x8A\x01\x82\x8A\x85\x01a\x0E'V[\x99\x88\x01\x99\x98PPP\x93\x85\x01\x93PPP`\x01\x01a\x0F\x8DV[PPP\x83\x81\x03`@\x85\x01Ra\x10\xAD\x81\x89a\r\xA8V[\x91PPa\x10\xBD``\x84\x01\x87a\x0EoV[\x82\x81\x03`\xE0\x84\x01Ra\x10\xCF\x81\x86a\r\xF8V[\x91PP\x82a\x01\0\x83\x01R\x98\x97PPPPPPPPV[` \x80\x82R`\x11\x90\x82\x01R\x7FGPv2: not creator\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`@\x82\x01R``\x01\x90V[` \x80\x82R\x81\x81\x01R\x7FGPv2: cannot transfer native ETH`@\x82\x01R``\x01\x90V[`@Q\x81\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x11mW\xFE[`@R\x91\x90PV[`\0g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x11\x89W\xFE[P` \x90\x81\x02\x01\x90V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x11\xB5W`\0\x80\xFD[PV\xFE\xA2dipfsX\"\x12 6JiA\xBE\xA6\x96 \xB7\xDC:\x95}\n\xB4\xCB\xF3\xBF\xC4Y\xC7\xAD9$\xD2 b\n\xCA\x92\x02\xFCdsolcC\0\x07\x06\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Interaction(address,uint256,bytes4)` and selector `0xed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c2`. + ```solidity + event Interaction(address indexed target, uint256 value, bytes4 selector); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Interaction { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub selector: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Interaction { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<4>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Interaction(address,uint256,bytes4)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 237u8, 153u8, 130u8, 126u8, 251u8, 55u8, 1u8, 111u8, 34u8, 117u8, 249u8, 140u8, + 75u8, 207u8, 113u8, 199u8, 85u8, 28u8, 117u8, 213u8, 158u8, 155u8, 69u8, 15u8, + 121u8, 250u8, 50u8, 230u8, 11u8, 230u8, 114u8, 194u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + target: topics.1, + value: data.0, + selector: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.selector), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.target.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.target, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Interaction { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Interaction> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Interaction) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OrderInvalidated(address,bytes)` and selector `0x875b6cb035bbd4ac6500fabc6d1e4ca5bdc58a3e2b424ccb5c24cdbebeb009a9`. + ```solidity + event OrderInvalidated(address indexed owner, bytes orderUid); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderInvalidated { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderInvalidated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderInvalidated(address,bytes)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 135u8, 91u8, 108u8, 176u8, 53u8, 187u8, 212u8, 172u8, 101u8, 0u8, 250u8, 188u8, + 109u8, 30u8, 76u8, 165u8, 189u8, 197u8, 138u8, 62u8, 43u8, 66u8, 76u8, 203u8, + 92u8, 36u8, 205u8, 190u8, 190u8, 176u8, 9u8, 169u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + orderUid: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.orderUid, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.owner.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderInvalidated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderInvalidated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderInvalidated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PreSignature(address,bytes,bool)` and selector `0x01bf7c8b0ca55deecbea89d7e58295b7ffbf685fd0d96801034ba8c6ffe1c68d`. + ```solidity + event PreSignature(address indexed owner, bytes orderUid, bool signed); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PreSignature { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub signed: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PreSignature { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Bool, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PreSignature(address,bytes,bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 1u8, 191u8, 124u8, 139u8, 12u8, 165u8, 93u8, 238u8, 203u8, 234u8, 137u8, 215u8, + 229u8, 130u8, 149u8, 183u8, 255u8, 191u8, 104u8, 95u8, 208u8, 217u8, 104u8, + 1u8, 3u8, 75u8, 168u8, 198u8, 255u8, 225u8, 198u8, 141u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + orderUid: data.0, + signed: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.orderUid, + ), + ::tokenize( + &self.signed, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.owner.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PreSignature { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PreSignature> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PreSignature) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Settlement(address)` and selector `0x40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db4`. + ```solidity + event Settlement(address indexed solver); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Settlement { + #[allow(missing_docs)] + pub solver: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Settlement { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Settlement(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 64u8, 51u8, 140u8, 225u8, 167u8, 196u8, 146u8, 4u8, 240u8, 9u8, 149u8, 51u8, + 177u8, 233u8, 167u8, 238u8, 10u8, 61u8, 38u8, 31u8, 132u8, 151u8, 74u8, 183u8, + 175u8, 54u8, 16u8, 91u8, 140u8, 78u8, 157u8, 180u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { solver: topics.1 } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.solver.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.solver, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Settlement { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Settlement> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Settlement) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Trade(address,address,address,uint256,uint256,uint256,bytes)` and selector `0xa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc17`. + ```solidity + event Trade(address indexed owner, address sellToken, address buyToken, uint256 sellAmount, uint256 buyAmount, uint256 feeAmount, bytes orderUid); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Trade { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub buyToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub buyAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub feeAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Trade { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "Trade(address,address,address,uint256,uint256,uint256,bytes)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 160u8, 122u8, 84u8, 58u8, 184u8, 160u8, 24u8, 25u8, 142u8, 153u8, 202u8, 1u8, + 132u8, 201u8, 63u8, 233u8, 5u8, 10u8, 121u8, 64u8, 10u8, 10u8, 114u8, 52u8, + 65u8, 248u8, 77u8, 225u8, 217u8, 114u8, 204u8, 23u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + sellToken: data.0, + buyToken: data.1, + sellAmount: data.2, + buyAmount: data.3, + feeAmount: data.4, + orderUid: data.5, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.sellToken, + ), + ::tokenize( + &self.buyToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sellAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.buyAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeAmount, + ), + ::tokenize( + &self.orderUid, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.owner.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Trade { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Trade> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Trade) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address authenticator_, address vault_); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub authenticator_: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub vault_: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.authenticator_, value.vault_) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + authenticator_: tuple.0, + vault_: tuple.1, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.authenticator_, + ), + ::tokenize( + &self.vault_, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `authenticator()` and selector `0x2335c76b`. + ```solidity + function authenticator() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct authenticatorCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`authenticator()`](authenticatorCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct authenticatorReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: authenticatorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for authenticatorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: authenticatorReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for authenticatorReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for authenticatorCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 53u8, 199u8, 107u8]; + const SIGNATURE: &'static str = "authenticator()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: authenticatorReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: authenticatorReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `domainSeparator()` and selector `0xf698da25`. + ```solidity + function domainSeparator() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct domainSeparatorCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`domainSeparator()`](domainSeparatorCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct domainSeparatorReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: domainSeparatorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for domainSeparatorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: domainSeparatorReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for domainSeparatorReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for domainSeparatorCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [246u8, 152u8, 218u8, 37u8]; + const SIGNATURE: &'static str = "domainSeparator()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: domainSeparatorReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: domainSeparatorReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `filledAmount(bytes)` and selector `0x2479fb6e`. + ```solidity + function filledAmount(bytes memory) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct filledAmountCall(pub alloy_sol_types::private::Bytes); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`filledAmount(bytes)`](filledAmountCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct filledAmountReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Bytes,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: filledAmountCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for filledAmountCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: filledAmountReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for filledAmountReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for filledAmountCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Bytes,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [36u8, 121u8, 251u8, 110u8]; + const SIGNATURE: &'static str = "filledAmount(bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: filledAmountReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: filledAmountReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `invalidateOrder(bytes)` and selector `0x15337bc0`. + ```solidity + function invalidateOrder(bytes memory orderUid) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct invalidateOrderCall { + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`invalidateOrder(bytes)`](invalidateOrderCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct invalidateOrderReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Bytes,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: invalidateOrderCall) -> Self { + (value.orderUid,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for invalidateOrderCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { orderUid: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: invalidateOrderReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for invalidateOrderReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl invalidateOrderReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for invalidateOrderCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Bytes,); + type Return = invalidateOrderReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [21u8, 51u8, 123u8, 192u8]; + const SIGNATURE: &'static str = "invalidateOrder(bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.orderUid, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + invalidateOrderReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `setPreSignature(bytes,bool)` and selector `0xec6cb13f`. + ```solidity + function setPreSignature(bytes memory orderUid, bool signed) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setPreSignatureCall { + #[allow(missing_docs)] + pub orderUid: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub signed: bool, + } + ///Container type for the return parameters of the + /// [`setPreSignature(bytes,bool)`](setPreSignatureCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct setPreSignatureReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Bytes, bool); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setPreSignatureCall) -> Self { + (value.orderUid, value.signed) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setPreSignatureCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + orderUid: tuple.0, + signed: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: setPreSignatureReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for setPreSignatureReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl setPreSignatureReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for setPreSignatureCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Bool, + ); + type Return = setPreSignatureReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [236u8, 108u8, 177u8, 63u8]; + const SIGNATURE: &'static str = "setPreSignature(bytes,bool)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.orderUid, + ), + ::tokenize( + &self.signed, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + setPreSignatureReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `settle(address[],uint256[],(uint256,uint256,address,uint256,uint256,uint32,bytes32,uint256,uint256,uint256,bytes)[],(address,uint256,bytes)[][3])` and selector `0x13d79a0b`. + ```solidity + function settle(address[] memory tokens, uint256[] memory clearingPrices, GPv2Trade.Data[] memory trades, GPv2Interaction.Data[][3] memory interactions) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settleCall { + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub clearingPrices: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub trades: + alloy_sol_types::private::Vec<::RustType>, + #[allow(missing_docs)] + pub interactions: [alloy_sol_types::private::Vec< + ::RustType, + >; 3usize], + } + ///Container type for the return parameters of the + /// [`settle(address[],uint256[],(uint256,uint256,address,uint256,uint256, + /// uint32,bytes32,uint256,uint256,uint256,bytes)[],(address,uint256, + /// bytes)[][3])`](settleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settleReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::FixedArray< + alloy_sol_types::sol_data::Array, + 3usize, + >, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec< + ::RustType, + >, + [alloy_sol_types::private::Vec< + ::RustType, + >; 3usize], + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settleCall) -> Self { + ( + value.tokens, + value.clearingPrices, + value.trades, + value.interactions, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokens: tuple.0, + clearingPrices: tuple.1, + trades: tuple.2, + interactions: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settleReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl settleReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for settleCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::FixedArray< + alloy_sol_types::sol_data::Array, + 3usize, + >, + ); + type Return = settleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [19u8, 215u8, 154u8, 11u8]; + const SIGNATURE: &'static str = "settle(address[],uint256[],(uint256,uint256,address,\ + uint256,uint256,uint32,bytes32,uint256,uint256,\ + uint256,bytes)[],(address,uint256,bytes)[][3])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.tokens), + , + > as alloy_sol_types::SolType>::tokenize(&self.clearingPrices), + as alloy_sol_types::SolType>::tokenize(&self.trades), + , + 3usize, + > as alloy_sol_types::SolType>::tokenize(&self.interactions), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + settleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `simulateDelegatecall(address,bytes)` and selector `0xf84436bd`. + ```solidity + function simulateDelegatecall(address targetContract, bytes memory calldataPayload) external returns (bytes memory response); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateDelegatecallCall { + #[allow(missing_docs)] + pub targetContract: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub calldataPayload: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`simulateDelegatecall(address,bytes)`](simulateDelegatecallCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct simulateDelegatecallReturn { + #[allow(missing_docs)] + pub response: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateDelegatecallCall) -> Self { + (value.targetContract, value.calldataPayload) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateDelegatecallCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + targetContract: tuple.0, + calldataPayload: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Bytes,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: simulateDelegatecallReturn) -> Self { + (value.response,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for simulateDelegatecallReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { response: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for simulateDelegatecallCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::Bytes; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bytes,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [248u8, 68u8, 54u8, 189u8]; + const SIGNATURE: &'static str = "simulateDelegatecall(address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.targetContract, + ), + ::tokenize( + &self.calldataPayload, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: simulateDelegatecallReturn = r.into(); + r.response + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: simulateDelegatecallReturn = r.into(); + r.response + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swap((bytes32,uint256,uint256,uint256,bytes)[],address[],(uint256,uint256,address,uint256,uint256,uint32,bytes32,uint256,uint256,uint256,bytes))` and selector `0x845a101f`. + ```solidity + function swap(IVault.BatchSwapStep[] memory swaps, address[] memory tokens, GPv2Trade.Data memory trade) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapCall { + #[allow(missing_docs)] + pub swaps: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub trade: ::RustType, + } + ///Container type for the return parameters of the + /// [`swap((bytes32,uint256,uint256,uint256,bytes)[],address[],(uint256, + /// uint256,address,uint256,uint256,uint32,bytes32,uint256,uint256,uint256, + /// bytes))`](swapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + GPv2Trade::Data, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec< + ::RustType, + >, + alloy_sol_types::private::Vec, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapCall) -> Self { + (value.swaps, value.tokens, value.trade) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + swaps: tuple.0, + tokens: tuple.1, + trade: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl swapReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + GPv2Trade::Data, + ); + type Return = swapReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [132u8, 90u8, 16u8, 31u8]; + const SIGNATURE: &'static str = "swap((bytes32,uint256,uint256,uint256,bytes)[],\ + address[],(uint256,uint256,address,uint256,uint256,\ + uint32,bytes32,uint256,uint256,uint256,bytes))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.swaps), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + ::tokenize(&self.trade), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + swapReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `vault()` and selector `0xfbfa77cf`. + ```solidity + function vault() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct vaultCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`vault()`](vaultCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct vaultReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: vaultCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for vaultCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: vaultReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for vaultReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for vaultCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [251u8, 250u8, 119u8, 207u8]; + const SIGNATURE: &'static str = "vault()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: vaultReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: vaultReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `vaultRelayer()` and selector `0x9b552cc2`. + ```solidity + function vaultRelayer() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct vaultRelayerCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`vaultRelayer()`](vaultRelayerCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct vaultRelayerReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: vaultRelayerCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for vaultRelayerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: vaultRelayerReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for vaultRelayerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for vaultRelayerCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [155u8, 85u8, 44u8, 194u8]; + const SIGNATURE: &'static str = "vaultRelayer()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: vaultRelayerReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: vaultRelayerReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`GPv2Settlement`](self) function calls. + #[derive(Clone)] + pub enum GPv2SettlementCalls { + #[allow(missing_docs)] + authenticator(authenticatorCall), + #[allow(missing_docs)] + domainSeparator(domainSeparatorCall), + #[allow(missing_docs)] + filledAmount(filledAmountCall), + #[allow(missing_docs)] + invalidateOrder(invalidateOrderCall), + #[allow(missing_docs)] + setPreSignature(setPreSignatureCall), + #[allow(missing_docs)] + settle(settleCall), + #[allow(missing_docs)] + simulateDelegatecall(simulateDelegatecallCall), + #[allow(missing_docs)] + swap(swapCall), + #[allow(missing_docs)] + vault(vaultCall), + #[allow(missing_docs)] + vaultRelayer(vaultRelayerCall), + } + impl GPv2SettlementCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [19u8, 215u8, 154u8, 11u8], + [21u8, 51u8, 123u8, 192u8], + [35u8, 53u8, 199u8, 107u8], + [36u8, 121u8, 251u8, 110u8], + [132u8, 90u8, 16u8, 31u8], + [155u8, 85u8, 44u8, 194u8], + [236u8, 108u8, 177u8, 63u8], + [246u8, 152u8, 218u8, 37u8], + [248u8, 68u8, 54u8, 189u8], + [251u8, 250u8, 119u8, 207u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(settle), + ::core::stringify!(invalidateOrder), + ::core::stringify!(authenticator), + ::core::stringify!(filledAmount), + ::core::stringify!(swap), + ::core::stringify!(vaultRelayer), + ::core::stringify!(setPreSignature), + ::core::stringify!(domainSeparator), + ::core::stringify!(simulateDelegatecall), + ::core::stringify!(vault), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for GPv2SettlementCalls { + const COUNT: usize = 10usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "GPv2SettlementCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::authenticator(_) => ::SELECTOR, + Self::domainSeparator(_) => { + ::SELECTOR + } + Self::filledAmount(_) => ::SELECTOR, + Self::invalidateOrder(_) => { + ::SELECTOR + } + Self::setPreSignature(_) => { + ::SELECTOR + } + Self::settle(_) => ::SELECTOR, + Self::simulateDelegatecall(_) => { + ::SELECTOR + } + Self::swap(_) => ::SELECTOR, + Self::vault(_) => ::SELECTOR, + Self::vaultRelayer(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn settle(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::settle) + } + settle + }, + { + fn invalidateOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::invalidateOrder) + } + invalidateOrder + }, + { + fn authenticator(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::authenticator) + } + authenticator + }, + { + fn filledAmount(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::filledAmount) + } + filledAmount + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::swap) + } + swap + }, + { + fn vaultRelayer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::vaultRelayer) + } + vaultRelayer + }, + { + fn setPreSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::setPreSignature) + } + setPreSignature + }, + { + fn domainSeparator( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::domainSeparator) + } + domainSeparator + }, + { + fn simulateDelegatecall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::simulateDelegatecall) + } + simulateDelegatecall + }, + { + fn vault(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(GPv2SettlementCalls::vault) + } + vault + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn settle(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GPv2SettlementCalls::settle) + } + settle + }, + { + fn invalidateOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2SettlementCalls::invalidateOrder) + } + invalidateOrder + }, + { + fn authenticator(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2SettlementCalls::authenticator) + } + authenticator + }, + { + fn filledAmount(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2SettlementCalls::filledAmount) + } + filledAmount + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GPv2SettlementCalls::swap) + } + swap + }, + { + fn vaultRelayer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2SettlementCalls::vaultRelayer) + } + vaultRelayer + }, + { + fn setPreSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2SettlementCalls::setPreSignature) + } + setPreSignature + }, + { + fn domainSeparator( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2SettlementCalls::domainSeparator) + } + domainSeparator + }, + { + fn simulateDelegatecall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(GPv2SettlementCalls::simulateDelegatecall) + } + simulateDelegatecall + }, + { + fn vault(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(GPv2SettlementCalls::vault) + } + vault + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::authenticator(inner) => { + ::abi_encoded_size(inner) + } + Self::domainSeparator(inner) => { + ::abi_encoded_size(inner) + } + Self::filledAmount(inner) => { + ::abi_encoded_size(inner) + } + Self::invalidateOrder(inner) => { + ::abi_encoded_size(inner) + } + Self::setPreSignature(inner) => { + ::abi_encoded_size(inner) + } + Self::settle(inner) => { + ::abi_encoded_size(inner) + } + Self::simulateDelegatecall(inner) => { + ::abi_encoded_size(inner) + } + Self::swap(inner) => { + ::abi_encoded_size(inner) + } + Self::vault(inner) => { + ::abi_encoded_size(inner) + } + Self::vaultRelayer(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::authenticator(inner) => { + ::abi_encode_raw(inner, out) + } + Self::domainSeparator(inner) => { + ::abi_encode_raw(inner, out) + } + Self::filledAmount(inner) => { + ::abi_encode_raw(inner, out) + } + Self::invalidateOrder(inner) => { + ::abi_encode_raw(inner, out) + } + Self::setPreSignature(inner) => { + ::abi_encode_raw(inner, out) + } + Self::settle(inner) => { + ::abi_encode_raw(inner, out) + } + Self::simulateDelegatecall(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::swap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::vault(inner) => { + ::abi_encode_raw(inner, out) + } + Self::vaultRelayer(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`GPv2Settlement`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum GPv2SettlementEvents { + #[allow(missing_docs)] + Interaction(Interaction), + #[allow(missing_docs)] + OrderInvalidated(OrderInvalidated), + #[allow(missing_docs)] + PreSignature(PreSignature), + #[allow(missing_docs)] + Settlement(Settlement), + #[allow(missing_docs)] + Trade(Trade), + } + impl GPv2SettlementEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 1u8, 191u8, 124u8, 139u8, 12u8, 165u8, 93u8, 238u8, 203u8, 234u8, 137u8, 215u8, + 229u8, 130u8, 149u8, 183u8, 255u8, 191u8, 104u8, 95u8, 208u8, 217u8, 104u8, 1u8, + 3u8, 75u8, 168u8, 198u8, 255u8, 225u8, 198u8, 141u8, + ], + [ + 64u8, 51u8, 140u8, 225u8, 167u8, 196u8, 146u8, 4u8, 240u8, 9u8, 149u8, 51u8, 177u8, + 233u8, 167u8, 238u8, 10u8, 61u8, 38u8, 31u8, 132u8, 151u8, 74u8, 183u8, 175u8, + 54u8, 16u8, 91u8, 140u8, 78u8, 157u8, 180u8, + ], + [ + 135u8, 91u8, 108u8, 176u8, 53u8, 187u8, 212u8, 172u8, 101u8, 0u8, 250u8, 188u8, + 109u8, 30u8, 76u8, 165u8, 189u8, 197u8, 138u8, 62u8, 43u8, 66u8, 76u8, 203u8, 92u8, + 36u8, 205u8, 190u8, 190u8, 176u8, 9u8, 169u8, + ], + [ + 160u8, 122u8, 84u8, 58u8, 184u8, 160u8, 24u8, 25u8, 142u8, 153u8, 202u8, 1u8, + 132u8, 201u8, 63u8, 233u8, 5u8, 10u8, 121u8, 64u8, 10u8, 10u8, 114u8, 52u8, 65u8, + 248u8, 77u8, 225u8, 217u8, 114u8, 204u8, 23u8, + ], + [ + 237u8, 153u8, 130u8, 126u8, 251u8, 55u8, 1u8, 111u8, 34u8, 117u8, 249u8, 140u8, + 75u8, 207u8, 113u8, 199u8, 85u8, 28u8, 117u8, 213u8, 158u8, 155u8, 69u8, 15u8, + 121u8, 250u8, 50u8, 230u8, 11u8, 230u8, 114u8, 194u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(PreSignature), + ::core::stringify!(Settlement), + ::core::stringify!(OrderInvalidated), + ::core::stringify!(Trade), + ::core::stringify!(Interaction), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for GPv2SettlementEvents { + const COUNT: usize = 5usize; + const NAME: &'static str = "GPv2SettlementEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Interaction) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OrderInvalidated) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PreSignature) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Settlement) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Trade) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for GPv2SettlementEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Interaction(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OrderInvalidated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PreSignature(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Settlement(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Trade(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Interaction(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OrderInvalidated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PreSignature(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Settlement(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Trade(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Settlement`](self) contract instance. + + See the [wrapper's documentation](`GPv2SettlementInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2SettlementInstance { + GPv2SettlementInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + vault_: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + GPv2SettlementInstance::::deploy(__provider, authenticator_, vault_) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + vault_: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + GPv2SettlementInstance::::deploy_builder(__provider, authenticator_, vault_) + } + /**A [`GPv2Settlement`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Settlement`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2SettlementInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2SettlementInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2SettlementInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2SettlementInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Settlement`](self) contract instance. + + See the [wrapper's documentation](`GPv2SettlementInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + vault_: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, authenticator_, vault_); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + vault_: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + authenticator_, + vault_, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2SettlementInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2SettlementInstance { + GPv2SettlementInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2SettlementInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`authenticator`] function. + pub fn authenticator(&self) -> alloy_contract::SolCallBuilder<&P, authenticatorCall, N> { + self.call_builder(&authenticatorCall) + } + + ///Creates a new call builder for the [`domainSeparator`] function. + pub fn domainSeparator( + &self, + ) -> alloy_contract::SolCallBuilder<&P, domainSeparatorCall, N> { + self.call_builder(&domainSeparatorCall) + } + + ///Creates a new call builder for the [`filledAmount`] function. + pub fn filledAmount( + &self, + _0: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, filledAmountCall, N> { + self.call_builder(&filledAmountCall(_0)) + } + + ///Creates a new call builder for the [`invalidateOrder`] function. + pub fn invalidateOrder( + &self, + orderUid: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, invalidateOrderCall, N> { + self.call_builder(&invalidateOrderCall { orderUid }) + } + + ///Creates a new call builder for the [`setPreSignature`] function. + pub fn setPreSignature( + &self, + orderUid: alloy_sol_types::private::Bytes, + signed: bool, + ) -> alloy_contract::SolCallBuilder<&P, setPreSignatureCall, N> { + self.call_builder(&setPreSignatureCall { orderUid, signed }) + } + + ///Creates a new call builder for the [`settle`] function. + pub fn settle( + &self, + tokens: alloy_sol_types::private::Vec, + clearingPrices: alloy_sol_types::private::Vec< + alloy_sol_types::private::primitives::aliases::U256, + >, + trades: alloy_sol_types::private::Vec< + ::RustType, + >, + interactions: [alloy_sol_types::private::Vec< + ::RustType, + >; 3usize], + ) -> alloy_contract::SolCallBuilder<&P, settleCall, N> { + self.call_builder(&settleCall { + tokens, + clearingPrices, + trades, + interactions, + }) + } + + ///Creates a new call builder for the [`simulateDelegatecall`] + /// function. + pub fn simulateDelegatecall( + &self, + targetContract: alloy_sol_types::private::Address, + calldataPayload: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, simulateDelegatecallCall, N> { + self.call_builder(&simulateDelegatecallCall { + targetContract, + calldataPayload, + }) + } + + ///Creates a new call builder for the [`swap`] function. + pub fn swap( + &self, + swaps: alloy_sol_types::private::Vec< + ::RustType, + >, + tokens: alloy_sol_types::private::Vec, + trade: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, swapCall, N> { + self.call_builder(&swapCall { + swaps, + tokens, + trade, + }) + } + + ///Creates a new call builder for the [`vault`] function. + pub fn vault(&self) -> alloy_contract::SolCallBuilder<&P, vaultCall, N> { + self.call_builder(&vaultCall) + } + + ///Creates a new call builder for the [`vaultRelayer`] function. + pub fn vaultRelayer(&self) -> alloy_contract::SolCallBuilder<&P, vaultRelayerCall, N> { + self.call_builder(&vaultRelayerCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2SettlementInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Interaction`] event. + pub fn Interaction_filter(&self) -> alloy_contract::Event<&P, Interaction, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OrderInvalidated`] event. + pub fn OrderInvalidated_filter(&self) -> alloy_contract::Event<&P, OrderInvalidated, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PreSignature`] event. + pub fn PreSignature_filter(&self) -> alloy_contract::Event<&P, PreSignature, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Settlement`] event. + pub fn Settlement_filter(&self) -> alloy_contract::Event<&P, Settlement, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Trade`] event. + pub fn Trade_filter(&self) -> alloy_contract::Event<&P, Trade, N> { + self.event_filter::() + } + } +} +pub type Instance = GPv2Settlement::GPv2SettlementInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(12593265u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(134254624u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(48173641u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(16465100u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(45859743u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(21407238u64), + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(3439711u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(204704802u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(59891356u64), + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(34436849u64), + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(24333100u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), + Some(4717488u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/honeyswaprouter/Cargo.toml b/contracts/generated/contracts-generated/honeyswaprouter/Cargo.toml new file mode 100644 index 0000000000..efba40cf2f --- /dev/null +++ b/contracts/generated/contracts-generated/honeyswaprouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-honeyswaprouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/honeyswaprouter/src/lib.rs b/contracts/generated/contracts-generated/honeyswaprouter/src/lib.rs new file mode 100644 index 0000000000..446d527c3f --- /dev/null +++ b/contracts/generated/contracts-generated/honeyswaprouter/src/lib.rs @@ -0,0 +1,1578 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface HoneyswapRouter { + function WETH() external pure returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external pure returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod HoneyswapRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`HoneyswapRouter`](self) function calls. + #[derive(Clone)] + pub enum HoneyswapRouterCalls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl HoneyswapRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for HoneyswapRouterCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "HoneyswapRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(HoneyswapRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(HoneyswapRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(HoneyswapRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(HoneyswapRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(HoneyswapRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(HoneyswapRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(HoneyswapRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(HoneyswapRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(HoneyswapRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(HoneyswapRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`HoneyswapRouter`](self) contract instance. + + See the [wrapper's documentation](`HoneyswapRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> HoneyswapRouterInstance { + HoneyswapRouterInstance::::new(address, __provider) + } + /**A [`HoneyswapRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`HoneyswapRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct HoneyswapRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for HoneyswapRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("HoneyswapRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + HoneyswapRouterInstance + { + /**Creates a new wrapper around an on-chain [`HoneyswapRouter`](self) contract instance. + + See the [wrapper's documentation](`HoneyswapRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl HoneyswapRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> HoneyswapRouterInstance { + HoneyswapRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + HoneyswapRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + HoneyswapRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = HoneyswapRouter::HoneyswapRouterInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 100u64 => Some(( + ::alloy_primitives::address!("0x1C232F01118CB8B424793ae03F870aa7D0ac7f77"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/hookstrampoline/Cargo.toml b/contracts/generated/contracts-generated/hookstrampoline/Cargo.toml new file mode 100644 index 0000000000..b872d54cda --- /dev/null +++ b/contracts/generated/contracts-generated/hookstrampoline/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-hookstrampoline" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/hookstrampoline/src/lib.rs b/contracts/generated/contracts-generated/hookstrampoline/src/lib.rs new file mode 100644 index 0000000000..b6002f94ac --- /dev/null +++ b/contracts/generated/contracts-generated/hookstrampoline/src/lib.rs @@ -0,0 +1,1329 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface HooksTrampoline { + struct Hook { + address target; + bytes callData; + uint256 gasLimit; + } + + error NotASettlement(); + + constructor(address settlement_); + + function execute(Hook[] memory hooks) external; + function settlement() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "settlement_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "execute", + "inputs": [ + { + "name": "hooks", + "type": "tuple[]", + "internalType": "struct HooksTrampoline.Hook[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "gasLimit", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settlement", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "error", + "name": "NotASettlement", + "inputs": [] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod HooksTrampoline { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60a060405234801561000f575f80fd5b5060405161047d38038061047d83398101604081905261002e9161003f565b6001600160a01b031660805261006c565b5f6020828403121561004f575f80fd5b81516001600160a01b0381168114610065575f80fd5b9392505050565b6080516103f46100895f395f8181603d015260b501526103f45ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80635116063014610038578063760f2a0b14610088575b5f80fd5b61005f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61009b610096366004610208565b61009d565b005b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461010c576040517f0cd41ec000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b365f5b828110156101fc5783838281811061012957610129610277565b905060200281019061013b91906102a4565b91505f60405a603f0281610151576101516102e0565b049050826040013581101561016857610168610202565b5f610176602085018561030d565b73ffffffffffffffffffffffffffffffffffffffff16604085013561019e6020870187610347565b6040516101ac9291906103af565b5f604051808303815f8787f1925050503d805f81146101e6576040519150601f19603f3d011682016040523d82523d5f602084013e6101eb565b606091505b50509050505080600101905061010f565b50505050565b5b610203565b5f8060208385031215610219575f80fd5b823567ffffffffffffffff80821115610230575f80fd5b818501915085601f830112610243575f80fd5b813581811115610251575f80fd5b8660208260051b8501011115610265575f80fd5b60209290920196919550909350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126102d6575f80fd5b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6020828403121561031d575f80fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610340575f80fd5b9392505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261037a575f80fd5b83018035915067ffffffffffffffff821115610394575f80fd5b6020019150368190038213156103a8575f80fd5b9250929050565b818382375f910190815291905056fea26469706673582212203aec56971844bf1bef69242a1f8e62bf0bc7f5471df240e4d8b1ed414b52b73c64736f6c63430008140033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xA0`@R4\x80\x15a\0\x0FW_\x80\xFD[P`@Qa\x04}8\x03\x80a\x04}\x839\x81\x01`@\x81\x90Ra\0.\x91a\0?V[`\x01`\x01`\xA0\x1B\x03\x16`\x80Ra\0lV[_` \x82\x84\x03\x12\x15a\0OW_\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0eW_\x80\xFD[\x93\x92PPPV[`\x80Qa\x03\xF4a\0\x89_9_\x81\x81`=\x01R`\xB5\x01Ra\x03\xF4_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80cQ\x16\x060\x14a\08W\x80cv\x0F*\x0B\x14a\0\x88W[_\x80\xFD[a\0_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\x9Ba\0\x966`\x04a\x02\x08V[a\0\x9DV[\0[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x01\x0CW`@Q\x7F\x0C\xD4\x1E\xC0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[6_[\x82\x81\x10\x15a\x01\xFCW\x83\x83\x82\x81\x81\x10a\x01)Wa\x01)a\x02wV[\x90P` \x02\x81\x01\x90a\x01;\x91\x90a\x02\xA4V[\x91P_`@Z`?\x02\x81a\x01QWa\x01Qa\x02\xE0V[\x04\x90P\x82`@\x015\x81\x10\x15a\x01hWa\x01ha\x02\x02V[_a\x01v` \x85\x01\x85a\x03\rV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`@\x85\x015a\x01\x9E` \x87\x01\x87a\x03GV[`@Qa\x01\xAC\x92\x91\x90a\x03\xAFV[_`@Q\x80\x83\x03\x81_\x87\x87\xF1\x92PPP=\x80_\x81\x14a\x01\xE6W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x01\xEBV[``\x91P[PP\x90PPP\x80`\x01\x01\x90Pa\x01\x0FV[PPPPV[[a\x02\x03V[_\x80` \x83\x85\x03\x12\x15a\x02\x19W_\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x020W_\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x02CW_\x80\xFD[\x815\x81\x81\x11\x15a\x02QW_\x80\xFD[\x86` \x82`\x05\x1B\x85\x01\x01\x11\x15a\x02eW_\x80\xFD[` \x92\x90\x92\x01\x96\x91\x95P\x90\x93PPPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[_\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xA1\x836\x03\x01\x81\x12a\x02\xD6W_\x80\xFD[\x91\x90\x91\x01\x92\x91PPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a\x03\x1DW_\x80\xFD[\x815s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x03@W_\x80\xFD[\x93\x92PPPV[_\x80\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x03zW_\x80\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x03\x94W_\x80\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\x03\xA8W_\x80\xFD[\x92P\x92\x90PV[\x81\x83\x827_\x91\x01\x90\x81R\x91\x90PV\xFE\xA2dipfsX\"\x12 :\xECV\x97\x18D\xBF\x1B\xEFi$*\x1F\x8Eb\xBF\x0B\xC7\xF5G\x1D\xF2@\xE4\xD8\xB1\xEDAKR\xB7 = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Hook) -> Self { + (value.target, value.callData, value.gasLimit) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Hook { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + callData: tuple.1, + gasLimit: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Hook { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Hook { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.target, + ), + ::tokenize( + &self.callData, + ), + as alloy_sol_types::SolType>::tokenize( + &self.gasLimit, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Hook { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Hook { + const NAME: &'static str = "Hook"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Hook(address target,bytes callData,uint256 gasLimit)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.target, + ) + .0, + ::eip712_data_word( + &self.callData, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.gasLimit) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Hook { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.target, + ) + + ::topic_preimage_length( + &rust.callData, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.gasLimit, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.target, + out, + ); + ::encode_topic_preimage( + &rust.callData, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.gasLimit, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `NotASettlement()` and selector `0x0cd41ec0`. + ```solidity + error NotASettlement(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NotASettlement; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NotASettlement) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NotASettlement { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for NotASettlement { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [12u8, 212u8, 30u8, 192u8]; + const SIGNATURE: &'static str = "NotASettlement()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + /**Constructor`. + ```solidity + constructor(address settlement_); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub settlement_: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.settlement_,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + settlement_: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.settlement_, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `execute((address,bytes,uint256)[])` and selector `0x760f2a0b`. + ```solidity + function execute(Hook[] memory hooks) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct executeCall { + #[allow(missing_docs)] + pub hooks: alloy_sol_types::private::Vec<::RustType>, + } + ///Container type for the return parameters of the + /// [`execute((address,bytes,uint256)[])`](executeCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct executeReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Array,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (alloy_sol_types::private::Vec<::RustType>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: executeCall) -> Self { + (value.hooks,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for executeCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { hooks: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: executeReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for executeReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl executeReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for executeCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Array,); + type Return = executeReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [118u8, 15u8, 42u8, 11u8]; + const SIGNATURE: &'static str = "execute((address,bytes,uint256)[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.hooks, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + executeReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `settlement()` and selector `0x51160630`. + ```solidity + function settlement() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settlementCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`settlement()`](settlementCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settlementReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settlementCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settlementCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settlementReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settlementReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for settlementCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [81u8, 22u8, 6u8, 48u8]; + const SIGNATURE: &'static str = "settlement()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: settlementReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: settlementReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`HooksTrampoline`](self) function calls. + #[derive(Clone)] + pub enum HooksTrampolineCalls { + #[allow(missing_docs)] + execute(executeCall), + #[allow(missing_docs)] + settlement(settlementCall), + } + impl HooksTrampolineCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[81u8, 22u8, 6u8, 48u8], [118u8, 15u8, 42u8, 11u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = + &[::core::stringify!(settlement), ::core::stringify!(execute)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for HooksTrampolineCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "HooksTrampolineCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::execute(_) => ::SELECTOR, + Self::settlement(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn settlement(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(HooksTrampolineCalls::settlement) + } + settlement + }, + { + fn execute(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(HooksTrampolineCalls::execute) + } + execute + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn settlement(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(HooksTrampolineCalls::settlement) + } + settlement + }, + { + fn execute(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(HooksTrampolineCalls::execute) + } + execute + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::execute(inner) => { + ::abi_encoded_size(inner) + } + Self::settlement(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::execute(inner) => { + ::abi_encode_raw(inner, out) + } + Self::settlement(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`HooksTrampoline`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum HooksTrampolineErrors { + #[allow(missing_docs)] + NotASettlement(NotASettlement), + } + impl HooksTrampolineErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[12u8, 212u8, 30u8, 192u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(NotASettlement)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for HooksTrampolineErrors { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "HooksTrampolineErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::NotASettlement(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[{ + fn NotASettlement( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(HooksTrampolineErrors::NotASettlement) + } + NotASettlement + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + HooksTrampolineErrors, + >] = &[{ + fn NotASettlement(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(HooksTrampolineErrors::NotASettlement) + } + NotASettlement + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::NotASettlement(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::NotASettlement(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`HooksTrampoline`](self) contract instance. + + See the [wrapper's documentation](`HooksTrampolineInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> HooksTrampolineInstance { + HooksTrampolineInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + settlement_: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + HooksTrampolineInstance::::deploy(__provider, settlement_) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + settlement_: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + HooksTrampolineInstance::::deploy_builder(__provider, settlement_) + } + /**A [`HooksTrampoline`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`HooksTrampoline`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct HooksTrampolineInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for HooksTrampolineInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("HooksTrampolineInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + HooksTrampolineInstance + { + /**Creates a new wrapper around an on-chain [`HooksTrampoline`](self) contract instance. + + See the [wrapper's documentation](`HooksTrampolineInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + settlement_: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, settlement_); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + settlement_: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { settlement_ }) + [..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl HooksTrampolineInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> HooksTrampolineInstance { + HooksTrampolineInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + HooksTrampolineInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`execute`] function. + pub fn execute( + &self, + hooks: alloy_sol_types::private::Vec<::RustType>, + ) -> alloy_contract::SolCallBuilder<&P, executeCall, N> { + self.call_builder(&executeCall { hooks }) + } + + ///Creates a new call builder for the [`settlement`] function. + pub fn settlement(&self) -> alloy_contract::SolCallBuilder<&P, settlementCall, N> { + self.call_builder(&settlementCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + HooksTrampolineInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = HooksTrampoline::HooksTrampolineInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x01DcB88678aedD0C4cC9552B20F4718550250574"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x60bf78233f48ec42ee3f101b9a05ec7878728006"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/icowwrapper/Cargo.toml b/contracts/generated/contracts-generated/icowwrapper/Cargo.toml new file mode 100644 index 0000000000..3395cef70f --- /dev/null +++ b/contracts/generated/contracts-generated/icowwrapper/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-icowwrapper" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/icowwrapper/src/lib.rs b/contracts/generated/contracts-generated/icowwrapper/src/lib.rs new file mode 100644 index 0000000000..500a73c78b --- /dev/null +++ b/contracts/generated/contracts-generated/icowwrapper/src/lib.rs @@ -0,0 +1,469 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface ICowWrapper { + function wrappedSettle(bytes memory settleData, bytes memory wrapperData) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "wrappedSettle", + "inputs": [ + { + "name": "settleData", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "wrapperData", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ICowWrapper { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `wrappedSettle(bytes,bytes)` and selector `0xd20e71e7`. + ```solidity + function wrappedSettle(bytes memory settleData, bytes memory wrapperData) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct wrappedSettleCall { + #[allow(missing_docs)] + pub settleData: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub wrapperData: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`wrappedSettle(bytes,bytes)`](wrappedSettleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct wrappedSettleReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Bytes, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: wrappedSettleCall) -> Self { + (value.settleData, value.wrapperData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for wrappedSettleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + settleData: tuple.0, + wrapperData: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: wrappedSettleReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for wrappedSettleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl wrappedSettleReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for wrappedSettleCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Bytes, + ); + type Return = wrappedSettleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [210u8, 14u8, 113u8, 231u8]; + const SIGNATURE: &'static str = "wrappedSettle(bytes,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.settleData, + ), + ::tokenize( + &self.wrapperData, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + wrappedSettleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`ICowWrapper`](self) function calls. + #[derive(Clone)] + pub enum ICowWrapperCalls { + #[allow(missing_docs)] + wrappedSettle(wrappedSettleCall), + } + impl ICowWrapperCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[210u8, 14u8, 113u8, 231u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(wrappedSettle)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for ICowWrapperCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 128usize; + const NAME: &'static str = "ICowWrapperCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::wrappedSettle(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[{ + fn wrappedSettle(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ICowWrapperCalls::wrappedSettle) + } + wrappedSettle + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[{ + fn wrappedSettle(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ICowWrapperCalls::wrappedSettle) + } + wrappedSettle + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::wrappedSettle(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::wrappedSettle(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ICowWrapper`](self) contract instance. + + See the [wrapper's documentation](`ICowWrapperInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ICowWrapperInstance { + ICowWrapperInstance::::new(address, __provider) + } + /**A [`ICowWrapper`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ICowWrapper`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ICowWrapperInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ICowWrapperInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ICowWrapperInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ICowWrapperInstance + { + /**Creates a new wrapper around an on-chain [`ICowWrapper`](self) contract instance. + + See the [wrapper's documentation](`ICowWrapperInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ICowWrapperInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ICowWrapperInstance { + ICowWrapperInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ICowWrapperInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`wrappedSettle`] function. + pub fn wrappedSettle( + &self, + settleData: alloy_sol_types::private::Bytes, + wrapperData: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, wrappedSettleCall, N> { + self.call_builder(&wrappedSettleCall { + settleData, + wrapperData, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ICowWrapperInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = ICowWrapper::ICowWrapperInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/ierc4626/Cargo.toml b/contracts/generated/contracts-generated/ierc4626/Cargo.toml new file mode 100644 index 0000000000..fe00f44d09 --- /dev/null +++ b/contracts/generated/contracts-generated/ierc4626/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-ierc4626" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/ierc4626/src/lib.rs b/contracts/generated/contracts-generated/ierc4626/src/lib.rs new file mode 100644 index 0000000000..11f48918c2 --- /dev/null +++ b/contracts/generated/contracts-generated/ierc4626/src/lib.rs @@ -0,0 +1,648 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface IERC4626 { + function asset() external view returns (address assetTokenAddress); + function convertToAssets(uint256 shares) external view returns (uint256 assets); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "asset", + "inputs": [], + "outputs": [ + { + "name": "assetTokenAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "convertToAssets", + "inputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "assets", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IERC4626 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `asset()` and selector `0x38d52e0f`. + ```solidity + function asset() external view returns (address assetTokenAddress); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct assetCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`asset()`](assetCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct assetReturn { + #[allow(missing_docs)] + pub assetTokenAddress: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: assetCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for assetCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: assetReturn) -> Self { + (value.assetTokenAddress,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for assetReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + assetTokenAddress: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for assetCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [56u8, 213u8, 46u8, 15u8]; + const SIGNATURE: &'static str = "asset()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: assetReturn = r.into(); + r.assetTokenAddress + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: assetReturn = r.into(); + r.assetTokenAddress + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `convertToAssets(uint256)` and selector `0x07a2d13a`. + ```solidity + function convertToAssets(uint256 shares) external view returns (uint256 assets); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct convertToAssetsCall { + #[allow(missing_docs)] + pub shares: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`convertToAssets(uint256)`](convertToAssetsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct convertToAssetsReturn { + #[allow(missing_docs)] + pub assets: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: convertToAssetsCall) -> Self { + (value.shares,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for convertToAssetsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { shares: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: convertToAssetsReturn) -> Self { + (value.assets,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for convertToAssetsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { assets: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for convertToAssetsCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [7u8, 162u8, 209u8, 58u8]; + const SIGNATURE: &'static str = "convertToAssets(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.shares, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: convertToAssetsReturn = r.into(); + r.assets + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: convertToAssetsReturn = r.into(); + r.assets + }) + } + } + }; + ///Container for all the [`IERC4626`](self) function calls. + #[derive(Clone)] + pub enum IERC4626Calls { + #[allow(missing_docs)] + asset(assetCall), + #[allow(missing_docs)] + convertToAssets(convertToAssetsCall), + } + impl IERC4626Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[7u8, 162u8, 209u8, 58u8], [56u8, 213u8, 46u8, 15u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(convertToAssets), + ::core::stringify!(asset), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for IERC4626Calls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "IERC4626Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::asset(_) => ::SELECTOR, + Self::convertToAssets(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn convertToAssets(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IERC4626Calls::convertToAssets) + } + convertToAssets + }, + { + fn asset(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IERC4626Calls::asset) + } + asset + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[ + { + fn convertToAssets(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IERC4626Calls::convertToAssets) + } + convertToAssets + }, + { + fn asset(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IERC4626Calls::asset) + } + asset + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::asset(inner) => { + ::abi_encoded_size(inner) + } + Self::convertToAssets(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::asset(inner) => { + ::abi_encode_raw(inner, out) + } + Self::convertToAssets(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IERC4626`](self) contract instance. + + See the [wrapper's documentation](`IERC4626Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IERC4626Instance { + IERC4626Instance::::new(address, __provider) + } + /**A [`IERC4626`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IERC4626`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IERC4626Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IERC4626Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IERC4626Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IERC4626Instance + { + /**Creates a new wrapper around an on-chain [`IERC4626`](self) contract instance. + + See the [wrapper's documentation](`IERC4626Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IERC4626Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IERC4626Instance { + IERC4626Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IERC4626Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`asset`] function. + pub fn asset(&self) -> alloy_contract::SolCallBuilder<&P, assetCall, N> { + self.call_builder(&assetCall) + } + + ///Creates a new call builder for the [`convertToAssets`] function. + pub fn convertToAssets( + &self, + shares: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, convertToAssetsCall, N> { + self.call_builder(&convertToAssetsCall { shares }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IERC4626Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = IERC4626::IERC4626Instance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/iswaprpair/Cargo.toml b/contracts/generated/contracts-generated/iswaprpair/Cargo.toml new file mode 100644 index 0000000000..915048461d --- /dev/null +++ b/contracts/generated/contracts-generated/iswaprpair/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-iswaprpair" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/iswaprpair/src/lib.rs b/contracts/generated/contracts-generated/iswaprpair/src/lib.rs new file mode 100644 index 0000000000..80abaf0f55 --- /dev/null +++ b/contracts/generated/contracts-generated/iswaprpair/src/lib.rs @@ -0,0 +1,5733 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface ISwaprPair { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to); + event Sync(uint112 reserve0, uint112 reserve1); + event Transfer(address indexed from, address indexed to, uint256 value); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 value) external returns (bool); + function balanceOf(address owner) external view returns (uint256); + function burn(address to) external returns (uint256 amount0, uint256 amount1); + function decimals() external pure returns (uint8); + function factory() external view returns (address); + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function initialize(address, address) external; + function mint(address to) external returns (uint256 liquidity); + function name() external pure returns (string memory); + function nonces(address owner) external view returns (uint256); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes memory data) external; + function swapFee() external view returns (uint32); + function symbol() external pure returns (string memory); + function sync() external; + function token0() external view returns (address); + function token1() external view returns (address); + function transfer(address to, uint256 value) external returns (bool); + function transferFrom(address from, address to, uint256 value) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getReserves", + "inputs": [], + "outputs": [ + { + "name": "reserve0", + "type": "uint112", + "internalType": "uint112" + }, + { + "name": "reserve1", + "type": "uint112", + "internalType": "uint112" + }, + { + "name": "blockTimestampLast", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "amount0Out", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1Out", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swapFee", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "sync", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "token0", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "token1", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Burn", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Mint", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Swap", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0In", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1In", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount0Out", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1Out", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Sync", + "inputs": [ + { + "name": "reserve0", + "type": "uint112", + "indexed": false, + "internalType": "uint112" + }, + { + "name": "reserve1", + "type": "uint112", + "indexed": false, + "internalType": "uint112" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ISwaprPair { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Burn(address,uint256,uint256,address)` and selector `0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496`. + ```solidity + event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Burn { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Burn { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Burn(address,uint256,uint256,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 220u8, 205u8, 65u8, 47u8, 11u8, 18u8, 82u8, 129u8, 156u8, 177u8, 253u8, 51u8, + 11u8, 147u8, 34u8, 76u8, 164u8, 38u8, 18u8, 137u8, 43u8, 179u8, 244u8, 247u8, + 137u8, 151u8, 110u8, 109u8, 129u8, 147u8, 100u8, 150u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + amount0: data.0, + amount1: data.1, + to: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.sender.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Burn { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Burn> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Burn) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Mint(address,uint256,uint256)` and selector `0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f`. + ```solidity + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Mint { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Mint { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Mint(address,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 76u8, 32u8, 155u8, 95u8, 200u8, 173u8, 80u8, 117u8, 143u8, 19u8, 226u8, 225u8, + 8u8, 139u8, 165u8, 106u8, 86u8, 13u8, 255u8, 105u8, 10u8, 28u8, 111u8, 239u8, + 38u8, 57u8, 79u8, 76u8, 3u8, 130u8, 28u8, 79u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + amount0: data.0, + amount1: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.sender.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Mint { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Mint> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Mint) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Swap(address,uint256,uint256,uint256,uint256,address)` and selector `0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822`. + ```solidity + event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Swap { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0In: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1In: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount0Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Swap { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Swap(address,uint256,uint256,uint256,uint256,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 215u8, 138u8, 217u8, 95u8, 164u8, 108u8, 153u8, 75u8, 101u8, 81u8, 208u8, + 218u8, 133u8, 252u8, 39u8, 95u8, 230u8, 19u8, 206u8, 55u8, 101u8, 127u8, 184u8, + 213u8, 227u8, 209u8, 48u8, 132u8, 1u8, 89u8, 216u8, 34u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + amount0In: data.0, + amount1In: data.1, + amount0Out: data.2, + amount1Out: data.3, + to: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0In, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1In, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0Out, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1Out, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.sender.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Swap { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Swap> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Swap) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Sync(uint112,uint112)` and selector `0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1`. + ```solidity + event Sync(uint112 reserve0, uint112 reserve1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Sync { + #[allow(missing_docs)] + pub reserve0: alloy_sol_types::private::primitives::aliases::U112, + #[allow(missing_docs)] + pub reserve1: alloy_sol_types::private::primitives::aliases::U112, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Sync { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<112>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Sync(uint112,uint112)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 28u8, 65u8, 30u8, 154u8, 150u8, 224u8, 113u8, 36u8, 28u8, 47u8, 33u8, 247u8, + 114u8, 107u8, 23u8, 174u8, 137u8, 227u8, 202u8, 180u8, 199u8, 139u8, 229u8, + 14u8, 6u8, 43u8, 3u8, 169u8, 255u8, 251u8, 186u8, 209u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + reserve0: data.0, + reserve1: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.reserve0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserve1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Sync { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Sync> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Sync) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 value) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + value: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `burn(address)` and selector `0x89afcb44`. + ```solidity + function burn(address to) external returns (uint256 amount0, uint256 amount1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct burnCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`burn(address)`](burnCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct burnReturn { + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: burnCall) -> Self { + (value.to,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for burnCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { to: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: burnReturn) -> Self { + (value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for burnReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0: tuple.0, + amount1: tuple.1, + } + } + } + } + impl burnReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for burnCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = burnReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [137u8, 175u8, 203u8, 68u8]; + const SIGNATURE: &'static str = "burn(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + burnReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external pure returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getReserves()` and selector `0x0902f1ac`. + ```solidity + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getReservesCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getReserves()`](getReservesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getReservesReturn { + #[allow(missing_docs)] + pub reserve0: alloy_sol_types::private::primitives::aliases::U112, + #[allow(missing_docs)] + pub reserve1: alloy_sol_types::private::primitives::aliases::U112, + #[allow(missing_docs)] + pub blockTimestampLast: u32, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getReservesCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getReservesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U112, + alloy_sol_types::private::primitives::aliases::U112, + u32, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getReservesReturn) -> Self { + (value.reserve0, value.reserve1, value.blockTimestampLast) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getReservesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + reserve0: tuple.0, + reserve1: tuple.1, + blockTimestampLast: tuple.2, + } + } + } + } + impl getReservesReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.reserve0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserve1, + ), + as alloy_sol_types::SolType>::tokenize( + &self.blockTimestampLast, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getReservesCall { + type Parameters<'a> = (); + type Return = getReservesReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<32>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 2u8, 241u8, 172u8]; + const SIGNATURE: &'static str = "getReserves()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getReservesReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `initialize(address,address)` and selector `0x485cc955`. + ```solidity + function initialize(address, address) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeCall { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`initialize(address,address)`](initializeCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeCall) -> Self { + (value._0, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl initializeReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for initializeCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = initializeReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [72u8, 92u8, 201u8, 85u8]; + const SIGNATURE: &'static str = "initialize(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._0, + ), + ::tokenize( + &self._1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + initializeReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address)` and selector `0x6a627842`. + ```solidity + function mint(address to) external returns (uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`mint(address)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn { + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + (value.to,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { to: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + (value.liquidity,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { liquidity: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [106u8, 98u8, 120u8, 66u8]; + const SIGNATURE: &'static str = "mint(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: mintReturn = r.into(); + r.liquidity + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: mintReturn = r.into(); + r.liquidity + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external pure returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swap(uint256,uint256,address,bytes)` and selector `0x022c0d9f`. + ```solidity + function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes memory data) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapCall { + #[allow(missing_docs)] + pub amount0Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`swap(uint256,uint256,address,bytes)`](swapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapCall) -> Self { + (value.amount0Out, value.amount1Out, value.to, value.data) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0Out: tuple.0, + amount1Out: tuple.1, + to: tuple.2, + data: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl swapReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = swapReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [2u8, 44u8, 13u8, 159u8]; + const SIGNATURE: &'static str = "swap(uint256,uint256,address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0Out, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1Out, + ), + ::tokenize( + &self.to, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + swapReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapFee()` and selector `0x54cf2aeb`. + ```solidity + function swapFee() external view returns (uint32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapFeeCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapFee()`](swapFeeCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapFeeReturn { + #[allow(missing_docs)] + pub _0: u32, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapFeeCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapFeeCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u32,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapFeeReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapFeeReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapFeeCall { + type Parameters<'a> = (); + type Return = u32; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [84u8, 207u8, 42u8, 235u8]; + const SIGNATURE: &'static str = "swapFee()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapFeeReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapFeeReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external pure returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `sync()` and selector `0xfff6cae9`. + ```solidity + function sync() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct syncCall; + ///Container type for the return parameters of the [`sync()`](syncCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct syncReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: syncCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for syncCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: syncReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for syncReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl syncReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for syncCall { + type Parameters<'a> = (); + type Return = syncReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [255u8, 246u8, 202u8, 233u8]; + const SIGNATURE: &'static str = "sync()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + syncReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token0()` and selector `0x0dfe1681`. + ```solidity + function token0() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token0()`](token0Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token0Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [13u8, 254u8, 22u8, 129u8]; + const SIGNATURE: &'static str = "token0()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token0Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token0Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token1()` and selector `0xd21220a7`. + ```solidity + function token1() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token1()`](token1Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token1Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [210u8, 18u8, 32u8, 167u8]; + const SIGNATURE: &'static str = "token1()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token1Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token1Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address to, uint256 value) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.to, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + value: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address from, address to, uint256 value) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.from, value.to, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + from: tuple.0, + to: tuple.1, + value: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.from, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`ISwaprPair`](self) function calls. + #[derive(Clone)] + pub enum ISwaprPairCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + burn(burnCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + getReserves(getReservesCall), + #[allow(missing_docs)] + initialize(initializeCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + swap(swapCall), + #[allow(missing_docs)] + swapFee(swapFeeCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + sync(syncCall), + #[allow(missing_docs)] + token0(token0Call), + #[allow(missing_docs)] + token1(token1Call), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl ISwaprPairCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [2u8, 44u8, 13u8, 159u8], + [6u8, 253u8, 222u8, 3u8], + [9u8, 2u8, 241u8, 172u8], + [9u8, 94u8, 167u8, 179u8], + [13u8, 254u8, 22u8, 129u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [72u8, 92u8, 201u8, 85u8], + [84u8, 207u8, 42u8, 235u8], + [106u8, 98u8, 120u8, 66u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [137u8, 175u8, 203u8, 68u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [196u8, 90u8, 1u8, 85u8], + [210u8, 18u8, 32u8, 167u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + [255u8, 246u8, 202u8, 233u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swap), + ::core::stringify!(name), + ::core::stringify!(getReserves), + ::core::stringify!(approve), + ::core::stringify!(token0), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(initialize), + ::core::stringify!(swapFee), + ::core::stringify!(mint), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(burn), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(factory), + ::core::stringify!(token1), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ::core::stringify!(sync), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for ISwaprPairCalls { + const COUNT: usize = 21usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "ISwaprPairCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::burn(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::getReserves(_) => ::SELECTOR, + Self::initialize(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::swap(_) => ::SELECTOR, + Self::swapFee(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::sync(_) => ::SELECTOR, + Self::token0(_) => ::SELECTOR, + Self::token1(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::swap) + } + swap + }, + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::name) + } + name + }, + { + fn getReserves(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::getReserves) + } + getReserves + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::approve) + } + approve + }, + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::token0) + } + token0 + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn initialize(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::initialize) + } + initialize + }, + { + fn swapFee(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::swapFee) + } + swapFee + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::nonces) + } + nonces + }, + { + fn burn(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::burn) + } + burn + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::transfer) + } + transfer + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::factory) + } + factory + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::token1) + } + token1 + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::allowance) + } + allowance + }, + { + fn sync(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(ISwaprPairCalls::sync) + } + sync + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::swap) + } + swap + }, + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::name) + } + name + }, + { + fn getReserves(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::getReserves) + } + getReserves + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::approve) + } + approve + }, + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::token0) + } + token0 + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(ISwaprPairCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(ISwaprPairCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn initialize(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::initialize) + } + initialize + }, + { + fn swapFee(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::swapFee) + } + swapFee + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::nonces) + } + nonces + }, + { + fn burn(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::burn) + } + burn + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::transfer) + } + transfer + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::factory) + } + factory + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::token1) + } + token1 + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::allowance) + } + allowance + }, + { + fn sync(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(ISwaprPairCalls::sync) + } + sync + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::burn(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::getReserves(inner) => { + ::abi_encoded_size(inner) + } + Self::initialize(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::swap(inner) => { + ::abi_encoded_size(inner) + } + Self::swapFee(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::sync(inner) => { + ::abi_encoded_size(inner) + } + Self::token0(inner) => { + ::abi_encoded_size(inner) + } + Self::token1(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::burn(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getReserves(inner) => { + ::abi_encode_raw(inner, out) + } + Self::initialize(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapFee(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::sync(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token0(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token1(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`ISwaprPair`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum ISwaprPairEvents { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + Burn(Burn), + #[allow(missing_docs)] + Mint(Mint), + #[allow(missing_docs)] + Swap(Swap), + #[allow(missing_docs)] + Sync(Sync), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl ISwaprPairEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 28u8, 65u8, 30u8, 154u8, 150u8, 224u8, 113u8, 36u8, 28u8, 47u8, 33u8, 247u8, 114u8, + 107u8, 23u8, 174u8, 137u8, 227u8, 202u8, 180u8, 199u8, 139u8, 229u8, 14u8, 6u8, + 43u8, 3u8, 169u8, 255u8, 251u8, 186u8, 209u8, + ], + [ + 76u8, 32u8, 155u8, 95u8, 200u8, 173u8, 80u8, 117u8, 143u8, 19u8, 226u8, 225u8, 8u8, + 139u8, 165u8, 106u8, 86u8, 13u8, 255u8, 105u8, 10u8, 28u8, 111u8, 239u8, 38u8, + 57u8, 79u8, 76u8, 3u8, 130u8, 28u8, 79u8, + ], + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 215u8, 138u8, 217u8, 95u8, 164u8, 108u8, 153u8, 75u8, 101u8, 81u8, 208u8, 218u8, + 133u8, 252u8, 39u8, 95u8, 230u8, 19u8, 206u8, 55u8, 101u8, 127u8, 184u8, 213u8, + 227u8, 209u8, 48u8, 132u8, 1u8, 89u8, 216u8, 34u8, + ], + [ + 220u8, 205u8, 65u8, 47u8, 11u8, 18u8, 82u8, 129u8, 156u8, 177u8, 253u8, 51u8, 11u8, + 147u8, 34u8, 76u8, 164u8, 38u8, 18u8, 137u8, 43u8, 179u8, 244u8, 247u8, 137u8, + 151u8, 110u8, 109u8, 129u8, 147u8, 100u8, 150u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(Sync), + ::core::stringify!(Mint), + ::core::stringify!(Approval), + ::core::stringify!(Swap), + ::core::stringify!(Burn), + ::core::stringify!(Transfer), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for ISwaprPairEvents { + const COUNT: usize = 6usize; + const NAME: &'static str = "ISwaprPairEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Burn) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Mint) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Swap) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Sync) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ISwaprPairEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Burn(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Mint(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Sync(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Burn(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Mint(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Sync(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ISwaprPair`](self) contract instance. + + See the [wrapper's documentation](`ISwaprPairInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ISwaprPairInstance { + ISwaprPairInstance::::new(address, __provider) + } + /**A [`ISwaprPair`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ISwaprPair`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ISwaprPairInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ISwaprPairInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ISwaprPairInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ISwaprPairInstance + { + /**Creates a new wrapper around an on-chain [`ISwaprPair`](self) contract instance. + + See the [wrapper's documentation](`ISwaprPairInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ISwaprPairInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ISwaprPairInstance { + ISwaprPairInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ISwaprPairInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, value }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { owner }) + } + + ///Creates a new call builder for the [`burn`] function. + pub fn burn( + &self, + to: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, burnCall, N> { + self.call_builder(&burnCall { to }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`getReserves`] function. + pub fn getReserves(&self) -> alloy_contract::SolCallBuilder<&P, getReservesCall, N> { + self.call_builder(&getReservesCall) + } + + ///Creates a new call builder for the [`initialize`] function. + pub fn initialize( + &self, + _0: alloy_sol_types::private::Address, + _1: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, initializeCall, N> { + self.call_builder(&initializeCall { _0, _1 }) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + to: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { to }) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`swap`] function. + pub fn swap( + &self, + amount0Out: alloy_sol_types::private::primitives::aliases::U256, + amount1Out: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + data: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, swapCall, N> { + self.call_builder(&swapCall { + amount0Out, + amount1Out, + to, + data, + }) + } + + ///Creates a new call builder for the [`swapFee`] function. + pub fn swapFee(&self) -> alloy_contract::SolCallBuilder<&P, swapFeeCall, N> { + self.call_builder(&swapFeeCall) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`sync`] function. + pub fn sync(&self) -> alloy_contract::SolCallBuilder<&P, syncCall, N> { + self.call_builder(&syncCall) + } + + ///Creates a new call builder for the [`token0`] function. + pub fn token0(&self) -> alloy_contract::SolCallBuilder<&P, token0Call, N> { + self.call_builder(&token0Call) + } + + ///Creates a new call builder for the [`token1`] function. + pub fn token1(&self) -> alloy_contract::SolCallBuilder<&P, token1Call, N> { + self.call_builder(&token1Call) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + to: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { to, value }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + from: alloy_sol_types::private::Address, + to: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { from, to, value }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ISwaprPairInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Burn`] event. + pub fn Burn_filter(&self) -> alloy_contract::Event<&P, Burn, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Mint`] event. + pub fn Mint_filter(&self) -> alloy_contract::Event<&P, Mint, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Swap`] event. + pub fn Swap_filter(&self) -> alloy_contract::Event<&P, Swap, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Sync`] event. + pub fn Sync_filter(&self) -> alloy_contract::Event<&P, Sync, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = ISwaprPair::ISwaprPairInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/iuniswaplikepair/Cargo.toml b/contracts/generated/contracts-generated/iuniswaplikepair/Cargo.toml new file mode 100644 index 0000000000..1d20caa72f --- /dev/null +++ b/contracts/generated/contracts-generated/iuniswaplikepair/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-iuniswaplikepair" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/iuniswaplikepair/src/lib.rs b/contracts/generated/contracts-generated/iuniswaplikepair/src/lib.rs new file mode 100644 index 0000000000..c15f524821 --- /dev/null +++ b/contracts/generated/contracts-generated/iuniswaplikepair/src/lib.rs @@ -0,0 +1,5554 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface IUniswapLikePair { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to); + event Sync(uint112 reserve0, uint112 reserve1); + event Transfer(address indexed from, address indexed to, uint256 value); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 value) external returns (bool); + function balanceOf(address owner) external view returns (uint256); + function burn(address to) external returns (uint256 amount0, uint256 amount1); + function decimals() external pure returns (uint8); + function factory() external view returns (address); + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + function initialize(address, address) external; + function mint(address to) external returns (uint256 liquidity); + function name() external pure returns (string memory); + function nonces(address owner) external view returns (uint256); + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes memory data) external; + function symbol() external pure returns (string memory); + function sync() external; + function token0() external view returns (address); + function token1() external view returns (address); + function transfer(address to, uint256 value) external returns (bool); + function transferFrom(address from, address to, uint256 value) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getReserves", + "inputs": [], + "outputs": [ + { + "name": "reserve0", + "type": "uint112", + "internalType": "uint112" + }, + { + "name": "reserve1", + "type": "uint112", + "internalType": "uint112" + }, + { + "name": "blockTimestampLast", + "type": "uint32", + "internalType": "uint32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "amount0Out", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1Out", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "sync", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "token0", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "token1", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Burn", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Mint", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Swap", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0In", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1In", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount0Out", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1Out", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Sync", + "inputs": [ + { + "name": "reserve0", + "type": "uint112", + "indexed": false, + "internalType": "uint112" + }, + { + "name": "reserve1", + "type": "uint112", + "indexed": false, + "internalType": "uint112" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IUniswapLikePair { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed owner, address indexed spender, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Burn(address,uint256,uint256,address)` and selector `0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496`. + ```solidity + event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Burn { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Burn { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Burn(address,uint256,uint256,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 220u8, 205u8, 65u8, 47u8, 11u8, 18u8, 82u8, 129u8, 156u8, 177u8, 253u8, 51u8, + 11u8, 147u8, 34u8, 76u8, 164u8, 38u8, 18u8, 137u8, 43u8, 179u8, 244u8, 247u8, + 137u8, 151u8, 110u8, 109u8, 129u8, 147u8, 100u8, 150u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + amount0: data.0, + amount1: data.1, + to: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.sender.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Burn { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Burn> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Burn) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Mint(address,uint256,uint256)` and selector `0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f`. + ```solidity + event Mint(address indexed sender, uint256 amount0, uint256 amount1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Mint { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Mint { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Mint(address,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 76u8, 32u8, 155u8, 95u8, 200u8, 173u8, 80u8, 117u8, 143u8, 19u8, 226u8, 225u8, + 8u8, 139u8, 165u8, 106u8, 86u8, 13u8, 255u8, 105u8, 10u8, 28u8, 111u8, 239u8, + 38u8, 57u8, 79u8, 76u8, 3u8, 130u8, 28u8, 79u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + amount0: data.0, + amount1: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.sender.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Mint { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Mint> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Mint) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Swap(address,uint256,uint256,uint256,uint256,address)` and selector `0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822`. + ```solidity + event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Swap { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0In: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1In: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount0Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Swap { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Swap(address,uint256,uint256,uint256,uint256,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 215u8, 138u8, 217u8, 95u8, 164u8, 108u8, 153u8, 75u8, 101u8, 81u8, 208u8, + 218u8, 133u8, 252u8, 39u8, 95u8, 230u8, 19u8, 206u8, 55u8, 101u8, 127u8, 184u8, + 213u8, 227u8, 209u8, 48u8, 132u8, 1u8, 89u8, 216u8, 34u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + amount0In: data.0, + amount1In: data.1, + amount0Out: data.2, + amount1Out: data.3, + to: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0In, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1In, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0Out, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1Out, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.sender.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Swap { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Swap> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Swap) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Sync(uint112,uint112)` and selector `0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1`. + ```solidity + event Sync(uint112 reserve0, uint112 reserve1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Sync { + #[allow(missing_docs)] + pub reserve0: alloy_sol_types::private::primitives::aliases::U112, + #[allow(missing_docs)] + pub reserve1: alloy_sol_types::private::primitives::aliases::U112, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Sync { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<112>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Sync(uint112,uint112)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 28u8, 65u8, 30u8, 154u8, 150u8, 224u8, 113u8, 36u8, 28u8, 47u8, 33u8, 247u8, + 114u8, 107u8, 23u8, 174u8, 137u8, 227u8, 202u8, 180u8, 199u8, 139u8, 229u8, + 14u8, 6u8, 43u8, 3u8, 169u8, 255u8, 251u8, 186u8, 209u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + reserve0: data.0, + reserve1: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.reserve0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserve1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Sync { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Sync> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Sync) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed from, address indexed to, uint256 value); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.from.clone(), + self.to.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address owner, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 value) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + value: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `burn(address)` and selector `0x89afcb44`. + ```solidity + function burn(address to) external returns (uint256 amount0, uint256 amount1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct burnCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`burn(address)`](burnCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct burnReturn { + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: burnCall) -> Self { + (value.to,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for burnCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { to: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: burnReturn) -> Self { + (value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for burnReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0: tuple.0, + amount1: tuple.1, + } + } + } + } + impl burnReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for burnCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = burnReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [137u8, 175u8, 203u8, 68u8]; + const SIGNATURE: &'static str = "burn(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + burnReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external pure returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getReserves()` and selector `0x0902f1ac`. + ```solidity + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getReservesCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getReserves()`](getReservesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getReservesReturn { + #[allow(missing_docs)] + pub reserve0: alloy_sol_types::private::primitives::aliases::U112, + #[allow(missing_docs)] + pub reserve1: alloy_sol_types::private::primitives::aliases::U112, + #[allow(missing_docs)] + pub blockTimestampLast: u32, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getReservesCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getReservesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U112, + alloy_sol_types::private::primitives::aliases::U112, + u32, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getReservesReturn) -> Self { + (value.reserve0, value.reserve1, value.blockTimestampLast) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getReservesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + reserve0: tuple.0, + reserve1: tuple.1, + blockTimestampLast: tuple.2, + } + } + } + } + impl getReservesReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.reserve0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserve1, + ), + as alloy_sol_types::SolType>::tokenize( + &self.blockTimestampLast, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getReservesCall { + type Parameters<'a> = (); + type Return = getReservesReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<112>, + alloy_sol_types::sol_data::Uint<32>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 2u8, 241u8, 172u8]; + const SIGNATURE: &'static str = "getReserves()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getReservesReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `initialize(address,address)` and selector `0x485cc955`. + ```solidity + function initialize(address, address) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeCall { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`initialize(address,address)`](initializeCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeCall) -> Self { + (value._0, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl initializeReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for initializeCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = initializeReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [72u8, 92u8, 201u8, 85u8]; + const SIGNATURE: &'static str = "initialize(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._0, + ), + ::tokenize( + &self._1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + initializeReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address)` and selector `0x6a627842`. + ```solidity + function mint(address to) external returns (uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`mint(address)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn { + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + (value.to,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { to: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + (value.liquidity,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { liquidity: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [106u8, 98u8, 120u8, 66u8]; + const SIGNATURE: &'static str = "mint(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: mintReturn = r.into(); + r.liquidity + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: mintReturn = r.into(); + r.liquidity + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external pure returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `nonces(address)` and selector `0x7ecebe00`. + ```solidity + function nonces(address owner) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`nonces(address)`](noncesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct noncesReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesCall) -> Self { + (value.owner,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { owner: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: noncesReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for noncesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for noncesCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [126u8, 206u8, 190u8, 0u8]; + const SIGNATURE: &'static str = "nonces(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: noncesReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: noncesReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `permit(address,address,uint256,uint256,uint8,bytes32,bytes32)` and selector `0xd505accf`. + ```solidity + function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + ///Container type for the return parameters of the + /// [`permit(address,address,uint256,uint256,uint8,bytes32, + /// bytes32)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + ( + value.owner, + value.spender, + value.value, + value.deadline, + value.v, + value.r, + value.s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + value: tuple.2, + deadline: tuple.3, + v: tuple.4, + r: tuple.5, + s: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [213u8, 5u8, 172u8, 207u8]; + const SIGNATURE: &'static str = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swap(uint256,uint256,address,bytes)` and selector `0x022c0d9f`. + ```solidity + function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes memory data) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapCall { + #[allow(missing_docs)] + pub amount0Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1Out: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`swap(uint256,uint256,address,bytes)`](swapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapCall) -> Self { + (value.amount0Out, value.amount1Out, value.to, value.data) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0Out: tuple.0, + amount1Out: tuple.1, + to: tuple.2, + data: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl swapReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = swapReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [2u8, 44u8, 13u8, 159u8]; + const SIGNATURE: &'static str = "swap(uint256,uint256,address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0Out, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1Out, + ), + ::tokenize( + &self.to, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + swapReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external pure returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `sync()` and selector `0xfff6cae9`. + ```solidity + function sync() external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct syncCall; + ///Container type for the return parameters of the [`sync()`](syncCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct syncReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: syncCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for syncCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: syncReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for syncReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl syncReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for syncCall { + type Parameters<'a> = (); + type Return = syncReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [255u8, 246u8, 202u8, 233u8]; + const SIGNATURE: &'static str = "sync()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + syncReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token0()` and selector `0x0dfe1681`. + ```solidity + function token0() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token0()`](token0Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token0Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [13u8, 254u8, 22u8, 129u8]; + const SIGNATURE: &'static str = "token0()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token0Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token0Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token1()` and selector `0xd21220a7`. + ```solidity + function token1() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token1()`](token1Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token1Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [210u8, 18u8, 32u8, 167u8]; + const SIGNATURE: &'static str = "token1()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token1Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token1Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address to, uint256 value) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.to, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + value: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address from, address to, uint256 value) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.from, value.to, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + from: tuple.0, + to: tuple.1, + value: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.from, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`IUniswapLikePair`](self) function calls. + #[derive(Clone)] + pub enum IUniswapLikePairCalls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + burn(burnCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + getReserves(getReservesCall), + #[allow(missing_docs)] + initialize(initializeCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + nonces(noncesCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + swap(swapCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + sync(syncCall), + #[allow(missing_docs)] + token0(token0Call), + #[allow(missing_docs)] + token1(token1Call), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl IUniswapLikePairCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [2u8, 44u8, 13u8, 159u8], + [6u8, 253u8, 222u8, 3u8], + [9u8, 2u8, 241u8, 172u8], + [9u8, 94u8, 167u8, 179u8], + [13u8, 254u8, 22u8, 129u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [54u8, 68u8, 229u8, 21u8], + [72u8, 92u8, 201u8, 85u8], + [106u8, 98u8, 120u8, 66u8], + [112u8, 160u8, 130u8, 49u8], + [126u8, 206u8, 190u8, 0u8], + [137u8, 175u8, 203u8, 68u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [196u8, 90u8, 1u8, 85u8], + [210u8, 18u8, 32u8, 167u8], + [213u8, 5u8, 172u8, 207u8], + [221u8, 98u8, 237u8, 62u8], + [255u8, 246u8, 202u8, 233u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swap), + ::core::stringify!(name), + ::core::stringify!(getReserves), + ::core::stringify!(approve), + ::core::stringify!(token0), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(initialize), + ::core::stringify!(mint), + ::core::stringify!(balanceOf), + ::core::stringify!(nonces), + ::core::stringify!(burn), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(factory), + ::core::stringify!(token1), + ::core::stringify!(permit), + ::core::stringify!(allowance), + ::core::stringify!(sync), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for IUniswapLikePairCalls { + const COUNT: usize = 20usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "IUniswapLikePairCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::burn(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::getReserves(_) => ::SELECTOR, + Self::initialize(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::name(_) => ::SELECTOR, + Self::nonces(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::swap(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::sync(_) => ::SELECTOR, + Self::token0(_) => ::SELECTOR, + Self::token1(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::swap) + } + swap + }, + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::name) + } + name + }, + { + fn getReserves(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::getReserves) + } + getReserves + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::approve) + } + approve + }, + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::token0) + } + token0 + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn initialize(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::initialize) + } + initialize + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::nonces) + } + nonces + }, + { + fn burn(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::burn) + } + burn + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::transfer) + } + transfer + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::factory) + } + factory + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::token1) + } + token1 + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::allowance) + } + allowance + }, + { + fn sync(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikePairCalls::sync) + } + sync + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + IUniswapLikePairCalls, + >] = &[ + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::swap) + } + swap + }, + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::name) + } + name + }, + { + fn getReserves(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::getReserves) + } + getReserves + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::approve) + } + approve + }, + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::token0) + } + token0 + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IUniswapLikePairCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::decimals) + } + decimals + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IUniswapLikePairCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn initialize(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::initialize) + } + initialize + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::balanceOf) + } + balanceOf + }, + { + fn nonces(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::nonces) + } + nonces + }, + { + fn burn(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::burn) + } + burn + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::transfer) + } + transfer + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::factory) + } + factory + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::token1) + } + token1 + }, + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::permit) + } + permit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::allowance) + } + allowance + }, + { + fn sync(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikePairCalls::sync) + } + sync + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::burn(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::getReserves(inner) => { + ::abi_encoded_size(inner) + } + Self::initialize(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::nonces(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::swap(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::sync(inner) => { + ::abi_encoded_size(inner) + } + Self::token0(inner) => { + ::abi_encoded_size(inner) + } + Self::token1(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::burn(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getReserves(inner) => { + ::abi_encode_raw(inner, out) + } + Self::initialize(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::nonces(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::sync(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token0(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token1(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`IUniswapLikePair`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum IUniswapLikePairEvents { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + Burn(Burn), + #[allow(missing_docs)] + Mint(Mint), + #[allow(missing_docs)] + Swap(Swap), + #[allow(missing_docs)] + Sync(Sync), + #[allow(missing_docs)] + Transfer(Transfer), + } + impl IUniswapLikePairEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 28u8, 65u8, 30u8, 154u8, 150u8, 224u8, 113u8, 36u8, 28u8, 47u8, 33u8, 247u8, 114u8, + 107u8, 23u8, 174u8, 137u8, 227u8, 202u8, 180u8, 199u8, 139u8, 229u8, 14u8, 6u8, + 43u8, 3u8, 169u8, 255u8, 251u8, 186u8, 209u8, + ], + [ + 76u8, 32u8, 155u8, 95u8, 200u8, 173u8, 80u8, 117u8, 143u8, 19u8, 226u8, 225u8, 8u8, + 139u8, 165u8, 106u8, 86u8, 13u8, 255u8, 105u8, 10u8, 28u8, 111u8, 239u8, 38u8, + 57u8, 79u8, 76u8, 3u8, 130u8, 28u8, 79u8, + ], + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 215u8, 138u8, 217u8, 95u8, 164u8, 108u8, 153u8, 75u8, 101u8, 81u8, 208u8, 218u8, + 133u8, 252u8, 39u8, 95u8, 230u8, 19u8, 206u8, 55u8, 101u8, 127u8, 184u8, 213u8, + 227u8, 209u8, 48u8, 132u8, 1u8, 89u8, 216u8, 34u8, + ], + [ + 220u8, 205u8, 65u8, 47u8, 11u8, 18u8, 82u8, 129u8, 156u8, 177u8, 253u8, 51u8, 11u8, + 147u8, 34u8, 76u8, 164u8, 38u8, 18u8, 137u8, 43u8, 179u8, 244u8, 247u8, 137u8, + 151u8, 110u8, 109u8, 129u8, 147u8, 100u8, 150u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(Sync), + ::core::stringify!(Mint), + ::core::stringify!(Approval), + ::core::stringify!(Swap), + ::core::stringify!(Burn), + ::core::stringify!(Transfer), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for IUniswapLikePairEvents { + const COUNT: usize = 6usize; + const NAME: &'static str = "IUniswapLikePairEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Burn) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Mint) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Swap) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Sync) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for IUniswapLikePairEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Burn(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Mint(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Sync(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Burn(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Mint(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Sync(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IUniswapLikePair`](self) contract instance. + + See the [wrapper's documentation](`IUniswapLikePairInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IUniswapLikePairInstance { + IUniswapLikePairInstance::::new(address, __provider) + } + /**A [`IUniswapLikePair`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IUniswapLikePair`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IUniswapLikePairInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IUniswapLikePairInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IUniswapLikePairInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IUniswapLikePairInstance + { + /**Creates a new wrapper around an on-chain [`IUniswapLikePair`](self) contract instance. + + See the [wrapper's documentation](`IUniswapLikePairInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IUniswapLikePairInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IUniswapLikePairInstance { + IUniswapLikePairInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IUniswapLikePairInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, value }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { owner }) + } + + ///Creates a new call builder for the [`burn`] function. + pub fn burn( + &self, + to: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, burnCall, N> { + self.call_builder(&burnCall { to }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`getReserves`] function. + pub fn getReserves(&self) -> alloy_contract::SolCallBuilder<&P, getReservesCall, N> { + self.call_builder(&getReservesCall) + } + + ///Creates a new call builder for the [`initialize`] function. + pub fn initialize( + &self, + _0: alloy_sol_types::private::Address, + _1: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, initializeCall, N> { + self.call_builder(&initializeCall { _0, _1 }) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + to: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { to }) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`nonces`] function. + pub fn nonces( + &self, + owner: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, noncesCall, N> { + self.call_builder(&noncesCall { owner }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + deadline: alloy_sol_types::private::primitives::aliases::U256, + v: u8, + r: alloy_sol_types::private::FixedBytes<32>, + s: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + spender, + value, + deadline, + v, + r, + s, + }) + } + + ///Creates a new call builder for the [`swap`] function. + pub fn swap( + &self, + amount0Out: alloy_sol_types::private::primitives::aliases::U256, + amount1Out: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + data: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, swapCall, N> { + self.call_builder(&swapCall { + amount0Out, + amount1Out, + to, + data, + }) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`sync`] function. + pub fn sync(&self) -> alloy_contract::SolCallBuilder<&P, syncCall, N> { + self.call_builder(&syncCall) + } + + ///Creates a new call builder for the [`token0`] function. + pub fn token0(&self) -> alloy_contract::SolCallBuilder<&P, token0Call, N> { + self.call_builder(&token0Call) + } + + ///Creates a new call builder for the [`token1`] function. + pub fn token1(&self) -> alloy_contract::SolCallBuilder<&P, token1Call, N> { + self.call_builder(&token1Call) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + to: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { to, value }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + from: alloy_sol_types::private::Address, + to: alloy_sol_types::private::Address, + value: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { from, to, value }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IUniswapLikePairInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Burn`] event. + pub fn Burn_filter(&self) -> alloy_contract::Event<&P, Burn, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Mint`] event. + pub fn Mint_filter(&self) -> alloy_contract::Event<&P, Mint, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Swap`] event. + pub fn Swap_filter(&self) -> alloy_contract::Event<&P, Swap, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Sync`] event. + pub fn Sync_filter(&self) -> alloy_contract::Event<&P, Sync, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} +pub type Instance = IUniswapLikePair::IUniswapLikePairInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/iuniswaplikerouter/Cargo.toml b/contracts/generated/contracts-generated/iuniswaplikerouter/Cargo.toml new file mode 100644 index 0000000000..8967d78c34 --- /dev/null +++ b/contracts/generated/contracts-generated/iuniswaplikerouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-iuniswaplikerouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/iuniswaplikerouter/src/lib.rs b/contracts/generated/contracts-generated/iuniswaplikerouter/src/lib.rs new file mode 100644 index 0000000000..f9916afb59 --- /dev/null +++ b/contracts/generated/contracts-generated/iuniswaplikerouter/src/lib.rs @@ -0,0 +1,1546 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface IUniswapLikeRouter { + function WETH() external pure returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external pure returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IUniswapLikeRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`IUniswapLikeRouter`](self) function calls. + #[derive(Clone)] + pub enum IUniswapLikeRouterCalls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl IUniswapLikeRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for IUniswapLikeRouterCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "IUniswapLikeRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(IUniswapLikeRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikeRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikeRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikeRouterCalls::factory) + } + factory + }, + { + fn addLiquidity( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapLikeRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + IUniswapLikeRouterCalls, + >] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IUniswapLikeRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikeRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikeRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapLikeRouterCalls::factory) + } + factory + }, + { + fn addLiquidity( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IUniswapLikeRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IUniswapLikeRouter`](self) contract instance. + + See the [wrapper's documentation](`IUniswapLikeRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IUniswapLikeRouterInstance { + IUniswapLikeRouterInstance::::new(address, __provider) + } + /**A [`IUniswapLikeRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IUniswapLikeRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IUniswapLikeRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IUniswapLikeRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IUniswapLikeRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IUniswapLikeRouterInstance + { + /**Creates a new wrapper around an on-chain [`IUniswapLikeRouter`](self) contract instance. + + See the [wrapper's documentation](`IUniswapLikeRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IUniswapLikeRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IUniswapLikeRouterInstance { + IUniswapLikeRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IUniswapLikeRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IUniswapLikeRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = IUniswapLikeRouter::IUniswapLikeRouterInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/iuniswapv3factory/Cargo.toml b/contracts/generated/contracts-generated/iuniswapv3factory/Cargo.toml new file mode 100644 index 0000000000..090a4745e0 --- /dev/null +++ b/contracts/generated/contracts-generated/iuniswapv3factory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-iuniswapv3factory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/iuniswapv3factory/src/lib.rs b/contracts/generated/contracts-generated/iuniswapv3factory/src/lib.rs new file mode 100644 index 0000000000..b2a65a95e4 --- /dev/null +++ b/contracts/generated/contracts-generated/iuniswapv3factory/src/lib.rs @@ -0,0 +1,1379 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface IUniswapV3Factory { + event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); + event OwnerChanged(address indexed oldOwner, address indexed newOwner); + event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool); + + function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool); + function owner() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "getPool", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint24", + "internalType": "uint24" + } + ], + "outputs": [ + { + "name": "pool", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FeeAmountEnabled", + "inputs": [ + { + "name": "fee", + "type": "uint24", + "indexed": true, + "internalType": "uint24" + }, + { + "name": "tickSpacing", + "type": "int24", + "indexed": true, + "internalType": "int24" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnerChanged", + "inputs": [ + { + "name": "oldOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PoolCreated", + "inputs": [ + { + "name": "token0", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "fee", + "type": "uint24", + "indexed": true, + "internalType": "uint24" + }, + { + "name": "tickSpacing", + "type": "int24", + "indexed": false, + "internalType": "int24" + }, + { + "name": "pool", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IUniswapV3Factory { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `FeeAmountEnabled(uint24,int24)` and selector `0xc66a3fdf07232cdd185febcc6579d408c241b47ae2f9907d84be655141eeaecc`. + ```solidity + event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct FeeAmountEnabled { + #[allow(missing_docs)] + pub fee: alloy_sol_types::private::primitives::aliases::U24, + #[allow(missing_docs)] + pub tickSpacing: alloy_sol_types::private::primitives::aliases::I24, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for FeeAmountEnabled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<24>, + alloy_sol_types::sol_data::Int<24>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "FeeAmountEnabled(uint24,int24)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 198u8, 106u8, 63u8, 223u8, 7u8, 35u8, 44u8, 221u8, 24u8, 95u8, 235u8, 204u8, + 101u8, 121u8, 212u8, 8u8, 194u8, 65u8, 180u8, 122u8, 226u8, 249u8, 144u8, + 125u8, 132u8, 190u8, 101u8, 81u8, 65u8, 238u8, 174u8, 204u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + fee: topics.1, + tickSpacing: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.fee.clone(), + self.tickSpacing.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.fee); + out[2usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tickSpacing); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for FeeAmountEnabled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&FeeAmountEnabled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &FeeAmountEnabled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OwnerChanged(address,address)` and selector `0xb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c`. + ```solidity + event OwnerChanged(address indexed oldOwner, address indexed newOwner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OwnerChanged { + #[allow(missing_docs)] + pub oldOwner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub newOwner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OwnerChanged { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OwnerChanged(address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 181u8, 50u8, 7u8, 59u8, 56u8, 200u8, 49u8, 69u8, 227u8, 229u8, 19u8, 83u8, + 119u8, 160u8, 139u8, 249u8, 170u8, 181u8, 91u8, 192u8, 253u8, 124u8, 17u8, + 121u8, 205u8, 79u8, 185u8, 149u8, 210u8, 165u8, 21u8, 156u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + oldOwner: topics.1, + newOwner: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.oldOwner.clone(), + self.newOwner.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.oldOwner, + ); + out[2usize] = ::encode_topic( + &self.newOwner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OwnerChanged { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OwnerChanged> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OwnerChanged) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PoolCreated(address,address,uint24,int24,address)` and selector `0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118`. + ```solidity + event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PoolCreated { + #[allow(missing_docs)] + pub token0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token1: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub fee: alloy_sol_types::private::primitives::aliases::U24, + #[allow(missing_docs)] + pub tickSpacing: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PoolCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Address, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<24>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PoolCreated(address,address,uint24,int24,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 120u8, 60u8, 202u8, 28u8, 4u8, 18u8, 221u8, 13u8, 105u8, 94u8, 120u8, 69u8, + 104u8, 201u8, 109u8, 162u8, 233u8, 194u8, 47u8, 249u8, 137u8, 53u8, 122u8, + 46u8, 139u8, 29u8, 155u8, 43u8, 78u8, 107u8, 113u8, 24u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + token0: topics.1, + token1: topics.2, + fee: topics.3, + tickSpacing: data.0, + pool: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.tickSpacing, + ), + ::tokenize( + &self.pool, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.token0.clone(), + self.token1.clone(), + self.fee.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.token0, + ); + out[2usize] = ::encode_topic( + &self.token1, + ); + out[3usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.fee); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PoolCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PoolCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PoolCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPool(address,address,uint24)` and selector `0x1698ee82`. + ```solidity + function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub fee: alloy_sol_types::private::primitives::aliases::U24, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPool(address,address,uint24)`](getPoolCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPoolReturn { + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<24>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U24, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolCall) -> Self { + (value.tokenA, value.tokenB, value.fee) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + fee: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPoolReturn) -> Self { + (value.pool,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPoolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { pool: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPoolCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<24>, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 152u8, 238u8, 130u8]; + const SIGNATURE: &'static str = "getPool(address,address,uint24)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.fee, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getPoolReturn = r.into(); + r.pool + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getPoolReturn = r.into(); + r.pool + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `owner()` and selector `0x8da5cb5b`. + ```solidity + function owner() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`owner()`](ownerCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for ownerCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [141u8, 165u8, 203u8, 91u8]; + const SIGNATURE: &'static str = "owner()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: ownerReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: ownerReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`IUniswapV3Factory`](self) function calls. + #[derive(Clone)] + pub enum IUniswapV3FactoryCalls { + #[allow(missing_docs)] + getPool(getPoolCall), + #[allow(missing_docs)] + owner(ownerCall), + } + impl IUniswapV3FactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[22u8, 152u8, 238u8, 130u8], [141u8, 165u8, 203u8, 91u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = + &[::core::stringify!(getPool), ::core::stringify!(owner)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for IUniswapV3FactoryCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "IUniswapV3FactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::getPool(_) => ::SELECTOR, + Self::owner(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[ + { + fn getPool(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapV3FactoryCalls::getPool) + } + getPool + }, + { + fn owner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IUniswapV3FactoryCalls::owner) + } + owner + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + IUniswapV3FactoryCalls, + >] = &[ + { + fn getPool(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapV3FactoryCalls::getPool) + } + getPool + }, + { + fn owner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IUniswapV3FactoryCalls::owner) + } + owner + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::getPool(inner) => { + ::abi_encoded_size(inner) + } + Self::owner(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::getPool(inner) => { + ::abi_encode_raw(inner, out) + } + Self::owner(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`IUniswapV3Factory`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum IUniswapV3FactoryEvents { + #[allow(missing_docs)] + FeeAmountEnabled(FeeAmountEnabled), + #[allow(missing_docs)] + OwnerChanged(OwnerChanged), + #[allow(missing_docs)] + PoolCreated(PoolCreated), + } + impl IUniswapV3FactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 120u8, 60u8, 202u8, 28u8, 4u8, 18u8, 221u8, 13u8, 105u8, 94u8, 120u8, 69u8, 104u8, + 201u8, 109u8, 162u8, 233u8, 194u8, 47u8, 249u8, 137u8, 53u8, 122u8, 46u8, 139u8, + 29u8, 155u8, 43u8, 78u8, 107u8, 113u8, 24u8, + ], + [ + 181u8, 50u8, 7u8, 59u8, 56u8, 200u8, 49u8, 69u8, 227u8, 229u8, 19u8, 83u8, 119u8, + 160u8, 139u8, 249u8, 170u8, 181u8, 91u8, 192u8, 253u8, 124u8, 17u8, 121u8, 205u8, + 79u8, 185u8, 149u8, 210u8, 165u8, 21u8, 156u8, + ], + [ + 198u8, 106u8, 63u8, 223u8, 7u8, 35u8, 44u8, 221u8, 24u8, 95u8, 235u8, 204u8, 101u8, + 121u8, 212u8, 8u8, 194u8, 65u8, 180u8, 122u8, 226u8, 249u8, 144u8, 125u8, 132u8, + 190u8, 101u8, 81u8, 65u8, 238u8, 174u8, 204u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(PoolCreated), + ::core::stringify!(OwnerChanged), + ::core::stringify!(FeeAmountEnabled), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for IUniswapV3FactoryEvents { + const COUNT: usize = 3usize; + const NAME: &'static str = "IUniswapV3FactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::FeeAmountEnabled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OwnerChanged) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PoolCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for IUniswapV3FactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::FeeAmountEnabled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OwnerChanged(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::FeeAmountEnabled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OwnerChanged(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PoolCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IUniswapV3Factory`](self) contract instance. + + See the [wrapper's documentation](`IUniswapV3FactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IUniswapV3FactoryInstance { + IUniswapV3FactoryInstance::::new(address, __provider) + } + /**A [`IUniswapV3Factory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IUniswapV3Factory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IUniswapV3FactoryInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IUniswapV3FactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IUniswapV3FactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IUniswapV3FactoryInstance + { + /**Creates a new wrapper around an on-chain [`IUniswapV3Factory`](self) contract instance. + + See the [wrapper's documentation](`IUniswapV3FactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IUniswapV3FactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IUniswapV3FactoryInstance { + IUniswapV3FactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IUniswapV3FactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`getPool`] function. + pub fn getPool( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + fee: alloy_sol_types::private::primitives::aliases::U24, + ) -> alloy_contract::SolCallBuilder<&P, getPoolCall, N> { + self.call_builder(&getPoolCall { + tokenA, + tokenB, + fee, + }) + } + + ///Creates a new call builder for the [`owner`] function. + pub fn owner(&self) -> alloy_contract::SolCallBuilder<&P, ownerCall, N> { + self.call_builder(&ownerCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IUniswapV3FactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`FeeAmountEnabled`] event. + pub fn FeeAmountEnabled_filter(&self) -> alloy_contract::Event<&P, FeeAmountEnabled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OwnerChanged`] event. + pub fn OwnerChanged_filter(&self) -> alloy_contract::Event<&P, OwnerChanged, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PoolCreated`] event. + pub fn PoolCreated_filter(&self) -> alloy_contract::Event<&P, PoolCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = IUniswapV3Factory::IUniswapV3FactoryInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x1F98431c8aD98523631AE4a59f267346ea31F984"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x1F98431c8aD98523631AE4a59f267346ea31F984"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xe32F7dD7e3f098D518ff19A22d5f028e076489B1"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x1F98431c8aD98523631AE4a59f267346ea31F984"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x33128a8fC17869897dcE68Ed026d694621f6FDfD"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0xcb2436774C3e191c85056d248EF4260ce5f27A9D"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x1F98431c8aD98523631AE4a59f267346ea31F984"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x640887A9ba3A9C53Ed27D0F7e8246A4F933f3424"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x1F98431c8aD98523631AE4a59f267346ea31F984"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/izeroex/Cargo.toml b/contracts/generated/contracts-generated/izeroex/Cargo.toml new file mode 100644 index 0000000000..394a6db115 --- /dev/null +++ b/contracts/generated/contracts-generated/izeroex/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-izeroex" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/izeroex/src/lib.rs b/contracts/generated/contracts-generated/izeroex/src/lib.rs new file mode 100644 index 0000000000..05d2728ef7 --- /dev/null +++ b/contracts/generated/contracts-generated/izeroex/src/lib.rs @@ -0,0 +1,8342 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library LibNFTOrder { + type TradeDirection is uint8; + struct Fee { address recipient; uint256 amount; bytes feeData; } + struct Property { address propertyValidator; bytes propertyData; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod LibNFTOrder { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct TradeDirection(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl TradeDirection { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for TradeDirection { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: TradeDirection) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for TradeDirection { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for TradeDirection { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Fee { address recipient; uint256 amount; bytes feeData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Fee { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub feeData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Fee) -> Self { + (value.recipient, value.amount, value.feeData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Fee { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount: tuple.1, + feeData: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Fee { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Fee { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ::tokenize( + &self.feeData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Fee { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Fee { + const NAME: &'static str = "Fee"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Fee(address recipient,uint256 amount,bytes feeData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.recipient, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ::eip712_data_word( + &self.feeData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Fee { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.recipient, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + ::topic_preimage_length( + &rust.feeData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.recipient, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + ::encode_topic_preimage( + &rust.feeData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Property { address propertyValidator; bytes propertyData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Property { + #[allow(missing_docs)] + pub propertyValidator: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub propertyData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Property) -> Self { + (value.propertyValidator, value.propertyData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Property { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + propertyValidator: tuple.0, + propertyData: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Property { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Property { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.propertyValidator, + ), + ::tokenize( + &self.propertyData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Property { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Property { + const NAME: &'static str = "Property"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Property(address propertyValidator,bytes propertyData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.propertyValidator, + ) + .0, + ::eip712_data_word( + &self.propertyData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Property { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.propertyValidator, + ) + + ::topic_preimage_length( + &rust.propertyData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.propertyValidator, + out, + ); + ::encode_topic_preimage( + &rust.propertyData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`LibNFTOrder`](self) contract instance. + + See the [wrapper's documentation](`LibNFTOrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> LibNFTOrderInstance { + LibNFTOrderInstance::::new(address, __provider) + } + /**A [`LibNFTOrder`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`LibNFTOrder`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct LibNFTOrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for LibNFTOrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("LibNFTOrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + LibNFTOrderInstance + { + /**Creates a new wrapper around an on-chain [`LibNFTOrder`](self) contract instance. + + See the [wrapper's documentation](`LibNFTOrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl LibNFTOrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> LibNFTOrderInstance { + LibNFTOrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + LibNFTOrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + LibNFTOrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library LibNativeOrder { + type OrderStatus is uint8; + struct LimitOrder { address makerToken; address takerToken; uint128 makerAmount; uint128 takerAmount; uint128 takerTokenFeeAmount; address maker; address taker; address sender; address feeRecipient; bytes32 pool; uint64 expiry; uint256 salt; } + struct OrderInfo { bytes32 orderHash; OrderStatus status; uint128 takerTokenFilledAmount; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod LibNativeOrder { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderStatus(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl OrderStatus { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for OrderStatus { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: OrderStatus) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for OrderStatus { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for OrderStatus { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct LimitOrder { address makerToken; address takerToken; uint128 makerAmount; uint128 takerAmount; uint128 takerTokenFeeAmount; address maker; address taker; address sender; address feeRecipient; bytes32 pool; uint64 expiry; uint256 salt; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct LimitOrder { + #[allow(missing_docs)] + pub makerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub makerAmount: u128, + #[allow(missing_docs)] + pub takerAmount: u128, + #[allow(missing_docs)] + pub takerTokenFeeAmount: u128, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub feeRecipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub expiry: u64, + #[allow(missing_docs)] + pub salt: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Uint<64>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + u128, + u128, + u128, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::FixedBytes<32>, + u64, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: LimitOrder) -> Self { + ( + value.makerToken, + value.takerToken, + value.makerAmount, + value.takerAmount, + value.takerTokenFeeAmount, + value.maker, + value.taker, + value.sender, + value.feeRecipient, + value.pool, + value.expiry, + value.salt, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for LimitOrder { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + makerToken: tuple.0, + takerToken: tuple.1, + makerAmount: tuple.2, + takerAmount: tuple.3, + takerTokenFeeAmount: tuple.4, + maker: tuple.5, + taker: tuple.6, + sender: tuple.7, + feeRecipient: tuple.8, + pool: tuple.9, + expiry: tuple.10, + salt: tuple.11, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for LimitOrder { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for LimitOrder { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.makerToken, + ), + ::tokenize( + &self.takerToken, + ), + as alloy_sol_types::SolType>::tokenize(&self.makerAmount), + as alloy_sol_types::SolType>::tokenize(&self.takerAmount), + as alloy_sol_types::SolType>::tokenize(&self.takerTokenFeeAmount), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + ::tokenize( + &self.sender, + ), + ::tokenize( + &self.feeRecipient, + ), + as alloy_sol_types::SolType>::tokenize(&self.pool), + as alloy_sol_types::SolType>::tokenize(&self.expiry), + as alloy_sol_types::SolType>::tokenize(&self.salt), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for LimitOrder { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for LimitOrder { + const NAME: &'static str = "LimitOrder"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "LimitOrder(address makerToken,address takerToken,uint128 makerAmount,uint128 \ + takerAmount,uint128 takerTokenFeeAmount,address maker,address taker,address \ + sender,address feeRecipient,bytes32 pool,uint64 expiry,uint256 salt)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.makerToken, + ) + .0, + ::eip712_data_word( + &self.takerToken, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.makerAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.takerAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.takerTokenFeeAmount, + ) + .0, + ::eip712_data_word( + &self.maker, + ) + .0, + ::eip712_data_word( + &self.taker, + ) + .0, + ::eip712_data_word( + &self.sender, + ) + .0, + ::eip712_data_word( + &self.feeRecipient, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.pool) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.expiry) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.salt) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for LimitOrder { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.makerToken, + ) + + ::topic_preimage_length( + &rust.takerToken, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.makerAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.takerAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.takerTokenFeeAmount, + ) + + ::topic_preimage_length( + &rust.maker, + ) + + ::topic_preimage_length( + &rust.taker, + ) + + ::topic_preimage_length( + &rust.sender, + ) + + ::topic_preimage_length( + &rust.feeRecipient, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.pool) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.expiry, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.salt) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.makerToken, + out, + ); + ::encode_topic_preimage( + &rust.takerToken, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.makerAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.takerAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.takerTokenFeeAmount, + out, + ); + ::encode_topic_preimage( + &rust.maker, + out, + ); + ::encode_topic_preimage( + &rust.taker, + out, + ); + ::encode_topic_preimage( + &rust.sender, + out, + ); + ::encode_topic_preimage( + &rust.feeRecipient, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.pool, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.expiry, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.salt, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct OrderInfo { bytes32 orderHash; OrderStatus status; uint128 takerTokenFilledAmount; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderInfo { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub status: ::RustType, + #[allow(missing_docs)] + pub takerTokenFilledAmount: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + OrderStatus, + alloy_sol_types::sol_data::Uint<128>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + ::RustType, + u128, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderInfo) -> Self { + (value.orderHash, value.status, value.takerTokenFilledAmount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderInfo { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + orderHash: tuple.0, + status: tuple.1, + takerTokenFilledAmount: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for OrderInfo { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for OrderInfo { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ::tokenize(&self.status), + as alloy_sol_types::SolType>::tokenize( + &self.takerTokenFilledAmount, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for OrderInfo { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for OrderInfo { + const NAME: &'static str = "OrderInfo"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "OrderInfo(bytes32 orderHash,uint8 status,uint128 takerTokenFilledAmount)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word(&self.orderHash) + .0, + ::eip712_data_word( + &self.status, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.takerTokenFilledAmount, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for OrderInfo { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.orderHash, + ) + + ::topic_preimage_length( + &rust.status, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.takerTokenFilledAmount, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.orderHash, + out, + ); + ::encode_topic_preimage( + &rust.status, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.takerTokenFilledAmount, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`LibNativeOrder`](self) contract instance. + + See the [wrapper's documentation](`LibNativeOrderInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> LibNativeOrderInstance { + LibNativeOrderInstance::::new(address, __provider) + } + /**A [`LibNativeOrder`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`LibNativeOrder`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct LibNativeOrderInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for LibNativeOrderInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("LibNativeOrderInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + LibNativeOrderInstance + { + /**Creates a new wrapper around an on-chain [`LibNativeOrder`](self) contract instance. + + See the [wrapper's documentation](`LibNativeOrderInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl LibNativeOrderInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> LibNativeOrderInstance { + LibNativeOrderInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + LibNativeOrderInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + LibNativeOrderInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library LibSignature { + type SignatureType is uint8; + struct Signature { SignatureType signatureType; uint8 v; bytes32 r; bytes32 s; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod LibSignature { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SignatureType(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl SignatureType { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for SignatureType { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: SignatureType) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for SignatureType { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for SignatureType { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Signature { SignatureType signatureType; uint8 v; bytes32 r; bytes32 s; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Signature { + #[allow(missing_docs)] + pub signatureType: ::RustType, + #[allow(missing_docs)] + pub v: u8, + #[allow(missing_docs)] + pub r: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + SignatureType, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + u8, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::FixedBytes<32>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Signature) -> Self { + (value.signatureType, value.v, value.r, value.s) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Signature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + signatureType: tuple.0, + v: tuple.1, + r: tuple.2, + s: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Signature { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Signature { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.signatureType, + ), + as alloy_sol_types::SolType>::tokenize(&self.v), + as alloy_sol_types::SolType>::tokenize(&self.r), + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Signature { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Signature { + const NAME: &'static str = "Signature"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Signature(uint8 signatureType,uint8 v,bytes32 r,bytes32 s)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.signatureType, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.v) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.r) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.s) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Signature { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.signatureType, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.v) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.r) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.s) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.signatureType, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage(&rust.v, out); + as alloy_sol_types::EventTopic>::encode_topic_preimage(&rust.r, out); + as alloy_sol_types::EventTopic>::encode_topic_preimage(&rust.s, out); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`LibSignature`](self) contract instance. + + See the [wrapper's documentation](`LibSignatureInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> LibSignatureInstance { + LibSignatureInstance::::new(address, __provider) + } + /**A [`LibSignature`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`LibSignature`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct LibSignatureInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for LibSignatureInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("LibSignatureInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + LibSignatureInstance + { + /**Creates a new wrapper around an on-chain [`LibSignature`](self) contract instance. + + See the [wrapper's documentation](`LibSignatureInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl LibSignatureInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> LibSignatureInstance { + LibSignatureInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + LibSignatureInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + LibSignatureInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library LibNFTOrder { + type TradeDirection is uint8; + struct Fee { + address recipient; + uint256 amount; + bytes feeData; + } + struct Property { + address propertyValidator; + bytes propertyData; + } +} + +library LibNativeOrder { + type OrderStatus is uint8; + struct LimitOrder { + address makerToken; + address takerToken; + uint128 makerAmount; + uint128 takerAmount; + uint128 takerTokenFeeAmount; + address maker; + address taker; + address sender; + address feeRecipient; + bytes32 pool; + uint64 expiry; + uint256 salt; + } + struct OrderInfo { + bytes32 orderHash; + OrderStatus status; + uint128 takerTokenFilledAmount; + } +} + +library LibSignature { + type SignatureType is uint8; + struct Signature { + SignatureType signatureType; + uint8 v; + bytes32 r; + bytes32 s; + } +} + +interface IZeroex { + event ERC1155OrderCancelled(address maker, uint256 nonce); + event ERC1155OrderFilled(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 nonce, address erc20Token, uint256 erc20FillAmount, address erc1155Token, uint256 erc1155TokenId, uint128 erc1155FillAmount, address matcher); + event ERC1155OrderPreSigned(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 expiry, uint256 nonce, address erc20Token, uint256 erc20TokenAmount, LibNFTOrder.Fee[] fees, address erc1155Token, uint256 erc1155TokenId, LibNFTOrder.Property[] erc1155TokenProperties, uint128 erc1155TokenAmount); + event ERC721OrderCancelled(address maker, uint256 nonce); + event ERC721OrderFilled(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 nonce, address erc20Token, uint256 erc20TokenAmount, address erc721Token, uint256 erc721TokenId, address matcher); + event ERC721OrderPreSigned(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 expiry, uint256 nonce, address erc20Token, uint256 erc20TokenAmount, LibNFTOrder.Fee[] fees, address erc721Token, uint256 erc721TokenId, LibNFTOrder.Property[] erc721TokenProperties); + event LimitOrderFilled(bytes32 orderHash, address maker, address taker, address feeRecipient, address makerToken, address takerToken, uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount, uint128 takerTokenFeeFilledAmount, uint256 protocolFeePaid, bytes32 pool); + event LiquidityProviderSwap(address inputToken, address outputToken, uint256 inputTokenAmount, uint256 outputTokenAmount, address provider, address recipient); + event MetaTransactionExecuted(bytes32 hash, bytes4 indexed selector, address signer, address sender); + event Migrated(address caller, address migrator, address newOwner); + event OrderCancelled(bytes32 orderHash, address maker); + event OrderSignerRegistered(address maker, address signer, bool allowed); + event OtcOrderFilled(bytes32 orderHash, address maker, address taker, address makerToken, address takerToken, uint128 makerTokenFilledAmount, uint128 takerTokenFilledAmount); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event PairCancelledLimitOrders(address maker, address makerToken, address takerToken, uint256 minValidSalt); + event PairCancelledRfqOrders(address maker, address makerToken, address takerToken, uint256 minValidSalt); + event ProxyFunctionUpdated(bytes4 indexed selector, address oldImpl, address newImpl); + event QuoteSignerUpdated(address quoteSigner); + event RfqOrderFilled(bytes32 orderHash, address maker, address taker, address makerToken, address takerToken, uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount, bytes32 pool); + event RfqOrderOriginsAllowed(address origin, address[] addrs, bool allowed); + event TransformedERC20(address indexed taker, address inputToken, address outputToken, uint256 inputTokenAmount, uint256 outputTokenAmount); + event TransformerDeployerUpdated(address transformerDeployer); + + function extend(bytes4 selector, address impl) external; + function fillOrKillLimitOrder(LibNativeOrder.LimitOrder memory order, LibSignature.Signature memory signature, uint128 takerTokenFillAmount) external payable returns (uint128 makerTokenFilledAmount); + function getLimitOrderRelevantState(LibNativeOrder.LimitOrder memory order, LibSignature.Signature memory signature) external view returns (LibNativeOrder.OrderInfo memory orderInfo, uint128 actualFillableTakerTokenAmount, bool isSignatureValid); + function owner() external view returns (address ownerAddress); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "extend", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "internalType": "bytes4" + }, + { + "name": "impl", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "fillOrKillLimitOrder", + "inputs": [ + { + "name": "order", + "type": "tuple", + "internalType": "struct LibNativeOrder.LimitOrder", + "components": [ + { + "name": "makerToken", + "type": "address", + "internalType": "contract IERC20TokenV06" + }, + { + "name": "takerToken", + "type": "address", + "internalType": "contract IERC20TokenV06" + }, + { + "name": "makerAmount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "takerAmount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "takerTokenFeeAmount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "maker", + "type": "address", + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "feeRecipient", + "type": "address", + "internalType": "address" + }, + { + "name": "pool", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "expiry", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "salt", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "signature", + "type": "tuple", + "internalType": "struct LibSignature.Signature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum LibSignature.SignatureType" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "takerTokenFillAmount", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [ + { + "name": "makerTokenFilledAmount", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "getLimitOrderRelevantState", + "inputs": [ + { + "name": "order", + "type": "tuple", + "internalType": "struct LibNativeOrder.LimitOrder", + "components": [ + { + "name": "makerToken", + "type": "address", + "internalType": "contract IERC20TokenV06" + }, + { + "name": "takerToken", + "type": "address", + "internalType": "contract IERC20TokenV06" + }, + { + "name": "makerAmount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "takerAmount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "takerTokenFeeAmount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "maker", + "type": "address", + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "feeRecipient", + "type": "address", + "internalType": "address" + }, + { + "name": "pool", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "expiry", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "salt", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "signature", + "type": "tuple", + "internalType": "struct LibSignature.Signature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum LibSignature.SignatureType" + }, + { + "name": "v", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "r", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [ + { + "name": "orderInfo", + "type": "tuple", + "internalType": "struct LibNativeOrder.OrderInfo", + "components": [ + { + "name": "orderHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "status", + "type": "uint8", + "internalType": "enum LibNativeOrder.OrderStatus" + }, + { + "name": "takerTokenFilledAmount", + "type": "uint128", + "internalType": "uint128" + } + ] + }, + { + "name": "actualFillableTakerTokenAmount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "isSignatureValid", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "ownerAddress", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "ERC1155OrderCancelled", + "inputs": [ + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ERC1155OrderFilled", + "inputs": [ + { + "name": "direction", + "type": "uint8", + "indexed": false, + "internalType": "enum LibNFTOrder.TradeDirection" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc20Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC20TokenV06" + }, + { + "name": "erc20FillAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc1155Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC1155Token" + }, + { + "name": "erc1155TokenId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc1155FillAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "matcher", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ERC1155OrderPreSigned", + "inputs": [ + { + "name": "direction", + "type": "uint8", + "indexed": false, + "internalType": "enum LibNFTOrder.TradeDirection" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "expiry", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc20Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC20TokenV06" + }, + { + "name": "erc20TokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "fees", + "type": "tuple[]", + "indexed": false, + "internalType": "struct LibNFTOrder.Fee[]", + "components": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "feeData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc1155Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC1155Token" + }, + { + "name": "erc1155TokenId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc1155TokenProperties", + "type": "tuple[]", + "indexed": false, + "internalType": "struct LibNFTOrder.Property[]", + "components": [ + { + "name": "propertyValidator", + "type": "address", + "internalType": "contract IPropertyValidator" + }, + { + "name": "propertyData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc1155TokenAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ERC721OrderCancelled", + "inputs": [ + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ERC721OrderFilled", + "inputs": [ + { + "name": "direction", + "type": "uint8", + "indexed": false, + "internalType": "enum LibNFTOrder.TradeDirection" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "nonce", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc20Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC20TokenV06" + }, + { + "name": "erc20TokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc721Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC721Token" + }, + { + "name": "erc721TokenId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "matcher", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ERC721OrderPreSigned", + "inputs": [ + { + "name": "direction", + "type": "uint8", + "indexed": false, + "internalType": "enum LibNFTOrder.TradeDirection" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "expiry", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "nonce", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc20Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC20TokenV06" + }, + { + "name": "erc20TokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "fees", + "type": "tuple[]", + "indexed": false, + "internalType": "struct LibNFTOrder.Fee[]", + "components": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "feeData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "erc721Token", + "type": "address", + "indexed": false, + "internalType": "contract IERC721Token" + }, + { + "name": "erc721TokenId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "erc721TokenProperties", + "type": "tuple[]", + "indexed": false, + "internalType": "struct LibNFTOrder.Property[]", + "components": [ + { + "name": "propertyValidator", + "type": "address", + "internalType": "contract IPropertyValidator" + }, + { + "name": "propertyData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LimitOrderFilled", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "feeRecipient", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "makerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "takerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "takerTokenFilledAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "makerTokenFilledAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "takerTokenFeeFilledAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "protocolFeePaid", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "pool", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidityProviderSwap", + "inputs": [ + { + "name": "inputToken", + "type": "address", + "indexed": false, + "internalType": "contract IERC20TokenV06" + }, + { + "name": "outputToken", + "type": "address", + "indexed": false, + "internalType": "contract IERC20TokenV06" + }, + { + "name": "inputTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "outputTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "provider", + "type": "address", + "indexed": false, + "internalType": "contract ILiquidityProvider" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MetaTransactionExecuted", + "inputs": [ + { + "name": "hash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "selector", + "type": "bytes4", + "indexed": true, + "internalType": "bytes4" + }, + { + "name": "signer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Migrated", + "inputs": [ + { + "name": "caller", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "migrator", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OrderCancelled", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OrderSignerRegistered", + "inputs": [ + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "signer", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "allowed", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OtcOrderFilled", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "makerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "takerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "makerTokenFilledAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "takerTokenFilledAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PairCancelledLimitOrders", + "inputs": [ + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "makerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "takerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "minValidSalt", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PairCancelledRfqOrders", + "inputs": [ + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "makerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "takerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "minValidSalt", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProxyFunctionUpdated", + "inputs": [ + { + "name": "selector", + "type": "bytes4", + "indexed": true, + "internalType": "bytes4" + }, + { + "name": "oldImpl", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newImpl", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "QuoteSignerUpdated", + "inputs": [ + { + "name": "quoteSigner", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RfqOrderFilled", + "inputs": [ + { + "name": "orderHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "maker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "taker", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "makerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "takerToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "takerTokenFilledAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "makerTokenFilledAmount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "pool", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RfqOrderOriginsAllowed", + "inputs": [ + { + "name": "origin", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "addrs", + "type": "address[]", + "indexed": false, + "internalType": "address[]" + }, + { + "name": "allowed", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TransformedERC20", + "inputs": [ + { + "name": "taker", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "inputToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "outputToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "inputTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "outputTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TransformerDeployerUpdated", + "inputs": [ + { + "name": "transformerDeployer", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IZeroex { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ERC1155OrderCancelled(address,uint256)` and selector `0x4d5ea7da64f50a4a329921b8d2cab52dff4ebcc58b61d10ff839e28e91445684`. + ```solidity + event ERC1155OrderCancelled(address maker, uint256 nonce); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ERC1155OrderCancelled { + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ERC1155OrderCancelled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ERC1155OrderCancelled(address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 77u8, 94u8, 167u8, 218u8, 100u8, 245u8, 10u8, 74u8, 50u8, 153u8, 33u8, 184u8, + 210u8, 202u8, 181u8, 45u8, 255u8, 78u8, 188u8, 197u8, 139u8, 97u8, 209u8, 15u8, + 248u8, 57u8, 226u8, 142u8, 145u8, 68u8, 86u8, 132u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + maker: data.0, + nonce: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.maker, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC1155OrderCancelled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ERC1155OrderCancelled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ERC1155OrderCancelled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ERC1155OrderFilled(uint8,address,address,uint256,address,uint256,address,uint256,uint128,address)` and selector `0x20cca81b0e269b265b3229d6b537da91ef475ca0ef55caed7dd30731700ba98d`. + ```solidity + event ERC1155OrderFilled(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 nonce, address erc20Token, uint256 erc20FillAmount, address erc1155Token, uint256 erc1155TokenId, uint128 erc1155FillAmount, address matcher); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ERC1155OrderFilled { + #[allow(missing_docs)] + pub direction: ::RustType, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc20Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc20FillAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc1155Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc1155TokenId: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc1155FillAmount: u128, + #[allow(missing_docs)] + pub matcher: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ERC1155OrderFilled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + LibNFTOrder::TradeDirection, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Address, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ERC1155OrderFilled(uint8,address,address,uint256,\ + address,uint256,address,uint256,uint128,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 32u8, 204u8, 168u8, 27u8, 14u8, 38u8, 155u8, 38u8, 91u8, 50u8, 41u8, 214u8, + 181u8, 55u8, 218u8, 145u8, 239u8, 71u8, 92u8, 160u8, 239u8, 85u8, 202u8, 237u8, + 125u8, 211u8, 7u8, 49u8, 112u8, 11u8, 169u8, 141u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + direction: data.0, + maker: data.1, + taker: data.2, + nonce: data.3, + erc20Token: data.4, + erc20FillAmount: data.5, + erc1155Token: data.6, + erc1155TokenId: data.7, + erc1155FillAmount: data.8, + matcher: data.9, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.direction, + ), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ::tokenize( + &self.erc20Token, + ), + as alloy_sol_types::SolType>::tokenize( + &self.erc20FillAmount, + ), + ::tokenize( + &self.erc1155Token, + ), + as alloy_sol_types::SolType>::tokenize( + &self.erc1155TokenId, + ), + as alloy_sol_types::SolType>::tokenize( + &self.erc1155FillAmount, + ), + ::tokenize( + &self.matcher, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC1155OrderFilled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ERC1155OrderFilled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ERC1155OrderFilled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ERC1155OrderPreSigned(uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[],uint128)` and selector `0x5e91ddfeb7bf2e12f7e8ab017d2b63a9217f004a15a53346ad90353ec63d14e4`. + ```solidity + event ERC1155OrderPreSigned(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 expiry, uint256 nonce, address erc20Token, uint256 erc20TokenAmount, LibNFTOrder.Fee[] fees, address erc1155Token, uint256 erc1155TokenId, LibNFTOrder.Property[] erc1155TokenProperties, uint128 erc1155TokenAmount); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ERC1155OrderPreSigned { + #[allow(missing_docs)] + pub direction: ::RustType, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub expiry: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc20Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc20TokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub fees: + alloy_sol_types::private::Vec<::RustType>, + #[allow(missing_docs)] + pub erc1155Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc1155TokenId: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc1155TokenProperties: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub erc1155TokenAmount: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ERC1155OrderPreSigned { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + LibNFTOrder::TradeDirection, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Uint<128>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ERC1155OrderPreSigned(uint8,address,address,uint256,\ + uint256,address,uint256,(address,uint256,bytes)[],\ + address,uint256,(address,bytes)[],uint128)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 94u8, 145u8, 221u8, 254u8, 183u8, 191u8, 46u8, 18u8, 247u8, 232u8, 171u8, 1u8, + 125u8, 43u8, 99u8, 169u8, 33u8, 127u8, 0u8, 74u8, 21u8, 165u8, 51u8, 70u8, + 173u8, 144u8, 53u8, 62u8, 198u8, 61u8, 20u8, 228u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + direction: data.0, + maker: data.1, + taker: data.2, + expiry: data.3, + nonce: data.4, + erc20Token: data.5, + erc20TokenAmount: data.6, + fees: data.7, + erc1155Token: data.8, + erc1155TokenId: data.9, + erc1155TokenProperties: data.10, + erc1155TokenAmount: data.11, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.direction, + ), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + as alloy_sol_types::SolType>::tokenize(&self.expiry), + as alloy_sol_types::SolType>::tokenize(&self.nonce), + ::tokenize( + &self.erc20Token, + ), + as alloy_sol_types::SolType>::tokenize(&self.erc20TokenAmount), + as alloy_sol_types::SolType>::tokenize(&self.fees), + ::tokenize( + &self.erc1155Token, + ), + as alloy_sol_types::SolType>::tokenize(&self.erc1155TokenId), + as alloy_sol_types::SolType>::tokenize( + &self.erc1155TokenProperties, + ), + as alloy_sol_types::SolType>::tokenize(&self.erc1155TokenAmount), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC1155OrderPreSigned { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ERC1155OrderPreSigned> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ERC1155OrderPreSigned) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ERC721OrderCancelled(address,uint256)` and selector `0xa015ad2dc32f266993958a0fd9884c746b971b254206f3478bc43e2f125c7b9e`. + ```solidity + event ERC721OrderCancelled(address maker, uint256 nonce); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ERC721OrderCancelled { + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ERC721OrderCancelled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ERC721OrderCancelled(address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 160u8, 21u8, 173u8, 45u8, 195u8, 47u8, 38u8, 105u8, 147u8, 149u8, 138u8, 15u8, + 217u8, 136u8, 76u8, 116u8, 107u8, 151u8, 27u8, 37u8, 66u8, 6u8, 243u8, 71u8, + 139u8, 196u8, 62u8, 47u8, 18u8, 92u8, 123u8, 158u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + maker: data.0, + nonce: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.maker, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC721OrderCancelled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ERC721OrderCancelled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ERC721OrderCancelled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ERC721OrderFilled(uint8,address,address,uint256,address,uint256,address,uint256,address)` and selector `0x50273fa02273cceea9cf085b42de5c8af60624140168bd71357db833535877af`. + ```solidity + event ERC721OrderFilled(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 nonce, address erc20Token, uint256 erc20TokenAmount, address erc721Token, uint256 erc721TokenId, address matcher); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ERC721OrderFilled { + #[allow(missing_docs)] + pub direction: ::RustType, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc20Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc20TokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc721Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc721TokenId: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub matcher: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ERC721OrderFilled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + LibNFTOrder::TradeDirection, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ERC721OrderFilled(uint8,address,address,uint256,\ + address,uint256,address,uint256,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 80u8, 39u8, 63u8, 160u8, 34u8, 115u8, 204u8, 238u8, 169u8, 207u8, 8u8, 91u8, + 66u8, 222u8, 92u8, 138u8, 246u8, 6u8, 36u8, 20u8, 1u8, 104u8, 189u8, 113u8, + 53u8, 125u8, 184u8, 51u8, 83u8, 88u8, 119u8, 175u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + direction: data.0, + maker: data.1, + taker: data.2, + nonce: data.3, + erc20Token: data.4, + erc20TokenAmount: data.5, + erc721Token: data.6, + erc721TokenId: data.7, + matcher: data.8, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.direction, + ), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ::tokenize( + &self.erc20Token, + ), + as alloy_sol_types::SolType>::tokenize( + &self.erc20TokenAmount, + ), + ::tokenize( + &self.erc721Token, + ), + as alloy_sol_types::SolType>::tokenize( + &self.erc721TokenId, + ), + ::tokenize( + &self.matcher, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC721OrderFilled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ERC721OrderFilled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ERC721OrderFilled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ERC721OrderPreSigned(uint8,address,address,uint256,uint256,address,uint256,(address,uint256,bytes)[],address,uint256,(address,bytes)[])` and selector `0x8c5d0c41fb16a7317a6c55ff7ba93d9d74f79e434fefa694e50d6028afbfa3f0`. + ```solidity + event ERC721OrderPreSigned(LibNFTOrder.TradeDirection direction, address maker, address taker, uint256 expiry, uint256 nonce, address erc20Token, uint256 erc20TokenAmount, LibNFTOrder.Fee[] fees, address erc721Token, uint256 erc721TokenId, LibNFTOrder.Property[] erc721TokenProperties); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ERC721OrderPreSigned { + #[allow(missing_docs)] + pub direction: ::RustType, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub expiry: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc20Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc20TokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub fees: + alloy_sol_types::private::Vec<::RustType>, + #[allow(missing_docs)] + pub erc721Token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub erc721TokenId: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub erc721TokenProperties: alloy_sol_types::private::Vec< + ::RustType, + >, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ERC721OrderPreSigned { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + LibNFTOrder::TradeDirection, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ERC721OrderPreSigned(uint8,address,address,uint256,\ + uint256,address,uint256,(address,uint256,bytes)[],\ + address,uint256,(address,bytes)[])"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 93u8, 12u8, 65u8, 251u8, 22u8, 167u8, 49u8, 122u8, 108u8, 85u8, 255u8, + 123u8, 169u8, 61u8, 157u8, 116u8, 247u8, 158u8, 67u8, 79u8, 239u8, 166u8, + 148u8, 229u8, 13u8, 96u8, 40u8, 175u8, 191u8, 163u8, 240u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + direction: data.0, + maker: data.1, + taker: data.2, + expiry: data.3, + nonce: data.4, + erc20Token: data.5, + erc20TokenAmount: data.6, + fees: data.7, + erc721Token: data.8, + erc721TokenId: data.9, + erc721TokenProperties: data.10, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.direction, + ), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + as alloy_sol_types::SolType>::tokenize(&self.expiry), + as alloy_sol_types::SolType>::tokenize(&self.nonce), + ::tokenize( + &self.erc20Token, + ), + as alloy_sol_types::SolType>::tokenize(&self.erc20TokenAmount), + as alloy_sol_types::SolType>::tokenize(&self.fees), + ::tokenize( + &self.erc721Token, + ), + as alloy_sol_types::SolType>::tokenize(&self.erc721TokenId), + as alloy_sol_types::SolType>::tokenize(&self.erc721TokenProperties), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ERC721OrderPreSigned { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ERC721OrderPreSigned> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ERC721OrderPreSigned) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `LimitOrderFilled(bytes32,address,address,address,address,address,uint128,uint128,uint128,uint256,bytes32)` and selector `0xab614d2b738543c0ea21f56347cf696a3a0c42a7cbec3212a5ca22a4dcff2124`. + ```solidity + event LimitOrderFilled(bytes32 orderHash, address maker, address taker, address feeRecipient, address makerToken, address takerToken, uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount, uint128 takerTokenFeeFilledAmount, uint256 protocolFeePaid, bytes32 pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct LimitOrderFilled { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub feeRecipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub makerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerTokenFilledAmount: u128, + #[allow(missing_docs)] + pub makerTokenFilledAmount: u128, + #[allow(missing_docs)] + pub takerTokenFeeFilledAmount: u128, + #[allow(missing_docs)] + pub protocolFeePaid: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for LimitOrderFilled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "LimitOrderFilled(bytes32,address,address,address,\ + address,address,uint128,uint128,uint128,uint256,\ + bytes32)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 171u8, 97u8, 77u8, 43u8, 115u8, 133u8, 67u8, 192u8, 234u8, 33u8, 245u8, 99u8, + 71u8, 207u8, 105u8, 106u8, 58u8, 12u8, 66u8, 167u8, 203u8, 236u8, 50u8, 18u8, + 165u8, 202u8, 34u8, 164u8, 220u8, 255u8, 33u8, 36u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + orderHash: data.0, + maker: data.1, + taker: data.2, + feeRecipient: data.3, + makerToken: data.4, + takerToken: data.5, + takerTokenFilledAmount: data.6, + makerTokenFilledAmount: data.7, + takerTokenFeeFilledAmount: data.8, + protocolFeePaid: data.9, + pool: data.10, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + ::tokenize( + &self.feeRecipient, + ), + ::tokenize( + &self.makerToken, + ), + ::tokenize( + &self.takerToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.takerTokenFilledAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.makerTokenFilledAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.takerTokenFeeFilledAmount, + ), + as alloy_sol_types::SolType>::tokenize(&self.protocolFeePaid), + as alloy_sol_types::SolType>::tokenize(&self.pool), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for LimitOrderFilled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&LimitOrderFilled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &LimitOrderFilled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `LiquidityProviderSwap(address,address,uint256,uint256,address,address)` and selector `0x40a6ba9513d09e3488135e0e0d10e2d4382b792720155b144cbea89ac9db6d34`. + ```solidity + event LiquidityProviderSwap(address inputToken, address outputToken, uint256 inputTokenAmount, uint256 outputTokenAmount, address provider, address recipient); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct LiquidityProviderSwap { + #[allow(missing_docs)] + pub inputToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub outputToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub inputTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub outputTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub provider: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for LiquidityProviderSwap { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "LiquidityProviderSwap(address,address,uint256,uint256,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 64u8, 166u8, 186u8, 149u8, 19u8, 208u8, 158u8, 52u8, 136u8, 19u8, 94u8, 14u8, + 13u8, 16u8, 226u8, 212u8, 56u8, 43u8, 121u8, 39u8, 32u8, 21u8, 91u8, 20u8, + 76u8, 190u8, 168u8, 154u8, 201u8, 219u8, 109u8, 52u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + inputToken: data.0, + outputToken: data.1, + inputTokenAmount: data.2, + outputTokenAmount: data.3, + provider: data.4, + recipient: data.5, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.inputToken, + ), + ::tokenize( + &self.outputToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.inputTokenAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.outputTokenAmount, + ), + ::tokenize( + &self.provider, + ), + ::tokenize( + &self.recipient, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for LiquidityProviderSwap { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&LiquidityProviderSwap> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &LiquidityProviderSwap) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `MetaTransactionExecuted(bytes32,bytes4,address,address)` and selector `0x7f4fe3ff8ae440e1570c558da08440b26f89fb1c1f2910cd91ca6452955f121a`. + ```solidity + event MetaTransactionExecuted(bytes32 hash, bytes4 indexed selector, address signer, address sender); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct MetaTransactionExecuted { + #[allow(missing_docs)] + pub hash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub selector: alloy_sol_types::private::FixedBytes<4>, + #[allow(missing_docs)] + pub signer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for MetaTransactionExecuted { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<4>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "MetaTransactionExecuted(bytes32,bytes4,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 127u8, 79u8, 227u8, 255u8, 138u8, 228u8, 64u8, 225u8, 87u8, 12u8, 85u8, 141u8, + 160u8, 132u8, 64u8, 178u8, 111u8, 137u8, 251u8, 28u8, 31u8, 41u8, 16u8, 205u8, + 145u8, 202u8, 100u8, 82u8, 149u8, 95u8, 18u8, 26u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + hash: data.0, + selector: topics.1, + signer: data.1, + sender: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.hash), + ::tokenize( + &self.signer, + ), + ::tokenize( + &self.sender, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.selector.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.selector); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for MetaTransactionExecuted { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&MetaTransactionExecuted> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &MetaTransactionExecuted) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Migrated(address,address,address)` and selector `0xe1b831b0e6f3aa16b4b1a6bd526b5cdeab4940744ca6e0251f5fe5f8caf1c81a`. + ```solidity + event Migrated(address caller, address migrator, address newOwner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Migrated { + #[allow(missing_docs)] + pub caller: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub migrator: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub newOwner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Migrated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Migrated(address,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 225u8, 184u8, 49u8, 176u8, 230u8, 243u8, 170u8, 22u8, 180u8, 177u8, 166u8, + 189u8, 82u8, 107u8, 92u8, 222u8, 171u8, 73u8, 64u8, 116u8, 76u8, 166u8, 224u8, + 37u8, 31u8, 95u8, 229u8, 248u8, 202u8, 241u8, 200u8, 26u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + caller: data.0, + migrator: data.1, + newOwner: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.caller, + ), + ::tokenize( + &self.migrator, + ), + ::tokenize( + &self.newOwner, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Migrated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Migrated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Migrated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OrderCancelled(bytes32,address)` and selector `0xa6eb7cdc219e1518ced964e9a34e61d68a94e4f1569db3e84256ba981ba52753`. + ```solidity + event OrderCancelled(bytes32 orderHash, address maker); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderCancelled { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderCancelled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderCancelled(bytes32,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 166u8, 235u8, 124u8, 220u8, 33u8, 158u8, 21u8, 24u8, 206u8, 217u8, 100u8, + 233u8, 163u8, 78u8, 97u8, 214u8, 138u8, 148u8, 228u8, 241u8, 86u8, 157u8, + 179u8, 232u8, 66u8, 86u8, 186u8, 152u8, 27u8, 165u8, 39u8, 83u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + orderHash: data.0, + maker: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ::tokenize( + &self.maker, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderCancelled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderCancelled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderCancelled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OrderSignerRegistered(address,address,bool)` and selector `0x6ea9dbe8b2cc119348716a9220a0742ad62b7884ecb0ff4b32cd508121fd9379`. + ```solidity + event OrderSignerRegistered(address maker, address signer, bool allowed); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OrderSignerRegistered { + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub signer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub allowed: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OrderSignerRegistered { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OrderSignerRegistered(address,address,bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 110u8, 169u8, 219u8, 232u8, 178u8, 204u8, 17u8, 147u8, 72u8, 113u8, 106u8, + 146u8, 32u8, 160u8, 116u8, 42u8, 214u8, 43u8, 120u8, 132u8, 236u8, 176u8, + 255u8, 75u8, 50u8, 205u8, 80u8, 129u8, 33u8, 253u8, 147u8, 121u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + maker: data.0, + signer: data.1, + allowed: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.signer, + ), + ::tokenize( + &self.allowed, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OrderSignerRegistered { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OrderSignerRegistered> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OrderSignerRegistered) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OtcOrderFilled(bytes32,address,address,address,address,uint128,uint128)` and selector `0xac75f773e3a92f1a02b12134d65e1f47f8a14eabe4eaf1e24624918e6a8b269f`. + ```solidity + event OtcOrderFilled(bytes32 orderHash, address maker, address taker, address makerToken, address takerToken, uint128 makerTokenFilledAmount, uint128 takerTokenFilledAmount); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OtcOrderFilled { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub makerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub makerTokenFilledAmount: u128, + #[allow(missing_docs)] + pub takerTokenFilledAmount: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OtcOrderFilled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "OtcOrderFilled(bytes32,address,address,address,address,uint128,uint128)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 172u8, 117u8, 247u8, 115u8, 227u8, 169u8, 47u8, 26u8, 2u8, 177u8, 33u8, 52u8, + 214u8, 94u8, 31u8, 71u8, 248u8, 161u8, 78u8, 171u8, 228u8, 234u8, 241u8, 226u8, + 70u8, 36u8, 145u8, 142u8, 106u8, 139u8, 38u8, 159u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + orderHash: data.0, + maker: data.1, + taker: data.2, + makerToken: data.3, + takerToken: data.4, + makerTokenFilledAmount: data.5, + takerTokenFilledAmount: data.6, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + ::tokenize( + &self.makerToken, + ), + ::tokenize( + &self.takerToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.makerTokenFilledAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.takerTokenFilledAmount, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OtcOrderFilled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OtcOrderFilled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OtcOrderFilled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `OwnershipTransferred(address,address)` and selector `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0`. + ```solidity + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct OwnershipTransferred { + #[allow(missing_docs)] + pub previousOwner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub newOwner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for OwnershipTransferred { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "OwnershipTransferred(address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 139u8, 224u8, 7u8, 156u8, 83u8, 22u8, 89u8, 20u8, 19u8, 68u8, 205u8, 31u8, + 208u8, 164u8, 242u8, 132u8, 25u8, 73u8, 127u8, 151u8, 34u8, 163u8, 218u8, + 175u8, 227u8, 180u8, 24u8, 111u8, 107u8, 100u8, 87u8, 224u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + previousOwner: topics.1, + newOwner: topics.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.previousOwner.clone(), + self.newOwner.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.previousOwner, + ); + out[2usize] = ::encode_topic( + &self.newOwner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for OwnershipTransferred { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&OwnershipTransferred> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &OwnershipTransferred) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PairCancelledLimitOrders(address,address,address,uint256)` and selector `0xa91fe7ae62fce669df2c7f880f8c14d178531aae72515558e5c948e37c32a572`. + ```solidity + event PairCancelledLimitOrders(address maker, address makerToken, address takerToken, uint256 minValidSalt); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PairCancelledLimitOrders { + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub makerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub minValidSalt: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PairCancelledLimitOrders { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "PairCancelledLimitOrders(address,address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 169u8, 31u8, 231u8, 174u8, 98u8, 252u8, 230u8, 105u8, 223u8, 44u8, 127u8, + 136u8, 15u8, 140u8, 20u8, 209u8, 120u8, 83u8, 26u8, 174u8, 114u8, 81u8, 85u8, + 88u8, 229u8, 201u8, 72u8, 227u8, 124u8, 50u8, 165u8, 114u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + maker: data.0, + makerToken: data.1, + takerToken: data.2, + minValidSalt: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.makerToken, + ), + ::tokenize( + &self.takerToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.minValidSalt, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PairCancelledLimitOrders { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PairCancelledLimitOrders> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PairCancelledLimitOrders) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PairCancelledRfqOrders(address,address,address,uint256)` and selector `0xfe7ffb1edfe79f4df716cb2dcad21cf2f31b104d816a7976ba1e6e4653c1efb1`. + ```solidity + event PairCancelledRfqOrders(address maker, address makerToken, address takerToken, uint256 minValidSalt); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PairCancelledRfqOrders { + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub makerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub minValidSalt: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PairCancelledRfqOrders { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "PairCancelledRfqOrders(address,address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 254u8, 127u8, 251u8, 30u8, 223u8, 231u8, 159u8, 77u8, 247u8, 22u8, 203u8, 45u8, + 202u8, 210u8, 28u8, 242u8, 243u8, 27u8, 16u8, 77u8, 129u8, 106u8, 121u8, 118u8, + 186u8, 30u8, 110u8, 70u8, 83u8, 193u8, 239u8, 177u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + maker: data.0, + makerToken: data.1, + takerToken: data.2, + minValidSalt: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.makerToken, + ), + ::tokenize( + &self.takerToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.minValidSalt, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PairCancelledRfqOrders { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PairCancelledRfqOrders> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PairCancelledRfqOrders) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ProxyFunctionUpdated(bytes4,address,address)` and selector `0x2ae221083467de52078b0096696ab88d8d53a7ecb44bb65b56a2bab687598367`. + ```solidity + event ProxyFunctionUpdated(bytes4 indexed selector, address oldImpl, address newImpl); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ProxyFunctionUpdated { + #[allow(missing_docs)] + pub selector: alloy_sol_types::private::FixedBytes<4>, + #[allow(missing_docs)] + pub oldImpl: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub newImpl: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ProxyFunctionUpdated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<4>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "ProxyFunctionUpdated(bytes4,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 42u8, 226u8, 33u8, 8u8, 52u8, 103u8, 222u8, 82u8, 7u8, 139u8, 0u8, 150u8, + 105u8, 106u8, 184u8, 141u8, 141u8, 83u8, 167u8, 236u8, 180u8, 75u8, 182u8, + 91u8, 86u8, 162u8, 186u8, 182u8, 135u8, 89u8, 131u8, 103u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + selector: topics.1, + oldImpl: data.0, + newImpl: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.oldImpl, + ), + ::tokenize( + &self.newImpl, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.selector.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.selector); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ProxyFunctionUpdated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ProxyFunctionUpdated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ProxyFunctionUpdated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `QuoteSignerUpdated(address)` and selector `0xf5550c5eea19b48ac6eb5f03abdc4f59c0a60697abb3d973cd68669703b5c8b9`. + ```solidity + event QuoteSignerUpdated(address quoteSigner); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct QuoteSignerUpdated { + #[allow(missing_docs)] + pub quoteSigner: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for QuoteSignerUpdated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "QuoteSignerUpdated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 245u8, 85u8, 12u8, 94u8, 234u8, 25u8, 180u8, 138u8, 198u8, 235u8, 95u8, 3u8, + 171u8, 220u8, 79u8, 89u8, 192u8, 166u8, 6u8, 151u8, 171u8, 179u8, 217u8, 115u8, + 205u8, 104u8, 102u8, 151u8, 3u8, 181u8, 200u8, 185u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + quoteSigner: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.quoteSigner, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for QuoteSignerUpdated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&QuoteSignerUpdated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &QuoteSignerUpdated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `RfqOrderFilled(bytes32,address,address,address,address,uint128,uint128,bytes32)` and selector `0x829fa99d94dc4636925b38632e625736a614c154d55006b7ab6bea979c210c32`. + ```solidity + event RfqOrderFilled(bytes32 orderHash, address maker, address taker, address makerToken, address takerToken, uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount, bytes32 pool); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct RfqOrderFilled { + #[allow(missing_docs)] + pub orderHash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub maker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub makerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub takerTokenFilledAmount: u128, + #[allow(missing_docs)] + pub makerTokenFilledAmount: u128, + #[allow(missing_docs)] + pub pool: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RfqOrderFilled { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "RfqOrderFilled(bytes32,address,address,address,address,uint128,uint128,bytes32)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 130u8, 159u8, 169u8, 157u8, 148u8, 220u8, 70u8, 54u8, 146u8, 91u8, 56u8, 99u8, + 46u8, 98u8, 87u8, 54u8, 166u8, 20u8, 193u8, 84u8, 213u8, 80u8, 6u8, 183u8, + 171u8, 107u8, 234u8, 151u8, 156u8, 33u8, 12u8, 50u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + orderHash: data.0, + maker: data.1, + taker: data.2, + makerToken: data.3, + takerToken: data.4, + takerTokenFilledAmount: data.5, + makerTokenFilledAmount: data.6, + pool: data.7, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.orderHash), + ::tokenize( + &self.maker, + ), + ::tokenize( + &self.taker, + ), + ::tokenize( + &self.makerToken, + ), + ::tokenize( + &self.takerToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.takerTokenFilledAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.makerTokenFilledAmount, + ), + as alloy_sol_types::SolType>::tokenize(&self.pool), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RfqOrderFilled { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RfqOrderFilled> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RfqOrderFilled) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `RfqOrderOriginsAllowed(address,address[],bool)` and selector `0x02dfead5eb769b298e82dd9650b31c40559a3d42701dbf53c931bc2682847c31`. + ```solidity + event RfqOrderOriginsAllowed(address origin, address[] addrs, bool allowed); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct RfqOrderOriginsAllowed { + #[allow(missing_docs)] + pub origin: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub addrs: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub allowed: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for RfqOrderOriginsAllowed { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Bool, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "RfqOrderOriginsAllowed(address,address[],bool)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 2u8, 223u8, 234u8, 213u8, 235u8, 118u8, 155u8, 41u8, 142u8, 130u8, 221u8, + 150u8, 80u8, 179u8, 28u8, 64u8, 85u8, 154u8, 61u8, 66u8, 112u8, 29u8, 191u8, + 83u8, 201u8, 49u8, 188u8, 38u8, 130u8, 132u8, 124u8, 49u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + origin: data.0, + addrs: data.1, + allowed: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.origin, + ), + as alloy_sol_types::SolType>::tokenize(&self.addrs), + ::tokenize( + &self.allowed, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for RfqOrderOriginsAllowed { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&RfqOrderOriginsAllowed> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &RfqOrderOriginsAllowed) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TransformedERC20(address,address,address,uint256,uint256)` and selector `0x0f6672f78a59ba8e5e5b5d38df3ebc67f3c792e2c9259b8d97d7f00dd78ba1b3`. + ```solidity + event TransformedERC20(address indexed taker, address inputToken, address outputToken, uint256 inputTokenAmount, uint256 outputTokenAmount); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TransformedERC20 { + #[allow(missing_docs)] + pub taker: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub inputToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub outputToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub inputTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub outputTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TransformedERC20 { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "TransformedERC20(address,address,address,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 15u8, 102u8, 114u8, 247u8, 138u8, 89u8, 186u8, 142u8, 94u8, 91u8, 93u8, 56u8, + 223u8, 62u8, 188u8, 103u8, 243u8, 199u8, 146u8, 226u8, 201u8, 37u8, 155u8, + 141u8, 151u8, 215u8, 240u8, 13u8, 215u8, 139u8, 161u8, 179u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + taker: topics.1, + inputToken: data.0, + outputToken: data.1, + inputTokenAmount: data.2, + outputTokenAmount: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.inputToken, + ), + ::tokenize( + &self.outputToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.inputTokenAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.outputTokenAmount, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.taker.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.taker, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TransformedERC20 { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TransformedERC20> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TransformedERC20) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TransformerDeployerUpdated(address)` and selector `0xfd45604abad79c16e23348a137ed8292661be1b8eba6e4806ebed6833b1c046a`. + ```solidity + event TransformerDeployerUpdated(address transformerDeployer); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TransformerDeployerUpdated { + #[allow(missing_docs)] + pub transformerDeployer: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TransformerDeployerUpdated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Address,); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "TransformerDeployerUpdated(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 253u8, 69u8, 96u8, 74u8, 186u8, 215u8, 156u8, 22u8, 226u8, 51u8, 72u8, 161u8, + 55u8, 237u8, 130u8, 146u8, 102u8, 27u8, 225u8, 184u8, 235u8, 166u8, 228u8, + 128u8, 110u8, 190u8, 214u8, 131u8, 59u8, 28u8, 4u8, 106u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + transformerDeployer: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.transformerDeployer, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TransformerDeployerUpdated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TransformerDeployerUpdated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TransformerDeployerUpdated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `extend(bytes4,address)` and selector `0x6eb224cb`. + ```solidity + function extend(bytes4 selector, address r#impl) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct extendCall { + #[allow(missing_docs)] + pub selector: alloy_sol_types::private::FixedBytes<4>, + #[allow(missing_docs)] + pub r#impl: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`extend(bytes4,address)`](extendCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct extendReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<4>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<4>, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: extendCall) -> Self { + (value.selector, value.r#impl) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for extendCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + selector: tuple.0, + r#impl: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: extendReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for extendReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl extendReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for extendCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<4>, + alloy_sol_types::sol_data::Address, + ); + type Return = extendReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [110u8, 178u8, 36u8, 203u8]; + const SIGNATURE: &'static str = "extend(bytes4,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.selector), + ::tokenize( + &self.r#impl, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + extendReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive()] + /**Function with signature `fillOrKillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)` and selector `0x9240529c`. + ```solidity + function fillOrKillLimitOrder(LibNativeOrder.LimitOrder memory order, LibSignature.Signature memory signature, uint128 takerTokenFillAmount) external payable returns (uint128 makerTokenFilledAmount); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct fillOrKillLimitOrderCall { + #[allow(missing_docs)] + pub order: ::RustType, + #[allow(missing_docs)] + pub signature: ::RustType, + #[allow(missing_docs)] + pub takerTokenFillAmount: u128, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`fillOrKillLimitOrder((address,address,uint128,uint128,uint128,address, + /// address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32, + /// bytes32),uint128)`](fillOrKillLimitOrderCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct fillOrKillLimitOrderReturn { + #[allow(missing_docs)] + pub makerTokenFilledAmount: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + LibNativeOrder::LimitOrder, + LibSignature::Signature, + alloy_sol_types::sol_data::Uint<128>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + ::RustType, + u128, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: fillOrKillLimitOrderCall) -> Self { + (value.order, value.signature, value.takerTokenFillAmount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for fillOrKillLimitOrderCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + order: tuple.0, + signature: tuple.1, + takerTokenFillAmount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<128>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u128,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: fillOrKillLimitOrderReturn) -> Self { + (value.makerTokenFilledAmount,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for fillOrKillLimitOrderReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + makerTokenFilledAmount: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for fillOrKillLimitOrderCall { + type Parameters<'a> = ( + LibNativeOrder::LimitOrder, + LibSignature::Signature, + alloy_sol_types::sol_data::Uint<128>, + ); + type Return = u128; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<128>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [146u8, 64u8, 82u8, 156u8]; + const SIGNATURE: &'static str = + "fillOrKillLimitOrder((address,address,uint128,uint128,uint128,address,address,\ + address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize(&self.order), + ::tokenize( + &self.signature, + ), + as alloy_sol_types::SolType>::tokenize( + &self.takerTokenFillAmount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: fillOrKillLimitOrderReturn = r.into(); + r.makerTokenFilledAmount + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: fillOrKillLimitOrderReturn = r.into(); + r.makerTokenFilledAmount + }) + } + } + }; + #[derive()] + /**Function with signature `getLimitOrderRelevantState((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32))` and selector `0x1fb09795`. + ```solidity + function getLimitOrderRelevantState(LibNativeOrder.LimitOrder memory order, LibSignature.Signature memory signature) external view returns (LibNativeOrder.OrderInfo memory orderInfo, uint128 actualFillableTakerTokenAmount, bool isSignatureValid); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getLimitOrderRelevantStateCall { + #[allow(missing_docs)] + pub order: ::RustType, + #[allow(missing_docs)] + pub signature: ::RustType, + } + #[derive()] + ///Container type for the return parameters of the + /// [`getLimitOrderRelevantState((address,address,uint128,uint128,uint128, + /// address,address,address,address,bytes32,uint64,uint256),(uint8,uint8, + /// bytes32,bytes32))`](getLimitOrderRelevantStateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getLimitOrderRelevantStateReturn { + #[allow(missing_docs)] + pub orderInfo: ::RustType, + #[allow(missing_docs)] + pub actualFillableTakerTokenAmount: u128, + #[allow(missing_docs)] + pub isSignatureValid: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (LibNativeOrder::LimitOrder, LibSignature::Signature); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getLimitOrderRelevantStateCall) -> Self { + (value.order, value.signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getLimitOrderRelevantStateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + order: tuple.0, + signature: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + LibNativeOrder::OrderInfo, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + u128, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getLimitOrderRelevantStateReturn) -> Self { + ( + value.orderInfo, + value.actualFillableTakerTokenAmount, + value.isSignatureValid, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getLimitOrderRelevantStateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + orderInfo: tuple.0, + actualFillableTakerTokenAmount: tuple.1, + isSignatureValid: tuple.2, + } + } + } + } + impl getLimitOrderRelevantStateReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> + { + ( + ::tokenize( + &self.orderInfo, + ), + as alloy_sol_types::SolType>::tokenize( + &self.actualFillableTakerTokenAmount, + ), + ::tokenize( + &self.isSignatureValid, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getLimitOrderRelevantStateCall { + type Parameters<'a> = (LibNativeOrder::LimitOrder, LibSignature::Signature); + type Return = getLimitOrderRelevantStateReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + LibNativeOrder::OrderInfo, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Bool, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [31u8, 176u8, 151u8, 149u8]; + const SIGNATURE: &'static str = + "getLimitOrderRelevantState((address,address,uint128,uint128,uint128,address,\ + address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize(&self.order), + ::tokenize( + &self.signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + getLimitOrderRelevantStateReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `owner()` and selector `0x8da5cb5b`. + ```solidity + function owner() external view returns (address ownerAddress); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`owner()`](ownerCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ownerReturn { + #[allow(missing_docs)] + pub ownerAddress: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ownerReturn) -> Self { + (value.ownerAddress,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ownerReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + ownerAddress: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for ownerCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [141u8, 165u8, 203u8, 91u8]; + const SIGNATURE: &'static str = "owner()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: ownerReturn = r.into(); + r.ownerAddress + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: ownerReturn = r.into(); + r.ownerAddress + }) + } + } + }; + ///Container for all the [`IZeroex`](self) function calls. + #[derive(Clone)] + pub enum IZeroexCalls { + #[allow(missing_docs)] + extend(extendCall), + #[allow(missing_docs)] + fillOrKillLimitOrder(fillOrKillLimitOrderCall), + #[allow(missing_docs)] + getLimitOrderRelevantState(getLimitOrderRelevantStateCall), + #[allow(missing_docs)] + owner(ownerCall), + } + impl IZeroexCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [31u8, 176u8, 151u8, 149u8], + [110u8, 178u8, 36u8, 203u8], + [141u8, 165u8, 203u8, 91u8], + [146u8, 64u8, 82u8, 156u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(getLimitOrderRelevantState), + ::core::stringify!(extend), + ::core::stringify!(owner), + ::core::stringify!(fillOrKillLimitOrder), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for IZeroexCalls { + const COUNT: usize = 4usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "IZeroexCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::extend(_) => ::SELECTOR, + Self::fillOrKillLimitOrder(_) => { + ::SELECTOR + } + Self::getLimitOrderRelevantState(_) => { + ::SELECTOR + } + Self::owner(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn getLimitOrderRelevantState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(IZeroexCalls::getLimitOrderRelevantState) + } + getLimitOrderRelevantState + }, + { + fn extend(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IZeroexCalls::extend) + } + extend + }, + { + fn owner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IZeroexCalls::owner) + } + owner + }, + { + fn fillOrKillLimitOrder(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IZeroexCalls::fillOrKillLimitOrder) + } + fillOrKillLimitOrder + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn getLimitOrderRelevantState( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IZeroexCalls::getLimitOrderRelevantState) + } + getLimitOrderRelevantState + }, + { + fn extend(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IZeroexCalls::extend) + } + extend + }, + { + fn owner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(IZeroexCalls::owner) + } + owner + }, + { + fn fillOrKillLimitOrder(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IZeroexCalls::fillOrKillLimitOrder) + } + fillOrKillLimitOrder + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::extend(inner) => { + ::abi_encoded_size(inner) + } + Self::fillOrKillLimitOrder(inner) => { + ::abi_encoded_size(inner) + } + Self::getLimitOrderRelevantState(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::owner(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::extend(inner) => { + ::abi_encode_raw(inner, out) + } + Self::fillOrKillLimitOrder(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::getLimitOrderRelevantState(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::owner(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`IZeroex`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum IZeroexEvents { + #[allow(missing_docs)] + ERC1155OrderCancelled(ERC1155OrderCancelled), + #[allow(missing_docs)] + ERC1155OrderFilled(ERC1155OrderFilled), + #[allow(missing_docs)] + ERC1155OrderPreSigned(ERC1155OrderPreSigned), + #[allow(missing_docs)] + ERC721OrderCancelled(ERC721OrderCancelled), + #[allow(missing_docs)] + ERC721OrderFilled(ERC721OrderFilled), + #[allow(missing_docs)] + ERC721OrderPreSigned(ERC721OrderPreSigned), + #[allow(missing_docs)] + LimitOrderFilled(LimitOrderFilled), + #[allow(missing_docs)] + LiquidityProviderSwap(LiquidityProviderSwap), + #[allow(missing_docs)] + MetaTransactionExecuted(MetaTransactionExecuted), + #[allow(missing_docs)] + Migrated(Migrated), + #[allow(missing_docs)] + OrderCancelled(OrderCancelled), + #[allow(missing_docs)] + OrderSignerRegistered(OrderSignerRegistered), + #[allow(missing_docs)] + OtcOrderFilled(OtcOrderFilled), + #[allow(missing_docs)] + OwnershipTransferred(OwnershipTransferred), + #[allow(missing_docs)] + PairCancelledLimitOrders(PairCancelledLimitOrders), + #[allow(missing_docs)] + PairCancelledRfqOrders(PairCancelledRfqOrders), + #[allow(missing_docs)] + ProxyFunctionUpdated(ProxyFunctionUpdated), + #[allow(missing_docs)] + QuoteSignerUpdated(QuoteSignerUpdated), + #[allow(missing_docs)] + RfqOrderFilled(RfqOrderFilled), + #[allow(missing_docs)] + RfqOrderOriginsAllowed(RfqOrderOriginsAllowed), + #[allow(missing_docs)] + TransformedERC20(TransformedERC20), + #[allow(missing_docs)] + TransformerDeployerUpdated(TransformerDeployerUpdated), + } + impl IZeroexEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 2u8, 223u8, 234u8, 213u8, 235u8, 118u8, 155u8, 41u8, 142u8, 130u8, 221u8, 150u8, + 80u8, 179u8, 28u8, 64u8, 85u8, 154u8, 61u8, 66u8, 112u8, 29u8, 191u8, 83u8, 201u8, + 49u8, 188u8, 38u8, 130u8, 132u8, 124u8, 49u8, + ], + [ + 15u8, 102u8, 114u8, 247u8, 138u8, 89u8, 186u8, 142u8, 94u8, 91u8, 93u8, 56u8, + 223u8, 62u8, 188u8, 103u8, 243u8, 199u8, 146u8, 226u8, 201u8, 37u8, 155u8, 141u8, + 151u8, 215u8, 240u8, 13u8, 215u8, 139u8, 161u8, 179u8, + ], + [ + 32u8, 204u8, 168u8, 27u8, 14u8, 38u8, 155u8, 38u8, 91u8, 50u8, 41u8, 214u8, 181u8, + 55u8, 218u8, 145u8, 239u8, 71u8, 92u8, 160u8, 239u8, 85u8, 202u8, 237u8, 125u8, + 211u8, 7u8, 49u8, 112u8, 11u8, 169u8, 141u8, + ], + [ + 42u8, 226u8, 33u8, 8u8, 52u8, 103u8, 222u8, 82u8, 7u8, 139u8, 0u8, 150u8, 105u8, + 106u8, 184u8, 141u8, 141u8, 83u8, 167u8, 236u8, 180u8, 75u8, 182u8, 91u8, 86u8, + 162u8, 186u8, 182u8, 135u8, 89u8, 131u8, 103u8, + ], + [ + 64u8, 166u8, 186u8, 149u8, 19u8, 208u8, 158u8, 52u8, 136u8, 19u8, 94u8, 14u8, 13u8, + 16u8, 226u8, 212u8, 56u8, 43u8, 121u8, 39u8, 32u8, 21u8, 91u8, 20u8, 76u8, 190u8, + 168u8, 154u8, 201u8, 219u8, 109u8, 52u8, + ], + [ + 77u8, 94u8, 167u8, 218u8, 100u8, 245u8, 10u8, 74u8, 50u8, 153u8, 33u8, 184u8, + 210u8, 202u8, 181u8, 45u8, 255u8, 78u8, 188u8, 197u8, 139u8, 97u8, 209u8, 15u8, + 248u8, 57u8, 226u8, 142u8, 145u8, 68u8, 86u8, 132u8, + ], + [ + 80u8, 39u8, 63u8, 160u8, 34u8, 115u8, 204u8, 238u8, 169u8, 207u8, 8u8, 91u8, 66u8, + 222u8, 92u8, 138u8, 246u8, 6u8, 36u8, 20u8, 1u8, 104u8, 189u8, 113u8, 53u8, 125u8, + 184u8, 51u8, 83u8, 88u8, 119u8, 175u8, + ], + [ + 94u8, 145u8, 221u8, 254u8, 183u8, 191u8, 46u8, 18u8, 247u8, 232u8, 171u8, 1u8, + 125u8, 43u8, 99u8, 169u8, 33u8, 127u8, 0u8, 74u8, 21u8, 165u8, 51u8, 70u8, 173u8, + 144u8, 53u8, 62u8, 198u8, 61u8, 20u8, 228u8, + ], + [ + 110u8, 169u8, 219u8, 232u8, 178u8, 204u8, 17u8, 147u8, 72u8, 113u8, 106u8, 146u8, + 32u8, 160u8, 116u8, 42u8, 214u8, 43u8, 120u8, 132u8, 236u8, 176u8, 255u8, 75u8, + 50u8, 205u8, 80u8, 129u8, 33u8, 253u8, 147u8, 121u8, + ], + [ + 127u8, 79u8, 227u8, 255u8, 138u8, 228u8, 64u8, 225u8, 87u8, 12u8, 85u8, 141u8, + 160u8, 132u8, 64u8, 178u8, 111u8, 137u8, 251u8, 28u8, 31u8, 41u8, 16u8, 205u8, + 145u8, 202u8, 100u8, 82u8, 149u8, 95u8, 18u8, 26u8, + ], + [ + 130u8, 159u8, 169u8, 157u8, 148u8, 220u8, 70u8, 54u8, 146u8, 91u8, 56u8, 99u8, + 46u8, 98u8, 87u8, 54u8, 166u8, 20u8, 193u8, 84u8, 213u8, 80u8, 6u8, 183u8, 171u8, + 107u8, 234u8, 151u8, 156u8, 33u8, 12u8, 50u8, + ], + [ + 139u8, 224u8, 7u8, 156u8, 83u8, 22u8, 89u8, 20u8, 19u8, 68u8, 205u8, 31u8, 208u8, + 164u8, 242u8, 132u8, 25u8, 73u8, 127u8, 151u8, 34u8, 163u8, 218u8, 175u8, 227u8, + 180u8, 24u8, 111u8, 107u8, 100u8, 87u8, 224u8, + ], + [ + 140u8, 93u8, 12u8, 65u8, 251u8, 22u8, 167u8, 49u8, 122u8, 108u8, 85u8, 255u8, + 123u8, 169u8, 61u8, 157u8, 116u8, 247u8, 158u8, 67u8, 79u8, 239u8, 166u8, 148u8, + 229u8, 13u8, 96u8, 40u8, 175u8, 191u8, 163u8, 240u8, + ], + [ + 160u8, 21u8, 173u8, 45u8, 195u8, 47u8, 38u8, 105u8, 147u8, 149u8, 138u8, 15u8, + 217u8, 136u8, 76u8, 116u8, 107u8, 151u8, 27u8, 37u8, 66u8, 6u8, 243u8, 71u8, 139u8, + 196u8, 62u8, 47u8, 18u8, 92u8, 123u8, 158u8, + ], + [ + 166u8, 235u8, 124u8, 220u8, 33u8, 158u8, 21u8, 24u8, 206u8, 217u8, 100u8, 233u8, + 163u8, 78u8, 97u8, 214u8, 138u8, 148u8, 228u8, 241u8, 86u8, 157u8, 179u8, 232u8, + 66u8, 86u8, 186u8, 152u8, 27u8, 165u8, 39u8, 83u8, + ], + [ + 169u8, 31u8, 231u8, 174u8, 98u8, 252u8, 230u8, 105u8, 223u8, 44u8, 127u8, 136u8, + 15u8, 140u8, 20u8, 209u8, 120u8, 83u8, 26u8, 174u8, 114u8, 81u8, 85u8, 88u8, 229u8, + 201u8, 72u8, 227u8, 124u8, 50u8, 165u8, 114u8, + ], + [ + 171u8, 97u8, 77u8, 43u8, 115u8, 133u8, 67u8, 192u8, 234u8, 33u8, 245u8, 99u8, 71u8, + 207u8, 105u8, 106u8, 58u8, 12u8, 66u8, 167u8, 203u8, 236u8, 50u8, 18u8, 165u8, + 202u8, 34u8, 164u8, 220u8, 255u8, 33u8, 36u8, + ], + [ + 172u8, 117u8, 247u8, 115u8, 227u8, 169u8, 47u8, 26u8, 2u8, 177u8, 33u8, 52u8, + 214u8, 94u8, 31u8, 71u8, 248u8, 161u8, 78u8, 171u8, 228u8, 234u8, 241u8, 226u8, + 70u8, 36u8, 145u8, 142u8, 106u8, 139u8, 38u8, 159u8, + ], + [ + 225u8, 184u8, 49u8, 176u8, 230u8, 243u8, 170u8, 22u8, 180u8, 177u8, 166u8, 189u8, + 82u8, 107u8, 92u8, 222u8, 171u8, 73u8, 64u8, 116u8, 76u8, 166u8, 224u8, 37u8, 31u8, + 95u8, 229u8, 248u8, 202u8, 241u8, 200u8, 26u8, + ], + [ + 245u8, 85u8, 12u8, 94u8, 234u8, 25u8, 180u8, 138u8, 198u8, 235u8, 95u8, 3u8, 171u8, + 220u8, 79u8, 89u8, 192u8, 166u8, 6u8, 151u8, 171u8, 179u8, 217u8, 115u8, 205u8, + 104u8, 102u8, 151u8, 3u8, 181u8, 200u8, 185u8, + ], + [ + 253u8, 69u8, 96u8, 74u8, 186u8, 215u8, 156u8, 22u8, 226u8, 51u8, 72u8, 161u8, 55u8, + 237u8, 130u8, 146u8, 102u8, 27u8, 225u8, 184u8, 235u8, 166u8, 228u8, 128u8, 110u8, + 190u8, 214u8, 131u8, 59u8, 28u8, 4u8, 106u8, + ], + [ + 254u8, 127u8, 251u8, 30u8, 223u8, 231u8, 159u8, 77u8, 247u8, 22u8, 203u8, 45u8, + 202u8, 210u8, 28u8, 242u8, 243u8, 27u8, 16u8, 77u8, 129u8, 106u8, 121u8, 118u8, + 186u8, 30u8, 110u8, 70u8, 83u8, 193u8, 239u8, 177u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(RfqOrderOriginsAllowed), + ::core::stringify!(TransformedERC20), + ::core::stringify!(ERC1155OrderFilled), + ::core::stringify!(ProxyFunctionUpdated), + ::core::stringify!(LiquidityProviderSwap), + ::core::stringify!(ERC1155OrderCancelled), + ::core::stringify!(ERC721OrderFilled), + ::core::stringify!(ERC1155OrderPreSigned), + ::core::stringify!(OrderSignerRegistered), + ::core::stringify!(MetaTransactionExecuted), + ::core::stringify!(RfqOrderFilled), + ::core::stringify!(OwnershipTransferred), + ::core::stringify!(ERC721OrderPreSigned), + ::core::stringify!(ERC721OrderCancelled), + ::core::stringify!(OrderCancelled), + ::core::stringify!(PairCancelledLimitOrders), + ::core::stringify!(LimitOrderFilled), + ::core::stringify!(OtcOrderFilled), + ::core::stringify!(Migrated), + ::core::stringify!(QuoteSignerUpdated), + ::core::stringify!(TransformerDeployerUpdated), + ::core::stringify!(PairCancelledRfqOrders), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for IZeroexEvents { + const COUNT: usize = 22usize; + const NAME: &'static str = "IZeroexEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ERC1155OrderCancelled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ERC1155OrderFilled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ERC1155OrderPreSigned) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ERC721OrderCancelled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::ERC721OrderFilled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ERC721OrderPreSigned) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::LimitOrderFilled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::LiquidityProviderSwap) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::MetaTransactionExecuted) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Migrated) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OrderCancelled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::OrderSignerRegistered) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::OtcOrderFilled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::OwnershipTransferred) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::PairCancelledLimitOrders) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::PairCancelledRfqOrders) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::ProxyFunctionUpdated) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::QuoteSignerUpdated) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::RfqOrderFilled) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::RfqOrderOriginsAllowed) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::TransformedERC20) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::TransformerDeployerUpdated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for IZeroexEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::ERC1155OrderCancelled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ERC1155OrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ERC1155OrderPreSigned(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ERC721OrderCancelled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ERC721OrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ERC721OrderPreSigned(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::LimitOrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::LiquidityProviderSwap(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::MetaTransactionExecuted(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Migrated(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::OrderCancelled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OrderSignerRegistered(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OtcOrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::OwnershipTransferred(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PairCancelledLimitOrders(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::PairCancelledRfqOrders(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::ProxyFunctionUpdated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::QuoteSignerUpdated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::RfqOrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::RfqOrderOriginsAllowed(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::TransformedERC20(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::TransformerDeployerUpdated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::ERC1155OrderCancelled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ERC1155OrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ERC1155OrderPreSigned(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ERC721OrderCancelled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ERC721OrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ERC721OrderPreSigned(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::LimitOrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::LiquidityProviderSwap(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::MetaTransactionExecuted(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Migrated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OrderCancelled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OrderSignerRegistered(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OtcOrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::OwnershipTransferred(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PairCancelledLimitOrders(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::PairCancelledRfqOrders(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::ProxyFunctionUpdated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::QuoteSignerUpdated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::RfqOrderFilled(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::RfqOrderOriginsAllowed(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TransformedERC20(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TransformerDeployerUpdated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IZeroex`](self) contract instance. + + See the [wrapper's documentation](`IZeroexInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IZeroexInstance { + IZeroexInstance::::new(address, __provider) + } + /**A [`IZeroex`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IZeroex`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IZeroexInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IZeroexInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IZeroexInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IZeroexInstance + { + /**Creates a new wrapper around an on-chain [`IZeroex`](self) contract instance. + + See the [wrapper's documentation](`IZeroexInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IZeroexInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IZeroexInstance { + IZeroexInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IZeroexInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`extend`] function. + pub fn extend( + &self, + selector: alloy_sol_types::private::FixedBytes<4>, + r#impl: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, extendCall, N> { + self.call_builder(&extendCall { selector, r#impl }) + } + + ///Creates a new call builder for the [`fillOrKillLimitOrder`] + /// function. + pub fn fillOrKillLimitOrder( + &self, + order: ::RustType, + signature: ::RustType, + takerTokenFillAmount: u128, + ) -> alloy_contract::SolCallBuilder<&P, fillOrKillLimitOrderCall, N> { + self.call_builder(&fillOrKillLimitOrderCall { + order, + signature, + takerTokenFillAmount, + }) + } + + ///Creates a new call builder for the [`getLimitOrderRelevantState`] + /// function. + pub fn getLimitOrderRelevantState( + &self, + order: ::RustType, + signature: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, getLimitOrderRelevantStateCall, N> { + self.call_builder(&getLimitOrderRelevantStateCall { order, signature }) + } + + ///Creates a new call builder for the [`owner`] function. + pub fn owner(&self) -> alloy_contract::SolCallBuilder<&P, ownerCall, N> { + self.call_builder(&ownerCall) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IZeroexInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`ERC1155OrderCancelled`] event. + pub fn ERC1155OrderCancelled_filter( + &self, + ) -> alloy_contract::Event<&P, ERC1155OrderCancelled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ERC1155OrderFilled`] event. + pub fn ERC1155OrderFilled_filter( + &self, + ) -> alloy_contract::Event<&P, ERC1155OrderFilled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ERC1155OrderPreSigned`] event. + pub fn ERC1155OrderPreSigned_filter( + &self, + ) -> alloy_contract::Event<&P, ERC1155OrderPreSigned, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ERC721OrderCancelled`] event. + pub fn ERC721OrderCancelled_filter( + &self, + ) -> alloy_contract::Event<&P, ERC721OrderCancelled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ERC721OrderFilled`] event. + pub fn ERC721OrderFilled_filter(&self) -> alloy_contract::Event<&P, ERC721OrderFilled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ERC721OrderPreSigned`] event. + pub fn ERC721OrderPreSigned_filter( + &self, + ) -> alloy_contract::Event<&P, ERC721OrderPreSigned, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`LimitOrderFilled`] event. + pub fn LimitOrderFilled_filter(&self) -> alloy_contract::Event<&P, LimitOrderFilled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`LiquidityProviderSwap`] event. + pub fn LiquidityProviderSwap_filter( + &self, + ) -> alloy_contract::Event<&P, LiquidityProviderSwap, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`MetaTransactionExecuted`] + /// event. + pub fn MetaTransactionExecuted_filter( + &self, + ) -> alloy_contract::Event<&P, MetaTransactionExecuted, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Migrated`] event. + pub fn Migrated_filter(&self) -> alloy_contract::Event<&P, Migrated, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OrderCancelled`] event. + pub fn OrderCancelled_filter(&self) -> alloy_contract::Event<&P, OrderCancelled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OrderSignerRegistered`] event. + pub fn OrderSignerRegistered_filter( + &self, + ) -> alloy_contract::Event<&P, OrderSignerRegistered, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OtcOrderFilled`] event. + pub fn OtcOrderFilled_filter(&self) -> alloy_contract::Event<&P, OtcOrderFilled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`OwnershipTransferred`] event. + pub fn OwnershipTransferred_filter( + &self, + ) -> alloy_contract::Event<&P, OwnershipTransferred, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PairCancelledLimitOrders`] + /// event. + pub fn PairCancelledLimitOrders_filter( + &self, + ) -> alloy_contract::Event<&P, PairCancelledLimitOrders, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`PairCancelledRfqOrders`] event. + pub fn PairCancelledRfqOrders_filter( + &self, + ) -> alloy_contract::Event<&P, PairCancelledRfqOrders, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`ProxyFunctionUpdated`] event. + pub fn ProxyFunctionUpdated_filter( + &self, + ) -> alloy_contract::Event<&P, ProxyFunctionUpdated, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`QuoteSignerUpdated`] event. + pub fn QuoteSignerUpdated_filter( + &self, + ) -> alloy_contract::Event<&P, QuoteSignerUpdated, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`RfqOrderFilled`] event. + pub fn RfqOrderFilled_filter(&self) -> alloy_contract::Event<&P, RfqOrderFilled, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`RfqOrderOriginsAllowed`] event. + pub fn RfqOrderOriginsAllowed_filter( + &self, + ) -> alloy_contract::Event<&P, RfqOrderOriginsAllowed, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TransformedERC20`] event. + pub fn TransformedERC20_filter(&self) -> alloy_contract::Event<&P, TransformedERC20, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TransformerDeployerUpdated`] + /// event. + pub fn TransformerDeployerUpdated_filter( + &self, + ) -> alloy_contract::Event<&P, TransformerDeployerUpdated, N> { + self.event_filter::() + } + } +} +pub type Instance = IZeroex::IZeroexInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0xdef1abe32c034e558cdd535791643c58a13acc10"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/liquoricesettlement/Cargo.toml b/contracts/generated/contracts-generated/liquoricesettlement/Cargo.toml new file mode 100644 index 0000000000..227b925146 --- /dev/null +++ b/contracts/generated/contracts-generated/liquoricesettlement/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-liquoricesettlement" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/liquoricesettlement/src/lib.rs b/contracts/generated/contracts-generated/liquoricesettlement/src/lib.rs new file mode 100644 index 0000000000..1e034b5f65 --- /dev/null +++ b/contracts/generated/contracts-generated/liquoricesettlement/src/lib.rs @@ -0,0 +1,9607 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library GPv2Interaction { + struct Data { address target; uint256 value; bytes callData; } + struct Hooks { Data[] beforeSettle; Data[] afterSettle; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod GPv2Interaction { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Data { address target; uint256 value; bytes callData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Data { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub callData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Data) -> Self { + (value.target, value.value, value.callData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Data { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + value: tuple.1, + callData: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Data { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Data { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.target, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.callData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Data { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Data { + const NAME: &'static str = "Data"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Data(address target,uint256 value,bytes callData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.target, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.value) + .0, + ::eip712_data_word( + &self.callData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Data { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.target, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.value) + + ::topic_preimage_length( + &rust.callData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.target, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.value, + out, + ); + ::encode_topic_preimage( + &rust.callData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Hooks { Data[] beforeSettle; Data[] afterSettle; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Hooks { + #[allow(missing_docs)] + pub beforeSettle: + alloy_sol_types::private::Vec<::RustType>, + #[allow(missing_docs)] + pub afterSettle: + alloy_sol_types::private::Vec<::RustType>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Array, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec<::RustType>, + alloy_sol_types::private::Vec<::RustType>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Hooks) -> Self { + (value.beforeSettle, value.afterSettle) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Hooks { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + beforeSettle: tuple.0, + afterSettle: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Hooks { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Hooks { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.beforeSettle, + ), + as alloy_sol_types::SolType>::tokenize( + &self.afterSettle, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Hooks { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Hooks { + const NAME: &'static str = "Hooks"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Hooks(Data[] beforeSettle,Data[] afterSettle)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + let mut components = alloy_sol_types::private::Vec::with_capacity(2); + components.push(::eip712_root_type()); + components.extend(::eip712_components()); + components.push(::eip712_root_type()); + components.extend(::eip712_components()); + components + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + as alloy_sol_types::SolType>::eip712_data_word(&self.beforeSettle) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.afterSettle) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Hooks { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.beforeSettle, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.afterSettle, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.beforeSettle, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.afterSettle, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`GPv2Interaction`](self) contract instance. + + See the [wrapper's documentation](`GPv2InteractionInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> GPv2InteractionInstance { + GPv2InteractionInstance::::new(address, __provider) + } + /**A [`GPv2Interaction`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`GPv2Interaction`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct GPv2InteractionInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for GPv2InteractionInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("GPv2InteractionInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /**Creates a new wrapper around an on-chain [`GPv2Interaction`](self) contract instance. + + See the [wrapper's documentation](`GPv2InteractionInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl GPv2InteractionInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> GPv2InteractionInstance { + GPv2InteractionInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + GPv2InteractionInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library ILiquoriceSettlement { + struct BaseTokenData { address addr; uint256 amount; uint256 toRecipient; uint256 toRepay; uint256 toSupply; } + struct Order { address market; uint256 chainId; string rfqId; uint256 nonce; address trader; address effectiveTrader; uint256 quoteExpiry; address recipient; uint256 minFillAmount; BaseTokenData baseTokenData; QuoteTokenData quoteTokenData; } + struct QuoteTokenData { address addr; uint256 amount; uint256 toTrader; uint256 toWithdraw; uint256 toBorrow; } + struct Single { string rfqId; uint256 nonce; address trader; address effectiveTrader; address baseToken; address quoteToken; uint256 baseTokenAmount; uint256 quoteTokenAmount; uint256 minFillAmount; uint256 quoteExpiry; address recipient; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod ILiquoriceSettlement { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct BaseTokenData { address addr; uint256 amount; uint256 toRecipient; uint256 toRepay; uint256 toSupply; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct BaseTokenData { + #[allow(missing_docs)] + pub addr: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub toRecipient: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub toRepay: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub toSupply: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: BaseTokenData) -> Self { + ( + value.addr, + value.amount, + value.toRecipient, + value.toRepay, + value.toSupply, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for BaseTokenData { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + addr: tuple.0, + amount: tuple.1, + toRecipient: tuple.2, + toRepay: tuple.3, + toSupply: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for BaseTokenData { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for BaseTokenData { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.addr, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.toRecipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.toRepay, + ), + as alloy_sol_types::SolType>::tokenize( + &self.toSupply, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for BaseTokenData { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for BaseTokenData { + const NAME: &'static str = "BaseTokenData"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "BaseTokenData(address addr,uint256 amount,uint256 toRecipient,uint256 \ + toRepay,uint256 toSupply)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.addr, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.toRecipient) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.toRepay) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.toSupply) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for BaseTokenData { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.addr, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.toRecipient, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.toRepay, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.toSupply, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.addr, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.toRecipient, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.toRepay, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.toSupply, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Order { address market; uint256 chainId; string rfqId; uint256 nonce; address trader; address effectiveTrader; uint256 quoteExpiry; address recipient; uint256 minFillAmount; BaseTokenData baseTokenData; QuoteTokenData quoteTokenData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Order { + #[allow(missing_docs)] + pub market: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub chainId: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub rfqId: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub trader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub effectiveTrader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub quoteExpiry: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub minFillAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub baseTokenData: ::RustType, + #[allow(missing_docs)] + pub quoteTokenData: ::RustType, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + BaseTokenData, + QuoteTokenData, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::String, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ::RustType, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Order) -> Self { + ( + value.market, + value.chainId, + value.rfqId, + value.nonce, + value.trader, + value.effectiveTrader, + value.quoteExpiry, + value.recipient, + value.minFillAmount, + value.baseTokenData, + value.quoteTokenData, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Order { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + market: tuple.0, + chainId: tuple.1, + rfqId: tuple.2, + nonce: tuple.3, + trader: tuple.4, + effectiveTrader: tuple.5, + quoteExpiry: tuple.6, + recipient: tuple.7, + minFillAmount: tuple.8, + baseTokenData: tuple.9, + quoteTokenData: tuple.10, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Order { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Order { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.market, + ), + as alloy_sol_types::SolType>::tokenize( + &self.chainId, + ), + ::tokenize( + &self.rfqId, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ::tokenize( + &self.trader, + ), + ::tokenize( + &self.effectiveTrader, + ), + as alloy_sol_types::SolType>::tokenize( + &self.quoteExpiry, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.minFillAmount, + ), + ::tokenize(&self.baseTokenData), + ::tokenize(&self.quoteTokenData), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Order { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Order { + const NAME: &'static str = "Order"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Order(address market,uint256 chainId,string rfqId,uint256 nonce,address \ + trader,address effectiveTrader,uint256 quoteExpiry,address recipient,uint256 \ + minFillAmount,BaseTokenData baseTokenData,QuoteTokenData quoteTokenData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + let mut components = alloy_sol_types::private::Vec::with_capacity(2); + components.push(::eip712_root_type()); + components + .extend(::eip712_components()); + components.push(::eip712_root_type()); + components + .extend(::eip712_components()); + components + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.market, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.chainId) + .0, + ::eip712_data_word( + &self.rfqId, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.nonce) + .0, + ::eip712_data_word( + &self.trader, + ) + .0, + ::eip712_data_word( + &self.effectiveTrader, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.quoteExpiry) + .0, + ::eip712_data_word( + &self.recipient, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.minFillAmount) + .0, + ::eip712_data_word( + &self.baseTokenData, + ) + .0, + ::eip712_data_word( + &self.quoteTokenData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Order { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.market, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.chainId, + ) + + ::topic_preimage_length( + &rust.rfqId, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.nonce) + + ::topic_preimage_length( + &rust.trader, + ) + + ::topic_preimage_length( + &rust.effectiveTrader, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.quoteExpiry, + ) + + ::topic_preimage_length( + &rust.recipient, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.minFillAmount, + ) + + ::topic_preimage_length( + &rust.baseTokenData, + ) + + ::topic_preimage_length( + &rust.quoteTokenData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.market, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.chainId, + out, + ); + ::encode_topic_preimage( + &rust.rfqId, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.nonce, + out, + ); + ::encode_topic_preimage( + &rust.trader, + out, + ); + ::encode_topic_preimage( + &rust.effectiveTrader, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.quoteExpiry, + out, + ); + ::encode_topic_preimage( + &rust.recipient, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.minFillAmount, + out, + ); + ::encode_topic_preimage( + &rust.baseTokenData, + out, + ); + ::encode_topic_preimage( + &rust.quoteTokenData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct QuoteTokenData { address addr; uint256 amount; uint256 toTrader; uint256 toWithdraw; uint256 toBorrow; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct QuoteTokenData { + #[allow(missing_docs)] + pub addr: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub toTrader: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub toWithdraw: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub toBorrow: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: QuoteTokenData) -> Self { + ( + value.addr, + value.amount, + value.toTrader, + value.toWithdraw, + value.toBorrow, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for QuoteTokenData { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + addr: tuple.0, + amount: tuple.1, + toTrader: tuple.2, + toWithdraw: tuple.3, + toBorrow: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for QuoteTokenData { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for QuoteTokenData { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.addr, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.toTrader, + ), + as alloy_sol_types::SolType>::tokenize( + &self.toWithdraw, + ), + as alloy_sol_types::SolType>::tokenize( + &self.toBorrow, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for QuoteTokenData { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for QuoteTokenData { + const NAME: &'static str = "QuoteTokenData"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "QuoteTokenData(address addr,uint256 amount,uint256 toTrader,uint256 \ + toWithdraw,uint256 toBorrow)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.addr, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.toTrader) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.toWithdraw) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.toBorrow) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for QuoteTokenData { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.addr, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.toTrader, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.toWithdraw, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.toBorrow, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.addr, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.toTrader, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.toWithdraw, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.toBorrow, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Single { string rfqId; uint256 nonce; address trader; address effectiveTrader; address baseToken; address quoteToken; uint256 baseTokenAmount; uint256 quoteTokenAmount; uint256 minFillAmount; uint256 quoteExpiry; address recipient; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Single { + #[allow(missing_docs)] + pub rfqId: alloy_sol_types::private::String, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub trader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub effectiveTrader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub baseToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub quoteToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub baseTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub quoteTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub minFillAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub quoteExpiry: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::String, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::String, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Single) -> Self { + ( + value.rfqId, + value.nonce, + value.trader, + value.effectiveTrader, + value.baseToken, + value.quoteToken, + value.baseTokenAmount, + value.quoteTokenAmount, + value.minFillAmount, + value.quoteExpiry, + value.recipient, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Single { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + rfqId: tuple.0, + nonce: tuple.1, + trader: tuple.2, + effectiveTrader: tuple.3, + baseToken: tuple.4, + quoteToken: tuple.5, + baseTokenAmount: tuple.6, + quoteTokenAmount: tuple.7, + minFillAmount: tuple.8, + quoteExpiry: tuple.9, + recipient: tuple.10, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Single { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Single { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.rfqId, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ::tokenize( + &self.trader, + ), + ::tokenize( + &self.effectiveTrader, + ), + ::tokenize( + &self.baseToken, + ), + ::tokenize( + &self.quoteToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.baseTokenAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.quoteTokenAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.minFillAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.quoteExpiry, + ), + ::tokenize( + &self.recipient, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Single { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Single { + const NAME: &'static str = "Single"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Single(string rfqId,uint256 nonce,address trader,address \ + effectiveTrader,address baseToken,address quoteToken,uint256 \ + baseTokenAmount,uint256 quoteTokenAmount,uint256 minFillAmount,uint256 \ + quoteExpiry,address recipient)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.rfqId, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.nonce) + .0, + ::eip712_data_word( + &self.trader, + ) + .0, + ::eip712_data_word( + &self.effectiveTrader, + ) + .0, + ::eip712_data_word( + &self.baseToken, + ) + .0, + ::eip712_data_word( + &self.quoteToken, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.baseTokenAmount, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.quoteTokenAmount, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.minFillAmount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.quoteExpiry) + .0, + ::eip712_data_word( + &self.recipient, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Single { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.rfqId, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.nonce) + + ::topic_preimage_length( + &rust.trader, + ) + + ::topic_preimage_length( + &rust.effectiveTrader, + ) + + ::topic_preimage_length( + &rust.baseToken, + ) + + ::topic_preimage_length( + &rust.quoteToken, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.baseTokenAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.quoteTokenAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.minFillAmount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.quoteExpiry, + ) + + ::topic_preimage_length( + &rust.recipient, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.rfqId, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.nonce, + out, + ); + ::encode_topic_preimage( + &rust.trader, + out, + ); + ::encode_topic_preimage( + &rust.effectiveTrader, + out, + ); + ::encode_topic_preimage( + &rust.baseToken, + out, + ); + ::encode_topic_preimage( + &rust.quoteToken, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.baseTokenAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.quoteTokenAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.minFillAmount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.quoteExpiry, + out, + ); + ::encode_topic_preimage( + &rust.recipient, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`ILiquoriceSettlement`](self) contract instance. + + See the [wrapper's documentation](`ILiquoriceSettlementInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> ILiquoriceSettlementInstance { + ILiquoriceSettlementInstance::::new(address, __provider) + } + /**A [`ILiquoriceSettlement`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`ILiquoriceSettlement`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct ILiquoriceSettlementInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for ILiquoriceSettlementInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("ILiquoriceSettlementInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + ILiquoriceSettlementInstance + { + /**Creates a new wrapper around an on-chain [`ILiquoriceSettlement`](self) contract instance. + + See the [wrapper's documentation](`ILiquoriceSettlementInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl ILiquoriceSettlementInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> ILiquoriceSettlementInstance { + ILiquoriceSettlementInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + ILiquoriceSettlementInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + ILiquoriceSettlementInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +///Module containing a contract's types and functions. +/** + +```solidity +library Signature { + type TransferCommand is uint8; + type Type is uint8; + struct TypedSignature { Type signatureType; TransferCommand transferCommand; bytes signatureBytes; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Signature { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct TransferCommand(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl TransferCommand { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for TransferCommand { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: TransferCommand) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for TransferCommand { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for TransferCommand { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Type(u8); + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for u8 { + #[inline] + fn stv_to_tokens( + &self, + ) -> as alloy_sol_types::SolType>::Token<'_> + { + alloy_sol_types::private::SolTypeValue::< + alloy_sol_types::sol_data::Uint<8>, + >::stv_to_tokens(self) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + as alloy_sol_types::SolType>::tokenize(self).0 + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + as alloy_sol_types::SolType>::abi_encode_packed_to(self, out) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + as alloy_sol_types::SolType>::abi_encoded_size( + self, + ) + } + } + impl Type { + /// The Solidity type name. + pub const NAME: &'static str = stringify!(@ name); + + /// Convert from the underlying value type. + #[inline] + pub const fn from_underlying(value: u8) -> Self { + Self(value) + } + + /// Return the underlying value. + #[inline] + pub const fn into_underlying(self) -> u8 { + self.0 + } + + /// Return the single encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode(&self) -> alloy_sol_types::private::Vec { + ::abi_encode(&self.0) + } + + /// Return the packed encoding of this value, delegating to the + /// underlying type. + #[inline] + pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec { + ::abi_encode_packed(&self.0) + } + } + #[automatically_derived] + impl From for Type { + fn from(value: u8) -> Self { + Self::from_underlying(value) + } + } + #[automatically_derived] + impl From for u8 { + fn from(value: Type) -> Self { + value.into_underlying() + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Type { + type RustType = u8; + type Token<'a> = + as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = Self::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + Self::type_check(token).is_ok() + } + + #[inline] + fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> { + as alloy_sol_types::SolType>::type_check(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + as alloy_sol_types::SolType>::detokenize(token) + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Type { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + as alloy_sol_types::EventTopic>::topic_preimage_length(rust) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out) + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + as alloy_sol_types::EventTopic>::encode_topic( + rust, + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct TypedSignature { Type signatureType; TransferCommand transferCommand; bytes signatureBytes; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct TypedSignature { + #[allow(missing_docs)] + pub signatureType: ::RustType, + #[allow(missing_docs)] + pub transferCommand: ::RustType, + #[allow(missing_docs)] + pub signatureBytes: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (Type, TransferCommand, alloy_sol_types::sol_data::Bytes); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + ::RustType, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: TypedSignature) -> Self { + ( + value.signatureType, + value.transferCommand, + value.signatureBytes, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for TypedSignature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + signatureType: tuple.0, + transferCommand: tuple.1, + signatureBytes: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for TypedSignature { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for TypedSignature { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize(&self.signatureType), + ::tokenize(&self.transferCommand), + ::tokenize( + &self.signatureBytes, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for TypedSignature { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for TypedSignature { + const NAME: &'static str = "TypedSignature"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "TypedSignature(uint8 signatureType,uint8 transferCommand,bytes \ + signatureBytes)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.signatureType, + ) + .0, + ::eip712_data_word( + &self.transferCommand, + ) + .0, + ::eip712_data_word( + &self.signatureBytes, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for TypedSignature { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.signatureType, + ) + + ::topic_preimage_length( + &rust.transferCommand, + ) + + ::topic_preimage_length( + &rust.signatureBytes, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.signatureType, + out, + ); + ::encode_topic_preimage( + &rust.transferCommand, + out, + ); + ::encode_topic_preimage( + &rust.signatureBytes, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Signature`](self) contract instance. + + See the [wrapper's documentation](`SignatureInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> SignatureInstance { + SignatureInstance::::new(address, __provider) + } + /**A [`Signature`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Signature`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct SignatureInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for SignatureInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("SignatureInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + SignatureInstance + { + /**Creates a new wrapper around an on-chain [`Signature`](self) contract instance. + + See the [wrapper's documentation](`SignatureInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl SignatureInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> SignatureInstance { + SignatureInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + SignatureInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + SignatureInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library GPv2Interaction { + struct Data { + address target; + uint256 value; + bytes callData; + } + struct Hooks { + Data[] beforeSettle; + Data[] afterSettle; + } +} + +library ILiquoriceSettlement { + struct BaseTokenData { + address addr; + uint256 amount; + uint256 toRecipient; + uint256 toRepay; + uint256 toSupply; + } + struct Order { + address market; + uint256 chainId; + string rfqId; + uint256 nonce; + address trader; + address effectiveTrader; + uint256 quoteExpiry; + address recipient; + uint256 minFillAmount; + BaseTokenData baseTokenData; + QuoteTokenData quoteTokenData; + } + struct QuoteTokenData { + address addr; + uint256 amount; + uint256 toTrader; + uint256 toWithdraw; + uint256 toBorrow; + } + struct Single { + string rfqId; + uint256 nonce; + address trader; + address effectiveTrader; + address baseToken; + address quoteToken; + uint256 baseTokenAmount; + uint256 quoteTokenAmount; + uint256 minFillAmount; + uint256 quoteExpiry; + address recipient; + } +} + +library Signature { + type TransferCommand is uint8; + type Type is uint8; + struct TypedSignature { + Type signatureType; + TransferCommand transferCommand; + bytes signatureBytes; + } +} + +interface LiquoriceSettlement { + error ECDSAInvalidSignature(); + error ECDSAInvalidSignatureLength(uint256 length); + error ECDSAInvalidSignatureS(bytes32 s); + error InvalidAmount(); + error InvalidAsset(); + error InvalidBaseTokenAmounts(); + error InvalidDestination(); + error InvalidEIP1271Signature(); + error InvalidEIP712Signature(); + error InvalidETHSignSignature(); + error InvalidFillAmount(); + error InvalidHooksTarget(); + error InvalidInteractionsBaseTokenAmounts(); + error InvalidInteractionsQuoteTokenAmounts(); + error InvalidLendingPoolInteraction(); + error InvalidQuoteTokenAmounts(); + error InvalidSignatureType(); + error InvalidSigner(); + error InvalidSource(); + error NonceInvalid(); + error NotMaker(); + error NotSolver(); + error OrderExpired(); + error PartialFillNotSupported(); + error ReceiverNotManager(); + error ReentrancyGuardReentrantCall(); + error SafeERC20FailedOperation(address token); + error SignatureIsExpired(); + error SignatureIsNotEmpty(); + error UpdatedMakerAmountsTooLow(); + error ZeroMakerAmount(); + + event Interaction(address indexed target, uint256 value, bytes4 selector); + event TradeOrder(string indexed rfqId, address trader, address effectiveTrader, address baseToken, address quoteToken, uint256 baseTokenAmount, uint256 quoteTokenAmount, address recipient); + + constructor(address authenticator_, address repository_, address permit2_); + + receive() external payable; + + function AUTHENTICATOR() external view returns (address); + function BALANCE_MANAGER() external view returns (address); + function DOMAIN_SEPARATOR() external view returns (bytes32); + function hashSingleOrder(ILiquoriceSettlement.Single memory _order) external view returns (bytes32); + function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4); + function settle(address _signer, uint256 _filledTakerAmount, ILiquoriceSettlement.Order memory _order, GPv2Interaction.Data[] memory _interactions, GPv2Interaction.Hooks memory _hooks, Signature.TypedSignature memory _makerSignature, Signature.TypedSignature memory _takerSignature) external; + function settleSingle(address _signer, ILiquoriceSettlement.Single memory _order, Signature.TypedSignature memory _makerSignature, uint256 _filledTakerAmount, Signature.TypedSignature memory _takerSignature) external payable; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "authenticator_", + "type": "address", + "internalType": "contract IAllowListAuthentication" + }, + { + "name": "repository_", + "type": "address", + "internalType": "contract IRepository" + }, + { + "name": "permit2_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "AUTHENTICATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IAllowListAuthentication" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "BALANCE_MANAGER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IBalanceManager" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hashSingleOrder", + "inputs": [ + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Single", + "components": [ + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "baseToken", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteToken", + "type": "address", + "internalType": "address" + }, + { + "name": "baseTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "_hash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "_signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "settle", + "inputs": [ + { + "name": "_signer", + "type": "address", + "internalType": "address" + }, + { + "name": "_filledTakerAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Order", + "components": [ + { + "name": "market", + "type": "address", + "internalType": "address" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "baseTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.BaseTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRecipient", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toRepay", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toSupply", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "quoteTokenData", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.QuoteTokenData", + "components": [ + { + "name": "addr", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toTrader", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "toBorrow", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + }, + { + "name": "_interactions", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_hooks", + "type": "tuple", + "internalType": "struct GPv2Interaction.Hooks", + "components": [ + { + "name": "beforeSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "afterSettle", + "type": "tuple[]", + "internalType": "struct GPv2Interaction.Data[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] + }, + { + "name": "_makerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_takerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "settleSingle", + "inputs": [ + { + "name": "_signer", + "type": "address", + "internalType": "address" + }, + { + "name": "_order", + "type": "tuple", + "internalType": "struct ILiquoriceSettlement.Single", + "components": [ + { + "name": "rfqId", + "type": "string", + "internalType": "string" + }, + { + "name": "nonce", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "internalType": "address" + }, + { + "name": "baseToken", + "type": "address", + "internalType": "address" + }, + { + "name": "quoteToken", + "type": "address", + "internalType": "address" + }, + { + "name": "baseTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteTokenAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minFillAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "quoteExpiry", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ] + }, + { + "name": "_makerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "_filledTakerAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_takerSignature", + "type": "tuple", + "internalType": "struct Signature.TypedSignature", + "components": [ + { + "name": "signatureType", + "type": "uint8", + "internalType": "enum Signature.Type" + }, + { + "name": "transferCommand", + "type": "uint8", + "internalType": "enum Signature.TransferCommand" + }, + { + "name": "signatureBytes", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "event", + "name": "Interaction", + "inputs": [ + { + "name": "target", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "selector", + "type": "bytes4", + "indexed": false, + "internalType": "bytes4" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TradeOrder", + "inputs": [ + { + "name": "rfqId", + "type": "string", + "indexed": true, + "internalType": "string" + }, + { + "name": "trader", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "effectiveTrader", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "baseToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "quoteToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "baseTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "quoteTokenAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "ECDSAInvalidSignature", + "inputs": [] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ECDSAInvalidSignatureS", + "inputs": [ + { + "name": "s", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidAmount", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidAsset", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidBaseTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidDestination", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEIP1271Signature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidEIP712Signature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidETHSignSignature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidFillAmount", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidHooksTarget", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInteractionsBaseTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidInteractionsQuoteTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidLendingPoolInteraction", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidQuoteTokenAmounts", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSignatureType", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSigner", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSource", + "inputs": [] + }, + { + "type": "error", + "name": "NonceInvalid", + "inputs": [] + }, + { + "type": "error", + "name": "NotMaker", + "inputs": [] + }, + { + "type": "error", + "name": "NotSolver", + "inputs": [] + }, + { + "type": "error", + "name": "OrderExpired", + "inputs": [] + }, + { + "type": "error", + "name": "PartialFillNotSupported", + "inputs": [] + }, + { + "type": "error", + "name": "ReceiverNotManager", + "inputs": [] + }, + { + "type": "error", + "name": "ReentrancyGuardReentrantCall", + "inputs": [] + }, + { + "type": "error", + "name": "SafeERC20FailedOperation", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "SignatureIsExpired", + "inputs": [] + }, + { + "type": "error", + "name": "SignatureIsNotEmpty", + "inputs": [] + }, + { + "type": "error", + "name": "UpdatedMakerAmountsTooLow", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroMakerAmount", + "inputs": [] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod LiquoriceSettlement { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x61012060405234801562000011575f80fd5b5060405162004ef638038062004ef6833981016040819052620000349162000175565b4660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201526080810192909252309082015260c00160408051601f19818403018152908290528051602090910120608052600180556001600160a01b03841660c05230908290620000fe906200014f565b6001600160a01b03928316815291166020820152604001604051809103905ff0801580156200012f573d5f803e3d5ffd5b506001600160a01b0390811660e052919091166101005250620001c69050565b610963806200459383390190565b6001600160a01b038116811462000172575f80fd5b50565b5f805f6060848603121562000188575f80fd5b835162000195816200015d565b6020850151909350620001a8816200015d565b6040850151909250620001bb816200015d565b809150509250925092565b60805160a05160c05160e0516101005161432d620002665f395f81816102570152818161078401526116dc01525f8181610197015281816107ba0152818161188c01528181611e2c01528181611f1e0152818161202c0152818161230b01528181612427015261303c01525f818161033801528181610412015281816106a70152818161152001526115ff01525f6104da01525f6105a4015261432d5ff3fe608060405260043610610126575f3560e01c8063a5cdc8fc116100a1578063c618618111610071578063db58772811610057578063db58772814610379578063e242924e1461038c578063fa5cd56c146103ab575f80fd5b8063c618618114610327578063cba673a71461035a575f80fd5b8063a5cdc8fc146102ab578063a7ab49bc146102ca578063ae80c584146102e9578063b11f126214610308575f80fd5b806351d46815116100f65780636f35d2d2116100dc5780636f35d2d214610246578063875530ff146102795780639935c86814610298575f80fd5b806351d46815146102125780635aa0e95d14610227575f80fd5b80631626ba7e1461013157806329bcdc95146101865780633644e515146101d15780634c9e03d3146101f3575f80fd5b3661012d57005b5f80fd5b34801561013c575f80fd5b5061015061014b366004613595565b6103ca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610191575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161017d565b3480156101dc575f80fd5b506101e56104d7565b60405190815260200161017d565b3480156101fe575f80fd5b506101e561020d366004613620565b6105c6565b6102256102203660046136d7565b610667565b005b348015610232575f80fd5b506102256102413660046137e1565b6109e8565b348015610251575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610284575f80fd5b506101e5610293366004613620565b610c30565b6102256102a636600461383f565b610c5f565b3480156102b6575f80fd5b506102256102c53660046138dd565b610c7f565b3480156102d5575f80fd5b506102256102e4366004613901565b610c8c565b3480156102f4575f80fd5b5061022561030336600461399d565b611067565b348015610313575f80fd5b506101e56103223660046139f2565b6112eb565b348015610332575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610365575f80fd5b50610225610374366004613a24565b6114ea565b610225610387366004613b0b565b611878565b348015610397575f80fd5b506101e56103a6366004613bc9565b61194c565b3480156103b6575f80fd5b506102256103c5366004613bc9565b611a8e565b5f806103d7858585611b50565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063e75600c390602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190613bfb565b156104ab577f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150506104d0565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b9392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000046146105a157604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f7f68b8e94dc077458241d6c8d89f0a7665c7cda2cfe70c9eb4437efee1663c66fe6105f56020840184613c16565b836020013584604001358560600135866080013560405160200161064a969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b61066f611bdb565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa1580156106ec573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107109190613bfb565b610746576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610200870135881580159061076057506101608801358911155b1561077f5761077c896102008a01356101608b01356001611c1e565b90505b6107b07f00000000000000000000000000000000000000000000000000000000000000008b838b8b8b8b8b8b611c69565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66107ef60c08b0160a08c01613c16565b6108016101408c016101208d01613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108449291906101608e0135908890600401613c8d565b5f604051808303815f87803b15801561085b575f80fd5b505af115801561086d573d5f803e3d5ffd5b505050506108b4888b838c5f148061088957506101608c01358d115b610893578c61089a565b6101608c01355b898c8c60026108af60408e0160208f01613d61565b611e01565b6108c16040890189613d7f565b6040516108cf929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661090960a08b0160808c01613c16565b61091960c08c0160a08d01613c16565b61092b6101408d016101208e01613c16565b61093d6101e08e016101c08f01613c16565b8e158061094e57506101608e01358f115b610958578e61095f565b6101408e01355b6102008f013588146109715787610978565b6101e08f01355b8f60e001602081019061098b9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a2506109dd60018055565b505050505050505050565b5f5b6109f48280613def565b9050811015610b065736610a088380613def565b83818110610a1857610a18613e53565b9050602002810190610a2a9190613e80565b90506001600160a01b03841663a8c4bc95610a486020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610aa2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac69190613bfb565b15610afd576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016109ea565b505f5b610b166020830183613def565b9050811015610c2b5736610b2d6020840184613def565b83818110610b3d57610b3d613e53565b9050602002810190610b4f9190613e80565b90506001600160a01b03841663a8c4bc95610b6d6020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610bc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610beb9190613bfb565b15610c22576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101610b09565b505050565b5f7fae676bf6913ac2689b7331293c989fe7723124faf8b5d275f06fbcebc77950096105f56020840184613c16565b610c698482612212565b610c78858585856001806122c9565b5050505050565b610c89338261261e565b50565b610cbf6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f5b828110156110535736848483818110610cdc57610cdc613e53565b9050602002810190610cee9190613e80565b9050365f610cff6040840184613d7f565b90925090506001600160a01b038b1663a8c4bc95610d206020860186613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9e9190613bfb565b15611045575f8915610ddc576040517f7d617bb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048210610de8575081355b7fc03a9de9000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610e5657610e3d83838d8c6126c4565b86602001818151610e4e9190613ebc565b905250611043565b7f243a4b7f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610ebc57610eab83838d8c6127da565b86606001818151610e4e9190613ebc565b7f7dc4f458000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f4757610f1183838d8c61294e565b60a088015260808701819052606087018051610f2e908390613ebc565b90525060a0860151602087018051610e4e908390613ebc565b7f68931b6b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610fab57610f9c83838d8c612bb6565b86518790610e4e908390613ebc565b7f0c9be7e4000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016110115761100083838d8c612cc0565b86604001818151610e4e9190613ebc565b6040517f0561d8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050806001019050610cc1565b5061105e8482612e29565b50505050505050565b60036110766020830183613f21565b600381111561108757611087613ef4565b036110ec576001600160a01b0383166110ac836110a76040850185613d7f565b611b50565b6001600160a01b031614610c2b576040517fb81d58e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016110fb6020830183613f21565b600381111561110c5761110c613ef4565b036111a0577f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c839052603c90206001600160a01b03841661115a826110a76040860186613d7f565b6001600160a01b03161461119a576040517f644ae6c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60026111af6020830183613f21565b60038111156111c0576111c0613ef4565b036112b9577f1626ba7e000000000000000000000000000000000000000000000000000000006001600160a01b038416631626ba7e846112036040860186613d7f565b6040518463ffffffff1660e01b815260040161122193929190613f3f565b602060405180830381865afa15801561123c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112609190613f58565b7fffffffff000000000000000000000000000000000000000000000000000000001614610c2b576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f60cd402d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112f46104d7565b7fd28e809b708f5ee38be8347d6d869d8232493c094ab2dde98369e4102369a99d61131f8480613d7f565b604051602001611330929190613f97565b60405160208183030381529060405280519060200120846020013585604001602081019061135e9190613c16565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526113c46080850160608601613c16565b6113d460a0860160808701613c16565b6113e460c0870160a08801613c16565b60c087013560e08801356101008901356101208a013561140c6101608c016101408d01613c16565b604080516001600160a01b03998a166020820152978916908801529487166060870152608086019390935260a085019190915260c084015260e083015290911661010082015261012001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526114929291602001613fd7565b6040516020818303038152906040528051906020012060405160200161064a9291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6114f2611bdb565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906302cc250d90602401602060405180830381865afa15801561156d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115919190613bfb565b6115c7576040517fc139eabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa158015611644573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116689190613bfb565b61169e576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61020086013587158015906116b857506101608701358811155b156116d7576116d4886102008901356101608a01356001611c1e565b90505b6117087f00000000000000000000000000000000000000000000000000000000000000008a838a8a8a8a8a8a611c69565b611745878a838b158061171f57506101608b01358c115b611729578b611730565b6101608b01355b888b8b60016108af60408d0160208e01613d61565b6117526040880188613d7f565b604051611760929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661179a60a08a0160808b01613c16565b6117aa60c08b0160a08c01613c16565b6117bc6101408c016101208d01613c16565b6117ce6101e08d016101c08e01613c16565b8d15806117df57506101608d01358e115b6117e9578d6117f0565b6101408d01355b6102008e013588146118025787611809565b6101e08e01355b8e60e001602081019061181c9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a25061186e60018055565b5050505050505050565b6118828583612212565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66118c16080880160608901613c16565b6118d160a0890160808a01613c16565b8860c00135856040518563ffffffff1660e01b81526004016118f69493929190613c8d565b5f604051808303815f87803b15801561190d575f80fd5b505af115801561191f573d5f803e3d5ffd5b5050505061194486868686600289602001602081019061193f9190613d61565b6122c9565b505050505050565b5f6119556104d7565b7fc994d2ca0375d6d473785e0ce0b1d203f069121bac1314f72c5c0fe601eb39106119836040850185613d7f565b604051602001611994929190613f97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060608501356119df60a0870160808801613c16565b6119ef60c0880160a08901613c16565b60c0880135611a056101008a0160e08b01613c16565b60408051602081019890985287019590955260608601939093526001600160a01b039182166080860152811660a085015260c08401919091521660e0820152610100808501359082015261012001604051602081830303815290604052611a6f8461012001610c30565b611a7c856101c0016105c6565b60405160200161149293929190613feb565b6101a0810135611aa8610180830135610160840135613ebc565b611ab29190613ebc565b61014082013514611aef576040517fc04377d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610240810135611b09610220830135610200840135613ebc565b611b139190613ebc565b6101e082013514610c89576040517f877630be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ed692505050565b90506001600160a01b038116611bd3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b600260015403611c17576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600155565b5f611c4b611c2b83612f00565b8015611c4657505f8480611c4157611c41614008565b868809115b151590565b611c56868686612f2c565b611c609190613ebc565b95945050505050565b5f611c738761194c565b9050611c80898285611067565b611c9060c0880160a08901613c16565b6001600160a01b0316336001600160a01b031614611cc757611cc2611cbb60c0890160a08a01613c16565b8284611067565b611d0e565b611cd46040830183613d7f565b90505f03611d0e576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d2b611d2160c0890160a08a01613c16565b886060013561261e565b8660c00135421115611d69576040517f133df02900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f88118015611d7c575086610100013588105b15611db3576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dbc87611a8e565b611dc68a856109e8565b611de78a8a5f8b118015611ddf57506102008a01358b14155b8a8a8a610c8c565b611df589886060013561261e565b50505050505050505050565b611e13611e0e8680613def565b613001565b5f611e286101808b01356101a08c0135613ebc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611e779190613c16565b6001600160a01b03168152602001306001600160a01b031681526020018d610120015f016020810190611eaa9190613c16565b6001600160a01b03168152602001848152602001866002811115611ed057611ed0613ef4565b8152506040518263ffffffff1660e01b8152600401611eef9190614035565b5f604051808303815f87803b158015611f06575f80fd5b505af1158015611f18573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611f699190613c16565b6001600160a01b031681526020018d60e0016020810190611f8a9190613c16565b6001600160a01b031681526020018d610120015f016020810190611fae9190613c16565b6001600160a01b031681526020018a8152602001866002811115611fd457611fd4613ef4565b8152506040518263ffffffff1660e01b8152600401611ff39190614035565b5f604051808303815f87803b15801561200a575f80fd5b505af115801561201c573d5f803e3d5ffd5b5050505061202a8585613001565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808c6001600160a01b031681526020018d60800160208101906120869190613c16565b6001600160a01b031681526020018d6101c0015f0160208101906120aa9190613c16565b6001600160a01b031681526020018b81526020018560028111156120d0576120d0613ef4565b8152506040518263ffffffff1660e01b81526004016120ef9190614035565b5f604051808303815f87803b158015612106575f80fd5b505af1158015612118573d5f803e3d5ffd5b5061212e9250611e0e9150506020880188613def565b5f6121416101408c016101208d01613c16565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561219e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c291906140b4565b90508015612205576122056121de6101008d0160e08e01613c16565b828d610120015f0160208101906121f59190613c16565b6001600160a01b03169190613139565b5050505050505050505050565b6122226080830160608401613c16565b6001600160a01b0316336001600160a01b0316146122615761225c61224d6080840160608501613c16565b612256846112eb565b83611067565b6122a8565b61226e6040820182613d7f565b90505f036122a8576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122c56122bb6080840160608501613c16565b836020013561261e565b5050565b60e085013583158015906122e057508560c0013584105b156122fd576122fa848760e001358860c001356001611c1e565b90505b612309878288886131b9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808960600160208101906123569190613c16565b6001600160a01b031681526020016123766101608b016101408c01613c16565b6001600160a01b0316815260200161239460a08b0160808c01613c16565b6001600160a01b031681526020018715806123b257508960c0013588115b6123bc57876123c2565b8960c001355b81526020018660028111156123d9576123d9613ef4565b8152506040518263ffffffff1660e01b81526004016123f89190614035565b5f604051808303815f87803b15801561240f575f80fd5b505af1158015612421573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808a6001600160a01b031681526020018960400160208101906124819190613c16565b6001600160a01b0316815260200161249f60c08b0160a08c01613c16565b6001600160a01b031681526020018481526020018560028111156124c5576124c5613ef4565b8152506040518263ffffffff1660e01b81526004016124e49190614035565b5f604051808303815f87803b1580156124fb575f80fd5b505af115801561250d573d5f803e3d5ffd5b5061251e9250889150819050613d7f565b60405161252c929190613de0565b60405180910390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b68760400160208101906125689190613c16565b61257860808a0160608b01613c16565b61258860a08b0160808c01613c16565b61259860c08c0160a08d01613c16565b8915806125a857508b60c001358a115b6125b257896125b8565b8b60c001355b878d6101400160208101906125cd9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a250505050505050565b6001600160a01b0382165f9081526020818152604080832084845290915290205460ff1615612679576040517fbc0da7d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b039091165f908152602081815260408083209383529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f8080806126d5876004818b6140cb565b8101906126e291906140f2565b50919450925090506126fc61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612746576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612791576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b979650505050505050565b5f808080806127ec886004818c6140cb565b8101906127f99190614142565b929650909450925090506128156101e087016101c08801613c16565b6001600160a01b0316846001600160a01b03161461285f576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b0316146128aa576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128ba60a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612904576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b98975050505050505050565b5f805f805f805f805f8c8c600490809261296a939291906140cb565b8101906129779190614190565b959c50939a50919850965094509250905061299a6101e08b016101c08c01613c16565b6001600160a01b0316876001600160a01b0316146129e4576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856001600160a01b03168b6001600160a01b031614612a2f576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385163014612a71576040517f8154374b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612a8160a08b0160808c01613c16565b6001600160a01b0316846001600160a01b031614612acb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408a01358314612b09576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b1b6101408b016101208c01613c16565b6001600160a01b0316826001600160a01b031614612b65576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a08a01358114612ba3576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919c919b50909950505050505050505050565b5f808080612bc7876004818b6140cb565b810190612bd4919061420f565b91945092509050612bed61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612c37576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612c82576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61018085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808080612cd2886004818c6140cb565b810190612cdf919061424d565b5092965090945092509050612cfc6101e087016101c08801613c16565b6001600160a01b0316846001600160a01b031614612d46576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614612d91576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612da160a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612deb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102208601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051610180830135141580612e47575060208101516101a083013514155b15612e7e576040517f4a55da2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610220830135141580612e9f5750606081015161024083013514155b156122c5576040517f77a5920300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f80612ee4868661325c565b925092509250612ef482826132a5565b50909150505b92915050565b5f6002826003811115612f1557612f15613ef4565b612f1f91906142b1565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03612f7f57838281612f7557612f75614008565b04925050506104d0565b808411612f9657612f9660038515026011186133ad565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f5b81811015610c2b573683838381811061301e5761301e613e53565b90506020028101906130309190613e80565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130696020830183613c16565b6001600160a01b0316036130a9576040517f79a1bff000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130b2816133be565b6130bf6020820182613c16565b6001600160a01b03167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356130f784613401565b604080519283527fffffffff0000000000000000000000000000000000000000000000000000000090911660208301520160405180910390a250600101613003565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610c2b90849061342a565b5f831180156131cc575081610100013583105b15613203576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61321084612256846112eb565b61321e84836020013561261e565b428261012001351161119a576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f8351604103613293576020840151604085015160608601515f1a613285888285856134af565b95509550955050505061329e565b505081515f91506002905b9250925092565b5f8260038111156132b8576132b8613ef4565b036132c1575050565b60018260038111156132d5576132d5613ef4565b0361330c576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561332057613320613ef4565b0361335f576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600382600381111561337357613373613ef4565b036122c5576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401613356565b634e487b715f52806020526024601cfd5b5f6133cc6020830183613c16565b90506020820135365f6133e26040860186613d7f565b91509150604051818382375f80838387895af1611944573d5f803e3d5ffd5b5f36816134116040850185613d7f565b90925090506004811061342357813592505b5050919050565b5f8060205f8451602086015f885af180613449576040513d5f823e3d81fd5b50505f513d9150811561346057806001141561346d565b6001600160a01b0384163b155b1561119a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613356565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156134e857505f9150600390508261358b565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613539573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811661358257505f92506001915082905061358b565b92505f91508190505b9450945094915050565b5f805f604084860312156135a7575f80fd5b83359250602084013567ffffffffffffffff808211156135c5575f80fd5b818601915086601f8301126135d8575f80fd5b8135818111156135e6575f80fd5b8760208285010111156135f7575f80fd5b6020830194508093505050509250925092565b5f60a0828403121561361a575f80fd5b50919050565b5f60a08284031215613630575f80fd5b6104d0838361360a565b6001600160a01b0381168114610c89575f80fd5b80356136598161363a565b919050565b5f610260828403121561361a575f80fd5b5f8083601f84011261367f575f80fd5b50813567ffffffffffffffff811115613696575f80fd5b6020830191508360208260051b85010111156136b0575f80fd5b9250929050565b5f6040828403121561361a575f80fd5b5f6060828403121561361a575f80fd5b5f805f805f805f805f6101008a8c0312156136f0575f80fd5b6136f98a61364e565b985060208a0135975060408a013567ffffffffffffffff8082111561371c575f80fd5b6137288d838e0161365e565b985060608c013591508082111561373d575f80fd5b6137498d838e0161366f565b909850965060808c0135915080821115613761575f80fd5b61376d8d838e016136b7565b955060a08c0135915080821115613782575f80fd5b61378e8d838e016136c7565b945060c08c01359150808211156137a3575f80fd5b6137af8d838e016136c7565b935060e08c01359150808211156137c4575f80fd5b506137d18c828d016136c7565b9150509295985092959850929598565b5f80604083850312156137f2575f80fd5b82356137fd8161363a565b9150602083013567ffffffffffffffff811115613818575f80fd5b613824858286016136b7565b9150509250929050565b5f610160828403121561361a575f80fd5b5f805f805f60a08688031215613853575f80fd5b853561385e8161363a565b9450602086013567ffffffffffffffff8082111561387a575f80fd5b61388689838a0161382e565b9550604088013591508082111561389b575f80fd5b6138a789838a016136c7565b94506060880135935060808801359150808211156138c3575f80fd5b506138d0888289016136c7565b9150509295509295909350565b5f602082840312156138ed575f80fd5b5035919050565b8015158114610c89575f80fd5b5f805f805f8060a08789031215613916575f80fd5b86356139218161363a565b955060208701356139318161363a565b94506040870135613941816138f4565b9350606087013567ffffffffffffffff8082111561395d575f80fd5b6139698a838b0161365e565b9450608089013591508082111561397e575f80fd5b5061398b89828a0161366f565b979a9699509497509295939492505050565b5f805f606084860312156139af575f80fd5b83356139ba8161363a565b925060208401359150604084013567ffffffffffffffff8111156139dc575f80fd5b6139e8868287016136c7565b9150509250925092565b5f60208284031215613a02575f80fd5b813567ffffffffffffffff811115613a18575f80fd5b611bd38482850161382e565b5f805f805f805f8060e0898b031215613a3b575f80fd5b613a448961364e565b975060208901359650604089013567ffffffffffffffff80821115613a67575f80fd5b613a738c838d0161365e565b975060608b0135915080821115613a88575f80fd5b613a948c838d0161366f565b909750955060808b0135915080821115613aac575f80fd5b613ab88c838d016136b7565b945060a08b0135915080821115613acd575f80fd5b613ad98c838d016136c7565b935060c08b0135915080821115613aee575f80fd5b50613afb8b828c016136c7565b9150509295985092959890939650565b5f805f805f8060c08789031215613b20575f80fd5b613b298761364e565b9550602087013567ffffffffffffffff80821115613b45575f80fd5b613b518a838b0161382e565b96506040890135915080821115613b66575f80fd5b613b728a838b016136c7565b9550606089013594506080890135915080821115613b8e575f80fd5b613b9a8a838b016136c7565b935060a0890135915080821115613baf575f80fd5b50613bbc89828a016136c7565b9150509295509295509295565b5f60208284031215613bd9575f80fd5b813567ffffffffffffffff811115613bef575f80fd5b611bd38482850161365e565b5f60208284031215613c0b575f80fd5b81516104d0816138f4565b5f60208284031215613c26575f80fd5b81356104d08161363a565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b803565ffffffffffff81168114613659575f80fd5b5f6001600160a01b0380871683528086166020840152508360408301526080606083015282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ce2575f80fd5b830160208101903567ffffffffffffffff811115613cfe575f80fd5b803603821315613d0c575f80fd5b60606080850152613d2160e085018284613c31565b915050613d3060208501613c78565b65ffffffffffff80821660a086015280613d4c60408801613c78565b1660c086015250508091505095945050505050565b5f60208284031215613d71575f80fd5b8135600381106104d0575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db2575f80fd5b83018035915067ffffffffffffffff821115613dcc575f80fd5b6020019150368190038213156136b0575f80fd5b818382375f9101908152919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e22575f80fd5b83018035915067ffffffffffffffff821115613e3c575f80fd5b6020019150600581901b36038213156136b0575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112613eb2575f80fd5b9190910192915050565b80820180821115612efa577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613f31575f80fd5b8135600481106104d0575f80fd5b838152604060208201525f611c60604083018486613c31565b5f60208284031215613f68575f80fd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146104d0575f80fd5b602081525f611bd3602083018486613c31565b5f81515f5b81811015613fc95760208185018101518683015201613faf565b505f93019283525090919050565b5f611bd3613fe58386613faa565b84613faa565b5f613ff68286613faa565b93845250506020820152604001919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60a0820190506001600160a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151600381106140a7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8060808401525092915050565b5f602082840312156140c4575f80fd5b5051919050565b5f80858511156140d9575f80fd5b838611156140e5575f80fd5b5050820193919092039150565b5f805f8060808587031215614105575f80fd5b84356141108161363a565b935060208501356141208161363a565b9250604085013591506060850135614137816138f4565b939692955090935050565b5f805f8060808587031215614155575f80fd5b84356141608161363a565b935060208501356141708161363a565b925060408501356141808161363a565b9396929550929360600135925050565b5f805f805f805f60e0888a0312156141a6575f80fd5b87356141b18161363a565b965060208801356141c18161363a565b955060408801356141d18161363a565b945060608801356141e18161363a565b93506080880135925060a08801356141f88161363a565b8092505060c0880135905092959891949750929550565b5f805f60608486031215614221575f80fd5b833561422c8161363a565b9250602084013561423c8161363a565b929592945050506040919091013590565b5f805f805f60a08688031215614261575f80fd5b853561426c8161363a565b9450602086013561427c8161363a565b9350604086013561428c8161363a565b92506060860135915060808601356142a3816138f4565b809150509295509295909350565b5f60ff8316806142e8577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff8416069150509291505056fea26469706673582212209be58acada353061a2a202cc7011f3c91393e0f2e305e9202445b042fc4a4ce664736f6c6343000817003360c060405234801561000f575f80fd5b5060405161096338038061096383398101604081905261002e91610060565b6001600160a01b039182166080521660a052610091565b80516001600160a01b038116811461005b575f80fd5b919050565b5f8060408385031215610071575f80fd5b61007a83610045565b915061008860208401610045565b90509250929050565b60805160a05161089e6100c55f395f81816048015281816101f2015261038101525f818160d30152610327015261089e5ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c80636afdd85014610043578063b519d36914610093578063bc1178e6146100a8575b5f80fd5b61006a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100a66100a136600461060a565b6100bb565b005b6100a66100b6366004610648565b61030f565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016811461012b576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820135156101af57600161014760a08401608085016106dd565b6002811115610158576101586106b0565b036101b3576101af61016d6020840184610702565b61017d6040850160208601610702565b606085018035906101919060408801610702565b73ffffffffffffffffffffffffffffffffffffffff169291906104cc565b5050565b60026101c560a08401608085016106dd565b60028111156101d6576101d66106b0565b036102dd5773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166336c785166102246020850185610702565b6102346040860160208701610702565b606086018035906102489060408901610702565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152908316604483015290911660648201526084015f604051808303815f87803b1580156102c3575f80fd5b505af11580156102d5573d5f803e3d5ffd5b505050505050565b6040517fc79aaa4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016811461037f576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632b67b57086604051806060016040528060405180608001604052808a73ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff16815260200188604001602081019061041d919061071b565b65ffffffffffff16815260200188602001602081019061043d919061071b565b65ffffffffffff1690528152306020820152604090810190610465906060890190890161071b565b65ffffffffffff1690526104798680610740565b6040518563ffffffff1660e01b815260040161049894939291906107a8565b5f604051808303815f87803b1580156104af575f80fd5b505af11580156104c1573d5f803e3d5ffd5b505050505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610561908590610567565b50505050565b5f8060205f8451602086015f885af180610586576040513d5f823e3d81fd5b50505f513d9150811561059d5780600114156105b7565b73ffffffffffffffffffffffffffffffffffffffff84163b155b15610561576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240160405180910390fd5b5f60a0828403121561061a575f80fd5b50919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610643575f80fd5b919050565b5f805f806080858703121561065b575f80fd5b61066485610620565b935061067260208601610620565b925060408501359150606085013567ffffffffffffffff811115610694575f80fd5b8501606081880312156106a5575f80fd5b939692955090935050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f602082840312156106ed575f80fd5b8135600381106106fb575f80fd5b9392505050565b5f60208284031215610712575f80fd5b6106fb82610620565b5f6020828403121561072b575f80fd5b813565ffffffffffff811681146106fb575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610773575f80fd5b83018035915067ffffffffffffffff82111561078d575f80fd5b6020019150368190038213156107a1575f80fd5b9250929050565b5f61010073ffffffffffffffffffffffffffffffffffffffff80881684528651818151166020860152816020820151166040860152604081015165ffffffffffff80821660608801528060608401511660808801525050508060208801511660a085015250604086015160c08401528060e08401528381840152506101208385828501375f838501820152601f9093017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910190910194935050505056fea2646970667358221220f3565f6589500276fcbb6fb33d3ee3b534d9566c5b2732fe10a6039b753c3a0764736f6c63430008170033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01 `@R4\x80\x15b\0\0\x11W_\x80\xFD[P`@Qb\0N\xF68\x03\x80b\0N\xF6\x839\x81\x01`@\x81\x90Rb\0\x004\x91b\0\x01uV[F`\xA0\x81\x81R`@\x80Q\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0F` \x82\x01R\x7Fd\xAF\xEC{\xE6Q\xC9/\x86uK\xEB+\xD5\xEE\xAF/\xA9^\x83\xFA\xF4\xAE\xE9\x89\x87}\xDE\x08\xE4I\x8C\x91\x81\x01\x91\x90\x91R\x7F\xC8\x9E\xFD\xAAT\xC0\xF2\x0Cz\xDFa(\x82\xDF\tP\xF5\xA9Qc~\x03\x07\xCD\xCBLg/)\x8B\x8B\xC6``\x82\x01R`\x80\x81\x01\x92\x90\x92R0\x90\x82\x01R`\xC0\x01`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x90\x82\x90R\x80Q` \x90\x91\x01 `\x80R`\x01\x80U`\x01`\x01`\xA0\x1B\x03\x84\x16`\xC0R0\x90\x82\x90b\0\0\xFE\x90b\0\x01OV[`\x01`\x01`\xA0\x1B\x03\x92\x83\x16\x81R\x91\x16` \x82\x01R`@\x01`@Q\x80\x91\x03\x90_\xF0\x80\x15\x80\x15b\0\x01/W=_\x80>=_\xFD[P`\x01`\x01`\xA0\x1B\x03\x90\x81\x16`\xE0R\x91\x90\x91\x16a\x01\0RPb\0\x01\xC6\x90PV[a\tc\x80b\0E\x93\x839\x01\x90V[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x01rW_\x80\xFD[PV[_\x80_``\x84\x86\x03\x12\x15b\0\x01\x88W_\x80\xFD[\x83Qb\0\x01\x95\x81b\0\x01]V[` \x85\x01Q\x90\x93Pb\0\x01\xA8\x81b\0\x01]V[`@\x85\x01Q\x90\x92Pb\0\x01\xBB\x81b\0\x01]V[\x80\x91PP\x92P\x92P\x92V[`\x80Q`\xA0Q`\xC0Q`\xE0Qa\x01\0QaC-b\0\x02f_9_\x81\x81a\x02W\x01R\x81\x81a\x07\x84\x01Ra\x16\xDC\x01R_\x81\x81a\x01\x97\x01R\x81\x81a\x07\xBA\x01R\x81\x81a\x18\x8C\x01R\x81\x81a\x1E,\x01R\x81\x81a\x1F\x1E\x01R\x81\x81a ,\x01R\x81\x81a#\x0B\x01R\x81\x81a$'\x01Ra0<\x01R_\x81\x81a\x038\x01R\x81\x81a\x04\x12\x01R\x81\x81a\x06\xA7\x01R\x81\x81a\x15 \x01Ra\x15\xFF\x01R_a\x04\xDA\x01R_a\x05\xA4\x01RaC-_\xF3\xFE`\x80`@R`\x046\x10a\x01&W_5`\xE0\x1C\x80c\xA5\xCD\xC8\xFC\x11a\0\xA1W\x80c\xC6\x18a\x81\x11a\0qW\x80c\xDBXw(\x11a\0WW\x80c\xDBXw(\x14a\x03yW\x80c\xE2B\x92N\x14a\x03\x8CW\x80c\xFA\\\xD5l\x14a\x03\xABW_\x80\xFD[\x80c\xC6\x18a\x81\x14a\x03'W\x80c\xCB\xA6s\xA7\x14a\x03ZW_\x80\xFD[\x80c\xA5\xCD\xC8\xFC\x14a\x02\xABW\x80c\xA7\xABI\xBC\x14a\x02\xCAW\x80c\xAE\x80\xC5\x84\x14a\x02\xE9W\x80c\xB1\x1F\x12b\x14a\x03\x08W_\x80\xFD[\x80cQ\xD4h\x15\x11a\0\xF6W\x80co5\xD2\xD2\x11a\0\xDCW\x80co5\xD2\xD2\x14a\x02FW\x80c\x87U0\xFF\x14a\x02yW\x80c\x995\xC8h\x14a\x02\x98W_\x80\xFD[\x80cQ\xD4h\x15\x14a\x02\x12W\x80cZ\xA0\xE9]\x14a\x02'W_\x80\xFD[\x80c\x16&\xBA~\x14a\x011W\x80c)\xBC\xDC\x95\x14a\x01\x86W\x80c6D\xE5\x15\x14a\x01\xD1W\x80cL\x9E\x03\xD3\x14a\x01\xF3W_\x80\xFD[6a\x01-W\0[_\x80\xFD[4\x80\x15a\x01=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x04}\x91\x90a;\xFBV[\x15a\x04\xABW\x7F\x16&\xBA~5oYy\xDD5Z=+\xFBC\xE8\x04 \xA4\x80\xC3\xB8T\xED\xCE(j\x82\xD7Ihi\x91PPa\x04\xD0V[P\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90P[\x93\x92PPPV[_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0F\x14a\x05\xA1W`@\x80Q\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0F` \x82\x01R\x7Fd\xAF\xEC{\xE6Q\xC9/\x86uK\xEB+\xD5\xEE\xAF/\xA9^\x83\xFA\xF4\xAE\xE9\x89\x87}\xDE\x08\xE4I\x8C\x91\x81\x01\x91\x90\x91R\x7F\xC8\x9E\xFD\xAAT\xC0\xF2\x0Cz\xDFa(\x82\xDF\tP\xF5\xA9Qc~\x03\x07\xCD\xCBLg/)\x8B\x8B\xC6``\x82\x01RF`\x80\x82\x01R0`\xA0\x82\x01R`\xC0\x01`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x90V[P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[_\x7Fh\xB8\xE9M\xC0wE\x82A\xD6\xC8\xD8\x9F\nve\xC7\xCD\xA2\xCF\xE7\x0C\x9E\xB4C~\xFE\xE1f=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x10\x91\x90a;\xFBV[a\x07FW`@Q\x7F\xB31\xE4!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02\0\x87\x015\x88\x15\x80\x15\x90a\x07`WPa\x01`\x88\x015\x89\x11\x15[\x15a\x07\x7FWa\x07|\x89a\x02\0\x8A\x015a\x01`\x8B\x015`\x01a\x1C\x1EV[\x90P[a\x07\xB0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8B\x83\x8B\x8B\x8B\x8B\x8B\x8Ba\x1CiV[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16c\xBC\x11x\xE6a\x07\xEF`\xC0\x8B\x01`\xA0\x8C\x01a<\x16V[a\x08\x01a\x01@\x8C\x01a\x01 \x8D\x01a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x85\x90\x1B\x16\x81Ra\x08D\x92\x91\x90a\x01`\x8E\x015\x90\x88\x90`\x04\x01a<\x8DV[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x08[W_\x80\xFD[PZ\xF1\x15\x80\x15a\x08mW=_\x80>=_\xFD[PPPPa\x08\xB4\x88\x8B\x83\x8C_\x14\x80a\x08\x89WPa\x01`\x8C\x015\x8D\x11[a\x08\x93W\x8Ca\x08\x9AV[a\x01`\x8C\x015[\x89\x8C\x8C`\x02a\x08\xAF`@\x8E\x01` \x8F\x01a=aV[a\x1E\x01V[a\x08\xC1`@\x89\x01\x89a=\x7FV[`@Qa\x08\xCF\x92\x91\x90a=\xE0V[`@Q\x90\x81\x90\x03\x90 \x7F\x0F\xCE\0|8\xC6\xC8\xED\x9ET[:\x14\x80\x95v'8a\x8F\x8C!\xB6s\"&\x13\xE4\xD4W4\xB6a\t\t`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[a\t\x19`\xC0\x8C\x01`\xA0\x8D\x01a<\x16V[a\t+a\x01@\x8D\x01a\x01 \x8E\x01a<\x16V[a\t=a\x01\xE0\x8E\x01a\x01\xC0\x8F\x01a<\x16V[\x8E\x15\x80a\tNWPa\x01`\x8E\x015\x8F\x11[a\tXW\x8Ea\t_V[a\x01@\x8E\x015[a\x02\0\x8F\x015\x88\x14a\tqW\x87a\txV[a\x01\xE0\x8F\x015[\x8F`\xE0\x01` \x81\x01\x90a\t\x8B\x91\x90a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x98\x89\x16\x81R\x96\x88\x16` \x88\x01R\x94\x87\x16\x94\x86\x01\x94\x90\x94R\x91\x85\x16``\x85\x01R`\x80\x84\x01R`\xA0\x83\x01R\x90\x91\x16`\xC0\x82\x01R`\xE0\x01`@Q\x80\x91\x03\x90\xA2Pa\t\xDD`\x01\x80UV[PPPPPPPPPV[_[a\t\xF4\x82\x80a=\xEFV[\x90P\x81\x10\x15a\x0B\x06W6a\n\x08\x83\x80a=\xEFV[\x83\x81\x81\x10a\n\x18Wa\n\x18a>SV[\x90P` \x02\x81\x01\x90a\n*\x91\x90a>\x80V[\x90P`\x01`\x01`\xA0\x1B\x03\x84\x16c\xA8\xC4\xBC\x95a\nH` \x84\x01\x84a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\n\xA2W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\n\xC6\x91\x90a;\xFBV[\x15a\n\xFDW`@Q\x7F\xC9\x9E\x88r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P`\x01\x01a\t\xEAV[P_[a\x0B\x16` \x83\x01\x83a=\xEFV[\x90P\x81\x10\x15a\x0C+W6a\x0B-` \x84\x01\x84a=\xEFV[\x83\x81\x81\x10a\x0B=Wa\x0B=a>SV[\x90P` \x02\x81\x01\x90a\x0BO\x91\x90a>\x80V[\x90P`\x01`\x01`\xA0\x1B\x03\x84\x16c\xA8\xC4\xBC\x95a\x0Bm` \x84\x01\x84a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0B\xC7W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0B\xEB\x91\x90a;\xFBV[\x15a\x0C\"W`@Q\x7F\xC9\x9E\x88r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P`\x01\x01a\x0B\tV[PPPV[_\x7F\xAEgk\xF6\x91:\xC2h\x9Bs1)<\x98\x9F\xE7r1$\xFA\xF8\xB5\xD2u\xF0o\xBC\xEB\xC7yP\ta\x05\xF5` \x84\x01\x84a<\x16V[a\x0Ci\x84\x82a\"\x12V[a\x0Cx\x85\x85\x85\x85`\x01\x80a\"\xC9V[PPPPPV[a\x0C\x893\x82a&\x1EV[PV[a\x0C\xBF`@Q\x80`\xC0\x01`@R\x80_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81RP\x90V[_[\x82\x81\x10\x15a\x10SW6\x84\x84\x83\x81\x81\x10a\x0C\xDCWa\x0C\xDCa>SV[\x90P` \x02\x81\x01\x90a\x0C\xEE\x91\x90a>\x80V[\x90P6_a\x0C\xFF`@\x84\x01\x84a=\x7FV[\x90\x92P\x90P`\x01`\x01`\xA0\x1B\x03\x8B\x16c\xA8\xC4\xBC\x95a\r ` \x86\x01\x86a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\rzW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\r\x9E\x91\x90a;\xFBV[\x15a\x10EW_\x89\x15a\r\xDCW`@Q\x7F}a{\xB3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x04\x82\x10a\r\xE8WP\x815[\x7F\xC0:\x9D\xE9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0EVWa\x0E=\x83\x83\x8D\x8Ca&\xC4V[\x86` \x01\x81\x81Qa\x0EN\x91\x90a>\xBCV[\x90RPa\x10CV[\x7F$:K\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0E\xBCWa\x0E\xAB\x83\x83\x8D\x8Ca'\xDAV[\x86``\x01\x81\x81Qa\x0EN\x91\x90a>\xBCV[\x7F}\xC4\xF4X\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0FGWa\x0F\x11\x83\x83\x8D\x8Ca)NV[`\xA0\x88\x01R`\x80\x87\x01\x81\x90R``\x87\x01\x80Qa\x0F.\x90\x83\x90a>\xBCV[\x90RP`\xA0\x86\x01Q` \x87\x01\x80Qa\x0EN\x90\x83\x90a>\xBCV[\x7Fh\x93\x1Bk\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0F\xABWa\x0F\x9C\x83\x83\x8D\x8Ca+\xB6V[\x86Q\x87\x90a\x0EN\x90\x83\x90a>\xBCV[\x7F\x0C\x9B\xE7\xE4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x10\x11Wa\x10\0\x83\x83\x8D\x8Ca,\xC0V[\x86`@\x01\x81\x81Qa\x0EN\x91\x90a>\xBCV[`@Q\x7F\x05a\xD8\xB3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P[PPP\x80`\x01\x01\x90Pa\x0C\xC1V[Pa\x10^\x84\x82a.)V[PPPPPPPV[`\x03a\x10v` \x83\x01\x83a?!V[`\x03\x81\x11\x15a\x10\x87Wa\x10\x87a>\xF4V[\x03a\x10\xECW`\x01`\x01`\xA0\x1B\x03\x83\x16a\x10\xAC\x83a\x10\xA7`@\x85\x01\x85a=\x7FV[a\x1BPV[`\x01`\x01`\xA0\x1B\x03\x16\x14a\x0C+W`@Q\x7F\xB8\x1DX\xE7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x01a\x10\xFB` \x83\x01\x83a?!V[`\x03\x81\x11\x15a\x11\x0CWa\x11\x0Ca>\xF4V[\x03a\x11\xA0W\x7F\x19Ethereum Signed Message:\n32\0\0\0\0_\x90\x81R`\x1C\x83\x90R`<\x90 `\x01`\x01`\xA0\x1B\x03\x84\x16a\x11Z\x82a\x10\xA7`@\x86\x01\x86a=\x7FV[`\x01`\x01`\xA0\x1B\x03\x16\x14a\x11\x9AW`@Q\x7FdJ\xE6\xC3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[PPPPV[`\x02a\x11\xAF` \x83\x01\x83a?!V[`\x03\x81\x11\x15a\x11\xC0Wa\x11\xC0a>\xF4V[\x03a\x12\xB9W\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x84\x16c\x16&\xBA~\x84a\x12\x03`@\x86\x01\x86a=\x7FV[`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x12!\x93\x92\x91\x90a??V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x12=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x12`\x91\x90a?XV[\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x0C+W`@Q\x7F]R\xCB\xE3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@Q\x7F`\xCD@-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x12\xF4a\x04\xD7V[\x7F\xD2\x8E\x80\x9Bp\x8F^\xE3\x8B\xE84}m\x86\x9D\x822I<\tJ\xB2\xDD\xE9\x83i\xE4\x10#i\xA9\x9Da\x13\x1F\x84\x80a=\x7FV[`@Q` \x01a\x130\x92\x91\x90a?\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x84` \x015\x85`@\x01` \x81\x01\x90a\x13^\x91\x90a<\x16V[`@\x80Q` \x81\x01\x95\x90\x95R\x84\x01\x92\x90\x92R``\x83\x01R`\x01`\x01`\xA0\x1B\x03\x16`\x80\x82\x01R`\xA0\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90Ra\x13\xC4`\x80\x85\x01``\x86\x01a<\x16V[a\x13\xD4`\xA0\x86\x01`\x80\x87\x01a<\x16V[a\x13\xE4`\xC0\x87\x01`\xA0\x88\x01a<\x16V[`\xC0\x87\x015`\xE0\x88\x015a\x01\0\x89\x015a\x01 \x8A\x015a\x14\x0Ca\x01`\x8C\x01a\x01@\x8D\x01a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x99\x8A\x16` \x82\x01R\x97\x89\x16\x90\x88\x01R\x94\x87\x16``\x87\x01R`\x80\x86\x01\x93\x90\x93R`\xA0\x85\x01\x91\x90\x91R`\xC0\x84\x01R`\xE0\x83\x01R\x90\x91\x16a\x01\0\x82\x01Ra\x01 \x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x90\x82\x90Ra\x14\x92\x92\x91` \x01a?\xD7V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `@Q` \x01a\x06J\x92\x91\x90\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x01\x90V[a\x14\xF2a\x1B\xDBV[`@Q\x7F\x02\xCC%\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x90c\x02\xCC%\r\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x15mW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x15\x91\x91\x90a;\xFBV[a\x15\xC7W`@Q\x7F\xC19\xEA\xBD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@Q\x7F\xE7V\0\xC3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x89\x81\x16`\x04\x83\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90c\xE7V\0\xC3\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x16DW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x16h\x91\x90a;\xFBV[a\x16\x9EW`@Q\x7F\xB31\xE4!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02\0\x86\x015\x87\x15\x80\x15\x90a\x16\xB8WPa\x01`\x87\x015\x88\x11\x15[\x15a\x16\xD7Wa\x16\xD4\x88a\x02\0\x89\x015a\x01`\x8A\x015`\x01a\x1C\x1EV[\x90P[a\x17\x08\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8A\x83\x8A\x8A\x8A\x8A\x8A\x8Aa\x1CiV[a\x17E\x87\x8A\x83\x8B\x15\x80a\x17\x1FWPa\x01`\x8B\x015\x8C\x11[a\x17)W\x8Ba\x170V[a\x01`\x8B\x015[\x88\x8B\x8B`\x01a\x08\xAF`@\x8D\x01` \x8E\x01a=aV[a\x17R`@\x88\x01\x88a=\x7FV[`@Qa\x17`\x92\x91\x90a=\xE0V[`@Q\x90\x81\x90\x03\x90 \x7F\x0F\xCE\0|8\xC6\xC8\xED\x9ET[:\x14\x80\x95v'8a\x8F\x8C!\xB6s\"&\x13\xE4\xD4W4\xB6a\x17\x9A`\xA0\x8A\x01`\x80\x8B\x01a<\x16V[a\x17\xAA`\xC0\x8B\x01`\xA0\x8C\x01a<\x16V[a\x17\xBCa\x01@\x8C\x01a\x01 \x8D\x01a<\x16V[a\x17\xCEa\x01\xE0\x8D\x01a\x01\xC0\x8E\x01a<\x16V[\x8D\x15\x80a\x17\xDFWPa\x01`\x8D\x015\x8E\x11[a\x17\xE9W\x8Da\x17\xF0V[a\x01@\x8D\x015[a\x02\0\x8E\x015\x88\x14a\x18\x02W\x87a\x18\tV[a\x01\xE0\x8E\x015[\x8E`\xE0\x01` \x81\x01\x90a\x18\x1C\x91\x90a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x98\x89\x16\x81R\x96\x88\x16` \x88\x01R\x94\x87\x16\x94\x86\x01\x94\x90\x94R\x91\x85\x16``\x85\x01R`\x80\x84\x01R`\xA0\x83\x01R\x90\x91\x16`\xC0\x82\x01R`\xE0\x01`@Q\x80\x91\x03\x90\xA2Pa\x18n`\x01\x80UV[PPPPPPPPV[a\x18\x82\x85\x83a\"\x12V[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16c\xBC\x11x\xE6a\x18\xC1`\x80\x88\x01``\x89\x01a<\x16V[a\x18\xD1`\xA0\x89\x01`\x80\x8A\x01a<\x16V[\x88`\xC0\x015\x85`@Q\x85c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x18\xF6\x94\x93\x92\x91\x90a<\x8DV[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x19\rW_\x80\xFD[PZ\xF1\x15\x80\x15a\x19\x1FW=_\x80>=_\xFD[PPPPa\x19D\x86\x86\x86\x86`\x02\x89` \x01` \x81\x01\x90a\x19?\x91\x90a=aV[a\"\xC9V[PPPPPPV[_a\x19Ua\x04\xD7V[\x7F\xC9\x94\xD2\xCA\x03u\xD6\xD4sx^\x0C\xE0\xB1\xD2\x03\xF0i\x12\x1B\xAC\x13\x14\xF7,\\\x0F\xE6\x01\xEB9\x10a\x19\x83`@\x85\x01\x85a=\x7FV[`@Q` \x01a\x19\x94\x92\x91\x90a?\x97V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R\x80Q` \x90\x91\x01 ``\x85\x015a\x19\xDF`\xA0\x87\x01`\x80\x88\x01a<\x16V[a\x19\xEF`\xC0\x88\x01`\xA0\x89\x01a<\x16V[`\xC0\x88\x015a\x1A\x05a\x01\0\x8A\x01`\xE0\x8B\x01a<\x16V[`@\x80Q` \x81\x01\x98\x90\x98R\x87\x01\x95\x90\x95R``\x86\x01\x93\x90\x93R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\x80\x86\x01R\x81\x16`\xA0\x85\x01R`\xC0\x84\x01\x91\x90\x91R\x16`\xE0\x82\x01Ra\x01\0\x80\x85\x015\x90\x82\x01Ra\x01 \x01`@Q` \x81\x83\x03\x03\x81R\x90`@Ra\x1Ao\x84a\x01 \x01a\x0C0V[a\x1A|\x85a\x01\xC0\x01a\x05\xC6V[`@Q` \x01a\x14\x92\x93\x92\x91\x90a?\xEBV[a\x01\xA0\x81\x015a\x1A\xA8a\x01\x80\x83\x015a\x01`\x84\x015a>\xBCV[a\x1A\xB2\x91\x90a>\xBCV[a\x01@\x82\x015\x14a\x1A\xEFW`@Q\x7F\xC0Cw\xD3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02@\x81\x015a\x1B\ta\x02 \x83\x015a\x02\0\x84\x015a>\xBCV[a\x1B\x13\x91\x90a>\xBCV[a\x01\xE0\x82\x015\x14a\x0C\x89W`@Q\x7F\x87v0\xBE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80a\x1B\x91\x85\x85\x85\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x91\x90\x91RPa.\xD6\x92PPPV[\x90P`\x01`\x01`\xA0\x1B\x03\x81\x16a\x1B\xD3W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x94\x93PPPPV[`\x02`\x01T\x03a\x1C\x17W`@Q\x7F>\xE5\xAE\xB5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x02`\x01UV[_a\x1CKa\x1C+\x83a/\0V[\x80\x15a\x1CFWP_\x84\x80a\x1CAWa\x1CAa@\x08V[\x86\x88\t\x11[\x15\x15\x90V[a\x1CV\x86\x86\x86a/,V[a\x1C`\x91\x90a>\xBCV[\x95\x94PPPPPV[_a\x1Cs\x87a\x19LV[\x90Pa\x1C\x80\x89\x82\x85a\x10gV[a\x1C\x90`\xC0\x88\x01`\xA0\x89\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14a\x1C\xC7Wa\x1C\xC2a\x1C\xBB`\xC0\x89\x01`\xA0\x8A\x01a<\x16V[\x82\x84a\x10gV[a\x1D\x0EV[a\x1C\xD4`@\x83\x01\x83a=\x7FV[\x90P_\x03a\x1D\x0EW`@Q\x7F\x0E6N\xFC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x1D+a\x1D!`\xC0\x89\x01`\xA0\x8A\x01a<\x16V[\x88``\x015a&\x1EV[\x86`\xC0\x015B\x11\x15a\x1DiW`@Q\x7F\x13=\xF0)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x88\x11\x80\x15a\x1D|WP\x86a\x01\0\x015\x88\x10[\x15a\x1D\xB3W`@Q\x7F\x94itD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x1D\xBC\x87a\x1A\x8EV[a\x1D\xC6\x8A\x85a\t\xE8V[a\x1D\xE7\x8A\x8A_\x8B\x11\x80\x15a\x1D\xDFWPa\x02\0\x8A\x015\x8B\x14\x15[\x8A\x8A\x8Aa\x0C\x8CV[a\x1D\xF5\x89\x88``\x015a&\x1EV[PPPPPPPPPPV[a\x1E\x13a\x1E\x0E\x86\x80a=\xEFV[a0\x01V[_a\x1E(a\x01\x80\x8B\x015a\x01\xA0\x8C\x015a>\xBCV[\x90P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8D`\xA0\x01` \x81\x01\x90a\x1Ew\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x010`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8Da\x01 \x01_\x01` \x81\x01\x90a\x1E\xAA\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x84\x81R` \x01\x86`\x02\x81\x11\x15a\x1E\xD0Wa\x1E\xD0a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x1E\xEF\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x1F\x06W_\x80\xFD[PZ\xF1\x15\x80\x15a\x1F\x18W=_\x80>=_\xFD[PPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8D`\xA0\x01` \x81\x01\x90a\x1Fi\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8D`\xE0\x01` \x81\x01\x90a\x1F\x8A\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8Da\x01 \x01_\x01` \x81\x01\x90a\x1F\xAE\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8A\x81R` \x01\x86`\x02\x81\x11\x15a\x1F\xD4Wa\x1F\xD4a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x1F\xF3\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a \nW_\x80\xFD[PZ\xF1\x15\x80\x15a \x1CW=_\x80>=_\xFD[PPPPa *\x85\x85a0\x01V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8C`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8D`\x80\x01` \x81\x01\x90a \x86\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8Da\x01\xC0\x01_\x01` \x81\x01\x90a \xAA\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8B\x81R` \x01\x85`\x02\x81\x11\x15a \xD0Wa \xD0a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a \xEF\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a!\x06W_\x80\xFD[PZ\xF1\x15\x80\x15a!\x18W=_\x80>=_\xFD[Pa!.\x92Pa\x1E\x0E\x91PP` \x88\x01\x88a=\xEFV[_a!Aa\x01@\x8C\x01a\x01 \x8D\x01a<\x16V[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a!\x9EW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a!\xC2\x91\x90a@\xB4V[\x90P\x80\x15a\"\x05Wa\"\x05a!\xDEa\x01\0\x8D\x01`\xE0\x8E\x01a<\x16V[\x82\x8Da\x01 \x01_\x01` \x81\x01\x90a!\xF5\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x91\x90a19V[PPPPPPPPPPPV[a\"\"`\x80\x83\x01``\x84\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14a\"aWa\"\\a\"M`\x80\x84\x01``\x85\x01a<\x16V[a\"V\x84a\x12\xEBV[\x83a\x10gV[a\"\xA8V[a\"n`@\x82\x01\x82a=\x7FV[\x90P_\x03a\"\xA8W`@Q\x7F\x0E6N\xFC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\"\xC5a\"\xBB`\x80\x84\x01``\x85\x01a<\x16V[\x83` \x015a&\x1EV[PPV[`\xE0\x85\x015\x83\x15\x80\x15\x90a\"\xE0WP\x85`\xC0\x015\x84\x10[\x15a\"\xFDWa\"\xFA\x84\x87`\xE0\x015\x88`\xC0\x015`\x01a\x1C\x1EV[\x90P[a#\t\x87\x82\x88\x88a1\xB9V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x89``\x01` \x81\x01\x90a#V\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01a#va\x01`\x8B\x01a\x01@\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01a#\x94`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x87\x15\x80a#\xB2WP\x89`\xC0\x015\x88\x11[a#\xBCW\x87a#\xC2V[\x89`\xC0\x015[\x81R` \x01\x86`\x02\x81\x11\x15a#\xD9Wa#\xD9a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a#\xF8\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a$\x0FW_\x80\xFD[PZ\xF1\x15\x80\x15a$!W=_\x80>=_\xFD[PPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8A`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x89`@\x01` \x81\x01\x90a$\x81\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01a$\x9F`\xC0\x8B\x01`\xA0\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x84\x81R` \x01\x85`\x02\x81\x11\x15a$\xC5Wa$\xC5a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a$\xE4\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a$\xFBW_\x80\xFD[PZ\xF1\x15\x80\x15a%\rW=_\x80>=_\xFD[Pa%\x1E\x92P\x88\x91P\x81\x90Pa=\x7FV[`@Qa%,\x92\x91\x90a=\xE0V[`@Q\x80\x91\x03\x90 \x7F\x0F\xCE\0|8\xC6\xC8\xED\x9ET[:\x14\x80\x95v'8a\x8F\x8C!\xB6s\"&\x13\xE4\xD4W4\xB6\x87`@\x01` \x81\x01\x90a%h\x91\x90a<\x16V[a%x`\x80\x8A\x01``\x8B\x01a<\x16V[a%\x88`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[a%\x98`\xC0\x8C\x01`\xA0\x8D\x01a<\x16V[\x89\x15\x80a%\xA8WP\x8B`\xC0\x015\x8A\x11[a%\xB2W\x89a%\xB8V[\x8B`\xC0\x015[\x87\x8Da\x01@\x01` \x81\x01\x90a%\xCD\x91\x90a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x98\x89\x16\x81R\x96\x88\x16` \x88\x01R\x94\x87\x16\x94\x86\x01\x94\x90\x94R\x91\x85\x16``\x85\x01R`\x80\x84\x01R`\xA0\x83\x01R\x90\x91\x16`\xC0\x82\x01R`\xE0\x01`@Q\x80\x91\x03\x90\xA2PPPPPPPV[`\x01`\x01`\xA0\x1B\x03\x82\x16_\x90\x81R` \x81\x81R`@\x80\x83 \x84\x84R\x90\x91R\x90 T`\xFF\x16\x15a&yW`@Q\x7F\xBC\r\xA7\xD6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x01`\x01`\xA0\x1B\x03\x90\x91\x16_\x90\x81R` \x81\x81R`@\x80\x83 \x93\x83R\x92\x90R \x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x16`\x01\x17\x90UV[_\x80\x80\x80a&\xD5\x87`\x04\x81\x8Ba@\xCBV[\x81\x01\x90a&\xE2\x91\x90a@\xF2V[P\x91\x94P\x92P\x90Pa&\xFCa\x01@\x86\x01a\x01 \x87\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x83`\x01`\x01`\xA0\x1B\x03\x16\x14a'FW`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x81`\x01`\x01`\xA0\x1B\x03\x16\x86`\x01`\x01`\xA0\x1B\x03\x16\x14a'\x91W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x01\xA0\x85\x015\x81\x14a'\xCFW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x97\x96PPPPPPPV[_\x80\x80\x80\x80a'\xEC\x88`\x04\x81\x8Ca@\xCBV[\x81\x01\x90a'\xF9\x91\x90aABV[\x92\x96P\x90\x94P\x92P\x90Pa(\x15a\x01\xE0\x87\x01a\x01\xC0\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x14a(_W`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x82`\x01`\x01`\xA0\x1B\x03\x16\x87`\x01`\x01`\xA0\x1B\x03\x16\x14a(\xAAW`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a(\xBA`\xA0\x87\x01`\x80\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14a)\x04W`@Q\x7F\xACk\x05\xF5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02@\x86\x015\x81\x14a)BW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x98\x97PPPPPPPPV[_\x80_\x80_\x80_\x80_\x8C\x8C`\x04\x90\x80\x92a)j\x93\x92\x91\x90a@\xCBV[\x81\x01\x90a)w\x91\x90aA\x90V[\x95\x9CP\x93\x9AP\x91\x98P\x96P\x94P\x92P\x90Pa)\x9Aa\x01\xE0\x8B\x01a\x01\xC0\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x87`\x01`\x01`\xA0\x1B\x03\x16\x14a)\xE4W`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x85`\x01`\x01`\xA0\x1B\x03\x16\x8B`\x01`\x01`\xA0\x1B\x03\x16\x14a*/W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x01`\x01`\xA0\x1B\x03\x85\x160\x14a*qW`@Q\x7F\x81T7K\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a*\x81`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x14a*\xCBW`@Q\x7F\xACk\x05\xF5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02@\x8A\x015\x83\x14a+\tW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a+\x1Ba\x01@\x8B\x01a\x01 \x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14a+eW`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x01\xA0\x8A\x015\x81\x14a+\xA3W`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x91\x9C\x91\x9BP\x90\x99PPPPPPPPPPV[_\x80\x80\x80a+\xC7\x87`\x04\x81\x8Ba@\xCBV[\x81\x01\x90a+\xD4\x91\x90aB\x0FV[\x91\x94P\x92P\x90Pa+\xEDa\x01@\x86\x01a\x01 \x87\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x83`\x01`\x01`\xA0\x1B\x03\x16\x14a,7W`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x81`\x01`\x01`\xA0\x1B\x03\x16\x86`\x01`\x01`\xA0\x1B\x03\x16\x14a,\x82W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x01\x80\x85\x015\x81\x14a'\xCFW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80\x80\x80\x80a,\xD2\x88`\x04\x81\x8Ca@\xCBV[\x81\x01\x90a,\xDF\x91\x90aBMV[P\x92\x96P\x90\x94P\x92P\x90Pa,\xFCa\x01\xE0\x87\x01a\x01\xC0\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x14a-FW`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x82`\x01`\x01`\xA0\x1B\x03\x16\x87`\x01`\x01`\xA0\x1B\x03\x16\x14a-\x91W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a-\xA1`\xA0\x87\x01`\x80\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14a-\xEBW`@Q\x7F\xACk\x05\xF5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02 \x86\x015\x81\x14a)BW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x80Qa\x01\x80\x83\x015\x14\x15\x80a.GWP` \x81\x01Qa\x01\xA0\x83\x015\x14\x15[\x15a.~W`@Q\x7FJU\xDA \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@\x81\x01Qa\x02 \x83\x015\x14\x15\x80a.\x9FWP``\x81\x01Qa\x02@\x83\x015\x14\x15[\x15a\"\xC5W`@Q\x7Fw\xA5\x92\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80_\x80a.\xE4\x86\x86a2\\V[\x92P\x92P\x92Pa.\xF4\x82\x82a2\xA5V[P\x90\x91PP[\x92\x91PPV[_`\x02\x82`\x03\x81\x11\x15a/\x15Wa/\x15a>\xF4V[a/\x1F\x91\x90aB\xB1V[`\xFF\x16`\x01\x14\x90P\x91\x90PV[_\x83\x83\x02\x81\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x87\t\x82\x81\x10\x83\x82\x03\x03\x91PP\x80_\x03a/\x7FW\x83\x82\x81a/uWa/ua@\x08V[\x04\x92PPPa\x04\xD0V[\x80\x84\x11a/\x96Wa/\x96`\x03\x85\x15\x02`\x11\x18a3\xADV[_\x84\x86\x88\t_\x86\x81\x03\x87\x16\x96\x87\x90\x04\x96`\x02`\x03\x89\x02\x81\x18\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x90\x91\x03\x02\x91\x81\x90\x03\x81\x90\x04`\x01\x01\x86\x84\x11\x90\x95\x03\x94\x90\x94\x02\x91\x90\x94\x03\x92\x90\x92\x04\x91\x90\x91\x17\x91\x90\x91\x02\x91PP\x93\x92PPPV[_[\x81\x81\x10\x15a\x0C+W6\x83\x83\x83\x81\x81\x10a0\x1EWa0\x1Ea>SV[\x90P` \x02\x81\x01\x90a00\x91\x90a>\x80V[\x90P`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16a0i` \x83\x01\x83a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x03a0\xA9W`@Q\x7Fy\xA1\xBF\xF0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a0\xB2\x81a3\xBEV[a0\xBF` \x82\x01\x82a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x7F\xED\x99\x82~\xFB7\x01o\"u\xF9\x8CK\xCFq\xC7U\x1Cu\xD5\x9E\x9BE\x0Fy\xFA2\xE6\x0B\xE6r\xC2\x82` \x015a0\xF7\x84a4\x01V[`@\x80Q\x92\x83R\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16` \x83\x01R\x01`@Q\x80\x91\x03\x90\xA2P`\x01\x01a0\x03V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x84\x16`$\x82\x01R`D\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`d\x90\x91\x01\x90\x91R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90Ra\x0C+\x90\x84\x90a4*V[_\x83\x11\x80\x15a1\xCCWP\x81a\x01\0\x015\x83\x10[\x15a2\x03W`@Q\x7F\x94itD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a2\x10\x84a\"V\x84a\x12\xEBV[a2\x1E\x84\x83` \x015a&\x1EV[B\x82a\x01 \x015\x11a\x11\x9AW`@Q\x7F\xC5hs\xBA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80_\x83Q`A\x03a2\x93W` \x84\x01Q`@\x85\x01Q``\x86\x01Q_\x1Aa2\x85\x88\x82\x85\x85a4\xAFV[\x95P\x95P\x95PPPPa2\x9EV[PP\x81Q_\x91P`\x02\x90[\x92P\x92P\x92V[_\x82`\x03\x81\x11\x15a2\xB8Wa2\xB8a>\xF4V[\x03a2\xC1WPPV[`\x01\x82`\x03\x81\x11\x15a2\xD5Wa2\xD5a>\xF4V[\x03a3\x0CW`@Q\x7F\xF6E\xEE\xDF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x02\x82`\x03\x81\x11\x15a3 Wa3 a>\xF4V[\x03a3_W`@Q\x7F\xFC\xE6\x98\xF7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x82\x90R`$\x01[`@Q\x80\x91\x03\x90\xFD[`\x03\x82`\x03\x81\x11\x15a3sWa3sa>\xF4V[\x03a\"\xC5W`@Q\x7F\xD7\x8B\xCE\x0C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x82\x90R`$\x01a3VV[cNH{q_R\x80` R`$`\x1C\xFD[_a3\xCC` \x83\x01\x83a<\x16V[\x90P` \x82\x0156_a3\xE2`@\x86\x01\x86a=\x7FV[\x91P\x91P`@Q\x81\x83\x827_\x80\x83\x83\x87\x89Z\xF1a\x19DW=_\x80>=_\xFD[_6\x81a4\x11`@\x85\x01\x85a=\x7FV[\x90\x92P\x90P`\x04\x81\x10a4#W\x815\x92P[PP\x91\x90PV[_\x80` _\x84Q` \x86\x01_\x88Z\xF1\x80a4IW`@Q=_\x82>=\x81\xFD[PP_Q=\x91P\x81\x15a4`W\x80`\x01\x14\x15a4mV[`\x01`\x01`\xA0\x1B\x03\x84\x16;\x15[\x15a\x11\x9AW`@Q\x7FRt\xAF\xE7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x85\x16`\x04\x82\x01R`$\x01a3VV[_\x80\x80\x7F\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF]WnsW\xA4P\x1D\xDF\xE9/Fh\x1B \xA0\x84\x11\x15a4\xE8WP_\x91P`\x03\x90P\x82a5\x8BV[`@\x80Q_\x80\x82R` \x82\x01\x80\x84R\x8A\x90R`\xFF\x89\x16\x92\x82\x01\x92\x90\x92R``\x81\x01\x87\x90R`\x80\x81\x01\x86\x90R`\x01\x90`\xA0\x01` `@Q` \x81\x03\x90\x80\x84\x03\x90\x85Z\xFA\x15\x80\x15a59W=_\x80>=_\xFD[PP`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01Q\x91PP`\x01`\x01`\xA0\x1B\x03\x81\x16a5\x82WP_\x92P`\x01\x91P\x82\x90Pa5\x8BV[\x92P_\x91P\x81\x90P[\x94P\x94P\x94\x91PPV[_\x80_`@\x84\x86\x03\x12\x15a5\xA7W_\x80\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a5\xC5W_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a5\xD8W_\x80\xFD[\x815\x81\x81\x11\x15a5\xE6W_\x80\xFD[\x87` \x82\x85\x01\x01\x11\x15a5\xF7W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[_`\xA0\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[P\x91\x90PV[_`\xA0\x82\x84\x03\x12\x15a60W_\x80\xFD[a\x04\xD0\x83\x83a6\nV[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x0C\x89W_\x80\xFD[\x805a6Y\x81a6:V[\x91\x90PV[_a\x02`\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_\x80\x83`\x1F\x84\x01\x12a6\x7FW_\x80\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a6\x96W_\x80\xFD[` \x83\x01\x91P\x83` \x82`\x05\x1B\x85\x01\x01\x11\x15a6\xB0W_\x80\xFD[\x92P\x92\x90PV[_`@\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_``\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_\x80_\x80_\x80_\x80_a\x01\0\x8A\x8C\x03\x12\x15a6\xF0W_\x80\xFD[a6\xF9\x8Aa6NV[\x98P` \x8A\x015\x97P`@\x8A\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a7\x1CW_\x80\xFD[a7(\x8D\x83\x8E\x01a6^V[\x98P``\x8C\x015\x91P\x80\x82\x11\x15a7=W_\x80\xFD[a7I\x8D\x83\x8E\x01a6oV[\x90\x98P\x96P`\x80\x8C\x015\x91P\x80\x82\x11\x15a7aW_\x80\xFD[a7m\x8D\x83\x8E\x01a6\xB7V[\x95P`\xA0\x8C\x015\x91P\x80\x82\x11\x15a7\x82W_\x80\xFD[a7\x8E\x8D\x83\x8E\x01a6\xC7V[\x94P`\xC0\x8C\x015\x91P\x80\x82\x11\x15a7\xA3W_\x80\xFD[a7\xAF\x8D\x83\x8E\x01a6\xC7V[\x93P`\xE0\x8C\x015\x91P\x80\x82\x11\x15a7\xC4W_\x80\xFD[Pa7\xD1\x8C\x82\x8D\x01a6\xC7V[\x91PP\x92\x95\x98P\x92\x95\x98P\x92\x95\x98V[_\x80`@\x83\x85\x03\x12\x15a7\xF2W_\x80\xFD[\x825a7\xFD\x81a6:V[\x91P` \x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a8\x18W_\x80\xFD[a8$\x85\x82\x86\x01a6\xB7V[\x91PP\x92P\x92\x90PV[_a\x01`\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_\x80_\x80_`\xA0\x86\x88\x03\x12\x15a8SW_\x80\xFD[\x855a8^\x81a6:V[\x94P` \x86\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a8zW_\x80\xFD[a8\x86\x89\x83\x8A\x01a8.V[\x95P`@\x88\x015\x91P\x80\x82\x11\x15a8\x9BW_\x80\xFD[a8\xA7\x89\x83\x8A\x01a6\xC7V[\x94P``\x88\x015\x93P`\x80\x88\x015\x91P\x80\x82\x11\x15a8\xC3W_\x80\xFD[Pa8\xD0\x88\x82\x89\x01a6\xC7V[\x91PP\x92\x95P\x92\x95\x90\x93PV[_` \x82\x84\x03\x12\x15a8\xEDW_\x80\xFD[P5\x91\x90PV[\x80\x15\x15\x81\x14a\x0C\x89W_\x80\xFD[_\x80_\x80_\x80`\xA0\x87\x89\x03\x12\x15a9\x16W_\x80\xFD[\x865a9!\x81a6:V[\x95P` \x87\x015a91\x81a6:V[\x94P`@\x87\x015a9A\x81a8\xF4V[\x93P``\x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a9]W_\x80\xFD[a9i\x8A\x83\x8B\x01a6^V[\x94P`\x80\x89\x015\x91P\x80\x82\x11\x15a9~W_\x80\xFD[Pa9\x8B\x89\x82\x8A\x01a6oV[\x97\x9A\x96\x99P\x94\x97P\x92\x95\x93\x94\x92PPPV[_\x80_``\x84\x86\x03\x12\x15a9\xAFW_\x80\xFD[\x835a9\xBA\x81a6:V[\x92P` \x84\x015\x91P`@\x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a9\xDCW_\x80\xFD[a9\xE8\x86\x82\x87\x01a6\xC7V[\x91PP\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a:\x02W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a:\x18W_\x80\xFD[a\x1B\xD3\x84\x82\x85\x01a8.V[_\x80_\x80_\x80_\x80`\xE0\x89\x8B\x03\x12\x15a:;W_\x80\xFD[a:D\x89a6NV[\x97P` \x89\x015\x96P`@\x89\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a:gW_\x80\xFD[a:s\x8C\x83\x8D\x01a6^V[\x97P``\x8B\x015\x91P\x80\x82\x11\x15a:\x88W_\x80\xFD[a:\x94\x8C\x83\x8D\x01a6oV[\x90\x97P\x95P`\x80\x8B\x015\x91P\x80\x82\x11\x15a:\xACW_\x80\xFD[a:\xB8\x8C\x83\x8D\x01a6\xB7V[\x94P`\xA0\x8B\x015\x91P\x80\x82\x11\x15a:\xCDW_\x80\xFD[a:\xD9\x8C\x83\x8D\x01a6\xC7V[\x93P`\xC0\x8B\x015\x91P\x80\x82\x11\x15a:\xEEW_\x80\xFD[Pa:\xFB\x8B\x82\x8C\x01a6\xC7V[\x91PP\x92\x95\x98P\x92\x95\x98\x90\x93\x96PV[_\x80_\x80_\x80`\xC0\x87\x89\x03\x12\x15a; W_\x80\xFD[a;)\x87a6NV[\x95P` \x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a;EW_\x80\xFD[a;Q\x8A\x83\x8B\x01a8.V[\x96P`@\x89\x015\x91P\x80\x82\x11\x15a;fW_\x80\xFD[a;r\x8A\x83\x8B\x01a6\xC7V[\x95P``\x89\x015\x94P`\x80\x89\x015\x91P\x80\x82\x11\x15a;\x8EW_\x80\xFD[a;\x9A\x8A\x83\x8B\x01a6\xC7V[\x93P`\xA0\x89\x015\x91P\x80\x82\x11\x15a;\xAFW_\x80\xFD[Pa;\xBC\x89\x82\x8A\x01a6\xC7V[\x91PP\x92\x95P\x92\x95P\x92\x95V[_` \x82\x84\x03\x12\x15a;\xD9W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a;\xEFW_\x80\xFD[a\x1B\xD3\x84\x82\x85\x01a6^V[_` \x82\x84\x03\x12\x15a<\x0BW_\x80\xFD[\x81Qa\x04\xD0\x81a8\xF4V[_` \x82\x84\x03\x12\x15a<&W_\x80\xFD[\x815a\x04\xD0\x81a6:V[\x81\x83R\x81\x81` \x85\x017P_` \x82\x84\x01\x01R_` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x84\x01\x01\x90P\x92\x91PPV[\x805e\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a6YW_\x80\xFD[_`\x01`\x01`\xA0\x1B\x03\x80\x87\x16\x83R\x80\x86\x16` \x84\x01RP\x83`@\x83\x01R`\x80``\x83\x01R\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a<\xE2W_\x80\xFD[\x83\x01` \x81\x01\x905g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a<\xFEW_\x80\xFD[\x806\x03\x82\x13\x15a=\x0CW_\x80\xFD[```\x80\x85\x01Ra=!`\xE0\x85\x01\x82\x84a<1V[\x91PPa=0` \x85\x01a\"W_\x80\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a>\xB2W_\x80\xFD[\x91\x90\x91\x01\x92\x91PPV[\x80\x82\x01\x80\x82\x11\x15a.\xFAW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a?1W_\x80\xFD[\x815`\x04\x81\x10a\x04\xD0W_\x80\xFD[\x83\x81R`@` \x82\x01R_a\x1C``@\x83\x01\x84\x86a<1V[_` \x82\x84\x03\x12\x15a?hW_\x80\xFD[\x81Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x81\x14a\x04\xD0W_\x80\xFD[` \x81R_a\x1B\xD3` \x83\x01\x84\x86a<1V[_\x81Q_[\x81\x81\x10\x15a?\xC9W` \x81\x85\x01\x81\x01Q\x86\x83\x01R\x01a?\xAFV[P_\x93\x01\x92\x83RP\x90\x91\x90PV[_a\x1B\xD3a?\xE5\x83\x86a?\xAAV[\x84a?\xAAV[_a?\xF6\x82\x86a?\xAAV[\x93\x84RPP` \x82\x01R`@\x01\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_`\xA0\x82\x01\x90P`\x01`\x01`\xA0\x1B\x03\x80\x84Q\x16\x83R\x80` \x85\x01Q\x16` \x84\x01R\x80`@\x85\x01Q\x16`@\x84\x01RP``\x83\x01Q``\x83\x01R`\x80\x83\x01Q`\x03\x81\x10a@\xA7W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x80`\x80\x84\x01RP\x92\x91PPV[_` \x82\x84\x03\x12\x15a@\xC4W_\x80\xFD[PQ\x91\x90PV[_\x80\x85\x85\x11\x15a@\xD9W_\x80\xFD[\x83\x86\x11\x15a@\xE5W_\x80\xFD[PP\x82\x01\x93\x91\x90\x92\x03\x91PV[_\x80_\x80`\x80\x85\x87\x03\x12\x15aA\x05W_\x80\xFD[\x845aA\x10\x81a6:V[\x93P` \x85\x015aA \x81a6:V[\x92P`@\x85\x015\x91P``\x85\x015aA7\x81a8\xF4V[\x93\x96\x92\x95P\x90\x93PPV[_\x80_\x80`\x80\x85\x87\x03\x12\x15aAUW_\x80\xFD[\x845aA`\x81a6:V[\x93P` \x85\x015aAp\x81a6:V[\x92P`@\x85\x015aA\x80\x81a6:V[\x93\x96\x92\x95P\x92\x93``\x015\x92PPV[_\x80_\x80_\x80_`\xE0\x88\x8A\x03\x12\x15aA\xA6W_\x80\xFD[\x875aA\xB1\x81a6:V[\x96P` \x88\x015aA\xC1\x81a6:V[\x95P`@\x88\x015aA\xD1\x81a6:V[\x94P``\x88\x015aA\xE1\x81a6:V[\x93P`\x80\x88\x015\x92P`\xA0\x88\x015aA\xF8\x81a6:V[\x80\x92PP`\xC0\x88\x015\x90P\x92\x95\x98\x91\x94\x97P\x92\x95PV[_\x80_``\x84\x86\x03\x12\x15aB!W_\x80\xFD[\x835aB,\x81a6:V[\x92P` \x84\x015aB<\x81a6:V[\x92\x95\x92\x94PPP`@\x91\x90\x91\x015\x90V[_\x80_\x80_`\xA0\x86\x88\x03\x12\x15aBaW_\x80\xFD[\x855aBl\x81a6:V[\x94P` \x86\x015aB|\x81a6:V[\x93P`@\x86\x015aB\x8C\x81a6:V[\x92P``\x86\x015\x91P`\x80\x86\x015aB\xA3\x81a8\xF4V[\x80\x91PP\x92\x95P\x92\x95\x90\x93PV[_`\xFF\x83\x16\x80aB\xE8W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[\x80`\xFF\x84\x16\x06\x91PP\x92\x91PPV\xFE\xA2dipfsX\"\x12 \x9B\xE5\x8A\xCA\xDA50a\xA2\xA2\x02\xCCp\x11\xF3\xC9\x13\x93\xE0\xF2\xE3\x05\xE9 $E\xB0B\xFCJL\xE6dsolcC\0\x08\x17\x003`\xC0`@R4\x80\x15a\0\x0FW_\x80\xFD[P`@Qa\tc8\x03\x80a\tc\x839\x81\x01`@\x81\x90Ra\0.\x91a\0`V[`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\x80R\x16`\xA0Ra\0\x91V[\x80Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0[W_\x80\xFD[\x91\x90PV[_\x80`@\x83\x85\x03\x12\x15a\0qW_\x80\xFD[a\0z\x83a\0EV[\x91Pa\0\x88` \x84\x01a\0EV[\x90P\x92P\x92\x90PV[`\x80Q`\xA0Qa\x08\x9Ea\0\xC5_9_\x81\x81`H\x01R\x81\x81a\x01\xF2\x01Ra\x03\x81\x01R_\x81\x81`\xD3\x01Ra\x03'\x01Ra\x08\x9E_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW_\x80\xFD[P`\x046\x10a\0?W_5`\xE0\x1C\x80cj\xFD\xD8P\x14a\0CW\x80c\xB5\x19\xD3i\x14a\0\x93W\x80c\xBC\x11x\xE6\x14a\0\xA8W[_\x80\xFD[a\0j\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\xA6a\0\xA16`\x04a\x06\nV[a\0\xBBV[\0[a\0\xA6a\0\xB66`\x04a\x06HV[a\x03\x0FV[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x81\x14a\x01+W`@Q\x7F|!O\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[``\x82\x015\x15a\x01\xAFW`\x01a\x01G`\xA0\x84\x01`\x80\x85\x01a\x06\xDDV[`\x02\x81\x11\x15a\x01XWa\x01Xa\x06\xB0V[\x03a\x01\xB3Wa\x01\xAFa\x01m` \x84\x01\x84a\x07\x02V[a\x01}`@\x85\x01` \x86\x01a\x07\x02V[``\x85\x01\x805\x90a\x01\x91\x90`@\x88\x01a\x07\x02V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x92\x91\x90a\x04\xCCV[PPV[`\x02a\x01\xC5`\xA0\x84\x01`\x80\x85\x01a\x06\xDDV[`\x02\x81\x11\x15a\x01\xD6Wa\x01\xD6a\x06\xB0V[\x03a\x02\xDDWs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16c6\xC7\x85\x16a\x02$` \x85\x01\x85a\x07\x02V[a\x024`@\x86\x01` \x87\x01a\x07\x02V[``\x86\x01\x805\x90a\x02H\x90`@\x89\x01a\x07\x02V[`@Q`\xE0\x86\x90\x1B\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x94\x85\x16`\x04\x82\x01R\x92\x84\x16`$\x84\x01R\x90\x83\x16`D\x83\x01R\x90\x91\x16`d\x82\x01R`\x84\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x02\xC3W_\x80\xFD[PZ\xF1\x15\x80\x15a\x02\xD5W=_\x80>=_\xFD[PPPPPPV[`@Q\x7F\xC7\x9A\xAAD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x81\x14a\x03\x7FW`@Q\x7F|!O\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c+g\xB5p\x86`@Q\x80``\x01`@R\x80`@Q\x80`\x80\x01`@R\x80\x8As\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x88`@\x01` \x81\x01\x90a\x04\x1D\x91\x90a\x07\x1BV[e\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x88` \x01` \x81\x01\x90a\x04=\x91\x90a\x07\x1BV[e\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90R\x81R0` \x82\x01R`@\x90\x81\x01\x90a\x04e\x90``\x89\x01\x90\x89\x01a\x07\x1BV[e\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90Ra\x04y\x86\x80a\x07@V[`@Q\x85c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x04\x98\x94\x93\x92\x91\x90a\x07\xA8V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x04\xAFW_\x80\xFD[PZ\xF1\x15\x80\x15a\x04\xC1W=_\x80>=_\xFD[PPPPPPPPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`$\x83\x01R\x84\x16`D\x82\x01R`d\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`\x84\x90\x91\x01\x90\x91R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F#\xB8r\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90Ra\x05a\x90\x85\x90a\x05gV[PPPPV[_\x80` _\x84Q` \x86\x01_\x88Z\xF1\x80a\x05\x86W`@Q=_\x82>=\x81\xFD[PP_Q=\x91P\x81\x15a\x05\x9DW\x80`\x01\x14\x15a\x05\xB7V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16;\x15[\x15a\x05aW`@Q\x7FRt\xAF\xE7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[_`\xA0\x82\x84\x03\x12\x15a\x06\x1AW_\x80\xFD[P\x91\x90PV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x06CW_\x80\xFD[\x91\x90PV[_\x80_\x80`\x80\x85\x87\x03\x12\x15a\x06[W_\x80\xFD[a\x06d\x85a\x06 V[\x93Pa\x06r` \x86\x01a\x06 V[\x92P`@\x85\x015\x91P``\x85\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x06\x94W_\x80\xFD[\x85\x01``\x81\x88\x03\x12\x15a\x06\xA5W_\x80\xFD[\x93\x96\x92\x95P\x90\x93PPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a\x06\xEDW_\x80\xFD[\x815`\x03\x81\x10a\x06\xFBW_\x80\xFD[\x93\x92PPPV[_` \x82\x84\x03\x12\x15a\x07\x12W_\x80\xFD[a\x06\xFB\x82a\x06 V[_` \x82\x84\x03\x12\x15a\x07+W_\x80\xFD[\x815e\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x06\xFBW_\x80\xFD[_\x80\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x07sW_\x80\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x07\x8DW_\x80\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\x07\xA1W_\x80\xFD[\x92P\x92\x90PV[_a\x01\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x88\x16\x84R\x86Q\x81\x81Q\x16` \x86\x01R\x81` \x82\x01Q\x16`@\x86\x01R`@\x81\x01Qe\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16``\x88\x01R\x80``\x84\x01Q\x16`\x80\x88\x01RPPP\x80` \x88\x01Q\x16`\xA0\x85\x01RP`@\x86\x01Q`\xC0\x84\x01R\x80`\xE0\x84\x01R\x83\x81\x84\x01RPa\x01 \x83\x85\x82\x85\x017_\x83\x85\x01\x82\x01R`\x1F\x90\x93\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x90\x91\x01\x90\x91\x01\x94\x93PPPPV\xFE\xA2dipfsX\"\x12 \xF3V_e\x89P\x02v\xFC\xBBo\xB3=>\xE3\xB54\xD9Vl['2\xFE\x10\xA6\x03\x9Bu<:\x07dsolcC\0\x08\x17\x003", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405260043610610126575f3560e01c8063a5cdc8fc116100a1578063c618618111610071578063db58772811610057578063db58772814610379578063e242924e1461038c578063fa5cd56c146103ab575f80fd5b8063c618618114610327578063cba673a71461035a575f80fd5b8063a5cdc8fc146102ab578063a7ab49bc146102ca578063ae80c584146102e9578063b11f126214610308575f80fd5b806351d46815116100f65780636f35d2d2116100dc5780636f35d2d214610246578063875530ff146102795780639935c86814610298575f80fd5b806351d46815146102125780635aa0e95d14610227575f80fd5b80631626ba7e1461013157806329bcdc95146101865780633644e515146101d15780634c9e03d3146101f3575f80fd5b3661012d57005b5f80fd5b34801561013c575f80fd5b5061015061014b366004613595565b6103ca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610191575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161017d565b3480156101dc575f80fd5b506101e56104d7565b60405190815260200161017d565b3480156101fe575f80fd5b506101e561020d366004613620565b6105c6565b6102256102203660046136d7565b610667565b005b348015610232575f80fd5b506102256102413660046137e1565b6109e8565b348015610251575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610284575f80fd5b506101e5610293366004613620565b610c30565b6102256102a636600461383f565b610c5f565b3480156102b6575f80fd5b506102256102c53660046138dd565b610c7f565b3480156102d5575f80fd5b506102256102e4366004613901565b610c8c565b3480156102f4575f80fd5b5061022561030336600461399d565b611067565b348015610313575f80fd5b506101e56103223660046139f2565b6112eb565b348015610332575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610365575f80fd5b50610225610374366004613a24565b6114ea565b610225610387366004613b0b565b611878565b348015610397575f80fd5b506101e56103a6366004613bc9565b61194c565b3480156103b6575f80fd5b506102256103c5366004613bc9565b611a8e565b5f806103d7858585611b50565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063e75600c390602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190613bfb565b156104ab577f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150506104d0565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b9392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000046146105a157604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f7f68b8e94dc077458241d6c8d89f0a7665c7cda2cfe70c9eb4437efee1663c66fe6105f56020840184613c16565b836020013584604001358560600135866080013560405160200161064a969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b61066f611bdb565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa1580156106ec573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107109190613bfb565b610746576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610200870135881580159061076057506101608801358911155b1561077f5761077c896102008a01356101608b01356001611c1e565b90505b6107b07f00000000000000000000000000000000000000000000000000000000000000008b838b8b8b8b8b8b611c69565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66107ef60c08b0160a08c01613c16565b6108016101408c016101208d01613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108449291906101608e0135908890600401613c8d565b5f604051808303815f87803b15801561085b575f80fd5b505af115801561086d573d5f803e3d5ffd5b505050506108b4888b838c5f148061088957506101608c01358d115b610893578c61089a565b6101608c01355b898c8c60026108af60408e0160208f01613d61565b611e01565b6108c16040890189613d7f565b6040516108cf929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661090960a08b0160808c01613c16565b61091960c08c0160a08d01613c16565b61092b6101408d016101208e01613c16565b61093d6101e08e016101c08f01613c16565b8e158061094e57506101608e01358f115b610958578e61095f565b6101408e01355b6102008f013588146109715787610978565b6101e08f01355b8f60e001602081019061098b9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a2506109dd60018055565b505050505050505050565b5f5b6109f48280613def565b9050811015610b065736610a088380613def565b83818110610a1857610a18613e53565b9050602002810190610a2a9190613e80565b90506001600160a01b03841663a8c4bc95610a486020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610aa2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac69190613bfb565b15610afd576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016109ea565b505f5b610b166020830183613def565b9050811015610c2b5736610b2d6020840184613def565b83818110610b3d57610b3d613e53565b9050602002810190610b4f9190613e80565b90506001600160a01b03841663a8c4bc95610b6d6020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610bc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610beb9190613bfb565b15610c22576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101610b09565b505050565b5f7fae676bf6913ac2689b7331293c989fe7723124faf8b5d275f06fbcebc77950096105f56020840184613c16565b610c698482612212565b610c78858585856001806122c9565b5050505050565b610c89338261261e565b50565b610cbf6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f5b828110156110535736848483818110610cdc57610cdc613e53565b9050602002810190610cee9190613e80565b9050365f610cff6040840184613d7f565b90925090506001600160a01b038b1663a8c4bc95610d206020860186613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9e9190613bfb565b15611045575f8915610ddc576040517f7d617bb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048210610de8575081355b7fc03a9de9000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610e5657610e3d83838d8c6126c4565b86602001818151610e4e9190613ebc565b905250611043565b7f243a4b7f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610ebc57610eab83838d8c6127da565b86606001818151610e4e9190613ebc565b7f7dc4f458000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f4757610f1183838d8c61294e565b60a088015260808701819052606087018051610f2e908390613ebc565b90525060a0860151602087018051610e4e908390613ebc565b7f68931b6b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610fab57610f9c83838d8c612bb6565b86518790610e4e908390613ebc565b7f0c9be7e4000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016110115761100083838d8c612cc0565b86604001818151610e4e9190613ebc565b6040517f0561d8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050806001019050610cc1565b5061105e8482612e29565b50505050505050565b60036110766020830183613f21565b600381111561108757611087613ef4565b036110ec576001600160a01b0383166110ac836110a76040850185613d7f565b611b50565b6001600160a01b031614610c2b576040517fb81d58e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016110fb6020830183613f21565b600381111561110c5761110c613ef4565b036111a0577f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c839052603c90206001600160a01b03841661115a826110a76040860186613d7f565b6001600160a01b03161461119a576040517f644ae6c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60026111af6020830183613f21565b60038111156111c0576111c0613ef4565b036112b9577f1626ba7e000000000000000000000000000000000000000000000000000000006001600160a01b038416631626ba7e846112036040860186613d7f565b6040518463ffffffff1660e01b815260040161122193929190613f3f565b602060405180830381865afa15801561123c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112609190613f58565b7fffffffff000000000000000000000000000000000000000000000000000000001614610c2b576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f60cd402d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112f46104d7565b7fd28e809b708f5ee38be8347d6d869d8232493c094ab2dde98369e4102369a99d61131f8480613d7f565b604051602001611330929190613f97565b60405160208183030381529060405280519060200120846020013585604001602081019061135e9190613c16565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526113c46080850160608601613c16565b6113d460a0860160808701613c16565b6113e460c0870160a08801613c16565b60c087013560e08801356101008901356101208a013561140c6101608c016101408d01613c16565b604080516001600160a01b03998a166020820152978916908801529487166060870152608086019390935260a085019190915260c084015260e083015290911661010082015261012001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526114929291602001613fd7565b6040516020818303038152906040528051906020012060405160200161064a9291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6114f2611bdb565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906302cc250d90602401602060405180830381865afa15801561156d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115919190613bfb565b6115c7576040517fc139eabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa158015611644573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116689190613bfb565b61169e576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61020086013587158015906116b857506101608701358811155b156116d7576116d4886102008901356101608a01356001611c1e565b90505b6117087f00000000000000000000000000000000000000000000000000000000000000008a838a8a8a8a8a8a611c69565b611745878a838b158061171f57506101608b01358c115b611729578b611730565b6101608b01355b888b8b60016108af60408d0160208e01613d61565b6117526040880188613d7f565b604051611760929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661179a60a08a0160808b01613c16565b6117aa60c08b0160a08c01613c16565b6117bc6101408c016101208d01613c16565b6117ce6101e08d016101c08e01613c16565b8d15806117df57506101608d01358e115b6117e9578d6117f0565b6101408d01355b6102008e013588146118025787611809565b6101e08e01355b8e60e001602081019061181c9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a25061186e60018055565b5050505050505050565b6118828583612212565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66118c16080880160608901613c16565b6118d160a0890160808a01613c16565b8860c00135856040518563ffffffff1660e01b81526004016118f69493929190613c8d565b5f604051808303815f87803b15801561190d575f80fd5b505af115801561191f573d5f803e3d5ffd5b5050505061194486868686600289602001602081019061193f9190613d61565b6122c9565b505050505050565b5f6119556104d7565b7fc994d2ca0375d6d473785e0ce0b1d203f069121bac1314f72c5c0fe601eb39106119836040850185613d7f565b604051602001611994929190613f97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060608501356119df60a0870160808801613c16565b6119ef60c0880160a08901613c16565b60c0880135611a056101008a0160e08b01613c16565b60408051602081019890985287019590955260608601939093526001600160a01b039182166080860152811660a085015260c08401919091521660e0820152610100808501359082015261012001604051602081830303815290604052611a6f8461012001610c30565b611a7c856101c0016105c6565b60405160200161149293929190613feb565b6101a0810135611aa8610180830135610160840135613ebc565b611ab29190613ebc565b61014082013514611aef576040517fc04377d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610240810135611b09610220830135610200840135613ebc565b611b139190613ebc565b6101e082013514610c89576040517f877630be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ed692505050565b90506001600160a01b038116611bd3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b600260015403611c17576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600155565b5f611c4b611c2b83612f00565b8015611c4657505f8480611c4157611c41614008565b868809115b151590565b611c56868686612f2c565b611c609190613ebc565b95945050505050565b5f611c738761194c565b9050611c80898285611067565b611c9060c0880160a08901613c16565b6001600160a01b0316336001600160a01b031614611cc757611cc2611cbb60c0890160a08a01613c16565b8284611067565b611d0e565b611cd46040830183613d7f565b90505f03611d0e576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d2b611d2160c0890160a08a01613c16565b886060013561261e565b8660c00135421115611d69576040517f133df02900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f88118015611d7c575086610100013588105b15611db3576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dbc87611a8e565b611dc68a856109e8565b611de78a8a5f8b118015611ddf57506102008a01358b14155b8a8a8a610c8c565b611df589886060013561261e565b50505050505050505050565b611e13611e0e8680613def565b613001565b5f611e286101808b01356101a08c0135613ebc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611e779190613c16565b6001600160a01b03168152602001306001600160a01b031681526020018d610120015f016020810190611eaa9190613c16565b6001600160a01b03168152602001848152602001866002811115611ed057611ed0613ef4565b8152506040518263ffffffff1660e01b8152600401611eef9190614035565b5f604051808303815f87803b158015611f06575f80fd5b505af1158015611f18573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611f699190613c16565b6001600160a01b031681526020018d60e0016020810190611f8a9190613c16565b6001600160a01b031681526020018d610120015f016020810190611fae9190613c16565b6001600160a01b031681526020018a8152602001866002811115611fd457611fd4613ef4565b8152506040518263ffffffff1660e01b8152600401611ff39190614035565b5f604051808303815f87803b15801561200a575f80fd5b505af115801561201c573d5f803e3d5ffd5b5050505061202a8585613001565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808c6001600160a01b031681526020018d60800160208101906120869190613c16565b6001600160a01b031681526020018d6101c0015f0160208101906120aa9190613c16565b6001600160a01b031681526020018b81526020018560028111156120d0576120d0613ef4565b8152506040518263ffffffff1660e01b81526004016120ef9190614035565b5f604051808303815f87803b158015612106575f80fd5b505af1158015612118573d5f803e3d5ffd5b5061212e9250611e0e9150506020880188613def565b5f6121416101408c016101208d01613c16565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561219e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c291906140b4565b90508015612205576122056121de6101008d0160e08e01613c16565b828d610120015f0160208101906121f59190613c16565b6001600160a01b03169190613139565b5050505050505050505050565b6122226080830160608401613c16565b6001600160a01b0316336001600160a01b0316146122615761225c61224d6080840160608501613c16565b612256846112eb565b83611067565b6122a8565b61226e6040820182613d7f565b90505f036122a8576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122c56122bb6080840160608501613c16565b836020013561261e565b5050565b60e085013583158015906122e057508560c0013584105b156122fd576122fa848760e001358860c001356001611c1e565b90505b612309878288886131b9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808960600160208101906123569190613c16565b6001600160a01b031681526020016123766101608b016101408c01613c16565b6001600160a01b0316815260200161239460a08b0160808c01613c16565b6001600160a01b031681526020018715806123b257508960c0013588115b6123bc57876123c2565b8960c001355b81526020018660028111156123d9576123d9613ef4565b8152506040518263ffffffff1660e01b81526004016123f89190614035565b5f604051808303815f87803b15801561240f575f80fd5b505af1158015612421573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808a6001600160a01b031681526020018960400160208101906124819190613c16565b6001600160a01b0316815260200161249f60c08b0160a08c01613c16565b6001600160a01b031681526020018481526020018560028111156124c5576124c5613ef4565b8152506040518263ffffffff1660e01b81526004016124e49190614035565b5f604051808303815f87803b1580156124fb575f80fd5b505af115801561250d573d5f803e3d5ffd5b5061251e9250889150819050613d7f565b60405161252c929190613de0565b60405180910390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b68760400160208101906125689190613c16565b61257860808a0160608b01613c16565b61258860a08b0160808c01613c16565b61259860c08c0160a08d01613c16565b8915806125a857508b60c001358a115b6125b257896125b8565b8b60c001355b878d6101400160208101906125cd9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a250505050505050565b6001600160a01b0382165f9081526020818152604080832084845290915290205460ff1615612679576040517fbc0da7d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b039091165f908152602081815260408083209383529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f8080806126d5876004818b6140cb565b8101906126e291906140f2565b50919450925090506126fc61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612746576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612791576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b979650505050505050565b5f808080806127ec886004818c6140cb565b8101906127f99190614142565b929650909450925090506128156101e087016101c08801613c16565b6001600160a01b0316846001600160a01b03161461285f576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b0316146128aa576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128ba60a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612904576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b98975050505050505050565b5f805f805f805f805f8c8c600490809261296a939291906140cb565b8101906129779190614190565b959c50939a50919850965094509250905061299a6101e08b016101c08c01613c16565b6001600160a01b0316876001600160a01b0316146129e4576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856001600160a01b03168b6001600160a01b031614612a2f576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385163014612a71576040517f8154374b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612a8160a08b0160808c01613c16565b6001600160a01b0316846001600160a01b031614612acb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408a01358314612b09576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b1b6101408b016101208c01613c16565b6001600160a01b0316826001600160a01b031614612b65576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a08a01358114612ba3576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919c919b50909950505050505050505050565b5f808080612bc7876004818b6140cb565b810190612bd4919061420f565b91945092509050612bed61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612c37576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612c82576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61018085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808080612cd2886004818c6140cb565b810190612cdf919061424d565b5092965090945092509050612cfc6101e087016101c08801613c16565b6001600160a01b0316846001600160a01b031614612d46576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614612d91576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612da160a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612deb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102208601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051610180830135141580612e47575060208101516101a083013514155b15612e7e576040517f4a55da2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610220830135141580612e9f5750606081015161024083013514155b156122c5576040517f77a5920300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f80612ee4868661325c565b925092509250612ef482826132a5565b50909150505b92915050565b5f6002826003811115612f1557612f15613ef4565b612f1f91906142b1565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03612f7f57838281612f7557612f75614008565b04925050506104d0565b808411612f9657612f9660038515026011186133ad565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f5b81811015610c2b573683838381811061301e5761301e613e53565b90506020028101906130309190613e80565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130696020830183613c16565b6001600160a01b0316036130a9576040517f79a1bff000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130b2816133be565b6130bf6020820182613c16565b6001600160a01b03167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356130f784613401565b604080519283527fffffffff0000000000000000000000000000000000000000000000000000000090911660208301520160405180910390a250600101613003565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610c2b90849061342a565b5f831180156131cc575081610100013583105b15613203576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61321084612256846112eb565b61321e84836020013561261e565b428261012001351161119a576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f8351604103613293576020840151604085015160608601515f1a613285888285856134af565b95509550955050505061329e565b505081515f91506002905b9250925092565b5f8260038111156132b8576132b8613ef4565b036132c1575050565b60018260038111156132d5576132d5613ef4565b0361330c576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561332057613320613ef4565b0361335f576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600382600381111561337357613373613ef4565b036122c5576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401613356565b634e487b715f52806020526024601cfd5b5f6133cc6020830183613c16565b90506020820135365f6133e26040860186613d7f565b91509150604051818382375f80838387895af1611944573d5f803e3d5ffd5b5f36816134116040850185613d7f565b90925090506004811061342357813592505b5050919050565b5f8060205f8451602086015f885af180613449576040513d5f823e3d81fd5b50505f513d9150811561346057806001141561346d565b6001600160a01b0384163b155b1561119a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613356565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156134e857505f9150600390508261358b565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613539573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811661358257505f92506001915082905061358b565b92505f91508190505b9450945094915050565b5f805f604084860312156135a7575f80fd5b83359250602084013567ffffffffffffffff808211156135c5575f80fd5b818601915086601f8301126135d8575f80fd5b8135818111156135e6575f80fd5b8760208285010111156135f7575f80fd5b6020830194508093505050509250925092565b5f60a0828403121561361a575f80fd5b50919050565b5f60a08284031215613630575f80fd5b6104d0838361360a565b6001600160a01b0381168114610c89575f80fd5b80356136598161363a565b919050565b5f610260828403121561361a575f80fd5b5f8083601f84011261367f575f80fd5b50813567ffffffffffffffff811115613696575f80fd5b6020830191508360208260051b85010111156136b0575f80fd5b9250929050565b5f6040828403121561361a575f80fd5b5f6060828403121561361a575f80fd5b5f805f805f805f805f6101008a8c0312156136f0575f80fd5b6136f98a61364e565b985060208a0135975060408a013567ffffffffffffffff8082111561371c575f80fd5b6137288d838e0161365e565b985060608c013591508082111561373d575f80fd5b6137498d838e0161366f565b909850965060808c0135915080821115613761575f80fd5b61376d8d838e016136b7565b955060a08c0135915080821115613782575f80fd5b61378e8d838e016136c7565b945060c08c01359150808211156137a3575f80fd5b6137af8d838e016136c7565b935060e08c01359150808211156137c4575f80fd5b506137d18c828d016136c7565b9150509295985092959850929598565b5f80604083850312156137f2575f80fd5b82356137fd8161363a565b9150602083013567ffffffffffffffff811115613818575f80fd5b613824858286016136b7565b9150509250929050565b5f610160828403121561361a575f80fd5b5f805f805f60a08688031215613853575f80fd5b853561385e8161363a565b9450602086013567ffffffffffffffff8082111561387a575f80fd5b61388689838a0161382e565b9550604088013591508082111561389b575f80fd5b6138a789838a016136c7565b94506060880135935060808801359150808211156138c3575f80fd5b506138d0888289016136c7565b9150509295509295909350565b5f602082840312156138ed575f80fd5b5035919050565b8015158114610c89575f80fd5b5f805f805f8060a08789031215613916575f80fd5b86356139218161363a565b955060208701356139318161363a565b94506040870135613941816138f4565b9350606087013567ffffffffffffffff8082111561395d575f80fd5b6139698a838b0161365e565b9450608089013591508082111561397e575f80fd5b5061398b89828a0161366f565b979a9699509497509295939492505050565b5f805f606084860312156139af575f80fd5b83356139ba8161363a565b925060208401359150604084013567ffffffffffffffff8111156139dc575f80fd5b6139e8868287016136c7565b9150509250925092565b5f60208284031215613a02575f80fd5b813567ffffffffffffffff811115613a18575f80fd5b611bd38482850161382e565b5f805f805f805f8060e0898b031215613a3b575f80fd5b613a448961364e565b975060208901359650604089013567ffffffffffffffff80821115613a67575f80fd5b613a738c838d0161365e565b975060608b0135915080821115613a88575f80fd5b613a948c838d0161366f565b909750955060808b0135915080821115613aac575f80fd5b613ab88c838d016136b7565b945060a08b0135915080821115613acd575f80fd5b613ad98c838d016136c7565b935060c08b0135915080821115613aee575f80fd5b50613afb8b828c016136c7565b9150509295985092959890939650565b5f805f805f8060c08789031215613b20575f80fd5b613b298761364e565b9550602087013567ffffffffffffffff80821115613b45575f80fd5b613b518a838b0161382e565b96506040890135915080821115613b66575f80fd5b613b728a838b016136c7565b9550606089013594506080890135915080821115613b8e575f80fd5b613b9a8a838b016136c7565b935060a0890135915080821115613baf575f80fd5b50613bbc89828a016136c7565b9150509295509295509295565b5f60208284031215613bd9575f80fd5b813567ffffffffffffffff811115613bef575f80fd5b611bd38482850161365e565b5f60208284031215613c0b575f80fd5b81516104d0816138f4565b5f60208284031215613c26575f80fd5b81356104d08161363a565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b803565ffffffffffff81168114613659575f80fd5b5f6001600160a01b0380871683528086166020840152508360408301526080606083015282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ce2575f80fd5b830160208101903567ffffffffffffffff811115613cfe575f80fd5b803603821315613d0c575f80fd5b60606080850152613d2160e085018284613c31565b915050613d3060208501613c78565b65ffffffffffff80821660a086015280613d4c60408801613c78565b1660c086015250508091505095945050505050565b5f60208284031215613d71575f80fd5b8135600381106104d0575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db2575f80fd5b83018035915067ffffffffffffffff821115613dcc575f80fd5b6020019150368190038213156136b0575f80fd5b818382375f9101908152919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e22575f80fd5b83018035915067ffffffffffffffff821115613e3c575f80fd5b6020019150600581901b36038213156136b0575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112613eb2575f80fd5b9190910192915050565b80820180821115612efa577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613f31575f80fd5b8135600481106104d0575f80fd5b838152604060208201525f611c60604083018486613c31565b5f60208284031215613f68575f80fd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146104d0575f80fd5b602081525f611bd3602083018486613c31565b5f81515f5b81811015613fc95760208185018101518683015201613faf565b505f93019283525090919050565b5f611bd3613fe58386613faa565b84613faa565b5f613ff68286613faa565b93845250506020820152604001919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60a0820190506001600160a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151600381106140a7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8060808401525092915050565b5f602082840312156140c4575f80fd5b5051919050565b5f80858511156140d9575f80fd5b838611156140e5575f80fd5b5050820193919092039150565b5f805f8060808587031215614105575f80fd5b84356141108161363a565b935060208501356141208161363a565b9250604085013591506060850135614137816138f4565b939692955090935050565b5f805f8060808587031215614155575f80fd5b84356141608161363a565b935060208501356141708161363a565b925060408501356141808161363a565b9396929550929360600135925050565b5f805f805f805f60e0888a0312156141a6575f80fd5b87356141b18161363a565b965060208801356141c18161363a565b955060408801356141d18161363a565b945060608801356141e18161363a565b93506080880135925060a08801356141f88161363a565b8092505060c0880135905092959891949750929550565b5f805f60608486031215614221575f80fd5b833561422c8161363a565b9250602084013561423c8161363a565b929592945050506040919091013590565b5f805f805f60a08688031215614261575f80fd5b853561426c8161363a565b9450602086013561427c8161363a565b9350604086013561428c8161363a565b92506060860135915060808601356142a3816138f4565b809150509295509295909350565b5f60ff8316806142e8577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff8416069150509291505056fea26469706673582212209be58acada353061a2a202cc7011f3c91393e0f2e305e9202445b042fc4a4ce664736f6c63430008170033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R`\x046\x10a\x01&W_5`\xE0\x1C\x80c\xA5\xCD\xC8\xFC\x11a\0\xA1W\x80c\xC6\x18a\x81\x11a\0qW\x80c\xDBXw(\x11a\0WW\x80c\xDBXw(\x14a\x03yW\x80c\xE2B\x92N\x14a\x03\x8CW\x80c\xFA\\\xD5l\x14a\x03\xABW_\x80\xFD[\x80c\xC6\x18a\x81\x14a\x03'W\x80c\xCB\xA6s\xA7\x14a\x03ZW_\x80\xFD[\x80c\xA5\xCD\xC8\xFC\x14a\x02\xABW\x80c\xA7\xABI\xBC\x14a\x02\xCAW\x80c\xAE\x80\xC5\x84\x14a\x02\xE9W\x80c\xB1\x1F\x12b\x14a\x03\x08W_\x80\xFD[\x80cQ\xD4h\x15\x11a\0\xF6W\x80co5\xD2\xD2\x11a\0\xDCW\x80co5\xD2\xD2\x14a\x02FW\x80c\x87U0\xFF\x14a\x02yW\x80c\x995\xC8h\x14a\x02\x98W_\x80\xFD[\x80cQ\xD4h\x15\x14a\x02\x12W\x80cZ\xA0\xE9]\x14a\x02'W_\x80\xFD[\x80c\x16&\xBA~\x14a\x011W\x80c)\xBC\xDC\x95\x14a\x01\x86W\x80c6D\xE5\x15\x14a\x01\xD1W\x80cL\x9E\x03\xD3\x14a\x01\xF3W_\x80\xFD[6a\x01-W\0[_\x80\xFD[4\x80\x15a\x01=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x04}\x91\x90a;\xFBV[\x15a\x04\xABW\x7F\x16&\xBA~5oYy\xDD5Z=+\xFBC\xE8\x04 \xA4\x80\xC3\xB8T\xED\xCE(j\x82\xD7Ihi\x91PPa\x04\xD0V[P\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90P[\x93\x92PPPV[_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0F\x14a\x05\xA1W`@\x80Q\x7F\x8Bs\xC3\xC6\x9B\xB8\xFE=Q.\xCCL\xF7Y\xCCy#\x9F{\x17\x9B\x0F\xFA\xCA\xA9\xA7]R+9@\x0F` \x82\x01R\x7Fd\xAF\xEC{\xE6Q\xC9/\x86uK\xEB+\xD5\xEE\xAF/\xA9^\x83\xFA\xF4\xAE\xE9\x89\x87}\xDE\x08\xE4I\x8C\x91\x81\x01\x91\x90\x91R\x7F\xC8\x9E\xFD\xAAT\xC0\xF2\x0Cz\xDFa(\x82\xDF\tP\xF5\xA9Qc~\x03\x07\xCD\xCBLg/)\x8B\x8B\xC6``\x82\x01RF`\x80\x82\x01R0`\xA0\x82\x01R`\xC0\x01`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x90V[P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90V[_\x7Fh\xB8\xE9M\xC0wE\x82A\xD6\xC8\xD8\x9F\nve\xC7\xCD\xA2\xCF\xE7\x0C\x9E\xB4C~\xFE\xE1f=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x07\x10\x91\x90a;\xFBV[a\x07FW`@Q\x7F\xB31\xE4!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02\0\x87\x015\x88\x15\x80\x15\x90a\x07`WPa\x01`\x88\x015\x89\x11\x15[\x15a\x07\x7FWa\x07|\x89a\x02\0\x8A\x015a\x01`\x8B\x015`\x01a\x1C\x1EV[\x90P[a\x07\xB0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8B\x83\x8B\x8B\x8B\x8B\x8B\x8Ba\x1CiV[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16c\xBC\x11x\xE6a\x07\xEF`\xC0\x8B\x01`\xA0\x8C\x01a<\x16V[a\x08\x01a\x01@\x8C\x01a\x01 \x8D\x01a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x85\x90\x1B\x16\x81Ra\x08D\x92\x91\x90a\x01`\x8E\x015\x90\x88\x90`\x04\x01a<\x8DV[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x08[W_\x80\xFD[PZ\xF1\x15\x80\x15a\x08mW=_\x80>=_\xFD[PPPPa\x08\xB4\x88\x8B\x83\x8C_\x14\x80a\x08\x89WPa\x01`\x8C\x015\x8D\x11[a\x08\x93W\x8Ca\x08\x9AV[a\x01`\x8C\x015[\x89\x8C\x8C`\x02a\x08\xAF`@\x8E\x01` \x8F\x01a=aV[a\x1E\x01V[a\x08\xC1`@\x89\x01\x89a=\x7FV[`@Qa\x08\xCF\x92\x91\x90a=\xE0V[`@Q\x90\x81\x90\x03\x90 \x7F\x0F\xCE\0|8\xC6\xC8\xED\x9ET[:\x14\x80\x95v'8a\x8F\x8C!\xB6s\"&\x13\xE4\xD4W4\xB6a\t\t`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[a\t\x19`\xC0\x8C\x01`\xA0\x8D\x01a<\x16V[a\t+a\x01@\x8D\x01a\x01 \x8E\x01a<\x16V[a\t=a\x01\xE0\x8E\x01a\x01\xC0\x8F\x01a<\x16V[\x8E\x15\x80a\tNWPa\x01`\x8E\x015\x8F\x11[a\tXW\x8Ea\t_V[a\x01@\x8E\x015[a\x02\0\x8F\x015\x88\x14a\tqW\x87a\txV[a\x01\xE0\x8F\x015[\x8F`\xE0\x01` \x81\x01\x90a\t\x8B\x91\x90a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x98\x89\x16\x81R\x96\x88\x16` \x88\x01R\x94\x87\x16\x94\x86\x01\x94\x90\x94R\x91\x85\x16``\x85\x01R`\x80\x84\x01R`\xA0\x83\x01R\x90\x91\x16`\xC0\x82\x01R`\xE0\x01`@Q\x80\x91\x03\x90\xA2Pa\t\xDD`\x01\x80UV[PPPPPPPPPV[_[a\t\xF4\x82\x80a=\xEFV[\x90P\x81\x10\x15a\x0B\x06W6a\n\x08\x83\x80a=\xEFV[\x83\x81\x81\x10a\n\x18Wa\n\x18a>SV[\x90P` \x02\x81\x01\x90a\n*\x91\x90a>\x80V[\x90P`\x01`\x01`\xA0\x1B\x03\x84\x16c\xA8\xC4\xBC\x95a\nH` \x84\x01\x84a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\n\xA2W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\n\xC6\x91\x90a;\xFBV[\x15a\n\xFDW`@Q\x7F\xC9\x9E\x88r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P`\x01\x01a\t\xEAV[P_[a\x0B\x16` \x83\x01\x83a=\xEFV[\x90P\x81\x10\x15a\x0C+W6a\x0B-` \x84\x01\x84a=\xEFV[\x83\x81\x81\x10a\x0B=Wa\x0B=a>SV[\x90P` \x02\x81\x01\x90a\x0BO\x91\x90a>\x80V[\x90P`\x01`\x01`\xA0\x1B\x03\x84\x16c\xA8\xC4\xBC\x95a\x0Bm` \x84\x01\x84a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x0B\xC7W=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x0B\xEB\x91\x90a;\xFBV[\x15a\x0C\"W`@Q\x7F\xC9\x9E\x88r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P`\x01\x01a\x0B\tV[PPPV[_\x7F\xAEgk\xF6\x91:\xC2h\x9Bs1)<\x98\x9F\xE7r1$\xFA\xF8\xB5\xD2u\xF0o\xBC\xEB\xC7yP\ta\x05\xF5` \x84\x01\x84a<\x16V[a\x0Ci\x84\x82a\"\x12V[a\x0Cx\x85\x85\x85\x85`\x01\x80a\"\xC9V[PPPPPV[a\x0C\x893\x82a&\x1EV[PV[a\x0C\xBF`@Q\x80`\xC0\x01`@R\x80_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81RP\x90V[_[\x82\x81\x10\x15a\x10SW6\x84\x84\x83\x81\x81\x10a\x0C\xDCWa\x0C\xDCa>SV[\x90P` \x02\x81\x01\x90a\x0C\xEE\x91\x90a>\x80V[\x90P6_a\x0C\xFF`@\x84\x01\x84a=\x7FV[\x90\x92P\x90P`\x01`\x01`\xA0\x1B\x03\x8B\x16c\xA8\xC4\xBC\x95a\r ` \x86\x01\x86a<\x16V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81R`\x01`\x01`\xA0\x1B\x03\x90\x91\x16`\x04\x82\x01R`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\rzW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\r\x9E\x91\x90a;\xFBV[\x15a\x10EW_\x89\x15a\r\xDCW`@Q\x7F}a{\xB3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x04\x82\x10a\r\xE8WP\x815[\x7F\xC0:\x9D\xE9\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0EVWa\x0E=\x83\x83\x8D\x8Ca&\xC4V[\x86` \x01\x81\x81Qa\x0EN\x91\x90a>\xBCV[\x90RPa\x10CV[\x7F$:K\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0E\xBCWa\x0E\xAB\x83\x83\x8D\x8Ca'\xDAV[\x86``\x01\x81\x81Qa\x0EN\x91\x90a>\xBCV[\x7F}\xC4\xF4X\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0FGWa\x0F\x11\x83\x83\x8D\x8Ca)NV[`\xA0\x88\x01R`\x80\x87\x01\x81\x90R``\x87\x01\x80Qa\x0F.\x90\x83\x90a>\xBCV[\x90RP`\xA0\x86\x01Q` \x87\x01\x80Qa\x0EN\x90\x83\x90a>\xBCV[\x7Fh\x93\x1Bk\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x0F\xABWa\x0F\x9C\x83\x83\x8D\x8Ca+\xB6V[\x86Q\x87\x90a\x0EN\x90\x83\x90a>\xBCV[\x7F\x0C\x9B\xE7\xE4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x01a\x10\x11Wa\x10\0\x83\x83\x8D\x8Ca,\xC0V[\x86`@\x01\x81\x81Qa\x0EN\x91\x90a>\xBCV[`@Q\x7F\x05a\xD8\xB3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[P[PPP\x80`\x01\x01\x90Pa\x0C\xC1V[Pa\x10^\x84\x82a.)V[PPPPPPPV[`\x03a\x10v` \x83\x01\x83a?!V[`\x03\x81\x11\x15a\x10\x87Wa\x10\x87a>\xF4V[\x03a\x10\xECW`\x01`\x01`\xA0\x1B\x03\x83\x16a\x10\xAC\x83a\x10\xA7`@\x85\x01\x85a=\x7FV[a\x1BPV[`\x01`\x01`\xA0\x1B\x03\x16\x14a\x0C+W`@Q\x7F\xB8\x1DX\xE7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x01a\x10\xFB` \x83\x01\x83a?!V[`\x03\x81\x11\x15a\x11\x0CWa\x11\x0Ca>\xF4V[\x03a\x11\xA0W\x7F\x19Ethereum Signed Message:\n32\0\0\0\0_\x90\x81R`\x1C\x83\x90R`<\x90 `\x01`\x01`\xA0\x1B\x03\x84\x16a\x11Z\x82a\x10\xA7`@\x86\x01\x86a=\x7FV[`\x01`\x01`\xA0\x1B\x03\x16\x14a\x11\x9AW`@Q\x7FdJ\xE6\xC3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[PPPPV[`\x02a\x11\xAF` \x83\x01\x83a?!V[`\x03\x81\x11\x15a\x11\xC0Wa\x11\xC0a>\xF4V[\x03a\x12\xB9W\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x84\x16c\x16&\xBA~\x84a\x12\x03`@\x86\x01\x86a=\x7FV[`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x12!\x93\x92\x91\x90a??V[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x12=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x12`\x91\x90a?XV[\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x0C+W`@Q\x7F]R\xCB\xE3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@Q\x7F`\xCD@-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_a\x12\xF4a\x04\xD7V[\x7F\xD2\x8E\x80\x9Bp\x8F^\xE3\x8B\xE84}m\x86\x9D\x822I<\tJ\xB2\xDD\xE9\x83i\xE4\x10#i\xA9\x9Da\x13\x1F\x84\x80a=\x7FV[`@Q` \x01a\x130\x92\x91\x90a?\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x84` \x015\x85`@\x01` \x81\x01\x90a\x13^\x91\x90a<\x16V[`@\x80Q` \x81\x01\x95\x90\x95R\x84\x01\x92\x90\x92R``\x83\x01R`\x01`\x01`\xA0\x1B\x03\x16`\x80\x82\x01R`\xA0\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90Ra\x13\xC4`\x80\x85\x01``\x86\x01a<\x16V[a\x13\xD4`\xA0\x86\x01`\x80\x87\x01a<\x16V[a\x13\xE4`\xC0\x87\x01`\xA0\x88\x01a<\x16V[`\xC0\x87\x015`\xE0\x88\x015a\x01\0\x89\x015a\x01 \x8A\x015a\x14\x0Ca\x01`\x8C\x01a\x01@\x8D\x01a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x99\x8A\x16` \x82\x01R\x97\x89\x16\x90\x88\x01R\x94\x87\x16``\x87\x01R`\x80\x86\x01\x93\x90\x93R`\xA0\x85\x01\x91\x90\x91R`\xC0\x84\x01R`\xE0\x83\x01R\x90\x91\x16a\x01\0\x82\x01Ra\x01 \x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x90\x82\x90Ra\x14\x92\x92\x91` \x01a?\xD7V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 `@Q` \x01a\x06J\x92\x91\x90\x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x02\x81\x01\x92\x90\x92R`\"\x82\x01R`B\x01\x90V[a\x14\xF2a\x1B\xDBV[`@Q\x7F\x02\xCC%\r\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16\x90c\x02\xCC%\r\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x15mW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x15\x91\x91\x90a;\xFBV[a\x15\xC7W`@Q\x7F\xC19\xEA\xBD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@Q\x7F\xE7V\0\xC3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x89\x81\x16`\x04\x83\x01R\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90c\xE7V\0\xC3\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x16DW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x16h\x91\x90a;\xFBV[a\x16\x9EW`@Q\x7F\xB31\xE4!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02\0\x86\x015\x87\x15\x80\x15\x90a\x16\xB8WPa\x01`\x87\x015\x88\x11\x15[\x15a\x16\xD7Wa\x16\xD4\x88a\x02\0\x89\x015a\x01`\x8A\x015`\x01a\x1C\x1EV[\x90P[a\x17\x08\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8A\x83\x8A\x8A\x8A\x8A\x8A\x8Aa\x1CiV[a\x17E\x87\x8A\x83\x8B\x15\x80a\x17\x1FWPa\x01`\x8B\x015\x8C\x11[a\x17)W\x8Ba\x170V[a\x01`\x8B\x015[\x88\x8B\x8B`\x01a\x08\xAF`@\x8D\x01` \x8E\x01a=aV[a\x17R`@\x88\x01\x88a=\x7FV[`@Qa\x17`\x92\x91\x90a=\xE0V[`@Q\x90\x81\x90\x03\x90 \x7F\x0F\xCE\0|8\xC6\xC8\xED\x9ET[:\x14\x80\x95v'8a\x8F\x8C!\xB6s\"&\x13\xE4\xD4W4\xB6a\x17\x9A`\xA0\x8A\x01`\x80\x8B\x01a<\x16V[a\x17\xAA`\xC0\x8B\x01`\xA0\x8C\x01a<\x16V[a\x17\xBCa\x01@\x8C\x01a\x01 \x8D\x01a<\x16V[a\x17\xCEa\x01\xE0\x8D\x01a\x01\xC0\x8E\x01a<\x16V[\x8D\x15\x80a\x17\xDFWPa\x01`\x8D\x015\x8E\x11[a\x17\xE9W\x8Da\x17\xF0V[a\x01@\x8D\x015[a\x02\0\x8E\x015\x88\x14a\x18\x02W\x87a\x18\tV[a\x01\xE0\x8E\x015[\x8E`\xE0\x01` \x81\x01\x90a\x18\x1C\x91\x90a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x98\x89\x16\x81R\x96\x88\x16` \x88\x01R\x94\x87\x16\x94\x86\x01\x94\x90\x94R\x91\x85\x16``\x85\x01R`\x80\x84\x01R`\xA0\x83\x01R\x90\x91\x16`\xC0\x82\x01R`\xE0\x01`@Q\x80\x91\x03\x90\xA2Pa\x18n`\x01\x80UV[PPPPPPPPV[a\x18\x82\x85\x83a\"\x12V[`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16c\xBC\x11x\xE6a\x18\xC1`\x80\x88\x01``\x89\x01a<\x16V[a\x18\xD1`\xA0\x89\x01`\x80\x8A\x01a<\x16V[\x88`\xC0\x015\x85`@Q\x85c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x18\xF6\x94\x93\x92\x91\x90a<\x8DV[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x19\rW_\x80\xFD[PZ\xF1\x15\x80\x15a\x19\x1FW=_\x80>=_\xFD[PPPPa\x19D\x86\x86\x86\x86`\x02\x89` \x01` \x81\x01\x90a\x19?\x91\x90a=aV[a\"\xC9V[PPPPPPV[_a\x19Ua\x04\xD7V[\x7F\xC9\x94\xD2\xCA\x03u\xD6\xD4sx^\x0C\xE0\xB1\xD2\x03\xF0i\x12\x1B\xAC\x13\x14\xF7,\\\x0F\xE6\x01\xEB9\x10a\x19\x83`@\x85\x01\x85a=\x7FV[`@Q` \x01a\x19\x94\x92\x91\x90a?\x97V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R\x80Q` \x90\x91\x01 ``\x85\x015a\x19\xDF`\xA0\x87\x01`\x80\x88\x01a<\x16V[a\x19\xEF`\xC0\x88\x01`\xA0\x89\x01a<\x16V[`\xC0\x88\x015a\x1A\x05a\x01\0\x8A\x01`\xE0\x8B\x01a<\x16V[`@\x80Q` \x81\x01\x98\x90\x98R\x87\x01\x95\x90\x95R``\x86\x01\x93\x90\x93R`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\x80\x86\x01R\x81\x16`\xA0\x85\x01R`\xC0\x84\x01\x91\x90\x91R\x16`\xE0\x82\x01Ra\x01\0\x80\x85\x015\x90\x82\x01Ra\x01 \x01`@Q` \x81\x83\x03\x03\x81R\x90`@Ra\x1Ao\x84a\x01 \x01a\x0C0V[a\x1A|\x85a\x01\xC0\x01a\x05\xC6V[`@Q` \x01a\x14\x92\x93\x92\x91\x90a?\xEBV[a\x01\xA0\x81\x015a\x1A\xA8a\x01\x80\x83\x015a\x01`\x84\x015a>\xBCV[a\x1A\xB2\x91\x90a>\xBCV[a\x01@\x82\x015\x14a\x1A\xEFW`@Q\x7F\xC0Cw\xD3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02@\x81\x015a\x1B\ta\x02 \x83\x015a\x02\0\x84\x015a>\xBCV[a\x1B\x13\x91\x90a>\xBCV[a\x01\xE0\x82\x015\x14a\x0C\x89W`@Q\x7F\x87v0\xBE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80a\x1B\x91\x85\x85\x85\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x91\x90\x91RPa.\xD6\x92PPPV[\x90P`\x01`\x01`\xA0\x1B\x03\x81\x16a\x1B\xD3W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x94\x93PPPPV[`\x02`\x01T\x03a\x1C\x17W`@Q\x7F>\xE5\xAE\xB5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x02`\x01UV[_a\x1CKa\x1C+\x83a/\0V[\x80\x15a\x1CFWP_\x84\x80a\x1CAWa\x1CAa@\x08V[\x86\x88\t\x11[\x15\x15\x90V[a\x1CV\x86\x86\x86a/,V[a\x1C`\x91\x90a>\xBCV[\x95\x94PPPPPV[_a\x1Cs\x87a\x19LV[\x90Pa\x1C\x80\x89\x82\x85a\x10gV[a\x1C\x90`\xC0\x88\x01`\xA0\x89\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14a\x1C\xC7Wa\x1C\xC2a\x1C\xBB`\xC0\x89\x01`\xA0\x8A\x01a<\x16V[\x82\x84a\x10gV[a\x1D\x0EV[a\x1C\xD4`@\x83\x01\x83a=\x7FV[\x90P_\x03a\x1D\x0EW`@Q\x7F\x0E6N\xFC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x1D+a\x1D!`\xC0\x89\x01`\xA0\x8A\x01a<\x16V[\x88``\x015a&\x1EV[\x86`\xC0\x015B\x11\x15a\x1DiW`@Q\x7F\x13=\xF0)\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x88\x11\x80\x15a\x1D|WP\x86a\x01\0\x015\x88\x10[\x15a\x1D\xB3W`@Q\x7F\x94itD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x1D\xBC\x87a\x1A\x8EV[a\x1D\xC6\x8A\x85a\t\xE8V[a\x1D\xE7\x8A\x8A_\x8B\x11\x80\x15a\x1D\xDFWPa\x02\0\x8A\x015\x8B\x14\x15[\x8A\x8A\x8Aa\x0C\x8CV[a\x1D\xF5\x89\x88``\x015a&\x1EV[PPPPPPPPPPV[a\x1E\x13a\x1E\x0E\x86\x80a=\xEFV[a0\x01V[_a\x1E(a\x01\x80\x8B\x015a\x01\xA0\x8C\x015a>\xBCV[\x90P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8D`\xA0\x01` \x81\x01\x90a\x1Ew\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x010`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8Da\x01 \x01_\x01` \x81\x01\x90a\x1E\xAA\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x84\x81R` \x01\x86`\x02\x81\x11\x15a\x1E\xD0Wa\x1E\xD0a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x1E\xEF\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x1F\x06W_\x80\xFD[PZ\xF1\x15\x80\x15a\x1F\x18W=_\x80>=_\xFD[PPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8D`\xA0\x01` \x81\x01\x90a\x1Fi\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8D`\xE0\x01` \x81\x01\x90a\x1F\x8A\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8Da\x01 \x01_\x01` \x81\x01\x90a\x1F\xAE\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8A\x81R` \x01\x86`\x02\x81\x11\x15a\x1F\xD4Wa\x1F\xD4a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\x1F\xF3\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a \nW_\x80\xFD[PZ\xF1\x15\x80\x15a \x1CW=_\x80>=_\xFD[PPPPa *\x85\x85a0\x01V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8C`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8D`\x80\x01` \x81\x01\x90a \x86\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8Da\x01\xC0\x01_\x01` \x81\x01\x90a \xAA\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x8B\x81R` \x01\x85`\x02\x81\x11\x15a \xD0Wa \xD0a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a \xEF\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a!\x06W_\x80\xFD[PZ\xF1\x15\x80\x15a!\x18W=_\x80>=_\xFD[Pa!.\x92Pa\x1E\x0E\x91PP` \x88\x01\x88a=\xEFV[_a!Aa\x01@\x8C\x01a\x01 \x8D\x01a<\x16V[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R`\x01`\x01`\xA0\x1B\x03\x91\x90\x91\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a!\x9EW=_\x80>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a!\xC2\x91\x90a@\xB4V[\x90P\x80\x15a\"\x05Wa\"\x05a!\xDEa\x01\0\x8D\x01`\xE0\x8E\x01a<\x16V[\x82\x8Da\x01 \x01_\x01` \x81\x01\x90a!\xF5\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x91\x90a19V[PPPPPPPPPPPV[a\"\"`\x80\x83\x01``\x84\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x163`\x01`\x01`\xA0\x1B\x03\x16\x14a\"aWa\"\\a\"M`\x80\x84\x01``\x85\x01a<\x16V[a\"V\x84a\x12\xEBV[\x83a\x10gV[a\"\xA8V[a\"n`@\x82\x01\x82a=\x7FV[\x90P_\x03a\"\xA8W`@Q\x7F\x0E6N\xFC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\"\xC5a\"\xBB`\x80\x84\x01``\x85\x01a<\x16V[\x83` \x015a&\x1EV[PPV[`\xE0\x85\x015\x83\x15\x80\x15\x90a\"\xE0WP\x85`\xC0\x015\x84\x10[\x15a\"\xFDWa\"\xFA\x84\x87`\xE0\x015\x88`\xC0\x015`\x01a\x1C\x1EV[\x90P[a#\t\x87\x82\x88\x88a1\xB9V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x89``\x01` \x81\x01\x90a#V\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01a#va\x01`\x8B\x01a\x01@\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01a#\x94`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x87\x15\x80a#\xB2WP\x89`\xC0\x015\x88\x11[a#\xBCW\x87a#\xC2V[\x89`\xC0\x015[\x81R` \x01\x86`\x02\x81\x11\x15a#\xD9Wa#\xD9a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a#\xF8\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a$\x0FW_\x80\xFD[PZ\xF1\x15\x80\x15a$!W=_\x80>=_\xFD[PPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\x01`\x01`\xA0\x1B\x03\x16c\xB5\x19\xD3i`@Q\x80`\xA0\x01`@R\x80\x8A`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x89`@\x01` \x81\x01\x90a$\x81\x91\x90a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01a$\x9F`\xC0\x8B\x01`\xA0\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x81R` \x01\x84\x81R` \x01\x85`\x02\x81\x11\x15a$\xC5Wa$\xC5a>\xF4V[\x81RP`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a$\xE4\x91\x90a@5V[_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a$\xFBW_\x80\xFD[PZ\xF1\x15\x80\x15a%\rW=_\x80>=_\xFD[Pa%\x1E\x92P\x88\x91P\x81\x90Pa=\x7FV[`@Qa%,\x92\x91\x90a=\xE0V[`@Q\x80\x91\x03\x90 \x7F\x0F\xCE\0|8\xC6\xC8\xED\x9ET[:\x14\x80\x95v'8a\x8F\x8C!\xB6s\"&\x13\xE4\xD4W4\xB6\x87`@\x01` \x81\x01\x90a%h\x91\x90a<\x16V[a%x`\x80\x8A\x01``\x8B\x01a<\x16V[a%\x88`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[a%\x98`\xC0\x8C\x01`\xA0\x8D\x01a<\x16V[\x89\x15\x80a%\xA8WP\x8B`\xC0\x015\x8A\x11[a%\xB2W\x89a%\xB8V[\x8B`\xC0\x015[\x87\x8Da\x01@\x01` \x81\x01\x90a%\xCD\x91\x90a<\x16V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x98\x89\x16\x81R\x96\x88\x16` \x88\x01R\x94\x87\x16\x94\x86\x01\x94\x90\x94R\x91\x85\x16``\x85\x01R`\x80\x84\x01R`\xA0\x83\x01R\x90\x91\x16`\xC0\x82\x01R`\xE0\x01`@Q\x80\x91\x03\x90\xA2PPPPPPPV[`\x01`\x01`\xA0\x1B\x03\x82\x16_\x90\x81R` \x81\x81R`@\x80\x83 \x84\x84R\x90\x91R\x90 T`\xFF\x16\x15a&yW`@Q\x7F\xBC\r\xA7\xD6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x01`\x01`\xA0\x1B\x03\x90\x91\x16_\x90\x81R` \x81\x81R`@\x80\x83 \x93\x83R\x92\x90R \x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\x16`\x01\x17\x90UV[_\x80\x80\x80a&\xD5\x87`\x04\x81\x8Ba@\xCBV[\x81\x01\x90a&\xE2\x91\x90a@\xF2V[P\x91\x94P\x92P\x90Pa&\xFCa\x01@\x86\x01a\x01 \x87\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x83`\x01`\x01`\xA0\x1B\x03\x16\x14a'FW`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x81`\x01`\x01`\xA0\x1B\x03\x16\x86`\x01`\x01`\xA0\x1B\x03\x16\x14a'\x91W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x01\xA0\x85\x015\x81\x14a'\xCFW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x97\x96PPPPPPPV[_\x80\x80\x80\x80a'\xEC\x88`\x04\x81\x8Ca@\xCBV[\x81\x01\x90a'\xF9\x91\x90aABV[\x92\x96P\x90\x94P\x92P\x90Pa(\x15a\x01\xE0\x87\x01a\x01\xC0\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x14a(_W`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x82`\x01`\x01`\xA0\x1B\x03\x16\x87`\x01`\x01`\xA0\x1B\x03\x16\x14a(\xAAW`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a(\xBA`\xA0\x87\x01`\x80\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14a)\x04W`@Q\x7F\xACk\x05\xF5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02@\x86\x015\x81\x14a)BW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x98\x97PPPPPPPPV[_\x80_\x80_\x80_\x80_\x8C\x8C`\x04\x90\x80\x92a)j\x93\x92\x91\x90a@\xCBV[\x81\x01\x90a)w\x91\x90aA\x90V[\x95\x9CP\x93\x9AP\x91\x98P\x96P\x94P\x92P\x90Pa)\x9Aa\x01\xE0\x8B\x01a\x01\xC0\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x87`\x01`\x01`\xA0\x1B\x03\x16\x14a)\xE4W`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x85`\x01`\x01`\xA0\x1B\x03\x16\x8B`\x01`\x01`\xA0\x1B\x03\x16\x14a*/W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x01`\x01`\xA0\x1B\x03\x85\x160\x14a*qW`@Q\x7F\x81T7K\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a*\x81`\xA0\x8B\x01`\x80\x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x14a*\xCBW`@Q\x7F\xACk\x05\xF5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02@\x8A\x015\x83\x14a+\tW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a+\x1Ba\x01@\x8B\x01a\x01 \x8C\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14a+eW`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x01\xA0\x8A\x015\x81\x14a+\xA3W`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x91\x9C\x91\x9BP\x90\x99PPPPPPPPPPV[_\x80\x80\x80a+\xC7\x87`\x04\x81\x8Ba@\xCBV[\x81\x01\x90a+\xD4\x91\x90aB\x0FV[\x91\x94P\x92P\x90Pa+\xEDa\x01@\x86\x01a\x01 \x87\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x83`\x01`\x01`\xA0\x1B\x03\x16\x14a,7W`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x81`\x01`\x01`\xA0\x1B\x03\x16\x86`\x01`\x01`\xA0\x1B\x03\x16\x14a,\x82W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x01\x80\x85\x015\x81\x14a'\xCFW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80\x80\x80\x80a,\xD2\x88`\x04\x81\x8Ca@\xCBV[\x81\x01\x90a,\xDF\x91\x90aBMV[P\x92\x96P\x90\x94P\x92P\x90Pa,\xFCa\x01\xE0\x87\x01a\x01\xC0\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x84`\x01`\x01`\xA0\x1B\x03\x16\x14a-FW`@Q\x7F\xC8\x91\xAD\xD2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x82`\x01`\x01`\xA0\x1B\x03\x16\x87`\x01`\x01`\xA0\x1B\x03\x16\x14a-\x91W`@Q\x7F\x81^\x1Dd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a-\xA1`\xA0\x87\x01`\x80\x88\x01a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x82`\x01`\x01`\xA0\x1B\x03\x16\x14a-\xEBW`@Q\x7F\xACk\x05\xF5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x02 \x86\x015\x81\x14a)BW`@Q\x7F,R\x11\xC6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[\x80Qa\x01\x80\x83\x015\x14\x15\x80a.GWP` \x81\x01Qa\x01\xA0\x83\x015\x14\x15[\x15a.~W`@Q\x7FJU\xDA \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`@\x81\x01Qa\x02 \x83\x015\x14\x15\x80a.\x9FWP``\x81\x01Qa\x02@\x83\x015\x14\x15[\x15a\"\xC5W`@Q\x7Fw\xA5\x92\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80_\x80a.\xE4\x86\x86a2\\V[\x92P\x92P\x92Pa.\xF4\x82\x82a2\xA5V[P\x90\x91PP[\x92\x91PPV[_`\x02\x82`\x03\x81\x11\x15a/\x15Wa/\x15a>\xF4V[a/\x1F\x91\x90aB\xB1V[`\xFF\x16`\x01\x14\x90P\x91\x90PV[_\x83\x83\x02\x81\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x87\t\x82\x81\x10\x83\x82\x03\x03\x91PP\x80_\x03a/\x7FW\x83\x82\x81a/uWa/ua@\x08V[\x04\x92PPPa\x04\xD0V[\x80\x84\x11a/\x96Wa/\x96`\x03\x85\x15\x02`\x11\x18a3\xADV[_\x84\x86\x88\t_\x86\x81\x03\x87\x16\x96\x87\x90\x04\x96`\x02`\x03\x89\x02\x81\x18\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x82\x03\x02\x80\x8A\x02\x90\x91\x03\x02\x91\x81\x90\x03\x81\x90\x04`\x01\x01\x86\x84\x11\x90\x95\x03\x94\x90\x94\x02\x91\x90\x94\x03\x92\x90\x92\x04\x91\x90\x91\x17\x91\x90\x91\x02\x91PP\x93\x92PPPV[_[\x81\x81\x10\x15a\x0C+W6\x83\x83\x83\x81\x81\x10a0\x1EWa0\x1Ea>SV[\x90P` \x02\x81\x01\x90a00\x91\x90a>\x80V[\x90P`\x01`\x01`\xA0\x1B\x03\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16a0i` \x83\x01\x83a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x03a0\xA9W`@Q\x7Fy\xA1\xBF\xF0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a0\xB2\x81a3\xBEV[a0\xBF` \x82\x01\x82a<\x16V[`\x01`\x01`\xA0\x1B\x03\x16\x7F\xED\x99\x82~\xFB7\x01o\"u\xF9\x8CK\xCFq\xC7U\x1Cu\xD5\x9E\x9BE\x0Fy\xFA2\xE6\x0B\xE6r\xC2\x82` \x015a0\xF7\x84a4\x01V[`@\x80Q\x92\x83R\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16` \x83\x01R\x01`@Q\x80\x91\x03\x90\xA2P`\x01\x01a0\x03V[`@\x80Q`\x01`\x01`\xA0\x1B\x03\x84\x16`$\x82\x01R`D\x80\x82\x01\x84\x90R\x82Q\x80\x83\x03\x90\x91\x01\x81R`d\x90\x91\x01\x90\x91R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90Ra\x0C+\x90\x84\x90a4*V[_\x83\x11\x80\x15a1\xCCWP\x81a\x01\0\x015\x83\x10[\x15a2\x03W`@Q\x7F\x94itD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a2\x10\x84a\"V\x84a\x12\xEBV[a2\x1E\x84\x83` \x015a&\x1EV[B\x82a\x01 \x015\x11a\x11\x9AW`@Q\x7F\xC5hs\xBA\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[_\x80_\x83Q`A\x03a2\x93W` \x84\x01Q`@\x85\x01Q``\x86\x01Q_\x1Aa2\x85\x88\x82\x85\x85a4\xAFV[\x95P\x95P\x95PPPPa2\x9EV[PP\x81Q_\x91P`\x02\x90[\x92P\x92P\x92V[_\x82`\x03\x81\x11\x15a2\xB8Wa2\xB8a>\xF4V[\x03a2\xC1WPPV[`\x01\x82`\x03\x81\x11\x15a2\xD5Wa2\xD5a>\xF4V[\x03a3\x0CW`@Q\x7F\xF6E\xEE\xDF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\x02\x82`\x03\x81\x11\x15a3 Wa3 a>\xF4V[\x03a3_W`@Q\x7F\xFC\xE6\x98\xF7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x82\x90R`$\x01[`@Q\x80\x91\x03\x90\xFD[`\x03\x82`\x03\x81\x11\x15a3sWa3sa>\xF4V[\x03a\"\xC5W`@Q\x7F\xD7\x8B\xCE\x0C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x81\x01\x82\x90R`$\x01a3VV[cNH{q_R\x80` R`$`\x1C\xFD[_a3\xCC` \x83\x01\x83a<\x16V[\x90P` \x82\x0156_a3\xE2`@\x86\x01\x86a=\x7FV[\x91P\x91P`@Q\x81\x83\x827_\x80\x83\x83\x87\x89Z\xF1a\x19DW=_\x80>=_\xFD[_6\x81a4\x11`@\x85\x01\x85a=\x7FV[\x90\x92P\x90P`\x04\x81\x10a4#W\x815\x92P[PP\x91\x90PV[_\x80` _\x84Q` \x86\x01_\x88Z\xF1\x80a4IW`@Q=_\x82>=\x81\xFD[PP_Q=\x91P\x81\x15a4`W\x80`\x01\x14\x15a4mV[`\x01`\x01`\xA0\x1B\x03\x84\x16;\x15[\x15a\x11\x9AW`@Q\x7FRt\xAF\xE7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x01`\x01`\xA0\x1B\x03\x85\x16`\x04\x82\x01R`$\x01a3VV[_\x80\x80\x7F\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF]WnsW\xA4P\x1D\xDF\xE9/Fh\x1B \xA0\x84\x11\x15a4\xE8WP_\x91P`\x03\x90P\x82a5\x8BV[`@\x80Q_\x80\x82R` \x82\x01\x80\x84R\x8A\x90R`\xFF\x89\x16\x92\x82\x01\x92\x90\x92R``\x81\x01\x87\x90R`\x80\x81\x01\x86\x90R`\x01\x90`\xA0\x01` `@Q` \x81\x03\x90\x80\x84\x03\x90\x85Z\xFA\x15\x80\x15a59W=_\x80>=_\xFD[PP`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01Q\x91PP`\x01`\x01`\xA0\x1B\x03\x81\x16a5\x82WP_\x92P`\x01\x91P\x82\x90Pa5\x8BV[\x92P_\x91P\x81\x90P[\x94P\x94P\x94\x91PPV[_\x80_`@\x84\x86\x03\x12\x15a5\xA7W_\x80\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a5\xC5W_\x80\xFD[\x81\x86\x01\x91P\x86`\x1F\x83\x01\x12a5\xD8W_\x80\xFD[\x815\x81\x81\x11\x15a5\xE6W_\x80\xFD[\x87` \x82\x85\x01\x01\x11\x15a5\xF7W_\x80\xFD[` \x83\x01\x94P\x80\x93PPPP\x92P\x92P\x92V[_`\xA0\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[P\x91\x90PV[_`\xA0\x82\x84\x03\x12\x15a60W_\x80\xFD[a\x04\xD0\x83\x83a6\nV[`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x0C\x89W_\x80\xFD[\x805a6Y\x81a6:V[\x91\x90PV[_a\x02`\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_\x80\x83`\x1F\x84\x01\x12a6\x7FW_\x80\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a6\x96W_\x80\xFD[` \x83\x01\x91P\x83` \x82`\x05\x1B\x85\x01\x01\x11\x15a6\xB0W_\x80\xFD[\x92P\x92\x90PV[_`@\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_``\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_\x80_\x80_\x80_\x80_a\x01\0\x8A\x8C\x03\x12\x15a6\xF0W_\x80\xFD[a6\xF9\x8Aa6NV[\x98P` \x8A\x015\x97P`@\x8A\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a7\x1CW_\x80\xFD[a7(\x8D\x83\x8E\x01a6^V[\x98P``\x8C\x015\x91P\x80\x82\x11\x15a7=W_\x80\xFD[a7I\x8D\x83\x8E\x01a6oV[\x90\x98P\x96P`\x80\x8C\x015\x91P\x80\x82\x11\x15a7aW_\x80\xFD[a7m\x8D\x83\x8E\x01a6\xB7V[\x95P`\xA0\x8C\x015\x91P\x80\x82\x11\x15a7\x82W_\x80\xFD[a7\x8E\x8D\x83\x8E\x01a6\xC7V[\x94P`\xC0\x8C\x015\x91P\x80\x82\x11\x15a7\xA3W_\x80\xFD[a7\xAF\x8D\x83\x8E\x01a6\xC7V[\x93P`\xE0\x8C\x015\x91P\x80\x82\x11\x15a7\xC4W_\x80\xFD[Pa7\xD1\x8C\x82\x8D\x01a6\xC7V[\x91PP\x92\x95\x98P\x92\x95\x98P\x92\x95\x98V[_\x80`@\x83\x85\x03\x12\x15a7\xF2W_\x80\xFD[\x825a7\xFD\x81a6:V[\x91P` \x83\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a8\x18W_\x80\xFD[a8$\x85\x82\x86\x01a6\xB7V[\x91PP\x92P\x92\x90PV[_a\x01`\x82\x84\x03\x12\x15a6\x1AW_\x80\xFD[_\x80_\x80_`\xA0\x86\x88\x03\x12\x15a8SW_\x80\xFD[\x855a8^\x81a6:V[\x94P` \x86\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a8zW_\x80\xFD[a8\x86\x89\x83\x8A\x01a8.V[\x95P`@\x88\x015\x91P\x80\x82\x11\x15a8\x9BW_\x80\xFD[a8\xA7\x89\x83\x8A\x01a6\xC7V[\x94P``\x88\x015\x93P`\x80\x88\x015\x91P\x80\x82\x11\x15a8\xC3W_\x80\xFD[Pa8\xD0\x88\x82\x89\x01a6\xC7V[\x91PP\x92\x95P\x92\x95\x90\x93PV[_` \x82\x84\x03\x12\x15a8\xEDW_\x80\xFD[P5\x91\x90PV[\x80\x15\x15\x81\x14a\x0C\x89W_\x80\xFD[_\x80_\x80_\x80`\xA0\x87\x89\x03\x12\x15a9\x16W_\x80\xFD[\x865a9!\x81a6:V[\x95P` \x87\x015a91\x81a6:V[\x94P`@\x87\x015a9A\x81a8\xF4V[\x93P``\x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a9]W_\x80\xFD[a9i\x8A\x83\x8B\x01a6^V[\x94P`\x80\x89\x015\x91P\x80\x82\x11\x15a9~W_\x80\xFD[Pa9\x8B\x89\x82\x8A\x01a6oV[\x97\x9A\x96\x99P\x94\x97P\x92\x95\x93\x94\x92PPPV[_\x80_``\x84\x86\x03\x12\x15a9\xAFW_\x80\xFD[\x835a9\xBA\x81a6:V[\x92P` \x84\x015\x91P`@\x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a9\xDCW_\x80\xFD[a9\xE8\x86\x82\x87\x01a6\xC7V[\x91PP\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a:\x02W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a:\x18W_\x80\xFD[a\x1B\xD3\x84\x82\x85\x01a8.V[_\x80_\x80_\x80_\x80`\xE0\x89\x8B\x03\x12\x15a:;W_\x80\xFD[a:D\x89a6NV[\x97P` \x89\x015\x96P`@\x89\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a:gW_\x80\xFD[a:s\x8C\x83\x8D\x01a6^V[\x97P``\x8B\x015\x91P\x80\x82\x11\x15a:\x88W_\x80\xFD[a:\x94\x8C\x83\x8D\x01a6oV[\x90\x97P\x95P`\x80\x8B\x015\x91P\x80\x82\x11\x15a:\xACW_\x80\xFD[a:\xB8\x8C\x83\x8D\x01a6\xB7V[\x94P`\xA0\x8B\x015\x91P\x80\x82\x11\x15a:\xCDW_\x80\xFD[a:\xD9\x8C\x83\x8D\x01a6\xC7V[\x93P`\xC0\x8B\x015\x91P\x80\x82\x11\x15a:\xEEW_\x80\xFD[Pa:\xFB\x8B\x82\x8C\x01a6\xC7V[\x91PP\x92\x95\x98P\x92\x95\x98\x90\x93\x96PV[_\x80_\x80_\x80`\xC0\x87\x89\x03\x12\x15a; W_\x80\xFD[a;)\x87a6NV[\x95P` \x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a;EW_\x80\xFD[a;Q\x8A\x83\x8B\x01a8.V[\x96P`@\x89\x015\x91P\x80\x82\x11\x15a;fW_\x80\xFD[a;r\x8A\x83\x8B\x01a6\xC7V[\x95P``\x89\x015\x94P`\x80\x89\x015\x91P\x80\x82\x11\x15a;\x8EW_\x80\xFD[a;\x9A\x8A\x83\x8B\x01a6\xC7V[\x93P`\xA0\x89\x015\x91P\x80\x82\x11\x15a;\xAFW_\x80\xFD[Pa;\xBC\x89\x82\x8A\x01a6\xC7V[\x91PP\x92\x95P\x92\x95P\x92\x95V[_` \x82\x84\x03\x12\x15a;\xD9W_\x80\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a;\xEFW_\x80\xFD[a\x1B\xD3\x84\x82\x85\x01a6^V[_` \x82\x84\x03\x12\x15a<\x0BW_\x80\xFD[\x81Qa\x04\xD0\x81a8\xF4V[_` \x82\x84\x03\x12\x15a<&W_\x80\xFD[\x815a\x04\xD0\x81a6:V[\x81\x83R\x81\x81` \x85\x017P_` \x82\x84\x01\x01R_` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x84\x01\x01\x90P\x92\x91PPV[\x805e\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a6YW_\x80\xFD[_`\x01`\x01`\xA0\x1B\x03\x80\x87\x16\x83R\x80\x86\x16` \x84\x01RP\x83`@\x83\x01R`\x80``\x83\x01R\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a<\xE2W_\x80\xFD[\x83\x01` \x81\x01\x905g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a<\xFEW_\x80\xFD[\x806\x03\x82\x13\x15a=\x0CW_\x80\xFD[```\x80\x85\x01Ra=!`\xE0\x85\x01\x82\x84a<1V[\x91PPa=0` \x85\x01a\"W_\x80\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a>\xB2W_\x80\xFD[\x91\x90\x91\x01\x92\x91PPV[\x80\x82\x01\x80\x82\x11\x15a.\xFAW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a?1W_\x80\xFD[\x815`\x04\x81\x10a\x04\xD0W_\x80\xFD[\x83\x81R`@` \x82\x01R_a\x1C``@\x83\x01\x84\x86a<1V[_` \x82\x84\x03\x12\x15a?hW_\x80\xFD[\x81Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x81\x14a\x04\xD0W_\x80\xFD[` \x81R_a\x1B\xD3` \x83\x01\x84\x86a<1V[_\x81Q_[\x81\x81\x10\x15a?\xC9W` \x81\x85\x01\x81\x01Q\x86\x83\x01R\x01a?\xAFV[P_\x93\x01\x92\x83RP\x90\x91\x90PV[_a\x1B\xD3a?\xE5\x83\x86a?\xAAV[\x84a?\xAAV[_a?\xF6\x82\x86a?\xAAV[\x93\x84RPP` \x82\x01R`@\x01\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_`\xA0\x82\x01\x90P`\x01`\x01`\xA0\x1B\x03\x80\x84Q\x16\x83R\x80` \x85\x01Q\x16` \x84\x01R\x80`@\x85\x01Q\x16`@\x84\x01RP``\x83\x01Q``\x83\x01R`\x80\x83\x01Q`\x03\x81\x10a@\xA7W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`!`\x04R`$_\xFD[\x80`\x80\x84\x01RP\x92\x91PPV[_` \x82\x84\x03\x12\x15a@\xC4W_\x80\xFD[PQ\x91\x90PV[_\x80\x85\x85\x11\x15a@\xD9W_\x80\xFD[\x83\x86\x11\x15a@\xE5W_\x80\xFD[PP\x82\x01\x93\x91\x90\x92\x03\x91PV[_\x80_\x80`\x80\x85\x87\x03\x12\x15aA\x05W_\x80\xFD[\x845aA\x10\x81a6:V[\x93P` \x85\x015aA \x81a6:V[\x92P`@\x85\x015\x91P``\x85\x015aA7\x81a8\xF4V[\x93\x96\x92\x95P\x90\x93PPV[_\x80_\x80`\x80\x85\x87\x03\x12\x15aAUW_\x80\xFD[\x845aA`\x81a6:V[\x93P` \x85\x015aAp\x81a6:V[\x92P`@\x85\x015aA\x80\x81a6:V[\x93\x96\x92\x95P\x92\x93``\x015\x92PPV[_\x80_\x80_\x80_`\xE0\x88\x8A\x03\x12\x15aA\xA6W_\x80\xFD[\x875aA\xB1\x81a6:V[\x96P` \x88\x015aA\xC1\x81a6:V[\x95P`@\x88\x015aA\xD1\x81a6:V[\x94P``\x88\x015aA\xE1\x81a6:V[\x93P`\x80\x88\x015\x92P`\xA0\x88\x015aA\xF8\x81a6:V[\x80\x92PP`\xC0\x88\x015\x90P\x92\x95\x98\x91\x94\x97P\x92\x95PV[_\x80_``\x84\x86\x03\x12\x15aB!W_\x80\xFD[\x835aB,\x81a6:V[\x92P` \x84\x015aB<\x81a6:V[\x92\x95\x92\x94PPP`@\x91\x90\x91\x015\x90V[_\x80_\x80_`\xA0\x86\x88\x03\x12\x15aBaW_\x80\xFD[\x855aBl\x81a6:V[\x94P` \x86\x015aB|\x81a6:V[\x93P`@\x86\x015aB\x8C\x81a6:V[\x92P``\x86\x015\x91P`\x80\x86\x015aB\xA3\x81a8\xF4V[\x80\x91PP\x92\x95P\x92\x95\x90\x93PV[_`\xFF\x83\x16\x80aB\xE8W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[\x80`\xFF\x84\x16\x06\x91PP\x92\x91PPV\xFE\xA2dipfsX\"\x12 \x9B\xE5\x8A\xCA\xDA50a\xA2\xA2\x02\xCCp\x11\xF3\xC9\x13\x93\xE0\xF2\xE3\x05\xE9 $E\xB0B\xFCJL\xE6dsolcC\0\x08\x17\x003", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ECDSAInvalidSignature()` and selector `0xf645eedf`. + ```solidity + error ECDSAInvalidSignature(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ECDSAInvalidSignature; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ECDSAInvalidSignature) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ECDSAInvalidSignature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ECDSAInvalidSignature { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [246u8, 69u8, 238u8, 223u8]; + const SIGNATURE: &'static str = "ECDSAInvalidSignature()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ECDSAInvalidSignatureLength(uint256)` and selector `0xfce698f7`. + ```solidity + error ECDSAInvalidSignatureLength(uint256 length); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ECDSAInvalidSignatureLength { + #[allow(missing_docs)] + pub length: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ECDSAInvalidSignatureLength) -> Self { + (value.length,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ECDSAInvalidSignatureLength { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { length: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ECDSAInvalidSignatureLength { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [252u8, 230u8, 152u8, 247u8]; + const SIGNATURE: &'static str = "ECDSAInvalidSignatureLength(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.length, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ECDSAInvalidSignatureS(bytes32)` and selector `0xd78bce0c`. + ```solidity + error ECDSAInvalidSignatureS(bytes32 s); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ECDSAInvalidSignatureS { + #[allow(missing_docs)] + pub s: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ECDSAInvalidSignatureS) -> Self { + (value.s,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ECDSAInvalidSignatureS { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { s: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ECDSAInvalidSignatureS { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [215u8, 139u8, 206u8, 12u8]; + const SIGNATURE: &'static str = "ECDSAInvalidSignatureS(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.s), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidAmount()` and selector `0x2c5211c6`. + ```solidity + error InvalidAmount(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidAmount; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidAmount) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidAmount { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidAmount { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [44u8, 82u8, 17u8, 198u8]; + const SIGNATURE: &'static str = "InvalidAmount()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidAsset()` and selector `0xc891add2`. + ```solidity + error InvalidAsset(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidAsset; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidAsset) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidAsset { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidAsset { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [200u8, 145u8, 173u8, 210u8]; + const SIGNATURE: &'static str = "InvalidAsset()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidBaseTokenAmounts()` and selector `0xc04377d3`. + ```solidity + error InvalidBaseTokenAmounts(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidBaseTokenAmounts; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidBaseTokenAmounts) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidBaseTokenAmounts { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidBaseTokenAmounts { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [192u8, 67u8, 119u8, 211u8]; + const SIGNATURE: &'static str = "InvalidBaseTokenAmounts()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidDestination()` and selector `0xac6b05f5`. + ```solidity + error InvalidDestination(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidDestination; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidDestination) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidDestination { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidDestination { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [172u8, 107u8, 5u8, 245u8]; + const SIGNATURE: &'static str = "InvalidDestination()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidEIP1271Signature()` and selector `0x5d52cbe3`. + ```solidity + error InvalidEIP1271Signature(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidEIP1271Signature; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidEIP1271Signature) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidEIP1271Signature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidEIP1271Signature { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [93u8, 82u8, 203u8, 227u8]; + const SIGNATURE: &'static str = "InvalidEIP1271Signature()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidEIP712Signature()` and selector `0xb81d58e7`. + ```solidity + error InvalidEIP712Signature(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidEIP712Signature; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidEIP712Signature) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidEIP712Signature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidEIP712Signature { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [184u8, 29u8, 88u8, 231u8]; + const SIGNATURE: &'static str = "InvalidEIP712Signature()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidETHSignSignature()` and selector `0x644ae6c3`. + ```solidity + error InvalidETHSignSignature(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidETHSignSignature; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidETHSignSignature) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidETHSignSignature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidETHSignSignature { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [100u8, 74u8, 230u8, 195u8]; + const SIGNATURE: &'static str = "InvalidETHSignSignature()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidFillAmount()` and selector `0x94697444`. + ```solidity + error InvalidFillAmount(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidFillAmount; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidFillAmount) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidFillAmount { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidFillAmount { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [148u8, 105u8, 116u8, 68u8]; + const SIGNATURE: &'static str = "InvalidFillAmount()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidHooksTarget()` and selector `0xc99e8872`. + ```solidity + error InvalidHooksTarget(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidHooksTarget; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidHooksTarget) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidHooksTarget { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidHooksTarget { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [201u8, 158u8, 136u8, 114u8]; + const SIGNATURE: &'static str = "InvalidHooksTarget()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidInteractionsBaseTokenAmounts()` and selector `0x4a55da20`. + ```solidity + error InvalidInteractionsBaseTokenAmounts(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidInteractionsBaseTokenAmounts; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidInteractionsBaseTokenAmounts) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidInteractionsBaseTokenAmounts { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidInteractionsBaseTokenAmounts { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [74u8, 85u8, 218u8, 32u8]; + const SIGNATURE: &'static str = "InvalidInteractionsBaseTokenAmounts()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidInteractionsQuoteTokenAmounts()` and selector `0x77a59203`. + ```solidity + error InvalidInteractionsQuoteTokenAmounts(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidInteractionsQuoteTokenAmounts; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidInteractionsQuoteTokenAmounts) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidInteractionsQuoteTokenAmounts { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidInteractionsQuoteTokenAmounts { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [119u8, 165u8, 146u8, 3u8]; + const SIGNATURE: &'static str = "InvalidInteractionsQuoteTokenAmounts()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidLendingPoolInteraction()` and selector `0x0561d8b3`. + ```solidity + error InvalidLendingPoolInteraction(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidLendingPoolInteraction; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidLendingPoolInteraction) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidLendingPoolInteraction { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidLendingPoolInteraction { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [5u8, 97u8, 216u8, 179u8]; + const SIGNATURE: &'static str = "InvalidLendingPoolInteraction()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidQuoteTokenAmounts()` and selector `0x877630be`. + ```solidity + error InvalidQuoteTokenAmounts(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidQuoteTokenAmounts; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidQuoteTokenAmounts) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidQuoteTokenAmounts { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidQuoteTokenAmounts { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [135u8, 118u8, 48u8, 190u8]; + const SIGNATURE: &'static str = "InvalidQuoteTokenAmounts()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidSignatureType()` and selector `0x60cd402d`. + ```solidity + error InvalidSignatureType(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidSignatureType; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidSignatureType) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidSignatureType { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidSignatureType { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [96u8, 205u8, 64u8, 45u8]; + const SIGNATURE: &'static str = "InvalidSignatureType()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidSigner()` and selector `0x815e1d64`. + ```solidity + error InvalidSigner(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidSigner; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidSigner) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidSigner { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidSigner { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [129u8, 94u8, 29u8, 100u8]; + const SIGNATURE: &'static str = "InvalidSigner()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidSource()` and selector `0x8154374b`. + ```solidity + error InvalidSource(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidSource; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidSource) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidSource { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidSource { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [129u8, 84u8, 55u8, 75u8]; + const SIGNATURE: &'static str = "InvalidSource()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `NonceInvalid()` and selector `0xbc0da7d6`. + ```solidity + error NonceInvalid(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NonceInvalid; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NonceInvalid) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NonceInvalid { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for NonceInvalid { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [188u8, 13u8, 167u8, 214u8]; + const SIGNATURE: &'static str = "NonceInvalid()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `NotMaker()` and selector `0xb331e421`. + ```solidity + error NotMaker(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NotMaker; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NotMaker) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NotMaker { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for NotMaker { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [179u8, 49u8, 228u8, 33u8]; + const SIGNATURE: &'static str = "NotMaker()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `NotSolver()` and selector `0xc139eabd`. + ```solidity + error NotSolver(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct NotSolver; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: NotSolver) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for NotSolver { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for NotSolver { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [193u8, 57u8, 234u8, 189u8]; + const SIGNATURE: &'static str = "NotSolver()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `OrderExpired()` and selector `0xc56873ba`. + ```solidity + error OrderExpired(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct OrderExpired; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: OrderExpired) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for OrderExpired { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for OrderExpired { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [197u8, 104u8, 115u8, 186u8]; + const SIGNATURE: &'static str = "OrderExpired()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `PartialFillNotSupported()` and selector `0x7d617bb3`. + ```solidity + error PartialFillNotSupported(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PartialFillNotSupported; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: PartialFillNotSupported) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for PartialFillNotSupported { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for PartialFillNotSupported { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [125u8, 97u8, 123u8, 179u8]; + const SIGNATURE: &'static str = "PartialFillNotSupported()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ReceiverNotManager()` and selector `0x79a1bff0`. + ```solidity + error ReceiverNotManager(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ReceiverNotManager; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ReceiverNotManager) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ReceiverNotManager { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ReceiverNotManager { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [121u8, 161u8, 191u8, 240u8]; + const SIGNATURE: &'static str = "ReceiverNotManager()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ReentrancyGuardReentrantCall()` and selector `0x3ee5aeb5`. + ```solidity + error ReentrancyGuardReentrantCall(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ReentrancyGuardReentrantCall; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ReentrancyGuardReentrantCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ReentrancyGuardReentrantCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ReentrancyGuardReentrantCall { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [62u8, 229u8, 174u8, 181u8]; + const SIGNATURE: &'static str = "ReentrancyGuardReentrantCall()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SafeERC20FailedOperation(address)` and selector `0x5274afe7`. + ```solidity + error SafeERC20FailedOperation(address token); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SafeERC20FailedOperation { + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SafeERC20FailedOperation) -> Self { + (value.token,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SafeERC20FailedOperation { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { token: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SafeERC20FailedOperation { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [82u8, 116u8, 175u8, 231u8]; + const SIGNATURE: &'static str = "SafeERC20FailedOperation(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.token, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SignatureIsExpired()` and selector `0x133df029`. + ```solidity + error SignatureIsExpired(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SignatureIsExpired; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SignatureIsExpired) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SignatureIsExpired { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SignatureIsExpired { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [19u8, 61u8, 240u8, 41u8]; + const SIGNATURE: &'static str = "SignatureIsExpired()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SignatureIsNotEmpty()` and selector `0x0e364efc`. + ```solidity + error SignatureIsNotEmpty(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SignatureIsNotEmpty; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SignatureIsNotEmpty) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SignatureIsNotEmpty { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SignatureIsNotEmpty { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [14u8, 54u8, 78u8, 252u8]; + const SIGNATURE: &'static str = "SignatureIsNotEmpty()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `UpdatedMakerAmountsTooLow()` and selector `0x711dbe4a`. + ```solidity + error UpdatedMakerAmountsTooLow(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct UpdatedMakerAmountsTooLow; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: UpdatedMakerAmountsTooLow) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for UpdatedMakerAmountsTooLow { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for UpdatedMakerAmountsTooLow { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [113u8, 29u8, 190u8, 74u8]; + const SIGNATURE: &'static str = "UpdatedMakerAmountsTooLow()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ZeroMakerAmount()` and selector `0xb2f300d0`. + ```solidity + error ZeroMakerAmount(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ZeroMakerAmount; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ZeroMakerAmount) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ZeroMakerAmount { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ZeroMakerAmount { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [178u8, 243u8, 0u8, 208u8]; + const SIGNATURE: &'static str = "ZeroMakerAmount()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Interaction(address,uint256,bytes4)` and selector `0xed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c2`. + ```solidity + event Interaction(address indexed target, uint256 value, bytes4 selector); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Interaction { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub selector: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Interaction { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::FixedBytes<4>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Interaction(address,uint256,bytes4)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 237u8, 153u8, 130u8, 126u8, 251u8, 55u8, 1u8, 111u8, 34u8, 117u8, 249u8, 140u8, + 75u8, 207u8, 113u8, 199u8, 85u8, 28u8, 117u8, 213u8, 158u8, 155u8, 69u8, 15u8, + 121u8, 250u8, 50u8, 230u8, 11u8, 230u8, 114u8, 194u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + target: topics.1, + value: data.0, + selector: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.value), + as alloy_sol_types::SolType>::tokenize(&self.selector), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.target.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.target, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Interaction { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Interaction> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Interaction) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `TradeOrder(string,address,address,address,address,uint256,uint256,address)` and selector `0x0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b6`. + ```solidity + event TradeOrder(string indexed rfqId, address trader, address effectiveTrader, address baseToken, address quoteToken, uint256 baseTokenAmount, uint256 quoteTokenAmount, address recipient); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct TradeOrder { + #[allow(missing_docs)] + pub rfqId: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub trader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub effectiveTrader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub baseToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub quoteToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub baseTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub quoteTokenAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for TradeOrder { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::FixedBytes<32>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "TradeOrder(string,address,address,address,address,uint256,uint256,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 15u8, 206u8, 0u8, 124u8, 56u8, 198u8, 200u8, 237u8, 158u8, 84u8, 91u8, 58u8, + 20u8, 128u8, 149u8, 118u8, 39u8, 56u8, 97u8, 143u8, 140u8, 33u8, 182u8, 115u8, + 34u8, 38u8, 19u8, 228u8, 212u8, 87u8, 52u8, 182u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + rfqId: topics.1, + trader: data.0, + effectiveTrader: data.1, + baseToken: data.2, + quoteToken: data.3, + baseTokenAmount: data.4, + quoteTokenAmount: data.5, + recipient: data.6, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.trader, + ), + ::tokenize( + &self.effectiveTrader, + ), + ::tokenize( + &self.baseToken, + ), + ::tokenize( + &self.quoteToken, + ), + as alloy_sol_types::SolType>::tokenize( + &self.baseTokenAmount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.quoteTokenAmount, + ), + ::tokenize( + &self.recipient, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.rfqId.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.rfqId); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for TradeOrder { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&TradeOrder> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &TradeOrder) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address authenticator_, address repository_, address permit2_); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub authenticator_: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub repository_: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub permit2_: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.authenticator_, value.repository_, value.permit2_) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + authenticator_: tuple.0, + repository_: tuple.1, + permit2_: tuple.2, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.authenticator_, + ), + ::tokenize( + &self.repository_, + ), + ::tokenize( + &self.permit2_, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `AUTHENTICATOR()` and selector `0xc6186181`. + ```solidity + function AUTHENTICATOR() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct AUTHENTICATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`AUTHENTICATOR()`](AUTHENTICATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct AUTHENTICATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: AUTHENTICATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for AUTHENTICATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: AUTHENTICATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for AUTHENTICATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for AUTHENTICATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [198u8, 24u8, 97u8, 129u8]; + const SIGNATURE: &'static str = "AUTHENTICATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: AUTHENTICATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: AUTHENTICATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `BALANCE_MANAGER()` and selector `0x29bcdc95`. + ```solidity + function BALANCE_MANAGER() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct BALANCE_MANAGERCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`BALANCE_MANAGER()`](BALANCE_MANAGERCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct BALANCE_MANAGERReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: BALANCE_MANAGERCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for BALANCE_MANAGERCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: BALANCE_MANAGERReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for BALANCE_MANAGERReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for BALANCE_MANAGERCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [41u8, 188u8, 220u8, 149u8]; + const SIGNATURE: &'static str = "BALANCE_MANAGER()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: BALANCE_MANAGERReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: BALANCE_MANAGERReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))` and selector `0xb11f1262`. + ```solidity + function hashSingleOrder(ILiquoriceSettlement.Single memory _order) external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct hashSingleOrderCall { + #[allow(missing_docs)] + pub _order: ::RustType, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`hashSingleOrder((string,uint256,address,address,address,address, + /// uint256,uint256,uint256,uint256,address))`](hashSingleOrderCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct hashSingleOrderReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (ILiquoriceSettlement::Single,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: hashSingleOrderCall) -> Self { + (value._order,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for hashSingleOrderCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _order: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: hashSingleOrderReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for hashSingleOrderReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for hashSingleOrderCall { + type Parameters<'a> = (ILiquoriceSettlement::Single,); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [177u8, 31u8, 18u8, 98u8]; + const SIGNATURE: &'static str = "hashSingleOrder((string,uint256,address,address,\ + address,address,uint256,uint256,uint256,uint256,\ + address))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._order, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: hashSingleOrderReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: hashSingleOrderReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes32,bytes)` and selector `0x1626ba7e`. + ```solidity + function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureCall { + #[allow(missing_docs)] + pub _hash: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub _signature: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes32,bytes)`](isValidSignatureCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureCall) -> Self { + (value._hash, value._signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _hash: tuple.0, + _signature: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignatureCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 38u8, 186u8, 126u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes32,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self._hash), + ::tokenize( + &self._signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }) + } + } + }; + #[derive()] + /**Function with signature `settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))` and selector `0xcba673a7`. + ```solidity + function settle(address _signer, uint256 _filledTakerAmount, ILiquoriceSettlement.Order memory _order, GPv2Interaction.Data[] memory _interactions, GPv2Interaction.Hooks memory _hooks, Signature.TypedSignature memory _makerSignature, Signature.TypedSignature memory _takerSignature) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settleCall { + #[allow(missing_docs)] + pub _signer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _filledTakerAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub _order: ::RustType, + #[allow(missing_docs)] + pub _interactions: alloy_sol_types::private::Vec< + ::RustType, + >, + #[allow(missing_docs)] + pub _hooks: ::RustType, + #[allow(missing_docs)] + pub _makerSignature: ::RustType, + #[allow(missing_docs)] + pub _takerSignature: ::RustType, + } + ///Container type for the return parameters of the + /// [`settle(address,uint256,(address,uint256,string,uint256,address, + /// address,uint256,address,uint256,(address,uint256,uint256,uint256, + /// uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256, + /// bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8, + /// uint8,bytes),(uint8,uint8,bytes))`](settleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settleReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ILiquoriceSettlement::Order, + alloy_sol_types::sol_data::Array, + GPv2Interaction::Hooks, + Signature::TypedSignature, + Signature::TypedSignature, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ::RustType, + alloy_sol_types::private::Vec< + ::RustType, + >, + ::RustType, + ::RustType, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settleCall) -> Self { + ( + value._signer, + value._filledTakerAmount, + value._order, + value._interactions, + value._hooks, + value._makerSignature, + value._takerSignature, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _signer: tuple.0, + _filledTakerAmount: tuple.1, + _order: tuple.2, + _interactions: tuple.3, + _hooks: tuple.4, + _makerSignature: tuple.5, + _takerSignature: tuple.6, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settleReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl settleReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for settleCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ILiquoriceSettlement::Order, + alloy_sol_types::sol_data::Array, + GPv2Interaction::Hooks, + Signature::TypedSignature, + Signature::TypedSignature, + ); + type Return = settleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [203u8, 166u8, 115u8, 167u8]; + const SIGNATURE: &'static str = + "settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,\ + address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,\ + uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],\ + (address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._signer, + ), + as alloy_sol_types::SolType>::tokenize(&self._filledTakerAmount), + ::tokenize( + &self._order, + ), + as alloy_sol_types::SolType>::tokenize(&self._interactions), + ::tokenize( + &self._hooks, + ), + ::tokenize( + &self._makerSignature, + ), + ::tokenize( + &self._takerSignature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + settleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive()] + /**Function with signature `settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))` and selector `0x9935c868`. + ```solidity + function settleSingle(address _signer, ILiquoriceSettlement.Single memory _order, Signature.TypedSignature memory _makerSignature, uint256 _filledTakerAmount, Signature.TypedSignature memory _takerSignature) external payable; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settleSingleCall { + #[allow(missing_docs)] + pub _signer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _order: ::RustType, + #[allow(missing_docs)] + pub _makerSignature: ::RustType, + #[allow(missing_docs)] + pub _filledTakerAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub _takerSignature: ::RustType, + } + ///Container type for the return parameters of the + /// [`settleSingle(address,(string,uint256,address,address,address,address, + /// uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256, + /// (uint8,uint8,bytes))`](settleSingleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct settleSingleReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + ILiquoriceSettlement::Single, + Signature::TypedSignature, + alloy_sol_types::sol_data::Uint<256>, + Signature::TypedSignature, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + ::RustType, + ::RustType, + alloy_sol_types::private::primitives::aliases::U256, + ::RustType, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settleSingleCall) -> Self { + ( + value._signer, + value._order, + value._makerSignature, + value._filledTakerAmount, + value._takerSignature, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settleSingleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _signer: tuple.0, + _order: tuple.1, + _makerSignature: tuple.2, + _filledTakerAmount: tuple.3, + _takerSignature: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: settleSingleReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for settleSingleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl settleSingleReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for settleSingleCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + ILiquoriceSettlement::Single, + Signature::TypedSignature, + alloy_sol_types::sol_data::Uint<256>, + Signature::TypedSignature, + ); + type Return = settleSingleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [153u8, 53u8, 200u8, 104u8]; + const SIGNATURE: &'static str = + "settleSingle(address,(string,uint256,address,address,address,address,uint256,\ + uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._signer, + ), + ::tokenize( + &self._order, + ), + ::tokenize( + &self._makerSignature, + ), + as alloy_sol_types::SolType>::tokenize( + &self._filledTakerAmount, + ), + ::tokenize( + &self._takerSignature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + settleSingleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`LiquoriceSettlement`](self) function calls. + #[derive(Clone)] + pub enum LiquoriceSettlementCalls { + #[allow(missing_docs)] + AUTHENTICATOR(AUTHENTICATORCall), + #[allow(missing_docs)] + BALANCE_MANAGER(BALANCE_MANAGERCall), + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + hashSingleOrder(hashSingleOrderCall), + #[allow(missing_docs)] + isValidSignature(isValidSignatureCall), + #[allow(missing_docs)] + settle(settleCall), + #[allow(missing_docs)] + settleSingle(settleSingleCall), + } + impl LiquoriceSettlementCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [22u8, 38u8, 186u8, 126u8], + [41u8, 188u8, 220u8, 149u8], + [54u8, 68u8, 229u8, 21u8], + [153u8, 53u8, 200u8, 104u8], + [177u8, 31u8, 18u8, 98u8], + [198u8, 24u8, 97u8, 129u8], + [203u8, 166u8, 115u8, 167u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(isValidSignature), + ::core::stringify!(BALANCE_MANAGER), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(settleSingle), + ::core::stringify!(hashSingleOrder), + ::core::stringify!(AUTHENTICATOR), + ::core::stringify!(settle), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for LiquoriceSettlementCalls { + const COUNT: usize = 7usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "LiquoriceSettlementCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::AUTHENTICATOR(_) => ::SELECTOR, + Self::BALANCE_MANAGER(_) => { + ::SELECTOR + } + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::hashSingleOrder(_) => { + ::SELECTOR + } + Self::isValidSignature(_) => { + ::SELECTOR + } + Self::settle(_) => ::SELECTOR, + Self::settleSingle(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn isValidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementCalls::isValidSignature) + } + isValidSignature + }, + { + fn BALANCE_MANAGER( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementCalls::BALANCE_MANAGER) + } + BALANCE_MANAGER + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn settleSingle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementCalls::settleSingle) + } + settleSingle + }, + { + fn hashSingleOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementCalls::hashSingleOrder) + } + hashSingleOrder + }, + { + fn AUTHENTICATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementCalls::AUTHENTICATOR) + } + AUTHENTICATOR + }, + { + fn settle(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementCalls::settle) + } + settle + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + LiquoriceSettlementCalls, + >] = &[ + { + fn isValidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementCalls::isValidSignature) + } + isValidSignature + }, + { + fn BALANCE_MANAGER( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementCalls::BALANCE_MANAGER) + } + BALANCE_MANAGER + }, + { + fn DOMAIN_SEPARATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementCalls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn settleSingle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementCalls::settleSingle) + } + settleSingle + }, + { + fn hashSingleOrder( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementCalls::hashSingleOrder) + } + hashSingleOrder + }, + { + fn AUTHENTICATOR( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementCalls::AUTHENTICATOR) + } + AUTHENTICATOR + }, + { + fn settle(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementCalls::settle) + } + settle + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::AUTHENTICATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::BALANCE_MANAGER(inner) => { + ::abi_encoded_size(inner) + } + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::hashSingleOrder(inner) => { + ::abi_encoded_size(inner) + } + Self::isValidSignature(inner) => { + ::abi_encoded_size(inner) + } + Self::settle(inner) => { + ::abi_encoded_size(inner) + } + Self::settleSingle(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::AUTHENTICATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::BALANCE_MANAGER(inner) => { + ::abi_encode_raw(inner, out) + } + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::hashSingleOrder(inner) => { + ::abi_encode_raw(inner, out) + } + Self::isValidSignature(inner) => { + ::abi_encode_raw(inner, out) + } + Self::settle(inner) => { + ::abi_encode_raw(inner, out) + } + Self::settleSingle(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`LiquoriceSettlement`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum LiquoriceSettlementErrors { + #[allow(missing_docs)] + ECDSAInvalidSignature(ECDSAInvalidSignature), + #[allow(missing_docs)] + ECDSAInvalidSignatureLength(ECDSAInvalidSignatureLength), + #[allow(missing_docs)] + ECDSAInvalidSignatureS(ECDSAInvalidSignatureS), + #[allow(missing_docs)] + InvalidAmount(InvalidAmount), + #[allow(missing_docs)] + InvalidAsset(InvalidAsset), + #[allow(missing_docs)] + InvalidBaseTokenAmounts(InvalidBaseTokenAmounts), + #[allow(missing_docs)] + InvalidDestination(InvalidDestination), + #[allow(missing_docs)] + InvalidEIP1271Signature(InvalidEIP1271Signature), + #[allow(missing_docs)] + InvalidEIP712Signature(InvalidEIP712Signature), + #[allow(missing_docs)] + InvalidETHSignSignature(InvalidETHSignSignature), + #[allow(missing_docs)] + InvalidFillAmount(InvalidFillAmount), + #[allow(missing_docs)] + InvalidHooksTarget(InvalidHooksTarget), + #[allow(missing_docs)] + InvalidInteractionsBaseTokenAmounts(InvalidInteractionsBaseTokenAmounts), + #[allow(missing_docs)] + InvalidInteractionsQuoteTokenAmounts(InvalidInteractionsQuoteTokenAmounts), + #[allow(missing_docs)] + InvalidLendingPoolInteraction(InvalidLendingPoolInteraction), + #[allow(missing_docs)] + InvalidQuoteTokenAmounts(InvalidQuoteTokenAmounts), + #[allow(missing_docs)] + InvalidSignatureType(InvalidSignatureType), + #[allow(missing_docs)] + InvalidSigner(InvalidSigner), + #[allow(missing_docs)] + InvalidSource(InvalidSource), + #[allow(missing_docs)] + NonceInvalid(NonceInvalid), + #[allow(missing_docs)] + NotMaker(NotMaker), + #[allow(missing_docs)] + NotSolver(NotSolver), + #[allow(missing_docs)] + OrderExpired(OrderExpired), + #[allow(missing_docs)] + PartialFillNotSupported(PartialFillNotSupported), + #[allow(missing_docs)] + ReceiverNotManager(ReceiverNotManager), + #[allow(missing_docs)] + ReentrancyGuardReentrantCall(ReentrancyGuardReentrantCall), + #[allow(missing_docs)] + SafeERC20FailedOperation(SafeERC20FailedOperation), + #[allow(missing_docs)] + SignatureIsExpired(SignatureIsExpired), + #[allow(missing_docs)] + SignatureIsNotEmpty(SignatureIsNotEmpty), + #[allow(missing_docs)] + UpdatedMakerAmountsTooLow(UpdatedMakerAmountsTooLow), + #[allow(missing_docs)] + ZeroMakerAmount(ZeroMakerAmount), + } + impl LiquoriceSettlementErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [5u8, 97u8, 216u8, 179u8], + [14u8, 54u8, 78u8, 252u8], + [19u8, 61u8, 240u8, 41u8], + [44u8, 82u8, 17u8, 198u8], + [62u8, 229u8, 174u8, 181u8], + [74u8, 85u8, 218u8, 32u8], + [82u8, 116u8, 175u8, 231u8], + [93u8, 82u8, 203u8, 227u8], + [96u8, 205u8, 64u8, 45u8], + [100u8, 74u8, 230u8, 195u8], + [113u8, 29u8, 190u8, 74u8], + [119u8, 165u8, 146u8, 3u8], + [121u8, 161u8, 191u8, 240u8], + [125u8, 97u8, 123u8, 179u8], + [129u8, 84u8, 55u8, 75u8], + [129u8, 94u8, 29u8, 100u8], + [135u8, 118u8, 48u8, 190u8], + [148u8, 105u8, 116u8, 68u8], + [172u8, 107u8, 5u8, 245u8], + [178u8, 243u8, 0u8, 208u8], + [179u8, 49u8, 228u8, 33u8], + [184u8, 29u8, 88u8, 231u8], + [188u8, 13u8, 167u8, 214u8], + [192u8, 67u8, 119u8, 211u8], + [193u8, 57u8, 234u8, 189u8], + [197u8, 104u8, 115u8, 186u8], + [200u8, 145u8, 173u8, 210u8], + [201u8, 158u8, 136u8, 114u8], + [215u8, 139u8, 206u8, 12u8], + [246u8, 69u8, 238u8, 223u8], + [252u8, 230u8, 152u8, 247u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(InvalidLendingPoolInteraction), + ::core::stringify!(SignatureIsNotEmpty), + ::core::stringify!(SignatureIsExpired), + ::core::stringify!(InvalidAmount), + ::core::stringify!(ReentrancyGuardReentrantCall), + ::core::stringify!(InvalidInteractionsBaseTokenAmounts), + ::core::stringify!(SafeERC20FailedOperation), + ::core::stringify!(InvalidEIP1271Signature), + ::core::stringify!(InvalidSignatureType), + ::core::stringify!(InvalidETHSignSignature), + ::core::stringify!(UpdatedMakerAmountsTooLow), + ::core::stringify!(InvalidInteractionsQuoteTokenAmounts), + ::core::stringify!(ReceiverNotManager), + ::core::stringify!(PartialFillNotSupported), + ::core::stringify!(InvalidSource), + ::core::stringify!(InvalidSigner), + ::core::stringify!(InvalidQuoteTokenAmounts), + ::core::stringify!(InvalidFillAmount), + ::core::stringify!(InvalidDestination), + ::core::stringify!(ZeroMakerAmount), + ::core::stringify!(NotMaker), + ::core::stringify!(InvalidEIP712Signature), + ::core::stringify!(NonceInvalid), + ::core::stringify!(InvalidBaseTokenAmounts), + ::core::stringify!(NotSolver), + ::core::stringify!(OrderExpired), + ::core::stringify!(InvalidAsset), + ::core::stringify!(InvalidHooksTarget), + ::core::stringify!(ECDSAInvalidSignatureS), + ::core::stringify!(ECDSAInvalidSignature), + ::core::stringify!(ECDSAInvalidSignatureLength), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for LiquoriceSettlementErrors { + const COUNT: usize = 31usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "LiquoriceSettlementErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::ECDSAInvalidSignature(_) => { + ::SELECTOR + } + Self::ECDSAInvalidSignatureLength(_) => { + ::SELECTOR + } + Self::ECDSAInvalidSignatureS(_) => { + ::SELECTOR + } + Self::InvalidAmount(_) => ::SELECTOR, + Self::InvalidAsset(_) => ::SELECTOR, + Self::InvalidBaseTokenAmounts(_) => { + ::SELECTOR + } + Self::InvalidDestination(_) => { + ::SELECTOR + } + Self::InvalidEIP1271Signature(_) => { + ::SELECTOR + } + Self::InvalidEIP712Signature(_) => { + ::SELECTOR + } + Self::InvalidETHSignSignature(_) => { + ::SELECTOR + } + Self::InvalidFillAmount(_) => { + ::SELECTOR + } + Self::InvalidHooksTarget(_) => { + ::SELECTOR + } + Self::InvalidInteractionsBaseTokenAmounts(_) => { + ::SELECTOR + } + Self::InvalidInteractionsQuoteTokenAmounts(_) => { + ::SELECTOR + } + Self::InvalidLendingPoolInteraction(_) => { + ::SELECTOR + } + Self::InvalidQuoteTokenAmounts(_) => { + ::SELECTOR + } + Self::InvalidSignatureType(_) => { + ::SELECTOR + } + Self::InvalidSigner(_) => ::SELECTOR, + Self::InvalidSource(_) => ::SELECTOR, + Self::NonceInvalid(_) => ::SELECTOR, + Self::NotMaker(_) => ::SELECTOR, + Self::NotSolver(_) => ::SELECTOR, + Self::OrderExpired(_) => ::SELECTOR, + Self::PartialFillNotSupported(_) => { + ::SELECTOR + } + Self::ReceiverNotManager(_) => { + ::SELECTOR + } + Self::ReentrancyGuardReentrantCall(_) => { + ::SELECTOR + } + Self::SafeERC20FailedOperation(_) => { + ::SELECTOR + } + Self::SignatureIsExpired(_) => { + ::SELECTOR + } + Self::SignatureIsNotEmpty(_) => { + ::SELECTOR + } + Self::UpdatedMakerAmountsTooLow(_) => { + ::SELECTOR + } + Self::ZeroMakerAmount(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn InvalidLendingPoolInteraction( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map( + LiquoriceSettlementErrors::InvalidLendingPoolInteraction, + ) + } + InvalidLendingPoolInteraction + }, + { + fn SignatureIsNotEmpty( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::SignatureIsNotEmpty) + } + SignatureIsNotEmpty + }, + { + fn SignatureIsExpired( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::SignatureIsExpired) + } + SignatureIsExpired + }, + { + fn InvalidAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidAmount) + } + InvalidAmount + }, + { + fn ReentrancyGuardReentrantCall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(LiquoriceSettlementErrors::ReentrancyGuardReentrantCall) + } + ReentrancyGuardReentrantCall + }, + { + fn InvalidInteractionsBaseTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map( + LiquoriceSettlementErrors::InvalidInteractionsBaseTokenAmounts, + ) + } + InvalidInteractionsBaseTokenAmounts + }, + { + fn SafeERC20FailedOperation( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(LiquoriceSettlementErrors::SafeERC20FailedOperation) + } + SafeERC20FailedOperation + }, + { + fn InvalidEIP1271Signature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidEIP1271Signature) + } + InvalidEIP1271Signature + }, + { + fn InvalidSignatureType( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidSignatureType) + } + InvalidSignatureType + }, + { + fn InvalidETHSignSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidETHSignSignature) + } + InvalidETHSignSignature + }, + { + fn UpdatedMakerAmountsTooLow( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(LiquoriceSettlementErrors::UpdatedMakerAmountsTooLow) + } + UpdatedMakerAmountsTooLow + }, + { + fn InvalidInteractionsQuoteTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map( + LiquoriceSettlementErrors::InvalidInteractionsQuoteTokenAmounts, + ) + } + InvalidInteractionsQuoteTokenAmounts + }, + { + fn ReceiverNotManager( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::ReceiverNotManager) + } + ReceiverNotManager + }, + { + fn PartialFillNotSupported( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::PartialFillNotSupported) + } + PartialFillNotSupported + }, + { + fn InvalidSource( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidSource) + } + InvalidSource + }, + { + fn InvalidSigner( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidSigner) + } + InvalidSigner + }, + { + fn InvalidQuoteTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(LiquoriceSettlementErrors::InvalidQuoteTokenAmounts) + } + InvalidQuoteTokenAmounts + }, + { + fn InvalidFillAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidFillAmount) + } + InvalidFillAmount + }, + { + fn InvalidDestination( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidDestination) + } + InvalidDestination + }, + { + fn ZeroMakerAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::ZeroMakerAmount) + } + ZeroMakerAmount + }, + { + fn NotMaker(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::NotMaker) + } + NotMaker + }, + { + fn InvalidEIP712Signature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidEIP712Signature) + } + InvalidEIP712Signature + }, + { + fn NonceInvalid( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::NonceInvalid) + } + NonceInvalid + }, + { + fn InvalidBaseTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidBaseTokenAmounts) + } + InvalidBaseTokenAmounts + }, + { + fn NotSolver( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::NotSolver) + } + NotSolver + }, + { + fn OrderExpired( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::OrderExpired) + } + OrderExpired + }, + { + fn InvalidAsset( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidAsset) + } + InvalidAsset + }, + { + fn InvalidHooksTarget( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::InvalidHooksTarget) + } + InvalidHooksTarget + }, + { + fn ECDSAInvalidSignatureS( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::ECDSAInvalidSignatureS) + } + ECDSAInvalidSignatureS + }, + { + fn ECDSAInvalidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(LiquoriceSettlementErrors::ECDSAInvalidSignature) + } + ECDSAInvalidSignature + }, + { + fn ECDSAInvalidSignatureLength( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(LiquoriceSettlementErrors::ECDSAInvalidSignatureLength) + } + ECDSAInvalidSignatureLength + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + LiquoriceSettlementErrors, + >] = &[ + { + fn InvalidLendingPoolInteraction( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map( + LiquoriceSettlementErrors::InvalidLendingPoolInteraction, + ) + } + InvalidLendingPoolInteraction + }, + { + fn SignatureIsNotEmpty( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::SignatureIsNotEmpty) + } + SignatureIsNotEmpty + }, + { + fn SignatureIsExpired( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::SignatureIsExpired) + } + SignatureIsExpired + }, + { + fn InvalidAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::InvalidAmount) + } + InvalidAmount + }, + { + fn ReentrancyGuardReentrantCall( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::ReentrancyGuardReentrantCall) + } + ReentrancyGuardReentrantCall + }, + { + fn InvalidInteractionsBaseTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map( + LiquoriceSettlementErrors::InvalidInteractionsBaseTokenAmounts, + ) + } + InvalidInteractionsBaseTokenAmounts + }, + { + fn SafeERC20FailedOperation( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::SafeERC20FailedOperation) + } + SafeERC20FailedOperation + }, + { + fn InvalidEIP1271Signature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidEIP1271Signature) + } + InvalidEIP1271Signature + }, + { + fn InvalidSignatureType( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidSignatureType) + } + InvalidSignatureType + }, + { + fn InvalidETHSignSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidETHSignSignature) + } + InvalidETHSignSignature + }, + { + fn UpdatedMakerAmountsTooLow( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::UpdatedMakerAmountsTooLow) + } + UpdatedMakerAmountsTooLow + }, + { + fn InvalidInteractionsQuoteTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map( + LiquoriceSettlementErrors::InvalidInteractionsQuoteTokenAmounts, + ) + } + InvalidInteractionsQuoteTokenAmounts + }, + { + fn ReceiverNotManager( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::ReceiverNotManager) + } + ReceiverNotManager + }, + { + fn PartialFillNotSupported( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::PartialFillNotSupported) + } + PartialFillNotSupported + }, + { + fn InvalidSource( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::InvalidSource) + } + InvalidSource + }, + { + fn InvalidSigner( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::InvalidSigner) + } + InvalidSigner + }, + { + fn InvalidQuoteTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidQuoteTokenAmounts) + } + InvalidQuoteTokenAmounts + }, + { + fn InvalidFillAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidFillAmount) + } + InvalidFillAmount + }, + { + fn InvalidDestination( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidDestination) + } + InvalidDestination + }, + { + fn ZeroMakerAmount( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::ZeroMakerAmount) + } + ZeroMakerAmount + }, + { + fn NotMaker(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::NotMaker) + } + NotMaker + }, + { + fn InvalidEIP712Signature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidEIP712Signature) + } + InvalidEIP712Signature + }, + { + fn NonceInvalid( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::NonceInvalid) + } + NonceInvalid + }, + { + fn InvalidBaseTokenAmounts( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidBaseTokenAmounts) + } + InvalidBaseTokenAmounts + }, + { + fn NotSolver( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::NotSolver) + } + NotSolver + }, + { + fn OrderExpired( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::OrderExpired) + } + OrderExpired + }, + { + fn InvalidAsset( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(LiquoriceSettlementErrors::InvalidAsset) + } + InvalidAsset + }, + { + fn InvalidHooksTarget( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::InvalidHooksTarget) + } + InvalidHooksTarget + }, + { + fn ECDSAInvalidSignatureS( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::ECDSAInvalidSignatureS) + } + ECDSAInvalidSignatureS + }, + { + fn ECDSAInvalidSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::ECDSAInvalidSignature) + } + ECDSAInvalidSignature + }, + { + fn ECDSAInvalidSignatureLength( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(LiquoriceSettlementErrors::ECDSAInvalidSignatureLength) + } + ECDSAInvalidSignatureLength + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::ECDSAInvalidSignature(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::ECDSAInvalidSignatureLength(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::ECDSAInvalidSignatureS(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidAmount(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidAsset(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidBaseTokenAmounts(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidDestination(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidEIP1271Signature(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidEIP712Signature(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidETHSignSignature(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidFillAmount(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidHooksTarget(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidInteractionsBaseTokenAmounts(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidInteractionsQuoteTokenAmounts(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidLendingPoolInteraction(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidQuoteTokenAmounts(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidSignatureType(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::InvalidSigner(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidSource(inner) => { + ::abi_encoded_size(inner) + } + Self::NonceInvalid(inner) => { + ::abi_encoded_size(inner) + } + Self::NotMaker(inner) => { + ::abi_encoded_size(inner) + } + Self::NotSolver(inner) => { + ::abi_encoded_size(inner) + } + Self::OrderExpired(inner) => { + ::abi_encoded_size(inner) + } + Self::PartialFillNotSupported(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::ReceiverNotManager(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::ReentrancyGuardReentrantCall(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::SafeERC20FailedOperation(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::SignatureIsExpired(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::SignatureIsNotEmpty(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::UpdatedMakerAmountsTooLow(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::ZeroMakerAmount(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::ECDSAInvalidSignature(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::ECDSAInvalidSignatureLength(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::ECDSAInvalidSignatureS(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidAmount(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidAsset(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidBaseTokenAmounts(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidDestination(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidEIP1271Signature(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidEIP712Signature(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidETHSignSignature(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidFillAmount(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidHooksTarget(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidInteractionsBaseTokenAmounts(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidInteractionsQuoteTokenAmounts(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidLendingPoolInteraction(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidQuoteTokenAmounts(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidSignatureType(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidSigner(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::InvalidSource(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::NonceInvalid(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::NotMaker(inner) => { + ::abi_encode_raw(inner, out) + } + Self::NotSolver(inner) => { + ::abi_encode_raw(inner, out) + } + Self::OrderExpired(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::PartialFillNotSupported(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::ReceiverNotManager(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::ReentrancyGuardReentrantCall(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::SafeERC20FailedOperation(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::SignatureIsExpired(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::SignatureIsNotEmpty(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::UpdatedMakerAmountsTooLow(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::ZeroMakerAmount(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + } + } + } + ///Container for all the [`LiquoriceSettlement`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum LiquoriceSettlementEvents { + #[allow(missing_docs)] + Interaction(Interaction), + #[allow(missing_docs)] + TradeOrder(TradeOrder), + } + impl LiquoriceSettlementEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 15u8, 206u8, 0u8, 124u8, 56u8, 198u8, 200u8, 237u8, 158u8, 84u8, 91u8, 58u8, 20u8, + 128u8, 149u8, 118u8, 39u8, 56u8, 97u8, 143u8, 140u8, 33u8, 182u8, 115u8, 34u8, + 38u8, 19u8, 228u8, 212u8, 87u8, 52u8, 182u8, + ], + [ + 237u8, 153u8, 130u8, 126u8, 251u8, 55u8, 1u8, 111u8, 34u8, 117u8, 249u8, 140u8, + 75u8, 207u8, 113u8, 199u8, 85u8, 28u8, 117u8, 213u8, 158u8, 155u8, 69u8, 15u8, + 121u8, 250u8, 50u8, 230u8, 11u8, 230u8, 114u8, 194u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(TradeOrder), + ::core::stringify!(Interaction), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for LiquoriceSettlementEvents { + const COUNT: usize = 2usize; + const NAME: &'static str = "LiquoriceSettlementEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Interaction) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::TradeOrder) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for LiquoriceSettlementEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Interaction(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::TradeOrder(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Interaction(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::TradeOrder(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`LiquoriceSettlement`](self) contract instance. + + See the [wrapper's documentation](`LiquoriceSettlementInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> LiquoriceSettlementInstance { + LiquoriceSettlementInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + repository_: alloy_sol_types::private::Address, + permit2_: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + LiquoriceSettlementInstance::::deploy( + __provider, + authenticator_, + repository_, + permit2_, + ) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + repository_: alloy_sol_types::private::Address, + permit2_: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + LiquoriceSettlementInstance::::deploy_builder( + __provider, + authenticator_, + repository_, + permit2_, + ) + } + /**A [`LiquoriceSettlement`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`LiquoriceSettlement`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct LiquoriceSettlementInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for LiquoriceSettlementInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("LiquoriceSettlementInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + LiquoriceSettlementInstance + { + /**Creates a new wrapper around an on-chain [`LiquoriceSettlement`](self) contract instance. + + See the [wrapper's documentation](`LiquoriceSettlementInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + repository_: alloy_sol_types::private::Address, + permit2_: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = + Self::deploy_builder(__provider, authenticator_, repository_, permit2_); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + authenticator_: alloy_sol_types::private::Address, + repository_: alloy_sol_types::private::Address, + permit2_: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + authenticator_, + repository_, + permit2_, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl LiquoriceSettlementInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> LiquoriceSettlementInstance { + LiquoriceSettlementInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + LiquoriceSettlementInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`AUTHENTICATOR`] function. + pub fn AUTHENTICATOR(&self) -> alloy_contract::SolCallBuilder<&P, AUTHENTICATORCall, N> { + self.call_builder(&AUTHENTICATORCall) + } + + ///Creates a new call builder for the [`BALANCE_MANAGER`] function. + pub fn BALANCE_MANAGER( + &self, + ) -> alloy_contract::SolCallBuilder<&P, BALANCE_MANAGERCall, N> { + self.call_builder(&BALANCE_MANAGERCall) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`hashSingleOrder`] function. + pub fn hashSingleOrder( + &self, + _order: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, hashSingleOrderCall, N> { + self.call_builder(&hashSingleOrderCall { _order }) + } + + ///Creates a new call builder for the [`isValidSignature`] function. + pub fn isValidSignature( + &self, + _hash: alloy_sol_types::private::FixedBytes<32>, + _signature: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignatureCall, N> { + self.call_builder(&isValidSignatureCall { _hash, _signature }) + } + + ///Creates a new call builder for the [`settle`] function. + pub fn settle( + &self, + _signer: alloy_sol_types::private::Address, + _filledTakerAmount: alloy_sol_types::private::primitives::aliases::U256, + _order: ::RustType, + _interactions: alloy_sol_types::private::Vec< + ::RustType, + >, + _hooks: ::RustType, + _makerSignature: ::RustType, + _takerSignature: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, settleCall, N> { + self.call_builder(&settleCall { + _signer, + _filledTakerAmount, + _order, + _interactions, + _hooks, + _makerSignature, + _takerSignature, + }) + } + + ///Creates a new call builder for the [`settleSingle`] function. + pub fn settleSingle( + &self, + _signer: alloy_sol_types::private::Address, + _order: ::RustType, + _makerSignature: ::RustType, + _filledTakerAmount: alloy_sol_types::private::primitives::aliases::U256, + _takerSignature: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, settleSingleCall, N> { + self.call_builder(&settleSingleCall { + _signer, + _order, + _makerSignature, + _filledTakerAmount, + _takerSignature, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + LiquoriceSettlementInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Interaction`] event. + pub fn Interaction_filter(&self) -> alloy_contract::Event<&P, Interaction, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`TradeOrder`] event. + pub fn TradeOrder_filter(&self) -> alloy_contract::Event<&P, TradeOrder, N> { + self.event_filter::() + } + } +} +pub type Instance = LiquoriceSettlement::LiquoriceSettlementInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x0448633eb8B0A42EfED924C42069E0DcF08fb552"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x0448633eb8B0A42EfED924C42069E0DcF08fb552"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/mockerc4626wrapper/Cargo.toml b/contracts/generated/contracts-generated/mockerc4626wrapper/Cargo.toml new file mode 100644 index 0000000000..77ca06c21e --- /dev/null +++ b/contracts/generated/contracts-generated/mockerc4626wrapper/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-mockerc4626wrapper" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/mockerc4626wrapper/src/lib.rs b/contracts/generated/contracts-generated/mockerc4626wrapper/src/lib.rs new file mode 100644 index 0000000000..33f38b216f --- /dev/null +++ b/contracts/generated/contracts-generated/mockerc4626wrapper/src/lib.rs @@ -0,0 +1,2768 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface MockERC4626Wrapper { + constructor(address _asset, uint8 _decimals, uint256 _rateNumerator, uint256 _rateDenominator); + + function allowance(address, address) external view returns (uint256); + function approve(address spender, uint256 amount) external returns (bool); + function asset() external view returns (address); + function balanceOf(address) external view returns (uint256); + function convertToAssets(uint256 shares) external view returns (uint256); + function decimals() external view returns (uint8); + function mint(address to, uint256 amount) external; + function rateDenominator() external view returns (uint256); + function rateNumerator() external view returns (uint256); + function transfer(address to, uint256 amount) external returns (bool); + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_asset", + "type": "address", + "internalType": "address" + }, + { + "name": "_decimals", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "_rateNumerator", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_rateDenominator", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "asset", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "convertToAssets", + "inputs": [ + { + "name": "shares", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rateDenominator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "rateNumerator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod MockERC4626Wrapper { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x610100604052348015610010575f5ffd5b50604051610c17380380610c1783398181016040528101906100329190610154565b8373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508260ff1660a08160ff16815250508160c081815250508060e08181525050505050506101b8565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100ba82610091565b9050919050565b6100ca816100b0565b81146100d4575f5ffd5b50565b5f815190506100e5816100c1565b92915050565b5f60ff82169050919050565b610100816100eb565b811461010a575f5ffd5b50565b5f8151905061011b816100f7565b92915050565b5f819050919050565b61013381610121565b811461013d575f5ffd5b50565b5f8151905061014e8161012a565b92915050565b5f5f5f5f6080858703121561016c5761016b61008d565b5b5f610179878288016100d7565b945050602061018a8782880161010d565b935050604061019b87828801610140565b92505060606101ac87828801610140565b91505092959194509250565b60805160a05160c05160e051610a1e6101f95f395f8181610262015261055c01525f8181610283015261034801525f6104aa01525f6104ce0152610a1e5ff3fe608060405234801561000f575f5ffd5b50600436106100a7575f3560e01c806338d52e0f1161006f57806338d52e0f1461017757806340c10f191461019557806370a08231146101b1578063865192f7146101e1578063a9059cbb146101ff578063dd62ed3e1461022f576100a7565b806307a2d13a146100ab578063095ea7b3146100db5780630b36b8db1461010b57806323b872dd14610129578063313ce56714610159575b5f5ffd5b6100c560048036038101906100c09190610684565b61025f565b6040516100d291906106be565b60405180910390f35b6100f560048036038101906100f09190610731565b6102be565b6040516101029190610789565b60405180910390f35b610113610346565b60405161012091906106be565b60405180910390f35b610143600480360381019061013e91906107a2565b61036a565b6040516101509190610789565b60405180910390f35b6101616104a8565b60405161016e919061080d565b60405180910390f35b61017f6104cc565b60405161018c9190610835565b60405180910390f35b6101af60048036038101906101aa9190610731565b6104f0565b005b6101cb60048036038101906101c6919061084e565b610546565b6040516101d891906106be565b60405180910390f35b6101e961055a565b6040516101f691906106be565b60405180910390f35b61021960048036038101906102149190610731565b61057e565b6040516102269190610789565b60405180910390f35b61024960048036038101906102449190610879565b61062d565b60405161025691906106be565b60405180910390f35b5f7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836102ad91906108e4565b6102b79190610952565b9050919050565b5f8160015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055506001905092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546103f29190610982565b92505081905550815f5f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546104449190610982565b92505081905550815f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461049691906109b5565b92505081905550600190509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461053b91906109b5565b925050819055505050565b5f602052805f5260405f205f915090505481565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f815f5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ca9190610982565b92505081905550815f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461061c91906109b5565b925050819055506001905092915050565b6001602052815f5260405f20602052805f5260405f205f91509150505481565b5f5ffd5b5f819050919050565b61066381610651565b811461066d575f5ffd5b50565b5f8135905061067e8161065a565b92915050565b5f602082840312156106995761069861064d565b5b5f6106a684828501610670565b91505092915050565b6106b881610651565b82525050565b5f6020820190506106d15f8301846106af565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610700826106d7565b9050919050565b610710816106f6565b811461071a575f5ffd5b50565b5f8135905061072b81610707565b92915050565b5f5f604083850312156107475761074661064d565b5b5f6107548582860161071d565b925050602061076585828601610670565b9150509250929050565b5f8115159050919050565b6107838161076f565b82525050565b5f60208201905061079c5f83018461077a565b92915050565b5f5f5f606084860312156107b9576107b861064d565b5b5f6107c68682870161071d565b93505060206107d78682870161071d565b92505060406107e886828701610670565b9150509250925092565b5f60ff82169050919050565b610807816107f2565b82525050565b5f6020820190506108205f8301846107fe565b92915050565b61082f816106f6565b82525050565b5f6020820190506108485f830184610826565b92915050565b5f602082840312156108635761086261064d565b5b5f6108708482850161071d565b91505092915050565b5f5f6040838503121561088f5761088e61064d565b5b5f61089c8582860161071d565b92505060206108ad8582860161071d565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6108ee82610651565b91506108f983610651565b925082820261090781610651565b9150828204841483151761091e5761091d6108b7565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61095c82610651565b915061096783610651565b92508261097757610976610925565b5b828204905092915050565b5f61098c82610651565b915061099783610651565b92508282039050818111156109af576109ae6108b7565b5b92915050565b5f6109bf82610651565b91506109ca83610651565b92508282019050808211156109e2576109e16108b7565b5b9291505056fea2646970667358221220b5ebafab2270a2c41eb9cd473eb8aca958511fe12b7302559d197e2a8704c94b64736f6c634300081e0033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01\0`@R4\x80\x15a\0\x10W__\xFD[P`@Qa\x0C\x178\x03\x80a\x0C\x17\x839\x81\x81\x01`@R\x81\x01\x90a\x002\x91\x90a\x01TV[\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\x80\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81RPP\x82`\xFF\x16`\xA0\x81`\xFF\x16\x81RPP\x81`\xC0\x81\x81RPP\x80`\xE0\x81\x81RPPPPPPa\x01\xB8V[__\xFD[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90P\x91\x90PV[_a\0\xBA\x82a\0\x91V[\x90P\x91\x90PV[a\0\xCA\x81a\0\xB0V[\x81\x14a\0\xD4W__\xFD[PV[_\x81Q\x90Pa\0\xE5\x81a\0\xC1V[\x92\x91PPV[_`\xFF\x82\x16\x90P\x91\x90PV[a\x01\0\x81a\0\xEBV[\x81\x14a\x01\nW__\xFD[PV[_\x81Q\x90Pa\x01\x1B\x81a\0\xF7V[\x92\x91PPV[_\x81\x90P\x91\x90PV[a\x013\x81a\x01!V[\x81\x14a\x01=W__\xFD[PV[_\x81Q\x90Pa\x01N\x81a\x01*V[\x92\x91PPV[____`\x80\x85\x87\x03\x12\x15a\x01lWa\x01ka\0\x8DV[[_a\x01y\x87\x82\x88\x01a\0\xD7V[\x94PP` a\x01\x8A\x87\x82\x88\x01a\x01\rV[\x93PP`@a\x01\x9B\x87\x82\x88\x01a\x01@V[\x92PP``a\x01\xAC\x87\x82\x88\x01a\x01@V[\x91PP\x92\x95\x91\x94P\x92PV[`\x80Q`\xA0Q`\xC0Q`\xE0Qa\n\x1Ea\x01\xF9_9_\x81\x81a\x02b\x01Ra\x05\\\x01R_\x81\x81a\x02\x83\x01Ra\x03H\x01R_a\x04\xAA\x01R_a\x04\xCE\x01Ra\n\x1E_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0\xA7W_5`\xE0\x1C\x80c8\xD5.\x0F\x11a\0oW\x80c8\xD5.\x0F\x14a\x01wW\x80c@\xC1\x0F\x19\x14a\x01\x95W\x80cp\xA0\x821\x14a\x01\xB1W\x80c\x86Q\x92\xF7\x14a\x01\xE1W\x80c\xA9\x05\x9C\xBB\x14a\x01\xFFW\x80c\xDDb\xED>\x14a\x02/Wa\0\xA7V[\x80c\x07\xA2\xD1:\x14a\0\xABW\x80c\t^\xA7\xB3\x14a\0\xDBW\x80c\x0B6\xB8\xDB\x14a\x01\x0BW\x80c#\xB8r\xDD\x14a\x01)W\x80c1<\xE5g\x14a\x01YW[__\xFD[a\0\xC5`\x04\x806\x03\x81\x01\x90a\0\xC0\x91\x90a\x06\x84V[a\x02_V[`@Qa\0\xD2\x91\x90a\x06\xBEV[`@Q\x80\x91\x03\x90\xF3[a\0\xF5`\x04\x806\x03\x81\x01\x90a\0\xF0\x91\x90a\x071V[a\x02\xBEV[`@Qa\x01\x02\x91\x90a\x07\x89V[`@Q\x80\x91\x03\x90\xF3[a\x01\x13a\x03FV[`@Qa\x01 \x91\x90a\x06\xBEV[`@Q\x80\x91\x03\x90\xF3[a\x01C`\x04\x806\x03\x81\x01\x90a\x01>\x91\x90a\x07\xA2V[a\x03jV[`@Qa\x01P\x91\x90a\x07\x89V[`@Q\x80\x91\x03\x90\xF3[a\x01aa\x04\xA8V[`@Qa\x01n\x91\x90a\x08\rV[`@Q\x80\x91\x03\x90\xF3[a\x01\x7Fa\x04\xCCV[`@Qa\x01\x8C\x91\x90a\x085V[`@Q\x80\x91\x03\x90\xF3[a\x01\xAF`\x04\x806\x03\x81\x01\x90a\x01\xAA\x91\x90a\x071V[a\x04\xF0V[\0[a\x01\xCB`\x04\x806\x03\x81\x01\x90a\x01\xC6\x91\x90a\x08NV[a\x05FV[`@Qa\x01\xD8\x91\x90a\x06\xBEV[`@Q\x80\x91\x03\x90\xF3[a\x01\xE9a\x05ZV[`@Qa\x01\xF6\x91\x90a\x06\xBEV[`@Q\x80\x91\x03\x90\xF3[a\x02\x19`\x04\x806\x03\x81\x01\x90a\x02\x14\x91\x90a\x071V[a\x05~V[`@Qa\x02&\x91\x90a\x07\x89V[`@Q\x80\x91\x03\x90\xF3[a\x02I`\x04\x806\x03\x81\x01\x90a\x02D\x91\x90a\x08yV[a\x06-V[`@Qa\x02V\x91\x90a\x06\xBEV[`@Q\x80\x91\x03\x90\xF3[_\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83a\x02\xAD\x91\x90a\x08\xE4V[a\x02\xB7\x91\x90a\tRV[\x90P\x91\x90PV[_\x81`\x01_3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ \x81\x90UP`\x01\x90P\x92\x91PPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[_\x81`\x01_\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _\x82\x82Ta\x03\xF2\x91\x90a\t\x82V[\x92PP\x81\x90UP\x81__\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _\x82\x82Ta\x04D\x91\x90a\t\x82V[\x92PP\x81\x90UP\x81__\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _\x82\x82Ta\x04\x96\x91\x90a\t\xB5V[\x92PP\x81\x90UP`\x01\x90P\x93\x92PPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[\x80__\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _\x82\x82Ta\x05;\x91\x90a\t\xB5V[\x92PP\x81\x90UPPPV[_` R\x80_R`@_ _\x91P\x90PT\x81V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[_\x81__3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _\x82\x82Ta\x05\xCA\x91\x90a\t\x82V[\x92PP\x81\x90UP\x81__\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01_ _\x82\x82Ta\x06\x1C\x91\x90a\t\xB5V[\x92PP\x81\x90UP`\x01\x90P\x92\x91PPV[`\x01` R\x81_R`@_ ` R\x80_R`@_ _\x91P\x91PPT\x81V[__\xFD[_\x81\x90P\x91\x90PV[a\x06c\x81a\x06QV[\x81\x14a\x06mW__\xFD[PV[_\x815\x90Pa\x06~\x81a\x06ZV[\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x06\x99Wa\x06\x98a\x06MV[[_a\x06\xA6\x84\x82\x85\x01a\x06pV[\x91PP\x92\x91PPV[a\x06\xB8\x81a\x06QV[\x82RPPV[_` \x82\x01\x90Pa\x06\xD1_\x83\x01\x84a\x06\xAFV[\x92\x91PPV[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90P\x91\x90PV[_a\x07\0\x82a\x06\xD7V[\x90P\x91\x90PV[a\x07\x10\x81a\x06\xF6V[\x81\x14a\x07\x1AW__\xFD[PV[_\x815\x90Pa\x07+\x81a\x07\x07V[\x92\x91PPV[__`@\x83\x85\x03\x12\x15a\x07GWa\x07Fa\x06MV[[_a\x07T\x85\x82\x86\x01a\x07\x1DV[\x92PP` a\x07e\x85\x82\x86\x01a\x06pV[\x91PP\x92P\x92\x90PV[_\x81\x15\x15\x90P\x91\x90PV[a\x07\x83\x81a\x07oV[\x82RPPV[_` \x82\x01\x90Pa\x07\x9C_\x83\x01\x84a\x07zV[\x92\x91PPV[___``\x84\x86\x03\x12\x15a\x07\xB9Wa\x07\xB8a\x06MV[[_a\x07\xC6\x86\x82\x87\x01a\x07\x1DV[\x93PP` a\x07\xD7\x86\x82\x87\x01a\x07\x1DV[\x92PP`@a\x07\xE8\x86\x82\x87\x01a\x06pV[\x91PP\x92P\x92P\x92V[_`\xFF\x82\x16\x90P\x91\x90PV[a\x08\x07\x81a\x07\xF2V[\x82RPPV[_` \x82\x01\x90Pa\x08 _\x83\x01\x84a\x07\xFEV[\x92\x91PPV[a\x08/\x81a\x06\xF6V[\x82RPPV[_` \x82\x01\x90Pa\x08H_\x83\x01\x84a\x08&V[\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x08cWa\x08ba\x06MV[[_a\x08p\x84\x82\x85\x01a\x07\x1DV[\x91PP\x92\x91PPV[__`@\x83\x85\x03\x12\x15a\x08\x8FWa\x08\x8Ea\x06MV[[_a\x08\x9C\x85\x82\x86\x01a\x07\x1DV[\x92PP` a\x08\xAD\x85\x82\x86\x01a\x07\x1DV[\x91PP\x92P\x92\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[_a\x08\xEE\x82a\x06QV[\x91Pa\x08\xF9\x83a\x06QV[\x92P\x82\x82\x02a\t\x07\x81a\x06QV[\x91P\x82\x82\x04\x84\x14\x83\x15\x17a\t\x1EWa\t\x1Da\x08\xB7V[[P\x92\x91PPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x12`\x04R`$_\xFD[_a\t\\\x82a\x06QV[\x91Pa\tg\x83a\x06QV[\x92P\x82a\twWa\tva\t%V[[\x82\x82\x04\x90P\x92\x91PPV[_a\t\x8C\x82a\x06QV[\x91Pa\t\x97\x83a\x06QV[\x92P\x82\x82\x03\x90P\x81\x81\x11\x15a\t\xAFWa\t\xAEa\x08\xB7V[[\x92\x91PPV[_a\t\xBF\x82a\x06QV[\x91Pa\t\xCA\x83a\x06QV[\x92P\x82\x82\x01\x90P\x80\x82\x11\x15a\t\xE2Wa\t\xE1a\x08\xB7V[[\x92\x91PPV\xFE\xA2dipfsX\"\x12 \xB5\xEB\xAF\xAB\"p\xA2\xC4\x1E\xB9\xCDG>\xB8\xAC\xA9XQ\x1F\xE1+s\x02U\x9D\x19~*\x87\x04\xC9KdsolcC\0\x08\x1E\x003", + ); + /**Constructor`. + ```solidity + constructor(address _asset, uint8 _decimals, uint256 _rateNumerator, uint256 _rateDenominator); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _asset: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _decimals: u8, + #[allow(missing_docs)] + pub _rateNumerator: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub _rateDenominator: alloy_sol_types::private::primitives::aliases::U256, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + u8, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + ( + value._asset, + value._decimals, + value._rateNumerator, + value._rateDenominator, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _asset: tuple.0, + _decimals: tuple.1, + _rateNumerator: tuple.2, + _rateDenominator: tuple.3, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._asset, + ), + as alloy_sol_types::SolType>::tokenize( + &self._decimals, + ), + as alloy_sol_types::SolType>::tokenize( + &self._rateNumerator, + ), + as alloy_sol_types::SolType>::tokenize( + &self._rateDenominator, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address, address) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value._0, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._0, + ), + ::tokenize( + &self._1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `asset()` and selector `0x38d52e0f`. + ```solidity + function asset() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct assetCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`asset()`](assetCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct assetReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: assetCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for assetCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: assetReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for assetReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for assetCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [56u8, 213u8, 46u8, 15u8]; + const SIGNATURE: &'static str = "asset()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: assetReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: assetReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall(pub alloy_sol_types::private::Address); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `convertToAssets(uint256)` and selector `0x07a2d13a`. + ```solidity + function convertToAssets(uint256 shares) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct convertToAssetsCall { + #[allow(missing_docs)] + pub shares: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`convertToAssets(uint256)`](convertToAssetsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct convertToAssetsReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: convertToAssetsCall) -> Self { + (value.shares,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for convertToAssetsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { shares: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: convertToAssetsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for convertToAssetsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for convertToAssetsCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [7u8, 162u8, 209u8, 58u8]; + const SIGNATURE: &'static str = "convertToAssets(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.shares, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: convertToAssetsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: convertToAssetsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external view returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address,uint256)` and selector `0x40c10f19`. + ```solidity + function mint(address to, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`mint(address,uint256)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + (value.to, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl mintReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = mintReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [64u8, 193u8, 15u8, 25u8]; + const SIGNATURE: &'static str = "mint(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + mintReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `rateDenominator()` and selector `0x865192f7`. + ```solidity + function rateDenominator() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct rateDenominatorCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`rateDenominator()`](rateDenominatorCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct rateDenominatorReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: rateDenominatorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for rateDenominatorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: rateDenominatorReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for rateDenominatorReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for rateDenominatorCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [134u8, 81u8, 146u8, 247u8]; + const SIGNATURE: &'static str = "rateDenominator()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: rateDenominatorReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: rateDenominatorReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `rateNumerator()` and selector `0x0b36b8db`. + ```solidity + function rateNumerator() external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct rateNumeratorCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`rateNumerator()`](rateNumeratorCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct rateNumeratorReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: rateNumeratorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for rateNumeratorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: rateNumeratorReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for rateNumeratorReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for rateNumeratorCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [11u8, 54u8, 184u8, 219u8]; + const SIGNATURE: &'static str = "rateNumerator()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: rateNumeratorReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: rateNumeratorReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address to, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.to, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address from, address to, uint256 amount) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.from, value.to, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + from: tuple.0, + to: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.from, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`MockERC4626Wrapper`](self) function calls. + #[derive(Clone)] + pub enum MockERC4626WrapperCalls { + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + asset(assetCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + convertToAssets(convertToAssetsCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + rateDenominator(rateDenominatorCall), + #[allow(missing_docs)] + rateNumerator(rateNumeratorCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl MockERC4626WrapperCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [7u8, 162u8, 209u8, 58u8], + [9u8, 94u8, 167u8, 179u8], + [11u8, 54u8, 184u8, 219u8], + [35u8, 184u8, 114u8, 221u8], + [49u8, 60u8, 229u8, 103u8], + [56u8, 213u8, 46u8, 15u8], + [64u8, 193u8, 15u8, 25u8], + [112u8, 160u8, 130u8, 49u8], + [134u8, 81u8, 146u8, 247u8], + [169u8, 5u8, 156u8, 187u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(convertToAssets), + ::core::stringify!(approve), + ::core::stringify!(rateNumerator), + ::core::stringify!(transferFrom), + ::core::stringify!(decimals), + ::core::stringify!(asset), + ::core::stringify!(mint), + ::core::stringify!(balanceOf), + ::core::stringify!(rateDenominator), + ::core::stringify!(transfer), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for MockERC4626WrapperCalls { + const COUNT: usize = 11usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "MockERC4626WrapperCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::asset(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::convertToAssets(_) => { + ::SELECTOR + } + Self::decimals(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::rateDenominator(_) => { + ::SELECTOR + } + Self::rateNumerator(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn convertToAssets( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::convertToAssets) + } + convertToAssets + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::approve) + } + approve + }, + { + fn rateNumerator( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::rateNumerator) + } + rateNumerator + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::decimals) + } + decimals + }, + { + fn asset(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::asset) + } + asset + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::balanceOf) + } + balanceOf + }, + { + fn rateDenominator( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::rateDenominator) + } + rateDenominator + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(MockERC4626WrapperCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + MockERC4626WrapperCalls, + >] = &[ + { + fn convertToAssets( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(MockERC4626WrapperCalls::convertToAssets) + } + convertToAssets + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(MockERC4626WrapperCalls::approve) + } + approve + }, + { + fn rateNumerator( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(MockERC4626WrapperCalls::rateNumerator) + } + rateNumerator + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(MockERC4626WrapperCalls::transferFrom) + } + transferFrom + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(MockERC4626WrapperCalls::decimals) + } + decimals + }, + { + fn asset(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(MockERC4626WrapperCalls::asset) + } + asset + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(MockERC4626WrapperCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(MockERC4626WrapperCalls::balanceOf) + } + balanceOf + }, + { + fn rateDenominator( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(MockERC4626WrapperCalls::rateDenominator) + } + rateDenominator + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(MockERC4626WrapperCalls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(MockERC4626WrapperCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::asset(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::convertToAssets(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::rateDenominator(inner) => { + ::abi_encoded_size(inner) + } + Self::rateNumerator(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::asset(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::convertToAssets(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::rateDenominator(inner) => { + ::abi_encode_raw(inner, out) + } + Self::rateNumerator(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`MockERC4626Wrapper`](self) contract instance. + + See the [wrapper's documentation](`MockERC4626WrapperInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> MockERC4626WrapperInstance { + MockERC4626WrapperInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _asset: alloy_sol_types::private::Address, + _decimals: u8, + _rateNumerator: alloy_sol_types::private::primitives::aliases::U256, + _rateDenominator: alloy_sol_types::private::primitives::aliases::U256, + ) -> impl ::core::future::Future>> + { + MockERC4626WrapperInstance::::deploy( + __provider, + _asset, + _decimals, + _rateNumerator, + _rateDenominator, + ) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _asset: alloy_sol_types::private::Address, + _decimals: u8, + _rateNumerator: alloy_sol_types::private::primitives::aliases::U256, + _rateDenominator: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::RawCallBuilder { + MockERC4626WrapperInstance::::deploy_builder( + __provider, + _asset, + _decimals, + _rateNumerator, + _rateDenominator, + ) + } + /**A [`MockERC4626Wrapper`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`MockERC4626Wrapper`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct MockERC4626WrapperInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for MockERC4626WrapperInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("MockERC4626WrapperInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + MockERC4626WrapperInstance + { + /**Creates a new wrapper around an on-chain [`MockERC4626Wrapper`](self) contract instance. + + See the [wrapper's documentation](`MockERC4626WrapperInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _asset: alloy_sol_types::private::Address, + _decimals: u8, + _rateNumerator: alloy_sol_types::private::primitives::aliases::U256, + _rateDenominator: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder( + __provider, + _asset, + _decimals, + _rateNumerator, + _rateDenominator, + ); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _asset: alloy_sol_types::private::Address, + _decimals: u8, + _rateNumerator: alloy_sol_types::private::primitives::aliases::U256, + _rateDenominator: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + _asset, + _decimals, + _rateNumerator, + _rateDenominator, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl MockERC4626WrapperInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> MockERC4626WrapperInstance { + MockERC4626WrapperInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + MockERC4626WrapperInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + _0: alloy_sol_types::private::Address, + _1: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { _0, _1 }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`asset`] function. + pub fn asset(&self) -> alloy_contract::SolCallBuilder<&P, assetCall, N> { + self.call_builder(&assetCall) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + _0: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall(_0)) + } + + ///Creates a new call builder for the [`convertToAssets`] function. + pub fn convertToAssets( + &self, + shares: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, convertToAssetsCall, N> { + self.call_builder(&convertToAssetsCall { shares }) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { to, amount }) + } + + ///Creates a new call builder for the [`rateDenominator`] function. + pub fn rateDenominator( + &self, + ) -> alloy_contract::SolCallBuilder<&P, rateDenominatorCall, N> { + self.call_builder(&rateDenominatorCall) + } + + ///Creates a new call builder for the [`rateNumerator`] function. + pub fn rateNumerator(&self) -> alloy_contract::SolCallBuilder<&P, rateNumeratorCall, N> { + self.call_builder(&rateNumeratorCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { to, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + from: alloy_sol_types::private::Address, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { from, to, amount }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + MockERC4626WrapperInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = MockERC4626Wrapper::MockERC4626WrapperInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/nonstandarderc20balances/Cargo.toml b/contracts/generated/contracts-generated/nonstandarderc20balances/Cargo.toml new file mode 100644 index 0000000000..74e9a223ba --- /dev/null +++ b/contracts/generated/contracts-generated/nonstandarderc20balances/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-nonstandarderc20balances" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/nonstandarderc20balances/src/lib.rs b/contracts/generated/contracts-generated/nonstandarderc20balances/src/lib.rs new file mode 100644 index 0000000000..f0f586feff --- /dev/null +++ b/contracts/generated/contracts-generated/nonstandarderc20balances/src/lib.rs @@ -0,0 +1,1643 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface NonStandardERC20Balances { + function allowance(address user, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external; + function balanceOf(address user) external view returns (uint256); + function mint(address user, uint256 amount) external; + function transfer(address to, uint256 amount) external; + function transferFrom(address from, address to, uint256 amount) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod NonStandardERC20Balances { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b5061050e8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061006f575f3560e01c806370a082311161004d57806370a082311461010b578063a9059cbb14610155578063dd62ed3e14610168575f5ffd5b8063095ea7b31461007357806323b872dd146100bb57806340c10f19146100ce575b5f5ffd5b6100b96100813660046103c4565b335f9081526020818152604080832073ffffffffffffffffffffffffffffffffffffffff959095168352600190940190529190912055565b005b6100b96100c93660046103ec565b61017b565b6100b96100dc3660046103c4565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526020819052604090206001815560020155565b610143610119366004610426565b73ffffffffffffffffffffffffffffffffffffffff165f9081526020819052604090206002015490565b60405190815260200160405180910390f35b6100b96101633660046103c4565b6102a7565b610143610176366004610446565b610361565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260208181526040808320338452600101909152812080548392906101bb9084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812060020180548392906101f79084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812080549161022c836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906102689084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812080549161029d836104b7565b9190505550505050565b335f90815260208190526040812060020180548392906102c89084906104a4565b9091555050335f9081526020819052604081208054916102e7836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906103239084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f908152602081905260408120805491610358836104b7565b91905055505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683526001909301905220545b92915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146103bf575f5ffd5b919050565b5f5f604083850312156103d5575f5ffd5b6103de8361039c565b946020939093013593505050565b5f5f5f606084860312156103fe575f5ffd5b6104078461039c565b92506104156020850161039c565b929592945050506040919091013590565b5f60208284031215610436575f5ffd5b61043f8261039c565b9392505050565b5f5f60408385031215610457575f5ffd5b6104608361039c565b915061046e6020840161039c565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561039657610396610477565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036104e7576104e7610477565b5060010190565b808201808211156103965761039661047756fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x05\x0E\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0oW_5`\xE0\x1C\x80cp\xA0\x821\x11a\0MW\x80cp\xA0\x821\x14a\x01\x0BW\x80c\xA9\x05\x9C\xBB\x14a\x01UW\x80c\xDDb\xED>\x14a\x01hW__\xFD[\x80c\t^\xA7\xB3\x14a\0sW\x80c#\xB8r\xDD\x14a\0\xBBW\x80c@\xC1\x0F\x19\x14a\0\xCEW[__\xFD[a\0\xB9a\0\x816`\x04a\x03\xC4V[3_\x90\x81R` \x81\x81R`@\x80\x83 s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x95\x90\x95\x16\x83R`\x01\x90\x94\x01\x90R\x91\x90\x91 UV[\0[a\0\xB9a\0\xC96`\x04a\x03\xECV[a\x01{V[a\0\xB9a\0\xDC6`\x04a\x03\xC4V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16_\x90\x81R` \x81\x90R`@\x90 `\x01\x81U`\x02\x01UV[a\x01Ca\x01\x196`\x04a\x04&V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16_\x90\x81R` \x81\x90R`@\x90 `\x02\x01T\x90V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\xB9a\x01c6`\x04a\x03\xC4V[a\x02\xA7V[a\x01Ca\x01v6`\x04a\x04FV[a\x03aV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x81R`@\x80\x83 3\x84R`\x01\x01\x90\x91R\x81 \x80T\x83\x92\x90a\x01\xBB\x90\x84\x90a\x04\xA4V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x01\xF7\x90\x84\x90a\x04\xA4V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02,\x83a\x04\xB7V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02h\x90\x84\x90a\x04\xEEV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02\x9D\x83a\x04\xB7V[\x91\x90PUPPPPV[3_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02\xC8\x90\x84\x90a\x04\xA4V[\x90\x91UPP3_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02\xE7\x83a\x04\xB7V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x03#\x90\x84\x90a\x04\xEEV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x03X\x83a\x04\xB7V[\x91\x90PUPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x83\x16_\x90\x81R` \x81\x81R`@\x80\x83 \x93\x85\x16\x83R`\x01\x90\x93\x01\x90R T[\x92\x91PPV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x03\xBFW__\xFD[\x91\x90PV[__`@\x83\x85\x03\x12\x15a\x03\xD5W__\xFD[a\x03\xDE\x83a\x03\x9CV[\x94` \x93\x90\x93\x015\x93PPPV[___``\x84\x86\x03\x12\x15a\x03\xFEW__\xFD[a\x04\x07\x84a\x03\x9CV[\x92Pa\x04\x15` \x85\x01a\x03\x9CV[\x92\x95\x92\x94PPP`@\x91\x90\x91\x015\x90V[_` \x82\x84\x03\x12\x15a\x046W__\xFD[a\x04?\x82a\x03\x9CV[\x93\x92PPPV[__`@\x83\x85\x03\x12\x15a\x04WW__\xFD[a\x04`\x83a\x03\x9CV[\x91Pa\x04n` \x84\x01a\x03\x9CV[\x90P\x92P\x92\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x81\x81\x03\x81\x81\x11\x15a\x03\x96Wa\x03\x96a\x04wV[_\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x03a\x04\xE7Wa\x04\xE7a\x04wV[P`\x01\x01\x90V[\x80\x82\x01\x80\x82\x11\x15a\x03\x96Wa\x03\x96a\x04wV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b506004361061006f575f3560e01c806370a082311161004d57806370a082311461010b578063a9059cbb14610155578063dd62ed3e14610168575f5ffd5b8063095ea7b31461007357806323b872dd146100bb57806340c10f19146100ce575b5f5ffd5b6100b96100813660046103c4565b335f9081526020818152604080832073ffffffffffffffffffffffffffffffffffffffff959095168352600190940190529190912055565b005b6100b96100c93660046103ec565b61017b565b6100b96100dc3660046103c4565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526020819052604090206001815560020155565b610143610119366004610426565b73ffffffffffffffffffffffffffffffffffffffff165f9081526020819052604090206002015490565b60405190815260200160405180910390f35b6100b96101633660046103c4565b6102a7565b610143610176366004610446565b610361565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260208181526040808320338452600101909152812080548392906101bb9084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812060020180548392906101f79084906104a4565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812080549161022c836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906102689084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812080549161029d836104b7565b9190505550505050565b335f90815260208190526040812060020180548392906102c89084906104a4565b9091555050335f9081526020819052604081208054916102e7836104b7565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812060020180548392906103239084906104ee565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f908152602081905260408120805491610358836104b7565b91905055505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683526001909301905220545b92915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146103bf575f5ffd5b919050565b5f5f604083850312156103d5575f5ffd5b6103de8361039c565b946020939093013593505050565b5f5f5f606084860312156103fe575f5ffd5b6104078461039c565b92506104156020850161039c565b929592945050506040919091013590565b5f60208284031215610436575f5ffd5b61043f8261039c565b9392505050565b5f5f60408385031215610457575f5ffd5b6104608361039c565b915061046e6020840161039c565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561039657610396610477565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036104e7576104e7610477565b5060010190565b808201808211156103965761039661047756fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0oW_5`\xE0\x1C\x80cp\xA0\x821\x11a\0MW\x80cp\xA0\x821\x14a\x01\x0BW\x80c\xA9\x05\x9C\xBB\x14a\x01UW\x80c\xDDb\xED>\x14a\x01hW__\xFD[\x80c\t^\xA7\xB3\x14a\0sW\x80c#\xB8r\xDD\x14a\0\xBBW\x80c@\xC1\x0F\x19\x14a\0\xCEW[__\xFD[a\0\xB9a\0\x816`\x04a\x03\xC4V[3_\x90\x81R` \x81\x81R`@\x80\x83 s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x95\x90\x95\x16\x83R`\x01\x90\x94\x01\x90R\x91\x90\x91 UV[\0[a\0\xB9a\0\xC96`\x04a\x03\xECV[a\x01{V[a\0\xB9a\0\xDC6`\x04a\x03\xC4V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16_\x90\x81R` \x81\x90R`@\x90 `\x01\x81U`\x02\x01UV[a\x01Ca\x01\x196`\x04a\x04&V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16_\x90\x81R` \x81\x90R`@\x90 `\x02\x01T\x90V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[a\0\xB9a\x01c6`\x04a\x03\xC4V[a\x02\xA7V[a\x01Ca\x01v6`\x04a\x04FV[a\x03aV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x81R`@\x80\x83 3\x84R`\x01\x01\x90\x91R\x81 \x80T\x83\x92\x90a\x01\xBB\x90\x84\x90a\x04\xA4V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x01\xF7\x90\x84\x90a\x04\xA4V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02,\x83a\x04\xB7V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02h\x90\x84\x90a\x04\xEEV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02\x9D\x83a\x04\xB7V[\x91\x90PUPPPPV[3_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02\xC8\x90\x84\x90a\x04\xA4V[\x90\x91UPP3_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02\xE7\x83a\x04\xB7V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x03#\x90\x84\x90a\x04\xEEV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x03X\x83a\x04\xB7V[\x91\x90PUPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x83\x16_\x90\x81R` \x81\x81R`@\x80\x83 \x93\x85\x16\x83R`\x01\x90\x93\x01\x90R T[\x92\x91PPV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x03\xBFW__\xFD[\x91\x90PV[__`@\x83\x85\x03\x12\x15a\x03\xD5W__\xFD[a\x03\xDE\x83a\x03\x9CV[\x94` \x93\x90\x93\x015\x93PPPV[___``\x84\x86\x03\x12\x15a\x03\xFEW__\xFD[a\x04\x07\x84a\x03\x9CV[\x92Pa\x04\x15` \x85\x01a\x03\x9CV[\x92\x95\x92\x94PPP`@\x91\x90\x91\x015\x90V[_` \x82\x84\x03\x12\x15a\x046W__\xFD[a\x04?\x82a\x03\x9CV[\x93\x92PPPV[__`@\x83\x85\x03\x12\x15a\x04WW__\xFD[a\x04`\x83a\x03\x9CV[\x91Pa\x04n` \x84\x01a\x03\x9CV[\x90P\x92P\x92\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x81\x81\x03\x81\x81\x11\x15a\x03\x96Wa\x03\x96a\x04wV[_\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x03a\x04\xE7Wa\x04\xE7a\x04wV[P`\x01\x01\x90V[\x80\x82\x01\x80\x82\x11\x15a\x03\x96Wa\x03\x96a\x04wV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address user, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.user, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + user: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl approveReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = approveReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + approveReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address user) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.user,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { user: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address,uint256)` and selector `0x40c10f19`. + ```solidity + function mint(address user, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`mint(address,uint256)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + (value.user, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + user: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl mintReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = mintReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [64u8, 193u8, 15u8, 25u8]; + const SIGNATURE: &'static str = "mint(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + mintReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address to, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.to, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl transferReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = transferReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + transferReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address from, address to, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.from, value.to, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + from: tuple.0, + to: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl transferFromReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = transferFromReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.from, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + transferFromReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`NonStandardERC20Balances`](self) function calls. + #[derive(Clone)] + pub enum NonStandardERC20BalancesCalls { + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl NonStandardERC20BalancesCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [9u8, 94u8, 167u8, 179u8], + [35u8, 184u8, 114u8, 221u8], + [64u8, 193u8, 15u8, 25u8], + [112u8, 160u8, 130u8, 49u8], + [169u8, 5u8, 156u8, 187u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(approve), + ::core::stringify!(transferFrom), + ::core::stringify!(mint), + ::core::stringify!(balanceOf), + ::core::stringify!(transfer), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for NonStandardERC20BalancesCalls { + const COUNT: usize = 6usize; + const MIN_DATA_LENGTH: usize = 32usize; + const NAME: &'static str = "NonStandardERC20BalancesCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(NonStandardERC20BalancesCalls::approve) + } + approve + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(NonStandardERC20BalancesCalls::transferFrom) + } + transferFrom + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(NonStandardERC20BalancesCalls::mint) + } + mint + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(NonStandardERC20BalancesCalls::balanceOf) + } + balanceOf + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(NonStandardERC20BalancesCalls::transfer) + } + transfer + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(NonStandardERC20BalancesCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + NonStandardERC20BalancesCalls, + >] = &[ + { + fn approve( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(NonStandardERC20BalancesCalls::approve) + } + approve + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(NonStandardERC20BalancesCalls::transferFrom) + } + transferFrom + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(NonStandardERC20BalancesCalls::mint) + } + mint + }, + { + fn balanceOf( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(NonStandardERC20BalancesCalls::balanceOf) + } + balanceOf + }, + { + fn transfer( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(NonStandardERC20BalancesCalls::transfer) + } + transfer + }, + { + fn allowance( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(NonStandardERC20BalancesCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`NonStandardERC20Balances`](self) contract instance. + + See the [wrapper's documentation](`NonStandardERC20BalancesInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> NonStandardERC20BalancesInstance { + NonStandardERC20BalancesInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + NonStandardERC20BalancesInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + NonStandardERC20BalancesInstance::::deploy_builder(__provider) + } + /**A [`NonStandardERC20Balances`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`NonStandardERC20Balances`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct NonStandardERC20BalancesInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for NonStandardERC20BalancesInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("NonStandardERC20BalancesInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + NonStandardERC20BalancesInstance + { + /**Creates a new wrapper around an on-chain [`NonStandardERC20Balances`](self) contract instance. + + See the [wrapper's documentation](`NonStandardERC20BalancesInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl NonStandardERC20BalancesInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> NonStandardERC20BalancesInstance { + NonStandardERC20BalancesInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + NonStandardERC20BalancesInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + user: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { user, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + user: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { user }) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + user: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { user, amount }) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { to, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + from: alloy_sol_types::private::Address, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { from, to, amount }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + NonStandardERC20BalancesInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = + NonStandardERC20Balances::NonStandardERC20BalancesInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/pancakerouter/Cargo.toml b/contracts/generated/contracts-generated/pancakerouter/Cargo.toml new file mode 100644 index 0000000000..0f4463b992 --- /dev/null +++ b/contracts/generated/contracts-generated/pancakerouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-pancakerouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/pancakerouter/src/lib.rs b/contracts/generated/contracts-generated/pancakerouter/src/lib.rs new file mode 100644 index 0000000000..7427fc054d --- /dev/null +++ b/contracts/generated/contracts-generated/pancakerouter/src/lib.rs @@ -0,0 +1,1590 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface PancakeRouter { + function WETH() external pure returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external pure returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod PancakeRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`PancakeRouter`](self) function calls. + #[derive(Clone)] + pub enum PancakeRouterCalls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl PancakeRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for PancakeRouterCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "PancakeRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(PancakeRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(PancakeRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(PancakeRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(PancakeRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(PancakeRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(PancakeRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(PancakeRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(PancakeRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(PancakeRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(PancakeRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`PancakeRouter`](self) contract instance. + + See the [wrapper's documentation](`PancakeRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> PancakeRouterInstance { + PancakeRouterInstance::::new(address, __provider) + } + /**A [`PancakeRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`PancakeRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct PancakeRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for PancakeRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("PancakeRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + PancakeRouterInstance + { + /**Creates a new wrapper around an on-chain [`PancakeRouter`](self) contract instance. + + See the [wrapper's documentation](`PancakeRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl PancakeRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> PancakeRouterInstance { + PancakeRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + PancakeRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + PancakeRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = PancakeRouter::PancakeRouterInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xEfF92A263d31888d860bD50809A8D171709b7b1c"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x10ED43C718714eb63d5aA57B78B54704E256024E"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/permit2/Cargo.toml b/contracts/generated/contracts-generated/permit2/Cargo.toml new file mode 100644 index 0000000000..364b5e1cc0 --- /dev/null +++ b/contracts/generated/contracts-generated/permit2/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-permit2" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/permit2/src/lib.rs b/contracts/generated/contracts-generated/permit2/src/lib.rs new file mode 100644 index 0000000000..a3af444fbc --- /dev/null +++ b/contracts/generated/contracts-generated/permit2/src/lib.rs @@ -0,0 +1,4706 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library IAllowanceTransfer { + struct PermitDetails { address token; uint160 amount; uint48 expiration; uint48 nonce; } + struct PermitSingle { PermitDetails details; address spender; uint256 sigDeadline; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IAllowanceTransfer { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct PermitDetails { address token; uint160 amount; uint48 expiration; uint48 nonce; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PermitDetails { + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub expiration: alloy_sol_types::private::primitives::aliases::U48, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U48, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<48>, + alloy_sol_types::sol_data::Uint<48>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U160, + alloy_sol_types::private::primitives::aliases::U48, + alloy_sol_types::private::primitives::aliases::U48, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: PermitDetails) -> Self { + (value.token, value.amount, value.expiration, value.nonce) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for PermitDetails { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + token: tuple.0, + amount: tuple.1, + expiration: tuple.2, + nonce: tuple.3, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for PermitDetails { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for PermitDetails { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.token, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.expiration, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for PermitDetails { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for PermitDetails { + const NAME: &'static str = "PermitDetails"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.token, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.expiration) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.nonce) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for PermitDetails { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.token, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.expiration, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.nonce) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.token, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.expiration, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.nonce, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct PermitSingle { PermitDetails details; address spender; uint256 sigDeadline; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct PermitSingle { + #[allow(missing_docs)] + pub details: ::RustType, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sigDeadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + PermitDetails, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: PermitSingle) -> Self { + (value.details, value.spender, value.sigDeadline) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for PermitSingle { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + details: tuple.0, + spender: tuple.1, + sigDeadline: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for PermitSingle { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for PermitSingle { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize(&self.details), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sigDeadline, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for PermitSingle { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for PermitSingle { + const NAME: &'static str = "PermitSingle"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + let mut components = alloy_sol_types::private::Vec::with_capacity(1); + components.push(::eip712_root_type()); + components + .extend(::eip712_components()); + components + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.details, + ) + .0, + ::eip712_data_word( + &self.spender, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.sigDeadline) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for PermitSingle { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.details, + ) + + ::topic_preimage_length( + &rust.spender, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sigDeadline, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.details, + out, + ); + ::encode_topic_preimage( + &rust.spender, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sigDeadline, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IAllowanceTransfer`](self) contract instance. + + See the [wrapper's documentation](`IAllowanceTransferInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IAllowanceTransferInstance { + IAllowanceTransferInstance::::new(address, __provider) + } + /**A [`IAllowanceTransfer`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IAllowanceTransfer`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IAllowanceTransferInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IAllowanceTransferInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IAllowanceTransferInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IAllowanceTransferInstance + { + /**Creates a new wrapper around an on-chain [`IAllowanceTransfer`](self) contract instance. + + See the [wrapper's documentation](`IAllowanceTransferInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IAllowanceTransferInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IAllowanceTransferInstance { + IAllowanceTransferInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IAllowanceTransferInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IAllowanceTransferInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library IAllowanceTransfer { + struct PermitDetails { + address token; + uint160 amount; + uint48 expiration; + uint48 nonce; + } + struct PermitSingle { + PermitDetails details; + address spender; + uint256 sigDeadline; + } +} + +interface Permit2 { + error AllowanceExpired(uint256 deadline); + error ExcessiveInvalidation(); + error InsufficientAllowance(uint256 amount); + error InvalidAmount(uint256 maxAmount); + error InvalidContractSignature(); + error InvalidNonce(); + error InvalidSignature(); + error InvalidSignatureLength(); + error InvalidSigner(); + error LengthMismatch(); + error SignatureExpired(uint256 signatureDeadline); + + event Approval(address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration); + event Lockdown(address indexed owner, address token, address spender); + event NonceInvalidation(address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce); + event Permit(address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration, uint48 nonce); + event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask); + + function DOMAIN_SEPARATOR() external view returns (bytes32); + function allowance(address, address, address) external view returns (uint160 amount, uint48 expiration, uint48 nonce); + function approve(address token, address spender, uint160 amount, uint48 expiration) external; + function permit(address owner, IAllowanceTransfer.PermitSingle memory permitSingle, bytes memory signature) external; + function transferFrom(address from, address to, uint160 amount, address token) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "amount", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "expiration", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "nonce", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "expiration", + "type": "uint48", + "internalType": "uint48" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "permitSingle", + "type": "tuple", + "internalType": "struct IAllowanceTransfer.PermitSingle", + "components": [ + { + "name": "details", + "type": "tuple", + "internalType": "struct IAllowanceTransfer.PermitDetails", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "expiration", + "type": "uint48", + "internalType": "uint48" + }, + { + "name": "nonce", + "type": "uint48", + "internalType": "uint48" + } + ] + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "sigDeadline", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint160", + "indexed": false, + "internalType": "uint160" + }, + { + "name": "expiration", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Lockdown", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NonceInvalidation", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newNonce", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, + { + "name": "oldNonce", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Permit", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint160", + "indexed": false, + "internalType": "uint160" + }, + { + "name": "expiration", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + }, + { + "name": "nonce", + "type": "uint48", + "indexed": false, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UnorderedNonceInvalidation", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "word", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "mask", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AllowanceExpired", + "inputs": [ + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ExcessiveInvalidation", + "inputs": [] + }, + { + "type": "error", + "name": "InsufficientAllowance", + "inputs": [ + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidAmount", + "inputs": [ + { + "name": "maxAmount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidContractSignature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSignature", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSignatureLength", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidSigner", + "inputs": [] + }, + { + "type": "error", + "name": "LengthMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "SignatureExpired", + "inputs": [ + { + "name": "signatureDeadline", + "type": "uint256", + "internalType": "uint256" + } + ] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Permit2 { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `AllowanceExpired(uint256)` and selector `0xd81b2f2e`. + ```solidity + error AllowanceExpired(uint256 deadline); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct AllowanceExpired { + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: AllowanceExpired) -> Self { + (value.deadline,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for AllowanceExpired { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { deadline: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for AllowanceExpired { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [216u8, 27u8, 47u8, 46u8]; + const SIGNATURE: &'static str = "AllowanceExpired(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `ExcessiveInvalidation()` and selector `0x24d35a26`. + ```solidity + error ExcessiveInvalidation(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ExcessiveInvalidation; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ExcessiveInvalidation) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ExcessiveInvalidation { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for ExcessiveInvalidation { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [36u8, 211u8, 90u8, 38u8]; + const SIGNATURE: &'static str = "ExcessiveInvalidation()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InsufficientAllowance(uint256)` and selector `0xf96fb071`. + ```solidity + error InsufficientAllowance(uint256 amount); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InsufficientAllowance { + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InsufficientAllowance) -> Self { + (value.amount,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InsufficientAllowance { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amount: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InsufficientAllowance { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [249u8, 111u8, 176u8, 113u8]; + const SIGNATURE: &'static str = "InsufficientAllowance(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidAmount(uint256)` and selector `0x3728b83d`. + ```solidity + error InvalidAmount(uint256 maxAmount); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidAmount { + #[allow(missing_docs)] + pub maxAmount: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidAmount) -> Self { + (value.maxAmount,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidAmount { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { maxAmount: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidAmount { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [55u8, 40u8, 184u8, 61u8]; + const SIGNATURE: &'static str = "InvalidAmount(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.maxAmount, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidContractSignature()` and selector `0xb0669cbc`. + ```solidity + error InvalidContractSignature(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidContractSignature; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidContractSignature) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidContractSignature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidContractSignature { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [176u8, 102u8, 156u8, 188u8]; + const SIGNATURE: &'static str = "InvalidContractSignature()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidNonce()` and selector `0x756688fe`. + ```solidity + error InvalidNonce(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidNonce; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidNonce) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidNonce { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidNonce { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [117u8, 102u8, 136u8, 254u8]; + const SIGNATURE: &'static str = "InvalidNonce()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidSignature()` and selector `0x8baa579f`. + ```solidity + error InvalidSignature(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidSignature; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidSignature) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidSignature { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidSignature { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [139u8, 170u8, 87u8, 159u8]; + const SIGNATURE: &'static str = "InvalidSignature()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidSignatureLength()` and selector `0x4be6321b`. + ```solidity + error InvalidSignatureLength(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidSignatureLength; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidSignatureLength) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidSignatureLength { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidSignatureLength { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [75u8, 230u8, 50u8, 27u8]; + const SIGNATURE: &'static str = "InvalidSignatureLength()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `InvalidSigner()` and selector `0x815e1d64`. + ```solidity + error InvalidSigner(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct InvalidSigner; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: InvalidSigner) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for InvalidSigner { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for InvalidSigner { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [129u8, 94u8, 29u8, 100u8]; + const SIGNATURE: &'static str = "InvalidSigner()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `LengthMismatch()` and selector `0xff633a38`. + ```solidity + error LengthMismatch(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct LengthMismatch; + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: LengthMismatch) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for LengthMismatch { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for LengthMismatch { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [255u8, 99u8, 58u8, 56u8]; + const SIGNATURE: &'static str = "LengthMismatch()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Custom error with signature `SignatureExpired(uint256)` and selector `0xcd21db4f`. + ```solidity + error SignatureExpired(uint256 signatureDeadline); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct SignatureExpired { + #[allow(missing_docs)] + pub signatureDeadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: SignatureExpired) -> Self { + (value.signatureDeadline,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for SignatureExpired { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + signatureDeadline: tuple.0, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for SignatureExpired { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [205u8, 33u8, 219u8, 79u8]; + const SIGNATURE: &'static str = "SignatureExpired(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.signatureDeadline, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,address,uint160,uint48)` and selector `0xda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b`. + ```solidity + event Approval(address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub expiration: alloy_sol_types::private::primitives::aliases::U48, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<48>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,address,uint160,uint48)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 218u8, 159u8, 167u8, 193u8, 176u8, 4u8, 2u8, 193u8, 125u8, 1u8, 97u8, 178u8, + 73u8, 177u8, 171u8, 139u8, 190u8, 192u8, 71u8, 197u8, 165u8, 34u8, 7u8, 185u8, + 193u8, 18u8, 222u8, 255u8, 216u8, 23u8, 3u8, 107u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + token: topics.2, + spender: topics.3, + amount: data.0, + expiration: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.expiration, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.token.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.token, + ); + out[3usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Lockdown(address,address,address)` and selector `0x89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4`. + ```solidity + event Lockdown(address indexed owner, address token, address spender); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Lockdown { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Lockdown { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Lockdown(address,address,address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 137u8, 177u8, 173u8, 209u8, 94u8, 255u8, 86u8, 179u8, 223u8, 226u8, 153u8, + 173u8, 148u8, 224u8, 31u8, 43u8, 82u8, 251u8, 203u8, 128u8, 174u8, 26u8, 59u8, + 174u8, 166u8, 174u8, 140u8, 4u8, 203u8, 43u8, 152u8, 164u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + token: data.0, + spender: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.token, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.owner.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Lockdown { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Lockdown> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Lockdown) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `NonceInvalidation(address,address,address,uint48,uint48)` and selector `0x55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f3`. + ```solidity + event NonceInvalidation(address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct NonceInvalidation { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub newNonce: alloy_sol_types::private::primitives::aliases::U48, + #[allow(missing_docs)] + pub oldNonce: alloy_sol_types::private::primitives::aliases::U48, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for NonceInvalidation { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<48>, + alloy_sol_types::sol_data::Uint<48>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "NonceInvalidation(address,address,address,uint48,uint48)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 85u8, 235u8, 144u8, 216u8, 16u8, 225u8, 112u8, 11u8, 53u8, 168u8, 231u8, 226u8, + 83u8, 149u8, 255u8, 127u8, 43u8, 34u8, 89u8, 171u8, 215u8, 65u8, 92u8, 162u8, + 40u8, 77u8, 251u8, 28u8, 36u8, 100u8, 24u8, 243u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + token: topics.2, + spender: topics.3, + newNonce: data.0, + oldNonce: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.newNonce, + ), + as alloy_sol_types::SolType>::tokenize( + &self.oldNonce, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.token.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.token, + ); + out[3usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for NonceInvalidation { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&NonceInvalidation> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &NonceInvalidation) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Permit(address,address,address,uint160,uint48,uint48)` and selector `0xc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec`. + ```solidity + event Permit(address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration, uint48 nonce); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Permit { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub expiration: alloy_sol_types::private::primitives::aliases::U48, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U48, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Permit { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<48>, + alloy_sol_types::sol_data::Uint<48>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Permit(address,address,address,uint160,uint48,uint48)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 198u8, 163u8, 119u8, 191u8, 196u8, 235u8, 18u8, 0u8, 36u8, 168u8, 172u8, 8u8, + 238u8, 242u8, 5u8, 190u8, 22u8, 184u8, 23u8, 2u8, 8u8, 18u8, 199u8, 50u8, 35u8, + 232u8, 29u8, 27u8, 219u8, 151u8, 8u8, 236u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + token: topics.2, + spender: topics.3, + amount: data.0, + expiration: data.1, + nonce: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.expiration, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.token.clone(), + self.spender.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.token, + ); + out[3usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Permit { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Permit> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Permit) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `UnorderedNonceInvalidation(address,uint256,uint256)` and selector `0x3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d`. + ```solidity + event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct UnorderedNonceInvalidation { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub word: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub mask: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for UnorderedNonceInvalidation { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "UnorderedNonceInvalidation(address,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 55u8, 4u8, 144u8, 47u8, 150u8, 55u8, 102u8, 164u8, 229u8, 97u8, 187u8, 170u8, + 182u8, 230u8, 205u8, 193u8, 177u8, 221u8, 18u8, 246u8, 233u8, 233u8, 150u8, + 72u8, 218u8, 136u8, 67u8, 179u8, 244u8, 107u8, 145u8, 141u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + word: data.0, + mask: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.word, + ), + as alloy_sol_types::SolType>::tokenize( + &self.mask, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.owner.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for UnorderedNonceInvalidation { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&UnorderedNonceInvalidation> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &UnorderedNonceInvalidation) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `DOMAIN_SEPARATOR()` and selector `0x3644e515`. + ```solidity + function DOMAIN_SEPARATOR() external view returns (bytes32); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`DOMAIN_SEPARATOR()`](DOMAIN_SEPARATORCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct DOMAIN_SEPARATORReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: DOMAIN_SEPARATORReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for DOMAIN_SEPARATORReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for DOMAIN_SEPARATORCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::FixedBytes<32>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 68u8, 229u8, 21u8]; + const SIGNATURE: &'static str = "DOMAIN_SEPARATOR()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: DOMAIN_SEPARATORReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address,address)` and selector `0x927da105`. + ```solidity + function allowance(address, address, address) external view returns (uint160 amount, uint48 expiration, uint48 nonce); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _2: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub expiration: alloy_sol_types::private::primitives::aliases::U48, + #[allow(missing_docs)] + pub nonce: alloy_sol_types::private::primitives::aliases::U48, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value._0, value._1, value._2) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + _2: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<48>, + alloy_sol_types::sol_data::Uint<48>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U160, + alloy_sol_types::private::primitives::aliases::U48, + alloy_sol_types::private::primitives::aliases::U48, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value.amount, value.expiration, value.nonce) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount: tuple.0, + expiration: tuple.1, + nonce: tuple.2, + } + } + } + } + impl allowanceReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.expiration, + ), + as alloy_sol_types::SolType>::tokenize( + &self.nonce, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = allowanceReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<48>, + alloy_sol_types::sol_data::Uint<48>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [146u8, 125u8, 161u8, 5u8]; + const SIGNATURE: &'static str = "allowance(address,address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._0, + ), + ::tokenize( + &self._1, + ), + ::tokenize( + &self._2, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + allowanceReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,address,uint160,uint48)` and selector `0x87517c45`. + ```solidity + function approve(address token, address spender, uint160 amount, uint48 expiration) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub expiration: alloy_sol_types::private::primitives::aliases::U48, + } + ///Container type for the return parameters of the + /// [`approve(address,address,uint160,uint48)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<48>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U160, + alloy_sol_types::private::primitives::aliases::U48, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.token, value.spender, value.amount, value.expiration) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + token: tuple.0, + spender: tuple.1, + amount: tuple.2, + expiration: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl approveReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<48>, + ); + type Return = approveReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [135u8, 81u8, 124u8, 69u8]; + const SIGNATURE: &'static str = "approve(address,address,uint160,uint48)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.token, + ), + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.expiration, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + approveReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive()] + /**Function with signature `permit(address,((address,uint160,uint48,uint48),address,uint256),bytes)` and selector `0x2b67b570`. + ```solidity + function permit(address owner, IAllowanceTransfer.PermitSingle memory permitSingle, bytes memory signature) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitCall { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub permitSingle: ::RustType, + #[allow(missing_docs)] + pub signature: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`permit(address,((address,uint160,uint48,uint48),address,uint256), + /// bytes)`](permitCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct permitReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + IAllowanceTransfer::PermitSingle, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + ::RustType, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitCall) -> Self { + (value.owner, value.permitSingle, value.signature) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + permitSingle: tuple.1, + signature: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: permitReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for permitReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl permitReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for permitCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + IAllowanceTransfer::PermitSingle, + alloy_sol_types::sol_data::Bytes, + ); + type Return = permitReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [43u8, 103u8, 181u8, 112u8]; + const SIGNATURE: &'static str = + "permit(address,((address,uint160,uint48,uint48),address,uint256),bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.permitSingle, + ), + ::tokenize( + &self.signature, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + permitReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint160,address)` and selector `0x36c78516`. + ```solidity + function transferFrom(address from, address to, uint160 amount, address token) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + } + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint160,address)`](transferFromCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U160, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.from, value.to, value.amount, value.token) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + from: tuple.0, + to: tuple.1, + amount: tuple.2, + token: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl transferFromReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Address, + ); + type Return = transferFromReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [54u8, 199u8, 133u8, 22u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint160,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.from, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ::tokenize( + &self.token, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + transferFromReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`Permit2`](self) function calls. + #[derive(Clone)] + pub enum Permit2Calls { + #[allow(missing_docs)] + DOMAIN_SEPARATOR(DOMAIN_SEPARATORCall), + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + permit(permitCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl Permit2Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [43u8, 103u8, 181u8, 112u8], + [54u8, 68u8, 229u8, 21u8], + [54u8, 199u8, 133u8, 22u8], + [135u8, 81u8, 124u8, 69u8], + [146u8, 125u8, 161u8, 5u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(permit), + ::core::stringify!(DOMAIN_SEPARATOR), + ::core::stringify!(transferFrom), + ::core::stringify!(approve), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for Permit2Calls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "Permit2Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::DOMAIN_SEPARATOR(_) => { + ::SELECTOR + } + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::permit(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Calls::permit) + } + permit + }, + { + fn DOMAIN_SEPARATOR(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Calls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Calls::transferFrom) + } + transferFrom + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Calls::approve) + } + approve + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn permit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(Permit2Calls::permit) + } + permit + }, + { + fn DOMAIN_SEPARATOR(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Calls::DOMAIN_SEPARATOR) + } + DOMAIN_SEPARATOR + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Calls::transferFrom) + } + transferFrom + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(Permit2Calls::approve) + } + approve + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(Permit2Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encoded_size(inner) + } + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::permit(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::DOMAIN_SEPARATOR(inner) => { + ::abi_encode_raw(inner, out) + } + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::permit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`Permit2`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum Permit2Errors { + #[allow(missing_docs)] + AllowanceExpired(AllowanceExpired), + #[allow(missing_docs)] + ExcessiveInvalidation(ExcessiveInvalidation), + #[allow(missing_docs)] + InsufficientAllowance(InsufficientAllowance), + #[allow(missing_docs)] + InvalidAmount(InvalidAmount), + #[allow(missing_docs)] + InvalidContractSignature(InvalidContractSignature), + #[allow(missing_docs)] + InvalidNonce(InvalidNonce), + #[allow(missing_docs)] + InvalidSignature(InvalidSignature), + #[allow(missing_docs)] + InvalidSignatureLength(InvalidSignatureLength), + #[allow(missing_docs)] + InvalidSigner(InvalidSigner), + #[allow(missing_docs)] + LengthMismatch(LengthMismatch), + #[allow(missing_docs)] + SignatureExpired(SignatureExpired), + } + impl Permit2Errors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [36u8, 211u8, 90u8, 38u8], + [55u8, 40u8, 184u8, 61u8], + [75u8, 230u8, 50u8, 27u8], + [117u8, 102u8, 136u8, 254u8], + [129u8, 94u8, 29u8, 100u8], + [139u8, 170u8, 87u8, 159u8], + [176u8, 102u8, 156u8, 188u8], + [205u8, 33u8, 219u8, 79u8], + [216u8, 27u8, 47u8, 46u8], + [249u8, 111u8, 176u8, 113u8], + [255u8, 99u8, 58u8, 56u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(ExcessiveInvalidation), + ::core::stringify!(InvalidAmount), + ::core::stringify!(InvalidSignatureLength), + ::core::stringify!(InvalidNonce), + ::core::stringify!(InvalidSigner), + ::core::stringify!(InvalidSignature), + ::core::stringify!(InvalidContractSignature), + ::core::stringify!(SignatureExpired), + ::core::stringify!(AllowanceExpired), + ::core::stringify!(InsufficientAllowance), + ::core::stringify!(LengthMismatch), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for Permit2Errors { + const COUNT: usize = 11usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "Permit2Errors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::AllowanceExpired(_) => { + ::SELECTOR + } + Self::ExcessiveInvalidation(_) => { + ::SELECTOR + } + Self::InsufficientAllowance(_) => { + ::SELECTOR + } + Self::InvalidAmount(_) => ::SELECTOR, + Self::InvalidContractSignature(_) => { + ::SELECTOR + } + Self::InvalidNonce(_) => ::SELECTOR, + Self::InvalidSignature(_) => { + ::SELECTOR + } + Self::InvalidSignatureLength(_) => { + ::SELECTOR + } + Self::InvalidSigner(_) => ::SELECTOR, + Self::LengthMismatch(_) => ::SELECTOR, + Self::SignatureExpired(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn ExcessiveInvalidation( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::ExcessiveInvalidation) + } + ExcessiveInvalidation + }, + { + fn InvalidAmount(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::InvalidAmount) + } + InvalidAmount + }, + { + fn InvalidSignatureLength( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::InvalidSignatureLength) + } + InvalidSignatureLength + }, + { + fn InvalidNonce(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::InvalidNonce) + } + InvalidNonce + }, + { + fn InvalidSigner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::InvalidSigner) + } + InvalidSigner + }, + { + fn InvalidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::InvalidSignature) + } + InvalidSignature + }, + { + fn InvalidContractSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(Permit2Errors::InvalidContractSignature) + } + InvalidContractSignature + }, + { + fn SignatureExpired(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::SignatureExpired) + } + SignatureExpired + }, + { + fn AllowanceExpired(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::AllowanceExpired) + } + AllowanceExpired + }, + { + fn InsufficientAllowance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::InsufficientAllowance) + } + InsufficientAllowance + }, + { + fn LengthMismatch(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Permit2Errors::LengthMismatch) + } + LengthMismatch + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[ + { + fn ExcessiveInvalidation( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::ExcessiveInvalidation) + } + ExcessiveInvalidation + }, + { + fn InvalidAmount(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::InvalidAmount) + } + InvalidAmount + }, + { + fn InvalidSignatureLength( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::InvalidSignatureLength) + } + InvalidSignatureLength + }, + { + fn InvalidNonce(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::InvalidNonce) + } + InvalidNonce + }, + { + fn InvalidSigner(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::InvalidSigner) + } + InvalidSigner + }, + { + fn InvalidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::InvalidSignature) + } + InvalidSignature + }, + { + fn InvalidContractSignature( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::InvalidContractSignature) + } + InvalidContractSignature + }, + { + fn SignatureExpired(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::SignatureExpired) + } + SignatureExpired + }, + { + fn AllowanceExpired(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::AllowanceExpired) + } + AllowanceExpired + }, + { + fn InsufficientAllowance( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::InsufficientAllowance) + } + InsufficientAllowance + }, + { + fn LengthMismatch(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(Permit2Errors::LengthMismatch) + } + LengthMismatch + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::AllowanceExpired(inner) => { + ::abi_encoded_size(inner) + } + Self::ExcessiveInvalidation(inner) => { + ::abi_encoded_size(inner) + } + Self::InsufficientAllowance(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidAmount(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidContractSignature(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidNonce(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidSignature(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidSignatureLength(inner) => { + ::abi_encoded_size(inner) + } + Self::InvalidSigner(inner) => { + ::abi_encoded_size(inner) + } + Self::LengthMismatch(inner) => { + ::abi_encoded_size(inner) + } + Self::SignatureExpired(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::AllowanceExpired(inner) => { + ::abi_encode_raw(inner, out) + } + Self::ExcessiveInvalidation(inner) => { + ::abi_encode_raw(inner, out) + } + Self::InsufficientAllowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::InvalidAmount(inner) => { + ::abi_encode_raw(inner, out) + } + Self::InvalidContractSignature(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::InvalidNonce(inner) => { + ::abi_encode_raw(inner, out) + } + Self::InvalidSignature(inner) => { + ::abi_encode_raw(inner, out) + } + Self::InvalidSignatureLength(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::InvalidSigner(inner) => { + ::abi_encode_raw(inner, out) + } + Self::LengthMismatch(inner) => { + ::abi_encode_raw(inner, out) + } + Self::SignatureExpired(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`Permit2`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum Permit2Events { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + Lockdown(Lockdown), + #[allow(missing_docs)] + NonceInvalidation(NonceInvalidation), + #[allow(missing_docs)] + Permit(Permit), + #[allow(missing_docs)] + UnorderedNonceInvalidation(UnorderedNonceInvalidation), + } + impl Permit2Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 55u8, 4u8, 144u8, 47u8, 150u8, 55u8, 102u8, 164u8, 229u8, 97u8, 187u8, 170u8, + 182u8, 230u8, 205u8, 193u8, 177u8, 221u8, 18u8, 246u8, 233u8, 233u8, 150u8, 72u8, + 218u8, 136u8, 67u8, 179u8, 244u8, 107u8, 145u8, 141u8, + ], + [ + 85u8, 235u8, 144u8, 216u8, 16u8, 225u8, 112u8, 11u8, 53u8, 168u8, 231u8, 226u8, + 83u8, 149u8, 255u8, 127u8, 43u8, 34u8, 89u8, 171u8, 215u8, 65u8, 92u8, 162u8, 40u8, + 77u8, 251u8, 28u8, 36u8, 100u8, 24u8, 243u8, + ], + [ + 137u8, 177u8, 173u8, 209u8, 94u8, 255u8, 86u8, 179u8, 223u8, 226u8, 153u8, 173u8, + 148u8, 224u8, 31u8, 43u8, 82u8, 251u8, 203u8, 128u8, 174u8, 26u8, 59u8, 174u8, + 166u8, 174u8, 140u8, 4u8, 203u8, 43u8, 152u8, 164u8, + ], + [ + 198u8, 163u8, 119u8, 191u8, 196u8, 235u8, 18u8, 0u8, 36u8, 168u8, 172u8, 8u8, + 238u8, 242u8, 5u8, 190u8, 22u8, 184u8, 23u8, 2u8, 8u8, 18u8, 199u8, 50u8, 35u8, + 232u8, 29u8, 27u8, 219u8, 151u8, 8u8, 236u8, + ], + [ + 218u8, 159u8, 167u8, 193u8, 176u8, 4u8, 2u8, 193u8, 125u8, 1u8, 97u8, 178u8, 73u8, + 177u8, 171u8, 139u8, 190u8, 192u8, 71u8, 197u8, 165u8, 34u8, 7u8, 185u8, 193u8, + 18u8, 222u8, 255u8, 216u8, 23u8, 3u8, 107u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(UnorderedNonceInvalidation), + ::core::stringify!(NonceInvalidation), + ::core::stringify!(Lockdown), + ::core::stringify!(Permit), + ::core::stringify!(Approval), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for Permit2Events { + const COUNT: usize = 5usize; + const NAME: &'static str = "Permit2Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Lockdown) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::NonceInvalidation) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Permit) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, data, + ) + .map(Self::UnorderedNonceInvalidation) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Permit2Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Lockdown(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::NonceInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Permit(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::UnorderedNonceInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Lockdown(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::NonceInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Permit(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::UnorderedNonceInvalidation(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Permit2`](self) contract instance. + + See the [wrapper's documentation](`Permit2Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> Permit2Instance { + Permit2Instance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + Permit2Instance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + Permit2Instance::::deploy_builder(__provider) + } + /**A [`Permit2`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Permit2`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct Permit2Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for Permit2Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("Permit2Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + Permit2Instance + { + /**Creates a new wrapper around an on-chain [`Permit2`](self) contract instance. + + See the [wrapper's documentation](`Permit2Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl Permit2Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> Permit2Instance { + Permit2Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + Permit2Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`DOMAIN_SEPARATOR`] function. + pub fn DOMAIN_SEPARATOR( + &self, + ) -> alloy_contract::SolCallBuilder<&P, DOMAIN_SEPARATORCall, N> { + self.call_builder(&DOMAIN_SEPARATORCall) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + _0: alloy_sol_types::private::Address, + _1: alloy_sol_types::private::Address, + _2: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { _0, _1, _2 }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + token: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U160, + expiration: alloy_sol_types::private::primitives::aliases::U48, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { + token, + spender, + amount, + expiration, + }) + } + + ///Creates a new call builder for the [`permit`] function. + pub fn permit( + &self, + owner: alloy_sol_types::private::Address, + permitSingle: ::RustType, + signature: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, permitCall, N> { + self.call_builder(&permitCall { + owner, + permitSingle, + signature, + }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + from: alloy_sol_types::private::Address, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U160, + token: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { + from, + to, + amount, + token, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + Permit2Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Lockdown`] event. + pub fn Lockdown_filter(&self) -> alloy_contract::Event<&P, Lockdown, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`NonceInvalidation`] event. + pub fn NonceInvalidation_filter(&self) -> alloy_contract::Event<&P, NonceInvalidation, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Permit`] event. + pub fn Permit_filter(&self) -> alloy_contract::Event<&P, Permit, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`UnorderedNonceInvalidation`] + /// event. + pub fn UnorderedNonceInvalidation_filter( + &self, + ) -> alloy_contract::Event<&P, UnorderedNonceInvalidation, N> { + self.event_filter::() + } + } +} +pub type Instance = Permit2::Permit2Instance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(15986406u64), + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(38854427u64), + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(25343783u64), + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(27338672u64), + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(35701901u64), + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(1425180u64), + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(7808u64), + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(38692735u64), + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(28844415u64), + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(0u64), + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), + Some(2356287u64), + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/remoteerc20balances/Cargo.toml b/contracts/generated/contracts-generated/remoteerc20balances/Cargo.toml new file mode 100644 index 0000000000..af047dacde --- /dev/null +++ b/contracts/generated/contracts-generated/remoteerc20balances/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-remoteerc20balances" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/remoteerc20balances/src/lib.rs b/contracts/generated/contracts-generated/remoteerc20balances/src/lib.rs new file mode 100644 index 0000000000..8178b3dc19 --- /dev/null +++ b/contracts/generated/contracts-generated/remoteerc20balances/src/lib.rs @@ -0,0 +1,1909 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface RemoteERC20Balances { + constructor(address _target, bool _balanceFromHere); + + function allowance(address user, address spender) external view returns (uint256); + function approve(address spender, uint256 amount) external; + function balanceOf(address user) external view returns (uint256); + function mint(address user, uint256 amount) external; + function target() external view returns (address); + function transfer(address to, uint256 amount) external; + function transferFrom(address from, address to, uint256 amount) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_target", + "type": "address", + "internalType": "contract NonStandardERC20Balances" + }, + { + "name": "_balanceFromHere", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "user", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "target", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract NonStandardERC20Balances" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod RemoteERC20Balances { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60c060405234801561000f575f5ffd5b5060405161071338038061071383398101604081905261002e91610044565b15156080526001600160a01b031660a05261008b565b5f5f60408385031215610055575f5ffd5b82516001600160a01b038116811461006b575f5ffd5b60208401519092508015158114610080575f5ffd5b809150509250929050565b60805160a0516106606100b35f395f8181610154015261032301525f61039001526106605ff3fe608060405234801561000f575f5ffd5b506004361061007a575f3560e01c806370a082311161005857806370a0823114610116578063a9059cbb1461013c578063d4b839921461014f578063dd62ed3e1461019b575f5ffd5b8063095ea7b31461007e57806323b872dd146100c657806340c10f19146100d9575b5f5ffd5b6100c461008c366004610506565b335f9081526020818152604080832073ffffffffffffffffffffffffffffffffffffffff959095168352600190940190529190912055565b005b6100c46100d436600461052e565b6101ae565b6100c46100e7366004610506565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526020819052604090206001815560020155565b610129610124366004610568565b6102da565b6040519081526020015b60405180910390f35b6100c461014a366004610506565b6103e9565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610133565b6101296101a9366004610581565b6104a3565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260208181526040808320338452600101909152812080548392906101ee9084906105df565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f908152602081905260408120600201805483929061022a9084906105df565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f90815260208190526040812080549161025f836105f2565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f908152602081905260408120600201805483929061029b908490610629565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f9081526020819052604081208054916102d0836105f2565b9190505550505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f9182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038c919061063c565b90507f00000000000000000000000000000000000000000000000000000000000000006103b957806103e2565b73ffffffffffffffffffffffffffffffffffffffff83165f908152602081905260409020600201545b9392505050565b335f908152602081905260408120600201805483929061040a9084906105df565b9091555050335f908152602081905260408120805491610429836105f2565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f9081526020819052604081206002018054839290610465908490610629565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f90815260208190526040812080549161049a836105f2565b91905055505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683526001909301905220545b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610501575f5ffd5b919050565b5f5f60408385031215610517575f5ffd5b610520836104de565b946020939093013593505050565b5f5f5f60608486031215610540575f5ffd5b610549846104de565b9250610557602085016104de565b929592945050506040919091013590565b5f60208284031215610578575f5ffd5b6103e2826104de565b5f5f60408385031215610592575f5ffd5b61059b836104de565b91506105a9602084016104de565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156104d8576104d86105b2565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610622576106226105b2565b5060010190565b808201808211156104d8576104d86105b2565b5f6020828403121561064c575f5ffd5b505191905056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xC0`@R4\x80\x15a\0\x0FW__\xFD[P`@Qa\x07\x138\x03\x80a\x07\x13\x839\x81\x01`@\x81\x90Ra\0.\x91a\0DV[\x15\x15`\x80R`\x01`\x01`\xA0\x1B\x03\x16`\xA0Ra\0\x8BV[__`@\x83\x85\x03\x12\x15a\0UW__\xFD[\x82Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0kW__\xFD[` \x84\x01Q\x90\x92P\x80\x15\x15\x81\x14a\0\x80W__\xFD[\x80\x91PP\x92P\x92\x90PV[`\x80Q`\xA0Qa\x06`a\0\xB3_9_\x81\x81a\x01T\x01Ra\x03#\x01R_a\x03\x90\x01Ra\x06`_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0zW_5`\xE0\x1C\x80cp\xA0\x821\x11a\0XW\x80cp\xA0\x821\x14a\x01\x16W\x80c\xA9\x05\x9C\xBB\x14a\x01\x14a\x01\x9BW__\xFD[\x80c\t^\xA7\xB3\x14a\0~W\x80c#\xB8r\xDD\x14a\0\xC6W\x80c@\xC1\x0F\x19\x14a\0\xD9W[__\xFD[a\0\xC4a\0\x8C6`\x04a\x05\x06V[3_\x90\x81R` \x81\x81R`@\x80\x83 s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x95\x90\x95\x16\x83R`\x01\x90\x94\x01\x90R\x91\x90\x91 UV[\0[a\0\xC4a\0\xD46`\x04a\x05.V[a\x01\xAEV[a\0\xC4a\0\xE76`\x04a\x05\x06V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16_\x90\x81R` \x81\x90R`@\x90 `\x01\x81U`\x02\x01UV[a\x01)a\x01$6`\x04a\x05hV[a\x02\xDAV[`@Q\x90\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[a\0\xC4a\x01J6`\x04a\x05\x06V[a\x03\xE9V[a\x01v\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x013V[a\x01)a\x01\xA96`\x04a\x05\x81V[a\x04\xA3V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x81R`@\x80\x83 3\x84R`\x01\x01\x90\x91R\x81 \x80T\x83\x92\x90a\x01\xEE\x90\x84\x90a\x05\xDFV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02*\x90\x84\x90a\x05\xDFV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02_\x83a\x05\xF2V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02\x9B\x90\x84\x90a\x06)V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02\xD0\x83a\x05\xF2V[\x91\x90PUPPPPV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x81\x16`\x04\x83\x01R_\x91\x82\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03hW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03\x8C\x91\x90a\x06\x14a\x01\x9BW__\xFD[\x80c\t^\xA7\xB3\x14a\0~W\x80c#\xB8r\xDD\x14a\0\xC6W\x80c@\xC1\x0F\x19\x14a\0\xD9W[__\xFD[a\0\xC4a\0\x8C6`\x04a\x05\x06V[3_\x90\x81R` \x81\x81R`@\x80\x83 s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x95\x90\x95\x16\x83R`\x01\x90\x94\x01\x90R\x91\x90\x91 UV[\0[a\0\xC4a\0\xD46`\x04a\x05.V[a\x01\xAEV[a\0\xC4a\0\xE76`\x04a\x05\x06V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16_\x90\x81R` \x81\x90R`@\x90 `\x01\x81U`\x02\x01UV[a\x01)a\x01$6`\x04a\x05hV[a\x02\xDAV[`@Q\x90\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[a\0\xC4a\x01J6`\x04a\x05\x06V[a\x03\xE9V[a\x01v\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01a\x013V[a\x01)a\x01\xA96`\x04a\x05\x81V[a\x04\xA3V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x81R`@\x80\x83 3\x84R`\x01\x01\x90\x91R\x81 \x80T\x83\x92\x90a\x01\xEE\x90\x84\x90a\x05\xDFV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02*\x90\x84\x90a\x05\xDFV[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02_\x83a\x05\xF2V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 `\x02\x01\x80T\x83\x92\x90a\x02\x9B\x90\x84\x90a\x06)V[\x90\x91UPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16_\x90\x81R` \x81\x90R`@\x81 \x80T\x91a\x02\xD0\x83a\x05\xF2V[\x91\x90PUPPPPV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x81\x16`\x04\x83\x01R_\x91\x82\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03hW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03\x8C\x91\x90a\x06 = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address, bool); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._target, value._balanceFromHere) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _target: tuple.0, + _balanceFromHere: tuple.1, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._target, + ), + ::tokenize( + &self._balanceFromHere, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address user, address spender) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.user, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + user: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + ::tokenize( + &self.spender, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address spender, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl approveReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = approveReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + approveReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address user) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.user,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { user: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address,uint256)` and selector `0x40c10f19`. + ```solidity + function mint(address user, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub user: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`mint(address,uint256)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + (value.user, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + user: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl mintReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = mintReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [64u8, 193u8, 15u8, 25u8]; + const SIGNATURE: &'static str = "mint(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.user, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + mintReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `target()` and selector `0xd4b83992`. + ```solidity + function target() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct targetCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`target()`](targetCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct targetReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: targetCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for targetCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: targetReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for targetReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for targetCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [212u8, 184u8, 57u8, 146u8]; + const SIGNATURE: &'static str = "target()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: targetReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: targetReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address to, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.to, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + amount: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl transferReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = transferReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + transferReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address from, address to, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub from: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.from, value.to, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + from: tuple.0, + to: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl transferFromReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = transferFromReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.from, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + transferFromReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`RemoteERC20Balances`](self) function calls. + #[derive(Clone)] + pub enum RemoteERC20BalancesCalls { + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + target(targetCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + impl RemoteERC20BalancesCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [9u8, 94u8, 167u8, 179u8], + [35u8, 184u8, 114u8, 221u8], + [64u8, 193u8, 15u8, 25u8], + [112u8, 160u8, 130u8, 49u8], + [169u8, 5u8, 156u8, 187u8], + [212u8, 184u8, 57u8, 146u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(approve), + ::core::stringify!(transferFrom), + ::core::stringify!(mint), + ::core::stringify!(balanceOf), + ::core::stringify!(transfer), + ::core::stringify!(target), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for RemoteERC20BalancesCalls { + const COUNT: usize = 7usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "RemoteERC20BalancesCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::target(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(RemoteERC20BalancesCalls::approve) + } + approve + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(RemoteERC20BalancesCalls::transferFrom) + } + transferFrom + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(RemoteERC20BalancesCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(RemoteERC20BalancesCalls::balanceOf) + } + balanceOf + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(RemoteERC20BalancesCalls::transfer) + } + transfer + }, + { + fn target(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(RemoteERC20BalancesCalls::target) + } + target + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(RemoteERC20BalancesCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + RemoteERC20BalancesCalls, + >] = &[ + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(RemoteERC20BalancesCalls::approve) + } + approve + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(RemoteERC20BalancesCalls::transferFrom) + } + transferFrom + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(RemoteERC20BalancesCalls::mint) + } + mint + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(RemoteERC20BalancesCalls::balanceOf) + } + balanceOf + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(RemoteERC20BalancesCalls::transfer) + } + transfer + }, + { + fn target(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(RemoteERC20BalancesCalls::target) + } + target + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(RemoteERC20BalancesCalls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::target(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::target(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`RemoteERC20Balances`](self) contract instance. + + See the [wrapper's documentation](`RemoteERC20BalancesInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> RemoteERC20BalancesInstance { + RemoteERC20BalancesInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _target: alloy_sol_types::private::Address, + _balanceFromHere: bool, + ) -> impl ::core::future::Future>> + { + RemoteERC20BalancesInstance::::deploy(__provider, _target, _balanceFromHere) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _target: alloy_sol_types::private::Address, + _balanceFromHere: bool, + ) -> alloy_contract::RawCallBuilder { + RemoteERC20BalancesInstance::::deploy_builder(__provider, _target, _balanceFromHere) + } + /**A [`RemoteERC20Balances`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`RemoteERC20Balances`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct RemoteERC20BalancesInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for RemoteERC20BalancesInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("RemoteERC20BalancesInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + RemoteERC20BalancesInstance + { + /**Creates a new wrapper around an on-chain [`RemoteERC20Balances`](self) contract instance. + + See the [wrapper's documentation](`RemoteERC20BalancesInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _target: alloy_sol_types::private::Address, + _balanceFromHere: bool, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, _target, _balanceFromHere); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _target: alloy_sol_types::private::Address, + _balanceFromHere: bool, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + _target, + _balanceFromHere, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl RemoteERC20BalancesInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> RemoteERC20BalancesInstance { + RemoteERC20BalancesInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + RemoteERC20BalancesInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + user: alloy_sol_types::private::Address, + spender: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { user, spender }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, amount }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + user: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { user }) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + user: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { user, amount }) + } + + ///Creates a new call builder for the [`target`] function. + pub fn target(&self) -> alloy_contract::SolCallBuilder<&P, targetCall, N> { + self.call_builder(&targetCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { to, amount }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + from: alloy_sol_types::private::Address, + to: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { from, to, amount }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + RemoteERC20BalancesInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = RemoteERC20Balances::RemoteERC20BalancesInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/signatures/Cargo.toml b/contracts/generated/contracts-generated/signatures/Cargo.toml new file mode 100644 index 0000000000..19b023805a --- /dev/null +++ b/contracts/generated/contracts-generated/signatures/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-signatures" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/signatures/src/lib.rs b/contracts/generated/contracts-generated/signatures/src/lib.rs new file mode 100644 index 0000000000..c787ca99df --- /dev/null +++ b/contracts/generated/contracts-generated/signatures/src/lib.rs @@ -0,0 +1,1171 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface Signatures { + struct Contracts { + address settlement; + address vaultRelayer; + } + struct Interaction { + address target; + uint256 value; + bytes callData; + } + + function validate(Contracts memory contracts, address signer, bytes32 order, bytes memory signature, Interaction[] memory interactions) external returns (uint256 gasUsed); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "validate", + "inputs": [ + { + "name": "contracts", + "type": "tuple", + "internalType": "struct Signatures.Contracts", + "components": [ + { + "name": "settlement", + "type": "address", + "internalType": "contract ISettlement" + }, + { + "name": "vaultRelayer", + "type": "address", + "internalType": "contract IVaultRelayer" + } + ] + }, + { + "name": "signer", + "type": "address", + "internalType": "contract IERC1271" + }, + { + "name": "order", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "signature", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "interactions", + "type": "tuple[]", + "internalType": "struct Interaction[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "gasUsed", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Signatures { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b506107238061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b46054151461002d575b5f5ffd5b61004061003b366004610450565b610052565b60405190815260200160405180910390f35b5f61005e8884846101a9565b5a90505f8773ffffffffffffffffffffffffffffffffffffffff16631626ba7e8888886040518463ffffffff1660e01b815260040161009f9392919061055a565b602060405180830381865afa1580156100ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100de91906105ad565b90505a6100eb90836105f3565b91507fffffffff0000000000000000000000000000000000000000000000000000000081167f1626ba7e000000000000000000000000000000000000000000000000000000001461019d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6469646e27742073617920746865206d6167696320776f72640000000000000060448201526064015b60405180910390fd5b50979650505050505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e74657874000000000000006044820152606401610194565b5f5b81811015610390575f83838381811061024657610246610631565b9050602002810190610258919061065e565b61026690602081019061069a565b90505f84848481811061027b5761027b610631565b905060200281019061028d919061065e565b602001359050365f8686868181106102a7576102a7610631565b90506020028101906102b9919061065e565b6102c79060408101906106b5565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e00000000006044820152606401610194565b604051818382375f5f838387895af161037f573d5f5f3e3d5ffd5b50506001909301925061022b915050565b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146103b7575f5ffd5b50565b80356103c581610396565b919050565b5f5f83601f8401126103da575f5ffd5b50813567ffffffffffffffff8111156103f1575f5ffd5b602083019150836020828501011115610408575f5ffd5b9250929050565b5f5f83601f84011261041f575f5ffd5b50813567ffffffffffffffff811115610436575f5ffd5b6020830191508360208260051b8501011115610408575f5ffd5b5f5f5f5f5f5f5f87890360c0811215610467575f5ffd5b6040811215610474575f5ffd5b506040516040810181811067ffffffffffffffff821117156104bd577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405288356104cb81610396565b815260208901356104db81610396565b602082015296506104ee604089016103ba565b955060608801359450608088013567ffffffffffffffff811115610510575f5ffd5b61051c8a828b016103ca565b90955093505060a088013567ffffffffffffffff81111561053b575f5ffd5b6105478a828b0161040f565b989b979a50959850939692959293505050565b83815260406020820152816040820152818360608301375f818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b5f602082840312156105bd575f5ffd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146105ec575f5ffd5b9392505050565b8181038181111561062b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610690575f5ffd5b9190910192915050565b5f602082840312156106aa575f5ffd5b81356105ec81610396565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126106e8575f5ffd5b83018035915067ffffffffffffffff821115610702575f5ffd5b602001915036819003821315610408575f5ffdfea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x07#\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c\xB4`T\x15\x14a\0-W[__\xFD[a\0@a\0;6`\x04a\x04PV[a\0RV[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[_a\0^\x88\x84\x84a\x01\xA9V[Z\x90P_\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x16&\xBA~\x88\x88\x88`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\0\x9F\x93\x92\x91\x90a\x05ZV[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xBAW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xDE\x91\x90a\x05\xADV[\x90PZa\0\xEB\x90\x83a\x05\xF3V[\x91P\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x14a\x01\x9DW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7Fdidn't say the magic word\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[P\x97\x96PPPPPPPV[\x82Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x160\x14a\x02)W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7Fincorrect calling context\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01\x94V[_[\x81\x81\x10\x15a\x03\x90W_\x83\x83\x83\x81\x81\x10a\x02FWa\x02Fa\x061V[\x90P` \x02\x81\x01\x90a\x02X\x91\x90a\x06^V[a\x02f\x90` \x81\x01\x90a\x06\x9AV[\x90P_\x84\x84\x84\x81\x81\x10a\x02{Wa\x02{a\x061V[\x90P` \x02\x81\x01\x90a\x02\x8D\x91\x90a\x06^V[` \x015\x90P6_\x86\x86\x86\x81\x81\x10a\x02\xA7Wa\x02\xA7a\x061V[\x90P` \x02\x81\x01\x90a\x02\xB9\x91\x90a\x06^V[a\x02\xC7\x90`@\x81\x01\x90a\x06\xB5V[\x91P\x91P\x87` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03a\x03dW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FGPv2: forbidden interaction\0\0\0\0\0`D\x82\x01R`d\x01a\x01\x94V[`@Q\x81\x83\x827__\x83\x83\x87\x89Z\xF1a\x03\x7FW=__>=_\xFD[PP`\x01\x90\x93\x01\x92Pa\x02+\x91PPV[PPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x03\xB7W__\xFD[PV[\x805a\x03\xC5\x81a\x03\x96V[\x91\x90PV[__\x83`\x1F\x84\x01\x12a\x03\xDAW__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x03\xF1W__\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\x04\x08W__\xFD[\x92P\x92\x90PV[__\x83`\x1F\x84\x01\x12a\x04\x1FW__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x046W__\xFD[` \x83\x01\x91P\x83` \x82`\x05\x1B\x85\x01\x01\x11\x15a\x04\x08W__\xFD[_______\x87\x89\x03`\xC0\x81\x12\x15a\x04gW__\xFD[`@\x81\x12\x15a\x04tW__\xFD[P`@Q`@\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xBDW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@R\x885a\x04\xCB\x81a\x03\x96V[\x81R` \x89\x015a\x04\xDB\x81a\x03\x96V[` \x82\x01R\x96Pa\x04\xEE`@\x89\x01a\x03\xBAV[\x95P``\x88\x015\x94P`\x80\x88\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x05\x10W__\xFD[a\x05\x1C\x8A\x82\x8B\x01a\x03\xCAV[\x90\x95P\x93PP`\xA0\x88\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x05;W__\xFD[a\x05G\x8A\x82\x8B\x01a\x04\x0FV[\x98\x9B\x97\x9AP\x95\x98P\x93\x96\x92\x95\x92\x93PPPV[\x83\x81R`@` \x82\x01R\x81`@\x82\x01R\x81\x83``\x83\x017_\x81\x83\x01``\x90\x81\x01\x91\x90\x91R`\x1F\x90\x92\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x01\x01\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x05\xBDW__\xFD[\x81Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x81\x14a\x05\xECW__\xFD[\x93\x92PPPV[\x81\x81\x03\x81\x81\x11\x15a\x06+W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x92\x91PPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[_\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xA1\x836\x03\x01\x81\x12a\x06\x90W__\xFD[\x91\x90\x91\x01\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x06\xAAW__\xFD[\x815a\x05\xEC\x81a\x03\x96V[__\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x06\xE8W__\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x07\x02W__\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\x04\x08W__\xFD\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b46054151461002d575b5f5ffd5b61004061003b366004610450565b610052565b60405190815260200160405180910390f35b5f61005e8884846101a9565b5a90505f8773ffffffffffffffffffffffffffffffffffffffff16631626ba7e8888886040518463ffffffff1660e01b815260040161009f9392919061055a565b602060405180830381865afa1580156100ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100de91906105ad565b90505a6100eb90836105f3565b91507fffffffff0000000000000000000000000000000000000000000000000000000081167f1626ba7e000000000000000000000000000000000000000000000000000000001461019d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6469646e27742073617920746865206d6167696320776f72640000000000000060448201526064015b60405180910390fd5b50979650505050505050565b825173ffffffffffffffffffffffffffffffffffffffff163014610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e636f72726563742063616c6c696e6720636f6e74657874000000000000006044820152606401610194565b5f5b81811015610390575f83838381811061024657610246610631565b9050602002810190610258919061065e565b61026690602081019061069a565b90505f84848481811061027b5761027b610631565b905060200281019061028d919061065e565b602001359050365f8686868181106102a7576102a7610631565b90506020028101906102b9919061065e565b6102c79060408101906106b5565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f475076323a20666f7262696464656e20696e746572616374696f6e00000000006044820152606401610194565b604051818382375f5f838387895af161037f573d5f5f3e3d5ffd5b50506001909301925061022b915050565b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146103b7575f5ffd5b50565b80356103c581610396565b919050565b5f5f83601f8401126103da575f5ffd5b50813567ffffffffffffffff8111156103f1575f5ffd5b602083019150836020828501011115610408575f5ffd5b9250929050565b5f5f83601f84011261041f575f5ffd5b50813567ffffffffffffffff811115610436575f5ffd5b6020830191508360208260051b8501011115610408575f5ffd5b5f5f5f5f5f5f5f87890360c0811215610467575f5ffd5b6040811215610474575f5ffd5b506040516040810181811067ffffffffffffffff821117156104bd577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405288356104cb81610396565b815260208901356104db81610396565b602082015296506104ee604089016103ba565b955060608801359450608088013567ffffffffffffffff811115610510575f5ffd5b61051c8a828b016103ca565b90955093505060a088013567ffffffffffffffff81111561053b575f5ffd5b6105478a828b0161040f565b989b979a50959850939692959293505050565b83815260406020820152816040820152818360608301375f818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b5f602082840312156105bd575f5ffd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146105ec575f5ffd5b9392505050565b8181038181111561062b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610690575f5ffd5b9190910192915050565b5f602082840312156106aa575f5ffd5b81356105ec81610396565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126106e8575f5ffd5b83018035915067ffffffffffffffff821115610702575f5ffd5b602001915036819003821315610408575f5ffdfea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c\xB4`T\x15\x14a\0-W[__\xFD[a\0@a\0;6`\x04a\x04PV[a\0RV[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3[_a\0^\x88\x84\x84a\x01\xA9V[Z\x90P_\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x16&\xBA~\x88\x88\x88`@Q\x84c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01a\0\x9F\x93\x92\x91\x90a\x05ZV[` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\0\xBAW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\0\xDE\x91\x90a\x05\xADV[\x90PZa\0\xEB\x90\x83a\x05\xF3V[\x91P\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x14a\x01\x9DW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7Fdidn't say the magic word\0\0\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[P\x97\x96PPPPPPPV[\x82Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x160\x14a\x02)W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x19`$\x82\x01R\x7Fincorrect calling context\0\0\0\0\0\0\0`D\x82\x01R`d\x01a\x01\x94V[_[\x81\x81\x10\x15a\x03\x90W_\x83\x83\x83\x81\x81\x10a\x02FWa\x02Fa\x061V[\x90P` \x02\x81\x01\x90a\x02X\x91\x90a\x06^V[a\x02f\x90` \x81\x01\x90a\x06\x9AV[\x90P_\x84\x84\x84\x81\x81\x10a\x02{Wa\x02{a\x061V[\x90P` \x02\x81\x01\x90a\x02\x8D\x91\x90a\x06^V[` \x015\x90P6_\x86\x86\x86\x81\x81\x10a\x02\xA7Wa\x02\xA7a\x061V[\x90P` \x02\x81\x01\x90a\x02\xB9\x91\x90a\x06^V[a\x02\xC7\x90`@\x81\x01\x90a\x06\xB5V[\x91P\x91P\x87` \x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03a\x03dW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FGPv2: forbidden interaction\0\0\0\0\0`D\x82\x01R`d\x01a\x01\x94V[`@Q\x81\x83\x827__\x83\x83\x87\x89Z\xF1a\x03\x7FW=__>=_\xFD[PP`\x01\x90\x93\x01\x92Pa\x02+\x91PPV[PPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x03\xB7W__\xFD[PV[\x805a\x03\xC5\x81a\x03\x96V[\x91\x90PV[__\x83`\x1F\x84\x01\x12a\x03\xDAW__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x03\xF1W__\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\x04\x08W__\xFD[\x92P\x92\x90PV[__\x83`\x1F\x84\x01\x12a\x04\x1FW__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x046W__\xFD[` \x83\x01\x91P\x83` \x82`\x05\x1B\x85\x01\x01\x11\x15a\x04\x08W__\xFD[_______\x87\x89\x03`\xC0\x81\x12\x15a\x04gW__\xFD[`@\x81\x12\x15a\x04tW__\xFD[P`@Q`@\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xBDW\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[`@R\x885a\x04\xCB\x81a\x03\x96V[\x81R` \x89\x015a\x04\xDB\x81a\x03\x96V[` \x82\x01R\x96Pa\x04\xEE`@\x89\x01a\x03\xBAV[\x95P``\x88\x015\x94P`\x80\x88\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x05\x10W__\xFD[a\x05\x1C\x8A\x82\x8B\x01a\x03\xCAV[\x90\x95P\x93PP`\xA0\x88\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x05;W__\xFD[a\x05G\x8A\x82\x8B\x01a\x04\x0FV[\x98\x9B\x97\x9AP\x95\x98P\x93\x96\x92\x95\x92\x93PPPV[\x83\x81R`@` \x82\x01R\x81`@\x82\x01R\x81\x83``\x83\x017_\x81\x83\x01``\x90\x81\x01\x91\x90\x91R`\x1F\x90\x92\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x01\x01\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x05\xBDW__\xFD[\x81Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x81\x14a\x05\xECW__\xFD[\x93\x92PPPV[\x81\x81\x03\x81\x81\x11\x15a\x06+W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x92\x91PPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[_\x825\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xA1\x836\x03\x01\x81\x12a\x06\x90W__\xFD[\x91\x90\x91\x01\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x06\xAAW__\xFD[\x815a\x05\xEC\x81a\x03\x96V[__\x835\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE1\x846\x03\x01\x81\x12a\x06\xE8W__\xFD[\x83\x01\x805\x91Pg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x07\x02W__\xFD[` \x01\x91P6\x81\x90\x03\x82\x13\x15a\x04\x08W__\xFD\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Contracts { address settlement; address vaultRelayer; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Contracts { + #[allow(missing_docs)] + pub settlement: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub vaultRelayer: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Contracts) -> Self { + (value.settlement, value.vaultRelayer) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Contracts { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + settlement: tuple.0, + vaultRelayer: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Contracts { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Contracts { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.settlement, + ), + ::tokenize( + &self.vaultRelayer, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Contracts { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Contracts { + const NAME: &'static str = "Contracts"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Contracts(address settlement,address vaultRelayer)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.settlement, + ) + .0, + ::eip712_data_word( + &self.vaultRelayer, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Contracts { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.settlement, + ) + + ::topic_preimage_length( + &rust.vaultRelayer, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.settlement, + out, + ); + ::encode_topic_preimage( + &rust.vaultRelayer, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Interaction { address target; uint256 value; bytes callData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Interaction { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub callData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Interaction) -> Self { + (value.target, value.value, value.callData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Interaction { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + value: tuple.1, + callData: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Interaction { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Interaction { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.target, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.callData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Interaction { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Interaction { + const NAME: &'static str = "Interaction"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Interaction(address target,uint256 value,bytes callData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.target, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.value) + .0, + ::eip712_data_word( + &self.callData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Interaction { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.target, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.value) + + ::topic_preimage_length( + &rust.callData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.target, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.value, + out, + ); + ::encode_topic_preimage( + &rust.callData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `validate((address,address),address,bytes32,bytes,(address,uint256,bytes)[])` and selector `0xb4605415`. + ```solidity + function validate(Contracts memory contracts, address signer, bytes32 order, bytes memory signature, Interaction[] memory interactions) external returns (uint256 gasUsed); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct validateCall { + #[allow(missing_docs)] + pub contracts: ::RustType, + #[allow(missing_docs)] + pub signer: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub order: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub signature: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub interactions: + alloy_sol_types::private::Vec<::RustType>, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`validate((address,address),address,bytes32,bytes,(address,uint256, + /// bytes)[])`](validateCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct validateReturn { + #[allow(missing_docs)] + pub gasUsed: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + Contracts, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Array, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + ::RustType, + alloy_sol_types::private::Address, + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + alloy_sol_types::private::Vec<::RustType>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: validateCall) -> Self { + ( + value.contracts, + value.signer, + value.order, + value.signature, + value.interactions, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for validateCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + contracts: tuple.0, + signer: tuple.1, + order: tuple.2, + signature: tuple.3, + interactions: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: validateReturn) -> Self { + (value.gasUsed,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for validateReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { gasUsed: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for validateCall { + type Parameters<'a> = ( + Contracts, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Array, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [180u8, 96u8, 84u8, 21u8]; + const SIGNATURE: &'static str = + "validate((address,address),address,bytes32,bytes,(address,uint256,bytes)[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize(&self.contracts), + ::tokenize( + &self.signer, + ), + as alloy_sol_types::SolType>::tokenize(&self.order), + ::tokenize( + &self.signature, + ), + as alloy_sol_types::SolType>::tokenize(&self.interactions), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: validateReturn = r.into(); + r.gasUsed + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: validateReturn = r.into(); + r.gasUsed + }) + } + } + }; + ///Container for all the [`Signatures`](self) function calls. + #[derive(Clone)] + pub enum SignaturesCalls { + #[allow(missing_docs)] + validate(validateCall), + } + impl SignaturesCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[180u8, 96u8, 84u8, 21u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(validate)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for SignaturesCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 256usize; + const NAME: &'static str = "SignaturesCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::validate(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[{ + fn validate(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SignaturesCalls::validate) + } + validate + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[{ + fn validate(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SignaturesCalls::validate) + } + validate + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::validate(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::validate(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Signatures`](self) contract instance. + + See the [wrapper's documentation](`SignaturesInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> SignaturesInstance { + SignaturesInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> + { + SignaturesInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + SignaturesInstance::::deploy_builder(__provider) + } + /**A [`Signatures`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Signatures`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct SignaturesInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for SignaturesInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("SignaturesInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + SignaturesInstance + { + /**Creates a new wrapper around an on-chain [`Signatures`](self) contract instance. + + See the [wrapper's documentation](`SignaturesInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl SignaturesInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> SignaturesInstance { + SignaturesInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + SignaturesInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`validate`] function. + pub fn validate( + &self, + contracts: ::RustType, + signer: alloy_sol_types::private::Address, + order: alloy_sol_types::private::FixedBytes<32>, + signature: alloy_sol_types::private::Bytes, + interactions: alloy_sol_types::private::Vec< + ::RustType, + >, + ) -> alloy_contract::SolCallBuilder<&P, validateCall, N> { + self.call_builder(&validateCall { + contracts, + signer, + order, + signature, + interactions, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + SignaturesInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = Signatures::SignaturesInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0xf6E57e72F7dB3D9A51a8B4c149C00475b94A37e4"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/solver/Cargo.toml b/contracts/generated/contracts-generated/solver/Cargo.toml new file mode 100644 index 0000000000..8f6ee5bae2 --- /dev/null +++ b/contracts/generated/contracts-generated/solver/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-solver" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/solver/src/lib.rs b/contracts/generated/contracts-generated/solver/src/lib.rs new file mode 100644 index 0000000000..5985799cf8 --- /dev/null +++ b/contracts/generated/contracts-generated/solver/src/lib.rs @@ -0,0 +1,911 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface Solver { + function storeBalance(address token, address owner, bool countGas) external; + function swap(address settlementContract, address[] memory tokens, address payable receiver, address trader, address sellToken, uint256 sellAmount, address settleCallTarget, bytes memory settlementCall) external returns (uint256 gasUsed, uint256[] memory queriedBalances); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "storeBalance", + "inputs": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "countGas", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "settlementContract", + "type": "address", + "internalType": "contract ISettlement" + }, + { + "name": "tokens", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "receiver", + "type": "address", + "internalType": "address payable" + }, + { + "name": "trader", + "type": "address", + "internalType": "address" + }, + { + "name": "sellToken", + "type": "address", + "internalType": "address" + }, + { + "name": "sellAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "settleCallTarget", + "type": "address", + "internalType": "address" + }, + { + "name": "settlementCall", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "gasUsed", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "queriedBalances", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Solver { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b50610acb8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80633bbb2e1d146100385780638581192b1461004d575b5f5ffd5b61004b610046366004610805565b610077565b005b61006061005b366004610896565b6101e6565b60405161006e929190610997565b60405180910390f35b5f5a90507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff861614610160576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528616906370a0823190602401602060405180830381865afa158015610137573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061015b91906109e4565b610179565b8373ffffffffffffffffffffffffffffffffffffffff16315b81546001810183555f92835260209092209091015581156101e0575a61019f9082610a28565b6101ab9061116c610a41565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f8282546101da9190610a41565b90915550505b50505050565b5f60606101f58c8989896102f7565b5f8973ffffffffffffffffffffffffffffffffffffffff165f6040515f6040518083038185875af1925050503d805f811461024b576040519150601f19603f3d011682016040523d82523d5f602084013e610250565b606091505b50509050506102608b8b8e61066f565b61026b858585610739565b91506102788b8b8e61066f565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c8054806020026020016040519081016040528092919081815260200182805480156102e157602002820191905f5260205f20905b8154815260200190600101908083116102cd575b505050505090509a509a98505050505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610341573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103659190610a54565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015280831660248301529192505f9185169063dd62ed3e90604401602060405180830381865afa1580156103dc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040091906109e4565b905082811015610497576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f74726164657220646964206e6f7420676976652074686520726571756972656460448201527f20617070726f76616c730000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301525f91908616906370a0823190602401602060405180830381865afa158015610504573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052891906109e4565b90508381101561066657731111111111111111111111111111111111111111636a52902687876105588589610a28565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064015f604051808303815f87803b1580156105c9575f5ffd5b505af19250505080156105da575060015b610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f74726164657220646f6573206e6f74206861766520656e6f7567682073656c6c60448201527f20746f6b656e0000000000000000000000000000000000000000000000000000606482015260840161048e565b50505050505050565b5f5b828110156101e05730633bbb2e1d85858481811061069157610691610a76565b90506020020160208101906106a69190610aa3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff918216600482015290851660248201525f60448201526064015f604051808303815f87803b158015610717575f5ffd5b505af1158015610729573d5f5f3e3d5ffd5b5050600190920191506106719050565b5f5f5a90505f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525084519495509384935091505060208401828a5af1610790573d5f5f3e3d5ffd5b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b545a6107bd9084610a28565b6107c79190610a28565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107f2575f5ffd5b50565b8035610800816107d1565b919050565b5f5f5f60608486031215610817575f5ffd5b8335610822816107d1565b92506020840135610832816107d1565b915060408401358015158114610846575f5ffd5b809150509250925092565b5f5f83601f840112610861575f5ffd5b50813567ffffffffffffffff811115610878575f5ffd5b60208301915083602082850101111561088f575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f5f5f6101008b8d0312156108b0575f5ffd5b8a356108bb816107d1565b995060208b013567ffffffffffffffff8111156108d6575f5ffd5b8b01601f81018d136108e6575f5ffd5b803567ffffffffffffffff8111156108fc575f5ffd5b8d60208260051b8401011115610910575f5ffd5b6020919091019950975061092660408c016107f5565b965061093460608c016107f5565b955061094260808c016107f5565b945060a08b0135935061095760c08c016107f5565b925060e08b013567ffffffffffffffff811115610972575f5ffd5b61097e8d828e01610851565b915080935050809150509295989b9194979a5092959850565b5f60408201848352604060208401528084518083526060850191506020860192505f5b818110156109d85783518352602093840193909201916001016109ba565b50909695505050505050565b5f602082840312156109f4575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610a3b57610a3b6109fb565b92915050565b80820180821115610a3b57610a3b6109fb565b5f60208284031215610a64575f5ffd5b8151610a6f816107d1565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215610ab3575f5ffd5b8135610a6f816107d156fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\n\xCB\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80c;\xBB.\x1D\x14a\08W\x80c\x85\x81\x19+\x14a\0MW[__\xFD[a\0Ka\0F6`\x04a\x08\x05V[a\0wV[\0[a\0`a\0[6`\x04a\x08\x96V[a\x01\xE6V[`@Qa\0n\x92\x91\x90a\t\x97V[`@Q\x80\x91\x03\x90\xF3[_Z\x90P\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r,s\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEEs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x16\x14a\x01`W`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`\x04\x83\x01R\x86\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x017W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01[\x91\x90a\t\xE4V[a\x01yV[\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x161[\x81T`\x01\x81\x01\x83U_\x92\x83R` \x90\x92 \x90\x91\x01U\x81\x15a\x01\xE0WZa\x01\x9F\x90\x82a\n(V[a\x01\xAB\x90a\x11la\nAV[\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r+_\x82\x82Ta\x01\xDA\x91\x90a\nAV[\x90\x91UPP[PPPPV[_``a\x01\xF5\x8C\x89\x89\x89a\x02\xF7V[_\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16_`@Q_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x02KW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x02PV[``\x91P[PP\x90PPa\x02`\x8B\x8B\x8Ea\x06oV[a\x02k\x85\x85\x85a\x079V[\x91Pa\x02x\x8B\x8B\x8Ea\x06oV[\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r,\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x02\xE1W` \x02\x82\x01\x91\x90_R` _ \x90[\x81T\x81R` \x01\x90`\x01\x01\x90\x80\x83\x11a\x02\xCDW[PPPPP\x90P\x9AP\x9A\x98PPPPPPPPPV[_\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03AW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03e\x91\x90a\nTV[`@Q\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x81\x16`\x04\x83\x01R\x80\x83\x16`$\x83\x01R\x91\x92P_\x91\x85\x16\x90c\xDDb\xED>\x90`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03\xDCW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x04\0\x91\x90a\t\xE4V[\x90P\x82\x81\x10\x15a\x04\x97W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`*`$\x82\x01R\x7Ftrader did not give the required`D\x82\x01R\x7F approvals\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x81\x16`\x04\x83\x01R_\x91\x90\x86\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05\x04W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05(\x91\x90a\t\xE4V[\x90P\x83\x81\x10\x15a\x06fWs\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11cjR\x90&\x87\x87a\x05X\x85\x89a\n(V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x86\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x93\x84\x16`\x04\x82\x01R\x92\x90\x91\x16`$\x83\x01R`D\x82\x01R`d\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x05\xC9W__\xFD[PZ\xF1\x92PPP\x80\x15a\x05\xDAWP`\x01[a\x06fW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7Ftrader does not have enough sell`D\x82\x01R\x7F token\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x04\x8EV[PPPPPPPV[_[\x82\x81\x10\x15a\x01\xE0W0c;\xBB.\x1D\x85\x85\x84\x81\x81\x10a\x06\x91Wa\x06\x91a\nvV[\x90P` \x02\x01` \x81\x01\x90a\x06\xA6\x91\x90a\n\xA3V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16`\x04\x82\x01R\x90\x85\x16`$\x82\x01R_`D\x82\x01R`d\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x07\x17W__\xFD[PZ\xF1\x15\x80\x15a\x07)W=__>=_\xFD[PP`\x01\x90\x92\x01\x91Pa\x06q\x90PV[__Z\x90P_\x84\x84\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x82\x90RP\x84Q\x94\x95P\x93\x84\x93P\x91PP` \x84\x01\x82\x8AZ\xF1a\x07\x90W=__>=_\xFD[\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r+TZa\x07\xBD\x90\x84a\n(V[a\x07\xC7\x91\x90a\n(V[\x96\x95PPPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x07\xF2W__\xFD[PV[\x805a\x08\0\x81a\x07\xD1V[\x91\x90PV[___``\x84\x86\x03\x12\x15a\x08\x17W__\xFD[\x835a\x08\"\x81a\x07\xD1V[\x92P` \x84\x015a\x082\x81a\x07\xD1V[\x91P`@\x84\x015\x80\x15\x15\x81\x14a\x08FW__\xFD[\x80\x91PP\x92P\x92P\x92V[__\x83`\x1F\x84\x01\x12a\x08aW__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08xW__\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\x08\x8FW__\xFD[\x92P\x92\x90PV[__________a\x01\0\x8B\x8D\x03\x12\x15a\x08\xB0W__\xFD[\x8A5a\x08\xBB\x81a\x07\xD1V[\x99P` \x8B\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08\xD6W__\xFD[\x8B\x01`\x1F\x81\x01\x8D\x13a\x08\xE6W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08\xFCW__\xFD[\x8D` \x82`\x05\x1B\x84\x01\x01\x11\x15a\t\x10W__\xFD[` \x91\x90\x91\x01\x99P\x97Pa\t&`@\x8C\x01a\x07\xF5V[\x96Pa\t4``\x8C\x01a\x07\xF5V[\x95Pa\tB`\x80\x8C\x01a\x07\xF5V[\x94P`\xA0\x8B\x015\x93Pa\tW`\xC0\x8C\x01a\x07\xF5V[\x92P`\xE0\x8B\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\trW__\xFD[a\t~\x8D\x82\x8E\x01a\x08QV[\x91P\x80\x93PP\x80\x91PP\x92\x95\x98\x9B\x91\x94\x97\x9AP\x92\x95\x98PV[_`@\x82\x01\x84\x83R`@` \x84\x01R\x80\x84Q\x80\x83R``\x85\x01\x91P` \x86\x01\x92P_[\x81\x81\x10\x15a\t\xD8W\x83Q\x83R` \x93\x84\x01\x93\x90\x92\x01\x91`\x01\x01a\t\xBAV[P\x90\x96\x95PPPPPPV[_` \x82\x84\x03\x12\x15a\t\xF4W__\xFD[PQ\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x81\x81\x03\x81\x81\x11\x15a\n;Wa\n;a\t\xFBV[\x92\x91PPV[\x80\x82\x01\x80\x82\x11\x15a\n;Wa\n;a\t\xFBV[_` \x82\x84\x03\x12\x15a\ndW__\xFD[\x81Qa\no\x81a\x07\xD1V[\x93\x92PPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a\n\xB3W__\xFD[\x815a\no\x81a\x07\xD1V\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80633bbb2e1d146100385780638581192b1461004d575b5f5ffd5b61004b610046366004610805565b610077565b005b61006061005b366004610896565b6101e6565b60405161006e929190610997565b60405180910390f35b5f5a90507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff861614610160576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528616906370a0823190602401602060405180830381865afa158015610137573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061015b91906109e4565b610179565b8373ffffffffffffffffffffffffffffffffffffffff16315b81546001810183555f92835260209092209091015581156101e0575a61019f9082610a28565b6101ab9061116c610a41565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f8282546101da9190610a41565b90915550505b50505050565b5f60606101f58c8989896102f7565b5f8973ffffffffffffffffffffffffffffffffffffffff165f6040515f6040518083038185875af1925050503d805f811461024b576040519150601f19603f3d011682016040523d82523d5f602084013e610250565b606091505b50509050506102608b8b8e61066f565b61026b858585610739565b91506102788b8b8e61066f565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c8054806020026020016040519081016040528092919081815260200182805480156102e157602002820191905f5260205f20905b8154815260200190600101908083116102cd575b505050505090509a509a98505050505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610341573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103659190610a54565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015280831660248301529192505f9185169063dd62ed3e90604401602060405180830381865afa1580156103dc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040091906109e4565b905082811015610497576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f74726164657220646964206e6f7420676976652074686520726571756972656460448201527f20617070726f76616c730000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301525f91908616906370a0823190602401602060405180830381865afa158015610504573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052891906109e4565b90508381101561066657731111111111111111111111111111111111111111636a52902687876105588589610a28565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015260448201526064015f604051808303815f87803b1580156105c9575f5ffd5b505af19250505080156105da575060015b610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f74726164657220646f6573206e6f74206861766520656e6f7567682073656c6c60448201527f20746f6b656e0000000000000000000000000000000000000000000000000000606482015260840161048e565b50505050505050565b5f5b828110156101e05730633bbb2e1d85858481811061069157610691610a76565b90506020020160208101906106a69190610aa3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff918216600482015290851660248201525f60448201526064015f604051808303815f87803b158015610717575f5ffd5b505af1158015610729573d5f5f3e3d5ffd5b5050600190920191506106719050565b5f5f5a90505f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92018290525084519495509384935091505060208401828a5af1610790573d5f5f3e3d5ffd5b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b545a6107bd9084610a28565b6107c79190610a28565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff811681146107f2575f5ffd5b50565b8035610800816107d1565b919050565b5f5f5f60608486031215610817575f5ffd5b8335610822816107d1565b92506020840135610832816107d1565b915060408401358015158114610846575f5ffd5b809150509250925092565b5f5f83601f840112610861575f5ffd5b50813567ffffffffffffffff811115610878575f5ffd5b60208301915083602082850101111561088f575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f5f5f6101008b8d0312156108b0575f5ffd5b8a356108bb816107d1565b995060208b013567ffffffffffffffff8111156108d6575f5ffd5b8b01601f81018d136108e6575f5ffd5b803567ffffffffffffffff8111156108fc575f5ffd5b8d60208260051b8401011115610910575f5ffd5b6020919091019950975061092660408c016107f5565b965061093460608c016107f5565b955061094260808c016107f5565b945060a08b0135935061095760c08c016107f5565b925060e08b013567ffffffffffffffff811115610972575f5ffd5b61097e8d828e01610851565b915080935050809150509295989b9194979a5092959850565b5f60408201848352604060208401528084518083526060850191506020860192505f5b818110156109d85783518352602093840193909201916001016109ba565b50909695505050505050565b5f602082840312156109f4575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610a3b57610a3b6109fb565b92915050565b80820180821115610a3b57610a3b6109fb565b5f60208284031215610a64575f5ffd5b8151610a6f816107d1565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215610ab3575f5ffd5b8135610a6f816107d156fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80c;\xBB.\x1D\x14a\08W\x80c\x85\x81\x19+\x14a\0MW[__\xFD[a\0Ka\0F6`\x04a\x08\x05V[a\0wV[\0[a\0`a\0[6`\x04a\x08\x96V[a\x01\xE6V[`@Qa\0n\x92\x91\x90a\t\x97V[`@Q\x80\x91\x03\x90\xF3[_Z\x90P\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r,s\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEEs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x16\x14a\x01`W`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`\x04\x83\x01R\x86\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x017W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01[\x91\x90a\t\xE4V[a\x01yV[\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x161[\x81T`\x01\x81\x01\x83U_\x92\x83R` \x90\x92 \x90\x91\x01U\x81\x15a\x01\xE0WZa\x01\x9F\x90\x82a\n(V[a\x01\xAB\x90a\x11la\nAV[\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r+_\x82\x82Ta\x01\xDA\x91\x90a\nAV[\x90\x91UPP[PPPPV[_``a\x01\xF5\x8C\x89\x89\x89a\x02\xF7V[_\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16_`@Q_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x02KW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x02PV[``\x91P[PP\x90PPa\x02`\x8B\x8B\x8Ea\x06oV[a\x02k\x85\x85\x85a\x079V[\x91Pa\x02x\x8B\x8B\x8Ea\x06oV[\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r,\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x02\xE1W` \x02\x82\x01\x91\x90_R` _ \x90[\x81T\x81R` \x01\x90`\x01\x01\x90\x80\x83\x11a\x02\xCDW[PPPPP\x90P\x9AP\x9A\x98PPPPPPPPPV[_\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03AW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x03e\x91\x90a\nTV[`@Q\x7F\xDDb\xED>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x81\x16`\x04\x83\x01R\x80\x83\x16`$\x83\x01R\x91\x92P_\x91\x85\x16\x90c\xDDb\xED>\x90`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x03\xDCW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x04\0\x91\x90a\t\xE4V[\x90P\x82\x81\x10\x15a\x04\x97W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`*`$\x82\x01R\x7Ftrader did not give the required`D\x82\x01R\x7F approvals\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x81\x16`\x04\x83\x01R_\x91\x90\x86\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05\x04W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05(\x91\x90a\t\xE4V[\x90P\x83\x81\x10\x15a\x06fWs\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11cjR\x90&\x87\x87a\x05X\x85\x89a\n(V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x86\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x93\x84\x16`\x04\x82\x01R\x92\x90\x91\x16`$\x83\x01R`D\x82\x01R`d\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x05\xC9W__\xFD[PZ\xF1\x92PPP\x80\x15a\x05\xDAWP`\x01[a\x06fW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7Ftrader does not have enough sell`D\x82\x01R\x7F token\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`d\x82\x01R`\x84\x01a\x04\x8EV[PPPPPPPV[_[\x82\x81\x10\x15a\x01\xE0W0c;\xBB.\x1D\x85\x85\x84\x81\x81\x10a\x06\x91Wa\x06\x91a\nvV[\x90P` \x02\x01` \x81\x01\x90a\x06\xA6\x91\x90a\n\xA3V[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x84\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16`\x04\x82\x01R\x90\x85\x16`$\x82\x01R_`D\x82\x01R`d\x01_`@Q\x80\x83\x03\x81_\x87\x80;\x15\x80\x15a\x07\x17W__\xFD[PZ\xF1\x15\x80\x15a\x07)W=__>=_\xFD[PP`\x01\x90\x92\x01\x91Pa\x06q\x90PV[__Z\x90P_\x84\x84\x80\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83\x80\x82\x847_\x92\x01\x82\x90RP\x84Q\x94\x95P\x93\x84\x93P\x91PP` \x84\x01\x82\x8AZ\xF1a\x07\x90W=__>=_\xFD[\x7F\x14\xF5\xB2\xC1\x85\xFC\x03\xC7\\x}\x1F\x0E\x10\xEA\x13|\xC6\xD25\xA0\x04tH\xEF\xF1\x8C\x9A\x17:r+TZa\x07\xBD\x90\x84a\n(V[a\x07\xC7\x91\x90a\n(V[\x96\x95PPPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x07\xF2W__\xFD[PV[\x805a\x08\0\x81a\x07\xD1V[\x91\x90PV[___``\x84\x86\x03\x12\x15a\x08\x17W__\xFD[\x835a\x08\"\x81a\x07\xD1V[\x92P` \x84\x015a\x082\x81a\x07\xD1V[\x91P`@\x84\x015\x80\x15\x15\x81\x14a\x08FW__\xFD[\x80\x91PP\x92P\x92P\x92V[__\x83`\x1F\x84\x01\x12a\x08aW__\xFD[P\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08xW__\xFD[` \x83\x01\x91P\x83` \x82\x85\x01\x01\x11\x15a\x08\x8FW__\xFD[\x92P\x92\x90PV[__________a\x01\0\x8B\x8D\x03\x12\x15a\x08\xB0W__\xFD[\x8A5a\x08\xBB\x81a\x07\xD1V[\x99P` \x8B\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08\xD6W__\xFD[\x8B\x01`\x1F\x81\x01\x8D\x13a\x08\xE6W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x08\xFCW__\xFD[\x8D` \x82`\x05\x1B\x84\x01\x01\x11\x15a\t\x10W__\xFD[` \x91\x90\x91\x01\x99P\x97Pa\t&`@\x8C\x01a\x07\xF5V[\x96Pa\t4``\x8C\x01a\x07\xF5V[\x95Pa\tB`\x80\x8C\x01a\x07\xF5V[\x94P`\xA0\x8B\x015\x93Pa\tW`\xC0\x8C\x01a\x07\xF5V[\x92P`\xE0\x8B\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\trW__\xFD[a\t~\x8D\x82\x8E\x01a\x08QV[\x91P\x80\x93PP\x80\x91PP\x92\x95\x98\x9B\x91\x94\x97\x9AP\x92\x95\x98PV[_`@\x82\x01\x84\x83R`@` \x84\x01R\x80\x84Q\x80\x83R``\x85\x01\x91P` \x86\x01\x92P_[\x81\x81\x10\x15a\t\xD8W\x83Q\x83R` \x93\x84\x01\x93\x90\x92\x01\x91`\x01\x01a\t\xBAV[P\x90\x96\x95PPPPPPV[_` \x82\x84\x03\x12\x15a\t\xF4W__\xFD[PQ\x91\x90PV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[\x81\x81\x03\x81\x81\x11\x15a\n;Wa\n;a\t\xFBV[\x92\x91PPV[\x80\x82\x01\x80\x82\x11\x15a\n;Wa\n;a\t\xFBV[_` \x82\x84\x03\x12\x15a\ndW__\xFD[\x81Qa\no\x81a\x07\xD1V[\x93\x92PPPV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[_` \x82\x84\x03\x12\x15a\n\xB3W__\xFD[\x815a\no\x81a\x07\xD1V\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `storeBalance(address,address,bool)` and selector `0x3bbb2e1d`. + ```solidity + function storeBalance(address token, address owner, bool countGas) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct storeBalanceCall { + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub countGas: bool, + } + ///Container type for the return parameters of the + /// [`storeBalance(address,address,bool)`](storeBalanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct storeBalanceReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: storeBalanceCall) -> Self { + (value.token, value.owner, value.countGas) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for storeBalanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + token: tuple.0, + owner: tuple.1, + countGas: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: storeBalanceReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for storeBalanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl storeBalanceReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for storeBalanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + ); + type Return = storeBalanceReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [59u8, 187u8, 46u8, 29u8]; + const SIGNATURE: &'static str = "storeBalance(address,address,bool)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.token, + ), + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.countGas, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + storeBalanceReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swap(address,address[],address,address,address,uint256,address,bytes)` and selector `0x8581192b`. + ```solidity + function swap(address settlementContract, address[] memory tokens, address receiver, address trader, address sellToken, uint256 sellAmount, address settleCallTarget, bytes memory settlementCall) external returns (uint256 gasUsed, uint256[] memory queriedBalances); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapCall { + #[allow(missing_docs)] + pub settlementContract: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokens: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub trader: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellToken: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sellAmount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub settleCallTarget: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub settlementCall: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swap(address,address[],address,address,address,uint256,address, + /// bytes)`](swapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapReturn { + #[allow(missing_docs)] + pub gasUsed: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub queriedBalances: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapCall) -> Self { + ( + value.settlementContract, + value.tokens, + value.receiver, + value.trader, + value.sellToken, + value.sellAmount, + value.settleCallTarget, + value.settlementCall, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + settlementContract: tuple.0, + tokens: tuple.1, + receiver: tuple.2, + trader: tuple.3, + sellToken: tuple.4, + sellAmount: tuple.5, + settleCallTarget: tuple.6, + settlementCall: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapReturn) -> Self { + (value.gasUsed, value.queriedBalances) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + gasUsed: tuple.0, + queriedBalances: tuple.1, + } + } + } + } + impl swapReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.gasUsed), + , + > as alloy_sol_types::SolType>::tokenize(&self.queriedBalances), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bytes, + ); + type Return = swapReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [133u8, 129u8, 25u8, 43u8]; + const SIGNATURE: &'static str = + "swap(address,address[],address,address,address,uint256,address,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.settlementContract, + ), + as alloy_sol_types::SolType>::tokenize(&self.tokens), + ::tokenize( + &self.receiver, + ), + ::tokenize( + &self.trader, + ), + ::tokenize( + &self.sellToken, + ), + as alloy_sol_types::SolType>::tokenize(&self.sellAmount), + ::tokenize( + &self.settleCallTarget, + ), + ::tokenize( + &self.settlementCall, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + swapReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`Solver`](self) function calls. + #[derive(Clone)] + pub enum SolverCalls { + #[allow(missing_docs)] + storeBalance(storeBalanceCall), + #[allow(missing_docs)] + swap(swapCall), + } + impl SolverCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[59u8, 187u8, 46u8, 29u8], [133u8, 129u8, 25u8, 43u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = + &[::core::stringify!(storeBalance), ::core::stringify!(swap)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for SolverCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 96usize; + const NAME: &'static str = "SolverCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::storeBalance(_) => ::SELECTOR, + Self::swap(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn storeBalance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SolverCalls::storeBalance) + } + storeBalance + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SolverCalls::swap) + } + swap + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn storeBalance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(SolverCalls::storeBalance) + } + storeBalance + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SolverCalls::swap) + } + swap + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::storeBalance(inner) => { + ::abi_encoded_size(inner) + } + Self::swap(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::storeBalance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swap(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Solver`](self) contract instance. + + See the [wrapper's documentation](`SolverInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> SolverInstance { + SolverInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + SolverInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + SolverInstance::::deploy_builder(__provider) + } + /**A [`Solver`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Solver`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct SolverInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for SolverInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("SolverInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + SolverInstance + { + /**Creates a new wrapper around an on-chain [`Solver`](self) contract instance. + + See the [wrapper's documentation](`SolverInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl SolverInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> SolverInstance { + SolverInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + SolverInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`storeBalance`] function. + pub fn storeBalance( + &self, + token: alloy_sol_types::private::Address, + owner: alloy_sol_types::private::Address, + countGas: bool, + ) -> alloy_contract::SolCallBuilder<&P, storeBalanceCall, N> { + self.call_builder(&storeBalanceCall { + token, + owner, + countGas, + }) + } + + ///Creates a new call builder for the [`swap`] function. + pub fn swap( + &self, + settlementContract: alloy_sol_types::private::Address, + tokens: alloy_sol_types::private::Vec, + receiver: alloy_sol_types::private::Address, + trader: alloy_sol_types::private::Address, + sellToken: alloy_sol_types::private::Address, + sellAmount: alloy_sol_types::private::primitives::aliases::U256, + settleCallTarget: alloy_sol_types::private::Address, + settlementCall: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, swapCall, N> { + self.call_builder(&swapCall { + settlementContract, + tokens, + receiver, + trader, + sellToken, + sellAmount, + settleCallTarget, + settlementCall, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + SolverInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = Solver::SolverInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/solver7702delegate/Cargo.toml b/contracts/generated/contracts-generated/solver7702delegate/Cargo.toml new file mode 100644 index 0000000000..d0406845fd --- /dev/null +++ b/contracts/generated/contracts-generated/solver7702delegate/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-solver7702delegate" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/solver7702delegate/src/lib.rs b/contracts/generated/contracts-generated/solver7702delegate/src/lib.rs new file mode 100644 index 0000000000..100ea9026d --- /dev/null +++ b/contracts/generated/contracts-generated/solver7702delegate/src/lib.rs @@ -0,0 +1,545 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface Solver7702Delegate { + error Unauthorized(address sender); + + constructor(address[5] approvedCallers); + + fallback() external payable; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "approvedCallers", + "type": "address[5]", + "internalType": "address[5]" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "fallback", + "stateMutability": "payable" + }, + { + "type": "error", + "name": "Unauthorized", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + } + ] + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Solver7702Delegate { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x610120604052348015610010575f5ffd5b506040516103fd3803806103fd83398101604081905261002f9161009c565b80516001600160a01b0390811660809081526020830151821660a0526040830151821660c0526060830151821660e05290910151166101005261011c565b634e487b7160e01b5f52604160045260245ffd5b80516001600160a01b0381168114610097575f5ffd5b919050565b5f60a082840312156100ac575f5ffd5b82601f8301126100ba575f5ffd5b60405160a081016001600160401b03811182821017156100dc576100dc61006d565b6040528060a08401858111156100f0575f5ffd5b845b818110156101115761010381610081565b8352602092830192016100f2565b509195945050505050565b60805160a05160c05160e051610100516102a86101555f395f61011b01525f60db01525f609b01525f605b01525f601c01526102a85ff3fe60806040523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148061007d57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b806100bd57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b806100fd57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b8061013d57503373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016145b1561014c5761014a610198565b005b5f34118061015957503330145b1561016057005b6040517f8e4a23d600000000000000000000000000000000000000000000000000000000815233600482015260240160405180910390fd5b60143610156101a357565b5f6101b160148236816101e5565b6101ba9161020c565b60601c90506014360360145f375f5f601436035f34855af13d5f5f3e8080156101e1573d5ff35b3d5ffd5b5f5f858511156101f3575f5ffd5b838611156101ff575f5ffd5b5050820193919092039150565b80357fffffffffffffffffffffffffffffffffffffffff000000000000000000000000811690601484101561026b577fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808560140360031b1b82161691505b509291505056fea2646970667358221220ef31ba5be14f09268bdfe684e4f9d33c71640e3412fc60118872f20167113f6964736f6c63430008220033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"a\x01 `@R4\x80\x15a\0\x10W__\xFD[P`@Qa\x03\xFD8\x03\x80a\x03\xFD\x839\x81\x01`@\x81\x90Ra\0/\x91a\0\x9CV[\x80Q`\x01`\x01`\xA0\x1B\x03\x90\x81\x16`\x80\x90\x81R` \x83\x01Q\x82\x16`\xA0R`@\x83\x01Q\x82\x16`\xC0R``\x83\x01Q\x82\x16`\xE0R\x90\x91\x01Q\x16a\x01\0Ra\x01\x1CV[cNH{q`\xE0\x1B_R`A`\x04R`$_\xFD[\x80Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\x97W__\xFD[\x91\x90PV[_`\xA0\x82\x84\x03\x12\x15a\0\xACW__\xFD[\x82`\x1F\x83\x01\x12a\0\xBAW__\xFD[`@Q`\xA0\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15a\0\xDCWa\0\xDCa\0mV[`@R\x80`\xA0\x84\x01\x85\x81\x11\x15a\0\xF0W__\xFD[\x84[\x81\x81\x10\x15a\x01\x11Wa\x01\x03\x81a\0\x81V[\x83R` \x92\x83\x01\x92\x01a\0\xF2V[P\x91\x95\x94PPPPPV[`\x80Q`\xA0Q`\xC0Q`\xE0Qa\x01\0Qa\x02\xA8a\x01U_9_a\x01\x1B\x01R_`\xDB\x01R_`\x9B\x01R_`[\x01R_`\x1C\x01Ra\x02\xA8_\xF3\xFE`\x80`@R3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14\x80a\0}WP3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14[\x80a\0\xBDWP3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14[\x80a\0\xFDWP3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14[\x80a\x01=WP3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14[\x15a\x01LWa\x01Ja\x01\x98V[\0[_4\x11\x80a\x01YWP30\x14[\x15a\x01`W\0[`@Q\x7F\x8EJ#\xD6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[`\x146\x10\x15a\x01\xA3WV[_a\x01\xB1`\x14\x826\x81a\x01\xE5V[a\x01\xBA\x91a\x02\x0CV[``\x1C\x90P`\x146\x03`\x14_7__`\x146\x03_4\x85Z\xF1=__>\x80\x80\x15a\x01\xE1W=_\xF3[=_\xFD[__\x85\x85\x11\x15a\x01\xF3W__\xFD[\x83\x86\x11\x15a\x01\xFFW__\xFD[PP\x82\x01\x93\x91\x90\x92\x03\x91PV[\x805\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x81\x16\x90`\x14\x84\x10\x15a\x02kW\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x80\x85`\x14\x03`\x03\x1B\x1B\x82\x16\x16\x91P[P\x92\x91PPV\xFE\xA2dipfsX\"\x12 \xEF1\xBA[\xE1O\t&\x8B\xDF\xE6\x84\xE4\xF9\xD3 = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Unauthorized) -> Self { + (value.sender,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Unauthorized { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { sender: tuple.0 } + } + } + #[automatically_derived] + impl alloy_sol_types::SolError for Unauthorized { + type Parameters<'a> = UnderlyingSolTuple<'a>; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [142u8, 74u8, 35u8, 214u8]; + const SIGNATURE: &'static str = "Unauthorized(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.sender, + ), + ) + } + + #[inline] + fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Self::new) + } + } + }; + /**Constructor`. + ```solidity + constructor(address[5] approvedCallers); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub approvedCallers: [alloy_sol_types::private::Address; 5usize], + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedArray, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ([alloy_sol_types::private::Address; 5usize],); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value.approvedCallers,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + approvedCallers: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedArray, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( as alloy_sol_types::SolType>::tokenize( + &self.approvedCallers, + ),) + } + } + }; + ///Container for all the [`Solver7702Delegate`](self) custom errors. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum Solver7702DelegateErrors { + #[allow(missing_docs)] + Unauthorized(Unauthorized), + } + impl Solver7702DelegateErrors { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[142u8, 74u8, 35u8, 214u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(Unauthorized)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for Solver7702DelegateErrors { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 32usize; + const NAME: &'static str = "Solver7702DelegateErrors"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::Unauthorized(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[{ + fn Unauthorized(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(Solver7702DelegateErrors::Unauthorized) + } + Unauthorized + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + Solver7702DelegateErrors, + >] = &[{ + fn Unauthorized(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(Solver7702DelegateErrors::Unauthorized) + } + Unauthorized + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::Unauthorized(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::Unauthorized(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Solver7702Delegate`](self) contract instance. + + See the [wrapper's documentation](`Solver7702DelegateInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> Solver7702DelegateInstance { + Solver7702DelegateInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + approvedCallers: [alloy_sol_types::private::Address; 5usize], + ) -> impl ::core::future::Future>> + { + Solver7702DelegateInstance::::deploy(__provider, approvedCallers) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + approvedCallers: [alloy_sol_types::private::Address; 5usize], + ) -> alloy_contract::RawCallBuilder { + Solver7702DelegateInstance::::deploy_builder(__provider, approvedCallers) + } + /**A [`Solver7702Delegate`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Solver7702Delegate`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct Solver7702DelegateInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for Solver7702DelegateInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("Solver7702DelegateInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + Solver7702DelegateInstance + { + /**Creates a new wrapper around an on-chain [`Solver7702Delegate`](self) contract instance. + + See the [wrapper's documentation](`Solver7702DelegateInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + approvedCallers: [alloy_sol_types::private::Address; 5usize], + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, approvedCallers); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + approvedCallers: [alloy_sol_types::private::Address; 5usize], + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + approvedCallers, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl Solver7702DelegateInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> Solver7702DelegateInstance { + Solver7702DelegateInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + Solver7702DelegateInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + Solver7702DelegateInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = Solver7702Delegate::Solver7702DelegateInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/spardose/Cargo.toml b/contracts/generated/contracts-generated/spardose/Cargo.toml new file mode 100644 index 0000000000..4082b38f9f --- /dev/null +++ b/contracts/generated/contracts-generated/spardose/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-spardose" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/spardose/src/lib.rs b/contracts/generated/contracts-generated/spardose/src/lib.rs new file mode 100644 index 0000000000..f3b89a2777 --- /dev/null +++ b/contracts/generated/contracts-generated/spardose/src/lib.rs @@ -0,0 +1,553 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface Spardose { + function requestFunds(address receiver, address token, uint256 amount) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "requestFunds", + "inputs": [ + { + "name": "receiver", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Spardose { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b506102ea8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80636a5290261461002d575b5f5ffd5b61004061003b366004610259565b610042565b005b61006373ffffffffffffffffffffffffffffffffffffffff83168483610068565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052905f906100fa90861683610176565b90506101058161018a565b61016f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a207472616e73666572206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b6060610183835f846101af565b9392505050565b5f81515f14806101a95750818060200190518101906101a99190610292565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516101d891906102b1565b5f6040518083038185875af1925050503d805f8114610212576040519150601f19603f3d011682016040523d82523d5f602084013e610217565b606091505b50925090508061022957815160208301fd5b509392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610254575f5ffd5b919050565b5f5f5f6060848603121561026b575f5ffd5b61027484610231565b925061028260208501610231565b9150604084013590509250925092565b5f602082840312156102a2575f5ffd5b81518015158114610183575f5ffd5b5f82515f5b818110156102d057602081860181015185830152016102b6565b505f92019182525091905056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x02\xEA\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80cjR\x90&\x14a\0-W[__\xFD[a\0@a\0;6`\x04a\x02YV[a\0BV[\0[a\0cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x84\x83a\0hV[PPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x81\x16`$\x83\x01R`D\x80\x83\x01\x85\x90R\x83Q\x80\x84\x03\x90\x91\x01\x81R`d\x90\x92\x01\x90\x92R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90_\x90a\0\xFA\x90\x86\x16\x83a\x01vV[\x90Pa\x01\x05\x81a\x01\x8AV[a\x01oW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7FSafeERC20: transfer failed\0\0\0\0\0\0`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPPPPV[``a\x01\x83\x83_\x84a\x01\xAFV[\x93\x92PPPV[_\x81Q_\x14\x80a\x01\xA9WP\x81\x80` \x01\x90Q\x81\x01\x90a\x01\xA9\x91\x90a\x02\x92V[\x92\x91PPV[``_\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84\x84`@Qa\x01\xD8\x91\x90a\x02\xB1V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x02\x12W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x02\x17V[``\x91P[P\x92P\x90P\x80a\x02)W\x81Q` \x83\x01\xFD[P\x93\x92PPPV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02TW__\xFD[\x91\x90PV[___``\x84\x86\x03\x12\x15a\x02kW__\xFD[a\x02t\x84a\x021V[\x92Pa\x02\x82` \x85\x01a\x021V[\x91P`@\x84\x015\x90P\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x02\xA2W__\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\x83W__\xFD[_\x82Q_[\x81\x81\x10\x15a\x02\xD0W` \x81\x86\x01\x81\x01Q\x85\x83\x01R\x01a\x02\xB6V[P_\x92\x01\x91\x82RP\x91\x90PV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80636a5290261461002d575b5f5ffd5b61004061003b366004610259565b610042565b005b61006373ffffffffffffffffffffffffffffffffffffffff83168483610068565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052905f906100fa90861683610176565b90506101058161018a565b61016f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a207472616e73666572206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b6060610183835f846101af565b9392505050565b5f81515f14806101a95750818060200190518101906101a99190610292565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516101d891906102b1565b5f6040518083038185875af1925050503d805f8114610212576040519150601f19603f3d011682016040523d82523d5f602084013e610217565b606091505b50925090508061022957815160208301fd5b509392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610254575f5ffd5b919050565b5f5f5f6060848603121561026b575f5ffd5b61027484610231565b925061028260208501610231565b9150604084013590509250925092565b5f602082840312156102a2575f5ffd5b81518015158114610183575f5ffd5b5f82515f5b818110156102d057602081860181015185830152016102b6565b505f92019182525091905056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80cjR\x90&\x14a\0-W[__\xFD[a\0@a\0;6`\x04a\x02YV[a\0BV[\0[a\0cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x84\x83a\0hV[PPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x81\x16`$\x83\x01R`D\x80\x83\x01\x85\x90R\x83Q\x80\x84\x03\x90\x91\x01\x81R`d\x90\x92\x01\x90\x92R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90_\x90a\0\xFA\x90\x86\x16\x83a\x01vV[\x90Pa\x01\x05\x81a\x01\x8AV[a\x01oW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7FSafeERC20: transfer failed\0\0\0\0\0\0`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPPPPV[``a\x01\x83\x83_\x84a\x01\xAFV[\x93\x92PPPV[_\x81Q_\x14\x80a\x01\xA9WP\x81\x80` \x01\x90Q\x81\x01\x90a\x01\xA9\x91\x90a\x02\x92V[\x92\x91PPV[``_\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84\x84`@Qa\x01\xD8\x91\x90a\x02\xB1V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\x02\x12W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x02\x17V[``\x91P[P\x92P\x90P\x80a\x02)W\x81Q` \x83\x01\xFD[P\x93\x92PPPV[\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\x02TW__\xFD[\x91\x90PV[___``\x84\x86\x03\x12\x15a\x02kW__\xFD[a\x02t\x84a\x021V[\x92Pa\x02\x82` \x85\x01a\x021V[\x91P`@\x84\x015\x90P\x92P\x92P\x92V[_` \x82\x84\x03\x12\x15a\x02\xA2W__\xFD[\x81Q\x80\x15\x15\x81\x14a\x01\x83W__\xFD[_\x82Q_[\x81\x81\x10\x15a\x02\xD0W` \x81\x86\x01\x81\x01Q\x85\x83\x01R\x01a\x02\xB6V[P_\x92\x01\x91\x82RP\x91\x90PV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `requestFunds(address,address,uint256)` and selector `0x6a529026`. + ```solidity + function requestFunds(address receiver, address token, uint256 amount) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct requestFundsCall { + #[allow(missing_docs)] + pub receiver: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`requestFunds(address,address,uint256)`](requestFundsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct requestFundsReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: requestFundsCall) -> Self { + (value.receiver, value.token, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for requestFundsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + receiver: tuple.0, + token: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: requestFundsReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for requestFundsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl requestFundsReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for requestFundsCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = requestFundsReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [106u8, 82u8, 144u8, 38u8]; + const SIGNATURE: &'static str = "requestFunds(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.receiver, + ), + ::tokenize( + &self.token, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + requestFundsReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`Spardose`](self) function calls. + #[derive(Clone)] + pub enum SpardoseCalls { + #[allow(missing_docs)] + requestFunds(requestFundsCall), + } + impl SpardoseCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[106u8, 82u8, 144u8, 38u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(requestFunds)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for SpardoseCalls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 96usize; + const NAME: &'static str = "SpardoseCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::requestFunds(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[{ + fn requestFunds(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SpardoseCalls::requestFunds) + } + requestFunds + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[{ + fn requestFunds(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(SpardoseCalls::requestFunds) + } + requestFunds + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::requestFunds(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::requestFunds(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Spardose`](self) contract instance. + + See the [wrapper's documentation](`SpardoseInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> SpardoseInstance { + SpardoseInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + SpardoseInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + SpardoseInstance::::deploy_builder(__provider) + } + /**A [`Spardose`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Spardose`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct SpardoseInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for SpardoseInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("SpardoseInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + SpardoseInstance + { + /**Creates a new wrapper around an on-chain [`Spardose`](self) contract instance. + + See the [wrapper's documentation](`SpardoseInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl SpardoseInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> SpardoseInstance { + SpardoseInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + SpardoseInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`requestFunds`] function. + pub fn requestFunds( + &self, + receiver: alloy_sol_types::private::Address, + token: alloy_sol_types::private::Address, + amount: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, requestFundsCall, N> { + self.call_builder(&requestFundsCall { + receiver, + token, + amount, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + SpardoseInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = Spardose::SpardoseInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/sushiswaprouter/Cargo.toml b/contracts/generated/contracts-generated/sushiswaprouter/Cargo.toml new file mode 100644 index 0000000000..4e099e1e1d --- /dev/null +++ b/contracts/generated/contracts-generated/sushiswaprouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-sushiswaprouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/sushiswaprouter/src/lib.rs b/contracts/generated/contracts-generated/sushiswaprouter/src/lib.rs new file mode 100644 index 0000000000..2bc72c6cbe --- /dev/null +++ b/contracts/generated/contracts-generated/sushiswaprouter/src/lib.rs @@ -0,0 +1,1606 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface SushiSwapRouter { + function WETH() external pure returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external pure returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod SushiSwapRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`SushiSwapRouter`](self) function calls. + #[derive(Clone)] + pub enum SushiSwapRouterCalls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl SushiSwapRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for SushiSwapRouterCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "SushiSwapRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(SushiSwapRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SushiSwapRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SushiSwapRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SushiSwapRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SushiSwapRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(SushiSwapRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SushiSwapRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SushiSwapRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SushiSwapRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(SushiSwapRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`SushiSwapRouter`](self) contract instance. + + See the [wrapper's documentation](`SushiSwapRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> SushiSwapRouterInstance { + SushiSwapRouterInstance::::new(address, __provider) + } + /**A [`SushiSwapRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`SushiSwapRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct SushiSwapRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for SushiSwapRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("SushiSwapRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + SushiSwapRouterInstance + { + /**Creates a new wrapper around an on-chain [`SushiSwapRouter`](self) contract instance. + + See the [wrapper's documentation](`SushiSwapRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl SushiSwapRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> SushiSwapRouterInstance { + SushiSwapRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + SushiSwapRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + SushiSwapRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = SushiSwapRouter::SushiSwapRouterInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x2abf469074dc0b54d793850807e6eb5faf2625b1"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x6bded42c6da8fbf0d2ba55b2fa120c5e0c8d7891"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/swapper/Cargo.toml b/contracts/generated/contracts-generated/swapper/Cargo.toml new file mode 100644 index 0000000000..d5555196aa --- /dev/null +++ b/contracts/generated/contracts-generated/swapper/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-swapper" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/swapper/src/lib.rs b/contracts/generated/contracts-generated/swapper/src/lib.rs new file mode 100644 index 0000000000..570e7ff6e7 --- /dev/null +++ b/contracts/generated/contracts-generated/swapper/src/lib.rs @@ -0,0 +1,1553 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface Swapper { + struct Allowance { + address spender; + uint256 amount; + } + struct Asset { + address token; + uint256 amount; + } + struct Interaction { + address target; + uint256 value; + bytes callData; + } + + function isValidSignature(bytes32, bytes memory) external pure returns (bytes4); + function swap(address settlement, Asset memory sell, Asset memory buy, Allowance memory allowance, Interaction[] memory calls) external returns (uint256 gasUsed); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "isValidSignature", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "settlement", + "type": "address", + "internalType": "contract ISettlement" + }, + { + "name": "sell", + "type": "tuple", + "internalType": "struct Asset", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "buy", + "type": "tuple", + "internalType": "struct Asset", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "allowance", + "type": "tuple", + "internalType": "struct Allowance", + "components": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "calls", + "type": "tuple[]", + "internalType": "struct Interaction[]", + "components": [ + { + "name": "target", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "callData", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "gasUsed", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod Swapper { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b506111ea8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80631626ba7e14610038578063e8333e0d146100a4575b5f5ffd5b61006e610046366004610a63565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b6100b76100b2366004610b14565b6100c5565b60405190815260200161009b565b5f602086018035906100d79088610bcc565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa158015610141573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101659190610be7565b101561017257505f61082e565b61020d8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101be573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101e29190610bfe565b5f6101f060208a018a610bcc565b73ffffffffffffffffffffffffffffffffffffffff169190610838565b61028e8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610259573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027d9190610bfe565b602088018035906101f0908a610bcc565b6040805160028082526060820183525f926020830190803683370190505090506102bb6020880188610bcc565b815f815181106102cd576102cd610c46565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526102fd90870187610bcc565b8160018151811061031057610310610c46565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160028082526060820183525f9391929091830190803683370190505090508660200135815f8151811061036e5761036e610c46565b60200260200101818152505087602001358160018151811061039257610392610c46565b60209081029190910101526040805160018082528183019092525f91816020015b6104226040518061016001604052805f81526020015f81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020015f81526020015f63ffffffff1681526020015f81526020015f81526020015f81526020015f8152602001606081525090565b8152602001906001900390816103b35790505090506040518061016001604052805f8152602001600181526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020018a6020013581526020018960200135815260200163ffffffff801681526020015f5f1b81526020015f8152602001604081526020015f8152602001306040516020016104e3919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604051602081830303815290604052815250815f8151811061050757610507610c46565b602002602001018190525061051a610a3c565b6020808901359061052d908c018c610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8d61055660208d018d610bcc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa1580156105c4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e89190610be7565b10156107625760408051600180825281830190925290816020015b60408051606080820183525f808352602083015291810191909152815260200190600190039081610603575050815261063f60208b018b610bcc565b815180515f9061065157610651610c46565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff909216909152610684908b018b610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b36106ac60208b018b610bcc565b60405173ffffffffffffffffffffffffffffffffffffffff909116602482015260208b01356044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b929092179091529050815f60200201515f8151811061075257610752610c46565b6020026020010151604001819052505b61076c8688610ceb565b60208201526040516108279073ffffffffffffffffffffffffffffffffffffffff8d16906313d79a0b906107aa9088908890889088906024016110a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b9290921790915273ffffffffffffffffffffffffffffffffffffffff8e169150610946565b9450505050505b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052905f906108ca90861683610959565b90506108d581610966565b61093f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b5f610952835f8461098b565b9392505050565b6060610952835f846109ba565b5f81515f1480610985575081806020019051810190610985919061116b565b92915050565b5f5a90505f5f83516020850186885af16109a7573d5f5f3e3d5ffd5b5a6109b2908261118a565b949350505050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516109e391906111c2565b5f6040518083038185875af1925050503d805f8114610a1d576040519150601f19603f3d011682016040523d82523d5f602084013e610a22565b606091505b509250905080610a3457815160208301fd5b509392505050565b60405180606001604052806003905b6060815260200190600190039081610a4b5790505090565b5f5f5f60408486031215610a75575f5ffd5b83359250602084013567ffffffffffffffff811115610a92575f5ffd5b8401601f81018613610aa2575f5ffd5b803567ffffffffffffffff811115610ab8575f5ffd5b866020828401011115610ac9575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610afb575f5ffd5b50565b5f60408284031215610b0e575f5ffd5b50919050565b5f5f5f5f5f5f6101008789031215610b2a575f5ffd5b8635610b3581610ada565b9550610b448860208901610afe565b9450610b538860608901610afe565b9350610b628860a08901610afe565b925060e087013567ffffffffffffffff811115610b7d575f5ffd5b8701601f81018913610b8d575f5ffd5b803567ffffffffffffffff811115610ba3575f5ffd5b8960208260051b8401011115610bb7575f5ffd5b60208201935080925050509295509295509295565b5f60208284031215610bdc575f5ffd5b813561095281610ada565b5f60208284031215610bf7575f5ffd5b5051919050565b5f60208284031215610c0e575f5ffd5b815161095281610ada565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040516060810167ffffffffffffffff81118282101715610c9657610c96610c19565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ce357610ce3610c19565b604052919050565b5f67ffffffffffffffff831115610d0457610d04610c19565b8260051b610d1460208201610c9c565b84815290830190602081019036831115610d2c575f5ffd5b845b83811015610e3857803567ffffffffffffffff811115610d4c575f5ffd5b86016060368290031215610d5e575f5ffd5b610d66610c73565b8135610d7181610ada565b815260208281013590820152604082013567ffffffffffffffff811115610d96575f5ffd5b919091019036601f830112610da9575f5ffd5b813567ffffffffffffffff811115610dc357610dc3610c19565b610df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610c9c565b818152366020838601011115610e08575f5ffd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050610d2e565b5095945050505050565b5f5b83811015610e5c578181015183820152602001610e44565b50505f910152565b5f8151808452610e7b816020860160208601610e42565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f82825180855260208501945060208160051b830101602085015f5b83811015610fbe577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0858403018852815180518452602081015160208501526040810151610f2f604086018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608501526080810151608085015260a0810151610f5b60a086018263ffffffff169052565b5060c081015160c085015260e081015160e08501526101008101516101008501526101208101516101208501526101408101519050610160610140850152610fa7610160850182610e64565b6020998a0199909450929092019150600101610ec9565b50909695505050505050565b5f8260608101835f5b600381101561109d578383038752815180518085526020918201918086019190600582901b8701015f5b82811015611083577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0888303018452845173ffffffffffffffffffffffffffffffffffffffff815116835260208101516020840152604081015190506060604084015261106d6060840182610e64565b6020968701969590950194925050600101610ffd565b5060209a8b019a9096509490940193505050600101610fd3565b509095945050505050565b608080825285519082018190525f90602087019060a0840190835b818110156110f757835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016110c3565b505083810360208501528091505f87518083526020830193506020890192505f5b81811015611136578351855260209485019490930192600101611118565b50505050828103604084015261114c8186610ead565b905082810360608401526111608185610fca565b979650505050505050565b5f6020828403121561117b575f5ffd5b81518015158114610952575f5ffd5b81810381811115610985577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f82516111d3818460208701610e42565b919091019291505056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x11\xEA\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80c\x16&\xBA~\x14a\08W\x80c\xE83>\r\x14a\0\xA4W[__\xFD[a\0na\0F6`\x04a\ncV[\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\x92PPPV[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[a\0\xB7a\0\xB26`\x04a\x0B\x14V[a\0\xC5V[`@Q\x90\x81R` \x01a\0\x9BV[_` \x86\x01\x805\x90a\0\xD7\x90\x88a\x0B\xCCV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x90\x91\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01AW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01e\x91\x90a\x0B\xE7V[\x10\x15a\x01rWP_a\x08.V[a\x02\r\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xBEW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xE2\x91\x90a\x0B\xFEV[_a\x01\xF0` \x8A\x01\x8Aa\x0B\xCCV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91\x90a\x088V[a\x02\x8E\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02YW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x02}\x91\x90a\x0B\xFEV[` \x88\x01\x805\x90a\x01\xF0\x90\x8Aa\x0B\xCCV[`@\x80Q`\x02\x80\x82R``\x82\x01\x83R_\x92` \x83\x01\x90\x806\x837\x01\x90PP\x90Pa\x02\xBB` \x88\x01\x88a\x0B\xCCV[\x81_\x81Q\x81\x10a\x02\xCDWa\x02\xCDa\x0CFV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16` \x92\x83\x02\x91\x90\x91\x01\x82\x01Ra\x02\xFD\x90\x87\x01\x87a\x0B\xCCV[\x81`\x01\x81Q\x81\x10a\x03\x10Wa\x03\x10a\x0CFV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16` \x92\x83\x02\x91\x90\x91\x01\x82\x01R`@\x80Q`\x02\x80\x82R``\x82\x01\x83R_\x93\x91\x92\x90\x91\x83\x01\x90\x806\x837\x01\x90PP\x90P\x86` \x015\x81_\x81Q\x81\x10a\x03nWa\x03na\x0CFV[` \x02` \x01\x01\x81\x81RPP\x87` \x015\x81`\x01\x81Q\x81\x10a\x03\x92Wa\x03\x92a\x0CFV[` \x90\x81\x02\x91\x90\x91\x01\x01R`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R_\x91\x81` \x01[a\x04\"`@Q\x80a\x01`\x01`@R\x80_\x81R` \x01_\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01_\x81R` \x01_c\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01``\x81RP\x90V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x03\xB3W\x90PP\x90P`@Q\x80a\x01`\x01`@R\x80_\x81R` \x01`\x01\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8A` \x015\x81R` \x01\x89` \x015\x81R` \x01c\xFF\xFF\xFF\xFF\x80\x16\x81R` \x01__\x1B\x81R` \x01_\x81R` \x01`@\x81R` \x01_\x81R` \x010`@Q` \x01a\x04\xE3\x91\x90``\x91\x90\x91\x1B\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x16\x81R`\x14\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x81RP\x81_\x81Q\x81\x10a\x05\x07Wa\x05\x07a\x0CFV[` \x02` \x01\x01\x81\x90RPa\x05\x1Aa\n\x8Da\x05V` \x8D\x01\x8Da\x0B\xCCV[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x85\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16`\x04\x82\x01R\x91\x16`$\x82\x01R`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05\xC4W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05\xE8\x91\x90a\x0B\xE7V[\x10\x15a\x07bW`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R\x90\x81` \x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x03WPP\x81Ra\x06?` \x8B\x01\x8Ba\x0B\xCCV[\x81Q\x80Q_\x90a\x06QWa\x06Qa\x0CFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x90\x91Ra\x06\x84\x90\x8B\x01\x8Ba\x0B\xCCV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\t^\xA7\xB3a\x06\xAC` \x8B\x01\x8Ba\x0B\xCCV[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16`$\x82\x01R` \x8B\x015`D\x82\x01R`d\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\xE0\x93\x90\x93\x1B\x92\x90\x92\x17\x90\x91R\x90P\x81_` \x02\x01Q_\x81Q\x81\x10a\x07RWa\x07Ra\x0CFV[` \x02` \x01\x01Q`@\x01\x81\x90RP[a\x07l\x86\x88a\x0C\xEBV[` \x82\x01R`@Qa\x08'\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8D\x16\x90c\x13\xD7\x9A\x0B\x90a\x07\xAA\x90\x88\x90\x88\x90\x88\x90\x88\x90`$\x01a\x10\xA8V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\xE0\x93\x90\x93\x1B\x92\x90\x92\x17\x90\x91Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8E\x16\x91Pa\tFV[\x94PPPPP[\x96\x95PPPPPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x81\x16`$\x83\x01R`D\x80\x83\x01\x85\x90R\x83Q\x80\x84\x03\x90\x91\x01\x81R`d\x90\x92\x01\x90\x92R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\t^\xA7\xB3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90_\x90a\x08\xCA\x90\x86\x16\x83a\tYV[\x90Pa\x08\xD5\x81a\tfV[a\t?W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7FSafeERC20: approval failed\0\0\0\0\0\0`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPPPPV[_a\tR\x83_\x84a\t\x8BV[\x93\x92PPPV[``a\tR\x83_\x84a\t\xBAV[_\x81Q_\x14\x80a\t\x85WP\x81\x80` \x01\x90Q\x81\x01\x90a\t\x85\x91\x90a\x11kV[\x92\x91PPV[_Z\x90P__\x83Q` \x85\x01\x86\x88Z\xF1a\t\xA7W=__>=_\xFD[Za\t\xB2\x90\x82a\x11\x8AV[\x94\x93PPPPV[``_\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84\x84`@Qa\t\xE3\x91\x90a\x11\xC2V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\n\x1DW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\n\"V[``\x91P[P\x92P\x90P\x80a\n4W\x81Q` \x83\x01\xFD[P\x93\x92PPPV[`@Q\x80``\x01`@R\x80`\x03\x90[``\x81R` \x01\x90`\x01\x90\x03\x90\x81a\nKW\x90PP\x90V[___`@\x84\x86\x03\x12\x15a\nuW__\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\x92W__\xFD[\x84\x01`\x1F\x81\x01\x86\x13a\n\xA2W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\xB8W__\xFD[\x86` \x82\x84\x01\x01\x11\x15a\n\xC9W__\xFD[\x93\x96` \x91\x90\x91\x01\x95P\x92\x93PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\n\xFBW__\xFD[PV[_`@\x82\x84\x03\x12\x15a\x0B\x0EW__\xFD[P\x91\x90PV[______a\x01\0\x87\x89\x03\x12\x15a\x0B*W__\xFD[\x865a\x0B5\x81a\n\xDAV[\x95Pa\x0BD\x88` \x89\x01a\n\xFEV[\x94Pa\x0BS\x88``\x89\x01a\n\xFEV[\x93Pa\x0Bb\x88`\xA0\x89\x01a\n\xFEV[\x92P`\xE0\x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x0B}W__\xFD[\x87\x01`\x1F\x81\x01\x89\x13a\x0B\x8DW__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x0B\xA3W__\xFD[\x89` \x82`\x05\x1B\x84\x01\x01\x11\x15a\x0B\xB7W__\xFD[` \x82\x01\x93P\x80\x92PPP\x92\x95P\x92\x95P\x92\x95V[_` \x82\x84\x03\x12\x15a\x0B\xDCW__\xFD[\x815a\tR\x81a\n\xDAV[_` \x82\x84\x03\x12\x15a\x0B\xF7W__\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a\x0C\x0EW__\xFD[\x81Qa\tR\x81a\n\xDAV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x0C\x96Wa\x0C\x96a\x0C\x19V[`@R\x90V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x0C\xE3Wa\x0C\xE3a\x0C\x19V[`@R\x91\x90PV[_g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11\x15a\r\x04Wa\r\x04a\x0C\x19V[\x82`\x05\x1Ba\r\x14` \x82\x01a\x0C\x9CV[\x84\x81R\x90\x83\x01\x90` \x81\x01\x906\x83\x11\x15a\r,W__\xFD[\x84[\x83\x81\x10\x15a\x0E8W\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\rLW__\xFD[\x86\x01``6\x82\x90\x03\x12\x15a\r^W__\xFD[a\rfa\x0CsV[\x815a\rq\x81a\n\xDAV[\x81R` \x82\x81\x015\x90\x82\x01R`@\x82\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r\x96W__\xFD[\x91\x90\x91\x01\x906`\x1F\x83\x01\x12a\r\xA9W__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r\xC3Wa\r\xC3a\x0C\x19V[a\r\xF4` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x0C\x9CV[\x81\x81R6` \x83\x86\x01\x01\x11\x15a\x0E\x08W__\xFD[\x81` \x85\x01` \x83\x017_` \x83\x83\x01\x01R\x80`@\x84\x01RPP\x80\x85RPP` \x83\x01\x92P` \x81\x01\x90Pa\r.V[P\x95\x94PPPPPV[_[\x83\x81\x10\x15a\x0E\\W\x81\x81\x01Q\x83\x82\x01R` \x01a\x0EDV[PP_\x91\x01RV[_\x81Q\x80\x84Ra\x0E{\x81` \x86\x01` \x86\x01a\x0EBV[`\x1F\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x92\x90\x92\x01` \x01\x92\x91PPV[_\x82\x82Q\x80\x85R` \x85\x01\x94P` \x81`\x05\x1B\x83\x01\x01` \x85\x01_[\x83\x81\x10\x15a\x0F\xBEW\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x85\x84\x03\x01\x88R\x81Q\x80Q\x84R` \x81\x01Q` \x85\x01R`@\x81\x01Qa\x0F/`@\x86\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x81\x01Q``\x85\x01R`\x80\x81\x01Q`\x80\x85\x01R`\xA0\x81\x01Qa\x0F[`\xA0\x86\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x81\x01Q`\xC0\x85\x01R`\xE0\x81\x01Q`\xE0\x85\x01Ra\x01\0\x81\x01Qa\x01\0\x85\x01Ra\x01 \x81\x01Qa\x01 \x85\x01Ra\x01@\x81\x01Q\x90Pa\x01`a\x01@\x85\x01Ra\x0F\xA7a\x01`\x85\x01\x82a\x0EdV[` \x99\x8A\x01\x99\x90\x94P\x92\x90\x92\x01\x91P`\x01\x01a\x0E\xC9V[P\x90\x96\x95PPPPPPV[_\x82``\x81\x01\x83_[`\x03\x81\x10\x15a\x10\x9DW\x83\x83\x03\x87R\x81Q\x80Q\x80\x85R` \x91\x82\x01\x91\x80\x86\x01\x91\x90`\x05\x82\x90\x1B\x87\x01\x01_[\x82\x81\x10\x15a\x10\x83W\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x88\x83\x03\x01\x84R\x84Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81Q\x16\x83R` \x81\x01Q` \x84\x01R`@\x81\x01Q\x90P```@\x84\x01Ra\x10m``\x84\x01\x82a\x0EdV[` \x96\x87\x01\x96\x95\x90\x95\x01\x94\x92PP`\x01\x01a\x0F\xFDV[P` \x9A\x8B\x01\x9A\x90\x96P\x94\x90\x94\x01\x93PPP`\x01\x01a\x0F\xD3V[P\x90\x95\x94PPPPPV[`\x80\x80\x82R\x85Q\x90\x82\x01\x81\x90R_\x90` \x87\x01\x90`\xA0\x84\x01\x90\x83[\x81\x81\x10\x15a\x10\xF7W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83R` \x93\x84\x01\x93\x90\x92\x01\x91`\x01\x01a\x10\xC3V[PP\x83\x81\x03` \x85\x01R\x80\x91P_\x87Q\x80\x83R` \x83\x01\x93P` \x89\x01\x92P_[\x81\x81\x10\x15a\x116W\x83Q\x85R` \x94\x85\x01\x94\x90\x93\x01\x92`\x01\x01a\x11\x18V[PPPP\x82\x81\x03`@\x84\x01Ra\x11L\x81\x86a\x0E\xADV[\x90P\x82\x81\x03``\x84\x01Ra\x11`\x81\x85a\x0F\xCAV[\x97\x96PPPPPPPV[_` \x82\x84\x03\x12\x15a\x11{W__\xFD[\x81Q\x80\x15\x15\x81\x14a\tRW__\xFD[\x81\x81\x03\x81\x81\x11\x15a\t\x85W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[_\x82Qa\x11\xD3\x81\x84` \x87\x01a\x0EBV[\x91\x90\x91\x01\x92\x91PPV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80631626ba7e14610038578063e8333e0d146100a4575b5f5ffd5b61006e610046366004610a63565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b6100b76100b2366004610b14565b6100c5565b60405190815260200161009b565b5f602086018035906100d79088610bcc565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa158015610141573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101659190610be7565b101561017257505f61082e565b61020d8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101be573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101e29190610bfe565b5f6101f060208a018a610bcc565b73ffffffffffffffffffffffffffffffffffffffff169190610838565b61028e8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610259573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061027d9190610bfe565b602088018035906101f0908a610bcc565b6040805160028082526060820183525f926020830190803683370190505090506102bb6020880188610bcc565b815f815181106102cd576102cd610c46565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526102fd90870187610bcc565b8160018151811061031057610310610c46565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160028082526060820183525f9391929091830190803683370190505090508660200135815f8151811061036e5761036e610c46565b60200260200101818152505087602001358160018151811061039257610392610c46565b60209081029190910101526040805160018082528183019092525f91816020015b6104226040518061016001604052805f81526020015f81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020015f81526020015f63ffffffff1681526020015f81526020015f81526020015f81526020015f8152602001606081525090565b8152602001906001900390816103b35790505090506040518061016001604052805f8152602001600181526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020018a6020013581526020018960200135815260200163ffffffff801681526020015f5f1b81526020015f8152602001604081526020015f8152602001306040516020016104e3919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604051602081830303815290604052815250815f8151811061050757610507610c46565b602002602001018190525061051a610a3c565b6020808901359061052d908c018c610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8d61055660208d018d610bcc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa1580156105c4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e89190610be7565b10156107625760408051600180825281830190925290816020015b60408051606080820183525f808352602083015291810191909152815260200190600190039081610603575050815261063f60208b018b610bcc565b815180515f9061065157610651610c46565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff909216909152610684908b018b610bcc565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b36106ac60208b018b610bcc565b60405173ffffffffffffffffffffffffffffffffffffffff909116602482015260208b01356044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b929092179091529050815f60200201515f8151811061075257610752610c46565b6020026020010151604001819052505b61076c8688610ceb565b60208201526040516108279073ffffffffffffffffffffffffffffffffffffffff8d16906313d79a0b906107aa9088908890889088906024016110a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b9290921790915273ffffffffffffffffffffffffffffffffffffffff8e169150610946565b9450505050505b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052905f906108ca90861683610959565b90506108d581610966565b61093f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b5f610952835f8461098b565b9392505050565b6060610952835f846109ba565b5f81515f1480610985575081806020019051810190610985919061116b565b92915050565b5f5a90505f5f83516020850186885af16109a7573d5f5f3e3d5ffd5b5a6109b2908261118a565b949350505050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516109e391906111c2565b5f6040518083038185875af1925050503d805f8114610a1d576040519150601f19603f3d011682016040523d82523d5f602084013e610a22565b606091505b509250905080610a3457815160208301fd5b509392505050565b60405180606001604052806003905b6060815260200190600190039081610a4b5790505090565b5f5f5f60408486031215610a75575f5ffd5b83359250602084013567ffffffffffffffff811115610a92575f5ffd5b8401601f81018613610aa2575f5ffd5b803567ffffffffffffffff811115610ab8575f5ffd5b866020828401011115610ac9575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610afb575f5ffd5b50565b5f60408284031215610b0e575f5ffd5b50919050565b5f5f5f5f5f5f6101008789031215610b2a575f5ffd5b8635610b3581610ada565b9550610b448860208901610afe565b9450610b538860608901610afe565b9350610b628860a08901610afe565b925060e087013567ffffffffffffffff811115610b7d575f5ffd5b8701601f81018913610b8d575f5ffd5b803567ffffffffffffffff811115610ba3575f5ffd5b8960208260051b8401011115610bb7575f5ffd5b60208201935080925050509295509295509295565b5f60208284031215610bdc575f5ffd5b813561095281610ada565b5f60208284031215610bf7575f5ffd5b5051919050565b5f60208284031215610c0e575f5ffd5b815161095281610ada565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040516060810167ffffffffffffffff81118282101715610c9657610c96610c19565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ce357610ce3610c19565b604052919050565b5f67ffffffffffffffff831115610d0457610d04610c19565b8260051b610d1460208201610c9c565b84815290830190602081019036831115610d2c575f5ffd5b845b83811015610e3857803567ffffffffffffffff811115610d4c575f5ffd5b86016060368290031215610d5e575f5ffd5b610d66610c73565b8135610d7181610ada565b815260208281013590820152604082013567ffffffffffffffff811115610d96575f5ffd5b919091019036601f830112610da9575f5ffd5b813567ffffffffffffffff811115610dc357610dc3610c19565b610df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610c9c565b818152366020838601011115610e08575f5ffd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050610d2e565b5095945050505050565b5f5b83811015610e5c578181015183820152602001610e44565b50505f910152565b5f8151808452610e7b816020860160208601610e42565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f82825180855260208501945060208160051b830101602085015f5b83811015610fbe577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0858403018852815180518452602081015160208501526040810151610f2f604086018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015160608501526080810151608085015260a0810151610f5b60a086018263ffffffff169052565b5060c081015160c085015260e081015160e08501526101008101516101008501526101208101516101208501526101408101519050610160610140850152610fa7610160850182610e64565b6020998a0199909450929092019150600101610ec9565b50909695505050505050565b5f8260608101835f5b600381101561109d578383038752815180518085526020918201918086019190600582901b8701015f5b82811015611083577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0888303018452845173ffffffffffffffffffffffffffffffffffffffff815116835260208101516020840152604081015190506060604084015261106d6060840182610e64565b6020968701969590950194925050600101610ffd565b5060209a8b019a9096509490940193505050600101610fd3565b509095945050505050565b608080825285519082018190525f90602087019060a0840190835b818110156110f757835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016110c3565b505083810360208501528091505f87518083526020830193506020890192505f5b81811015611136578351855260209485019490930192600101611118565b50505050828103604084015261114c8186610ead565b905082810360608401526111608185610fca565b979650505050505050565b5f6020828403121561117b575f5ffd5b81518015158114610952575f5ffd5b81810381811115610985577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f82516111d3818460208701610e42565b919091019291505056fea164736f6c634300081e000a + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80c\x16&\xBA~\x14a\08W\x80c\xE83>\r\x14a\0\xA4W[__\xFD[a\0na\0F6`\x04a\ncV[\x7F\x16&\xBA~\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\x92PPPV[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x91\x16\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[a\0\xB7a\0\xB26`\x04a\x0B\x14V[a\0\xC5V[`@Q\x90\x81R` \x01a\0\x9BV[_` \x86\x01\x805\x90a\0\xD7\x90\x88a\x0B\xCCV[`@Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x90\x91\x16\x90cp\xA0\x821\x90`$\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01AW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01e\x91\x90a\x0B\xE7V[\x10\x15a\x01rWP_a\x08.V[a\x02\r\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x01\xBEW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x01\xE2\x91\x90a\x0B\xFEV[_a\x01\xF0` \x8A\x01\x8Aa\x0B\xCCV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91\x90a\x088V[a\x02\x8E\x87s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x9BU,\xC2`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x02YW=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x02}\x91\x90a\x0B\xFEV[` \x88\x01\x805\x90a\x01\xF0\x90\x8Aa\x0B\xCCV[`@\x80Q`\x02\x80\x82R``\x82\x01\x83R_\x92` \x83\x01\x90\x806\x837\x01\x90PP\x90Pa\x02\xBB` \x88\x01\x88a\x0B\xCCV[\x81_\x81Q\x81\x10a\x02\xCDWa\x02\xCDa\x0CFV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16` \x92\x83\x02\x91\x90\x91\x01\x82\x01Ra\x02\xFD\x90\x87\x01\x87a\x0B\xCCV[\x81`\x01\x81Q\x81\x10a\x03\x10Wa\x03\x10a\x0CFV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16` \x92\x83\x02\x91\x90\x91\x01\x82\x01R`@\x80Q`\x02\x80\x82R``\x82\x01\x83R_\x93\x91\x92\x90\x91\x83\x01\x90\x806\x837\x01\x90PP\x90P\x86` \x015\x81_\x81Q\x81\x10a\x03nWa\x03na\x0CFV[` \x02` \x01\x01\x81\x81RPP\x87` \x015\x81`\x01\x81Q\x81\x10a\x03\x92Wa\x03\x92a\x0CFV[` \x90\x81\x02\x91\x90\x91\x01\x01R`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R_\x91\x81` \x01[a\x04\"`@Q\x80a\x01`\x01`@R\x80_\x81R` \x01_\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01_\x81R` \x01_c\xFF\xFF\xFF\xFF\x16\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01_\x81R` \x01``\x81RP\x90V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x03\xB3W\x90PP\x90P`@Q\x80a\x01`\x01`@R\x80_\x81R` \x01`\x01\x81R` \x01_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x8A` \x015\x81R` \x01\x89` \x015\x81R` \x01c\xFF\xFF\xFF\xFF\x80\x16\x81R` \x01__\x1B\x81R` \x01_\x81R` \x01`@\x81R` \x01_\x81R` \x010`@Q` \x01a\x04\xE3\x91\x90``\x91\x90\x91\x1B\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\x16\x81R`\x14\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x81RP\x81_\x81Q\x81\x10a\x05\x07Wa\x05\x07a\x0CFV[` \x02` \x01\x01\x81\x90RPa\x05\x1Aa\n\x8Da\x05V` \x8D\x01\x8Da\x0B\xCCV[`@Q\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\xE0\x85\x90\x1B\x16\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x83\x16`\x04\x82\x01R\x91\x16`$\x82\x01R`D\x01` `@Q\x80\x83\x03\x81\x86Z\xFA\x15\x80\x15a\x05\xC4W=__>=_\xFD[PPPP`@Q=`\x1F\x19`\x1F\x82\x01\x16\x82\x01\x80`@RP\x81\x01\x90a\x05\xE8\x91\x90a\x0B\xE7V[\x10\x15a\x07bW`@\x80Q`\x01\x80\x82R\x81\x83\x01\x90\x92R\x90\x81` \x01[`@\x80Q``\x80\x82\x01\x83R_\x80\x83R` \x83\x01R\x91\x81\x01\x91\x90\x91R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x03WPP\x81Ra\x06?` \x8B\x01\x8Ba\x0B\xCCV[\x81Q\x80Q_\x90a\x06QWa\x06Qa\x0CFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x90\x91Ra\x06\x84\x90\x8B\x01\x8Ba\x0B\xCCV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\t^\xA7\xB3a\x06\xAC` \x8B\x01\x8Ba\x0B\xCCV[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16`$\x82\x01R` \x8B\x015`D\x82\x01R`d\x01`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\xE0\x93\x90\x93\x1B\x92\x90\x92\x17\x90\x91R\x90P\x81_` \x02\x01Q_\x81Q\x81\x10a\x07RWa\x07Ra\x0CFV[` \x02` \x01\x01Q`@\x01\x81\x90RP[a\x07l\x86\x88a\x0C\xEBV[` \x82\x01R`@Qa\x08'\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8D\x16\x90c\x13\xD7\x9A\x0B\x90a\x07\xAA\x90\x88\x90\x88\x90\x88\x90\x88\x90`$\x01a\x10\xA8V[`@\x80Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x84\x03\x01\x81R\x91\x90R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16`\xE0\x93\x90\x93\x1B\x92\x90\x92\x17\x90\x91Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8E\x16\x91Pa\tFV[\x94PPPPP[\x96\x95PPPPPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x81\x16`$\x83\x01R`D\x80\x83\x01\x85\x90R\x83Q\x80\x84\x03\x90\x91\x01\x81R`d\x90\x92\x01\x90\x92R` \x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\t^\xA7\xB3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x90R\x90_\x90a\x08\xCA\x90\x86\x16\x83a\tYV[\x90Pa\x08\xD5\x81a\tfV[a\t?W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7FSafeERC20: approval failed\0\0\0\0\0\0`D\x82\x01R`d\x01`@Q\x80\x91\x03\x90\xFD[PPPPPV[_a\tR\x83_\x84a\t\x8BV[\x93\x92PPPV[``a\tR\x83_\x84a\t\xBAV[_\x81Q_\x14\x80a\t\x85WP\x81\x80` \x01\x90Q\x81\x01\x90a\t\x85\x91\x90a\x11kV[\x92\x91PPV[_Z\x90P__\x83Q` \x85\x01\x86\x88Z\xF1a\t\xA7W=__>=_\xFD[Za\t\xB2\x90\x82a\x11\x8AV[\x94\x93PPPPV[``_\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84\x84`@Qa\t\xE3\x91\x90a\x11\xC2V[_`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80_\x81\x14a\n\x1DW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\n\"V[``\x91P[P\x92P\x90P\x80a\n4W\x81Q` \x83\x01\xFD[P\x93\x92PPPV[`@Q\x80``\x01`@R\x80`\x03\x90[``\x81R` \x01\x90`\x01\x90\x03\x90\x81a\nKW\x90PP\x90V[___`@\x84\x86\x03\x12\x15a\nuW__\xFD[\x835\x92P` \x84\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\x92W__\xFD[\x84\x01`\x1F\x81\x01\x86\x13a\n\xA2W__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\n\xB8W__\xFD[\x86` \x82\x84\x01\x01\x11\x15a\n\xC9W__\xFD[\x93\x96` \x91\x90\x91\x01\x95P\x92\x93PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x81\x14a\n\xFBW__\xFD[PV[_`@\x82\x84\x03\x12\x15a\x0B\x0EW__\xFD[P\x91\x90PV[______a\x01\0\x87\x89\x03\x12\x15a\x0B*W__\xFD[\x865a\x0B5\x81a\n\xDAV[\x95Pa\x0BD\x88` \x89\x01a\n\xFEV[\x94Pa\x0BS\x88``\x89\x01a\n\xFEV[\x93Pa\x0Bb\x88`\xA0\x89\x01a\n\xFEV[\x92P`\xE0\x87\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x0B}W__\xFD[\x87\x01`\x1F\x81\x01\x89\x13a\x0B\x8DW__\xFD[\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\x0B\xA3W__\xFD[\x89` \x82`\x05\x1B\x84\x01\x01\x11\x15a\x0B\xB7W__\xFD[` \x82\x01\x93P\x80\x92PPP\x92\x95P\x92\x95P\x92\x95V[_` \x82\x84\x03\x12\x15a\x0B\xDCW__\xFD[\x815a\tR\x81a\n\xDAV[_` \x82\x84\x03\x12\x15a\x0B\xF7W__\xFD[PQ\x91\x90PV[_` \x82\x84\x03\x12\x15a\x0C\x0EW__\xFD[\x81Qa\tR\x81a\n\xDAV[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`A`\x04R`$_\xFD[\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`2`\x04R`$_\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x0C\x96Wa\x0C\x96a\x0C\x19V[`@R\x90V[`@Q`\x1F\x82\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x0C\xE3Wa\x0C\xE3a\x0C\x19V[`@R\x91\x90PV[_g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11\x15a\r\x04Wa\r\x04a\x0C\x19V[\x82`\x05\x1Ba\r\x14` \x82\x01a\x0C\x9CV[\x84\x81R\x90\x83\x01\x90` \x81\x01\x906\x83\x11\x15a\r,W__\xFD[\x84[\x83\x81\x10\x15a\x0E8W\x805g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\rLW__\xFD[\x86\x01``6\x82\x90\x03\x12\x15a\r^W__\xFD[a\rfa\x0CsV[\x815a\rq\x81a\n\xDAV[\x81R` \x82\x81\x015\x90\x82\x01R`@\x82\x015g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r\x96W__\xFD[\x91\x90\x91\x01\x906`\x1F\x83\x01\x12a\r\xA9W__\xFD[\x815g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x15a\r\xC3Wa\r\xC3a\x0C\x19V[a\r\xF4` \x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0`\x1F\x84\x01\x16\x01a\x0C\x9CV[\x81\x81R6` \x83\x86\x01\x01\x11\x15a\x0E\x08W__\xFD[\x81` \x85\x01` \x83\x017_` \x83\x83\x01\x01R\x80`@\x84\x01RPP\x80\x85RPP` \x83\x01\x92P` \x81\x01\x90Pa\r.V[P\x95\x94PPPPPV[_[\x83\x81\x10\x15a\x0E\\W\x81\x81\x01Q\x83\x82\x01R` \x01a\x0EDV[PP_\x91\x01RV[_\x81Q\x80\x84Ra\x0E{\x81` \x86\x01` \x86\x01a\x0EBV[`\x1F\x01\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x16\x92\x90\x92\x01` \x01\x92\x91PPV[_\x82\x82Q\x80\x85R` \x85\x01\x94P` \x81`\x05\x1B\x83\x01\x01` \x85\x01_[\x83\x81\x10\x15a\x0F\xBEW\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x85\x84\x03\x01\x88R\x81Q\x80Q\x84R` \x81\x01Q` \x85\x01R`@\x81\x01Qa\x0F/`@\x86\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90RV[P``\x81\x01Q``\x85\x01R`\x80\x81\x01Q`\x80\x85\x01R`\xA0\x81\x01Qa\x0F[`\xA0\x86\x01\x82c\xFF\xFF\xFF\xFF\x16\x90RV[P`\xC0\x81\x01Q`\xC0\x85\x01R`\xE0\x81\x01Q`\xE0\x85\x01Ra\x01\0\x81\x01Qa\x01\0\x85\x01Ra\x01 \x81\x01Qa\x01 \x85\x01Ra\x01@\x81\x01Q\x90Pa\x01`a\x01@\x85\x01Ra\x0F\xA7a\x01`\x85\x01\x82a\x0EdV[` \x99\x8A\x01\x99\x90\x94P\x92\x90\x92\x01\x91P`\x01\x01a\x0E\xC9V[P\x90\x96\x95PPPPPPV[_\x82``\x81\x01\x83_[`\x03\x81\x10\x15a\x10\x9DW\x83\x83\x03\x87R\x81Q\x80Q\x80\x85R` \x91\x82\x01\x91\x80\x86\x01\x91\x90`\x05\x82\x90\x1B\x87\x01\x01_[\x82\x81\x10\x15a\x10\x83W\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x88\x83\x03\x01\x84R\x84Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81Q\x16\x83R` \x81\x01Q` \x84\x01R`@\x81\x01Q\x90P```@\x84\x01Ra\x10m``\x84\x01\x82a\x0EdV[` \x96\x87\x01\x96\x95\x90\x95\x01\x94\x92PP`\x01\x01a\x0F\xFDV[P` \x9A\x8B\x01\x9A\x90\x96P\x94\x90\x94\x01\x93PPP`\x01\x01a\x0F\xD3V[P\x90\x95\x94PPPPPV[`\x80\x80\x82R\x85Q\x90\x82\x01\x81\x90R_\x90` \x87\x01\x90`\xA0\x84\x01\x90\x83[\x81\x81\x10\x15a\x10\xF7W\x83Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83R` \x93\x84\x01\x93\x90\x92\x01\x91`\x01\x01a\x10\xC3V[PP\x83\x81\x03` \x85\x01R\x80\x91P_\x87Q\x80\x83R` \x83\x01\x93P` \x89\x01\x92P_[\x81\x81\x10\x15a\x116W\x83Q\x85R` \x94\x85\x01\x94\x90\x93\x01\x92`\x01\x01a\x11\x18V[PPPP\x82\x81\x03`@\x84\x01Ra\x11L\x81\x86a\x0E\xADV[\x90P\x82\x81\x03``\x84\x01Ra\x11`\x81\x85a\x0F\xCAV[\x97\x96PPPPPPPV[_` \x82\x84\x03\x12\x15a\x11{W__\xFD[\x81Q\x80\x15\x15\x81\x14a\tRW__\xFD[\x81\x81\x03\x81\x81\x11\x15a\t\x85W\x7FNH{q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0_R`\x11`\x04R`$_\xFD[_\x82Qa\x11\xD3\x81\x84` \x87\x01a\x0EBV[\x91\x90\x91\x01\x92\x91PPV\xFE\xA1dsolcC\0\x08\x1E\0\n", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Allowance { address spender; uint256 amount; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Allowance { + #[allow(missing_docs)] + pub spender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Allowance) -> Self { + (value.spender, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Allowance { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + amount: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Allowance { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Allowance { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Allowance { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Allowance { + const NAME: &'static str = "Allowance"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed("Allowance(address spender,uint256 amount)") + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.spender, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Allowance { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.spender, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.spender, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Asset { address token; uint256 amount; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Asset { + #[allow(missing_docs)] + pub token: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Asset) -> Self { + (value.token, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Asset { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + token: tuple.0, + amount: tuple.1, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Asset { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Asset { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.token, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Asset { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Asset { + const NAME: &'static str = "Asset"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed("Asset(address token,uint256 amount)") + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.token, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Asset { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.token, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.token, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct Interaction { address target; uint256 value; bytes callData; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct Interaction { + #[allow(missing_docs)] + pub target: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub callData: alloy_sol_types::private::Bytes, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: Interaction) -> Self { + (value.target, value.value, value.callData) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for Interaction { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + target: tuple.0, + value: tuple.1, + callData: tuple.2, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for Interaction { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for Interaction { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.target, + ), + as alloy_sol_types::SolType>::tokenize( + &self.value, + ), + ::tokenize( + &self.callData, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for Interaction { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for Interaction { + const NAME: &'static str = "Interaction"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "Interaction(address target,uint256 value,bytes callData)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.target, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.value) + .0, + ::eip712_data_word( + &self.callData, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for Interaction { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.target, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.value) + + ::topic_preimage_length( + &rust.callData, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.target, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.value, + out, + ); + ::encode_topic_preimage( + &rust.callData, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `isValidSignature(bytes32,bytes)` and selector `0x1626ba7e`. + ```solidity + function isValidSignature(bytes32, bytes memory) external pure returns (bytes4); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureCall { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<32>, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`isValidSignature(bytes32,bytes)`](isValidSignatureCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct isValidSignatureReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::FixedBytes<4>, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::FixedBytes<32>, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureCall) -> Self { + (value._0, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<4>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: isValidSignatureReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for isValidSignatureReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for isValidSignatureCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = alloy_sol_types::private::FixedBytes<4>; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<4>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [22u8, 38u8, 186u8, 126u8]; + const SIGNATURE: &'static str = "isValidSignature(bytes32,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self._0), + ::tokenize( + &self._1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: isValidSignatureReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swap(address,(address,uint256),(address,uint256),(address,uint256),(address,uint256,bytes)[])` and selector `0xe8333e0d`. + ```solidity + function swap(address settlement, Asset memory sell, Asset memory buy, Allowance memory allowance, Interaction[] memory calls) external returns (uint256 gasUsed); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapCall { + #[allow(missing_docs)] + pub settlement: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub sell: ::RustType, + #[allow(missing_docs)] + pub buy: ::RustType, + #[allow(missing_docs)] + pub allowance: ::RustType, + #[allow(missing_docs)] + pub calls: + alloy_sol_types::private::Vec<::RustType>, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swap(address,(address,uint256),(address,uint256),(address,uint256), + /// (address,uint256,bytes)[])`](swapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapReturn { + #[allow(missing_docs)] + pub gasUsed: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + Asset, + Asset, + Allowance, + alloy_sol_types::sol_data::Array, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + ::RustType, + ::RustType, + ::RustType, + alloy_sol_types::private::Vec<::RustType>, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapCall) -> Self { + ( + value.settlement, + value.sell, + value.buy, + value.allowance, + value.calls, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + settlement: tuple.0, + sell: tuple.1, + buy: tuple.2, + allowance: tuple.3, + calls: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapReturn) -> Self { + (value.gasUsed,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { gasUsed: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + Asset, + Asset, + Allowance, + alloy_sol_types::sol_data::Array, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 51u8, 62u8, 13u8]; + const SIGNATURE: &'static str = "swap(address,(address,uint256),(address,uint256),\ + (address,uint256),(address,uint256,bytes)[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.settlement, + ), + ::tokenize(&self.sell), + ::tokenize(&self.buy), + ::tokenize(&self.allowance), + as alloy_sol_types::SolType>::tokenize(&self.calls), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapReturn = r.into(); + r.gasUsed + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapReturn = r.into(); + r.gasUsed + }) + } + } + }; + ///Container for all the [`Swapper`](self) function calls. + #[derive(Clone)] + pub enum SwapperCalls { + #[allow(missing_docs)] + isValidSignature(isValidSignatureCall), + #[allow(missing_docs)] + swap(swapCall), + } + impl SwapperCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[22u8, 38u8, 186u8, 126u8], [232u8, 51u8, 62u8, 13u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(isValidSignature), + ::core::stringify!(swap), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for SwapperCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 96usize; + const NAME: &'static str = "SwapperCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::isValidSignature(_) => { + ::SELECTOR + } + Self::swap(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn isValidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SwapperCalls::isValidSignature) + } + isValidSignature + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SwapperCalls::swap) + } + swap + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn isValidSignature(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(SwapperCalls::isValidSignature) + } + isValidSignature + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SwapperCalls::swap) + } + swap + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::isValidSignature(inner) => { + ::abi_encoded_size(inner) + } + Self::swap(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::isValidSignature(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swap(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`Swapper`](self) contract instance. + + See the [wrapper's documentation](`SwapperInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> SwapperInstance { + SwapperInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + SwapperInstance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + SwapperInstance::::deploy_builder(__provider) + } + /**A [`Swapper`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`Swapper`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct SwapperInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for SwapperInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("SwapperInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + SwapperInstance + { + /**Creates a new wrapper around an on-chain [`Swapper`](self) contract instance. + + See the [wrapper's documentation](`SwapperInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl SwapperInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> SwapperInstance { + SwapperInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + SwapperInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`isValidSignature`] function. + pub fn isValidSignature( + &self, + _0: alloy_sol_types::private::FixedBytes<32>, + _1: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, isValidSignatureCall, N> { + self.call_builder(&isValidSignatureCall { _0, _1 }) + } + + ///Creates a new call builder for the [`swap`] function. + pub fn swap( + &self, + settlement: alloy_sol_types::private::Address, + sell: ::RustType, + buy: ::RustType, + allowance: ::RustType, + calls: alloy_sol_types::private::Vec< + ::RustType, + >, + ) -> alloy_contract::SolCallBuilder<&P, swapCall, N> { + self.call_builder(&swapCall { + settlement, + sell, + buy, + allowance, + calls, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + SwapperInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = Swapper::SwapperInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/swaprrouter/Cargo.toml b/contracts/generated/contracts-generated/swaprrouter/Cargo.toml new file mode 100644 index 0000000000..f33aba7f10 --- /dev/null +++ b/contracts/generated/contracts-generated/swaprrouter/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-swaprrouter" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/swaprrouter/src/lib.rs b/contracts/generated/contracts-generated/swaprrouter/src/lib.rs new file mode 100644 index 0000000000..08100f9c89 --- /dev/null +++ b/contracts/generated/contracts-generated/swaprrouter/src/lib.rs @@ -0,0 +1,1586 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface SwaprRouter { + function WETH() external pure returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external pure returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod SwaprRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`SwaprRouter`](self) function calls. + #[derive(Clone)] + pub enum SwaprRouterCalls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl SwaprRouterCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for SwaprRouterCalls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "SwaprRouterCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(SwaprRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SwaprRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SwaprRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SwaprRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(SwaprRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(SwaprRouterCalls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SwaprRouterCalls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SwaprRouterCalls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(SwaprRouterCalls::factory) + } + factory + }, + { + fn addLiquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(SwaprRouterCalls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`SwaprRouter`](self) contract instance. + + See the [wrapper's documentation](`SwaprRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> SwaprRouterInstance { + SwaprRouterInstance::::new(address, __provider) + } + /**A [`SwaprRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`SwaprRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct SwaprRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for SwaprRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("SwaprRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + SwaprRouterInstance + { + /**Creates a new wrapper around an on-chain [`SwaprRouter`](self) contract instance. + + See the [wrapper's documentation](`SwaprRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl SwaprRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> SwaprRouterInstance { + SwaprRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + SwaprRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + SwaprRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = SwaprRouter::SwaprRouterInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xb9960d9bca016e9748be75dd52f02188b9d0829f"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xE43e60736b1cb4a75ad25240E2f9a62Bff65c0C0"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x530476d5583724A89c8841eB6Da76E7Af4C0F17E"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/testnetuniswapv2router02/Cargo.toml b/contracts/generated/contracts-generated/testnetuniswapv2router02/Cargo.toml new file mode 100644 index 0000000000..75fff0fbb5 --- /dev/null +++ b/contracts/generated/contracts-generated/testnetuniswapv2router02/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-testnetuniswapv2router02" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/testnetuniswapv2router02/src/lib.rs b/contracts/generated/contracts-generated/testnetuniswapv2router02/src/lib.rs new file mode 100644 index 0000000000..82fea0f265 --- /dev/null +++ b/contracts/generated/contracts-generated/testnetuniswapv2router02/src/lib.rs @@ -0,0 +1,1603 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface TestnetUniswapV2Router02 { + function WETH() external pure returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external pure returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod TestnetUniswapV2Router02 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external pure returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`TestnetUniswapV2Router02`](self) function calls. + #[derive(Clone)] + pub enum TestnetUniswapV2Router02Calls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl TestnetUniswapV2Router02Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for TestnetUniswapV2Router02Calls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "TestnetUniswapV2Router02Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw( + data, + ) + .map(TestnetUniswapV2Router02Calls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(TestnetUniswapV2Router02Calls::WETH) + } + WETH + }, + { + fn quote( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(TestnetUniswapV2Router02Calls::quote) + } + quote + }, + { + fn factory( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(TestnetUniswapV2Router02Calls::factory) + } + factory + }, + { + fn addLiquidity( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(TestnetUniswapV2Router02Calls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + TestnetUniswapV2Router02Calls, + >] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(TestnetUniswapV2Router02Calls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(TestnetUniswapV2Router02Calls::WETH) + } + WETH + }, + { + fn quote( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(TestnetUniswapV2Router02Calls::quote) + } + quote + }, + { + fn factory( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate(data) + .map(TestnetUniswapV2Router02Calls::factory) + } + factory + }, + { + fn addLiquidity( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw_validate( + data, + ) + .map(TestnetUniswapV2Router02Calls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`TestnetUniswapV2Router02`](self) contract instance. + + See the [wrapper's documentation](`TestnetUniswapV2Router02Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> TestnetUniswapV2Router02Instance { + TestnetUniswapV2Router02Instance::::new(address, __provider) + } + /**A [`TestnetUniswapV2Router02`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`TestnetUniswapV2Router02`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct TestnetUniswapV2Router02Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for TestnetUniswapV2Router02Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("TestnetUniswapV2Router02Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + TestnetUniswapV2Router02Instance + { + /**Creates a new wrapper around an on-chain [`TestnetUniswapV2Router02`](self) contract instance. + + See the [wrapper's documentation](`TestnetUniswapV2Router02Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl TestnetUniswapV2Router02Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> TestnetUniswapV2Router02Instance { + TestnetUniswapV2Router02Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + TestnetUniswapV2Router02Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + TestnetUniswapV2Router02Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = + TestnetUniswapV2Router02::TestnetUniswapV2Router02Instance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 11155111u64 => Some(( + ::alloy_primitives::address!("0x86dcd3293C53Cf8EFd7303B57beb2a3F671dDE98"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/uniswapv2factory/Cargo.toml b/contracts/generated/contracts-generated/uniswapv2factory/Cargo.toml new file mode 100644 index 0000000000..6fb108842d --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv2factory/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-uniswapv2factory" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/uniswapv2factory/src/lib.rs b/contracts/generated/contracts-generated/uniswapv2factory/src/lib.rs new file mode 100644 index 0000000000..910bde2c93 --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv2factory/src/lib.rs @@ -0,0 +1,1191 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface UniswapV2Factory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint256); + + constructor(address _feeToSetter); + + function createPair(address tokenA, address tokenB) external returns (address pair); + function getPair(address, address) external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_feeToSetter", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createPair", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "pair", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getPair", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + }, + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "PairCreated", + "inputs": [ + { + "name": "token0", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token1", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "pair", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod UniswapV2Factory { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x608060405234801561001057600080fd5b506040516136863803806136868339818101604052602081101561003357600080fd5b5051600180546001600160a01b0319166001600160a01b03909216919091179055613623806100636000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063a2e74af61161005b578063a2e74af6146100fd578063c9c6539614610132578063e6a439051461016d578063f46901ed146101a857610088565b8063017e7e581461008d578063094b7415146100be5780631e3dd18b146100c6578063574f2ba3146100e3575b600080fd5b6100956101db565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100956101f7565b610095600480360360208110156100dc57600080fd5b5035610213565b6100eb610247565b60408051918252519081900360200190f35b6101306004803603602081101561011357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661024d565b005b6100956004803603604081101561014857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661031a565b6100956004803603604081101561018357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661076d565b610130600480360360208110156101be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166107a0565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6003818154811061022057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60035490565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156103b757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056323a204944454e544943414c5f4144445245535345530000604482015290519081900360640190fd5b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16106103f45783856103f7565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff821661047e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f556e697377617056323a205a45524f5f41444452455353000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526002602090815260408083208585168452909152902054161561051f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e697377617056323a20504149525f45584953545300000000000000000000604482015290519081900360640190fd5b6060604051806020016105319061086d565b6020820181038252601f19601f82011660405250905060008383604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140192505050604051602081830303815290604052805190602001209050808251602084016000f5604080517f485cc95500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152868116602483015291519297509087169163485cc9559160448082019260009290919082900301818387803b15801561065e57600080fd5b505af1158015610672573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff84811660008181526002602081815260408084208987168086529083528185208054978d167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90950180549097168417909655925483519283529082015281517f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9929181900390910190a35050505092915050565b600260209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff16331461082657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b612d748061087b8339019056fe60806040526001600c5534801561001557600080fd5b506040514690806052612d228239604080519182900360520182208282018252600a8352692ab734b9bbb0b8102b1960b11b6020938401528151808301835260018152603160f81b908401528151808401919091527fbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c09094019052825192019190912060035550600580546001600160a01b03191633179055612c1d806101056000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a265627a7a723158202760f92d7fa1db6f5aa16307bad65df4ebcc8550c4b1f03755ab8dfd830c178f64736f6c63430005100032 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa6\x868\x03\x80a6\x86\x839\x81\x81\x01`@R` \x81\x10\x15a\x003W`\0\x80\xFD[PQ`\x01\x80T`\x01`\x01`\xA0\x1B\x03\x19\x16`\x01`\x01`\xA0\x1B\x03\x90\x92\x16\x91\x90\x91\x17\x90Ua6#\x80a\0c`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\x88W`\x005`\xE0\x1C\x80c\xA2\xE7J\xF6\x11a\0[W\x80c\xA2\xE7J\xF6\x14a\0\xFDW\x80c\xC9\xC6S\x96\x14a\x012W\x80c\xE6\xA49\x05\x14a\x01mW\x80c\xF4i\x01\xED\x14a\x01\xA8Wa\0\x88V[\x80c\x01~~X\x14a\0\x8DW\x80c\tKt\x15\x14a\0\xBEW\x80c\x1E=\xD1\x8B\x14a\0\xC6W\x80cWO+\xA3\x14a\0\xE3W[`\0\x80\xFD[a\0\x95a\x01\xDBV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\0\x95a\x01\xF7V[a\0\x95`\x04\x806\x03` \x81\x10\x15a\0\xDCW`\0\x80\xFD[P5a\x02\x13V[a\0\xEBa\x02GV[`@\x80Q\x91\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x010`\x04\x806\x03` \x81\x10\x15a\x01\x13W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x02MV[\0[a\0\x95`\x04\x806\x03`@\x81\x10\x15a\x01HW`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x015\x16a\x03\x1AV[a\0\x95`\x04\x806\x03`@\x81\x10\x15a\x01\x83W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x015\x16a\x07mV[a\x010`\x04\x806\x03` \x81\x10\x15a\x01\xBEW`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x07\xA0V[`\0Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`\x01Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`\x03\x81\x81T\x81\x10a\x02 W\xFE[`\0\x91\x82R` \x90\x91 \x01Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90P\x81V[`\x03T\x90V[`\x01Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x02\xD3W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7FUniswapV2: FORBIDDEN\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\x01\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x91\x90\x91\x17\x90UV[`\0\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15a\x03\xB7W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FUniswapV2: IDENTICAL_ADDRESSES\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x10a\x03\xF4W\x83\x85a\x03\xF7V[\x84\x84[\x90\x92P\x90Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16a\x04~W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FUniswapV2: ZERO_ADDRESS\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x81\x16`\0\x90\x81R`\x02` \x90\x81R`@\x80\x83 \x85\x85\x16\x84R\x90\x91R\x90 T\x16\x15a\x05\x1FW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x16`$\x82\x01R\x7FUniswapV2: PAIR_EXISTS\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[```@Q\x80` \x01a\x051\x90a\x08mV[` \x82\x01\x81\x03\x82R`\x1F\x19`\x1F\x82\x01\x16`@RP\x90P`\0\x83\x83`@Q` \x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16``\x1B\x81R`\x14\x01\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16``\x1B\x81R`\x14\x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x80\x82Q` \x84\x01`\0\xF5`@\x80Q\x7FH\\\xC9U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x81\x16`\x04\x83\x01R\x86\x81\x16`$\x83\x01R\x91Q\x92\x97P\x90\x87\x16\x91cH\\\xC9U\x91`D\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a\x06^W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x06rW=`\0\x80>=`\0\xFD[PPPPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x81\x16`\0\x81\x81R`\x02` \x81\x81R`@\x80\x84 \x89\x87\x16\x80\x86R\x90\x83R\x81\x85 \x80T\x97\x8D\x16\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x98\x89\x16\x81\x17\x90\x91U\x93\x83R\x81\x85 \x86\x86R\x83R\x81\x85 \x80T\x88\x16\x85\x17\x90U`\x03\x80T`\x01\x81\x01\x82U\x95\x81\x90R\x7F\xC2WZ\x0E\x9EY<\0\xF9Y\xF8\xC9/\x12\xDB(i\xC39Z;\x05\x02\xD0^%\x16Doq\xF8[\x90\x95\x01\x80T\x90\x97\x16\x84\x17\x90\x96U\x92T\x83Q\x92\x83R\x90\x82\x01R\x81Q\x7F\r6H\xBD\x0Fk\xA8\x014\xA3;\xA9'Z\xC5\x85\xD9\xD3\x15\xF0\xAD\x83U\xCD\xDE\xFD\xE3\x1A\xFA(\xD0\xE9\x92\x91\x81\x90\x03\x90\x91\x01\x90\xA3PPPP\x92\x91PPV[`\x02` \x90\x81R`\0\x92\x83R`@\x80\x84 \x90\x91R\x90\x82R\x90 Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`\x01Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x08&W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7FUniswapV2: FORBIDDEN\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x91\x90\x91\x17\x90UV[a-t\x80a\x08{\x839\x01\x90V\xFE`\x80`@R`\x01`\x0CU4\x80\x15a\0\x15W`\0\x80\xFD[P`@QF\x90\x80`Ra-\"\x829`@\x80Q\x91\x82\x90\x03`R\x01\x82 \x82\x82\x01\x82R`\n\x83Ri*\xB74\xB9\xBB\xB0\xB8\x10+\x19`\xB1\x1B` \x93\x84\x01R\x81Q\x80\x83\x01\x83R`\x01\x81R`1`\xF8\x1B\x90\x84\x01R\x81Q\x80\x84\x01\x91\x90\x91R\x7F\xBF\xCC\x8E\xF9\x8F\xFB\xF7\xB6\xC3\xFE\xC7\xBFQ\x85\xB5f\xB9\x86>5\xA9\xD8:\xCDI\xADh$\xB5\x96\x978\x81\x83\x01R\x7F\xC8\x9E\xFD\xAAT\xC0\xF2\x0Cz\xDFa(\x82\xDF\tP\xF5\xA9Qc~\x03\x07\xCD\xCBLg/)\x8B\x8B\xC6``\x82\x01R`\x80\x81\x01\x94\x90\x94R0`\xA0\x80\x86\x01\x91\x90\x91R\x81Q\x80\x86\x03\x90\x91\x01\x81R`\xC0\x90\x94\x01\x90R\x82Q\x92\x01\x91\x90\x91 `\x03UP`\x05\x80T`\x01`\x01`\xA0\x1B\x03\x19\x163\x17\x90Ua,\x1D\x80a\x01\x05`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\x01\xB9W`\x005`\xE0\x1C\x80cjbxB\x11a\0\xF9W\x80c\xBA\x9AzV\x11a\0\x97W\x80c\xD2\x12 \xA7\x11a\0qW\x80c\xD2\x12 \xA7\x14a\x05\xDAW\x80c\xD5\x05\xAC\xCF\x14a\x05\xE2W\x80c\xDDb\xED>\x14a\x06@W\x80c\xFF\xF6\xCA\xE9\x14a\x06{Wa\x01\xB9V[\x80c\xBA\x9AzV\x14a\x05\x97W\x80c\xBC%\xCFw\x14a\x05\x9FW\x80c\xC4Z\x01U\x14a\x05\xD2Wa\x01\xB9V[\x80c~\xCE\xBE\0\x11a\0\xD3W\x80c~\xCE\xBE\0\x14a\x04\xD7W\x80c\x89\xAF\xCBD\x14a\x05\nW\x80c\x95\xD8\x9BA\x14a\x05VW\x80c\xA9\x05\x9C\xBB\x14a\x05^Wa\x01\xB9V[\x80cjbxB\x14a\x04iW\x80cp\xA0\x821\x14a\x04\x9CW\x80ctd\xFC=\x14a\x04\xCFWa\x01\xB9V[\x80c#\xB8r\xDD\x11a\x01fW\x80c6D\xE5\x15\x11a\x01@W\x80c6D\xE5\x15\x14a\x04\x16W\x80cH\\\xC9U\x14a\x04\x1EW\x80cY\t\xC0\xD5\x14a\x04YW\x80cZ=T\x93\x14a\x04aWa\x01\xB9V[\x80c#\xB8r\xDD\x14a\x03\xADW\x80c0\xAD\xF8\x1F\x14a\x03\xF0W\x80c1<\xE5g\x14a\x03\xF8Wa\x01\xB9V[\x80c\t^\xA7\xB3\x11a\x01\x97W\x80c\t^\xA7\xB3\x14a\x03\x15W\x80c\r\xFE\x16\x81\x14a\x03bW\x80c\x18\x16\r\xDD\x14a\x03\x93Wa\x01\xB9V[\x80c\x02,\r\x9F\x14a\x01\xBEW\x80c\x06\xFD\xDE\x03\x14a\x02YW\x80c\t\x02\xF1\xAC\x14a\x02\xD6W[`\0\x80\xFD[a\x02W`\x04\x806\x03`\x80\x81\x10\x15a\x01\xD4W`\0\x80\xFD[\x815\x91` \x81\x015\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF`@\x83\x015\x16\x91\x90\x81\x01\x90`\x80\x81\x01``\x82\x015d\x01\0\0\0\0\x81\x11\x15a\x02\x18W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x02*W`\0\x80\xFD[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x02LW`\0\x80\xFD[P\x90\x92P\x90Pa\x06\x83V[\0[a\x02aa\rWV[`@\x80Q` \x80\x82R\x83Q\x81\x83\x01R\x83Q\x91\x92\x83\x92\x90\x83\x01\x91\x85\x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x02\x9BW\x81\x81\x01Q\x83\x82\x01R` \x01a\x02\x83V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x02\xC8W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[a\x02\xDEa\r\x90V[`@\x80Qm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x94\x85\x16\x81R\x92\x90\x93\x16` \x83\x01Rc\xFF\xFF\xFF\xFF\x16\x81\x83\x01R\x90Q\x90\x81\x90\x03``\x01\x90\xF3[a\x03N`\x04\x806\x03`@\x81\x10\x15a\x03+W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a\r\xE5V[`@\x80Q\x91\x15\x15\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x03ja\r\xFCV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x03\x9Ba\x0E\x18V[`@\x80Q\x91\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x03N`\x04\x806\x03``\x81\x10\x15a\x03\xC3W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x90\x91\x16\x90`@\x015a\x0E\x1EV[a\x03\x9Ba\x0E\xFDV[a\x04\0a\x0F!V[`@\x80Q`\xFF\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[a\x03\x9Ba\x0F&V[a\x02W`\x04\x806\x03`@\x81\x10\x15a\x044W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x015\x16a\x0F,V[a\x03\x9Ba\x10\x05V[a\x03\x9Ba\x10\x0BV[a\x03\x9B`\x04\x806\x03` \x81\x10\x15a\x04\x7FW`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x10\x11V[a\x03\x9B`\x04\x806\x03` \x81\x10\x15a\x04\xB2W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x13\xCBV[a\x03\x9Ba\x13\xDDV[a\x03\x9B`\x04\x806\x03` \x81\x10\x15a\x04\xEDW`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x13\xE3V[a\x05=`\x04\x806\x03` \x81\x10\x15a\x05 W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x13\xF5V[`@\x80Q\x92\x83R` \x83\x01\x91\x90\x91R\x80Q\x91\x82\x90\x03\x01\x90\xF3[a\x02aa\x18\x92V[a\x03N`\x04\x806\x03`@\x81\x10\x15a\x05tW`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a\x18\xCBV[a\x03\x9Ba\x18\xD8V[a\x02W`\x04\x806\x03` \x81\x10\x15a\x05\xB5W`\0\x80\xFD[P5s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16a\x18\xDEV[a\x03ja\x1A\xD4V[a\x03ja\x1A\xF0V[a\x02W`\x04\x806\x03`\xE0\x81\x10\x15a\x05\xF8W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x90\x91\x16\x90`@\x81\x015\x90``\x81\x015\x90`\xFF`\x80\x82\x015\x16\x90`\xA0\x81\x015\x90`\xC0\x015a\x1B\x0CV[a\x03\x9B`\x04\x806\x03`@\x81\x10\x15a\x06VW`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x015\x16a\x1D\xD8V[a\x02Wa\x1D\xF5V[`\x0CT`\x01\x14a\x06\xF4W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7FUniswapV2: LOCKED\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0`\x0CU\x84\x15\x15\x80a\x07\x07WP`\0\x84\x11[a\x07\\W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`%\x81R` \x01\x80a+/`%\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x80a\x07ga\r\x90V[P\x91P\x91P\x81m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x87\x10\x80\x15a\x07\x9AWP\x80m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x86\x10[a\x07\xEFW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`!\x81R` \x01\x80a+x`!\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\x06T`\x07T`\0\x91\x82\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16\x91\x90\x81\x16\x90\x89\x16\x82\x14\x80\x15\x90a\x08TWP\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x89s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15[a\x08\xBFW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7FUniswapV2: INVALID_TO\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x8A\x15a\x08\xD0Wa\x08\xD0\x82\x8A\x8Da\x1F\xDBV[\x89\x15a\x08\xE1Wa\x08\xE1\x81\x8A\x8Ca\x1F\xDBV[\x86\x15a\t\xC3W\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x10\xD1\xE8\\3\x8D\x8D\x8C\x8C`@Q\x86c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x85\x81R` \x01\x84\x81R` \x01\x80` \x01\x82\x81\x03\x82R\x84\x84\x82\x81\x81R` \x01\x92P\x80\x82\x847`\0\x81\x84\x01R`\x1F\x19`\x1F\x82\x01\x16\x90P\x80\x83\x01\x92PPP\x96PPPPPPP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\t\xAAW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\t\xBEW=`\0\x80>=`\0\xFD[PPPP[`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x91cp\xA0\x821\x91`$\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\n/W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\nCW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\nYW`\0\x80\xFD[PQ`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q\x91\x95Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\n\xCBW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\n\xDFW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\n\xF5W`\0\x80\xFD[PQ\x92P`\0\x91PPm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x8A\x90\x03\x83\x11a\x0B\x1FW`\0a\x0B5V[\x89\x85m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03\x83\x03[\x90P`\0\x89\x85m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03\x83\x11a\x0BYW`\0a\x0BoV[\x89\x85m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x03\x83\x03[\x90P`\0\x82\x11\x80a\x0B\x80WP`\0\x81\x11[a\x0B\xD5W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`$\x81R` \x01\x80a+T`$\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0a\x0C\ta\x0B\xEB\x84`\x03c\xFF\xFF\xFF\xFFa!\xE8\x16V[a\x0B\xFD\x87a\x03\xE8c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x90c\xFF\xFF\xFF\xFFa\"n\x16V[\x90P`\0a\x0C!a\x0B\xEB\x84`\x03c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x90Pa\x0CYb\x0FB@a\x0CMm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8B\x81\x16\x90\x8B\x16c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x90c\xFF\xFF\xFF\xFFa!\xE8\x16V[a\x0Ci\x83\x83c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x10\x15a\x0C\xD6W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x0C`$\x82\x01R\x7FUniswapV2: K\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[PPa\x0C\xE4\x84\x84\x88\x88a\"\xE0V[`@\x80Q\x83\x81R` \x81\x01\x83\x90R\x80\x82\x01\x8D\x90R``\x81\x01\x8C\x90R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8B\x16\x913\x91\x7F\xD7\x8A\xD9_\xA4l\x99KeQ\xD0\xDA\x85\xFC'_\xE6\x13\xCE7e\x7F\xB8\xD5\xE3\xD10\x84\x01Y\xD8\"\x91\x81\x90\x03`\x80\x01\x90\xA3PP`\x01`\x0CUPPPPPPPPPV[`@Q\x80`@\x01`@R\x80`\n\x81R` \x01\x7FUniswap V2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP\x81V[`\x08Tm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16\x92n\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x83\x04\x90\x91\x16\x91|\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04c\xFF\xFF\xFF\xFF\x16\x90V[`\0a\r\xF23\x84\x84a%\x9CV[P`\x01[\x92\x91PPV[`\x06Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`\0T\x81V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16`\0\x90\x81R`\x02` \x90\x81R`@\x80\x83 3\x84R\x90\x91R\x81 T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x14a\x0E\xE8Ws\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16`\0\x90\x81R`\x02` \x90\x81R`@\x80\x83 3\x84R\x90\x91R\x90 Ta\x0E\xB6\x90\x83c\xFF\xFF\xFF\xFFa\"n\x16V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16`\0\x90\x81R`\x02` \x90\x81R`@\x80\x83 3\x84R\x90\x91R\x90 U[a\x0E\xF3\x84\x84\x84a&\x0BV[P`\x01\x93\x92PPPV[\x7Fnq\xED\xAE\x12\xB1\xB9\x7FM\x1F`7\x0F\xEF\x10\x10_\xA2\xFA\xAE\x01&\x11J\x16\x9Cd\x84]a&\xC9\x81V[`\x12\x81V[`\x03T\x81V[`\x05Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163\x14a\x0F\xB2W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7FUniswapV2: FORBIDDEN\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\x06\x80Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x93\x84\x16\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\x82\x16\x17\x90\x91U`\x07\x80T\x92\x90\x93\x16\x91\x16\x17\x90UV[`\tT\x81V[`\nT\x81V[`\0`\x0CT`\x01\x14a\x10\x84W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7FUniswapV2: LOCKED\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0`\x0C\x81\x90U\x80a\x10\x94a\r\x90V[P`\x06T`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q\x93\x95P\x91\x93P`\0\x92s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x91cp\xA0\x821\x91`$\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x11\x0EW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x11\"W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x118W`\0\x80\xFD[PQ`\x07T`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q\x92\x93P`\0\x92s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x11\xB1W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x11\xC5W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x11\xDBW`\0\x80\xFD[PQ\x90P`\0a\x12\x01\x83m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x16c\xFF\xFF\xFF\xFFa\"n\x16V[\x90P`\0a\x12%\x83m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x16c\xFF\xFF\xFF\xFFa\"n\x16V[\x90P`\0a\x123\x87\x87a&\xECV[`\0T\x90\x91P\x80a\x12pWa\x12\\a\x03\xE8a\x0B\xFDa\x12W\x87\x87c\xFF\xFF\xFF\xFFa!\xE8\x16V[a(xV[\x98Pa\x12k`\0a\x03\xE8a(\xCAV[a\x12\xCDV[a\x12\xCAm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x89\x16a\x12\x94\x86\x84c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x81a\x12\x9BW\xFE[\x04m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x89\x16a\x12\xBD\x86\x85c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x81a\x12\xC4W\xFE[\x04a)zV[\x98P[`\0\x89\x11a\x13&W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`(\x81R` \x01\x80a+\xC1`(\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x130\x8A\x8Aa(\xCAV[a\x13<\x86\x86\x8A\x8Aa\"\xE0V[\x81\x15a\x13~W`\x08Ta\x13z\x90m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16\x91n\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04\x16c\xFF\xFF\xFF\xFFa!\xE8\x16V[`\x0BU[`@\x80Q\x85\x81R` \x81\x01\x85\x90R\x81Q3\x92\x7FL \x9B_\xC8\xADPu\x8F\x13\xE2\xE1\x08\x8B\xA5jV\r\xFFi\n\x1Co\xEF&9OL\x03\x82\x1CO\x92\x82\x90\x03\x01\x90\xA2PP`\x01`\x0CUP\x94\x96\x95PPPPPPV[`\x01` R`\0\x90\x81R`@\x90 T\x81V[`\x0BT\x81V[`\x04` R`\0\x90\x81R`@\x90 T\x81V[`\0\x80`\x0CT`\x01\x14a\x14iW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7FUniswapV2: LOCKED\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0`\x0C\x81\x90U\x80a\x14ya\r\x90V[P`\x06T`\x07T`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q\x94\x96P\x92\x94Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16\x93\x91\x16\x91`\0\x91\x84\x91cp\xA0\x821\x91`$\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x14\xFBW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x15\x0FW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x15%W`\0\x80\xFD[PQ`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q\x91\x92P`\0\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x91cp\xA0\x821\x91`$\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x15\x99W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x15\xADW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x15\xC3W`\0\x80\xFD[PQ0`\0\x90\x81R`\x01` R`@\x81 T\x91\x92Pa\x15\xE2\x88\x88a&\xECV[`\0T\x90\x91P\x80a\x15\xF9\x84\x87c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x81a\x16\0W\xFE[\x04\x9AP\x80a\x16\x14\x84\x86c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x81a\x16\x1BW\xFE[\x04\x99P`\0\x8B\x11\x80\x15a\x16.WP`\0\x8A\x11[a\x16\x83W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`(\x81R` \x01\x80a+\x99`(\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x16\x8D0\x84a)\x92V[a\x16\x98\x87\x8D\x8Da\x1F\xDBV[a\x16\xA3\x86\x8D\x8Ca\x1F\xDBV[`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x89\x16\x91cp\xA0\x821\x91`$\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x17\x0FW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x17#W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x179W`\0\x80\xFD[PQ`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q\x91\x96Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x88\x16\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x17\xABW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x17\xBFW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x17\xD5W`\0\x80\xFD[PQ\x93Pa\x17\xE5\x85\x85\x8B\x8Ba\"\xE0V[\x81\x15a\x18'W`\x08Ta\x18#\x90m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16\x91n\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04\x16c\xFF\xFF\xFF\xFFa!\xE8\x16V[`\x0BU[`@\x80Q\x8C\x81R` \x81\x01\x8C\x90R\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8F\x16\x923\x92\x7F\xDC\xCDA/\x0B\x12R\x81\x9C\xB1\xFD3\x0B\x93\"L\xA4&\x12\x89+\xB3\xF4\xF7\x89\x97nm\x81\x93d\x96\x92\x90\x81\x90\x03\x90\x91\x01\x90\xA3PPPPPPPPP`\x01`\x0C\x81\x90UP\x91P\x91V[`@Q\x80`@\x01`@R\x80`\x06\x81R` \x01\x7FUNI-V2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP\x81V[`\0a\r\xF23\x84\x84a&\x0BV[a\x03\xE8\x81V[`\x0CT`\x01\x14a\x19OW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7FUniswapV2: LOCKED\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0`\x0CU`\x06T`\x07T`\x08T`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x94\x85\x16\x94\x90\x93\x16\x92a\x1A+\x92\x85\x92\x87\x92a\x1A&\x92m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91\x85\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x19\xEEW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1A\x02W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x1A\x18W`\0\x80\xFD[PQ\x90c\xFF\xFF\xFF\xFFa\"n\x16V[a\x1F\xDBV[`\x08T`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qa\x1A\xCA\x92\x84\x92\x87\x92a\x1A&\x92n\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x86\x16\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x19\xEEW`\0\x80\xFD[PP`\x01`\x0CUPV[`\x05Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`\x07Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[B\x84\x10\x15a\x1B{W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x12`$\x82\x01R\x7FUniswapV2: EXPIRED\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\x03Ts\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x89\x16`\0\x81\x81R`\x04` \x90\x81R`@\x80\x83 \x80T`\x01\x80\x82\x01\x90\x92U\x82Q\x7Fnq\xED\xAE\x12\xB1\xB9\x7FM\x1F`7\x0F\xEF\x10\x10_\xA2\xFA\xAE\x01&\x11J\x16\x9Cd\x84]a&\xC9\x81\x86\x01R\x80\x84\x01\x96\x90\x96R\x95\x8D\x16``\x86\x01R`\x80\x85\x01\x8C\x90R`\xA0\x85\x01\x95\x90\x95R`\xC0\x80\x85\x01\x8B\x90R\x81Q\x80\x86\x03\x90\x91\x01\x81R`\xE0\x85\x01\x82R\x80Q\x90\x83\x01 \x7F\x19\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a\x01\0\x86\x01Ra\x01\x02\x85\x01\x96\x90\x96Ra\x01\"\x80\x85\x01\x96\x90\x96R\x80Q\x80\x85\x03\x90\x96\x01\x86Ra\x01B\x84\x01\x80\x82R\x86Q\x96\x83\x01\x96\x90\x96 \x95\x83\x90Ra\x01b\x84\x01\x80\x82R\x86\x90R`\xFF\x89\x16a\x01\x82\x85\x01Ra\x01\xA2\x84\x01\x88\x90Ra\x01\xC2\x84\x01\x87\x90RQ\x91\x93\x92a\x01\xE2\x80\x82\x01\x93\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x81\x01\x92\x81\x90\x03\x90\x91\x01\x90\x85Z\xFA\x15\x80\x15a\x1C\xDCW=`\0\x80>=`\0\xFD[PP`@Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x01Q\x91PPs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x16\x15\x80\x15\x90a\x1DWWP\x88s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14[a\x1D\xC2W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FUniswapV2: INVALID_SIGNATURE\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a\x1D\xCD\x89\x89\x89a%\x9CV[PPPPPPPPPV[`\x02` \x90\x81R`\0\x92\x83R`@\x80\x84 \x90\x91R\x90\x82R\x90 T\x81V[`\x0CT`\x01\x14a\x1EfW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x11`$\x82\x01R\x7FUniswapV2: LOCKED\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0`\x0CU`\x06T`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qa\x1F\xD4\x92s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x91cp\xA0\x821\x91`$\x80\x83\x01\x92` \x92\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x1E\xDDW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1E\xF1W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x1F\x07W`\0\x80\xFD[PQ`\x07T`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x1FzW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1F\x8EW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x1F\xA4W`\0\x80\xFD[PQ`\x08Tm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x16\x91n\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04\x16a\"\xE0V[`\x01`\x0CUV[`@\x80Q\x80\x82\x01\x82R`\x19\x81R\x7Ftransfer(address,uint256)\0\0\0\0\0\0\0` \x91\x82\x01R\x81Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`$\x83\x01R`D\x80\x83\x01\x86\x90R\x84Q\x80\x84\x03\x90\x91\x01\x81R`d\x90\x92\x01\x84R\x91\x81\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x81R\x92Q\x81Q`\0\x94``\x94\x89\x16\x93\x92\x91\x82\x91\x90\x80\x83\x83[` \x83\x10a \xE1W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a \xA4V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14a!CW`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a!HV[``\x91P[P\x91P\x91P\x81\x80\x15a!vWP\x80Q\x15\x80a!vWP\x80\x80` \x01\x90Q` \x81\x10\x15a!sW`\0\x80\xFD[PQ[a!\xE1W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1A`$\x82\x01R\x7FUniswapV2: TRANSFER_FAILED\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[PPPPPV[`\0\x81\x15\x80a\"\x03WPP\x80\x82\x02\x82\x82\x82\x81a\"\0W\xFE[\x04\x14[a\r\xF6W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7Fds-math-mul-overflow\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x80\x82\x03\x82\x81\x11\x15a\r\xF6W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7Fds-math-sub-underflow\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x11\x80\x15\x90a#\x0CWPm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x11\x15[a#wW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x13`$\x82\x01R\x7FUniswapV2: OVERFLOW\0\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\x08Tc\xFF\xFF\xFF\xFFB\x81\x16\x91|\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04\x81\x16\x82\x03\x90\x81\x16\x15\x80\x15\x90a#\xC7WPm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x15\x15[\x80\x15a#\xE2WPm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x15\x15[\x15a$\x92W\x80c\xFF\xFF\xFF\xFF\x16a$%\x85a#\xFB\x86a*WV[{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90c\xFF\xFF\xFF\xFFa*{\x16V[`\t\x80T{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x92\x90\x92\x02\x01\x90Uc\xFF\xFF\xFF\xFF\x81\x16a$e\x84a#\xFB\x87a*WV[`\n\x80T{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x92\x90\x92\x16\x92\x90\x92\x02\x01\x90U[`\x08\x80T\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x88\x81\x16\x91\x90\x91\x17\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16n\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\x83\x16\x81\x02\x91\x90\x91\x17{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16|\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0c\xFF\xFF\xFF\xFF\x87\x16\x02\x17\x92\x83\x90U`@\x80Q\x84\x84\x16\x81R\x91\x90\x93\x04\x90\x91\x16` \x82\x01R\x81Q\x7F\x1CA\x1E\x9A\x96\xE0q$\x1C/!\xF7rk\x17\xAE\x89\xE3\xCA\xB4\xC7\x8B\xE5\x0E\x06+\x03\xA9\xFF\xFB\xBA\xD1\x92\x91\x81\x90\x03\x90\x91\x01\x90\xA1PPPPPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16`\0\x81\x81R`\x02` \x90\x81R`@\x80\x83 \x94\x87\x16\x80\x84R\x94\x82R\x91\x82\x90 \x85\x90U\x81Q\x85\x81R\x91Q\x7F\x8C[\xE1\xE5\xEB\xEC}[\xD1OqB}\x1E\x84\xF3\xDD\x03\x14\xC0\xF7\xB2)\x1E[ \n\xC8\xC7\xC3\xB9%\x92\x81\x90\x03\x90\x91\x01\x90\xA3PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16`\0\x90\x81R`\x01` R`@\x90 Ta&A\x90\x82c\xFF\xFF\xFF\xFFa\"n\x16V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x85\x16`\0\x90\x81R`\x01` R`@\x80\x82 \x93\x90\x93U\x90\x84\x16\x81R Ta&\x83\x90\x82c\xFF\xFF\xFF\xFFa*\xBC\x16V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x84\x16`\0\x81\x81R`\x01` \x90\x81R`@\x91\x82\x90 \x94\x90\x94U\x80Q\x85\x81R\x90Q\x91\x93\x92\x87\x16\x92\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x92\x91\x82\x90\x03\x01\x90\xA3PPPV[`\0\x80`\x05`\0\x90T\x90a\x01\0\n\x90\x04s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x01~~X`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a'WW`\0\x80\xFD[PZ\xFA\x15\x80\x15a'kW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a'\x81W`\0\x80\xFD[PQ`\x0BTs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x15\x80\x15\x94P\x91\x92P\x90a(dW\x80\x15a(_W`\0a'\xD8a\x12Wm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x88\x81\x16\x90\x88\x16c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x90P`\0a'\xE5\x83a(xV[\x90P\x80\x82\x11\x15a(\\W`\0a(\x13a(\x04\x84\x84c\xFF\xFF\xFF\xFFa\"n\x16V[`\0T\x90c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x90P`\0a(8\x83a(,\x86`\x05c\xFF\xFF\xFF\xFFa!\xE8\x16V[\x90c\xFF\xFF\xFF\xFFa*\xBC\x16V[\x90P`\0\x81\x83\x81a(EW\xFE[\x04\x90P\x80\x15a(XWa(X\x87\x82a(\xCAV[PPP[PP[a(pV[\x80\x15a(pW`\0`\x0BU[PP\x92\x91PPV[`\0`\x03\x82\x11\x15a(\xBBWP\x80`\x01`\x02\x82\x04\x01[\x81\x81\x10\x15a(\xB5W\x80\x91P`\x02\x81\x82\x85\x81a(\xA4W\xFE[\x04\x01\x81a(\xADW\xFE[\x04\x90Pa(\x8DV[Pa(\xC5V[\x81\x15a(\xC5WP`\x01[\x91\x90PV[`\0Ta(\xDD\x90\x82c\xFF\xFF\xFF\xFFa*\xBC\x16V[`\0\x90\x81Us\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16\x81R`\x01` R`@\x90 Ta)\x15\x90\x82c\xFF\xFF\xFF\xFFa*\xBC\x16V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 \x94\x90\x94U\x83Q\x85\x81R\x93Q\x92\x93\x91\x92\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x92\x81\x90\x03\x90\x91\x01\x90\xA3PPV[`\0\x81\x83\x10a)\x89W\x81a)\x8BV[\x82[\x93\x92PPPV[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16`\0\x90\x81R`\x01` R`@\x90 Ta)\xC8\x90\x82c\xFF\xFF\xFF\xFFa\"n\x16V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16`\0\x90\x81R`\x01` R`@\x81 \x91\x90\x91UTa*\x02\x90\x82c\xFF\xFF\xFF\xFFa\"n\x16V[`\0\x90\x81U`@\x80Q\x83\x81R\x90Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x16\x91\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x91\x90\x81\x90\x03` \x01\x90\xA3PPV[m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16n\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x90V[`\0m\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x81a*\xB4W\xFE[\x04\x93\x92PPPV[\x80\x82\x01\x82\x81\x10\x15a\r\xF6W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7Fds-math-add-overflow\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD\xFEUniswapV2: INSUFFICIENT_OUTPUT_AMOUNTUniswapV2: INSUFFICIENT_INPUT_AMOUNTUniswapV2: INSUFFICIENT_LIQUIDITYUniswapV2: INSUFFICIENT_LIQUIDITY_BURNEDUniswapV2: INSUFFICIENT_LIQUIDITY_MINTED\xA2ebzzr1X }\xCA\x18G\x9EXHv\x06\xBFp\xC7\x9ED\xD8\xDE\xE6#S\xC9\xEEm\x01\xF9\xA9\xD7\x08\x85\xB8v_\"dsolcC\0\x05\x10\x002EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\xA2ebzzr1X '`\xF9-\x7F\xA1\xDBoZ\xA1c\x07\xBA\xD6]\xF4\xEB\xCC\x85P\xC4\xB1\xF07U\xAB\x8D\xFD\x83\x0C\x17\x8FdsolcC\0\x05\x10\x002", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `PairCreated(address,address,address,uint256)` and selector `0x0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9`. + ```solidity + event PairCreated(address indexed token0, address indexed token1, address pair, uint256); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct PairCreated { + #[allow(missing_docs)] + pub token0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub token1: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub pair: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _3: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for PairCreated { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "PairCreated(address,address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 13u8, 54u8, 72u8, 189u8, 15u8, 107u8, 168u8, 1u8, 52u8, 163u8, 59u8, 169u8, + 39u8, 90u8, 197u8, 133u8, 217u8, 211u8, 21u8, 240u8, 173u8, 131u8, 85u8, 205u8, + 222u8, 253u8, 227u8, 26u8, 250u8, 40u8, 208u8, 233u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + token0: topics.1, + token1: topics.2, + pair: data.0, + _3: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.pair, + ), + as alloy_sol_types::SolType>::tokenize( + &self._3, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.token0.clone(), + self.token1.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.token0, + ); + out[2usize] = ::encode_topic( + &self.token1, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for PairCreated { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&PairCreated> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &PairCreated) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(address _feeToSetter); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _feeToSetter: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._feeToSetter,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _feeToSetter: tuple.0, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._feeToSetter, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `createPair(address,address)` and selector `0xc9c65396`. + ```solidity + function createPair(address tokenA, address tokenB) external returns (address pair); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createPairCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`createPair(address,address)`](createPairCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct createPairReturn { + #[allow(missing_docs)] + pub pair: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createPairCall) -> Self { + (value.tokenA, value.tokenB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createPairCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: createPairReturn) -> Self { + (value.pair,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for createPairReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { pair: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for createPairCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [201u8, 198u8, 83u8, 150u8]; + const SIGNATURE: &'static str = "createPair(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: createPairReturn = r.into(); + r.pair + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: createPairReturn = r.into(); + r.pair + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getPair(address,address)` and selector `0xe6a43905`. + ```solidity + function getPair(address, address) external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPairCall { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`getPair(address,address)`](getPairCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getPairReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPairCall) -> Self { + (value._0, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPairCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: getPairReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for getPairReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getPairCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [230u8, 164u8, 57u8, 5u8]; + const SIGNATURE: &'static str = "getPair(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._0, + ), + ::tokenize( + &self._1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: getPairReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: getPairReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`UniswapV2Factory`](self) function calls. + #[derive(Clone)] + pub enum UniswapV2FactoryCalls { + #[allow(missing_docs)] + createPair(createPairCall), + #[allow(missing_docs)] + getPair(getPairCall), + } + impl UniswapV2FactoryCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = + &[[201u8, 198u8, 83u8, 150u8], [230u8, 164u8, 57u8, 5u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = + &[::core::stringify!(createPair), ::core::stringify!(getPair)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for UniswapV2FactoryCalls { + const COUNT: usize = 2usize; + const MIN_DATA_LENGTH: usize = 64usize; + const NAME: &'static str = "UniswapV2FactoryCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::createPair(_) => ::SELECTOR, + Self::getPair(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn createPair(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV2FactoryCalls::createPair) + } + createPair + }, + { + fn getPair(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV2FactoryCalls::getPair) + } + getPair + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + UniswapV2FactoryCalls, + >] = &[ + { + fn createPair(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV2FactoryCalls::createPair) + } + createPair + }, + { + fn getPair(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV2FactoryCalls::getPair) + } + getPair + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::createPair(inner) => { + ::abi_encoded_size(inner) + } + Self::getPair(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::createPair(inner) => { + ::abi_encode_raw(inner, out) + } + Self::getPair(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`UniswapV2Factory`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum UniswapV2FactoryEvents { + #[allow(missing_docs)] + PairCreated(PairCreated), + } + impl UniswapV2FactoryEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[[ + 13u8, 54u8, 72u8, 189u8, 15u8, 107u8, 168u8, 1u8, 52u8, 163u8, 59u8, 169u8, 39u8, 90u8, + 197u8, 133u8, 217u8, 211u8, 21u8, 240u8, 173u8, 131u8, 85u8, 205u8, 222u8, 253u8, + 227u8, 26u8, 250u8, 40u8, 208u8, 233u8, + ]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(PairCreated)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for UniswapV2FactoryEvents { + const COUNT: usize = 1usize; + const NAME: &'static str = "UniswapV2FactoryEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::PairCreated) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for UniswapV2FactoryEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::PairCreated(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::PairCreated(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`UniswapV2Factory`](self) contract instance. + + See the [wrapper's documentation](`UniswapV2FactoryInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> UniswapV2FactoryInstance { + UniswapV2FactoryInstance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _feeToSetter: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + UniswapV2FactoryInstance::::deploy(__provider, _feeToSetter) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _feeToSetter: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + UniswapV2FactoryInstance::::deploy_builder(__provider, _feeToSetter) + } + /**A [`UniswapV2Factory`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`UniswapV2Factory`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct UniswapV2FactoryInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for UniswapV2FactoryInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("UniswapV2FactoryInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + UniswapV2FactoryInstance + { + /**Creates a new wrapper around an on-chain [`UniswapV2Factory`](self) contract instance. + + See the [wrapper's documentation](`UniswapV2FactoryInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _feeToSetter: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, _feeToSetter); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _feeToSetter: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { _feeToSetter }) + [..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl UniswapV2FactoryInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> UniswapV2FactoryInstance { + UniswapV2FactoryInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + UniswapV2FactoryInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`createPair`] function. + pub fn createPair( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, createPairCall, N> { + self.call_builder(&createPairCall { tokenA, tokenB }) + } + + ///Creates a new call builder for the [`getPair`] function. + pub fn getPair( + &self, + _0: alloy_sol_types::private::Address, + _1: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, getPairCall, N> { + self.call_builder(&getPairCall { _0, _1 }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + UniswapV2FactoryInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`PairCreated`] event. + pub fn PairCreated_filter(&self) -> alloy_contract::Event<&P, PairCreated, N> { + self.event_filter::() + } + } +} +pub type Instance = UniswapV2Factory::UniswapV2FactoryInstance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xA818b4F111Ccac7AA31D0BCc0806d64F2E0737D7"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xF62c03E08ada871A0bEb309762E260a7a6a880E6"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/uniswapv2router02/Cargo.toml b/contracts/generated/contracts-generated/uniswapv2router02/Cargo.toml new file mode 100644 index 0000000000..22cfbf004c --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv2router02/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-uniswapv2router02" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/uniswapv2router02/src/lib.rs b/contracts/generated/contracts-generated/uniswapv2router02/src/lib.rs new file mode 100644 index 0000000000..bd336c469f --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv2router02/src/lib.rs @@ -0,0 +1,1800 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface UniswapV2Router02 { + constructor(address _factory, address _WETH); + + receive() external payable; + + function WETH() external view returns (address); + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + function factory() external view returns (address); + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_factory", + "type": "address", + "internalType": "address" + }, + { + "name": "_WETH", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "WETH", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "tokenA", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenB", + "type": "address", + "internalType": "address" + }, + { + "name": "amountADesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBDesired", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountAMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountBMin", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidity", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "quote", + "inputs": [ + { + "name": "amountA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveA", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveB", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountB", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "swapTokensForExactTokens", + "inputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMax", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "path", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amounts", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod UniswapV2Router02 { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60c06040523480156200001157600080fd5b506040516200573e3803806200573e833981810160405260408110156200003757600080fd5b5080516020909101516001600160601b0319606092831b8116608052911b1660a05260805160601c60a05160601c6155b762000187600039806101ac5280610e5d5280610e985280610fd5528061129852806116f252806118d65280611e1e5280611fa252806120725280612179528061232c52806123c15280612673528061271a52806127ef52806128f452806129dc5280612a5d52806130ec5280613422528061347852806134ac528061352d528061374752806138f7528061398c5250806110c752806111c5528061136b52806113a4528061154f52806117e452806118b45280611aa1528061225f528061240052806125a95280612a9c5280612ddf5280613071528061309a52806130ca52806132a75280613456528061382d52806139cb528061444a528061448d52806147ed52806149ce5280614f49528061502a52806150aa52506155b76000f3fe60806040526004361061018f5760003560e01c80638803dbee116100d6578063c45a01551161007f578063e8e3370011610059578063e8e3370014610c71578063f305d71914610cfe578063fb3bdb4114610d51576101d5565b8063c45a015514610b25578063d06ca61f14610b3a578063ded9382a14610bf1576101d5565b8063af2979eb116100b0578063af2979eb146109c8578063b6f9de9514610a28578063baa2abde14610abb576101d5565b80638803dbee146108af578063ad5c464814610954578063ad615dec14610992576101d5565b80634a25d94a11610138578063791ac94711610112578063791ac947146107415780637ff36ab5146107e657806385f8c25914610879576101d5565b80634a25d94a146105775780635b0d59841461061c5780635c11d7951461069c576101d5565b80631f00ca74116101695780631f00ca74146103905780632195995c1461044757806338ed1739146104d2576101d5565b806302751cec146101da578063054d50d41461025357806318cbafe51461029b576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061023a600480360360c08110156101fd57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a00135610de4565b6040805192835260208301919091528051918290030190f35b34801561025f57600080fd5b506102896004803603606081101561027657600080fd5b5080359060208101359060400135610f37565b60408051918252519081900360200190f35b3480156102a757600080fd5b50610340600480360360a08110156102be57600080fd5b8135916020810135918101906060810160408201356401000000008111156102e557600080fd5b8201836020820111156102f757600080fd5b8035906020019184602083028401116401000000008311171561031957600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f4c565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561037c578181015183820152602001610364565b505050509050019250505060405180910390f35b34801561039c57600080fd5b50610340600480360360408110156103b357600080fd5b813591908101906040810160208201356401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611364945050505050565b34801561045357600080fd5b5061023a600480360361016081101561046b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff610100820135169061012081013590610140013561139a565b3480156104de57600080fd5b50610340600480360360a08110156104f557600080fd5b81359160208101359181019060608101604082013564010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184602083028401116401000000008311171561055057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356114d8565b34801561058357600080fd5b50610340600480360360a081101561059a57600080fd5b8135916020810135918101906060810160408201356401000000008111156105c157600080fd5b8201836020820111156105d357600080fd5b803590602001918460208302840111640100000000831117156105f557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611669565b34801561062857600080fd5b50610289600480360361014081101561064057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356118ac565b3480156106a857600080fd5b506101d3600480360360a08110156106bf57600080fd5b8135916020810135918101906060810160408201356401000000008111156106e657600080fd5b8201836020820111156106f857600080fd5b8035906020019184602083028401116401000000008311171561071a57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356119fe565b34801561074d57600080fd5b506101d3600480360360a081101561076457600080fd5b81359160208101359181019060608101604082013564010000000081111561078b57600080fd5b82018360208201111561079d57600080fd5b803590602001918460208302840111640100000000831117156107bf57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d97565b610340600480360360808110156107fc57600080fd5b8135919081019060408101602082013564010000000081111561081e57600080fd5b82018360208201111561083057600080fd5b8035906020019184602083028401116401000000008311171561085257600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612105565b34801561088557600080fd5b506102896004803603606081101561089c57600080fd5b5080359060208101359060400135612525565b3480156108bb57600080fd5b50610340600480360360a08110156108d257600080fd5b8135916020810135918101906060810160408201356401000000008111156108f957600080fd5b82018360208201111561090b57600080fd5b8035906020019184602083028401116401000000008311171561092d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612532565b34801561096057600080fd5b50610969612671565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561099e57600080fd5b50610289600480360360608110156109b557600080fd5b5080359060208101359060400135612695565b3480156109d457600080fd5b50610289600480360360c08110156109eb57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356126a2565b6101d360048036036080811015610a3e57600080fd5b81359190810190604081016020820135640100000000811115610a6057600080fd5b820183602082011115610a7257600080fd5b80359060200191846020830284011164010000000083111715610a9457600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612882565b348015610ac757600080fd5b5061023a600480360360e0811015610ade57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135612d65565b348015610b3157600080fd5b5061096961306f565b348015610b4657600080fd5b5061034060048036036040811015610b5d57600080fd5b81359190810190604081016020820135640100000000811115610b7f57600080fd5b820183602082011115610b9157600080fd5b80359060200191846020830284011164010000000083111715610bb357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613093945050505050565b348015610bfd57600080fd5b5061023a6004803603610140811015610c1557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356130c0565b348015610c7d57600080fd5b50610ce06004803603610100811015610c9557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135613218565b60408051938452602084019290925282820152519081900360600190f35b610ce0600480360360c0811015610d1457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356133a7565b61034060048036036080811015610d6757600080fd5b81359190810190604081016020820135640100000000811115610d8957600080fd5b820183602082011115610d9b57600080fd5b80359060200191846020830284011164010000000083111715610dbd57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356136d3565b6000808242811015610e5757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b610e86897f00000000000000000000000000000000000000000000000000000000000000008a8a8a308a612d65565b9093509150610e96898685613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050610f2b8583613cff565b50965096945050505050565b6000610f44848484613e3c565b949350505050565b60608142811015610fbe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061102357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146110c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6111207f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b9150868260018451038151811061113357fe5b60200260200101511015611192576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b611257868660008181106111a257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff163361123d7f00000000000000000000000000000000000000000000000000000000000000008a8a60008181106111f157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b8b600181811061121b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166140c6565b8560008151811061124a57fe5b60200260200101516141b1565b61129682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614381915050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836001855103815181106112e257fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b50505050611359848360018551038151811061134c57fe5b6020026020010151613cff565b509695505050505050565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484614608565b90505b92915050565b60008060006113ca7f00000000000000000000000000000000000000000000000000000000000000008f8f6140c6565b90506000876113d9578c6113fb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506114be8f8f8f8f8f8f8f612d65565b809450819550505050509b509b9950505050505050505050565b6060814281101561154a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6115a87f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106115bb57fe5b6020026020010151101561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b61162a868660008181106111a257fe5b61135982878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b606081428110156116db57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061174057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146117df57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b61183d7f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061184d57fe5b60200260200101511115611192576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b6000806118fa7f00000000000000000000000000000000000000000000000000000000000000008d7f00000000000000000000000000000000000000000000000000000000000000006140c6565b9050600086611909578b61192b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506119ed8d8d8d8d8d8d6126a2565b9d9c50505050505050505050505050565b8042811015611a6e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b611afd85856000818110611a7e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1633611af77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168a8a600181811061121b57fe5b8a6141b1565b600085857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611b2d57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611bc657600080fd5b505afa158015611bda573d6000803e3d6000fd5b505050506040513d6020811015611bf057600080fd5b50516040805160208881028281018201909352888252929350611c32929091899189918291850190849080828437600092019190915250889250614796915050565b86611d368288887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611c6557fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b50519063ffffffff614b2916565b1015611d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b5050505050505050565b8042811015611e0757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611e6c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b611f1b85856000818110611a7e57fe5b611f59858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614796915050565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b5051905086811015612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b50505050611d8d8482613cff565b6060814281101561217757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16868660008181106121bb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461225a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6122b87f000000000000000000000000000000000000000000000000000000000000000034888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106122cb57fe5b6020026020010151101561232a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061237357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61242c7f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b8460008151811061243957fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505050506040513d60208110156124d457600080fd5b50516124dc57fe5b61251b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b5095945050505050565b6000610f44848484614b9b565b606081428110156125a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6126027f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061261257fe5b6020026020010151111561161a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610f44848484614cbf565b6000814281101561271457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b612743887f00000000000000000000000000000000000000000000000000000000000000008989893089612d65565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519194506127ed92508a91879173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b1580156127bc57600080fd5b505afa1580156127d0573d6000803e3d6000fd5b505050506040513d60208110156127e657600080fd5b5051613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561286057600080fd5b505af1158015612874573d6000803e3d6000fd5b505050506113598483613cff565b80428110156128f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168585600081811061293657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146129d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b60003490507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4257600080fd5b505af1158015612a56573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb612ac87f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b3257600080fd5b505af1158015612b46573d6000803e3d6000fd5b505050506040513d6020811015612b5c57600080fd5b5051612b6457fe5b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612b9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c2d57600080fd5b505afa158015612c41573d6000803e3d6000fd5b505050506040513d6020811015612c5757600080fd5b50516040805160208981028281018201909352898252929350612c999290918a918a918291850190849080828437600092019190915250899250614796915050565b87611d368289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612ccc57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b6000808242811015612dd857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6000612e057f00000000000000000000000000000000000000000000000000000000000000008c8c6140c6565b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b158015612e8657600080fd5b505af1158015612e9a573d6000803e3d6000fd5b505050506040513d6020811015612eb057600080fd5b5050604080517f89afcb4400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b158015612f2357600080fd5b505af1158015612f37573d6000803e3d6000fd5b505050506040513d6040811015612f4d57600080fd5b50805160209091015190925090506000612f678e8e614d9f565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614612fa4578183612fa7565b82825b90975095508a871015613005576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b8986101561305e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b505050505097509795505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484613f60565b60008060006131107f00000000000000000000000000000000000000000000000000000000000000008e7f00000000000000000000000000000000000000000000000000000000000000006140c6565b905060008761311f578c613141565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156131dd57600080fd5b505af11580156131f1573d6000803e3d6000fd5b505050506132038e8e8e8e8e8e610de4565b909f909e509c50505050505050505050505050565b6000806000834281101561328d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61329b8c8c8c8c8c8c614ef2565b909450925060006132cd7f00000000000000000000000000000000000000000000000000000000000000008e8e6140c6565b90506132db8d3383886141b1565b6132e78c3383876141b1565b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561336657600080fd5b505af115801561337a573d6000803e3d6000fd5b505050506040513d602081101561339057600080fd5b5051949d939c50939a509198505050505050505050565b6000806000834281101561341c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61344a8a7f00000000000000000000000000000000000000000000000000000000000000008b348c8c614ef2565b9094509250600061349c7f00000000000000000000000000000000000000000000000000000000000000008c7f00000000000000000000000000000000000000000000000000000000000000006140c6565b90506134aa8b3383886141b1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561351257600080fd5b505af1158015613526573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb82866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b505050506040513d60208110156135fc57600080fd5b505161360457fe5b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561368357600080fd5b505af1158015613697573d6000803e3d6000fd5b505050506040513d60208110156136ad57600080fd5b50519250348410156136c5576136c533853403613cff565b505096509650969350505050565b6060814281101561374557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168686600081811061378957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461382857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6138867f00000000000000000000000000000000000000000000000000000000000000008888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150348260008151811061389657fe5b602002602001015111156138f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061393e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397157600080fd5b505af1158015613985573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6139f77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b84600081518110613a0457fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015613a7557600080fd5b505af1158015613a89573d6000803e3d6000fd5b505050506040513d6020811015613a9f57600080fd5b5051613aa757fe5b613ae682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b81600081518110613af357fe5b602002602001015134111561251b5761251b3383600081518110613b1357fe5b60200260200101513403613cff565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613bf857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613bbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c5a576040519150601f19603f3d011682016040523d82523d6000602084013e613c5f565b606091505b5091509150818015613c8d575080511580613c8d5750808060200190516020811015613c8a57600080fd5b50515b613cf857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b5050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310613d7657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613d39565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613dd8576040519150601f19603f3d011682016040523d82523d6000602084013e613ddd565b606091505b5050905080613e37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806154e56023913960400191505060405180910390fd5b505050565b6000808411613e96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615557602b913960400191505060405180910390fd5b600083118015613ea65750600082115b613efb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000613f0f856103e563ffffffff6151f316565b90506000613f23828563ffffffff6151f316565b90506000613f4983613f3d886103e863ffffffff6151f316565b9063ffffffff61527916565b9050808281613f5457fe5b04979650505050505050565b6060600282511015613fd357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff81118015613feb57600080fd5b50604051908082528060200260200182016040528015614015578160200160208202803683370190505b509050828160008151811061402657fe5b60200260200101818152505060005b60018351038110156140be576000806140788786858151811061405457fe5b602002602001015187866001018151811061406b57fe5b60200260200101516152eb565b9150915061409a84848151811061408b57fe5b60200260200101518383613e3c565b8484600101815181106140a957fe5b60209081029190910101525050600101614035565b509392505050565b60008060006140d58585614d9f565b604080517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017815292518251600094606094938a169392918291908083835b6020831061428f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614252565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146142f1576040519150601f19603f3d011682016040523d82523d6000602084013e6142f6565b606091505b5091509150818015614324575080511580614324575080806020019051602081101561432157600080fd5b50515b614379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806155336024913960400191505060405180910390fd5b505050505050565b60005b60018351038110156146025760008084838151811061439f57fe5b60200260200101518584600101815181106143b657fe5b60200260200101519150915060006143ce8383614d9f565b50905060008785600101815181106143e257fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461442a5782600061442e565b6000835b91509150600060028a510388106144455788614486565b6144867f0000000000000000000000000000000000000000000000000000000000000000878c8b6002018151811061447957fe5b60200260200101516140c6565b90506144b37f000000000000000000000000000000000000000000000000000000000000000088886140c6565b73ffffffffffffffffffffffffffffffffffffffff1663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156144fd576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614588578181015183820152602001614570565b50505050905090810190601f1680156145b55780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156145d757600080fd5b505af11580156145eb573d6000803e3d6000fd5b505060019099019850614384975050505050505050565b50505050565b606060028251101561467b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561469357600080fd5b506040519080825280602002602001820160405280156146bd578160200160208202803683370190505b50905082816001835103815181106146d157fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b80156140be576000806147318786600186038151811061471d57fe5b602002602001015187868151811061406b57fe5b9150915061475384848151811061474457fe5b60200260200101518383614b9b565b84600185038151811061476257fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614701565b60005b6001835103811015613e37576000808483815181106147b457fe5b60200260200101518584600101815181106147cb57fe5b60200260200101519150915060006147e38383614d9f565b50905060006148137f000000000000000000000000000000000000000000000000000000000000000085856140c6565b90506000806000808473ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561486157600080fd5b505afa158015614875573d6000803e3d6000fd5b505050506040513d606081101561488b57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905060008073ffffffffffffffffffffffffffffffffffffffff8a8116908916146148d55782846148d8565b83835b9150915061495d828b73ffffffffffffffffffffffffffffffffffffffff166370a082318a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b955061496a868383613e3c565b9450505050506000808573ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146149ae578260006149b2565b6000835b91509150600060028c51038a106149c9578a6149fd565b6149fd7f0000000000000000000000000000000000000000000000000000000000000000898e8d6002018151811061447957fe5b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614aad578181015183820152602001614a95565b50505050905090810190601f168015614ada5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614afc57600080fd5b505af1158015614b10573d6000803e3d6000fd5b50506001909b019a506147999950505050505050505050565b8082038281111561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6000808411614bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806153d4602c913960400191505060405180910390fd5b600083118015614c055750600082115b614c5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000614c7e6103e8614c72868863ffffffff6151f316565b9063ffffffff6151f316565b90506000614c986103e5614c72868963ffffffff614b2916565b9050614cb56001828481614ca857fe5b049063ffffffff61527916565b9695505050505050565b6000808411614d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154736025913960400191505060405180910390fd5b600083118015614d295750600082115b614d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b82614d8f858463ffffffff6151f316565b81614d9657fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415614e27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154006025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610614e61578284614e64565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216614eeb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529151600092839283927f00000000000000000000000000000000000000000000000000000000000000009092169163e6a4390591604480820192602092909190829003018186803b158015614f9257600080fd5b505afa158015614fa6573d6000803e3d6000fd5b505050506040513d6020811015614fbc57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614156150a257604080517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152898116602483015291517f00000000000000000000000000000000000000000000000000000000000000009092169163c9c65396916044808201926020929091908290030181600087803b15801561507557600080fd5b505af1158015615089573d6000803e3d6000fd5b505050506040513d602081101561509f57600080fd5b50505b6000806150d07f00000000000000000000000000000000000000000000000000000000000000008b8b6152eb565b915091508160001480156150e2575080155b156150f2578793508692506151e6565b60006150ff898484614cbf565b905087811161516c5785811015615161576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b8894509250826151e4565b6000615179898486614cbf565b90508981111561518557fe5b878110156151de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061520e5750508082028282828161520b57fe5b04145b61139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b8082018281101561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008060006152fa8585614d9f565b50905060008061530b8888886140c6565b73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561535057600080fd5b505afa158015615364573d6000803e3d6000fd5b505050506040513d606081101561537a57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905073ffffffffffffffffffffffffffffffffffffffff878116908416146153c15780826153c4565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a26469706673582212206dd6e03c4b2c0a8e55214926227ae9e2d6f9fec2ce74a6446d615afa355c84f364736f6c63430006060033 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\xC0`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`@Qb\0W>8\x03\x80b\0W>\x839\x81\x81\x01`@R`@\x81\x10\x15b\0\x007W`\0\x80\xFD[P\x80Q` \x90\x91\x01Q`\x01`\x01``\x1B\x03\x19``\x92\x83\x1B\x81\x16`\x80R\x91\x1B\x16`\xA0R`\x80Q``\x1C`\xA0Q``\x1CaU\xB7b\0\x01\x87`\09\x80a\x01\xACR\x80a\x0E]R\x80a\x0E\x98R\x80a\x0F\xD5R\x80a\x12\x98R\x80a\x16\xF2R\x80a\x18\xD6R\x80a\x1E\x1ER\x80a\x1F\xA2R\x80a rR\x80a!yR\x80a#,R\x80a#\xC1R\x80a&sR\x80a'\x1AR\x80a'\xEFR\x80a(\xF4R\x80a)\xDCR\x80a*]R\x80a0\xECR\x80a4\"R\x80a4xR\x80a4\xACR\x80a5-R\x80a7GR\x80a8\xF7R\x80a9\x8CRP\x80a\x10\xC7R\x80a\x11\xC5R\x80a\x13kR\x80a\x13\xA4R\x80a\x15OR\x80a\x17\xE4R\x80a\x18\xB4R\x80a\x1A\xA1R\x80a\"_R\x80a$\0R\x80a%\xA9R\x80a*\x9CR\x80a-\xDFR\x80a0qR\x80a0\x9AR\x80a0\xCAR\x80a2\xA7R\x80a4VR\x80a8-R\x80a9\xCBR\x80aDJR\x80aD\x8DR\x80aG\xEDR\x80aI\xCER\x80aOIR\x80aP*R\x80aP\xAARPaU\xB7`\0\xF3\xFE`\x80`@R`\x046\x10a\x01\x8FW`\x005`\xE0\x1C\x80c\x88\x03\xDB\xEE\x11a\0\xD6W\x80c\xC4Z\x01U\x11a\0\x7FW\x80c\xE8\xE37\0\x11a\0YW\x80c\xE8\xE37\0\x14a\x0CqW\x80c\xF3\x05\xD7\x19\x14a\x0C\xFEW\x80c\xFB;\xDBA\x14a\rQWa\x01\xD5V[\x80c\xC4Z\x01U\x14a\x0B%W\x80c\xD0l\xA6\x1F\x14a\x0B:W\x80c\xDE\xD98*\x14a\x0B\xF1Wa\x01\xD5V[\x80c\xAF)y\xEB\x11a\0\xB0W\x80c\xAF)y\xEB\x14a\t\xC8W\x80c\xB6\xF9\xDE\x95\x14a\n(W\x80c\xBA\xA2\xAB\xDE\x14a\n\xBBWa\x01\xD5V[\x80c\x88\x03\xDB\xEE\x14a\x08\xAFW\x80c\xAD\\FH\x14a\tTW\x80c\xADa]\xEC\x14a\t\x92Wa\x01\xD5V[\x80cJ%\xD9J\x11a\x018W\x80cy\x1A\xC9G\x11a\x01\x12W\x80cy\x1A\xC9G\x14a\x07AW\x80c\x7F\xF3j\xB5\x14a\x07\xE6W\x80c\x85\xF8\xC2Y\x14a\x08yWa\x01\xD5V[\x80cJ%\xD9J\x14a\x05wW\x80c[\rY\x84\x14a\x06\x1CW\x80c\\\x11\xD7\x95\x14a\x06\x9CWa\x01\xD5V[\x80c\x1F\0\xCAt\x11a\x01iW\x80c\x1F\0\xCAt\x14a\x03\x90W\x80c!\x95\x99\\\x14a\x04GW\x80c8\xED\x179\x14a\x04\xD2Wa\x01\xD5V[\x80c\x02u\x1C\xEC\x14a\x01\xDAW\x80c\x05MP\xD4\x14a\x02SW\x80c\x18\xCB\xAF\xE5\x14a\x02\x9BWa\x01\xD5V[6a\x01\xD5W3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x14a\x01\xD3W\xFE[\0[`\0\x80\xFD[4\x80\x15a\x01\xE6W`\0\x80\xFD[Pa\x02:`\x04\x806\x03`\xC0\x81\x10\x15a\x01\xFDW`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x16\x90`\xA0\x015a\r\xE4V[`@\x80Q\x92\x83R` \x83\x01\x91\x90\x91R\x80Q\x91\x82\x90\x03\x01\x90\xF3[4\x80\x15a\x02_W`\0\x80\xFD[Pa\x02\x89`\x04\x806\x03``\x81\x10\x15a\x02vW`\0\x80\xFD[P\x805\x90` \x81\x015\x90`@\x015a\x0F7V[`@\x80Q\x91\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[4\x80\x15a\x02\xA7W`\0\x80\xFD[Pa\x03@`\x04\x806\x03`\xA0\x81\x10\x15a\x02\xBEW`\0\x80\xFD[\x815\x91` \x81\x015\x91\x81\x01\x90``\x81\x01`@\x82\x015d\x01\0\0\0\0\x81\x11\x15a\x02\xE5W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x02\xF7W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x03\x19W`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a\x0FLV[`@\x80Q` \x80\x82R\x83Q\x81\x83\x01R\x83Q\x91\x92\x83\x92\x90\x83\x01\x91\x85\x81\x01\x91\x02\x80\x83\x83`\0[\x83\x81\x10\x15a\x03|W\x81\x81\x01Q\x83\x82\x01R` \x01a\x03dV[PPPP\x90P\x01\x92PPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x03\x9CW`\0\x80\xFD[Pa\x03@`\x04\x806\x03`@\x81\x10\x15a\x03\xB3W`\0\x80\xFD[\x815\x91\x90\x81\x01\x90`@\x81\x01` \x82\x015d\x01\0\0\0\0\x81\x11\x15a\x03\xD5W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x03\xE7W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x04\tW`\0\x80\xFD[\x91\x90\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x92\x95Pa\x13d\x94PPPPPV[4\x80\x15a\x04SW`\0\x80\xFD[Pa\x02:`\x04\x806\x03a\x01`\x81\x10\x15a\x04kW`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x82\x16\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x91`\xA0\x81\x015\x90\x91\x16\x90`\xC0\x81\x015\x90`\xE0\x81\x015\x15\x15\x90`\xFFa\x01\0\x82\x015\x16\x90a\x01 \x81\x015\x90a\x01@\x015a\x13\x9AV[4\x80\x15a\x04\xDEW`\0\x80\xFD[Pa\x03@`\x04\x806\x03`\xA0\x81\x10\x15a\x04\xF5W`\0\x80\xFD[\x815\x91` \x81\x015\x91\x81\x01\x90``\x81\x01`@\x82\x015d\x01\0\0\0\0\x81\x11\x15a\x05\x1CW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x05.W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x05PW`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a\x14\xD8V[4\x80\x15a\x05\x83W`\0\x80\xFD[Pa\x03@`\x04\x806\x03`\xA0\x81\x10\x15a\x05\x9AW`\0\x80\xFD[\x815\x91` \x81\x015\x91\x81\x01\x90``\x81\x01`@\x82\x015d\x01\0\0\0\0\x81\x11\x15a\x05\xC1W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x05\xD3W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x05\xF5W`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a\x16iV[4\x80\x15a\x06(W`\0\x80\xFD[Pa\x02\x89`\x04\x806\x03a\x01@\x81\x10\x15a\x06@W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x16\x90`\xA0\x81\x015\x90`\xC0\x81\x015\x15\x15\x90`\xFF`\xE0\x82\x015\x16\x90a\x01\0\x81\x015\x90a\x01 \x015a\x18\xACV[4\x80\x15a\x06\xA8W`\0\x80\xFD[Pa\x01\xD3`\x04\x806\x03`\xA0\x81\x10\x15a\x06\xBFW`\0\x80\xFD[\x815\x91` \x81\x015\x91\x81\x01\x90``\x81\x01`@\x82\x015d\x01\0\0\0\0\x81\x11\x15a\x06\xE6W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x06\xF8W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x07\x1AW`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a\x19\xFEV[4\x80\x15a\x07MW`\0\x80\xFD[Pa\x01\xD3`\x04\x806\x03`\xA0\x81\x10\x15a\x07dW`\0\x80\xFD[\x815\x91` \x81\x015\x91\x81\x01\x90``\x81\x01`@\x82\x015d\x01\0\0\0\0\x81\x11\x15a\x07\x8BW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x07\x9DW`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x07\xBFW`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a\x1D\x97V[a\x03@`\x04\x806\x03`\x80\x81\x10\x15a\x07\xFCW`\0\x80\xFD[\x815\x91\x90\x81\x01\x90`@\x81\x01` \x82\x015d\x01\0\0\0\0\x81\x11\x15a\x08\x1EW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x080W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x08RW`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a!\x05V[4\x80\x15a\x08\x85W`\0\x80\xFD[Pa\x02\x89`\x04\x806\x03``\x81\x10\x15a\x08\x9CW`\0\x80\xFD[P\x805\x90` \x81\x015\x90`@\x015a%%V[4\x80\x15a\x08\xBBW`\0\x80\xFD[Pa\x03@`\x04\x806\x03`\xA0\x81\x10\x15a\x08\xD2W`\0\x80\xFD[\x815\x91` \x81\x015\x91\x81\x01\x90``\x81\x01`@\x82\x015d\x01\0\0\0\0\x81\x11\x15a\x08\xF9W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\t\x0BW`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\t-W`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a%2V[4\x80\x15a\t`W`\0\x80\xFD[Pa\tia&qV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x92\x16\x82RQ\x90\x81\x90\x03` \x01\x90\xF3[4\x80\x15a\t\x9EW`\0\x80\xFD[Pa\x02\x89`\x04\x806\x03``\x81\x10\x15a\t\xB5W`\0\x80\xFD[P\x805\x90` \x81\x015\x90`@\x015a&\x95V[4\x80\x15a\t\xD4W`\0\x80\xFD[Pa\x02\x89`\x04\x806\x03`\xC0\x81\x10\x15a\t\xEBW`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x16\x90`\xA0\x015a&\xA2V[a\x01\xD3`\x04\x806\x03`\x80\x81\x10\x15a\n>W`\0\x80\xFD[\x815\x91\x90\x81\x01\x90`@\x81\x01` \x82\x015d\x01\0\0\0\0\x81\x11\x15a\n`W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\nrW`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\n\x94W`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a(\x82V[4\x80\x15a\n\xC7W`\0\x80\xFD[Pa\x02:`\x04\x806\x03`\xE0\x81\x10\x15a\n\xDEW`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x82\x16\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x91`\xA0\x81\x015\x90\x91\x16\x90`\xC0\x015a-eV[4\x80\x15a\x0B1W`\0\x80\xFD[Pa\tia0oV[4\x80\x15a\x0BFW`\0\x80\xFD[Pa\x03@`\x04\x806\x03`@\x81\x10\x15a\x0B]W`\0\x80\xFD[\x815\x91\x90\x81\x01\x90`@\x81\x01` \x82\x015d\x01\0\0\0\0\x81\x11\x15a\x0B\x7FW`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\x0B\x91W`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\x0B\xB3W`\0\x80\xFD[\x91\x90\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x92\x95Pa0\x93\x94PPPPPV[4\x80\x15a\x0B\xFDW`\0\x80\xFD[Pa\x02:`\x04\x806\x03a\x01@\x81\x10\x15a\x0C\x15W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x16\x90`\xA0\x81\x015\x90`\xC0\x81\x015\x15\x15\x90`\xFF`\xE0\x82\x015\x16\x90a\x01\0\x81\x015\x90a\x01 \x015a0\xC0V[4\x80\x15a\x0C}W`\0\x80\xFD[Pa\x0C\xE0`\x04\x806\x03a\x01\0\x81\x10\x15a\x0C\x95W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x82\x16\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x91`\xA0\x81\x015\x91`\xC0\x82\x015\x16\x90`\xE0\x015a2\x18V[`@\x80Q\x93\x84R` \x84\x01\x92\x90\x92R\x82\x82\x01RQ\x90\x81\x90\x03``\x01\x90\xF3[a\x0C\xE0`\x04\x806\x03`\xC0\x81\x10\x15a\r\x14W`\0\x80\xFD[Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x81\x16\x91` \x81\x015\x91`@\x82\x015\x91``\x81\x015\x91`\x80\x82\x015\x16\x90`\xA0\x015a3\xA7V[a\x03@`\x04\x806\x03`\x80\x81\x10\x15a\rgW`\0\x80\xFD[\x815\x91\x90\x81\x01\x90`@\x81\x01` \x82\x015d\x01\0\0\0\0\x81\x11\x15a\r\x89W`\0\x80\xFD[\x82\x01\x83` \x82\x01\x11\x15a\r\x9BW`\0\x80\xFD[\x805\x90` \x01\x91\x84` \x83\x02\x84\x01\x11d\x01\0\0\0\0\x83\x11\x17\x15a\r\xBDW`\0\x80\xFD[\x91\x93P\x91Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x815\x16\x90` \x015a6\xD3V[`\0\x80\x82B\x81\x10\x15a\x0EWW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a\x0E\x86\x89\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8A\x8A\x8A0\x8Aa-eV[\x90\x93P\x91Pa\x0E\x96\x89\x86\x85a;\"V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c.\x1A}M\x83`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82\x81R` \x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a\x0F\tW`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x0F\x1DW=`\0\x80>=`\0\xFD[PPPPa\x0F+\x85\x83a<\xFFV[P\x96P\x96\x94PPPPPV[`\0a\x0FD\x84\x84\x84a>=`\0\xFD[PPPPa\x13Y\x84\x83`\x01\x85Q\x03\x81Q\x81\x10a\x13LW\xFE[` \x02` \x01\x01Qa<\xFFV[P\x96\x95PPPPPPV[``a\x13\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x84aF\x08V[\x90P[\x92\x91PPV[`\0\x80`\0a\x13\xCA\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8F\x8Fa@\xC6V[\x90P`\0\x87a\x13\xD9W\x8Ca\x13\xFBV[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF[`@\x80Q\x7F\xD5\x05\xAC\xCF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R0`$\x82\x01R`D\x81\x01\x83\x90R`d\x81\x01\x8C\x90R`\xFF\x8A\x16`\x84\x82\x01R`\xA4\x81\x01\x89\x90R`\xC4\x81\x01\x88\x90R\x90Q\x91\x92Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x91c\xD5\x05\xAC\xCF\x91`\xE4\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a\x14\x97W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x14\xABW=`\0\x80>=`\0\xFD[PPPPa\x14\xBE\x8F\x8F\x8F\x8F\x8F\x8F\x8Fa-eV[\x80\x94P\x81\x95PPPPP\x9BP\x9B\x99PPPPPPPPPPV[``\x81B\x81\x10\x15a\x15JW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a\x15\xA8\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x88\x88\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RPa?`\x92PPPV[\x91P\x86\x82`\x01\x84Q\x03\x81Q\x81\x10a\x15\xBBW\xFE[` \x02` \x01\x01Q\x10\x15a\x16\x1AW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`+\x81R` \x01\x80aU\x08`+\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[a\x16*\x86\x86`\0\x81\x81\x10a\x11\xA2W\xFE[a\x13Y\x82\x87\x87\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x89\x92PaC\x81\x91PPV[``\x81B\x81\x10\x15a\x16\xDBW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x86\x86\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x01\x81\x81\x10a\x17@W\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x17\xDFW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FUniswapV2Router: INVALID_PATH\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a\x18=\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x88\x88\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RPaF\x08\x92PPPV[\x91P\x86\x82`\0\x81Q\x81\x10a\x18MW\xFE[` \x02` \x01\x01Q\x11\x15a\x11\x92W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`'\x81R` \x01\x80aT\x98`'\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x80a\x18\xFA\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8D\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a@\xC6V[\x90P`\0\x86a\x19\tW\x8Ba\x19+V[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF[`@\x80Q\x7F\xD5\x05\xAC\xCF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R0`$\x82\x01R`D\x81\x01\x83\x90R`d\x81\x01\x8B\x90R`\xFF\x89\x16`\x84\x82\x01R`\xA4\x81\x01\x88\x90R`\xC4\x81\x01\x87\x90R\x90Q\x91\x92Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x91c\xD5\x05\xAC\xCF\x91`\xE4\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a\x19\xC7W`\0\x80\xFD[PZ\xF1\x15\x80\x15a\x19\xDBW=`\0\x80>=`\0\xFD[PPPPa\x19\xED\x8D\x8D\x8D\x8D\x8D\x8Da&\xA2V[\x9D\x9CPPPPPPPPPPPPPV[\x80B\x81\x10\x15a\x1AnW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a\x1A\xFD\x85\x85`\0\x81\x81\x10a\x1A~W\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x163a\x1A\xF7\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x89`\0\x81\x81\x10a\x1A\xCDW\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x8A\x8A`\x01\x81\x81\x10a\x12\x1BW\xFE[\x8AaA\xB1V[`\0\x85\x85\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x01\x81\x81\x10a\x1B-W\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cp\xA0\x821\x85`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1B\xC6W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1B\xDAW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x1B\xF0W`\0\x80\xFD[PQ`@\x80Q` \x88\x81\x02\x82\x81\x01\x82\x01\x90\x93R\x88\x82R\x92\x93Pa\x1C2\x92\x90\x91\x89\x91\x89\x91\x82\x91\x85\x01\x90\x84\x90\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x88\x92PaG\x96\x91PPV[\x86a\x1D6\x82\x88\x88\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x01\x81\x81\x10a\x1CeW\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cp\xA0\x821\x88`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1C\xFEW`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1D\x12W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a\x1D(W`\0\x80\xFD[PQ\x90c\xFF\xFF\xFF\xFFaK)\x16V[\x10\x15a\x1D\x8DW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`+\x81R` \x01\x80aU\x08`+\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[PPPPPPPPV[\x80B\x81\x10\x15a\x1E\x07W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x85\x85\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x01\x81\x81\x10a\x1ElW\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\x1F\x0BW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FUniswapV2Router: INVALID_PATH\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a\x1F\x1B\x85\x85`\0\x81\x81\x10a\x1A~W\xFE[a\x1FY\x85\x85\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RP0\x92PaG\x96\x91PPV[`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q`\0\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a\x1F\xE9W`\0\x80\xFD[PZ\xFA\x15\x80\x15a\x1F\xFDW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a \x13W`\0\x80\xFD[PQ\x90P\x86\x81\x10\x15a pW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`+\x81R` \x01\x80aU\x08`+\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c.\x1A}M\x82`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82\x81R` \x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a \xE3W`\0\x80\xFD[PZ\xF1\x15\x80\x15a \xF7W=`\0\x80>=`\0\xFD[PPPPa\x1D\x8D\x84\x82a<\xFFV[``\x81B\x81\x10\x15a!wW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x86\x86`\0\x81\x81\x10a!\xBBW\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a\"ZW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FUniswapV2Router: INVALID_PATH\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a\"\xB8\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x004\x88\x88\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RPa?`\x92PPPV[\x91P\x86\x82`\x01\x84Q\x03\x81Q\x81\x10a\"\xCBW\xFE[` \x02` \x01\x01Q\x10\x15a#*W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`+\x81R` \x01\x80aU\x08`+\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD0\xE3\r\xB0\x83`\0\x81Q\x81\x10a#sW\xFE[` \x02` \x01\x01Q`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01`\0`@Q\x80\x83\x03\x81\x85\x88\x80;\x15\x80\x15a#\xA6W`\0\x80\xFD[PZ\xF1\x15\x80\x15a#\xBAW=`\0\x80>=`\0\xFD[PPPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xA9\x05\x9C\xBBa$,\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x89`\0\x81\x81\x10a\x1A\xCDW\xFE[\x84`\0\x81Q\x81\x10a$9W\xFE[` \x02` \x01\x01Q`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81R` \x01\x92PPP` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a$\xAAW`\0\x80\xFD[PZ\xF1\x15\x80\x15a$\xBEW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a$\xD4W`\0\x80\xFD[PQa$\xDCW\xFE[a%\x1B\x82\x87\x87\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x89\x92PaC\x81\x91PPV[P\x95\x94PPPPPV[`\0a\x0FD\x84\x84\x84aK\x9BV[``\x81B\x81\x10\x15a%\xA4W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a&\x02\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x88\x88\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RPaF\x08\x92PPPV[\x91P\x86\x82`\0\x81Q\x81\x10a&\x12W\xFE[` \x02` \x01\x01Q\x11\x15a\x16\x1AW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`'\x81R` \x01\x80aT\x98`'\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[`\0a\x0FD\x84\x84\x84aL\xBFV[`\0\x81B\x81\x10\x15a'\x14W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a'C\x88\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x89\x890\x89a-eV[`@\x80Q\x7Fp\xA0\x821\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R0`\x04\x82\x01R\x90Q\x91\x94Pa'\xED\x92P\x8A\x91\x87\x91s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x91cp\xA0\x821\x91`$\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15a'\xBCW`\0\x80\xFD[PZ\xFA\x15\x80\x15a'\xD0W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a'\xE6W`\0\x80\xFD[PQa;\"V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c.\x1A}M\x83`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82\x81R` \x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a(`W`\0\x80\xFD[PZ\xF1\x15\x80\x15a(tW=`\0\x80>=`\0\xFD[PPPPa\x13Y\x84\x83a<\xFFV[\x80B\x81\x10\x15a(\xF2W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x85\x85`\0\x81\x81\x10a)6W\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a)\xD5W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FUniswapV2Router: INVALID_PATH\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\x004\x90P\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD0\xE3\r\xB0\x82`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01`\0`@Q\x80\x83\x03\x81\x85\x88\x80;\x15\x80\x15a*BW`\0\x80\xFD[PZ\xF1\x15\x80\x15a*VW=`\0\x80>=`\0\xFD[PPPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xA9\x05\x9C\xBBa*\xC8\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x89`\0\x81\x81\x10a\x1A\xCDW\xFE[\x83`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81R` \x01\x92PPP` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a+2W`\0\x80\xFD[PZ\xF1\x15\x80\x15a+FW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a+\\W`\0\x80\xFD[PQa+dW\xFE[`\0\x86\x86\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x01\x81\x81\x10a+\x94W\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cp\xA0\x821\x86`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a,-W`\0\x80\xFD[PZ\xFA\x15\x80\x15a,AW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a,WW`\0\x80\xFD[PQ`@\x80Q` \x89\x81\x02\x82\x81\x01\x82\x01\x90\x93R\x89\x82R\x92\x93Pa,\x99\x92\x90\x91\x8A\x91\x8A\x91\x82\x91\x85\x01\x90\x84\x90\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x89\x92PaG\x96\x91PPV[\x87a\x1D6\x82\x89\x89\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x01\x81\x81\x10a,\xCCW\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cp\xA0\x821\x89`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1C\xFEW`\0\x80\xFD[`\0\x80\x82B\x81\x10\x15a-\xD8W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0a.\x05\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8C\x8Ca@\xC6V[`@\x80Q\x7F#\xB8r\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x83\x16`$\x82\x01\x81\x90R`D\x82\x01\x8D\x90R\x91Q\x92\x93P\x90\x91c#\xB8r\xDD\x91`d\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81`\0\x87\x80;\x15\x80\x15a.\x86W`\0\x80\xFD[PZ\xF1\x15\x80\x15a.\x9AW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a.\xB0W`\0\x80\xFD[PP`@\x80Q\x7F\x89\xAF\xCBD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x88\x81\x16`\x04\x83\x01R\x82Q`\0\x93\x84\x93\x92\x86\x16\x92c\x89\xAF\xCBD\x92`$\x80\x83\x01\x93\x92\x82\x90\x03\x01\x81\x87\x87\x80;\x15\x80\x15a/#W`\0\x80\xFD[PZ\xF1\x15\x80\x15a/7W=`\0\x80>=`\0\xFD[PPPP`@Q=`@\x81\x10\x15a/MW`\0\x80\xFD[P\x80Q` \x90\x91\x01Q\x90\x92P\x90P`\0a/g\x8E\x8EaM\x9FV[P\x90P\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x8Es\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a/\xA4W\x81\x83a/\xA7V[\x82\x82[\x90\x97P\x95P\x8A\x87\x10\x15a0\x05W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80aT\xBF`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x89\x86\x10\x15a0^W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80aT%`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[PPPPP\x97P\x97\x95PPPPPPV[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81V[``a\x13\x91\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x84a?`V[`\0\x80`\0a1\x10\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8E\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a@\xC6V[\x90P`\0\x87a1\x1FW\x8Ca1AV[\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF[`@\x80Q\x7F\xD5\x05\xAC\xCF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R3`\x04\x82\x01R0`$\x82\x01R`D\x81\x01\x83\x90R`d\x81\x01\x8C\x90R`\xFF\x8A\x16`\x84\x82\x01R`\xA4\x81\x01\x89\x90R`\xC4\x81\x01\x88\x90R\x90Q\x91\x92Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x91c\xD5\x05\xAC\xCF\x91`\xE4\x80\x82\x01\x92`\0\x92\x90\x91\x90\x82\x90\x03\x01\x81\x83\x87\x80;\x15\x80\x15a1\xDDW`\0\x80\xFD[PZ\xF1\x15\x80\x15a1\xF1W=`\0\x80>=`\0\xFD[PPPPa2\x03\x8E\x8E\x8E\x8E\x8E\x8Ea\r\xE4V[\x90\x9F\x90\x9EP\x9CPPPPPPPPPPPPPV[`\0\x80`\0\x83B\x81\x10\x15a2\x8DW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a2\x9B\x8C\x8C\x8C\x8C\x8C\x8CaN\xF2V[\x90\x94P\x92P`\0a2\xCD\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8E\x8Ea@\xC6V[\x90Pa2\xDB\x8D3\x83\x88aA\xB1V[a2\xE7\x8C3\x83\x87aA\xB1V[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cjbxB\x88`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a3fW`\0\x80\xFD[PZ\xF1\x15\x80\x15a3zW=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a3\x90W`\0\x80\xFD[PQ\x94\x9D\x93\x9CP\x93\x9AP\x91\x98PPPPPPPPPV[`\0\x80`\0\x83B\x81\x10\x15a4\x1CW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a4J\x8A\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8B4\x8C\x8CaN\xF2V[\x90\x94P\x92P`\0a4\x9C\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8C\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0a@\xC6V[\x90Pa4\xAA\x8B3\x83\x88aA\xB1V[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD0\xE3\r\xB0\x85`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01`\0`@Q\x80\x83\x03\x81\x85\x88\x80;\x15\x80\x15a5\x12W`\0\x80\xFD[PZ\xF1\x15\x80\x15a5&W=`\0\x80>=`\0\xFD[PPPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xA9\x05\x9C\xBB\x82\x86`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81R` \x01\x92PPP` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a5\xD2W`\0\x80\xFD[PZ\xF1\x15\x80\x15a5\xE6W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a5\xFCW`\0\x80\xFD[PQa6\x04W\xFE[\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cjbxB\x88`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a6\x83W`\0\x80\xFD[PZ\xF1\x15\x80\x15a6\x97W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a6\xADW`\0\x80\xFD[PQ\x92P4\x84\x10\x15a6\xC5Wa6\xC53\x854\x03a<\xFFV[PP\x96P\x96P\x96\x93PPPPV[``\x81B\x81\x10\x15a7EW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x18`$\x82\x01R\x7FUniswapV2Router: EXPIRED\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x86\x86`\0\x81\x81\x10a7\x89W\xFE[\x90P` \x02\x015s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14a8(W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FUniswapV2Router: INVALID_PATH\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[a8\x86\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\x88\x88\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RPaF\x08\x92PPPV[\x91P4\x82`\0\x81Q\x81\x10a8\x96W\xFE[` \x02` \x01\x01Q\x11\x15a8\xF5W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`'\x81R` \x01\x80aT\x98`'\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xD0\xE3\r\xB0\x83`\0\x81Q\x81\x10a9>W\xFE[` \x02` \x01\x01Q`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01`\0`@Q\x80\x83\x03\x81\x85\x88\x80;\x15\x80\x15a9qW`\0\x80\xFD[PZ\xF1\x15\x80\x15a9\x85W=`\0\x80>=`\0\xFD[PPPPP\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\xA9\x05\x9C\xBBa9\xF7\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x89`\0\x81\x81\x10a\x1A\xCDW\xFE[\x84`\0\x81Q\x81\x10a:\x04W\xFE[` \x02` \x01\x01Q`@Q\x83c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x82\x81R` \x01\x92PPP` `@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15a:uW`\0\x80\xFD[PZ\xF1\x15\x80\x15a:\x89W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15a:\x9FW`\0\x80\xFD[PQa:\xA7W\xFE[a:\xE6\x82\x87\x87\x80\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x93\x92\x91\x90\x81\x81R` \x01\x83\x83` \x02\x80\x82\x847`\0\x92\x01\x91\x90\x91RP\x89\x92PaC\x81\x91PPV[\x81`\0\x81Q\x81\x10a:\xF3W\xFE[` \x02` \x01\x01Q4\x11\x15a%\x1BWa%\x1B3\x83`\0\x81Q\x81\x10a;\x13W\xFE[` \x02` \x01\x01Q4\x03a<\xFFV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x81\x16`$\x83\x01R`D\x80\x83\x01\x85\x90R\x83Q\x80\x84\x03\x90\x91\x01\x81R`d\x90\x92\x01\x83R` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xA9\x05\x9C\xBB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x81R\x92Q\x82Q`\0\x94``\x94\x93\x89\x16\x93\x92\x91\x82\x91\x90\x80\x83\x83[` \x83\x10a;\xF8W\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a;\xBBV[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14aa<_V[``\x91P[P\x91P\x91P\x81\x80\x15a<\x8DWP\x80Q\x15\x80a<\x8DWP\x80\x80` \x01\x90Q` \x81\x10\x15a<\x8AW`\0\x80\xFD[PQ[a<\xF8W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1F`$\x82\x01R\x7FTransferHelper: TRANSFER_FAILED\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[PPPPPV[`@\x80Q`\0\x80\x82R` \x82\x01\x90\x92Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x84\x16\x90\x83\x90`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a=vW\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a=9V[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81\x85\x87Z\xF1\x92PPP=\x80`\0\x81\x14a=\xD8W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>a=\xDDV[``\x91P[PP\x90P\x80a>7W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`#\x81R` \x01\x80aT\xE5`#\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[PPPV[`\0\x80\x84\x11a>\x96W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`+\x81R` \x01\x80aUW`+\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x83\x11\x80\x15a>\xA6WP`\0\x82\x11[a>\xFBW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`(\x81R` \x01\x80aTK`(\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0a?\x0F\x85a\x03\xE5c\xFF\xFF\xFF\xFFaQ\xF3\x16V[\x90P`\0a?#\x82\x85c\xFF\xFF\xFF\xFFaQ\xF3\x16V[\x90P`\0a?I\x83a?=\x88a\x03\xE8c\xFF\xFF\xFF\xFFaQ\xF3\x16V[\x90c\xFF\xFF\xFF\xFFaRy\x16V[\x90P\x80\x82\x81a?TW\xFE[\x04\x97\x96PPPPPPPV[```\x02\x82Q\x10\x15a?\xD3W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FUniswapV2Library: INVALID_PATH\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15a?\xEBW`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a@\x15W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P\x82\x81`\0\x81Q\x81\x10a@&W\xFE[` \x02` \x01\x01\x81\x81RPP`\0[`\x01\x83Q\x03\x81\x10\x15a@\xBEW`\0\x80a@x\x87\x86\x85\x81Q\x81\x10a@TW\xFE[` \x02` \x01\x01Q\x87\x86`\x01\x01\x81Q\x81\x10a@kW\xFE[` \x02` \x01\x01QaR\xEBV[\x91P\x91Pa@\x9A\x84\x84\x81Q\x81\x10a@\x8BW\xFE[` \x02` \x01\x01Q\x83\x83a>}\xA3H\x84_`\x9D\x80\x84\x01\x91\x90\x91R\x88Q\x80\x84\x03\x90\x91\x01\x81R`\xBD\x90\x92\x01\x90\x97R\x80Q\x96\x01\x95\x90\x95 \x95\x94PPPPPV[`@\x80Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x85\x81\x16`$\x83\x01R\x84\x81\x16`D\x83\x01R`d\x80\x83\x01\x85\x90R\x83Q\x80\x84\x03\x90\x91\x01\x81R`\x84\x90\x92\x01\x83R` \x82\x01\x80Q{\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F#\xB8r\xDD\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x17\x81R\x92Q\x82Q`\0\x94``\x94\x93\x8A\x16\x93\x92\x91\x82\x91\x90\x80\x83\x83[` \x83\x10aB\x8FW\x80Q\x82R\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE0\x90\x92\x01\x91` \x91\x82\x01\x91\x01aBRV[`\x01\x83` \x03a\x01\0\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x91PP`\0`@Q\x80\x83\x03\x81`\0\x86Z\xF1\x91PP=\x80`\0\x81\x14aB\xF1W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=`\0` \x84\x01>aB\xF6V[``\x91P[P\x91P\x91P\x81\x80\x15aC$WP\x80Q\x15\x80aC$WP\x80\x80` \x01\x90Q` \x81\x10\x15aC!W`\0\x80\xFD[PQ[aCyW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`$\x81R` \x01\x80aU3`$\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[PPPPPPV[`\0[`\x01\x83Q\x03\x81\x10\x15aF\x02W`\0\x80\x84\x83\x81Q\x81\x10aC\x9FW\xFE[` \x02` \x01\x01Q\x85\x84`\x01\x01\x81Q\x81\x10aC\xB6W\xFE[` \x02` \x01\x01Q\x91P\x91P`\0aC\xCE\x83\x83aM\x9FV[P\x90P`\0\x87\x85`\x01\x01\x81Q\x81\x10aC\xE2W\xFE[` \x02` \x01\x01Q\x90P`\0\x80\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x86s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14aD*W\x82`\0aD.V[`\0\x83[\x91P\x91P`\0`\x02\x8AQ\x03\x88\x10aDEW\x88aD\x86V[aD\x86\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87\x8C\x8B`\x02\x01\x81Q\x81\x10aDyW\xFE[` \x02` \x01\x01Qa@\xC6V[\x90PaD\xB3\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\x88a@\xC6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\x02,\r\x9F\x84\x84\x84`\0`@Q\x90\x80\x82R\x80`\x1F\x01`\x1F\x19\x16` \x01\x82\x01`@R\x80\x15aD\xFDW` \x82\x01\x81\x806\x837\x01\x90P[P`@Q\x85c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x85\x81R` \x01\x84\x81R` \x01\x83s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15aE\x88W\x81\x81\x01Q\x83\x82\x01R` \x01aEpV[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15aE\xB5W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x95PPPPPP`\0`@Q\x80\x83\x03\x81`\0\x87\x80;\x15\x80\x15aE\xD7W`\0\x80\xFD[PZ\xF1\x15\x80\x15aE\xEBW=`\0\x80>=`\0\xFD[PP`\x01\x90\x99\x01\x98PaC\x84\x97PPPPPPPPV[PPPPV[```\x02\x82Q\x10\x15aF{W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FUniswapV2Library: INVALID_PATH\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x81Qg\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x80\x15aF\x93W`\0\x80\xFD[P`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15aF\xBDW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P\x82\x81`\x01\x83Q\x03\x81Q\x81\x10aF\xD1W\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01R\x81Q\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01[\x80\x15a@\xBEW`\0\x80aG1\x87\x86`\x01\x86\x03\x81Q\x81\x10aG\x1DW\xFE[` \x02` \x01\x01Q\x87\x86\x81Q\x81\x10a@kW\xFE[\x91P\x91PaGS\x84\x84\x81Q\x81\x10aGDW\xFE[` \x02` \x01\x01Q\x83\x83aK\x9BV[\x84`\x01\x85\x03\x81Q\x81\x10aGbW\xFE[` \x90\x81\x02\x91\x90\x91\x01\x01RPP\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01aG\x01V[`\0[`\x01\x83Q\x03\x81\x10\x15a>7W`\0\x80\x84\x83\x81Q\x81\x10aG\xB4W\xFE[` \x02` \x01\x01Q\x85\x84`\x01\x01\x81Q\x81\x10aG\xCBW\xFE[` \x02` \x01\x01Q\x91P\x91P`\0aG\xE3\x83\x83aM\x9FV[P\x90P`\0aH\x13\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\x85a@\xC6V[\x90P`\0\x80`\0\x80\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\t\x02\xF1\xAC`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01```@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15aHaW`\0\x80\xFD[PZ\xFA\x15\x80\x15aHuW=`\0\x80>=`\0\xFD[PPPP`@Q=``\x81\x10\x15aH\x8BW`\0\x80\xFD[P\x80Q` \x90\x91\x01Qm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16\x93P\x16\x90P`\0\x80s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8A\x81\x16\x90\x89\x16\x14aH\xD5W\x82\x84aH\xD8V[\x83\x83[\x91P\x91PaI]\x82\x8Bs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16cp\xA0\x821\x8A`@Q\x82c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x91PP` `@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15a\x1C\xFEW`\0\x80\xFD[\x95PaIj\x86\x83\x83a>=`\0\xFD[PP`\x01\x90\x9B\x01\x9APaG\x99\x99PPPPPPPPPPV[\x80\x82\x03\x82\x81\x11\x15a\x13\x94W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x15`$\x82\x01R\x7Fds-math-sub-underflow\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0\x80\x84\x11aK\xF5W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`,\x81R` \x01\x80aS\xD4`,\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x83\x11\x80\x15aL\x05WP`\0\x82\x11[aLZW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`(\x81R` \x01\x80aTK`(\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0aL~a\x03\xE8aLr\x86\x88c\xFF\xFF\xFF\xFFaQ\xF3\x16V[\x90c\xFF\xFF\xFF\xFFaQ\xF3\x16V[\x90P`\0aL\x98a\x03\xE5aLr\x86\x89c\xFF\xFF\xFF\xFFaK)\x16V[\x90PaL\xB5`\x01\x82\x84\x81aL\xA8W\xFE[\x04\x90c\xFF\xFF\xFF\xFFaRy\x16V[\x96\x95PPPPPPV[`\0\x80\x84\x11aM\x19W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`%\x81R` \x01\x80aTs`%\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[`\0\x83\x11\x80\x15aM)WP`\0\x82\x11[aM~W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`(\x81R` \x01\x80aTK`(\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x82aM\x8F\x85\x84c\xFF\xFF\xFF\xFFaQ\xF3\x16V[\x81aM\x96W\xFE[\x04\x94\x93PPPPV[`\0\x80\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15aN'W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`%\x81R` \x01\x80aT\0`%\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x84s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x10aNaW\x82\x84aNdV[\x83\x83[\x90\x92P\x90Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16aN\xEBW`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x1E`$\x82\x01R\x7FUniswapV2Library: ZERO_ADDRESS\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x92P\x92\x90PV[`@\x80Q\x7F\xE6\xA49\x05\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x88\x81\x16`\x04\x83\x01R\x87\x81\x16`$\x83\x01R\x91Q`\0\x92\x83\x92\x83\x92\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x92\x16\x91c\xE6\xA49\x05\x91`D\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81\x86\x80;\x15\x80\x15aO\x92W`\0\x80\xFD[PZ\xFA\x15\x80\x15aO\xA6W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15aO\xBCW`\0\x80\xFD[PQs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x14\x15aP\xA2W`@\x80Q\x7F\xC9\xC6S\x96\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81Rs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x8A\x81\x16`\x04\x83\x01R\x89\x81\x16`$\x83\x01R\x91Q\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x92\x16\x91c\xC9\xC6S\x96\x91`D\x80\x82\x01\x92` \x92\x90\x91\x90\x82\x90\x03\x01\x81`\0\x87\x80;\x15\x80\x15aPuW`\0\x80\xFD[PZ\xF1\x15\x80\x15aP\x89W=`\0\x80>=`\0\xFD[PPPP`@Q=` \x81\x10\x15aP\x9FW`\0\x80\xFD[PP[`\0\x80aP\xD0\x7F\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8B\x8BaR\xEBV[\x91P\x91P\x81`\0\x14\x80\x15aP\xE2WP\x80\x15[\x15aP\xF2W\x87\x93P\x86\x92PaQ\xE6V[`\0aP\xFF\x89\x84\x84aL\xBFV[\x90P\x87\x81\x11aQlW\x85\x81\x10\x15aQaW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80aT%`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x88\x94P\x92P\x82aQ\xE4V[`\0aQy\x89\x84\x86aL\xBFV[\x90P\x89\x81\x11\x15aQ\x85W\xFE[\x87\x81\x10\x15aQ\xDEW`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80aT\xBF`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xFD[\x94P\x87\x93P[P[PP\x96P\x96\x94PPPPPV[`\0\x81\x15\x80aR\x0EWPP\x80\x82\x02\x82\x82\x82\x81aR\x0BW\xFE[\x04\x14[a\x13\x94W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7Fds-math-mul-overflow\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[\x80\x82\x01\x82\x81\x10\x15a\x13\x94W`@\x80Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R` `\x04\x82\x01R`\x14`$\x82\x01R\x7Fds-math-add-overflow\0\0\0\0\0\0\0\0\0\0\0\0`D\x82\x01R\x90Q\x90\x81\x90\x03`d\x01\x90\xFD[`\0\x80`\0aR\xFA\x85\x85aM\x9FV[P\x90P`\0\x80aS\x0B\x88\x88\x88a@\xC6V[s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16c\t\x02\xF1\xAC`@Q\x81c\xFF\xFF\xFF\xFF\x16`\xE0\x1B\x81R`\x04\x01```@Q\x80\x83\x03\x81\x86\x80;\x15\x80\x15aSPW`\0\x80\xFD[PZ\xFA\x15\x80\x15aSdW=`\0\x80>=`\0\xFD[PPPP`@Q=``\x81\x10\x15aSzW`\0\x80\xFD[P\x80Q` \x90\x91\x01Qm\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x91\x82\x16\x93P\x16\x90Ps\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x87\x81\x16\x90\x84\x16\x14aS\xC1W\x80\x82aS\xC4V[\x81\x81[\x90\x99\x90\x98P\x96PPPPPPPV\xFEUniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNTUniswapV2Library: IDENTICAL_ADDRESSESUniswapV2Router: INSUFFICIENT_B_AMOUNTUniswapV2Library: INSUFFICIENT_LIQUIDITYUniswapV2Library: INSUFFICIENT_AMOUNTUniswapV2Router: EXCESSIVE_INPUT_AMOUNTUniswapV2Router: INSUFFICIENT_A_AMOUNTTransferHelper: ETH_TRANSFER_FAILEDUniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNTTransferHelper: TRANSFER_FROM_FAILEDUniswapV2Library: INSUFFICIENT_INPUT_AMOUNT\xA2dipfsX\"\x12 m\xD6\xE0 = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._factory, value._WETH) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _factory: tuple.0, + _WETH: tuple.1, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._factory, + ), + ::tokenize( + &self._WETH, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH()` and selector `0xad5c4648`. + ```solidity + function WETH() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH()`](WETHCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETHReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETHReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETHReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETHCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + const SIGNATURE: &'static str = "WETH()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETHReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETHReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)` and selector `0xe8e33700`. + ```solidity + function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityCall { + #[allow(missing_docs)] + pub tokenA: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenB: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountADesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountAMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountBMin: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`addLiquidity(address,address,uint256,uint256,uint256,uint256,address, + /// uint256)`](addLiquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct addLiquidityReturn { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub liquidity: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityCall) -> Self { + ( + value.tokenA, + value.tokenB, + value.amountADesired, + value.amountBDesired, + value.amountAMin, + value.amountBMin, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenA: tuple.0, + tokenB: tuple.1, + amountADesired: tuple.2, + amountBDesired: tuple.3, + amountAMin: tuple.4, + amountBMin: tuple.5, + to: tuple.6, + deadline: tuple.7, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: addLiquidityReturn) -> Self { + (value.amountA, value.amountB, value.liquidity) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for addLiquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + amountB: tuple.1, + liquidity: tuple.2, + } + } + } + } + impl addLiquidityReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for addLiquidityCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = addLiquidityReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [232u8, 227u8, 55u8, 0u8]; + const SIGNATURE: &'static str = + "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.tokenA, + ), + ::tokenize( + &self.tokenB, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountADesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBDesired, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountAMin, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountBMin, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize( + &self.deadline, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + addLiquidityReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quote(uint256,uint256,uint256)` and selector `0xad615dec`. + ```solidity + function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteCall { + #[allow(missing_docs)] + pub amountA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveA: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub reserveB: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quote(uint256,uint256,uint256)`](quoteCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteReturn { + #[allow(missing_docs)] + pub amountB: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteCall) -> Self { + (value.amountA, value.reserveA, value.reserveB) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountA: tuple.0, + reserveA: tuple.1, + reserveB: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteReturn) -> Self { + (value.amountB,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountB: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [173u8, 97u8, 93u8, 236u8]; + const SIGNATURE: &'static str = "quote(uint256,uint256,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveA, + ), + as alloy_sol_types::SolType>::tokenize( + &self.reserveB, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: quoteReturn = r.into(); + r.amountB + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: quoteReturn = r.into(); + r.amountB + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swapTokensForExactTokens(uint256,uint256,address[],address,uint256)` and selector `0x8803dbee`. + ```solidity + function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] memory path, address to, uint256 deadline) external returns (uint256[] memory amounts); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensCall { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMax: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub to: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub deadline: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swapTokensForExactTokens(uint256,uint256,address[],address, + /// uint256)`](swapTokensForExactTokensCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapTokensForExactTokensReturn { + #[allow(missing_docs)] + pub amounts: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensCall) -> Self { + ( + value.amountOut, + value.amountInMax, + value.path, + value.to, + value.deadline, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + amountInMax: tuple.1, + path: tuple.2, + to: tuple.3, + deadline: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapTokensForExactTokensReturn) -> Self { + (value.amounts,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapTokensForExactTokensReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amounts: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapTokensForExactTokensCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = + alloy_sol_types::private::Vec; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 3u8, 219u8, 238u8]; + const SIGNATURE: &'static str = + "swapTokensForExactTokens(uint256,uint256,address[],address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + as alloy_sol_types::SolType>::tokenize(&self.amountInMax), + as alloy_sol_types::SolType>::tokenize(&self.path), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.deadline), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (, + > as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: swapTokensForExactTokensReturn = r.into(); + r.amounts + }) + } + } + }; + ///Container for all the [`UniswapV2Router02`](self) function calls. + #[derive(Clone)] + pub enum UniswapV2Router02Calls { + #[allow(missing_docs)] + WETH(WETHCall), + #[allow(missing_docs)] + addLiquidity(addLiquidityCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quote(quoteCall), + #[allow(missing_docs)] + swapTokensForExactTokens(swapTokensForExactTokensCall), + } + impl UniswapV2Router02Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [136u8, 3u8, 219u8, 238u8], + [173u8, 92u8, 70u8, 72u8], + [173u8, 97u8, 93u8, 236u8], + [196u8, 90u8, 1u8, 85u8], + [232u8, 227u8, 55u8, 0u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(swapTokensForExactTokens), + ::core::stringify!(WETH), + ::core::stringify!(quote), + ::core::stringify!(factory), + ::core::stringify!(addLiquidity), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for UniswapV2Router02Calls { + const COUNT: usize = 5usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "UniswapV2Router02Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH(_) => ::SELECTOR, + Self::addLiquidity(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quote(_) => ::SELECTOR, + Self::swapTokensForExactTokens(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw( + data, + ) + .map(UniswapV2Router02Calls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV2Router02Calls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV2Router02Calls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV2Router02Calls::factory) + } + factory + }, + { + fn addLiquidity( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(UniswapV2Router02Calls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + UniswapV2Router02Calls, + >] = &[ + { + fn swapTokensForExactTokens( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV2Router02Calls::swapTokensForExactTokens) + } + swapTokensForExactTokens + }, + { + fn WETH(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV2Router02Calls::WETH) + } + WETH + }, + { + fn quote(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV2Router02Calls::quote) + } + quote + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV2Router02Calls::factory) + } + factory + }, + { + fn addLiquidity( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV2Router02Calls::addLiquidity) + } + addLiquidity + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH(inner) => { + ::abi_encoded_size(inner) + } + Self::addLiquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quote(inner) => { + ::abi_encoded_size(inner) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH(inner) => { + ::abi_encode_raw(inner, out) + } + Self::addLiquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quote(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swapTokensForExactTokens(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`UniswapV2Router02`](self) contract instance. + + See the [wrapper's documentation](`UniswapV2Router02Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> UniswapV2Router02Instance { + UniswapV2Router02Instance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + _factory: alloy_sol_types::private::Address, + _WETH: alloy_sol_types::private::Address, + ) -> impl ::core::future::Future>> + { + UniswapV2Router02Instance::::deploy(__provider, _factory, _WETH) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + _factory: alloy_sol_types::private::Address, + _WETH: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + UniswapV2Router02Instance::::deploy_builder(__provider, _factory, _WETH) + } + /**A [`UniswapV2Router02`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`UniswapV2Router02`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct UniswapV2Router02Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for UniswapV2Router02Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("UniswapV2Router02Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + UniswapV2Router02Instance + { + /**Creates a new wrapper around an on-chain [`UniswapV2Router02`](self) contract instance. + + See the [wrapper's documentation](`UniswapV2Router02Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + __provider: P, + _factory: alloy_sol_types::private::Address, + _WETH: alloy_sol_types::private::Address, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider, _factory, _WETH); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder( + __provider: P, + _factory: alloy_sol_types::private::Address, + _WETH: alloy_sol_types::private::Address, + ) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + [ + &BYTECODE[..], + &alloy_sol_types::SolConstructor::abi_encode(&constructorCall { + _factory, + _WETH, + })[..], + ] + .concat() + .into(), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl UniswapV2Router02Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> UniswapV2Router02Instance { + UniswapV2Router02Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + UniswapV2Router02Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH`] function. + pub fn WETH(&self) -> alloy_contract::SolCallBuilder<&P, WETHCall, N> { + self.call_builder(&WETHCall) + } + + ///Creates a new call builder for the [`addLiquidity`] function. + pub fn addLiquidity( + &self, + tokenA: alloy_sol_types::private::Address, + tokenB: alloy_sol_types::private::Address, + amountADesired: alloy_sol_types::private::primitives::aliases::U256, + amountBDesired: alloy_sol_types::private::primitives::aliases::U256, + amountAMin: alloy_sol_types::private::primitives::aliases::U256, + amountBMin: alloy_sol_types::private::primitives::aliases::U256, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, addLiquidityCall, N> { + self.call_builder(&addLiquidityCall { + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin, + to, + deadline, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quote`] function. + pub fn quote( + &self, + amountA: alloy_sol_types::private::primitives::aliases::U256, + reserveA: alloy_sol_types::private::primitives::aliases::U256, + reserveB: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteCall, N> { + self.call_builder("eCall { + amountA, + reserveA, + reserveB, + }) + } + + ///Creates a new call builder for the [`swapTokensForExactTokens`] + /// function. + pub fn swapTokensForExactTokens( + &self, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + amountInMax: alloy_sol_types::private::primitives::aliases::U256, + path: alloy_sol_types::private::Vec, + to: alloy_sol_types::private::Address, + deadline: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, swapTokensForExactTokensCall, N> { + self.call_builder(&swapTokensForExactTokensCall { + amountOut, + amountInMax, + path, + to, + deadline, + }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + UniswapV2Router02Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = UniswapV2Router02::UniswapV2Router02Instance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0xedf6066a2b290C185783862C7F4776A2C8077AD1"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/uniswapv3pool/Cargo.toml b/contracts/generated/contracts-generated/uniswapv3pool/Cargo.toml new file mode 100644 index 0000000000..65106539a9 --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv3pool/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-uniswapv3pool" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/uniswapv3pool/src/lib.rs b/contracts/generated/contracts-generated/uniswapv3pool/src/lib.rs new file mode 100644 index 0000000000..bb14908ba7 --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv3pool/src/lib.rs @@ -0,0 +1,5990 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface UniswapV3Pool { + event Burn(address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1); + event Collect(address indexed owner, address recipient, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount0, uint128 amount1); + event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1); + event Flash(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1); + event IncreaseObservationCardinalityNext(uint16 observationCardinalityNextOld, uint16 observationCardinalityNextNew); + event Initialize(uint160 sqrtPriceX96, int24 tick); + event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1); + event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New); + event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick); + + constructor(); + + function burn(int24 tickLower, int24 tickUpper, uint128 amount) external returns (uint256 amount0, uint256 amount1); + function collect(address recipient, int24 tickLower, int24 tickUpper, uint128 amount0Requested, uint128 amount1Requested) external returns (uint128 amount0, uint128 amount1); + function factory() external view returns (address); + function fee() external view returns (uint24); + function flash(address recipient, uint256 amount0, uint256 amount1, bytes memory data) external; + function initialize(uint160 sqrtPriceX96) external; + function liquidity() external view returns (uint128); + function mint(address recipient, int24 tickLower, int24 tickUpper, uint128 amount, bytes memory data) external returns (uint256 amount0, uint256 amount1); + function observations(uint256) external view returns (uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized); + function observe(uint32[] memory secondsAgos) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s); + function positions(bytes32) external view returns (uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1); + function protocolFees() external view returns (uint128 token0, uint128 token1); + function swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes memory data) external returns (int256 amount0, int256 amount1); + function ticks(int24) external view returns (uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized); + function token0() external view returns (address); + function token1() external view returns (address); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { + "name": "tickLower", + "type": "int24", + "internalType": "int24" + }, + { + "name": "tickUpper", + "type": "int24", + "internalType": "int24" + }, + { + "name": "amount", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [ + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "collect", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "tickLower", + "type": "int24", + "internalType": "int24" + }, + { + "name": "tickUpper", + "type": "int24", + "internalType": "int24" + }, + { + "name": "amount0Requested", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "amount1Requested", + "type": "uint128", + "internalType": "uint128" + } + ], + "outputs": [ + { + "name": "amount0", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "fee", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint24", + "internalType": "uint24" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "flash", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "sqrtPriceX96", + "type": "uint160", + "internalType": "uint160" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "liquidity", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "tickLower", + "type": "int24", + "internalType": "int24" + }, + { + "name": "tickUpper", + "type": "int24", + "internalType": "int24" + }, + { + "name": "amount", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "amount0", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "observations", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "blockTimestamp", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "tickCumulative", + "type": "int56", + "internalType": "int56" + }, + { + "name": "secondsPerLiquidityCumulativeX128", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "observe", + "inputs": [ + { + "name": "secondsAgos", + "type": "uint32[]", + "internalType": "uint32[]" + } + ], + "outputs": [ + { + "name": "tickCumulatives", + "type": "int56[]", + "internalType": "int56[]" + }, + { + "name": "secondsPerLiquidityCumulativeX128s", + "type": "uint160[]", + "internalType": "uint160[]" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "positions", + "inputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "liquidity", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "feeGrowthInside0LastX128", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "feeGrowthInside1LastX128", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "tokensOwed0", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "tokensOwed1", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "protocolFees", + "inputs": [], + "outputs": [ + { + "name": "token0", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "token1", + "type": "uint128", + "internalType": "uint128" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "swap", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "zeroForOne", + "type": "bool", + "internalType": "bool" + }, + { + "name": "amountSpecified", + "type": "int256", + "internalType": "int256" + }, + { + "name": "sqrtPriceLimitX96", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "amount0", + "type": "int256", + "internalType": "int256" + }, + { + "name": "amount1", + "type": "int256", + "internalType": "int256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "ticks", + "inputs": [ + { + "name": "", + "type": "int24", + "internalType": "int24" + } + ], + "outputs": [ + { + "name": "liquidityGross", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "liquidityNet", + "type": "int128", + "internalType": "int128" + }, + { + "name": "feeGrowthOutside0X128", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "feeGrowthOutside1X128", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "tickCumulativeOutside", + "type": "int56", + "internalType": "int56" + }, + { + "name": "secondsPerLiquidityOutsideX128", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "secondsOutside", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "initialized", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "token0", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "token1", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "Burn", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tickLower", + "type": "int24", + "indexed": true, + "internalType": "int24" + }, + { + "name": "tickUpper", + "type": "int24", + "indexed": true, + "internalType": "int24" + }, + { + "name": "amount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "amount0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Collect", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "tickLower", + "type": "int24", + "indexed": true, + "internalType": "int24" + }, + { + "name": "tickUpper", + "type": "int24", + "indexed": true, + "internalType": "int24" + }, + { + "name": "amount0", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CollectProtocol", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "amount1", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Flash", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "paid0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "paid1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "IncreaseObservationCardinalityNext", + "inputs": [ + { + "name": "observationCardinalityNextOld", + "type": "uint16", + "indexed": false, + "internalType": "uint16" + }, + { + "name": "observationCardinalityNextNew", + "type": "uint16", + "indexed": false, + "internalType": "uint16" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialize", + "inputs": [ + { + "name": "sqrtPriceX96", + "type": "uint160", + "indexed": false, + "internalType": "uint160" + }, + { + "name": "tick", + "type": "int24", + "indexed": false, + "internalType": "int24" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Mint", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tickLower", + "type": "int24", + "indexed": true, + "internalType": "int24" + }, + { + "name": "tickUpper", + "type": "int24", + "indexed": true, + "internalType": "int24" + }, + { + "name": "amount", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "amount0", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount1", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SetFeeProtocol", + "inputs": [ + { + "name": "feeProtocol0Old", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + }, + { + "name": "feeProtocol1Old", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + }, + { + "name": "feeProtocol0New", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + }, + { + "name": "feeProtocol1New", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Swap", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount0", + "type": "int256", + "indexed": false, + "internalType": "int256" + }, + { + "name": "amount1", + "type": "int256", + "indexed": false, + "internalType": "int256" + }, + { + "name": "sqrtPriceX96", + "type": "uint160", + "indexed": false, + "internalType": "uint160" + }, + { + "name": "liquidity", + "type": "uint128", + "indexed": false, + "internalType": "uint128" + }, + { + "name": "tick", + "type": "int24", + "indexed": false, + "internalType": "int24" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod UniswapV3Pool { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Burn(address,int24,int24,uint128,uint256,uint256)` and selector `0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c`. + ```solidity + event Burn(address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Burn { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tickLower: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub tickUpper: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub amount: u128, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Burn { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Burn(address,int24,int24,uint128,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 12u8, 57u8, 108u8, 217u8, 137u8, 163u8, 159u8, 68u8, 89u8, 181u8, 250u8, 26u8, + 237u8, 106u8, 154u8, 141u8, 205u8, 188u8, 69u8, 144u8, 138u8, 207u8, 214u8, + 126u8, 2u8, 140u8, 213u8, 104u8, 218u8, 152u8, 152u8, 44u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + tickLower: topics.2, + tickUpper: topics.3, + amount: data.0, + amount0: data.1, + amount1: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.tickLower.clone(), + self.tickUpper.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tickLower); + out[3usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tickUpper); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Burn { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Burn> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Burn) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Collect(address,address,int24,int24,uint128,uint128)` and selector `0x70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0`. + ```solidity + event Collect(address indexed owner, address recipient, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount0, uint128 amount1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Collect { + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tickLower: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub tickUpper: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub amount0: u128, + #[allow(missing_docs)] + pub amount1: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Collect { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Collect(address,address,int24,int24,uint128,uint128)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 112u8, 147u8, 83u8, 56u8, 230u8, 151u8, 117u8, 69u8, 106u8, 133u8, 221u8, + 239u8, 34u8, 108u8, 57u8, 95u8, 182u8, 104u8, 182u8, 63u8, 160u8, 17u8, 95u8, + 95u8, 32u8, 97u8, 11u8, 56u8, 142u8, 108u8, 169u8, 192u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + recipient: data.0, + tickLower: topics.2, + tickUpper: topics.3, + amount0: data.1, + amount1: data.2, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.tickLower.clone(), + self.tickUpper.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tickLower); + out[3usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tickUpper); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Collect { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Collect> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Collect) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `CollectProtocol(address,address,uint128,uint128)` and selector `0x596b573906218d3411850b26a6b437d6c4522fdb43d2d2386263f86d50b8b151`. + ```solidity + event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct CollectProtocol { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: u128, + #[allow(missing_docs)] + pub amount1: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for CollectProtocol { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "CollectProtocol(address,address,uint128,uint128)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 89u8, 107u8, 87u8, 57u8, 6u8, 33u8, 141u8, 52u8, 17u8, 133u8, 11u8, 38u8, + 166u8, 180u8, 55u8, 214u8, 196u8, 82u8, 47u8, 219u8, 67u8, 210u8, 210u8, 56u8, + 98u8, 99u8, 248u8, 109u8, 80u8, 184u8, 177u8, 81u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + recipient: topics.2, + amount0: data.0, + amount1: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.sender.clone(), + self.recipient.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + out[2usize] = ::encode_topic( + &self.recipient, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for CollectProtocol { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&CollectProtocol> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &CollectProtocol) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Flash(address,address,uint256,uint256,uint256,uint256)` and selector `0xbdbdb71d7860376ba52b25a5028beea23581364a40522f6bcfb86bb1f2dca633`. + ```solidity + event Flash(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Flash { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub paid0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub paid1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Flash { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "Flash(address,address,uint256,uint256,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 189u8, 189u8, 183u8, 29u8, 120u8, 96u8, 55u8, 107u8, 165u8, 43u8, 37u8, 165u8, + 2u8, 139u8, 238u8, 162u8, 53u8, 129u8, 54u8, 74u8, 64u8, 82u8, 47u8, 107u8, + 207u8, 184u8, 107u8, 177u8, 242u8, 220u8, 166u8, 51u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + recipient: topics.2, + amount0: data.0, + amount1: data.1, + paid0: data.2, + paid1: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + as alloy_sol_types::SolType>::tokenize( + &self.paid0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.paid1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.sender.clone(), + self.recipient.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + out[2usize] = ::encode_topic( + &self.recipient, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Flash { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Flash> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Flash) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `IncreaseObservationCardinalityNext(uint16,uint16)` and selector `0xac49e518f90a358f652e4400164f05a5d8f7e35e7747279bc3a93dbf584e125a`. + ```solidity + event IncreaseObservationCardinalityNext(uint16 observationCardinalityNextOld, uint16 observationCardinalityNextNew); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct IncreaseObservationCardinalityNext { + #[allow(missing_docs)] + pub observationCardinalityNextOld: u16, + #[allow(missing_docs)] + pub observationCardinalityNextNew: u16, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for IncreaseObservationCardinalityNext { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<16>, + alloy_sol_types::sol_data::Uint<16>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "IncreaseObservationCardinalityNext(uint16,uint16)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 172u8, 73u8, 229u8, 24u8, 249u8, 10u8, 53u8, 143u8, 101u8, 46u8, 68u8, 0u8, + 22u8, 79u8, 5u8, 165u8, 216u8, 247u8, 227u8, 94u8, 119u8, 71u8, 39u8, 155u8, + 195u8, 169u8, 61u8, 191u8, 88u8, 78u8, 18u8, 90u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + observationCardinalityNextOld: data.0, + observationCardinalityNextNew: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.observationCardinalityNextOld, + ), + as alloy_sol_types::SolType>::tokenize( + &self.observationCardinalityNextNew, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for IncreaseObservationCardinalityNext { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&IncreaseObservationCardinalityNext> for alloy_sol_types::private::LogData { + #[inline] + fn from( + this: &IncreaseObservationCardinalityNext, + ) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Initialize(uint160,int24)` and selector `0x98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c95`. + ```solidity + event Initialize(uint160 sqrtPriceX96, int24 tick); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Initialize { + #[allow(missing_docs)] + pub sqrtPriceX96: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub tick: alloy_sol_types::private::primitives::aliases::I24, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Initialize { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Int<24>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Initialize(uint160,int24)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 152u8, 99u8, 96u8, 54u8, 203u8, 102u8, 169u8, 193u8, 154u8, 55u8, 67u8, 94u8, + 252u8, 30u8, 144u8, 20u8, 33u8, 144u8, 33u8, 78u8, 138u8, 190u8, 184u8, 33u8, + 189u8, 186u8, 63u8, 41u8, 144u8, 221u8, 76u8, 149u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sqrtPriceX96: data.0, + tick: data.1, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceX96, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tick, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Initialize { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Initialize> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Initialize) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Mint(address,address,int24,int24,uint128,uint256,uint256)` and selector `0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde`. + ```solidity + event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Mint { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub owner: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tickLower: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub tickUpper: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub amount: u128, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Mint { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "Mint(address,address,int24,int24,uint128,uint256,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 122u8, 83u8, 8u8, 11u8, 164u8, 20u8, 21u8, 139u8, 231u8, 236u8, 105u8, 185u8, + 135u8, 181u8, 251u8, 125u8, 7u8, 222u8, 225u8, 1u8, 254u8, 133u8, 72u8, 143u8, + 8u8, 83u8, 174u8, 22u8, 35u8, 157u8, 11u8, 222u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: data.0, + owner: topics.1, + tickLower: topics.2, + tickUpper: topics.3, + amount: data.1, + amount0: data.2, + amount1: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + ::tokenize( + &self.sender, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.owner.clone(), + self.tickLower.clone(), + self.tickUpper.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tickLower); + out[3usize] = as alloy_sol_types::EventTopic>::encode_topic(&self.tickUpper); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Mint { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Mint> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Mint) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `SetFeeProtocol(uint8,uint8,uint8,uint8)` and selector `0x973d8d92bb299f4af6ce49b52a8adb85ae46b9f214c4c4fc06ac77401237b133`. + ```solidity + event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct SetFeeProtocol { + #[allow(missing_docs)] + pub feeProtocol0Old: u8, + #[allow(missing_docs)] + pub feeProtocol1Old: u8, + #[allow(missing_docs)] + pub feeProtocol0New: u8, + #[allow(missing_docs)] + pub feeProtocol1New: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for SetFeeProtocol { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::Uint<8>, + alloy_sol_types::sol_data::Uint<8>, + ); + type TopicList = (alloy_sol_types::sol_data::FixedBytes<32>,); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "SetFeeProtocol(uint8,uint8,uint8,uint8)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 151u8, 61u8, 141u8, 146u8, 187u8, 41u8, 159u8, 74u8, 246u8, 206u8, 73u8, 181u8, + 42u8, 138u8, 219u8, 133u8, 174u8, 70u8, 185u8, 242u8, 20u8, 196u8, 196u8, + 252u8, 6u8, 172u8, 119u8, 64u8, 18u8, 55u8, 177u8, 51u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + feeProtocol0Old: data.0, + feeProtocol1Old: data.1, + feeProtocol0New: data.2, + feeProtocol1New: data.3, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.feeProtocol0Old, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeProtocol1Old, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeProtocol0New, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeProtocol1New, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(),) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for SetFeeProtocol { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&SetFeeProtocol> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &SetFeeProtocol) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Swap(address,address,int256,int256,uint160,uint128,int24)` and selector `0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67`. + ```solidity + event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Swap { + #[allow(missing_docs)] + pub sender: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::I256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::I256, + #[allow(missing_docs)] + pub sqrtPriceX96: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub liquidity: u128, + #[allow(missing_docs)] + pub tick: alloy_sol_types::private::primitives::aliases::I24, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Swap { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = ( + alloy_sol_types::sol_data::Int<256>, + alloy_sol_types::sol_data::Int<256>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Int<24>, + ); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = + "Swap(address,address,int256,int256,uint160,uint128,int24)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 196u8, 32u8, 121u8, 249u8, 74u8, 99u8, 80u8, 215u8, 230u8, 35u8, 95u8, 41u8, + 23u8, 73u8, 36u8, 249u8, 40u8, 204u8, 42u8, 200u8, 24u8, 235u8, 100u8, 254u8, + 216u8, 0u8, 78u8, 17u8, 95u8, 188u8, 202u8, 103u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + sender: topics.1, + recipient: topics.2, + amount0: data.0, + amount1: data.1, + sqrtPriceX96: data.2, + liquidity: data.3, + tick: data.4, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceX96, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tick, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.sender.clone(), + self.recipient.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.sender, + ); + out[2usize] = ::encode_topic( + &self.recipient, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Swap { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Swap> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Swap) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + /**Constructor`. + ```solidity + constructor(); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall {} + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `burn(int24,int24,uint128)` and selector `0xa34123a7`. + ```solidity + function burn(int24 tickLower, int24 tickUpper, uint128 amount) external returns (uint256 amount0, uint256 amount1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct burnCall { + #[allow(missing_docs)] + pub tickLower: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub tickUpper: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub amount: u128, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`burn(int24,int24,uint128)`](burnCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct burnReturn { + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Uint<128>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::I24, + alloy_sol_types::private::primitives::aliases::I24, + u128, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: burnCall) -> Self { + (value.tickLower, value.tickUpper, value.amount) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for burnCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tickLower: tuple.0, + tickUpper: tuple.1, + amount: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: burnReturn) -> Self { + (value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for burnReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0: tuple.0, + amount1: tuple.1, + } + } + } + } + impl burnReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for burnCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Uint<128>, + ); + type Return = burnReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [163u8, 65u8, 35u8, 167u8]; + const SIGNATURE: &'static str = "burn(int24,int24,uint128)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.tickLower, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tickUpper, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + burnReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `collect(address,int24,int24,uint128,uint128)` and selector `0x4f1eb3d8`. + ```solidity + function collect(address recipient, int24 tickLower, int24 tickUpper, uint128 amount0Requested, uint128 amount1Requested) external returns (uint128 amount0, uint128 amount1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct collectCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tickLower: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub tickUpper: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub amount0Requested: u128, + #[allow(missing_docs)] + pub amount1Requested: u128, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`collect(address,int24,int24,uint128,uint128)`](collectCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct collectReturn { + #[allow(missing_docs)] + pub amount0: u128, + #[allow(missing_docs)] + pub amount1: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::I24, + alloy_sol_types::private::primitives::aliases::I24, + u128, + u128, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: collectCall) -> Self { + ( + value.recipient, + value.tickLower, + value.tickUpper, + value.amount0Requested, + value.amount1Requested, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for collectCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + tickLower: tuple.1, + tickUpper: tuple.2, + amount0Requested: tuple.3, + amount1Requested: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u128, u128); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: collectReturn) -> Self { + (value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for collectReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0: tuple.0, + amount1: tuple.1, + } + } + } + } + impl collectReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for collectCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + type Return = collectReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [79u8, 30u8, 179u8, 216u8]; + const SIGNATURE: &'static str = "collect(address,int24,int24,uint128,uint128)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tickLower, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tickUpper, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0Requested, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1Requested, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + collectReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `fee()` and selector `0xddca3f43`. + ```solidity + function fee() external view returns (uint24); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct feeCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`fee()`](feeCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct feeReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U24, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: feeCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for feeCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<24>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U24,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: feeReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for feeReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for feeCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::primitives::aliases::U24; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<24>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 202u8, 63u8, 67u8]; + const SIGNATURE: &'static str = "fee()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: feeReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: feeReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `flash(address,uint256,uint256,bytes)` and selector `0x490e6cbc`. + ```solidity + function flash(address recipient, uint256 amount0, uint256 amount1, bytes memory data) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct flashCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + ///Container type for the return parameters of the + /// [`flash(address,uint256,uint256,bytes)`](flashCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct flashReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: flashCall) -> Self { + (value.recipient, value.amount0, value.amount1, value.data) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for flashCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + amount0: tuple.1, + amount1: tuple.2, + data: tuple.3, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: flashReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for flashReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl flashReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for flashCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = flashReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [73u8, 14u8, 108u8, 188u8]; + const SIGNATURE: &'static str = "flash(address,uint256,uint256,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + flashReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `initialize(uint160)` and selector `0xf637731d`. + ```solidity + function initialize(uint160 sqrtPriceX96) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeCall { + #[allow(missing_docs)] + pub sqrtPriceX96: alloy_sol_types::private::primitives::aliases::U160, + } + ///Container type for the return parameters of the + /// [`initialize(uint160)`](initializeCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct initializeReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<160>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U160,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeCall) -> Self { + (value.sqrtPriceX96,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + sqrtPriceX96: tuple.0, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: initializeReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for initializeReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl initializeReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for initializeCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Uint<160>,); + type Return = initializeReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [246u8, 55u8, 115u8, 29u8]; + const SIGNATURE: &'static str = "initialize(uint160)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceX96, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + initializeReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `liquidity()` and selector `0x1a686502`. + ```solidity + function liquidity() external view returns (uint128); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct liquidityCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`liquidity()`](liquidityCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct liquidityReturn { + #[allow(missing_docs)] + pub _0: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: liquidityCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for liquidityCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<128>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u128,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: liquidityReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for liquidityReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for liquidityCall { + type Parameters<'a> = (); + type Return = u128; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<128>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [26u8, 104u8, 101u8, 2u8]; + const SIGNATURE: &'static str = "liquidity()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: liquidityReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: liquidityReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `mint(address,int24,int24,uint128,bytes)` and selector `0x3c8a7d8d`. + ```solidity + function mint(address recipient, int24 tickLower, int24 tickUpper, uint128 amount, bytes memory data) external returns (uint256 amount0, uint256 amount1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tickLower: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub tickUpper: alloy_sol_types::private::primitives::aliases::I24, + #[allow(missing_docs)] + pub amount: u128, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`mint(address,int24,int24,uint128,bytes)`](mintCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct mintReturn { + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::I24, + alloy_sol_types::private::primitives::aliases::I24, + u128, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintCall) -> Self { + ( + value.recipient, + value.tickLower, + value.tickUpper, + value.amount, + value.data, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + tickLower: tuple.1, + tickUpper: tuple.2, + amount: tuple.3, + data: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: mintReturn) -> Self { + (value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for mintReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0: tuple.0, + amount1: tuple.1, + } + } + } + } + impl mintReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for mintCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Int<24>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = mintReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [60u8, 138u8, 125u8, 141u8]; + const SIGNATURE: &'static str = "mint(address,int24,int24,uint128,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tickLower, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tickUpper, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + mintReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `observations(uint256)` and selector `0x252c09d7`. + ```solidity + function observations(uint256) external view returns (uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct observationsCall(pub alloy_sol_types::private::primitives::aliases::U256); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`observations(uint256)`](observationsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct observationsReturn { + #[allow(missing_docs)] + pub blockTimestamp: u32, + #[allow(missing_docs)] + pub tickCumulative: alloy_sol_types::private::primitives::aliases::I56, + #[allow(missing_docs)] + pub secondsPerLiquidityCumulativeX128: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub initialized: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: observationsCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for observationsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Int<56>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + u32, + alloy_sol_types::private::primitives::aliases::I56, + alloy_sol_types::private::primitives::aliases::U160, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: observationsReturn) -> Self { + ( + value.blockTimestamp, + value.tickCumulative, + value.secondsPerLiquidityCumulativeX128, + value.initialized, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for observationsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + blockTimestamp: tuple.0, + tickCumulative: tuple.1, + secondsPerLiquidityCumulativeX128: tuple.2, + initialized: tuple.3, + } + } + } + } + impl observationsReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.blockTimestamp, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tickCumulative, + ), + as alloy_sol_types::SolType>::tokenize( + &self.secondsPerLiquidityCumulativeX128, + ), + ::tokenize( + &self.initialized, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for observationsCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Return = observationsReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Int<56>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Bool, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [37u8, 44u8, 9u8, 215u8]; + const SIGNATURE: &'static str = "observations(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + observationsReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `observe(uint32[])` and selector `0x883bdbfd`. + ```solidity + function observe(uint32[] memory secondsAgos) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct observeCall { + #[allow(missing_docs)] + pub secondsAgos: alloy_sol_types::private::Vec, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`observe(uint32[])`](observeCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct observeReturn { + #[allow(missing_docs)] + pub tickCumulatives: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub secondsPerLiquidityCumulativeX128s: + alloy_sol_types::private::Vec, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = + (alloy_sol_types::sol_data::Array>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Vec,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: observeCall) -> Self { + (value.secondsAgos,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for observeCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + secondsAgos: tuple.0, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: observeReturn) -> Self { + ( + value.tickCumulatives, + value.secondsPerLiquidityCumulativeX128s, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for observeReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tickCumulatives: tuple.0, + secondsPerLiquidityCumulativeX128s: tuple.1, + } + } + } + } + impl observeReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + , + > as alloy_sol_types::SolType>::tokenize(&self.tickCumulatives), + , + > as alloy_sol_types::SolType>::tokenize( + &self.secondsPerLiquidityCumulativeX128s, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for observeCall { + type Parameters<'a> = + (alloy_sol_types::sol_data::Array>,); + type Return = observeReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [136u8, 59u8, 219u8, 253u8]; + const SIGNATURE: &'static str = "observe(uint32[])"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + (, + > as alloy_sol_types::SolType>::tokenize( + &self.secondsAgos + ),) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + observeReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `positions(bytes32)` and selector `0x514ea4bf`. + ```solidity + function positions(bytes32) external view returns (uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct positionsCall(pub alloy_sol_types::private::FixedBytes<32>); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`positions(bytes32)`](positionsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct positionsReturn { + #[allow(missing_docs)] + pub liquidity: u128, + #[allow(missing_docs)] + pub feeGrowthInside0LastX128: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub feeGrowthInside1LastX128: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub tokensOwed0: u128, + #[allow(missing_docs)] + pub tokensOwed1: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::FixedBytes<32>,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: positionsCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for positionsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + u128, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + u128, + u128, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: positionsReturn) -> Self { + ( + value.liquidity, + value.feeGrowthInside0LastX128, + value.feeGrowthInside1LastX128, + value.tokensOwed0, + value.tokensOwed1, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for positionsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + liquidity: tuple.0, + feeGrowthInside0LastX128: tuple.1, + feeGrowthInside1LastX128: tuple.2, + tokensOwed0: tuple.3, + tokensOwed1: tuple.4, + } + } + } + } + impl positionsReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.liquidity, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeGrowthInside0LastX128, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeGrowthInside1LastX128, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tokensOwed0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tokensOwed1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for positionsCall { + type Parameters<'a> = (alloy_sol_types::sol_data::FixedBytes<32>,); + type Return = positionsReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [81u8, 78u8, 164u8, 191u8]; + const SIGNATURE: &'static str = "positions(bytes32)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.0), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + positionsReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `protocolFees()` and selector `0x1ad8b03b`. + ```solidity + function protocolFees() external view returns (uint128 token0, uint128 token1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct protocolFeesCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`protocolFees()`](protocolFeesCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct protocolFeesReturn { + #[allow(missing_docs)] + pub token0: u128, + #[allow(missing_docs)] + pub token1: u128, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: protocolFeesCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for protocolFeesCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u128, u128); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: protocolFeesReturn) -> Self { + (value.token0, value.token1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for protocolFeesReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + token0: tuple.0, + token1: tuple.1, + } + } + } + } + impl protocolFeesReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.token0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.token1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for protocolFeesCall { + type Parameters<'a> = (); + type Return = protocolFeesReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Uint<128>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [26u8, 216u8, 176u8, 59u8]; + const SIGNATURE: &'static str = "protocolFees()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + protocolFeesReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `swap(address,bool,int256,uint160,bytes)` and selector `0x128acb08`. + ```solidity + function swap(address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes memory data) external returns (int256 amount0, int256 amount1); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapCall { + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub zeroForOne: bool, + #[allow(missing_docs)] + pub amountSpecified: alloy_sol_types::private::primitives::aliases::I256, + #[allow(missing_docs)] + pub sqrtPriceLimitX96: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub data: alloy_sol_types::private::Bytes, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`swap(address,bool,int256,uint160,bytes)`](swapCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct swapReturn { + #[allow(missing_docs)] + pub amount0: alloy_sol_types::private::primitives::aliases::I256, + #[allow(missing_docs)] + pub amount1: alloy_sol_types::private::primitives::aliases::I256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Int<256>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Bytes, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + bool, + alloy_sol_types::private::primitives::aliases::I256, + alloy_sol_types::private::primitives::aliases::U160, + alloy_sol_types::private::Bytes, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapCall) -> Self { + ( + value.recipient, + value.zeroForOne, + value.amountSpecified, + value.sqrtPriceLimitX96, + value.data, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + recipient: tuple.0, + zeroForOne: tuple.1, + amountSpecified: tuple.2, + sqrtPriceLimitX96: tuple.3, + data: tuple.4, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Int<256>, + alloy_sol_types::sol_data::Int<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::I256, + alloy_sol_types::private::primitives::aliases::I256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: swapReturn) -> Self { + (value.amount0, value.amount1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for swapReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amount0: tuple.0, + amount1: tuple.1, + } + } + } + } + impl swapReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amount0, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount1, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for swapCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Bool, + alloy_sol_types::sol_data::Int<256>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Bytes, + ); + type Return = swapReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Int<256>, + alloy_sol_types::sol_data::Int<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [18u8, 138u8, 203u8, 8u8]; + const SIGNATURE: &'static str = "swap(address,bool,int256,uint160,bytes)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.recipient, + ), + ::tokenize( + &self.zeroForOne, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountSpecified, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceLimitX96, + ), + ::tokenize( + &self.data, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + swapReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `ticks(int24)` and selector `0xf30dba93`. + ```solidity + function ticks(int24) external view returns (uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ticksCall(pub alloy_sol_types::private::primitives::aliases::I24); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`ticks(int24)`](ticksCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ticksReturn { + #[allow(missing_docs)] + pub liquidityGross: u128, + #[allow(missing_docs)] + pub liquidityNet: i128, + #[allow(missing_docs)] + pub feeGrowthOutside0X128: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub feeGrowthOutside1X128: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub tickCumulativeOutside: alloy_sol_types::private::primitives::aliases::I56, + #[allow(missing_docs)] + pub secondsPerLiquidityOutsideX128: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub secondsOutside: u32, + #[allow(missing_docs)] + pub initialized: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Int<24>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::I24,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ticksCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ticksCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Int<128>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Int<56>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Bool, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + u128, + i128, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::I56, + alloy_sol_types::private::primitives::aliases::U160, + u32, + bool, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ticksReturn) -> Self { + ( + value.liquidityGross, + value.liquidityNet, + value.feeGrowthOutside0X128, + value.feeGrowthOutside1X128, + value.tickCumulativeOutside, + value.secondsPerLiquidityOutsideX128, + value.secondsOutside, + value.initialized, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ticksReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + liquidityGross: tuple.0, + liquidityNet: tuple.1, + feeGrowthOutside0X128: tuple.2, + feeGrowthOutside1X128: tuple.3, + tickCumulativeOutside: tuple.4, + secondsPerLiquidityOutsideX128: tuple.5, + secondsOutside: tuple.6, + initialized: tuple.7, + } + } + } + } + impl ticksReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.liquidityGross, + ), + as alloy_sol_types::SolType>::tokenize( + &self.liquidityNet, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeGrowthOutside0X128, + ), + as alloy_sol_types::SolType>::tokenize( + &self.feeGrowthOutside1X128, + ), + as alloy_sol_types::SolType>::tokenize( + &self.tickCumulativeOutside, + ), + as alloy_sol_types::SolType>::tokenize( + &self.secondsPerLiquidityOutsideX128, + ), + as alloy_sol_types::SolType>::tokenize( + &self.secondsOutside, + ), + ::tokenize( + &self.initialized, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for ticksCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Int<24>,); + type Return = ticksReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<128>, + alloy_sol_types::sol_data::Int<128>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Int<56>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Bool, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [243u8, 13u8, 186u8, 147u8]; + const SIGNATURE: &'static str = "ticks(int24)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ticksReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token0()` and selector `0x0dfe1681`. + ```solidity + function token0() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token0()`](token0Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token0Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token0Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token0Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token0Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [13u8, 254u8, 22u8, 129u8]; + const SIGNATURE: &'static str = "token0()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token0Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token0Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `token1()` and selector `0xd21220a7`. + ```solidity + function token1() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`token1()`](token1Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct token1Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: token1Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for token1Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for token1Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [210u8, 18u8, 32u8, 167u8]; + const SIGNATURE: &'static str = "token1()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: token1Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: token1Return = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`UniswapV3Pool`](self) function calls. + #[derive(Clone)] + pub enum UniswapV3PoolCalls { + #[allow(missing_docs)] + burn(burnCall), + #[allow(missing_docs)] + collect(collectCall), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + fee(feeCall), + #[allow(missing_docs)] + flash(flashCall), + #[allow(missing_docs)] + initialize(initializeCall), + #[allow(missing_docs)] + liquidity(liquidityCall), + #[allow(missing_docs)] + mint(mintCall), + #[allow(missing_docs)] + observations(observationsCall), + #[allow(missing_docs)] + observe(observeCall), + #[allow(missing_docs)] + positions(positionsCall), + #[allow(missing_docs)] + protocolFees(protocolFeesCall), + #[allow(missing_docs)] + swap(swapCall), + #[allow(missing_docs)] + ticks(ticksCall), + #[allow(missing_docs)] + token0(token0Call), + #[allow(missing_docs)] + token1(token1Call), + } + impl UniswapV3PoolCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [13u8, 254u8, 22u8, 129u8], + [18u8, 138u8, 203u8, 8u8], + [26u8, 104u8, 101u8, 2u8], + [26u8, 216u8, 176u8, 59u8], + [37u8, 44u8, 9u8, 215u8], + [60u8, 138u8, 125u8, 141u8], + [73u8, 14u8, 108u8, 188u8], + [79u8, 30u8, 179u8, 216u8], + [81u8, 78u8, 164u8, 191u8], + [136u8, 59u8, 219u8, 253u8], + [163u8, 65u8, 35u8, 167u8], + [196u8, 90u8, 1u8, 85u8], + [210u8, 18u8, 32u8, 167u8], + [221u8, 202u8, 63u8, 67u8], + [243u8, 13u8, 186u8, 147u8], + [246u8, 55u8, 115u8, 29u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(token0), + ::core::stringify!(swap), + ::core::stringify!(liquidity), + ::core::stringify!(protocolFees), + ::core::stringify!(observations), + ::core::stringify!(mint), + ::core::stringify!(flash), + ::core::stringify!(collect), + ::core::stringify!(positions), + ::core::stringify!(observe), + ::core::stringify!(burn), + ::core::stringify!(factory), + ::core::stringify!(token1), + ::core::stringify!(fee), + ::core::stringify!(ticks), + ::core::stringify!(initialize), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for UniswapV3PoolCalls { + const COUNT: usize = 16usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "UniswapV3PoolCalls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::burn(_) => ::SELECTOR, + Self::collect(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::fee(_) => ::SELECTOR, + Self::flash(_) => ::SELECTOR, + Self::initialize(_) => ::SELECTOR, + Self::liquidity(_) => ::SELECTOR, + Self::mint(_) => ::SELECTOR, + Self::observations(_) => ::SELECTOR, + Self::observe(_) => ::SELECTOR, + Self::positions(_) => ::SELECTOR, + Self::protocolFees(_) => ::SELECTOR, + Self::swap(_) => ::SELECTOR, + Self::ticks(_) => ::SELECTOR, + Self::token0(_) => ::SELECTOR, + Self::token1(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::token0) + } + token0 + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::swap) + } + swap + }, + { + fn liquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::liquidity) + } + liquidity + }, + { + fn protocolFees(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::protocolFees) + } + protocolFees + }, + { + fn observations(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::observations) + } + observations + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::mint) + } + mint + }, + { + fn flash(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::flash) + } + flash + }, + { + fn collect(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::collect) + } + collect + }, + { + fn positions(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::positions) + } + positions + }, + { + fn observe(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::observe) + } + observe + }, + { + fn burn(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::burn) + } + burn + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::factory) + } + factory + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::token1) + } + token1 + }, + { + fn fee(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::fee) + } + fee + }, + { + fn ticks(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::ticks) + } + ticks + }, + { + fn initialize(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3PoolCalls::initialize) + } + initialize + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[ + { + fn token0(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::token0) + } + token0 + }, + { + fn swap(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::swap) + } + swap + }, + { + fn liquidity(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::liquidity) + } + liquidity + }, + { + fn protocolFees(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV3PoolCalls::protocolFees) + } + protocolFees + }, + { + fn observations(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV3PoolCalls::observations) + } + observations + }, + { + fn mint(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::mint) + } + mint + }, + { + fn flash(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::flash) + } + flash + }, + { + fn collect(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::collect) + } + collect + }, + { + fn positions(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::positions) + } + positions + }, + { + fn observe(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::observe) + } + observe + }, + { + fn burn(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::burn) + } + burn + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::factory) + } + factory + }, + { + fn token1(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::token1) + } + token1 + }, + { + fn fee(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::fee) + } + fee + }, + { + fn ticks(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::ticks) + } + ticks + }, + { + fn initialize(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3PoolCalls::initialize) + } + initialize + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::burn(inner) => { + ::abi_encoded_size(inner) + } + Self::collect(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::fee(inner) => ::abi_encoded_size(inner), + Self::flash(inner) => { + ::abi_encoded_size(inner) + } + Self::initialize(inner) => { + ::abi_encoded_size(inner) + } + Self::liquidity(inner) => { + ::abi_encoded_size(inner) + } + Self::mint(inner) => { + ::abi_encoded_size(inner) + } + Self::observations(inner) => { + ::abi_encoded_size(inner) + } + Self::observe(inner) => { + ::abi_encoded_size(inner) + } + Self::positions(inner) => { + ::abi_encoded_size(inner) + } + Self::protocolFees(inner) => { + ::abi_encoded_size(inner) + } + Self::swap(inner) => { + ::abi_encoded_size(inner) + } + Self::ticks(inner) => { + ::abi_encoded_size(inner) + } + Self::token0(inner) => { + ::abi_encoded_size(inner) + } + Self::token1(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::burn(inner) => { + ::abi_encode_raw(inner, out) + } + Self::collect(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::fee(inner) => { + ::abi_encode_raw(inner, out) + } + Self::flash(inner) => { + ::abi_encode_raw(inner, out) + } + Self::initialize(inner) => { + ::abi_encode_raw(inner, out) + } + Self::liquidity(inner) => { + ::abi_encode_raw(inner, out) + } + Self::mint(inner) => { + ::abi_encode_raw(inner, out) + } + Self::observations(inner) => { + ::abi_encode_raw(inner, out) + } + Self::observe(inner) => { + ::abi_encode_raw(inner, out) + } + Self::positions(inner) => { + ::abi_encode_raw(inner, out) + } + Self::protocolFees(inner) => { + ::abi_encode_raw(inner, out) + } + Self::swap(inner) => { + ::abi_encode_raw(inner, out) + } + Self::ticks(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token0(inner) => { + ::abi_encode_raw(inner, out) + } + Self::token1(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`UniswapV3Pool`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum UniswapV3PoolEvents { + #[allow(missing_docs)] + Burn(Burn), + #[allow(missing_docs)] + Collect(Collect), + #[allow(missing_docs)] + CollectProtocol(CollectProtocol), + #[allow(missing_docs)] + Flash(Flash), + #[allow(missing_docs)] + IncreaseObservationCardinalityNext(IncreaseObservationCardinalityNext), + #[allow(missing_docs)] + Initialize(Initialize), + #[allow(missing_docs)] + Mint(Mint), + #[allow(missing_docs)] + SetFeeProtocol(SetFeeProtocol), + #[allow(missing_docs)] + Swap(Swap), + } + impl UniswapV3PoolEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 12u8, 57u8, 108u8, 217u8, 137u8, 163u8, 159u8, 68u8, 89u8, 181u8, 250u8, 26u8, + 237u8, 106u8, 154u8, 141u8, 205u8, 188u8, 69u8, 144u8, 138u8, 207u8, 214u8, 126u8, + 2u8, 140u8, 213u8, 104u8, 218u8, 152u8, 152u8, 44u8, + ], + [ + 89u8, 107u8, 87u8, 57u8, 6u8, 33u8, 141u8, 52u8, 17u8, 133u8, 11u8, 38u8, 166u8, + 180u8, 55u8, 214u8, 196u8, 82u8, 47u8, 219u8, 67u8, 210u8, 210u8, 56u8, 98u8, 99u8, + 248u8, 109u8, 80u8, 184u8, 177u8, 81u8, + ], + [ + 112u8, 147u8, 83u8, 56u8, 230u8, 151u8, 117u8, 69u8, 106u8, 133u8, 221u8, 239u8, + 34u8, 108u8, 57u8, 95u8, 182u8, 104u8, 182u8, 63u8, 160u8, 17u8, 95u8, 95u8, 32u8, + 97u8, 11u8, 56u8, 142u8, 108u8, 169u8, 192u8, + ], + [ + 122u8, 83u8, 8u8, 11u8, 164u8, 20u8, 21u8, 139u8, 231u8, 236u8, 105u8, 185u8, + 135u8, 181u8, 251u8, 125u8, 7u8, 222u8, 225u8, 1u8, 254u8, 133u8, 72u8, 143u8, 8u8, + 83u8, 174u8, 22u8, 35u8, 157u8, 11u8, 222u8, + ], + [ + 151u8, 61u8, 141u8, 146u8, 187u8, 41u8, 159u8, 74u8, 246u8, 206u8, 73u8, 181u8, + 42u8, 138u8, 219u8, 133u8, 174u8, 70u8, 185u8, 242u8, 20u8, 196u8, 196u8, 252u8, + 6u8, 172u8, 119u8, 64u8, 18u8, 55u8, 177u8, 51u8, + ], + [ + 152u8, 99u8, 96u8, 54u8, 203u8, 102u8, 169u8, 193u8, 154u8, 55u8, 67u8, 94u8, + 252u8, 30u8, 144u8, 20u8, 33u8, 144u8, 33u8, 78u8, 138u8, 190u8, 184u8, 33u8, + 189u8, 186u8, 63u8, 41u8, 144u8, 221u8, 76u8, 149u8, + ], + [ + 172u8, 73u8, 229u8, 24u8, 249u8, 10u8, 53u8, 143u8, 101u8, 46u8, 68u8, 0u8, 22u8, + 79u8, 5u8, 165u8, 216u8, 247u8, 227u8, 94u8, 119u8, 71u8, 39u8, 155u8, 195u8, + 169u8, 61u8, 191u8, 88u8, 78u8, 18u8, 90u8, + ], + [ + 189u8, 189u8, 183u8, 29u8, 120u8, 96u8, 55u8, 107u8, 165u8, 43u8, 37u8, 165u8, 2u8, + 139u8, 238u8, 162u8, 53u8, 129u8, 54u8, 74u8, 64u8, 82u8, 47u8, 107u8, 207u8, + 184u8, 107u8, 177u8, 242u8, 220u8, 166u8, 51u8, + ], + [ + 196u8, 32u8, 121u8, 249u8, 74u8, 99u8, 80u8, 215u8, 230u8, 35u8, 95u8, 41u8, 23u8, + 73u8, 36u8, 249u8, 40u8, 204u8, 42u8, 200u8, 24u8, 235u8, 100u8, 254u8, 216u8, 0u8, + 78u8, 17u8, 95u8, 188u8, 202u8, 103u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(Burn), + ::core::stringify!(CollectProtocol), + ::core::stringify!(Collect), + ::core::stringify!(Mint), + ::core::stringify!(SetFeeProtocol), + ::core::stringify!(Initialize), + ::core::stringify!(IncreaseObservationCardinalityNext), + ::core::stringify!(Flash), + ::core::stringify!(Swap), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for UniswapV3PoolEvents { + const COUNT: usize = 9usize; + const NAME: &'static str = "UniswapV3PoolEvents"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Burn) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Collect) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::CollectProtocol) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Flash) + } + Some( + ::SIGNATURE_HASH, + ) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::IncreaseObservationCardinalityNext) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::Initialize) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Mint) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::SetFeeProtocol) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Swap) + } + _ => { + alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }) + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for UniswapV3PoolEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Burn(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Collect(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::CollectProtocol(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Flash(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::IncreaseObservationCardinalityNext(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Initialize(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Mint(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::SetFeeProtocol(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Burn(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Collect(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::CollectProtocol(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Flash(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::IncreaseObservationCardinalityNext(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Initialize(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Mint(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::SetFeeProtocol(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Swap(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`UniswapV3Pool`](self) contract instance. + + See the [wrapper's documentation](`UniswapV3PoolInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> UniswapV3PoolInstance { + UniswapV3PoolInstance::::new(address, __provider) + } + /**A [`UniswapV3Pool`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`UniswapV3Pool`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct UniswapV3PoolInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for UniswapV3PoolInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("UniswapV3PoolInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + UniswapV3PoolInstance + { + /**Creates a new wrapper around an on-chain [`UniswapV3Pool`](self) contract instance. + + See the [wrapper's documentation](`UniswapV3PoolInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl UniswapV3PoolInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> UniswapV3PoolInstance { + UniswapV3PoolInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + UniswapV3PoolInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`burn`] function. + pub fn burn( + &self, + tickLower: alloy_sol_types::private::primitives::aliases::I24, + tickUpper: alloy_sol_types::private::primitives::aliases::I24, + amount: u128, + ) -> alloy_contract::SolCallBuilder<&P, burnCall, N> { + self.call_builder(&burnCall { + tickLower, + tickUpper, + amount, + }) + } + + ///Creates a new call builder for the [`collect`] function. + pub fn collect( + &self, + recipient: alloy_sol_types::private::Address, + tickLower: alloy_sol_types::private::primitives::aliases::I24, + tickUpper: alloy_sol_types::private::primitives::aliases::I24, + amount0Requested: u128, + amount1Requested: u128, + ) -> alloy_contract::SolCallBuilder<&P, collectCall, N> { + self.call_builder(&collectCall { + recipient, + tickLower, + tickUpper, + amount0Requested, + amount1Requested, + }) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`fee`] function. + pub fn fee(&self) -> alloy_contract::SolCallBuilder<&P, feeCall, N> { + self.call_builder(&feeCall) + } + + ///Creates a new call builder for the [`flash`] function. + pub fn flash( + &self, + recipient: alloy_sol_types::private::Address, + amount0: alloy_sol_types::private::primitives::aliases::U256, + amount1: alloy_sol_types::private::primitives::aliases::U256, + data: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, flashCall, N> { + self.call_builder(&flashCall { + recipient, + amount0, + amount1, + data, + }) + } + + ///Creates a new call builder for the [`initialize`] function. + pub fn initialize( + &self, + sqrtPriceX96: alloy_sol_types::private::primitives::aliases::U160, + ) -> alloy_contract::SolCallBuilder<&P, initializeCall, N> { + self.call_builder(&initializeCall { sqrtPriceX96 }) + } + + ///Creates a new call builder for the [`liquidity`] function. + pub fn liquidity(&self) -> alloy_contract::SolCallBuilder<&P, liquidityCall, N> { + self.call_builder(&liquidityCall) + } + + ///Creates a new call builder for the [`mint`] function. + pub fn mint( + &self, + recipient: alloy_sol_types::private::Address, + tickLower: alloy_sol_types::private::primitives::aliases::I24, + tickUpper: alloy_sol_types::private::primitives::aliases::I24, + amount: u128, + data: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, mintCall, N> { + self.call_builder(&mintCall { + recipient, + tickLower, + tickUpper, + amount, + data, + }) + } + + ///Creates a new call builder for the [`observations`] function. + pub fn observations( + &self, + _0: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, observationsCall, N> { + self.call_builder(&observationsCall(_0)) + } + + ///Creates a new call builder for the [`observe`] function. + pub fn observe( + &self, + secondsAgos: alloy_sol_types::private::Vec, + ) -> alloy_contract::SolCallBuilder<&P, observeCall, N> { + self.call_builder(&observeCall { secondsAgos }) + } + + ///Creates a new call builder for the [`positions`] function. + pub fn positions( + &self, + _0: alloy_sol_types::private::FixedBytes<32>, + ) -> alloy_contract::SolCallBuilder<&P, positionsCall, N> { + self.call_builder(&positionsCall(_0)) + } + + ///Creates a new call builder for the [`protocolFees`] function. + pub fn protocolFees(&self) -> alloy_contract::SolCallBuilder<&P, protocolFeesCall, N> { + self.call_builder(&protocolFeesCall) + } + + ///Creates a new call builder for the [`swap`] function. + pub fn swap( + &self, + recipient: alloy_sol_types::private::Address, + zeroForOne: bool, + amountSpecified: alloy_sol_types::private::primitives::aliases::I256, + sqrtPriceLimitX96: alloy_sol_types::private::primitives::aliases::U160, + data: alloy_sol_types::private::Bytes, + ) -> alloy_contract::SolCallBuilder<&P, swapCall, N> { + self.call_builder(&swapCall { + recipient, + zeroForOne, + amountSpecified, + sqrtPriceLimitX96, + data, + }) + } + + ///Creates a new call builder for the [`ticks`] function. + pub fn ticks( + &self, + _0: alloy_sol_types::private::primitives::aliases::I24, + ) -> alloy_contract::SolCallBuilder<&P, ticksCall, N> { + self.call_builder(&ticksCall(_0)) + } + + ///Creates a new call builder for the [`token0`] function. + pub fn token0(&self) -> alloy_contract::SolCallBuilder<&P, token0Call, N> { + self.call_builder(&token0Call) + } + + ///Creates a new call builder for the [`token1`] function. + pub fn token1(&self) -> alloy_contract::SolCallBuilder<&P, token1Call, N> { + self.call_builder(&token1Call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + UniswapV3PoolInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Burn`] event. + pub fn Burn_filter(&self) -> alloy_contract::Event<&P, Burn, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Collect`] event. + pub fn Collect_filter(&self) -> alloy_contract::Event<&P, Collect, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`CollectProtocol`] event. + pub fn CollectProtocol_filter(&self) -> alloy_contract::Event<&P, CollectProtocol, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Flash`] event. + pub fn Flash_filter(&self) -> alloy_contract::Event<&P, Flash, N> { + self.event_filter::() + } + + ///Creates a new event filter for the + /// [`IncreaseObservationCardinalityNext`] event. + pub fn IncreaseObservationCardinalityNext_filter( + &self, + ) -> alloy_contract::Event<&P, IncreaseObservationCardinalityNext, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Initialize`] event. + pub fn Initialize_filter(&self) -> alloy_contract::Event<&P, Initialize, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Mint`] event. + pub fn Mint_filter(&self) -> alloy_contract::Event<&P, Mint, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`SetFeeProtocol`] event. + pub fn SetFeeProtocol_filter(&self) -> alloy_contract::Event<&P, SetFeeProtocol, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Swap`] event. + pub fn Swap_filter(&self) -> alloy_contract::Event<&P, Swap, N> { + self.event_filter::() + } + } +} +pub type Instance = UniswapV3Pool::UniswapV3PoolInstance<::alloy_provider::DynProvider>; diff --git a/contracts/generated/contracts-generated/uniswapv3quoterv2/Cargo.toml b/contracts/generated/contracts-generated/uniswapv3quoterv2/Cargo.toml new file mode 100644 index 0000000000..6bbff33248 --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv3quoterv2/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-uniswapv3quoterv2" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/uniswapv3quoterv2/src/lib.rs b/contracts/generated/contracts-generated/uniswapv3quoterv2/src/lib.rs new file mode 100644 index 0000000000..075674a2bc --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv3quoterv2/src/lib.rs @@ -0,0 +1,2716 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library IQuoterV2 { + struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; uint24 fee; uint160 sqrtPriceLimitX96; } + struct QuoteExactOutputSingleParams { address tokenIn; address tokenOut; uint256 amount; uint24 fee; uint160 sqrtPriceLimitX96; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IQuoterV2 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; uint24 fee; uint160 sqrtPriceLimitX96; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct QuoteExactInputSingleParams { + #[allow(missing_docs)] + pub tokenIn: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenOut: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountIn: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub fee: alloy_sol_types::private::primitives::aliases::U24, + #[allow(missing_docs)] + pub sqrtPriceLimitX96: alloy_sol_types::private::primitives::aliases::U160, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<24>, + alloy_sol_types::sol_data::Uint<160>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U24, + alloy_sol_types::private::primitives::aliases::U160, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: QuoteExactInputSingleParams) -> Self { + ( + value.tokenIn, + value.tokenOut, + value.amountIn, + value.fee, + value.sqrtPriceLimitX96, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for QuoteExactInputSingleParams { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenIn: tuple.0, + tokenOut: tuple.1, + amountIn: tuple.2, + fee: tuple.3, + sqrtPriceLimitX96: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for QuoteExactInputSingleParams { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for QuoteExactInputSingleParams { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.tokenIn, + ), + ::tokenize( + &self.tokenOut, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountIn, + ), + as alloy_sol_types::SolType>::tokenize( + &self.fee, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceLimitX96, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for QuoteExactInputSingleParams { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for QuoteExactInputSingleParams { + const NAME: &'static str = "QuoteExactInputSingleParams"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "QuoteExactInputSingleParams(address tokenIn,address tokenOut,uint256 \ + amountIn,uint24 fee,uint160 sqrtPriceLimitX96)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.tokenIn, + ) + .0, + ::eip712_data_word( + &self.tokenOut, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amountIn) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.fee) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.sqrtPriceLimitX96, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for QuoteExactInputSingleParams { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.tokenIn, + ) + + ::topic_preimage_length( + &rust.tokenOut, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amountIn, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.fee) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sqrtPriceLimitX96, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.tokenIn, + out, + ); + ::encode_topic_preimage( + &rust.tokenOut, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amountIn, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage(&rust.fee, out); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sqrtPriceLimitX96, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct QuoteExactOutputSingleParams { address tokenIn; address tokenOut; uint256 amount; uint24 fee; uint160 sqrtPriceLimitX96; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct QuoteExactOutputSingleParams { + #[allow(missing_docs)] + pub tokenIn: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenOut: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amount: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub fee: alloy_sol_types::private::primitives::aliases::U24, + #[allow(missing_docs)] + pub sqrtPriceLimitX96: alloy_sol_types::private::primitives::aliases::U160, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<24>, + alloy_sol_types::sol_data::Uint<160>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U24, + alloy_sol_types::private::primitives::aliases::U160, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: QuoteExactOutputSingleParams) -> Self { + ( + value.tokenIn, + value.tokenOut, + value.amount, + value.fee, + value.sqrtPriceLimitX96, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for QuoteExactOutputSingleParams { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenIn: tuple.0, + tokenOut: tuple.1, + amount: tuple.2, + fee: tuple.3, + sqrtPriceLimitX96: tuple.4, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for QuoteExactOutputSingleParams { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for QuoteExactOutputSingleParams { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.tokenIn, + ), + ::tokenize( + &self.tokenOut, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amount, + ), + as alloy_sol_types::SolType>::tokenize( + &self.fee, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceLimitX96, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for QuoteExactOutputSingleParams { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for QuoteExactOutputSingleParams { + const NAME: &'static str = "QuoteExactOutputSingleParams"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "QuoteExactOutputSingleParams(address tokenIn,address tokenOut,uint256 \ + amount,uint24 fee,uint160 sqrtPriceLimitX96)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.tokenIn, + ) + .0, + ::eip712_data_word( + &self.tokenOut, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amount) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.fee) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.sqrtPriceLimitX96, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for QuoteExactOutputSingleParams { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.tokenIn, + ) + + ::topic_preimage_length( + &rust.tokenOut, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amount, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.fee) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sqrtPriceLimitX96, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.tokenIn, + out, + ); + ::encode_topic_preimage( + &rust.tokenOut, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amount, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage(&rust.fee, out); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sqrtPriceLimitX96, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IQuoterV2`](self) contract instance. + + See the [wrapper's documentation](`IQuoterV2Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IQuoterV2Instance { + IQuoterV2Instance::::new(address, __provider) + } + /**A [`IQuoterV2`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IQuoterV2`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IQuoterV2Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IQuoterV2Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IQuoterV2Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IQuoterV2Instance + { + /**Creates a new wrapper around an on-chain [`IQuoterV2`](self) contract instance. + + See the [wrapper's documentation](`IQuoterV2Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IQuoterV2Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IQuoterV2Instance { + IQuoterV2Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IQuoterV2Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IQuoterV2Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library IQuoterV2 { + struct QuoteExactInputSingleParams { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + struct QuoteExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint256 amount; + uint24 fee; + uint160 sqrtPriceLimitX96; + } +} + +interface UniswapV3QuoterV2 { + constructor(address _factory, address _WETH9); + + function WETH9() external view returns (address); + function factory() external view returns (address); + function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate); + function quoteExactInputSingle(IQuoterV2.QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate); + function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate); + function quoteExactOutputSingle(IQuoterV2.QuoteExactOutputSingleParams memory params) external returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_factory", + "type": "address", + "internalType": "address" + }, + { + "name": "_WETH9", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "WETH9", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "factory", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "quoteExactInput", + "inputs": [ + { + "name": "path", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "amountIn", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sqrtPriceX96AfterList", + "type": "uint160[]", + "internalType": "uint160[]" + }, + { + "name": "initializedTicksCrossedList", + "type": "uint32[]", + "internalType": "uint32[]" + }, + { + "name": "gasEstimate", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "quoteExactInputSingle", + "inputs": [ + { + "name": "params", + "type": "tuple", + "internalType": "struct IQuoterV2.QuoteExactInputSingleParams", + "components": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "address" + }, + { + "name": "amountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "fee", + "type": "uint24", + "internalType": "uint24" + }, + { + "name": "sqrtPriceLimitX96", + "type": "uint160", + "internalType": "uint160" + } + ] + } + ], + "outputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sqrtPriceX96After", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "initializedTicksCrossed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "gasEstimate", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "quoteExactOutput", + "inputs": [ + { + "name": "path", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "amountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sqrtPriceX96AfterList", + "type": "uint160[]", + "internalType": "uint160[]" + }, + { + "name": "initializedTicksCrossedList", + "type": "uint32[]", + "internalType": "uint32[]" + }, + { + "name": "gasEstimate", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "quoteExactOutputSingle", + "inputs": [ + { + "name": "params", + "type": "tuple", + "internalType": "struct IQuoterV2.QuoteExactOutputSingleParams", + "components": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "fee", + "type": "uint24", + "internalType": "uint24" + }, + { + "name": "sqrtPriceLimitX96", + "type": "uint160", + "internalType": "uint160" + } + ] + } + ], + "outputs": [ + { + "name": "amountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sqrtPriceX96After", + "type": "uint160", + "internalType": "uint160" + }, + { + "name": "initializedTicksCrossed", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "gasEstimate", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod UniswapV3QuoterV2 { + use {super::*, alloy_sol_types}; + /**Constructor`. + ```solidity + constructor(address _factory, address _WETH9); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct constructorCall { + #[allow(missing_docs)] + pub _factory: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _WETH9: alloy_sol_types::private::Address, + } + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: constructorCall) -> Self { + (value._factory, value._WETH9) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for constructorCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _factory: tuple.0, + _WETH9: tuple.1, + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolConstructor for constructorCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._factory, + ), + ::tokenize( + &self._WETH9, + ), + ) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `WETH9()` and selector `0x4aa4a4fc`. + ```solidity + function WETH9() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETH9Call; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`WETH9()`](WETH9Call) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct WETH9Return { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETH9Call) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETH9Call { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: WETH9Return) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for WETH9Return { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for WETH9Call { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [74u8, 164u8, 164u8, 252u8]; + const SIGNATURE: &'static str = "WETH9()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: WETH9Return = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: WETH9Return = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `factory()` and selector `0xc45a0155`. + ```solidity + function factory() external view returns (address); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`factory()`](factoryCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct factoryReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: factoryReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for factoryReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for factoryCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::Address; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [196u8, 90u8, 1u8, 85u8]; + const SIGNATURE: &'static str = "factory()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: factoryReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: factoryReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quoteExactInput(bytes,uint256)` and selector `0xcdca1753`. + ```solidity + function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactInputCall { + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub amountIn: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quoteExactInput(bytes,uint256)`](quoteExactInputCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactInputReturn { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub sqrtPriceX96AfterList: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub initializedTicksCrossedList: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub gasEstimate: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Bytes, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactInputCall) -> Self { + (value.path, value.amountIn) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactInputCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + path: tuple.0, + amountIn: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactInputReturn) -> Self { + ( + value.amountOut, + value.sqrtPriceX96AfterList, + value.initializedTicksCrossedList, + value.gasEstimate, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactInputReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + sqrtPriceX96AfterList: tuple.1, + initializedTicksCrossedList: tuple.2, + gasEstimate: tuple.3, + } + } + } + } + impl quoteExactInputReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountOut), + , + > as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceX96AfterList, + ), + , + > as alloy_sol_types::SolType>::tokenize( + &self.initializedTicksCrossedList, + ), + as alloy_sol_types::SolType>::tokenize(&self.gasEstimate), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteExactInputCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = quoteExactInputReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [205u8, 202u8, 23u8, 83u8]; + const SIGNATURE: &'static str = "quoteExactInput(bytes,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.path, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountIn, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + quoteExactInputReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quoteExactInputSingle((address,address,uint256,uint24,uint160))` and selector `0xc6a5026a`. + ```solidity + function quoteExactInputSingle(IQuoterV2.QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactInputSingleCall { + #[allow(missing_docs)] + pub params: ::RustType, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quoteExactInputSingle((address,address,uint256,uint24, + /// uint160))`](quoteExactInputSingleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactInputSingleReturn { + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub sqrtPriceX96After: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub initializedTicksCrossed: u32, + #[allow(missing_docs)] + pub gasEstimate: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (IQuoterV2::QuoteExactInputSingleParams,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactInputSingleCall) -> Self { + (value.params,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactInputSingleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { params: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U160, + u32, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactInputSingleReturn) -> Self { + ( + value.amountOut, + value.sqrtPriceX96After, + value.initializedTicksCrossed, + value.gasEstimate, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactInputSingleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountOut: tuple.0, + sqrtPriceX96After: tuple.1, + initializedTicksCrossed: tuple.2, + gasEstimate: tuple.3, + } + } + } + } + impl quoteExactInputSingleReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> + { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountOut, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceX96After, + ), + as alloy_sol_types::SolType>::tokenize( + &self.initializedTicksCrossed, + ), + as alloy_sol_types::SolType>::tokenize( + &self.gasEstimate, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteExactInputSingleCall { + type Parameters<'a> = (IQuoterV2::QuoteExactInputSingleParams,); + type Return = quoteExactInputSingleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [198u8, 165u8, 2u8, 106u8]; + const SIGNATURE: &'static str = + "quoteExactInputSingle((address,address,uint256,uint24,uint160))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.params, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + quoteExactInputSingleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quoteExactOutput(bytes,uint256)` and selector `0x2f80bb1d`. + ```solidity + function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactOutputCall { + #[allow(missing_docs)] + pub path: alloy_sol_types::private::Bytes, + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quoteExactOutput(bytes,uint256)`](quoteExactOutputCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactOutputReturn { + #[allow(missing_docs)] + pub amountIn: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub sqrtPriceX96AfterList: + alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub initializedTicksCrossedList: alloy_sol_types::private::Vec, + #[allow(missing_docs)] + pub gasEstimate: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Bytes, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactOutputCall) -> Self { + (value.path, value.amountOut) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactOutputCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + path: tuple.0, + amountOut: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::Vec, + alloy_sol_types::private::Vec, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactOutputReturn) -> Self { + ( + value.amountIn, + value.sqrtPriceX96AfterList, + value.initializedTicksCrossedList, + value.gasEstimate, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactOutputReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountIn: tuple.0, + sqrtPriceX96AfterList: tuple.1, + initializedTicksCrossedList: tuple.2, + gasEstimate: tuple.3, + } + } + } + } + impl quoteExactOutputReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.amountIn), + , + > as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceX96AfterList, + ), + , + > as alloy_sol_types::SolType>::tokenize( + &self.initializedTicksCrossedList, + ), + as alloy_sol_types::SolType>::tokenize(&self.gasEstimate), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteExactOutputCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Bytes, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = quoteExactOutputReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Array>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [47u8, 128u8, 187u8, 29u8]; + const SIGNATURE: &'static str = "quoteExactOutput(bytes,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.path, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountOut, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + quoteExactOutputReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `quoteExactOutputSingle((address,address,uint256,uint24,uint160))` and selector `0xbd21704a`. + ```solidity + function quoteExactOutputSingle(IQuoterV2.QuoteExactOutputSingleParams memory params) external returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactOutputSingleCall { + #[allow(missing_docs)] + pub params: ::RustType, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`quoteExactOutputSingle((address,address,uint256,uint24, + /// uint160))`](quoteExactOutputSingleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct quoteExactOutputSingleReturn { + #[allow(missing_docs)] + pub amountIn: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub sqrtPriceX96After: alloy_sol_types::private::primitives::aliases::U160, + #[allow(missing_docs)] + pub initializedTicksCrossed: u32, + #[allow(missing_docs)] + pub gasEstimate: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (IQuoterV2::QuoteExactOutputSingleParams,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactOutputSingleCall) -> Self { + (value.params,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactOutputSingleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { params: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U160, + u32, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: quoteExactOutputSingleReturn) -> Self { + ( + value.amountIn, + value.sqrtPriceX96After, + value.initializedTicksCrossed, + value.gasEstimate, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for quoteExactOutputSingleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + amountIn: tuple.0, + sqrtPriceX96After: tuple.1, + initializedTicksCrossed: tuple.2, + gasEstimate: tuple.3, + } + } + } + } + impl quoteExactOutputSingleReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> + { + ( + as alloy_sol_types::SolType>::tokenize( + &self.amountIn, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceX96After, + ), + as alloy_sol_types::SolType>::tokenize( + &self.initializedTicksCrossed, + ), + as alloy_sol_types::SolType>::tokenize( + &self.gasEstimate, + ), + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for quoteExactOutputSingleCall { + type Parameters<'a> = (IQuoterV2::QuoteExactOutputSingleParams,); + type Return = quoteExactOutputSingleReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = ( + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<160>, + alloy_sol_types::sol_data::Uint<32>, + alloy_sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [189u8, 33u8, 112u8, 74u8]; + const SIGNATURE: &'static str = + "quoteExactOutputSingle((address,address,uint256,uint24,uint160))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.params, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + quoteExactOutputSingleReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`UniswapV3QuoterV2`](self) function calls. + #[derive(Clone)] + pub enum UniswapV3QuoterV2Calls { + #[allow(missing_docs)] + WETH9(WETH9Call), + #[allow(missing_docs)] + factory(factoryCall), + #[allow(missing_docs)] + quoteExactInput(quoteExactInputCall), + #[allow(missing_docs)] + quoteExactInputSingle(quoteExactInputSingleCall), + #[allow(missing_docs)] + quoteExactOutput(quoteExactOutputCall), + #[allow(missing_docs)] + quoteExactOutputSingle(quoteExactOutputSingleCall), + } + impl UniswapV3QuoterV2Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [47u8, 128u8, 187u8, 29u8], + [74u8, 164u8, 164u8, 252u8], + [189u8, 33u8, 112u8, 74u8], + [196u8, 90u8, 1u8, 85u8], + [198u8, 165u8, 2u8, 106u8], + [205u8, 202u8, 23u8, 83u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(quoteExactOutput), + ::core::stringify!(WETH9), + ::core::stringify!(quoteExactOutputSingle), + ::core::stringify!(factory), + ::core::stringify!(quoteExactInputSingle), + ::core::stringify!(quoteExactInput), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for UniswapV3QuoterV2Calls { + const COUNT: usize = 6usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "UniswapV3QuoterV2Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::WETH9(_) => ::SELECTOR, + Self::factory(_) => ::SELECTOR, + Self::quoteExactInput(_) => { + ::SELECTOR + } + Self::quoteExactInputSingle(_) => { + ::SELECTOR + } + Self::quoteExactOutput(_) => { + ::SELECTOR + } + Self::quoteExactOutputSingle(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = + &[ + { + fn quoteExactOutput( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(UniswapV3QuoterV2Calls::quoteExactOutput) + } + quoteExactOutput + }, + { + fn WETH9(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3QuoterV2Calls::WETH9) + } + WETH9 + }, + { + fn quoteExactOutputSingle( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw( + data, + ) + .map(UniswapV3QuoterV2Calls::quoteExactOutputSingle) + } + quoteExactOutputSingle + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3QuoterV2Calls::factory) + } + factory + }, + { + fn quoteExactInputSingle( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw( + data, + ) + .map(UniswapV3QuoterV2Calls::quoteExactInputSingle) + } + quoteExactInputSingle + }, + { + fn quoteExactInput( + data: &[u8], + ) -> alloy_sol_types::Result + { + ::abi_decode_raw(data) + .map(UniswapV3QuoterV2Calls::quoteExactInput) + } + quoteExactInput + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + UniswapV3QuoterV2Calls, + >] = &[ + { + fn quoteExactOutput( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV3QuoterV2Calls::quoteExactOutput) + } + quoteExactOutput + }, + { + fn WETH9(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3QuoterV2Calls::WETH9) + } + WETH9 + }, + { + fn quoteExactOutputSingle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV3QuoterV2Calls::quoteExactOutputSingle) + } + quoteExactOutputSingle + }, + { + fn factory(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(UniswapV3QuoterV2Calls::factory) + } + factory + }, + { + fn quoteExactInputSingle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV3QuoterV2Calls::quoteExactInputSingle) + } + quoteExactInputSingle + }, + { + fn quoteExactInput( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV3QuoterV2Calls::quoteExactInput) + } + quoteExactInput + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::WETH9(inner) => { + ::abi_encoded_size(inner) + } + Self::factory(inner) => { + ::abi_encoded_size(inner) + } + Self::quoteExactInput(inner) => { + ::abi_encoded_size(inner) + } + Self::quoteExactInputSingle(inner) => { + ::abi_encoded_size(inner) + } + Self::quoteExactOutput(inner) => { + ::abi_encoded_size(inner) + } + Self::quoteExactOutputSingle(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::WETH9(inner) => { + ::abi_encode_raw(inner, out) + } + Self::factory(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quoteExactInput(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quoteExactInputSingle(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + Self::quoteExactOutput(inner) => { + ::abi_encode_raw(inner, out) + } + Self::quoteExactOutputSingle(inner) => { + ::abi_encode_raw( + inner, out, + ) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`UniswapV3QuoterV2`](self) contract instance. + + See the [wrapper's documentation](`UniswapV3QuoterV2Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> UniswapV3QuoterV2Instance { + UniswapV3QuoterV2Instance::::new(address, __provider) + } + /**A [`UniswapV3QuoterV2`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`UniswapV3QuoterV2`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct UniswapV3QuoterV2Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for UniswapV3QuoterV2Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("UniswapV3QuoterV2Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + UniswapV3QuoterV2Instance + { + /**Creates a new wrapper around an on-chain [`UniswapV3QuoterV2`](self) contract instance. + + See the [wrapper's documentation](`UniswapV3QuoterV2Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl UniswapV3QuoterV2Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> UniswapV3QuoterV2Instance { + UniswapV3QuoterV2Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + UniswapV3QuoterV2Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`WETH9`] function. + pub fn WETH9(&self) -> alloy_contract::SolCallBuilder<&P, WETH9Call, N> { + self.call_builder(&WETH9Call) + } + + ///Creates a new call builder for the [`factory`] function. + pub fn factory(&self) -> alloy_contract::SolCallBuilder<&P, factoryCall, N> { + self.call_builder(&factoryCall) + } + + ///Creates a new call builder for the [`quoteExactInput`] function. + pub fn quoteExactInput( + &self, + path: alloy_sol_types::private::Bytes, + amountIn: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteExactInputCall, N> { + self.call_builder("eExactInputCall { path, amountIn }) + } + + ///Creates a new call builder for the [`quoteExactInputSingle`] + /// function. + pub fn quoteExactInputSingle( + &self, + params: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, quoteExactInputSingleCall, N> { + self.call_builder("eExactInputSingleCall { params }) + } + + ///Creates a new call builder for the [`quoteExactOutput`] function. + pub fn quoteExactOutput( + &self, + path: alloy_sol_types::private::Bytes, + amountOut: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, quoteExactOutputCall, N> { + self.call_builder("eExactOutputCall { path, amountOut }) + } + + ///Creates a new call builder for the [`quoteExactOutputSingle`] + /// function. + pub fn quoteExactOutputSingle( + &self, + params: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, quoteExactOutputSingleCall, N> { + self.call_builder("eExactOutputSingleCall { params }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + UniswapV3QuoterV2Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = UniswapV3QuoterV2::UniswapV3QuoterV2Instance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0x78D78E420Da98ad378D7799bE8f4AF69033EB077"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0x7E9cB3499A6cee3baBe5c8a3D328EA7FD36578f4"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0xaa52bB8110fE38D0d2d2AF0B85C3A3eE622CA455"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xbe0F5544EC67e9B3b2D979aaA43f18Fd87E6257F"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x96b572D2d880cf2Fa2563651BD23ADE6f5516652"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x42bE4D6527829FeFA1493e1fb9F3676d2425C3C1"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/uniswapv3swaprouterv2/Cargo.toml b/contracts/generated/contracts-generated/uniswapv3swaprouterv2/Cargo.toml new file mode 100644 index 0000000000..8114568730 --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv3swaprouterv2/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-uniswapv3swaprouterv2" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/uniswapv3swaprouterv2/src/lib.rs b/contracts/generated/contracts-generated/uniswapv3swaprouterv2/src/lib.rs new file mode 100644 index 0000000000..677099792b --- /dev/null +++ b/contracts/generated/contracts-generated/uniswapv3swaprouterv2/src/lib.rs @@ -0,0 +1,1073 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +///Module containing a contract's types and functions. +/** + +```solidity +library IV3SwapRouter { + struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } +} +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IV3SwapRouter { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**```solidity + struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct ExactOutputSingleParams { + #[allow(missing_docs)] + pub tokenIn: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub tokenOut: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub fee: alloy_sol_types::private::primitives::aliases::U24, + #[allow(missing_docs)] + pub recipient: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub amountOut: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub amountInMaximum: alloy_sol_types::private::primitives::aliases::U256, + #[allow(missing_docs)] + pub sqrtPriceLimitX96: alloy_sol_types::private::primitives::aliases::U160, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<24>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<256>, + alloy_sol_types::sol_data::Uint<160>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U24, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U256, + alloy_sol_types::private::primitives::aliases::U160, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: ExactOutputSingleParams) -> Self { + ( + value.tokenIn, + value.tokenOut, + value.fee, + value.recipient, + value.amountOut, + value.amountInMaximum, + value.sqrtPriceLimitX96, + ) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for ExactOutputSingleParams { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + tokenIn: tuple.0, + tokenOut: tuple.1, + fee: tuple.2, + recipient: tuple.3, + amountOut: tuple.4, + amountInMaximum: tuple.5, + sqrtPriceLimitX96: tuple.6, + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolValue for ExactOutputSingleParams { + type SolType = Self; + } + #[automatically_derived] + impl alloy_sol_types::private::SolTypeValue for ExactOutputSingleParams { + #[inline] + fn stv_to_tokens(&self) -> ::Token<'_> { + ( + ::tokenize( + &self.tokenIn, + ), + ::tokenize( + &self.tokenOut, + ), + as alloy_sol_types::SolType>::tokenize( + &self.fee, + ), + ::tokenize( + &self.recipient, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountOut, + ), + as alloy_sol_types::SolType>::tokenize( + &self.amountInMaximum, + ), + as alloy_sol_types::SolType>::tokenize( + &self.sqrtPriceLimitX96, + ), + ) + } + + #[inline] + fn stv_abi_encoded_size(&self) -> usize { + if let Some(size) = ::ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encoded_size(&tuple) + } + + #[inline] + fn stv_eip712_data_word(&self) -> alloy_sol_types::Word { + ::eip712_hash_struct(self) + } + + #[inline] + fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec) { + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_encode_packed_to( + &tuple, out, + ) + } + + #[inline] + fn stv_abi_packed_encoded_size(&self) -> usize { + if let Some(size) = ::PACKED_ENCODED_SIZE { + return size; + } + let tuple = + as ::core::convert::From>::from(self.clone()); + as alloy_sol_types::SolType>::abi_packed_encoded_size( + &tuple, + ) + } + } + #[automatically_derived] + impl alloy_sol_types::SolType for ExactOutputSingleParams { + type RustType = Self; + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::ENCODED_SIZE; + const PACKED_ENCODED_SIZE: Option = + as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE; + const SOL_NAME: &'static str = ::NAME; + + #[inline] + fn valid_token(token: &Self::Token<'_>) -> bool { + as alloy_sol_types::SolType>::valid_token(token) + } + + #[inline] + fn detokenize(token: Self::Token<'_>) -> Self::RustType { + let tuple = as alloy_sol_types::SolType>::detokenize(token); + >>::from(tuple) + } + } + #[automatically_derived] + impl alloy_sol_types::SolStruct for ExactOutputSingleParams { + const NAME: &'static str = "ExactOutputSingleParams"; + + #[inline] + fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> { + alloy_sol_types::private::Cow::Borrowed( + "ExactOutputSingleParams(address tokenIn,address tokenOut,uint24 fee,address \ + recipient,uint256 amountOut,uint256 amountInMaximum,uint160 \ + sqrtPriceLimitX96)", + ) + } + + #[inline] + fn eip712_components() + -> alloy_sol_types::private::Vec> + { + alloy_sol_types::private::Vec::new() + } + + #[inline] + fn eip712_encode_type() -> alloy_sol_types::private::Cow<'static, str> { + ::eip712_root_type() + } + + #[inline] + fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec { + [ + ::eip712_data_word( + &self.tokenIn, + ) + .0, + ::eip712_data_word( + &self.tokenOut, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.fee) + .0, + ::eip712_data_word( + &self.recipient, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word(&self.amountOut) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.amountInMaximum, + ) + .0, + as alloy_sol_types::SolType>::eip712_data_word( + &self.sqrtPriceLimitX96, + ) + .0, + ] + .concat() + } + } + #[automatically_derived] + impl alloy_sol_types::EventTopic for ExactOutputSingleParams { + #[inline] + fn topic_preimage_length(rust: &Self::RustType) -> usize { + 0usize + + ::topic_preimage_length( + &rust.tokenIn, + ) + + ::topic_preimage_length( + &rust.tokenOut, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length(&rust.fee) + + ::topic_preimage_length( + &rust.recipient, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amountOut, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.amountInMaximum, + ) + + as alloy_sol_types::EventTopic>::topic_preimage_length( + &rust.sqrtPriceLimitX96, + ) + } + + #[inline] + fn encode_topic_preimage( + rust: &Self::RustType, + out: &mut alloy_sol_types::private::Vec, + ) { + out.reserve(::topic_preimage_length(rust)); + ::encode_topic_preimage( + &rust.tokenIn, + out, + ); + ::encode_topic_preimage( + &rust.tokenOut, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage(&rust.fee, out); + ::encode_topic_preimage( + &rust.recipient, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amountOut, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.amountInMaximum, + out, + ); + as alloy_sol_types::EventTopic>::encode_topic_preimage( + &rust.sqrtPriceLimitX96, + out, + ); + } + + #[inline] + fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken { + let mut out = alloy_sol_types::private::Vec::new(); + ::encode_topic_preimage(rust, &mut out); + alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out)) + } + } + }; + use alloy_contract; + /**Creates a new wrapper around an on-chain [`IV3SwapRouter`](self) contract instance. + + See the [wrapper's documentation](`IV3SwapRouterInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> IV3SwapRouterInstance { + IV3SwapRouterInstance::::new(address, __provider) + } + /**A [`IV3SwapRouter`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`IV3SwapRouter`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IV3SwapRouterInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IV3SwapRouterInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IV3SwapRouterInstance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + IV3SwapRouterInstance + { + /**Creates a new wrapper around an on-chain [`IV3SwapRouter`](self) contract instance. + + See the [wrapper's documentation](`IV3SwapRouterInstance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IV3SwapRouterInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> IV3SwapRouterInstance { + IV3SwapRouterInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + IV3SwapRouterInstance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + IV3SwapRouterInstance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +/** + +Generated by the following Solidity interface... +```solidity +library IV3SwapRouter { + struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } +} + +interface UniswapV3SwapRouterV2 { + function exactOutputSingle(IV3SwapRouter.ExactOutputSingleParams memory params) external payable returns (uint256 amountIn); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "exactOutputSingle", + "inputs": [ + { + "name": "params", + "type": "tuple", + "internalType": "struct IV3SwapRouter.ExactOutputSingleParams", + "components": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "address" + }, + { + "name": "fee", + "type": "uint24", + "internalType": "uint24" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "amountInMaximum", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sqrtPriceLimitX96", + "type": "uint160", + "internalType": "uint160" + } + ] + } + ], + "outputs": [ + { + "name": "amountIn", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod UniswapV3SwapRouterV2 { + use {super::*, alloy_sol_types}; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))` and selector `0x5023b4df`. + ```solidity + function exactOutputSingle(IV3SwapRouter.ExactOutputSingleParams memory params) external payable returns (uint256 amountIn); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct exactOutputSingleCall { + #[allow(missing_docs)] + pub params: ::RustType, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`exactOutputSingle((address,address,uint24,address,uint256,uint256, + /// uint160))`](exactOutputSingleCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct exactOutputSingleReturn { + #[allow(missing_docs)] + pub amountIn: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (IV3SwapRouter::ExactOutputSingleParams,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = + (::RustType,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: exactOutputSingleCall) -> Self { + (value.params,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for exactOutputSingleCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { params: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: exactOutputSingleReturn) -> Self { + (value.amountIn,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for exactOutputSingleReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { amountIn: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for exactOutputSingleCall { + type Parameters<'a> = (IV3SwapRouter::ExactOutputSingleParams,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [80u8, 35u8, 180u8, 223u8]; + const SIGNATURE: &'static str = + "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint160))"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.params, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: exactOutputSingleReturn = r.into(); + r.amountIn + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: exactOutputSingleReturn = r.into(); + r.amountIn + }) + } + } + }; + ///Container for all the [`UniswapV3SwapRouterV2`](self) function calls. + #[derive(Clone)] + pub enum UniswapV3SwapRouterV2Calls { + #[allow(missing_docs)] + exactOutputSingle(exactOutputSingleCall), + } + impl UniswapV3SwapRouterV2Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[80u8, 35u8, 180u8, 223u8]]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = + &[::SIGNATURE]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[::core::stringify!(exactOutputSingle)]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for UniswapV3SwapRouterV2Calls { + const COUNT: usize = 1usize; + const MIN_DATA_LENGTH: usize = 224usize; + const NAME: &'static str = "UniswapV3SwapRouterV2Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::exactOutputSingle(_) => { + ::SELECTOR + } + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) + -> alloy_sol_types::Result] = &[{ + fn exactOutputSingle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(UniswapV3SwapRouterV2Calls::exactOutputSingle) + } + exactOutputSingle + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result< + UniswapV3SwapRouterV2Calls, + >] = &[{ + fn exactOutputSingle( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(UniswapV3SwapRouterV2Calls::exactOutputSingle) + } + exactOutputSingle + }]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::exactOutputSingle(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::exactOutputSingle(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`UniswapV3SwapRouterV2`](self) contract instance. + + See the [wrapper's documentation](`UniswapV3SwapRouterV2Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> UniswapV3SwapRouterV2Instance { + UniswapV3SwapRouterV2Instance::::new(address, __provider) + } + /**A [`UniswapV3SwapRouterV2`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`UniswapV3SwapRouterV2`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct UniswapV3SwapRouterV2Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for UniswapV3SwapRouterV2Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("UniswapV3SwapRouterV2Instance") + .field(&self.address) + .finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + UniswapV3SwapRouterV2Instance + { + /**Creates a new wrapper around an on-chain [`UniswapV3SwapRouterV2`](self) contract instance. + + See the [wrapper's documentation](`UniswapV3SwapRouterV2Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl UniswapV3SwapRouterV2Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> UniswapV3SwapRouterV2Instance { + UniswapV3SwapRouterV2Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + UniswapV3SwapRouterV2Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`exactOutputSingle`] function. + pub fn exactOutputSingle( + &self, + params: ::RustType, + ) -> alloy_contract::SolCallBuilder<&P, exactOutputSingleCall, N> { + self.call_builder(&exactOutputSingleCall { params }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + UniswapV3SwapRouterV2Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} +pub type Instance = + UniswapV3SwapRouterV2::UniswapV3SwapRouterV2Instance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xc6D25285D5C5b62b7ca26D6092751A145D50e9Be"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x2626664c2603336E57B271c5C0b26F421741e481"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x807F4E281B7A3B324825C64ca53c69F0b418dE40"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xbb00FF08d01D300023C629E8fFfFcb65A5a578cE"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x177778F19E89dD1012BdBe603F144088A95C4B53"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/contracts-generated/weth9/Cargo.toml b/contracts/generated/contracts-generated/weth9/Cargo.toml new file mode 100644 index 0000000000..2bd1f8db76 --- /dev/null +++ b/contracts/generated/contracts-generated/weth9/Cargo.toml @@ -0,0 +1,19 @@ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = "cow-contract-weth9" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true diff --git a/contracts/generated/contracts-generated/weth9/src/lib.rs b/contracts/generated/contracts-generated/weth9/src/lib.rs new file mode 100644 index 0000000000..dc0b098bb5 --- /dev/null +++ b/contracts/generated/contracts-generated/weth9/src/lib.rs @@ -0,0 +1,3114 @@ +#![allow( + unused_imports, + unused_attributes, + clippy::all, + rustdoc::all, + non_snake_case +)] +//! Auto-generated contract bindings. Do not edit. +/** + +Generated by the following Solidity interface... +```solidity +interface WETH9 { + event Approval(address indexed src, address indexed guy, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + fallback() external payable; + + function allowance(address, address) external view returns (uint256); + function approve(address guy, uint256 wad) external returns (bool); + function balanceOf(address) external view returns (uint256); + function decimals() external view returns (uint8); + function deposit() external payable; + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function transfer(address dst, uint256 wad) external returns (bool); + function transferFrom(address src, address dst, uint256 wad) external returns (bool); + function withdraw(uint256 wad) external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "fallback", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "guy", + "type": "address" + }, + { + "name": "wad", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "deposit", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "wad", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "wad", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdraw", + "inputs": [ + { + "name": "wad", + "type": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "src", + "type": "address", + "indexed": true + }, + { + "name": "guy", + "type": "address", + "indexed": true + }, + { + "name": "wad", + "type": "uint256", + "indexed": false + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Deposit", + "inputs": [ + { + "name": "dst", + "type": "address", + "indexed": true + }, + { + "name": "wad", + "type": "uint256", + "indexed": false + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "src", + "type": "address", + "indexed": true + }, + { + "name": "dst", + "type": "address", + "indexed": true + }, + { + "name": "wad", + "type": "uint256", + "indexed": false + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Withdrawal", + "inputs": [ + { + "name": "src", + "type": "address", + "indexed": true + }, + { + "name": "wad", + "type": "uint256", + "indexed": false + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod WETH9 { + use {super::*, alloy_sol_types}; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x60806040526040805190810160405280600d81526020017f57726170706564204574686572000000000000000000000000000000000000008152506000908051906020019061004f9291906100ca565b506040805190810160405280600481526020017f57455448000000000000000000000000000000000000000000000000000000008152506001908051906020019061009b9291906100ca565b506012600260006101000a81548160ff021916908360ff1602179055503480156100c457600080fd5b5061016f565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061010b57805160ff1916838001178555610139565b82800160010185558215610139579182015b8281111561013857825182559160200191906001019061011d565b5b509050610146919061014a565b5090565b61016c91905b80821115610168576000816000905550600101610150565b5090565b90565b610cd88061017e6000396000f3fe6080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b9578063095ea7b31461014957806318160ddd146101bc57806323b872dd146101e75780632e1a7d4d1461027a578063313ce567146102b557806370a08231146102e657806395d89b411461034b578063a9059cbb146103db578063d0e30db01461044e578063dd62ed3e14610458575b6100b76104dd565b005b3480156100c557600080fd5b506100ce61057a565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010e5780820151818401526020810190506100f3565b50505050905090810190601f16801561013b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015557600080fd5b506101a26004803603604081101561016c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610618565b604051808215151515815260200191505060405180910390f35b3480156101c857600080fd5b506101d161070a565b6040518082815260200191505060405180910390f35b3480156101f357600080fd5b506102606004803603606081101561020a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610729565b604051808215151515815260200191505060405180910390f35b34801561028657600080fd5b506102b36004803603602081101561029d57600080fd5b8101908080359060200190929190505050610a76565b005b3480156102c157600080fd5b506102ca610ba9565b604051808260ff1660ff16815260200191505060405180910390f35b3480156102f257600080fd5b506103356004803603602081101561030957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bbc565b6040518082815260200191505060405180910390f35b34801561035757600080fd5b50610360610bd4565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103a0578082015181840152602081019050610385565b50505050905090810190601f1680156103cd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103e757600080fd5b50610434600480360360408110156103fe57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c72565b604051808215151515815260200191505060405180910390f35b6104566104dd565b005b34801561046457600080fd5b506104c76004803603604081101561047b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c87565b6040518082815260200191505060405180910390f35b34600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a2565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106105780601f106105e557610100808354040283529160200191610610565b820191906000526020600020905b8154815290600101906020018083116105f357829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b600081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561077957600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415801561085157507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b1561096c5781600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156108e157600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b81600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610ac457600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610b57573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040518082815260200191505060405180910390a250565b600260009054906101000a900460ff1681565b60036020528060005260406000206000915090505481565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c6a5780601f10610c3f57610100808354040283529160200191610c6a565b820191906000526020600020905b815481529060010190602001808311610c4d57829003601f168201915b505050505081565b6000610c7f338484610729565b905092915050565b600460205281600052604060002060205280600052604060002060009150915050548156fea165627a7a7230582089f5a509ec49def9e0fd69996f7ea7cb42adb14f134f71ea034b8ce39df0a1e00029 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R`@\x80Q\x90\x81\x01`@R\x80`\r\x81R` \x01\x7FWrapped Ether\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP`\0\x90\x80Q\x90` \x01\x90a\0O\x92\x91\x90a\0\xCAV[P`@\x80Q\x90\x81\x01`@R\x80`\x04\x81R` \x01\x7FWETH\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP`\x01\x90\x80Q\x90` \x01\x90a\0\x9B\x92\x91\x90a\0\xCAV[P`\x12`\x02`\0a\x01\0\n\x81T\x81`\xFF\x02\x19\x16\x90\x83`\xFF\x16\x02\x17\x90UP4\x80\x15a\0\xC4W`\0\x80\xFD[Pa\x01oV[\x82\x80T`\x01\x81`\x01\x16\x15a\x01\0\x02\x03\x16`\x02\x90\x04\x90`\0R` `\0 \x90`\x1F\x01` \x90\x04\x81\x01\x92\x82`\x1F\x10a\x01\x0BW\x80Q`\xFF\x19\x16\x83\x80\x01\x17\x85Ua\x019V[\x82\x80\x01`\x01\x01\x85U\x82\x15a\x019W\x91\x82\x01[\x82\x81\x11\x15a\x018W\x82Q\x82U\x91` \x01\x91\x90`\x01\x01\x90a\x01\x1DV[[P\x90Pa\x01F\x91\x90a\x01JV[P\x90V[a\x01l\x91\x90[\x80\x82\x11\x15a\x01hW`\0\x81`\0\x90UP`\x01\x01a\x01PV[P\x90V[\x90V[a\x0C\xD8\x80a\x01~`\09`\0\xF3\xFE`\x80`@R`\x046\x10a\0\xAFW`\x005|\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x04c\xFF\xFF\xFF\xFF\x16\x80c\x06\xFD\xDE\x03\x14a\0\xB9W\x80c\t^\xA7\xB3\x14a\x01IW\x80c\x18\x16\r\xDD\x14a\x01\xBCW\x80c#\xB8r\xDD\x14a\x01\xE7W\x80c.\x1A}M\x14a\x02zW\x80c1<\xE5g\x14a\x02\xB5W\x80cp\xA0\x821\x14a\x02\xE6W\x80c\x95\xD8\x9BA\x14a\x03KW\x80c\xA9\x05\x9C\xBB\x14a\x03\xDBW\x80c\xD0\xE3\r\xB0\x14a\x04NW\x80c\xDDb\xED>\x14a\x04XW[a\0\xB7a\x04\xDDV[\0[4\x80\x15a\0\xC5W`\0\x80\xFD[Pa\0\xCEa\x05zV[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x01\x0EW\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\0\xF3V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x01;W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x01UW`\0\x80\xFD[Pa\x01\xA2`\x04\x806\x03`@\x81\x10\x15a\x01lW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x06\x18V[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x01\xC8W`\0\x80\xFD[Pa\x01\xD1a\x07\nV[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x01\xF3W`\0\x80\xFD[Pa\x02``\x04\x806\x03``\x81\x10\x15a\x02\nW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x07)V[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x02\x86W`\0\x80\xFD[Pa\x02\xB3`\x04\x806\x03` \x81\x10\x15a\x02\x9DW`\0\x80\xFD[\x81\x01\x90\x80\x805\x90` \x01\x90\x92\x91\x90PPPa\nvV[\0[4\x80\x15a\x02\xC1W`\0\x80\xFD[Pa\x02\xCAa\x0B\xA9V[`@Q\x80\x82`\xFF\x16`\xFF\x16\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x02\xF2W`\0\x80\xFD[Pa\x035`\x04\x806\x03` \x81\x10\x15a\x03\tW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa\x0B\xBCV[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x03WW`\0\x80\xFD[Pa\x03`a\x0B\xD4V[`@Q\x80\x80` \x01\x82\x81\x03\x82R\x83\x81\x81Q\x81R` \x01\x91P\x80Q\x90` \x01\x90\x80\x83\x83`\0[\x83\x81\x10\x15a\x03\xA0W\x80\x82\x01Q\x81\x84\x01R` \x81\x01\x90Pa\x03\x85V[PPPP\x90P\x90\x81\x01\x90`\x1F\x16\x80\x15a\x03\xCDW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\0\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xF3[4\x80\x15a\x03\xE7W`\0\x80\xFD[Pa\x044`\x04\x806\x03`@\x81\x10\x15a\x03\xFEW`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805\x90` \x01\x90\x92\x91\x90PPPa\x0CrV[`@Q\x80\x82\x15\x15\x15\x15\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[a\x04Va\x04\xDDV[\0[4\x80\x15a\x04dW`\0\x80\xFD[Pa\x04\xC7`\x04\x806\x03`@\x81\x10\x15a\x04{W`\0\x80\xFD[\x81\x01\x90\x80\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90\x805s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90` \x01\x90\x92\x91\x90PPPa\x0C\x87V[`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xF3[4`\x03`\x003s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01\x90\x81R` \x01`\0 `\0\x82\x82T\x01\x92PP\x81\x90UP3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\xE1\xFF\xFC\xC4\x92=\x04\xB5Y\xF4\xD2\x9A\x8B\xFCl\xDA\x04\xEB[\r=`\0\xFD[P3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x7F\xCFS,\x15\xF0\xA6\xDB\x0B\xD6\xD0\xE08\xBE\xA7\x1D0\xD8\x08\xC7\xD9\x8C\xB3\xBFrh\xA9[\xF5\x08\x1Be\x82`@Q\x80\x82\x81R` \x01\x91PP`@Q\x80\x91\x03\x90\xA2PV[`\x02`\0\x90T\x90a\x01\0\n\x90\x04`\xFF\x16\x81V[`\x03` R\x80`\0R`@`\0 `\0\x91P\x90PT\x81V[`\x01\x80T`\x01\x81`\x01\x16\x15a\x01\0\x02\x03\x16`\x02\x90\x04\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T`\x01\x81`\x01\x16\x15a\x01\0\x02\x03\x16`\x02\x90\x04\x80\x15a\x0CjW\x80`\x1F\x10a\x0C?Wa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x0CjV[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x0CMW\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x81V[`\0a\x0C\x7F3\x84\x84a\x07)V[\x90P\x92\x91PPV[`\x04` R\x81`\0R`@`\0 ` R\x80`\0R`@`\0 `\0\x91P\x91PPT\x81V\xFE\xA1ebzzr0X \x89\xF5\xA5\t\xECI\xDE\xF9\xE0\xFDi\x99o~\xA7\xCBB\xAD\xB1O\x13Oq\xEA\x03K\x8C\xE3\x9D\xF0\xA1\xE0\0)", + ); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. + ```solidity + event Approval(address indexed src, address indexed guy, uint256 wad); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub src: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub guy: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, + 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + src: topics.1, + guy: topics.2, + wad: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.src.clone(), + self.guy.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.src, + ); + out[2usize] = ::encode_topic( + &self.guy, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Deposit(address,uint256)` and selector `0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c`. + ```solidity + event Deposit(address indexed dst, uint256 wad); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Deposit { + #[allow(missing_docs)] + pub dst: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Deposit { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Deposit(address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 225u8, 255u8, 252u8, 196u8, 146u8, 61u8, 4u8, 181u8, 89u8, 244u8, 210u8, 154u8, + 139u8, 252u8, 108u8, 218u8, 4u8, 235u8, 91u8, 13u8, 60u8, 70u8, 7u8, 81u8, + 194u8, 64u8, 44u8, 92u8, 92u8, 201u8, 16u8, 156u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + dst: topics.1, + wad: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.dst.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.dst, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Deposit { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Deposit> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Deposit) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. + ```solidity + event Transfer(address indexed src, address indexed dst, uint256 wad); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub src: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub dst: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, + 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, + 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + src: topics.1, + dst: topics.2, + wad: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + ( + Self::SIGNATURE_HASH.into(), + self.src.clone(), + self.dst.clone(), + ) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.src, + ); + out[2usize] = ::encode_topic( + &self.dst, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Withdrawal(address,uint256)` and selector `0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65`. + ```solidity + event Withdrawal(address indexed src, uint256 wad); + ```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Withdrawal { + #[allow(missing_docs)] + pub src: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Withdrawal { + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type DataTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy_sol_types::sol_data::Address, + ); + + const ANONYMOUS: bool = false; + const SIGNATURE: &'static str = "Withdrawal(address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = + alloy_sol_types::private::B256::new([ + 127u8, 207u8, 83u8, 44u8, 21u8, 240u8, 166u8, 219u8, 11u8, 214u8, 208u8, 224u8, + 56u8, 190u8, 167u8, 29u8, 48u8, 216u8, 8u8, 199u8, 217u8, 140u8, 179u8, 191u8, + 114u8, 104u8, 169u8, 91u8, 245u8, 8u8, 27u8, 101u8, + ]); + + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + src: topics.1, + wad: data.0, + } + } + + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err(alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + )); + } + Ok(()) + } + + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.src.clone()) + } + + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken(Self::SIGNATURE_HASH); + out[1usize] = ::encode_topic( + &self.src, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Withdrawal { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Withdrawal> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Withdrawal) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. + ```solidity + function allowance(address, address) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub _1: alloy_sol_types::private::Address, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value._0, value._1) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + _0: tuple.0, + _1: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + ); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + const SIGNATURE: &'static str = "allowance(address,address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self._0, + ), + ::tokenize( + &self._1, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: allowanceReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. + ```solidity + function approve(address guy, uint256 wad) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub guy: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.guy, value.wad) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + guy: tuple.0, + wad: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + const SIGNATURE: &'static str = "approve(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.guy, + ), + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: approveReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. + ```solidity + function balanceOf(address) external view returns (uint256); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall(pub alloy_sol_types::private::Address); + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self(tuple.0) + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Address,); + type Return = alloy_sol_types::private::primitives::aliases::U256; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + const SIGNATURE: &'static str = "balanceOf(address)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.0, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + ret, + ), + ) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: balanceOfReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `decimals()` and selector `0x313ce567`. + ```solidity + function decimals() external view returns (uint8); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`decimals()`](decimalsCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct decimalsReturn { + #[allow(missing_docs)] + pub _0: u8, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (u8,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: decimalsReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for decimalsReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for decimalsCall { + type Parameters<'a> = (); + type Return = u8; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Uint<8>,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [49u8, 60u8, 229u8, 103u8]; + const SIGNATURE: &'static str = "decimals()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( as alloy_sol_types::SolType>::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: decimalsReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: decimalsReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `deposit()` and selector `0xd0e30db0`. + ```solidity + function deposit() external payable; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct depositCall; + ///Container type for the return parameters of the + /// [`deposit()`](depositCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct depositReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: depositCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for depositCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: depositReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for depositReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl depositReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for depositCall { + type Parameters<'a> = (); + type Return = depositReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [208u8, 227u8, 13u8, 176u8]; + const SIGNATURE: &'static str = "deposit()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + depositReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `name()` and selector `0x06fdde03`. + ```solidity + function name() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`name()`](nameCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct nameReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: nameReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for nameReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for nameCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [6u8, 253u8, 222u8, 3u8]; + const SIGNATURE: &'static str = "name()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: nameReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: nameReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `symbol()` and selector `0x95d89b41`. + ```solidity + function symbol() external view returns (string memory); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolCall; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`symbol()`](symbolCall) + /// function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct symbolReturn { + #[allow(missing_docs)] + pub _0: alloy_sol_types::private::String, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::String,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::String,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: symbolReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for symbolReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for symbolCall { + type Parameters<'a> = (); + type Return = alloy_sol_types::private::String; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::String,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [149u8, 216u8, 155u8, 65u8]; + const SIGNATURE: &'static str = "symbol()"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: symbolReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: symbolReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. + ```solidity + function transfer(address dst, uint256 wad) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub dst: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.dst, value.wad) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + dst: tuple.0, + wad: tuple.1, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.dst, + ), + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. + ```solidity + function transferFrom(address src, address dst, uint256 wad) external returns (bool); + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub src: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub dst: alloy_sol_types::private::Address, + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the + /// [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy_sol_types::private::Address, + alloy_sol_types::private::Address, + alloy_sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.src, value.dst, value.wad) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + src: tuple.0, + dst: tuple.1, + wad: tuple.2, + } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Address, + alloy_sol_types::sol_data::Uint<256>, + ); + type Return = bool; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (alloy_sol_types::sol_data::Bool,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.src, + ), + ::tokenize( + &self.dst, + ), + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + (::tokenize(ret),) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data).map( + |r| { + let r: transferFromReturn = r.into(); + r._0 + }, + ) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `withdraw(uint256)` and selector `0x2e1a7d4d`. + ```solidity + function withdraw(uint256 wad) external; + ```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct withdrawCall { + #[allow(missing_docs)] + pub wad: alloy_sol_types::private::primitives::aliases::U256, + } + ///Container type for the return parameters of the + /// [`withdraw(uint256)`](withdrawCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct withdrawReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy_sol_types; + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (alloy_sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy_sol_types::private::primitives::aliases::U256,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: withdrawCall) -> Self { + (value.wad,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for withdrawCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { wad: tuple.0 } + } + } + } + { + #[doc(hidden)] + #[allow(dead_code)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: withdrawReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for withdrawReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl withdrawReturn { + fn _tokenize(&self) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for withdrawCall { + type Parameters<'a> = (alloy_sol_types::sol_data::Uint<256>,); + type Return = withdrawReturn; + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type ReturnTuple<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + + const SELECTOR: [u8; 4] = [46u8, 26u8, 125u8, 77u8]; + const SIGNATURE: &'static str = "withdraw(uint256)"; + + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + as alloy_sol_types::SolType>::tokenize( + &self.wad, + ), + ) + } + + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + withdrawReturn::_tokenize(ret) + } + + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + + #[inline] + fn abi_decode_returns_validate(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate( + data, + ) + .map(Into::into) + } + } + }; + ///Container for all the [`WETH9`](self) function calls. + #[derive(Clone)] + pub enum WETH9Calls { + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + decimals(decimalsCall), + #[allow(missing_docs)] + deposit(depositCall), + #[allow(missing_docs)] + name(nameCall), + #[allow(missing_docs)] + symbol(symbolCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + #[allow(missing_docs)] + withdraw(withdrawCall), + } + impl WETH9Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [6u8, 253u8, 222u8, 3u8], + [9u8, 94u8, 167u8, 179u8], + [35u8, 184u8, 114u8, 221u8], + [46u8, 26u8, 125u8, 77u8], + [49u8, 60u8, 229u8, 103u8], + [112u8, 160u8, 130u8, 49u8], + [149u8, 216u8, 155u8, 65u8], + [169u8, 5u8, 156u8, 187u8], + [208u8, 227u8, 13u8, 176u8], + [221u8, 98u8, 237u8, 62u8], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(name), + ::core::stringify!(approve), + ::core::stringify!(transferFrom), + ::core::stringify!(withdraw), + ::core::stringify!(decimals), + ::core::stringify!(balanceOf), + ::core::stringify!(symbol), + ::core::stringify!(transfer), + ::core::stringify!(deposit), + ::core::stringify!(allowance), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 4usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 4usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for WETH9Calls { + const COUNT: usize = 10usize; + const MIN_DATA_LENGTH: usize = 0usize; + const NAME: &'static str = "WETH9Calls"; + + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::allowance(_) => ::SELECTOR, + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => ::SELECTOR, + Self::decimals(_) => ::SELECTOR, + Self::deposit(_) => ::SELECTOR, + Self::name(_) => ::SELECTOR, + Self::symbol(_) => ::SELECTOR, + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => ::SELECTOR, + Self::withdraw(_) => ::SELECTOR, + } + } + + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::transferFrom) + } + transferFrom + }, + { + fn withdraw(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::withdraw) + } + withdraw + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::decimals) + } + decimals + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::balanceOf) + } + balanceOf + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::transfer) + } + transfer + }, + { + fn deposit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::deposit) + } + deposit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(WETH9Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_SHIMS[idx](data) + } + + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn name(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::name) + } + name + }, + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::approve) + } + approve + }, + { + fn transferFrom(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(WETH9Calls::transferFrom) + } + transferFrom + }, + { + fn withdraw(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::withdraw) + } + withdraw + }, + { + fn decimals(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::decimals) + } + decimals + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::balanceOf) + } + balanceOf + }, + { + fn symbol(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::symbol) + } + symbol + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::transfer) + } + transfer + }, + { + fn deposit(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::deposit) + } + deposit + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate(data) + .map(WETH9Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err(alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + )); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::decimals(inner) => { + ::abi_encoded_size(inner) + } + Self::deposit(inner) => { + ::abi_encoded_size(inner) + } + Self::name(inner) => { + ::abi_encoded_size(inner) + } + Self::symbol(inner) => { + ::abi_encoded_size(inner) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size(inner) + } + Self::withdraw(inner) => { + ::abi_encoded_size(inner) + } + } + } + + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::allowance(inner) => { + ::abi_encode_raw(inner, out) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw(inner, out) + } + Self::decimals(inner) => { + ::abi_encode_raw(inner, out) + } + Self::deposit(inner) => { + ::abi_encode_raw(inner, out) + } + Self::name(inner) => { + ::abi_encode_raw(inner, out) + } + Self::symbol(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transfer(inner) => { + ::abi_encode_raw(inner, out) + } + Self::transferFrom(inner) => { + ::abi_encode_raw(inner, out) + } + Self::withdraw(inner) => { + ::abi_encode_raw(inner, out) + } + } + } + } + ///Container for all the [`WETH9`](self) events. + #[derive(Clone, Debug, PartialEq, Eq, Hash)] + pub enum WETH9Events { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + Deposit(Deposit), + #[allow(missing_docs)] + Transfer(Transfer), + #[allow(missing_docs)] + Withdrawal(Withdrawal), + } + impl WETH9Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the + /// variants. No guarantees are made about the order of the + /// selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 127u8, 207u8, 83u8, 44u8, 21u8, 240u8, 166u8, 219u8, 11u8, 214u8, 208u8, 224u8, + 56u8, 190u8, 167u8, 29u8, 48u8, 216u8, 8u8, 199u8, 217u8, 140u8, 179u8, 191u8, + 114u8, 104u8, 169u8, 91u8, 245u8, 8u8, 27u8, 101u8, + ], + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, 66u8, + 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, 41u8, 30u8, 91u8, + 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, 176u8, 104u8, + 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, 196u8, 161u8, 22u8, + 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + [ + 225u8, 255u8, 252u8, 196u8, 146u8, 61u8, 4u8, 181u8, 89u8, 244u8, 210u8, 154u8, + 139u8, 252u8, 108u8, 218u8, 4u8, 235u8, 91u8, 13u8, 60u8, 70u8, 7u8, 81u8, 194u8, + 64u8, 44u8, 92u8, 92u8, 201u8, 16u8, 156u8, + ], + ]; + /// The signatures in the same order as `SELECTORS`. + pub const SIGNATURES: &'static [&'static str] = &[ + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ::SIGNATURE, + ]; + /// The names of the variants in the same order as `SELECTORS`. + pub const VARIANT_NAMES: &'static [&'static str] = &[ + ::core::stringify!(Withdrawal), + ::core::stringify!(Approval), + ::core::stringify!(Transfer), + ::core::stringify!(Deposit), + ]; + + /// Returns the signature for the given selector, if known. + #[inline] + pub fn signature_by_selector( + selector: [u8; 32usize], + ) -> ::core::option::Option<&'static str> { + match Self::SELECTORS.binary_search(&selector) { + ::core::result::Result::Ok(idx) => { + ::core::option::Option::Some(Self::SIGNATURES[idx]) + } + ::core::result::Result::Err(_) => ::core::option::Option::None, + } + } + + /// Returns the enum variant name for the given selector, if known. + #[inline] + pub fn name_by_selector(selector: [u8; 32usize]) -> ::core::option::Option<&'static str> { + let sig = Self::signature_by_selector(selector)?; + sig.split_once('(').map(|(name, _)| name) + } + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for WETH9Events { + const COUNT: usize = 4usize; + const NAME: &'static str = "WETH9Events"; + + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Deposit) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Withdrawal) + } + _ => alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }), + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for WETH9Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Deposit(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Transfer(inner) => alloy_sol_types::private::IntoLogData::to_log_data(inner), + Self::Withdrawal(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Deposit(inner) => alloy_sol_types::private::IntoLogData::into_log_data(inner), + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Withdrawal(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy_contract; + /**Creates a new wrapper around an on-chain [`WETH9`](self) contract instance. + + See the [wrapper's documentation](`WETH9Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + __provider: P, + ) -> WETH9Instance { + WETH9Instance::::new(address, __provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy, N: alloy_contract::private::Network>( + __provider: P, + ) -> impl ::core::future::Future>> { + WETH9Instance::::deploy(__provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + __provider: P, + ) -> alloy_contract::RawCallBuilder { + WETH9Instance::::deploy_builder(__provider) + } + /**A [`WETH9`](self) instance. + + Contains type-safe methods for interacting with an on-chain instance of the + [`WETH9`](self) contract located at a given `address`, using a given + provider `P`. + + If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) + documentation on how to provide it), the `deploy` and `deploy_builder` methods can + be used to deploy a new instance of the contract. + + See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct WETH9Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for WETH9Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("WETH9Instance").field(&self.address).finish() + } + } + /// Instantiation and getters/setters. + impl, N: alloy_contract::private::Network> + WETH9Instance + { + /**Creates a new wrapper around an on-chain [`WETH9`](self) contract instance. + + See the [wrapper's documentation](`WETH9Instance`) for more details.*/ + #[inline] + pub const fn new(address: alloy_sol_types::private::Address, __provider: P) -> Self { + Self { + address, + provider: __provider, + _network: ::core::marker::PhantomData, + } + } + + /**Deploys this contract using the given `provider` and constructor arguments, if any. + + Returns a new instance of the contract, if the deployment was successful. + + For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy(__provider: P) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(__provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` + and constructor arguments, if any. + + This is a simple wrapper around creating a `RawCallBuilder` with the data set to + the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(__provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + __provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl WETH9Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned + /// provider. + #[inline] + pub fn with_cloned_provider(self) -> WETH9Instance { + WETH9Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + impl, N: alloy_contract::private::Network> + WETH9Instance + { + /// Creates a new call builder using this contract instance's provider + /// and address. + /// + /// Note that the call can be any function call, not just those defined + /// in this contract. Prefer using the other methods for + /// building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + _0: alloy_sol_types::private::Address, + _1: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { _0, _1 }) + } + + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + guy: alloy_sol_types::private::Address, + wad: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { guy, wad }) + } + + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + _0: alloy_sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall(_0)) + } + + ///Creates a new call builder for the [`decimals`] function. + pub fn decimals(&self) -> alloy_contract::SolCallBuilder<&P, decimalsCall, N> { + self.call_builder(&decimalsCall) + } + + ///Creates a new call builder for the [`deposit`] function. + pub fn deposit(&self) -> alloy_contract::SolCallBuilder<&P, depositCall, N> { + self.call_builder(&depositCall) + } + + ///Creates a new call builder for the [`name`] function. + pub fn name(&self) -> alloy_contract::SolCallBuilder<&P, nameCall, N> { + self.call_builder(&nameCall) + } + + ///Creates a new call builder for the [`symbol`] function. + pub fn symbol(&self) -> alloy_contract::SolCallBuilder<&P, symbolCall, N> { + self.call_builder(&symbolCall) + } + + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + dst: alloy_sol_types::private::Address, + wad: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { dst, wad }) + } + + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + src: alloy_sol_types::private::Address, + dst: alloy_sol_types::private::Address, + wad: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder(&transferFromCall { src, dst, wad }) + } + + ///Creates a new call builder for the [`withdraw`] function. + pub fn withdraw( + &self, + wad: alloy_sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, withdrawCall, N> { + self.call_builder(&withdrawCall { wad }) + } + } + /// Event filters. + impl, N: alloy_contract::private::Network> + WETH9Instance + { + /// Creates a new event filter using this contract instance's provider + /// and address. + /// + /// Note that the type can be any event, not just those defined in this + /// contract. Prefer using the other methods for building + /// type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Deposit`] event. + pub fn Deposit_filter(&self) -> alloy_contract::Event<&P, Deposit, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + + ///Creates a new event filter for the [`Withdrawal`] event. + pub fn Withdrawal_filter(&self) -> alloy_contract::Event<&P, Withdrawal, N> { + self.event_filter::() + } + } +} +pub type Instance = WETH9::WETH9Instance<::alloy_provider::DynProvider>; +use { + alloy_primitives::{Address, address}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result}, + std::{collections::HashMap, sync::LazyLock}, +}; +pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + 1u64 => Some(( + ::alloy_primitives::address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + None, + )), + 10u64 => Some(( + ::alloy_primitives::address!("0x4200000000000000000000000000000000000006"), + None, + )), + 56u64 => Some(( + ::alloy_primitives::address!("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), + None, + )), + 100u64 => Some(( + ::alloy_primitives::address!("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"), + None, + )), + 137u64 => Some(( + ::alloy_primitives::address!("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"), + None, + )), + 8453u64 => Some(( + ::alloy_primitives::address!("0x4200000000000000000000000000000000000006"), + None, + )), + 9745u64 => Some(( + ::alloy_primitives::address!("0x6100E367285b01F48D07953803A2d8dCA5D19873"), + None, + )), + 42161u64 => Some(( + ::alloy_primitives::address!("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), + None, + )), + 43114u64 => Some(( + ::alloy_primitives::address!("0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"), + None, + )), + 57073u64 => Some(( + ::alloy_primitives::address!("0x4200000000000000000000000000000000000006"), + None, + )), + 59144u64 => Some(( + ::alloy_primitives::address!("0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f"), + None, + )), + 11155111u64 => Some(( + ::alloy_primitives::address!("0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"), + None, + )), + _ => None, + } +} +pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } +} +pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } +} +impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + Ok(Instance::new(address, provider.clone())) + } + } +} diff --git a/contracts/generated/rustfmt.toml b/contracts/generated/rustfmt.toml new file mode 100644 index 0000000000..2349451ea0 --- /dev/null +++ b/contracts/generated/rustfmt.toml @@ -0,0 +1,12 @@ +format_code_in_doc_comments = true +format_strings = true +imports_layout = "HorizontalVertical" +imports_granularity = "One" +normalize_doc_attributes = true +reorder_impl_items = true +group_imports = "StdExternalCrate" +use_try_shorthand = true +wrap_comments = true +remove_nested_parens = true +unstable_features = true +use_field_init_shorthand = true diff --git a/crates/contracts/script/DeployBalances.s.sol b/contracts/script/DeployBalances.s.sol similarity index 100% rename from crates/contracts/script/DeployBalances.s.sol rename to contracts/script/DeployBalances.s.sol diff --git a/crates/contracts/script/DeploySignatures.s.sol b/contracts/script/DeploySignatures.s.sol similarity index 100% rename from crates/contracts/script/DeploySignatures.s.sol rename to contracts/script/DeploySignatures.s.sol diff --git a/crates/contracts/solidity/AnyoneAuthenticator.sol b/contracts/solidity/AnyoneAuthenticator.sol similarity index 100% rename from crates/contracts/solidity/AnyoneAuthenticator.sol rename to contracts/solidity/AnyoneAuthenticator.sol diff --git a/crates/contracts/solidity/Balances.sol b/contracts/solidity/Balances.sol similarity index 95% rename from crates/contracts/solidity/Balances.sol rename to contracts/solidity/Balances.sol index c7d5a2d5a0..2ab9afe006 100644 --- a/crates/contracts/solidity/Balances.sol +++ b/contracts/solidity/Balances.sol @@ -38,6 +38,8 @@ contract Balances { /// contract when executing a trade. /// @return canTransfer - Returns whether or not the transfer into the /// settlement contract for the specified amount would succeed. + /// @return transferRevertReason - The revert reason bytes if the transfer + /// failed, or empty bytes if it succeeded. function balance( Contracts memory contracts, address trader, @@ -49,7 +51,8 @@ contract Balances { uint256 tokenBalance, uint256 allowance, uint256 effectiveBalance, - bool canTransfer + bool canTransfer, + bytes memory transferRevertReason ) { // Execute the interactions within the current context. This ensures // that any pre-interactions that setup balances and/or allowances @@ -96,8 +99,9 @@ contract Balances { try contracts.vaultRelayer.transferFromAccounts(transfers) { canTransfer = true; } - catch { + catch (bytes memory reason) { canTransfer = false; + transferRevertReason = reason; } } diff --git a/crates/contracts/solidity/Makefile b/contracts/solidity/Makefile similarity index 86% rename from crates/contracts/solidity/Makefile rename to contracts/solidity/Makefile index 04370ce7e8..e23e6f9100 100644 --- a/crates/contracts/solidity/Makefile +++ b/contracts/solidity/Makefile @@ -4,7 +4,7 @@ JQ := jq SOLC := ethereum/solc:0.8.30 SOLFLAGS := --overwrite --abi --bin --bin-runtime --metadata-hash none --optimize --optimize-runs 1000000 --evm-version shanghai -TARGETDIR := ../../../target/solidity +TARGETDIR := ../target/solidity ARTIFACTDIR := ../artifacts CONTRACTS := \ @@ -13,11 +13,10 @@ CONTRACTS := \ Signatures.sol \ Solver.sol \ Spardose.sol \ - Swapper.sol \ - Trader.sol + Swapper.sol ARTIFACTS := $(patsubst %.sol,$(ARTIFACTDIR)/%.json,$(CONTRACTS)) -TEST_CONTRACTS := Counter.sol GasHog.sol +TEST_CONTRACTS := Counter.sol GasHog.sol NonStandardERC20Balances.sol RemoteERC20Balances.sol TEST_ARTIFACTS := $(patsubst %.sol,$(ARTIFACTDIR)/%.json,$(TEST_CONTRACTS)) .PHONY: artifacts @@ -40,7 +39,7 @@ export ARTIFACTTEMPLATE $(ARTIFACTDIR)/%.json: $(TARGETDIR)/%.abi @echo jq "'...'" '>' $@ @echo "$$ARTIFACTTEMPLATE" \ - | jq -c \ + | jq \ --argjson ABI '$(shell cat $(TARGETDIR)/$*.abi)' \ --arg BIN '0x$(shell cat $(TARGETDIR)/$*.bin | head -n1)' \ --arg BINRT '0x$(shell cat $(TARGETDIR)/$*.bin-runtime | head -n1)' \ @@ -50,7 +49,7 @@ $(ARTIFACTDIR)/%.json: $(TARGETDIR)/%.abi $(TARGETDIR)/%.abi: %.sol @mkdir -p $(TARGETDIR) @echo solc $(SOLFLAGS) -o /target $< - @$(DOCKER) run -it --rm \ + @$(DOCKER) run --platform linux/amd64 -t --rm \ -v "$(abspath .):/contracts" -w "/contracts" \ -v "$(abspath $(TARGETDIR)):/target" \ $(SOLC) \ @@ -59,7 +58,7 @@ $(TARGETDIR)/%.abi: %.sol $(TARGETDIR)/%.abi: tests/%.sol @mkdir -p $(TARGETDIR) @echo solc $(SOLFLAGS) -o /target $(notdir $<) - @$(DOCKER) run -it --rm \ + @$(DOCKER) run --platform linux/amd64 -t --rm \ -v "$(abspath .)/tests:/contracts" -w "/contracts" \ -v "$(abspath $(TARGETDIR)):/target" \ $(SOLC) \ diff --git a/crates/contracts/solidity/README.md b/contracts/solidity/README.md similarity index 100% rename from crates/contracts/solidity/README.md rename to contracts/solidity/README.md diff --git a/crates/contracts/solidity/Signatures.sol b/contracts/solidity/Signatures.sol similarity index 100% rename from crates/contracts/solidity/Signatures.sol rename to contracts/solidity/Signatures.sol diff --git a/crates/contracts/solidity/Solver.sol b/contracts/solidity/Solver.sol similarity index 57% rename from crates/contracts/solidity/Solver.sol rename to contracts/solidity/Solver.sol index b141f28653..f4f367abd4 100644 --- a/crates/contracts/solidity/Solver.sol +++ b/contracts/solidity/Solver.sol @@ -6,7 +6,7 @@ import { Interaction, Trade, ISettlement } from "./interfaces/ISettlement.sol"; import { Caller } from "./libraries/Caller.sol"; import { Math } from "./libraries/Math.sol"; import { SafeERC20 } from "./libraries/SafeERC20.sol"; -import { Trader } from "./Trader.sol"; +import { Spardose } from "./Spardose.sol"; /// @title A contract for impersonating a solver. This contract assume the solver /// does not execute extra logic outside of the settlement that affects the execution @@ -23,6 +23,12 @@ contract Solver layout at 0x14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff1 uint256 private _simulationOverhead; uint256[] private _queriedBalances; + /// @dev When setting up the simulation we compute state overrides to fund this + /// address with the necessary sell tokens. If the user does not have the tokens + /// already the solver will transfer them from this account to the user. + /// If you update this constant it also needs to be updated in `trade_verifier.rs`. + address private constant PIGGY_BANK = 0x1111111111111111111111111111111111111111; + /// @dev Executes the given transaction from the context of a solver. /// That way we don't have to fake the authentication logic of the /// settlement contract as this address should actually be a @@ -32,6 +38,7 @@ contract Solver layout at 0x14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff1 /// it does not have a stable address in tests. /// @param tokens - list of tokens used in the trade /// @param receiver - address receiving the bought tokens + /// @param settleCallTarget - contract we send the `settlementCall` to /// @param settlementCall - the calldata of the `settle()` call /// /// @return gasUsed - gas used for the `settle()` call @@ -40,13 +47,16 @@ contract Solver layout at 0x14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff1 ISettlement settlementContract, address[] calldata tokens, address payable receiver, + address trader, + address sellToken, + uint256 sellAmount, + address settleCallTarget, bytes calldata settlementCall ) external returns ( uint256 gasUsed, uint256[] memory queriedBalances ) { - require(msg.sender == address(this), "only simulation logic is allowed to call 'swap' function"); - + ensureTradePreconditions(settlementContract, trader, sellToken, sellAmount); // Warm the storage for sending ETH to smart contract addresses. // We allow this call to revert becaues it was either unnecessary in the first place // or failing to send `ETH` to the `receiver` will cause a revert in the settlement @@ -59,7 +69,7 @@ contract Solver layout at 0x14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff1 // Store pre-settlement balances _storeSettlementBalances(tokens, settlementContract); - gasUsed = _executeSettlement(address(settlementContract), settlementCall); + gasUsed = _executeAndMeasure(settleCallTarget, settlementCall); // Store post-settlement balances _storeSettlementBalances(tokens, settlementContract); @@ -67,6 +77,64 @@ contract Solver layout at 0x14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff1 queriedBalances = _queriedBalances; } + /// @dev Copies `settlementCall` to memory, invokes the settlement, and + /// returns the net gas consumed. + function _executeAndMeasure( + address settleCallTarget, + bytes calldata settlementCall + ) internal returns (uint256 gasUsed) { + uint256 gasStart = gasleft(); + // In order to call a function we need to copy the arguments into memory. + // In a regular transaction that would actually not happen because the arguments + // would get referenced directly from the calldata. To not overcount the gas + // usage due to this difference we manually copy the calldata to memory and + // pass the arguments via pointers outside of the metered section. + bytes memory settlementCallMem = settlementCall; + assembly { + if iszero(call(gas(), settleCallTarget, 0, add(settlementCallMem, 32), mload(settlementCallMem), 0, 0)) { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + } + gasUsed = gasStart - gasleft() - _simulationOverhead; + } + + /// @dev Ensures that the user has given the necessary approvals and transfers sell + /// tokens to the user if needed. + /// @param settlementContract - pass in settlement contract because it does not have + /// a stable address in tests. + /// @param trader - account wanting to trade + /// @param sellToken - token being sold by the trade + /// @param sellAmount - expected amount to be sold according to the quote + function ensureTradePreconditions( + ISettlement settlementContract, + address trader, + address sellToken, + uint256 sellAmount + ) internal { + address vaultRelayer = settlementContract.vaultRelayer(); + uint256 allowance = IERC20(sellToken).allowance(trader, vaultRelayer); + + // User did not actually give the required approval or we were not able + // to compute the required state overrides. + // Revert with a helpful message. + require(allowance >= sellAmount, "trader did not give the required approvals"); + + // Ensure that the user has sufficient sell token balance. If not, request some + // funds from the piggy bank which will be available if balance overrides could + // be computed correctly. + uint256 sellBalance = IERC20(sellToken).balanceOf(trader); + if (sellBalance < sellAmount) { + try Spardose(PIGGY_BANK).requestFunds(trader, sellToken, sellAmount - sellBalance) {} + catch { + // The trader does not have sufficient sell token balance, and the + // piggy bank pre-fund failed, as balance overrides are not available. + // Revert with a helpful message. + revert("trader does not have enough sell token"); + } + } + } + /// @dev Helper function that reads the `owner`s balance for a given `token` and /// stores it. These stored balances will be returned as part of the simulation /// `Summary`. @@ -94,41 +162,4 @@ contract Solver layout at 0x14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff1 this.storeBalance(tokens[i], address(settlementContract), false); } } - - /// @dev Executes the settlement and measures the gas used. - /// @param settlementContract The address of the settlement contract. - /// @param settlementCall The calldata for the settlement function. - /// @return gasUsed The amount of gas used during the settlement execution. - function _executeSettlement( - address settlementContract, - bytes calldata settlementCall - ) private returns (uint256 gasUsed) { - uint256 gasStart = gasleft(); - address(settlementContract).doCall(settlementCall); - gasUsed = gasStart - gasleft() - _simulationOverhead; - } - - /// @dev Simple wrapper around `Trader.ensureTradePreconditions()` that - /// discounts the gas used to prepare the swap (setting up approvals - /// and balances) from the total gas cost since that would normally - /// not happen during the settlement. - function ensureTradePreconditions( - Trader trader, - ISettlement settlementContract, - address sellToken, - uint256 sellAmount, - address nativeToken, - address spardose - ) external { - uint256 gasStart = gasleft(); - trader.ensureTradePreconditions( - settlementContract, - sellToken, - sellAmount, - nativeToken, - spardose - ); - // Account for costs of gas used outside of metered section. - _simulationOverhead += gasStart - gasleft() + 4460; - } } diff --git a/crates/contracts/solidity/Spardose.sol b/contracts/solidity/Spardose.sol similarity index 79% rename from crates/contracts/solidity/Spardose.sol rename to contracts/solidity/Spardose.sol index f453a0940e..3f818809a4 100644 --- a/crates/contracts/solidity/Spardose.sol +++ b/contracts/solidity/Spardose.sol @@ -15,9 +15,10 @@ contract Spardose { /// @dev Request funds from the piggy bank to be transferred to the caller. /// Reverts if the transfer fails. /// + /// @param receiver - the account that should get the funds /// @param token - the token request funds for /// @param amount - the amount of `token` to transfer - function requestFunds(address token, uint256 amount) external { - IERC20(token).safeTransfer(msg.sender, amount); + function requestFunds(address receiver, address token, uint256 amount) external { + IERC20(token).safeTransfer(receiver, amount); } } diff --git a/crates/contracts/solidity/Swapper.sol b/contracts/solidity/Swapper.sol similarity index 100% rename from crates/contracts/solidity/Swapper.sol rename to contracts/solidity/Swapper.sol diff --git a/crates/contracts/solidity/interfaces/IERC1271.sol b/contracts/solidity/interfaces/IERC1271.sol similarity index 100% rename from crates/contracts/solidity/interfaces/IERC1271.sol rename to contracts/solidity/interfaces/IERC1271.sol diff --git a/crates/contracts/solidity/interfaces/IERC20.sol b/contracts/solidity/interfaces/IERC20.sol similarity index 100% rename from crates/contracts/solidity/interfaces/IERC20.sol rename to contracts/solidity/interfaces/IERC20.sol diff --git a/contracts/solidity/interfaces/IERC4626.sol b/contracts/solidity/interfaces/IERC4626.sol new file mode 100644 index 0000000000..ca6522cca7 --- /dev/null +++ b/contracts/solidity/interfaces/IERC4626.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +/// @title ERC-4626 vaults interface +interface IERC4626 { + function asset() external view returns (address assetTokenAddress); + function convertToAssets(uint256 shares) external view returns (uint256 assets); +} diff --git a/crates/contracts/solidity/interfaces/ISettlement.sol b/contracts/solidity/interfaces/ISettlement.sol similarity index 100% rename from crates/contracts/solidity/interfaces/ISettlement.sol rename to contracts/solidity/interfaces/ISettlement.sol diff --git a/crates/contracts/solidity/interfaces/IStorageAccessible.sol b/contracts/solidity/interfaces/IStorageAccessible.sol similarity index 100% rename from crates/contracts/solidity/interfaces/IStorageAccessible.sol rename to contracts/solidity/interfaces/IStorageAccessible.sol diff --git a/crates/contracts/solidity/interfaces/IVault.sol b/contracts/solidity/interfaces/IVault.sol similarity index 100% rename from crates/contracts/solidity/interfaces/IVault.sol rename to contracts/solidity/interfaces/IVault.sol diff --git a/crates/contracts/solidity/interfaces/IVaultRelayer.sol b/contracts/solidity/interfaces/IVaultRelayer.sol similarity index 100% rename from crates/contracts/solidity/interfaces/IVaultRelayer.sol rename to contracts/solidity/interfaces/IVaultRelayer.sol diff --git a/crates/contracts/solidity/libraries/Caller.sol b/contracts/solidity/libraries/Caller.sol similarity index 100% rename from crates/contracts/solidity/libraries/Caller.sol rename to contracts/solidity/libraries/Caller.sol diff --git a/crates/contracts/solidity/libraries/Math.sol b/contracts/solidity/libraries/Math.sol similarity index 100% rename from crates/contracts/solidity/libraries/Math.sol rename to contracts/solidity/libraries/Math.sol diff --git a/crates/contracts/solidity/libraries/SafeERC20.sol b/contracts/solidity/libraries/SafeERC20.sol similarity index 100% rename from crates/contracts/solidity/libraries/SafeERC20.sol rename to contracts/solidity/libraries/SafeERC20.sol diff --git a/crates/contracts/solidity/tests/Counter.sol b/contracts/solidity/tests/Counter.sol similarity index 100% rename from crates/contracts/solidity/tests/Counter.sol rename to contracts/solidity/tests/Counter.sol diff --git a/crates/contracts/solidity/tests/GasHog.sol b/contracts/solidity/tests/GasHog.sol similarity index 100% rename from crates/contracts/solidity/tests/GasHog.sol rename to contracts/solidity/tests/GasHog.sol diff --git a/contracts/solidity/tests/MockERC4626Wrapper.sol b/contracts/solidity/tests/MockERC4626Wrapper.sol new file mode 100644 index 0000000000..8a33eef4e8 --- /dev/null +++ b/contracts/solidity/tests/MockERC4626Wrapper.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +/// @title MockERC4626Wrapper +/// @notice Minimal EIP-4626 wrapper for testing recursive vault pricing. +/// @dev Wraps another ERC-4626 vault (or any ERC-20) with a configurable +/// conversion rate. Not a real vault -- just enough to satisfy `asset()`, +/// `decimals()`, `convertToAssets()`, `balanceOf()`, `approve()`, and +/// `transfer()` so the e2e pricing pipeline works. +contract MockERC4626Wrapper { + address public immutable asset; + uint8 public immutable decimals; + uint256 public immutable rateNumerator; + uint256 public immutable rateDenominator; + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + constructor(address _asset, uint8 _decimals, uint256 _rateNumerator, uint256 _rateDenominator) { + asset = _asset; + decimals = _decimals; + rateNumerator = _rateNumerator; + rateDenominator = _rateDenominator; + } + + /// @notice Returns the equivalent amount of underlying assets for the + /// given number of vault shares, scaled by the configured rate. + function convertToAssets(uint256 shares) external view returns (uint256) { + return shares * rateNumerator / rateDenominator; + } + + function transfer(address to, uint256 amount) external returns (bool) { + balanceOf[msg.sender] -= amount; + balanceOf[to] += amount; + return true; + } + + function approve(address spender, uint256 amount) external returns (bool) { + allowance[msg.sender][spender] = amount; + return true; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + allowance[from][msg.sender] -= amount; + balanceOf[from] -= amount; + balanceOf[to] += amount; + return true; + } + + /// @notice Mints tokens to an address. Only for testing. + function mint(address to, uint256 amount) external { + balanceOf[to] += amount; + } +} diff --git a/contracts/solidity/tests/NonStandardERC20Balances.sol b/contracts/solidity/tests/NonStandardERC20Balances.sol new file mode 100644 index 0000000000..70c7bc753b --- /dev/null +++ b/contracts/solidity/tests/NonStandardERC20Balances.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract NonStandardERC20Balances { + + struct UserData { + // hypothetical other field + uint256 epoch; + mapping(address => uint256) approvals; + uint256 balance; + } + + // In this token, the user's balance is stored at an offset position in the mapping -> cannot be detected by standard methods + mapping(address => UserData) users; + + function mint(address user, uint256 amount) external { + users[user].epoch = 1; + users[user].balance = amount; + } + + function balanceOf(address user) external virtual view returns (uint256) { + return users[user].balance; + } + + function allowance(address user, address spender) external view returns (uint256) { + return users[user].approvals[spender]; + } + + function transfer(address to, uint256 amount) external { + users[msg.sender].balance -= amount; + users[msg.sender].epoch++; + users[to].balance += amount; + users[to].epoch++; + } + + function transferFrom(address from, address to, uint256 amount) external { + users[from].approvals[msg.sender] -= amount; + users[from].balance -= amount; + users[from].epoch++; + users[to].balance += amount; + users[to].epoch++; + } + + function approve(address spender, uint256 amount) external { + users[msg.sender].approvals[spender] = amount; + } +} diff --git a/contracts/solidity/tests/RemoteERC20Balances.sol b/contracts/solidity/tests/RemoteERC20Balances.sol new file mode 100644 index 0000000000..dbd7d1c905 --- /dev/null +++ b/contracts/solidity/tests/RemoteERC20Balances.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "./NonStandardERC20Balances.sol"; + +contract RemoteERC20Balances is NonStandardERC20Balances { + bool internal immutable isLocalBalance; + NonStandardERC20Balances public immutable target; + + constructor(NonStandardERC20Balances _target, bool _balanceFromHere) { + isLocalBalance = _balanceFromHere; + target = _target; + } + + function balanceOf(address user) external view override returns (uint256) { + // retrieve the balance from the target contract regardless (for testing) + uint256 otherBalanceOf = target.balanceOf(user); + + return isLocalBalance ? users[user].balance : otherBalanceOf; + } + +} diff --git a/contracts/src/codegen.rs b/contracts/src/codegen.rs new file mode 100644 index 0000000000..84c0822c76 --- /dev/null +++ b/contracts/src/codegen.rs @@ -0,0 +1,487 @@ +use { + alloy_sol_macro_expander::expand::expand, + alloy_sol_macro_input::{SolInput, SolInputKind}, + anyhow::{Context, Result}, + proc_macro2::{Span, TokenStream}, + quote::{ToTokens, format_ident}, + rayon::prelude::*, + std::{ + collections::HashMap, + fmt::Write, + path::{Path, PathBuf}, + }, +}; + +/// Header for generated lib.rs files. +const LIB_HEADER: &str = "\ +#![allow(unused_imports, unused_attributes, clippy::all, rustdoc::all, non_snake_case)] +//! Auto-generated contract bindings. Do not edit. +"; + +/// Header for the facade lib.rs. +const FACADE_HEADER: &str = "\ +#![allow(unused_imports, unused_attributes, clippy::all, rustdoc::all, non_snake_case)] +//! This crate re-exports per-contract crate bindings. +//! Auto-generated by contracts-generate. Do not edit. +"; + +/// Cargo.toml template for generated per-contract crates. +const CARGO_TOML_TEMPLATE: &str = "\ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = \"{crate_name}\" +version = \"0.1.0\" +edition = \"2024\" +publish = false + +[lib] +doctest = false + +[dependencies] +alloy-primitives = { workspace = true } +alloy-sol-types = { workspace = true } +alloy-contract = { workspace = true } +alloy-provider = { workspace = true } +anyhow = { workspace = true } + +[lints] +workspace = true +"; + +/// Workspace Cargo.toml template for the generated workspace. +const WORKSPACE_CARGO_TOML: &str = "\ +# Auto-generated by contracts-generate. Do not edit. +[workspace] +resolver = \"3\" +members = [ + \"contracts-facade\", + \"contracts-generated/*\", +] + +[workspace.dependencies] +alloy-primitives = { version = \"1.5.7\", default-features = false } +alloy-sol-types = { version = \"1.5.7\", default-features = false } +alloy-contract = { version = \"1.7.3\" } +alloy-provider = { version = \"1.7.3\", default-features = false } +anyhow = \"1.0.100\" + +[workspace.lints.clippy] +all = \"warn\" +"; + +/// Convert a PascalCase contract name to a kebab-case crate name. +fn to_crate_name(contract_name: &str) -> String { + format!("cow-contract-{}", contract_name.to_lowercase()) +} + +/// Convert a contract name to a directory name under contracts-generated/. +fn to_dir_name(contract_name: &str) -> String { + contract_name.to_lowercase() +} + +/// Convert a crate name (kebab-case) to a Rust identifier (underscore_case). +fn to_rust_ident(crate_name: &str) -> String { + crate_name.replace('-', "_") +} + +/// Metadata about a generated contract crate, used for facade generation. +struct CrateEntry { + contract_name: String, + crate_name: String, + dir_name: String, + submodule: Option, +} + +#[derive(Default)] +pub struct Module { + pub contracts: Vec, + pub submodules: Vec, +} + +impl Module { + pub fn add_contract(mut self, contract: Contract) -> Self { + self.contracts.push(contract); + self + } + + pub fn add_submodule(mut self, submodule: Submodule) -> Self { + self.submodules.push(submodule); + self + } + + /// Generate a self-contained Cargo workspace under `output_dir` containing: + /// - `contracts-generated//` per-contract crates + /// - `contracts-facade/` facade crate that re-exports all contracts + /// - Root workspace `Cargo.toml` + pub fn generate(self, artifacts_dir: &Path, output_dir: &Path) -> Result<()> { + let contracts_generated_dir = output_dir.join("contracts-generated"); + let facade_dir = output_dir.join("contracts-facade"); + + std::fs::create_dir_all(&contracts_generated_dir)?; + std::fs::create_dir_all(&facade_dir)?; + + // Collect all contracts with their submodule association, then + // generate crates in parallel. + let entries: Vec = self + .contracts + .iter() + .map(|c| (c, None)) + .chain( + self.submodules + .iter() + .flat_map(|s| s.contracts.iter().map(move |c| (c, Some(s.name.clone())))), + ) + .collect::>() + .into_par_iter() + .map(|(contract, submodule)| { + contract.write_crate(artifacts_dir, &contracts_generated_dir)?; + Ok(CrateEntry { + contract_name: contract.name.clone(), + crate_name: to_crate_name(&contract.name), + dir_name: to_dir_name(&contract.name), + submodule, + }) + }) + .collect::>>()?; + + let mut entries = entries; + entries.sort_by_key(|entry| entry.crate_name.clone()); + + // Generate the facade crate + write_facade_lib(&entries, &facade_dir)?; + write_facade_cargo_toml(&entries, &facade_dir)?; + + // Generate the workspace Cargo.toml + write_workspace_cargo_toml(output_dir)?; + + Ok(()) + } +} + +/// Generate the facade crate's lib.rs file. +fn write_facade_lib(entries: &[CrateEntry], facade_dir: &Path) -> Result<()> { + let src_dir = facade_dir.join("src"); + std::fs::create_dir_all(&src_dir)?; + + let mut contents = String::from(FACADE_HEADER); + + // Top-level re-exports + for entry in entries { + if entry.submodule.is_none() { + let rust_ident = to_rust_ident(&entry.crate_name); + writeln!(contents, "pub use {rust_ident} as {};", entry.contract_name)?; + } + } + + // Group submodule contracts, preserving insertion order + let mut submodule_names: Vec = Vec::new(); + let mut submodule_map: HashMap> = HashMap::new(); + for entry in entries { + if let Some(submod) = &entry.submodule { + if !submodule_map.contains_key(submod) { + submodule_names.push(submod.clone()); + } + submodule_map.entry(submod.clone()).or_default().push(entry); + } + } + + // Write submodule blocks in insertion order + for submod_name in &submodule_names { + let contracts = &submodule_map[submod_name]; + writeln!(contents, "pub mod {submod_name} {{")?; + for entry in contracts { + let rust_ident = to_rust_ident(&entry.crate_name); + writeln!( + contents, + " pub use {rust_ident} as {};", + entry.contract_name + )?; + } + writeln!(contents, "}}")?; + } + + let file: syn::File = syn::parse_file(&contents)?; + let formatted = prettyplease::unparse(&file); + std::fs::write(src_dir.join("lib.rs"), formatted)?; + + Ok(()) +} + +/// Generate the facade crate's Cargo.toml. +fn write_facade_cargo_toml(entries: &[CrateEntry], facade_dir: &Path) -> Result<()> { + let mut contents = String::from( + "\ +# Auto-generated by contracts-generate. Do not edit. +[package] +name = \"contracts\" +version = \"0.1.0\" +edition = \"2024\" +publish = false + +[lib] +doctest = false + +[dependencies] +", + ); + + for entry in entries { + writeln!( + contents, + "{} = {{ path = \"../contracts-generated/{}\" }}", + entry.crate_name, entry.dir_name + )?; + } + + contents.push_str("\n[lints]\nworkspace = true\n"); + + std::fs::write(facade_dir.join("Cargo.toml"), contents)?; + eprintln!(" generated facade Cargo.toml"); + + Ok(()) +} + +/// Generate the workspace root Cargo.toml. +fn write_workspace_cargo_toml(output_dir: &Path) -> Result<()> { + std::fs::write(output_dir.join("Cargo.toml"), WORKSPACE_CARGO_TOML)?; + eprintln!(" generated workspace Cargo.toml"); + Ok(()) +} + +pub struct Submodule { + pub name: String, + pub contracts: Vec, +} + +impl Submodule { + pub fn new(name: S) -> Self { + Self { + name: name.to_string(), + contracts: vec![], + } + } + + pub fn add_contract(mut self, contract: Contract) -> Self { + self.contracts.push(contract); + self + } +} + +pub struct Contract { + pub name: String, + networks: HashMap)>, +} + +impl Contract { + pub fn new>(name: S) -> Self { + Self { + name: name.as_ref().to_string(), + networks: HashMap::new(), + } + } + + pub fn with_networks(mut self, networks: I) -> Self + where + S: AsRef, + I: IntoIterator))>, + { + for (id, (address, block_number)) in networks.into_iter() { + self.networks + .insert(id, (address.as_ref().to_string(), block_number)); + } + self + } + + fn artifacts_path(&self, artifacts_dir: &Path) -> PathBuf { + artifacts_dir.join(&self.name).with_extension("json") + } + + /// Generate the Rust code for this contract's bindings. + fn generate_code(&self, artifacts_dir: &Path) -> Result { + let bindings_path = self.artifacts_path(artifacts_dir); + let mut macrogen = SolMacroGen::new(bindings_path, self.name.clone()); + generate_binding(&mut macrogen, true)?; + let mut expansion = macrogen + .expansion + .expect("if the expansion failed, it should have errored earlier"); + + let module_name_ident = format_ident!("{}", self.name); + let instance_name_ident = format_ident!("{}Instance", self.name); + let instance = quote::quote! { + pub type Instance = #module_name_ident :: #instance_name_ident<::alloy_provider::DynProvider>; + }; + expansion.extend(instance); + + if !self.networks.is_empty() { + let mut networks: Vec<_> = self + .networks + .iter() + .map(|(&chain_id, info)| NetworkArm(chain_id, (info.0.clone(), info.1))) + .collect(); + // Sorting is required to keep generation stable and changes to a minimum + networks.sort_by_key(|arm| arm.0); + let deployment_info = quote::quote! { + use { + std::{ + sync::LazyLock, + collections::HashMap + }, + anyhow::{Result, Context}, + alloy_primitives::{address, Address}, + alloy_provider::{Provider, DynProvider}, + }; + + pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + #( #networks ,)* + _ => None + } + } + + pub const fn deployment_address(chain_id: &u64) -> Option<::alloy_primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } + } + + pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } + } + + impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + + Ok(Instance::new( + address, + provider.clone(), + )) + } + } + } + }; + expansion.extend(deployment_info); + } + + Ok(expansion) + } + + /// Write a per-contract crate to the contracts-generated directory. + fn write_crate(&self, artifacts_dir: &Path, contracts_generated_dir: &Path) -> Result<()> { + let crate_name = to_crate_name(&self.name); + let dir_name = to_dir_name(&self.name); + let crate_dir = contracts_generated_dir.join(&dir_name); + let src_dir = crate_dir.join("src"); + std::fs::create_dir_all(&src_dir)?; + + // Generate Cargo.toml + let cargo_toml = CARGO_TOML_TEMPLATE.replace("{crate_name}", &crate_name); + std::fs::write(crate_dir.join("Cargo.toml"), cargo_toml)?; + + // Generate lib.rs + let token_stream = self.generate_code(artifacts_dir)?; + let mut buffer = String::from(LIB_HEADER); + write!(buffer, "{}", token_stream)?; + let file: syn::File = syn::parse_file(&buffer) + .with_context(|| format!("parsing generated code for {}", self.name))?; + let formatted = prettyplease::unparse(&file); + std::fs::write(src_dir.join("lib.rs"), formatted)?; + + eprintln!(" generated crate: {crate_name} (contracts-generated/{dir_name})"); + Ok(()) + } +} + +fn generate_binding(instance: &mut SolMacroGen, all_derives: bool) -> Result<()> { + let input = instance + .get_sol_input() + .map_err(|err| anyhow::anyhow!("{:?}", err))? + .normalize_json() + .map_err(|err| anyhow::anyhow!("{:?}", err))?; + let SolInput { + attrs: _, + path: _, + kind, + } = input; + + let tokens = match kind { + SolInputKind::Sol(mut file) => { + let sol_attr: syn::Attribute = if all_derives { + syn::parse_quote! { + #[sol(rpc, alloy_sol_types = alloy_sol_types, alloy_contract = + alloy_contract, all_derives = true)] + } + } else { + syn::parse_quote! { + #[sol(rpc, alloy_sol_types = alloy_sol_types, alloy_contract = + alloy_contract)] + } + }; + file.attrs.push(sol_attr); + expand(file)? + } + _ => unreachable!(), + }; + + instance.expansion = Some(tokens); + Ok(()) +} + +struct NetworkArm(u64, (String, Option)); + +impl ToTokens for NetworkArm { + fn to_tokens(&self, tokens: &mut TokenStream) { + let chain_id = self.0; + let address = &self.1.0; + let block_number = match self.1.1 { + Some(block) => quote::quote! {Some(#block)}, + None => quote::quote! {None}, + }; + tokens.extend(quote::quote! { + #chain_id => Some((::alloy_primitives::address!(#address), #block_number)) + }); + } +} + +/// SolMacroGen implementation vendored from +/// +struct SolMacroGen { + path: PathBuf, + name: String, + expansion: Option, +} + +impl SolMacroGen { + fn new(path: PathBuf, name: String) -> Self { + Self { + path, + name, + expansion: None, + } + } + + fn get_sol_input(&self) -> Result { + let path = self.path.to_string_lossy().into_owned(); + let name = proc_macro2::Ident::new(&self.name, Span::call_site()); + let tokens = quote::quote! { + #[sol(ignore_unlinked)] + #name, + #path + }; + + let sol_input: SolInput = syn::parse2(tokens).context("failed to parse input")?; + + Ok(sol_input) + } +} diff --git a/contracts/src/main.rs b/contracts/src/main.rs new file mode 100644 index 0000000000..2c46fc1944 --- /dev/null +++ b/contracts/src/main.rs @@ -0,0 +1,563 @@ +mod codegen; +mod networks; +mod vendor; + +use { + codegen::{Contract, Module, Submodule}, + networks::*, + std::path::Path, +}; + +/// Declare a network tuple with an optional block number. +/// +/// Example, without blocks: +/// ```no_run +/// networks! { +/// MAINNET => "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", +/// SEPOLIA => "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", +/// }; +/// ``` +/// +/// Example, with blocks: +/// ```no_run +/// networks! { +/// MAINNET => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 12593265), +/// SEPOLIA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 4717488), +/// }; +/// ``` +macro_rules! networks { + [$( + $id:expr => $value:tt + ),* $(,)?] => { + [$( + networks!(@entry $id => $value) + ),*] + }; + + (@entry $id:expr => ($addr:expr, $block:expr)) => { + ($id, ($addr, Some($block))) + }; + + (@entry $id:expr => $value:expr) => { + ($id, ($value, None)) + }; +} + +fn main() { + let args: Vec = std::env::args().skip(1).collect(); + let command = args.first().map(String::as_str).unwrap_or("generate"); + + let result = match command { + "vendor" => run_vendor(), + "generate" => run_generate(), + "all" => run_vendor().and_then(|()| run_generate()), + other => { + eprintln!("Unknown command: {other}"); + eprintln!("Usage: contracts-generate [vendor|generate|all]"); + std::process::exit(1); + } + }; + + if let Err(err) = result { + eprintln!("Error: {err:?}"); + std::process::exit(1); + } +} + +fn workspace_root() -> &'static Path { + Path::new(env!("CARGO_MANIFEST_DIR")) +} + +fn run_vendor() -> anyhow::Result<()> { + let artifacts_dir = workspace_root().join("artifacts"); + vendor::run(&artifacts_dir) +} + +fn run_generate() -> anyhow::Result<()> { + let workspace_root = workspace_root(); + + let artifacts_dir = workspace_root.join("artifacts"); + let output_dir = workspace_root.join("generated"); + + eprintln!("Generating workspace under {}...", output_dir.display()); + eprintln!(" artifacts: {}", artifacts_dir.display()); + + build_module().generate(&artifacts_dir, &output_dir)?; + + eprintln!("\nDone!"); + Ok(()) +} + +#[rustfmt::skip] +fn build_module() -> Module { + Module::default() + // 0x + .add_contract(Contract::new("IZeroex").with_networks(networks![ + MAINNET => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + SEPOLIA => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + ARBITRUM_ONE => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + BASE => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + AVALANCHE => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + BNB => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + OPTIMISM => "0xdef1abe32c034e558cdd535791643c58a13acc10", + POLYGON => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + ])) + // Misc + .add_contract(Contract::new("ERC20")) + .add_contract(Contract::new("ERC20Mintable")) + .add_contract(Contract::new("IERC4626")) + // GnosisSafe + .add_contract(Contract::new("GnosisSafe")) + .add_contract(Contract::new("GnosisSafeCompatibilityFallbackHandler")) + .add_contract(Contract::new("GnosisSafeProxy")) + .add_contract(Contract::new("GnosisSafeProxyFactory")) + // Balancer V2 + .add_contract(Contract::new("BalancerV2Authorizer")) + .add_contract(Contract::new("BalancerV2BasePool")) + .add_contract(Contract::new("BalancerV2BasePoolFactory")) + .add_contract(Contract::new("BalancerV2WeightedPool")) + .add_contract(Contract::new("BalancerV2StablePool")) + .add_contract(Contract::new("BalancerV2ComposableStablePool")) + .add_contract(Contract::new("BalancerV2LiquidityBootstrappingPool")) + .add_contract( + Contract::new("BalancerV2WeightedPoolFactory").with_networks(networks![ + MAINNET => ("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9", 12272147), + ]), + ) + .add_contract( + Contract::new("BalancerV2WeightedPoolFactoryV3").with_networks(networks![ + MAINNET => ("0x5Dd94Da3644DDD055fcf6B3E1aa310Bb7801EB8b", 16520627), + GNOSIS => ("0xC128a9954e6c874eA3d62ce62B468bA073093F25", 26226256), + AVALANCHE => ("0x94f68b54191F62f781Fe8298A8A5Fa3ed772d227", 26389236), + OPTIMISM => ("0xA0DAbEBAAd1b243BBb243f933013d560819eB66f", 72832703), + POLYGON => ("0x82e4cFaef85b1B6299935340c964C942280327f4", 39036828), + BNB => ("0x6e4cF292C5349c79cCd66349c3Ed56357dD11B46", 25474982), + ]), + ) + .add_contract( + Contract::new("BalancerV2WeightedPoolFactoryV4").with_networks(networks![ + MAINNET => ("0x897888115Ada5773E02aA29F775430BFB5F34c51", 16878323), + GNOSIS => ("0x6CaD2ea22BFA7F4C14Aae92E47F510Cd5C509bc7", 27055829), + SEPOLIA => ("0x7920BFa1b2041911b354747CA7A6cDD2dfC50Cfd", 3424893), + ARBITRUM_ONE => ("0xc7E5ED1054A24Ef31D827E6F86caA58B3Bc168d7", 72222060), + BASE => ("0x4C32a8a8fDa4E24139B51b456B42290f51d6A1c4", 1204869), + AVALANCHE => ("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a", 27739006), + OPTIMISM => ("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a", 82737545), + POLYGON => ("0xFc8a407Bba312ac761D8BFe04CE1201904842B76", 40611103), + BNB => ("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a", 26665331), + ]), + ) + .add_contract( + Contract::new("BalancerV2WeightedPool2TokensFactory").with_networks(networks![ + MAINNET => ("0xa5bf2ddf098bb0ef6d120c98217dd6b141c74ee0", 12349891), + ARBITRUM_ONE => ("0xCF0a32Bbef8F064969F21f7e02328FB577382018", 222864), + OPTIMISM => ("0xdAE7e32ADc5d490a43cCba1f0c736033F2b4eFca", 7005512), + POLYGON => ("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9", 15832998), + ]), + ) + .add_contract( + Contract::new("BalancerV2StablePoolFactoryV2").with_networks(networks![ + MAINNET => ("0x8df6efec5547e31b0eb7d1291b511ff8a2bf987c", 14934936), + GNOSIS => ("0xf23b4DB826DbA14c0e857029dfF076b1c0264843", 25415344), + ARBITRUM_ONE => ("0xEF44D6786b2b4d544b7850Fe67CE6381626Bf2D6", 14244664), + OPTIMISM => ("0xeb151668006CD04DAdD098AFd0a82e78F77076c3", 11088891), + POLYGON => ("0xcA96C4f198d343E251b1a01F3EBA061ef3DA73C1", 29371951), + ]), + ) + .add_contract( + Contract::new("BalancerV2LiquidityBootstrappingPoolFactory").with_networks(networks![ + MAINNET => ("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE", 12871780), + ARBITRUM_ONE => ("0x142B9666a0a3A30477b052962ddA81547E7029ab", 222870), + POLYGON => ("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE", 17116402), + ]), + ) + .add_contract( + Contract::new("BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory") + .with_networks(networks![ + MAINNET => ("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e", 13730248), + GNOSIS => ("0x85a80afee867aDf27B50BdB7b76DA70f1E853062", 25415236), + SEPOLIA => ("0x45fFd460cC6642B8D8Fb12373DFd77Ceb0f4932B", 3419649), + ARBITRUM_ONE => ("0x1802953277FD955f9a254B80Aa0582f193cF1d77", 4859669), + BASE => ("0x0c6052254551EAe3ECac77B01DFcf1025418828f", 1206531), + AVALANCHE => ("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e", 26386552), + BNB => ("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD", 22691243), + OPTIMISM => ("0xf302f9F50958c5593770FDf4d4812309fF77414f", 7005915), + POLYGON => ("0x41B953164995c11C81DA73D212ED8Af25741b7Ac", 22067480), + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactory").with_networks(networks![ + MAINNET => ("0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F", 15485885), + ARBITRUM_ONE => ("0xaEb406b0E430BF5Ea2Dc0B9Fe62E4E53f74B3a33", 23227044), + BNB => ("0xf302f9F50958c5593770FDf4d4812309fF77414f", 22691193), + OPTIMISM => ("0xf145caFB67081895EE80eB7c04A30Cf87f07b745", 22182522), + POLYGON => ("0x136FD06Fa01eCF624C7F2B3CB15742c1339dC2c4", 32774224), + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV3").with_networks(networks![ + MAINNET => ("0xdba127fBc23fb20F5929C546af220A991b5C6e01", 16580899), + GNOSIS => ("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD", 26365805), + ARBITRUM_ONE => ("0x1c99324EDC771c82A0DCCB780CC7DDA0045E50e7", 58948370), + BNB => ("0xacAaC3e6D6Df918Bf3c809DFC7d42de0e4a72d4C", 25475700), + OPTIMISM => ("0xe2E901AB09f37884BA31622dF3Ca7FC19AA443Be", 72832821), + POLYGON => ("0x7bc6C0E73EDAa66eF3F6E2f27b0EE8661834c6C9", 39037615), + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV4").with_networks(networks![ + MAINNET => ("0xfADa0f4547AB2de89D1304A668C39B3E09Aa7c76", 16878679), + GNOSIS => ("0xD87F44Df0159DC78029AB9CA7D7e57E7249F5ACD", 27056416), + SEPOLIA => ("0xA3fd20E29358c056B727657E83DFd139abBC9924", 3425277), + ARBITRUM_ONE => ("0x2498A2B0d6462d2260EAC50aE1C3e03F4829BA95", 72235860), + AVALANCHE => ("0x3B1eb8EB7b43882b385aB30533D9A2BeF9052a98", 29221425), + BNB => ("0x1802953277FD955f9a254B80Aa0582f193cF1d77", 26666380), + OPTIMISM => ("0x1802953277FD955f9a254B80Aa0582f193cF1d77", 82748180), + POLYGON => ("0x6Ab5549bBd766A43aFb687776ad8466F8b42f777", 40613553), + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV5").with_networks(networks![ + MAINNET => ("0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A", 17672478), + GNOSIS => ("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7", 28900564), + SEPOLIA => ("0xa523f47A933D5020b23629dDf689695AA94612Dc", 3872211), + ARBITRUM_ONE => ("0xA8920455934Da4D853faac1f94Fe7bEf72943eF1", 110212282), + BASE => ("0x8df317a729fcaA260306d7de28888932cb579b88", 1204710), + AVALANCHE => ("0xE42FFA682A26EF8F25891db4882932711D42e467", 32478827), + BNB => ("0x4fb47126Fa83A8734991E41B942Ac29A3266C968", 29877945), + OPTIMISM => ("0x043A2daD730d585C44FB79D2614F295D2d625412", 106752707), + POLYGON => ("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b", 44961548), + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV6").with_networks(networks![ + MAINNET => ("0x5B42eC6D40f7B7965BE5308c70e2603c0281C1E9", 19314764), + GNOSIS => ("0x47B489bf5836f83ABD928C316F8e39bC0587B020", 32650879), + SEPOLIA => ("0x05503B3aDE04aCA81c8D6F88eCB73Ba156982D2B", 5369821), + ARBITRUM_ONE => ("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7", 184805448), + BASE => ("0x956CCab09898C0AF2aCa5e6C228c3aD4E93d9288", 11099703), + AVALANCHE => ("0xb9F8AB3ED3F3aCBa64Bc6cd2DcA74B7F38fD7B88", 42186350), + BNB => ("0x6B5dA774890Db7B7b96C6f44e6a4b0F657399E2e", 36485719), + OPTIMISM => ("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7", 116694338), + POLYGON => ("0xEAedc32a51c510d35ebC11088fD5fF2b47aACF2E", 53996258), + ]), + ) + .add_contract(Contract::new("BalancerV2Vault").with_networks(networks![ + MAINNET => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 12272146), + GNOSIS => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 24821598), + SEPOLIA => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 3418831), + ARBITRUM_ONE => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 222832), + BASE => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 1196036), + AVALANCHE => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 26386141), + BNB => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 22691002), + OPTIMISM => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 7003431), + POLYGON => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 15832990), + INK => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 34313901), + ])) + .add_contract( + Contract::new("BalancerV3BatchRouter").with_networks(networks![ + MAINNET => ("0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", 21339510), + GNOSIS => ("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b", 37377506), + SEPOLIA => ("0xC85b652685567C1B074e8c0D4389f83a2E458b1C", 7219301), + ARBITRUM_ONE => ("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E", 297828544), + BASE => ("0x85a80afee867aDf27B50BdB7b76DA70f1E853062", 25347205), + AVALANCHE => ("0xc9b36096f5201ea332Db35d6D195774ea0D5988f", 59965747), + OPTIMISM => ("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E", 133969588), + PLASMA => ("0x85a80afee867aDf27B50BdB7b76DA70f1E853062", 782312), + ]), + ) + // UniV2 + .add_contract(Contract::new("BaoswapRouter").with_networks(networks![ + GNOSIS => "0x6093AeBAC87d62b1A5a4cEec91204e35020E38bE", + ])) + .add_contract(Contract::new("HoneyswapRouter").with_networks(networks![ + GNOSIS => "0x1C232F01118CB8B424793ae03F870aa7D0ac7f77", + ])) + .add_contract(Contract::new("PancakeRouter").with_networks(networks![ + MAINNET => "0xEfF92A263d31888d860bD50809A8D171709b7b1c", + ARBITRUM_ONE => "0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb", + BASE => "0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb", + BNB => "0x10ED43C718714eb63d5aA57B78B54704E256024E", + ])) + .add_contract(Contract::new("SushiSwapRouter").with_networks(networks![ + MAINNET => "0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f", + GNOSIS => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + ARBITRUM_ONE => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + BASE => "0x6bded42c6da8fbf0d2ba55b2fa120c5e0c8d7891", + AVALANCHE => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + BNB => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + OPTIMISM => "0x2abf469074dc0b54d793850807e6eb5faf2625b1", + POLYGON => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + ])) + .add_contract(Contract::new("SwaprRouter").with_networks(networks![ + MAINNET => "0xb9960d9bca016e9748be75dd52f02188b9d0829f", + GNOSIS => "0xE43e60736b1cb4a75ad25240E2f9a62Bff65c0C0", + ARBITRUM_ONE => "0x530476d5583724A89c8841eB6Da76E7Af4C0F17E", + ])) + .add_contract(Contract::new("ISwaprPair")) + .add_contract( + Contract::new("TestnetUniswapV2Router02").with_networks(networks![ + SEPOLIA => "0x86dcd3293C53Cf8EFd7303B57beb2a3F671dDE98", + ]), + ) + .add_contract(Contract::new("UniswapV2Factory").with_networks(networks![ + MAINNET => "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f", + GNOSIS => "0xA818b4F111Ccac7AA31D0BCc0806d64F2E0737D7", + ARBITRUM_ONE => "0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9", + BASE => "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", + SEPOLIA => "0xF62c03E08ada871A0bEb309762E260a7a6a880E6", + AVALANCHE => "0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C", + BNB => "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", + OPTIMISM => "0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf", + POLYGON => "0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C", + ])) + .add_contract(Contract::new("UniswapV2Router02").with_networks(networks![ + MAINNET => "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", + // GNOSIS: Uniswap V2 is not officially deployed on Gnosis. Use HoneyswapRouter (with custom init hash) instead. + ARBITRUM_ONE => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + BASE => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + SEPOLIA => "0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3", + AVALANCHE => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + BNB => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + OPTIMISM => "0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2", + POLYGON => "0xedf6066a2b290C185783862C7F4776A2C8077AD1", + ])) + .add_contract(Contract::new("IUniswapLikeRouter")) + .add_contract(Contract::new("IUniswapLikePair")) + .add_contract(Contract::new("UniswapV3Pool")) + .add_contract(Contract::new("UniswapV3QuoterV2").with_networks(networks![ + MAINNET => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + GNOSIS => "0x7E9cB3499A6cee3baBe5c8a3D328EA7FD36578f4", + ARBITRUM_ONE => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + BASE => "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a", + AVALANCHE => "0xbe0F5544EC67e9B3b2D979aaA43f18Fd87E6257F", + BNB => "0x78D78E420Da98ad378D7799bE8f4AF69033EB077", + OPTIMISM => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + POLYGON => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + LINEA => "0x42bE4D6527829FeFA1493e1fb9F3676d2425C3C1", + PLASMA => "0xaa52bB8110fE38D0d2d2AF0B85C3A3eE622CA455", + INK => "0x96b572D2d880cf2Fa2563651BD23ADE6f5516652", + ])) + .add_contract( + Contract::new("UniswapV3SwapRouterV2").with_networks(networks![ + ARBITRUM_ONE => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + MAINNET => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + GNOSIS => "0xc6D25285D5C5b62b7ca26D6092751A145D50e9Be", + POLYGON => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + OPTIMISM => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + BASE => "0x2626664c2603336E57B271c5C0b26F421741e481", + AVALANCHE => "0xbb00FF08d01D300023C629E8fFfFcb65A5a578cE", + BNB => "0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2", + LINEA => "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a", + PLASMA => "0x807F4E281B7A3B324825C64ca53c69F0b418dE40", + INK => "0x177778F19E89dD1012BdBe603F144088A95C4B53", + ]), + ) + .add_contract(Contract::new("IUniswapV3Factory").with_networks(networks![ + MAINNET => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + GNOSIS => "0xe32F7dD7e3f098D518ff19A22d5f028e076489B1", + SEPOLIA => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + ARBITRUM_ONE => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + BASE => "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", + AVALANCHE => "0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD", + BNB => "0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7", + OPTIMISM => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + POLYGON => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + LINEA => "0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9", + PLASMA => "0xcb2436774C3e191c85056d248EF4260ce5f27A9D", + INK => "0x640887A9ba3A9C53Ed27D0F7e8246A4F933f3424", + ])) + .add_contract(Contract::new("HooksTrampoline").with_networks(networks![ + MAINNET => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + GNOSIS => "0x01DcB88678aedD0C4cC9552B20F4718550250574", + SEPOLIA => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + ARBITRUM_ONE => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + BASE => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + AVALANCHE => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + BNB => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + OPTIMISM => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + POLYGON => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + LINEA => "0x60bf78233f48ec42ee3f101b9a05ec7878728006", + PLASMA => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + INK => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + ])) + .add_contract(Contract::new("CoWSwapEthFlow").with_networks(networks![ + MAINNET => ("0x40a50cf069e992aa4536211b23f286ef88752187", 16169866), + GNOSIS => ("0x40a50cf069e992aa4536211b23f286ef88752187", 25414331), + SEPOLIA => ("0x0b7795E18767259CC253a2dF471db34c72B49516", 4718739), + ARBITRUM_ONE => ("0x6DFE75B5ddce1ADE279D4fa6BD6AeF3cBb6f49dB", 204747458), + BASE => ("0x3C3eA1829891BC9bEC3d06A81d5d169e52a415e3", 21490258), + AVALANCHE => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 60496408), + BNB => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 48411237), + OPTIMISM => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 134607215), + POLYGON => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 71296258), + LINEA => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 24522097), + PLASMA => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 3521855), + ])) + .add_contract(Contract::new("CoWSwapOnchainOrders")) + .add_contract(Contract::new("ERC1271SignatureValidator")) + .add_contract(Contract::new("BalancerQueries").with_networks(networks![ + MAINNET => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 15188261), + ARBITRUM_ONE => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 18238624), + OPTIMISM => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 15288107), + BASE => ("0x300Ab2038EAc391f26D9F895dc61F8F66a548833", 1205869), + GNOSIS => ("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e", 24821845), + POLYGON => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 30988035), + AVALANCHE => ("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD", 26387068), + ])) + .add_contract( + Contract::new("LiquoriceSettlement").with_networks(networks![ + MAINNET => "0x0448633eb8B0A42EfED924C42069E0DcF08fb552", + ARBITRUM_ONE => "0x0448633eb8B0A42EfED924C42069E0DcF08fb552", + ]), + ) + .add_contract(Contract::new("FlashLoanRouter").with_networks(networks![ + MAINNET => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + GNOSIS => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + SEPOLIA => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + ARBITRUM_ONE => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + BASE => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + POLYGON => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + AVALANCHE => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + BNB => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + OPTIMISM => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + LINEA => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + PLASMA => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + INK => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + ])) + .add_contract(Contract::new("Solver7702Delegate")) + .add_contract(Contract::new("ICowWrapper")) + .add_contract(Contract::new("ChainalysisOracle").with_networks(networks![ + MAINNET => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + ARBITRUM_ONE => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + BASE => "0x3A91A31cB3dC49b4db9Ce721F50a9D076c8D739B", + AVALANCHE => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + BNB => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + OPTIMISM => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + POLYGON => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + ])) + .add_contract(Contract::new("Permit2").with_networks(networks![ + MAINNET => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 15986406), + GNOSIS => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 27338672), + SEPOLIA => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 2356287), + ARBITRUM_ONE => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 38692735), + BASE => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 1425180), + AVALANCHE => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 28844415), + BNB => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 25343783), + OPTIMISM => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 38854427), + POLYGON => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 35701901), + PLASMA => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 7808), + INK => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 0), + ])) + .add_contract( + Contract::new("GPv2AllowListAuthentication").with_networks(networks![ + MAINNET => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 12593263), + GNOSIS => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 16465099), + SEPOLIA => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 4717469), + ARBITRUM_ONE => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 204702129), + BASE => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 21407137), + AVALANCHE => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 59891351), + BNB => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 48173639), + OPTIMISM => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 134254466), + POLYGON => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 45854728), + LINEA => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 24333100), + PLASMA => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 3439709), + INK => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 34436840), + ]), + ) + .add_contract(Contract::new("GPv2Settlement").with_networks(networks![ + MAINNET => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 12593265), + GNOSIS => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 16465100), + SEPOLIA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 4717488), + ARBITRUM_ONE => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 204704802), + BASE => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 21407238), + AVALANCHE => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 59891356), + BNB => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 48173641), + OPTIMISM => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 134254624), + POLYGON => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 45859743), + LINEA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 24333100), + PLASMA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 3439711), + INK => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 34436849), + ])) + .add_contract(Contract::new("WETH9").with_networks(networks![ + MAINNET => "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + GNOSIS => "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", + SEPOLIA => "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + ARBITRUM_ONE => "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + BASE => "0x4200000000000000000000000000000000000006", + AVALANCHE => "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", + BNB => "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + OPTIMISM => "0x4200000000000000000000000000000000000006", + POLYGON => "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", + LINEA => "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + PLASMA => "0x6100E367285b01F48D07953803A2d8dCA5D19873", + INK => "0x4200000000000000000000000000000000000006", + ])) + .add_submodule( + Submodule::new("cow_amm") + .add_contract(Contract::new("CowAmm")) + .add_contract(Contract::new("CowAmmConstantProductFactory").with_networks( + networks![ + MAINNET => ("0x40664207e3375FB4b733d4743CE9b159331fd034", 19861952), + GNOSIS => ("0xdb1cba3a87f2db53b6e1e6af48e28ed877592ec0", 33874317), + SEPOLIA => ("0xb808e8183e3a72d196457d127c7fd4befa0d7fd3", 5874562), + ], + )) + .add_contract(Contract::new("CowAmmLegacyHelper").with_networks(networks![ + MAINNET => ("0x3705ceee5eaa561e3157cf92641ce28c45a3999c", 20332745), + GNOSIS => ("0xd9ec06b001957498ab1bc716145515d1d0e30ffb", 35026999), + ])) + .add_contract(Contract::new("CowAmmUniswapV2PriceOracle")) + .add_contract(Contract::new("CowAmmFactoryGetter")), + ) + .add_submodule( + Submodule::new("test") + .add_contract(Contract::new("GasHog")) + .add_contract(Contract::new("Counter")) + .add_contract(Contract::new("MockERC4626Wrapper")) + .add_contract(Contract::new("CowProtocolToken").with_networks(networks![ + MAINNET => "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB", + GNOSIS => "0x177127622c4A00F3d409B75571e12cB3c8973d3c", + SEPOLIA => "0x0625aFB445C3B6B7B929342a04A22599fd5dBB59", + ARBITRUM_ONE => "0xcb8b5CD20BdCaea9a010aC1F8d835824F5C87A04", + BASE => "0xc694a91e6b071bF030A18BD3053A7fE09B6DaE69", + ])) + .add_contract(Contract::new("NonStandardERC20Balances")) + .add_contract(Contract::new("RemoteERC20Balances")), + ) + .add_submodule( + Submodule::new("support") + .add_contract(Contract::new("AnyoneAuthenticator")) + .add_contract(Contract::new("Solver")) + .add_contract(Contract::new("Spardose")) + .add_contract(Contract::new("Swapper")) + .add_contract(Contract::new("Signatures").with_networks(networks![ + MAINNET => "0x8262d639c38470F38d2eff15926F7071c28057Af", + ARBITRUM_ONE => "0x8262d639c38470F38d2eff15926F7071c28057Af", + BASE => "0x8262d639c38470F38d2eff15926F7071c28057Af", + AVALANCHE => "0x8262d639c38470F38d2eff15926F7071c28057Af", + BNB => "0x8262d639c38470F38d2eff15926F7071c28057Af", + OPTIMISM => "0x8262d639c38470F38d2eff15926F7071c28057Af", + POLYGON => "0x8262d639c38470F38d2eff15926F7071c28057Af", + GNOSIS => "0x8262d639c38470F38d2eff15926F7071c28057Af", + SEPOLIA => "0x8262d639c38470F38d2eff15926F7071c28057Af", + LINEA => "0xf6E57e72F7dB3D9A51a8B4c149C00475b94A37e4", + PLASMA => "0x8262d639c38470F38d2eff15926F7071c28057Af", + INK => "0x8262d639c38470F38d2eff15926F7071c28057Af", + ])) + .add_contract(Contract::new("Balances").with_networks(networks![ + MAINNET => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + ARBITRUM_ONE => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + BASE => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + AVALANCHE => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + BNB => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + OPTIMISM => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + POLYGON => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + GNOSIS => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + SEPOLIA => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + PLASMA => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + LINEA => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + INK => "0x88b4B74082BffB2976C306CB3f7E9093AE48B94F", + ])), + ) +} diff --git a/contracts/src/networks.rs b/contracts/src/networks.rs new file mode 100644 index 0000000000..1d8948644b --- /dev/null +++ b/contracts/src/networks.rs @@ -0,0 +1,12 @@ +pub const MAINNET: u64 = 1; +pub const GNOSIS: u64 = 100; +pub const SEPOLIA: u64 = 11155111; +pub const ARBITRUM_ONE: u64 = 42161; +pub const BASE: u64 = 8453; +pub const POLYGON: u64 = 137; +pub const AVALANCHE: u64 = 43114; +pub const BNB: u64 = 56; +pub const OPTIMISM: u64 = 10; +pub const LINEA: u64 = 59144; +pub const PLASMA: u64 = 9745; +pub const INK: u64 = 57073; diff --git a/crates/contracts/src/bin/vendor.rs b/contracts/src/vendor.rs similarity index 81% rename from crates/contracts/src/bin/vendor.rs rename to contracts/src/vendor.rs index bd58d0b377..b26b903b19 100644 --- a/crates/contracts/src/bin/vendor.rs +++ b/contracts/src/vendor.rs @@ -1,35 +1,16 @@ -//! This script is used to vendor Truffle JSON artifacts to be used for code -//! generation with `ethcontract`. This is done instead of fetching contracts -//! at build time to reduce the risk of failure. - use { anyhow::Result, - contracts::paths, - ethcontract_generate::Source, - serde_json::{Map, Value}, + reqwest::Url, + serde_json::{Map, Value, json}, std::{ fs, path::{Path, PathBuf}, }, - tracing_subscriber::EnvFilter, }; -fn main() { - tracing_subscriber::fmt::fmt() - .with_env_filter( - EnvFilter::try_from_env("LOG_FILTER").unwrap_or_else(|_| "warn,vendor=info".into()), - ) - .init(); - - if let Err(err) = run() { - tracing::error!("Error vendoring contracts: {:?}", err); - std::process::exit(-1); - } -} - #[rustfmt::skip] -fn run() -> Result<()> { - let vendor = Vendor::try_new()?; +pub fn run(artifacts_dir: &Path) -> Result<()> { + let vendor = Vendor::new(artifacts_dir)?; const ETHFLOW_VERSION: &str = "0.0.0-rc.3"; @@ -55,6 +36,11 @@ fn run() -> Result<()> { "balancer-labs/balancer-v2-monorepo/a3b570a2aa655d4c4941a67e3db6a06fbd72ef09/pkg/\ deployments/deployed/mainnet/WeightedPool2TokensFactory.json", )? + .github( + "Solver7702Delegate", + "cowprotocol/solver-7702-delegate/d2382297c6edee05b035ddcb285185d0938e038c/out/\ + Solver7702Delegate.sol/Solver7702Delegate.json", + )? .npm( "CowProtocolToken", "@cowprotocol/token@1.1.0/build/artifacts/src/contracts/CowProtocolToken.sol/\ @@ -181,6 +167,10 @@ fn run() -> Result<()> { "ERC1271SignatureValidator", "Manually vendored ABI for ERC-1271 signature validation", ) + .manual( + "IERC4626", + "Manually vendored ABI for ERC-4626 tokenized vault interface", + ) .npm( "IUniswapLikePair", "@uniswap/v2-periphery@1.1.0-beta.0/build/IUniswapV2Pair.json", @@ -224,11 +214,15 @@ struct Vendor { } impl Vendor { - fn try_new() -> Result { - let artifacts = paths::contract_artifacts_dir(); - tracing::info!("vendoring contract artifacts to '{}'", artifacts.display()); - fs::create_dir_all(&artifacts)?; - Ok(Self { artifacts }) + fn new(artifacts_dir: &Path) -> Result { + eprintln!( + "vendoring contract artifacts to '{}'", + artifacts_dir.display() + ); + fs::create_dir_all(artifacts_dir)?; + Ok(Self { + artifacts: artifacts_dir.to_path_buf(), + }) } /// Creates a context for vendoring "full" contract data, including bytecode @@ -262,6 +256,44 @@ impl Vendor { } } +struct Src(Url); + +impl Src { + fn npm(path: &str) -> Result { + Ok(Self(Url::parse(&format!("https://unpkg.com/{path}"))?)) + } + + fn github(path: &str) -> Result { + Ok(Self(Url::parse(&format!( + "https://raw.githubusercontent.com/{path}" + ))?)) + } + + fn fetch_json(self) -> Result { + let value = match reqwest::blocking::get(self.0)?.json::()? { + serde_json::Value::Array(values) => { + json!({"abi": values}) + } + value @ serde_json::Value::Object(_) => value, + value => { + eprintln!( + "warning: unexpected value format, expected an array or object, got {value:?}" + ); + value + } + }; + Ok(value) + } +} + +impl std::fmt::Debug for Src { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("Src") + .field("url", &self.0.as_str()) + .finish() + } +} + struct VendorContext<'a> { artifacts: &'a Path, properties: &'a [(&'a str, &'a str)], @@ -269,20 +301,15 @@ struct VendorContext<'a> { impl VendorContext<'_> { fn npm(&self, name: &str, path: &str) -> Result<&Self> { - self.vendor_source(name, Source::npm(path)) + self.vendor_source(name, Src::npm(path)?) } fn github(&self, name: &str, path: &str) -> Result<&Self> { - self.vendor_source( - name, - Source::http(&format!("https://raw.githubusercontent.com/{path}"))?, - ) + self.vendor_source(name, Src::github(path)?) } fn manual(&self, name: &str, reason: &str) -> &Self { - // We just keep these here to document that they are manually generated - // and not pulled from some source. - tracing::info!("skipping {}: {}", name, reason); + eprintln!(" skipping {name}: {reason}"); self } @@ -294,28 +321,25 @@ impl VendorContext<'_> { current_value.clone() } - fn vendor_source(&self, name: &str, source: Source) -> Result<&Self> { - tracing::info!("retrieving {:?}", source); - let artifact_json = source.artifact_json()?; + fn vendor_source(&self, name: &str, source: Src) -> Result<&Self> { + eprintln!(" fetching {source:?}"); + let artifact_json = source.fetch_json()?; - tracing::debug!("pruning artifact JSON"); let pruned_artifact_json = { - let json = serde_json::from_str::(&artifact_json)?; let mut pruned = Map::new(); for (property, paths) in self.properties { if let Some(value) = paths .split(',') - .map(|path| Self::retrieve_value_from_path(&json, path)) + .map(|path| Self::retrieve_value_from_path(&artifact_json, path)) .find(|value| !value.is_null()) { pruned.insert(property.to_string(), value); } } - serde_json::to_string(&pruned)? + serde_json::to_string_pretty(&pruned)? }; let path = self.artifacts.join(name).with_extension("json"); - tracing::debug!("saving artifact to {}", path.display()); fs::write(path, pruned_artifact_json)?; Ok(self) diff --git a/crates/account-balances/Cargo.toml b/crates/account-balances/Cargo.toml new file mode 100644 index 0000000000..33bc1d3422 --- /dev/null +++ b/crates/account-balances/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "account-balances" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-contract = { workspace = true } +alloy-dyn-abi = { workspace = true } +alloy-primitives = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +balance-overrides = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +futures = { workspace = true } +itertools = { workspace = true } +mockall = { workspace = true, optional = true } +model = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +mockall = { workspace = true } + +[features] +test-util = ["dep:mockall"] + +[lints] +workspace = true diff --git a/crates/account-balances/LICENSE-APACHE b/crates/account-balances/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/account-balances/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/account-balances/LICENSE-MIT b/crates/account-balances/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/account-balances/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/shared/src/account_balances/cached.rs b/crates/account-balances/src/cached.rs similarity index 91% rename from crates/shared/src/account_balances/cached.rs rename to crates/account-balances/src/cached.rs index 4f87854ef0..f06362a29e 100644 --- a/crates/shared/src/account_balances/cached.rs +++ b/crates/account-balances/src/cached.rs @@ -1,10 +1,10 @@ use { - crate::account_balances::{BalanceFetching, Query, TransferSimulationError}, + crate::{BalanceFetching, Query, TransferSimulationError}, + alloy_primitives::U256, anyhow::Result, ethrpc::block_stream::{CurrentBlockWatcher, into_stream}, futures::StreamExt, itertools::Itertools, - primitive_types::U256, std::{ collections::HashMap, sync::{Arc, Mutex}, @@ -201,16 +201,16 @@ impl BalanceFetching for Balances { mod tests { use { super::*, - crate::account_balances::MockBalanceFetching, - ethcontract::H160, + crate::MockBalanceFetching, + alloy_primitives::Address, ethrpc::block_stream::BlockInfo, model::order::SellTokenSource, }; fn query(token: u8) -> Query { Query { - owner: H160([1; 20]), - token: H160([token; 20]), + owner: Address::repeat_byte(1), + token: Address::repeat_byte(token), source: SellTokenSource::Erc20, interactions: vec![], balance_override: None, @@ -224,15 +224,15 @@ mod tests { .expect_get_balances() .times(1) .withf(|arg| arg == [query(1)]) - .returning(|_| vec![Ok(1.into())]); + .returning(|_| vec![Ok(U256::ONE)]); let fetcher = Balances::new(Arc::new(inner)); // 1st call to `inner`. let result = fetcher.get_balances(&[query(1)]).await; - assert_eq!(result[0].as_ref().unwrap(), &1.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::ONE); // Fetches balance from cache and skips calling `inner`. let result = fetcher.get_balances(&[query(1)]).await; - assert_eq!(result[0].as_ref().unwrap(), &1.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::ONE); } #[tokio::test] @@ -261,14 +261,14 @@ mod tests { .expect_get_balances() .times(2) .withf(|arg| arg == [query(1)]) - .returning(|_| vec![Ok(U256::one())]); + .returning(|_| vec![Ok(U256::ONE)]); let fetcher = Balances::new(Arc::new(inner)); fetcher.spawn_background_task(receiver); // 1st call to `inner`. Balance gets cached. let result = fetcher.get_balances(&[query(1)]).await; - assert_eq!(result[0].as_ref().unwrap(), &1.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::ONE); // New block gets detected. sender @@ -283,7 +283,7 @@ mod tests { // Balance was already updated so this will hit the cache and skip calling // `inner`. let result = fetcher.get_balances(&[query(1)]).await; - assert_eq!(result[0].as_ref().unwrap(), &1.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::ONE); } #[tokio::test] @@ -293,26 +293,26 @@ mod tests { .expect_get_balances() .times(1) .withf(|arg| arg == [query(1)]) - .returning(|_| vec![Ok(1.into())]); + .returning(|_| vec![Ok(U256::ONE)]); inner .expect_get_balances() .times(1) .withf(|arg| arg == [query(2)]) - .returning(|_| vec![Ok(2.into())]); + .returning(|_| vec![Ok(U256::from(2))]); let fetcher = Balances::new(Arc::new(inner)); // 1st call to `inner` putting balance 1 into the cache. let result = fetcher.get_balances(&[query(1)]).await; - assert_eq!(result[0].as_ref().unwrap(), &1.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::ONE); // Fetches balance 1 from cache and balance 2 fresh. (2nd call to `inner`) let result = fetcher.get_balances(&[query(1), query(2)]).await; - assert_eq!(result[0].as_ref().unwrap(), &1.into()); - assert_eq!(result[1].as_ref().unwrap(), &2.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::ONE); + assert_eq!(result[1].as_ref().unwrap(), &U256::from(2)); // Now balance 2 is also in the cache. Skipping call to `inner`. let result = fetcher.get_balances(&[query(2)]).await; - assert_eq!(result[0].as_ref().unwrap(), &2.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::from(2)); } #[tokio::test] @@ -324,7 +324,7 @@ mod tests { inner .expect_get_balances() .times(7) - .returning(|_| vec![Ok(U256::one())]); + .returning(|_| vec![Ok(U256::ONE)]); let fetcher = Balances::new(Arc::new(inner)); fetcher.spawn_background_task(receiver); @@ -337,7 +337,7 @@ mod tests { assert!(cached_entry().is_none()); // 1st call to `inner`. Balance gets cached. let result = fetcher.get_balances(&[query(1)]).await; - assert_eq!(result[0].as_ref().unwrap(), &1.into()); + assert_eq!(result[0].as_ref().unwrap(), &U256::ONE); for block in 1..=EVICTION_TIME + 1 { assert!(cached_entry().is_some()); diff --git a/crates/shared/src/account_balances/mod.rs b/crates/account-balances/src/lib.rs similarity index 68% rename from crates/shared/src/account_balances/mod.rs rename to crates/account-balances/src/lib.rs index 2f8a2be1c1..0eaf66ce16 100644 --- a/crates/shared/src/account_balances/mod.rs +++ b/crates/account-balances/src/lib.rs @@ -1,23 +1,15 @@ use { - crate::price_estimation::trade_verifier::balance_overrides::{ - BalanceOverrideRequest, - BalanceOverriding, - }, - alloy::sol_types::{SolCall, SolType, sol_data}, - contracts::alloy::{GPv2Settlement, support::Balances}, - ethcontract::state_overrides::StateOverrides, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, + alloy_primitives::{Address, U256}, + alloy_rpc_types::state::StateOverride, + alloy_sol_types::{SolCall, SolType, sol_data}, + balance_overrides::{BalanceOverrideRequest, StateOverriding}, + contracts::{GPv2Settlement, support::Balances}, + ethrpc::{Web3, block_stream::CurrentBlockWatcher}, model::{ interaction::InteractionData, order::{Order, SellTokenSource}, }, - primitive_types::{H160, U256}, - std::sync::Arc, - thiserror::Error, + std::sync::{Arc, LazyLock}, }; mod cached; @@ -25,8 +17,8 @@ mod simulation; #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Query { - pub owner: H160, - pub token: H160, + pub owner: Address, + pub token: Address, pub source: SellTokenSource, pub interactions: Vec, pub balance_override: Option, @@ -35,8 +27,8 @@ pub struct Query { impl Query { pub fn from_order(o: &Order) -> Self { Self { - owner: o.metadata.owner.into_legacy(), - token: o.data.sell_token.into_legacy(), + owner: o.metadata.owner, + token: o.data.sell_token, source: o.data.sell_token_balance, interactions: o.interactions.pre.clone(), // TODO eventually delete together with the balance @@ -50,7 +42,7 @@ impl Query { pub enum TransferSimulationError { InsufficientAllowance, InsufficientBalance, - TransferFailed, + TransferFailed(Vec), Other(anyhow::Error), } @@ -100,18 +92,18 @@ pub fn cached( pub struct BalanceSimulator { settlement: GPv2Settlement::Instance, balances: Balances::Instance, - vault_relayer: H160, - vault: H160, - balance_overrider: Arc, + vault_relayer: Address, + vault: Address, + balance_overrider: Arc, } impl BalanceSimulator { pub fn new( settlement: GPv2Settlement::Instance, balances: Balances::Instance, - vault_relayer: H160, - vault: Option, - balance_overrider: Arc, + vault_relayer: Address, + vault: Option
, + balance_overrider: Arc, ) -> Self { Self { settlement, @@ -122,27 +114,27 @@ impl BalanceSimulator { } } - pub fn vault_relayer(&self) -> H160 { + pub fn vault_relayer(&self) -> Address { self.vault_relayer } - pub fn vault(&self) -> H160 { + pub fn vault(&self) -> Address { self.vault } pub async fn simulate( &self, - owner: H160, - token: H160, + owner: Address, + token: Address, source: SellTokenSource, interactions: &[InteractionData], amount: Option, balance_override: Option, ) -> Result { - let overrides: StateOverrides = match balance_override { + let overrides: StateOverride = match balance_override { Some(overrides) => self .balance_overrider - .state_override(overrides) + .balance_override(overrides) .await .into_iter() .collect(), @@ -158,12 +150,12 @@ impl BalanceSimulator { let balance_call = Balances::Balances::balanceCall { contracts: Balances::Balances::Contracts { settlement: *self.settlement.address(), - vaultRelayer: self.vault_relayer.into_alloy(), - vault: self.vault.into_alloy(), + vaultRelayer: self.vault_relayer, + vault: self.vault, }, - trader: owner.into_alloy(), - token: token.into_alloy(), - amount: amount.unwrap_or_default().into_alloy(), + trader: owner, + token, + amount: amount.unwrap_or_default(), source: source.as_bytes().into(), interactions: interactions .iter() @@ -179,28 +171,30 @@ impl BalanceSimulator { .settlement .simulateDelegatecall(*self.balances.address(), balance_call.abi_encode().into()) .with_cloned_provider() - .state(overrides.into_alloy()) - .from(crate::SIMULATION_ACCOUNT.clone().address().into_alloy()) + .state(overrides) + .from(*SIMULATION_ACCOUNT) .call() .await?; - let (token_balance, allowance, effective_balance, can_transfer) = + let (token_balance, allowance, effective_balance, can_transfer, transfer_revert_reason) = <( sol_data::Uint<256>, sol_data::Uint<256>, sol_data::Uint<256>, sol_data::Bool, - )>::abi_decode(&response.0) + sol_data::Bytes, + )>::abi_decode_params(&response.0) .map_err(|err| { tracing::error!(?err, "failed to decode balance response"); - web3::error::Error::Decoder("failed to decode balance response".to_string()) + alloy_contract::Error::AbiError(alloy_dyn_abi::Error::SolTypes(err)) })?; let simulation = Simulation { - token_balance: U256::from_little_endian(&token_balance.as_le_bytes()), - allowance: U256::from_little_endian(&allowance.as_le_bytes()), - effective_balance: U256::from_little_endian(&effective_balance.as_le_bytes()), + token_balance: U256::from_le_slice(&token_balance.as_le_bytes()), + allowance: U256::from_le_slice(&allowance.as_le_bytes()), + effective_balance: U256::from_le_slice(&effective_balance.as_le_bytes()), can_transfer, + transfer_revert_reason: transfer_revert_reason.to_vec(), }; tracing::trace!( @@ -222,12 +216,30 @@ pub struct Simulation { pub allowance: U256, pub effective_balance: U256, pub can_transfer: bool, + pub transfer_revert_reason: Vec, } -#[derive(Debug, Error)] +#[derive(Debug)] pub enum SimulationError { - #[error("method error: {0:?}")] - Method(#[from] alloy::contract::Error), - #[error("web3 error: {0:?}")] - Web3(#[from] web3::error::Error), + Method(alloy_contract::Error), +} + +impl std::fmt::Display for SimulationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Method(err) => write!(f, "method error: {err:?}"), + } + } +} + +impl std::error::Error for SimulationError {} + +impl From for SimulationError { + fn from(err: alloy_contract::Error) -> Self { + Self::Method(err) + } } + +// ZKSync-based chains don't use the default 0x0 account when `tx.from` is not +// specified, so we need to use a random account when sending a simulation tx. +static SIMULATION_ACCOUNT: LazyLock
= LazyLock::new(|| Address::random()); diff --git a/crates/shared/src/account_balances/simulation.rs b/crates/account-balances/src/simulation.rs similarity index 67% rename from crates/shared/src/account_balances/simulation.rs rename to crates/account-balances/src/simulation.rs index e0319989cc..b4f3ebe857 100644 --- a/crates/shared/src/account_balances/simulation.rs +++ b/crates/account-balances/src/simulation.rs @@ -4,14 +4,11 @@ use { super::{BalanceFetching, Query, TransferSimulationError}, - crate::account_balances::BalanceSimulator, + crate::BalanceSimulator, + alloy_primitives::{Address, U256}, anyhow::Result, - contracts::alloy::{BalancerV2Vault::BalancerV2Vault, ERC20}, - ethcontract::{H160, U256}, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - }, + contracts::{BalancerV2Vault::BalancerV2Vault, ERC20}, + ethrpc::{Web3, alloy::ProviderLabelingExt}, futures::future, model::order::SellTokenSource, tracing::instrument, @@ -31,7 +28,7 @@ impl Balances { // contracts exist at addresses that get called. This allows us to // properly check if the `source` is not supported for the deployment // work without additional code paths :tada:! - let web3 = ethrpc::instrumented::instrument_with_label(web3, "balanceFetching".into()); + let web3 = web3.labeled("balanceFetching"); Self { web3, @@ -39,11 +36,11 @@ impl Balances { } } - fn vault_relayer(&self) -> H160 { + fn vault_relayer(&self) -> Address { self.balance_simulator.vault_relayer } - fn vault(&self) -> H160 { + fn vault(&self) -> Address { self.balance_simulator.vault } @@ -62,7 +59,7 @@ impl Balances { Ok(if simulation.can_transfer { simulation.effective_balance } else { - U256::zero() + U256::ZERO }) } @@ -73,24 +70,19 @@ impl Balances { ) -> Result { let usable_balance = match query.source { SellTokenSource::Erc20 => { - let balance = token.balanceOf(query.owner.into_alloy()); - let allowance = - token.allowance(query.owner.into_alloy(), self.vault_relayer().into_alloy()); + let balance = token.balanceOf(query.owner); + let allowance = token.allowance(query.owner, self.vault_relayer()); let (balance, allowance) = futures::try_join!( balance.call().into_future(), allowance.call().into_future() )?; - std::cmp::min(balance, allowance).into_legacy() + std::cmp::min(balance, allowance) } SellTokenSource::External => { - let vault = BalancerV2Vault::new(self.vault().into_alloy(), &self.web3.alloy); - let balance = token.balanceOf(query.owner.into_alloy()); - let approved = vault.hasApprovedRelayer( - query.owner.into_alloy(), - self.vault_relayer().into_alloy(), - ); - let allowance = - token.allowance(query.owner.into_alloy(), self.vault().into_alloy()); + let vault = BalancerV2Vault::new(self.vault(), &self.web3.provider); + let balance = token.balanceOf(query.owner); + let approved = vault.hasApprovedRelayer(query.owner, self.vault_relayer()); + let allowance = token.allowance(query.owner, self.vault()); let (balance, approved, allowance) = futures::try_join!( balance.call().into_future(), approved.call().into_future(), @@ -98,27 +90,21 @@ impl Balances { )?; match approved { true => std::cmp::min(balance, allowance), - false => alloy::primitives::U256::ZERO, + false => U256::ZERO, } - .into_legacy() } SellTokenSource::Internal => { - let vault = BalancerV2Vault::new(self.vault().into_alloy(), &self.web3.alloy); - let balance = vault - .getInternalBalance(query.owner.into_alloy(), vec![query.token.into_alloy()]); - let approved = vault.hasApprovedRelayer( - query.owner.into_alloy(), - self.vault_relayer().into_alloy(), - ); + let vault = BalancerV2Vault::new(self.vault(), &self.web3.provider); + let balance = vault.getInternalBalance(query.owner, vec![query.token]); + let approved = vault.hasApprovedRelayer(query.owner, self.vault_relayer()); let (balance, approved) = futures::try_join!( balance.call().into_future(), approved.call().into_future() )?; match approved { true => balance[0], // internal approvals are always U256::MAX - false => alloy::primitives::U256::ZERO, + false => U256::ZERO, } - .into_legacy() } }; Ok(usable_balance) @@ -134,8 +120,7 @@ impl BalanceFetching for Balances { .iter() .map(|query| async { if query.interactions.is_empty() { - let token = - ERC20::Instance::new(query.token.into_alloy(), self.web3.alloy.clone()); + let token = ERC20::Instance::new(query.token, self.web3.provider.clone()); self.tradable_balance_simple(query, &token).await } else { self.tradable_balance_simulated(query).await @@ -171,7 +156,9 @@ impl BalanceFetching for Balances { return Err(TransferSimulationError::InsufficientAllowance); } if !simulation.can_transfer { - return Err(TransferSimulationError::TransferFailed); + return Err(TransferSimulationError::TransferFailed( + simulation.transfer_revert_reason, + )); } Ok(()) @@ -182,9 +169,9 @@ impl BalanceFetching for Balances { mod tests { use { super::*, - crate::price_estimation::trade_verifier::balance_overrides::DummyOverrider, - alloy::primitives::address, - contracts::alloy::GPv2Settlement, + alloy_primitives::address, + balance_overrides::DummyStateOverrider, + contracts::GPv2Settlement, ethrpc::Web3, model::order::SellTokenSource, std::sync::Arc, @@ -195,27 +182,27 @@ mod tests { async fn test_for_user() { let web3 = Web3::new_from_env(); let settlement = GPv2Settlement::GPv2Settlement::new( - alloy::primitives::address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), - web3.alloy.clone(), + address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + web3.provider.clone(), ); - let balances = contracts::alloy::support::Balances::Instance::new( + let balances = contracts::support::Balances::Instance::new( address!("3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - web3.alloy.clone(), + web3.provider.clone(), ); let balances = Balances::new( &web3, BalanceSimulator::new( settlement, balances, - addr!("C92E8bdf79f0507f65a392b0ab4667716BFE0110"), - Some(addr!("BA12222222228d8Ba445958a75a0704d566BF2C8")), - Arc::new(DummyOverrider), + address!("C92E8bdf79f0507f65a392b0ab4667716BFE0110"), + Some(address!("BA12222222228d8Ba445958a75a0704d566BF2C8")), + Arc::new(DummyStateOverrider), ), ); - let owner = addr!("b0a4e99371dfb0734f002ae274933b4888f618ef"); - let token = addr!("d909c5862cdb164adb949d92622082f0092efc3d"); - let amount = 50000000000000000000000_u128.into(); + let owner = address!("b0a4e99371dfb0734f002ae274933b4888f618ef"); + let token = address!("d909c5862cdb164adb949d92622082f0092efc3d"); + let amount = U256::from(50000000000000000000000_u128); let source = SellTokenSource::Erc20; balances diff --git a/crates/alerter/Cargo.toml b/crates/alerter/Cargo.toml deleted file mode 100644 index b7b1f89a69..0000000000 --- a/crates/alerter/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "alerter" -version = "0.1.0" -authors = ["Gnosis Developers ", "Cow Protocol Developers "] -edition = "2024" -license = "MIT OR Apache-2.0" - -[dependencies] -alloy = { workspace = true } -anyhow = { workspace = true } -clap = { workspace = true } -humantime = { workspace = true } -observe = { workspace = true } -mimalloc = { workspace = true } -model = { workspace = true } -number = { workspace = true } -prometheus = { workspace = true } -reqwest = { workspace = true, features = ["json"] } -serde_with = { workspace = true } -serde = { workspace = true } -shared = { workspace = true } -tokio = { workspace = true, features = ["macros", "time", "rt-multi-thread"] } -tracing = { workspace = true } -url = { workspace = true } -warp = { workspace = true } - -[lints] -workspace = true diff --git a/crates/alerter/src/lib.rs b/crates/alerter/src/lib.rs deleted file mode 100644 index fe6d412428..0000000000 --- a/crates/alerter/src/lib.rs +++ /dev/null @@ -1,435 +0,0 @@ -// This application observes the order book api and tries to determine if the -// solver is down. It does this by checking if no trades have been made recently -// and if so checking if it finds a matchable order according to an external -// price api (0x). If this is the case it alerts. - -use { - alloy::primitives::{Address, U256, address}, - anyhow::{Context, Result}, - clap::Parser, - model::order::{BUY_ETH_ADDRESS, OrderClass, OrderKind, OrderStatus, OrderUid}, - number::serialization::HexOrDecimalU256, - prometheus::IntGauge, - reqwest::Client, - serde_with::serde_as, - std::{ - collections::HashMap, - time::{Duration, Instant}, - }, - url::Url, -}; - -#[serde_as] -#[derive(Debug, serde::Deserialize, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -struct Order { - kind: OrderKind, - buy_token: Address, - #[serde_as(as = "HexOrDecimalU256")] - buy_amount: U256, - sell_token: Address, - #[serde_as(as = "HexOrDecimalU256")] - sell_amount: U256, - uid: OrderUid, - partially_fillable: bool, - #[serde(flatten)] - class: OrderClass, - // Some if the order is fetched from api/v1/orders/{uid} - // None if the order is fetched from api/v1/auction - #[serde(default)] - status: Option, -} - -impl Order { - fn is_liquidity_order(&self) -> bool { - matches!(self.class, OrderClass::Liquidity) - } -} - -struct OrderBookApi { - base: Url, - client: Client, -} - -impl OrderBookApi { - pub fn new(client: Client, base_url: &str) -> Self { - Self { - base: base_url.parse().unwrap(), - client, - } - } - - pub async fn solvable_orders(&self) -> reqwest::Result> { - #[derive(serde::Deserialize)] - struct Auction { - orders: Vec, - } - let url = shared::url::join(&self.base, "api/v1/auction"); - let auction: Auction = self - .client - .get(url) - .send() - .await? - .error_for_status()? - .json() - .await?; - Ok(auction.orders) - } - - pub async fn order(&self, uid: &OrderUid) -> reqwest::Result { - let url = shared::url::join(&self.base, &format!("api/v1/orders/{uid}")); - self.client - .get(url) - .send() - .await? - .error_for_status()? - .json() - .await - } -} - -// Converts the eth placeholder address to weth. Leaves other addresses -// untouched. -fn convert_eth_to_weth(token: Address) -> Address { - const WETH: Address = address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); - if token.as_slice() == BUY_ETH_ADDRESS.as_bytes() { - WETH - } else { - token - } -} - -struct ZeroExApi { - base: Url, - client: Client, - api_key: String, -} - -impl ZeroExApi { - pub fn new(client: Client, api_key: String) -> Self { - Self { - base: "https://api.0x.org".parse().unwrap(), - client, - api_key, - } - } - - pub async fn can_be_settled(&self, order: &Order) -> Result { - let mut url = shared::url::join(&self.base, "swap/v1/price"); - - let (amount_name, amount) = match order.kind { - OrderKind::Buy => ("buyAmount", order.buy_amount), - OrderKind::Sell => ("sellAmount", order.sell_amount), - }; - - let buy_token = convert_eth_to_weth(order.buy_token); - url.query_pairs_mut() - .append_pair("sellToken", &format!("{:#x}", order.sell_token)) - .append_pair("buyToken", &format!("{buy_token:#x}")) - .append_pair(amount_name, &amount.to_string()); - - #[serde_as] - #[derive(Debug, serde::Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct Response { - #[serde_as(as = "HexOrDecimalU256")] - pub sell_amount: U256, - #[serde_as(as = "HexOrDecimalU256")] - pub buy_amount: U256, - } - - let response: Response = self - .client - .get(url.clone()) - .header("0x-api-key", self.api_key.clone()) - .send() - .await? - .error_for_status()? - .json() - .await?; - - tracing::debug!(url = url.as_str(), ?response, "0x"); - - let can_settle = - response.sell_amount <= order.sell_amount && response.buy_amount >= order.buy_amount; - if can_settle { - tracing::debug!(%order.uid, "marking order as settleable"); - } - - Ok(can_settle) - } -} - -struct Alerter { - orderbook_api: OrderBookApi, - zeroex_api: ZeroExApi, - config: AlertConfig, - last_observed_trade: Instant, - last_alert: Option, - // order and for how long it has been matchable - open_orders: HashMap)>, - // Expose a prometheus metric so that we can use our Grafana alert infrastructure. - // - // Set to 0 or 1 depending on whether our alert condition is satisfied which is that there - // hasn't been a trade for some time and that there is an order that has been matchable for - // some time. - no_trades_but_matchable_order: IntGauge, - api_get_order_min_interval: Duration, -} - -struct AlertConfig { - // Alert if no trades have been observed for this long. - time_without_trade: Duration, - // Give the solver some time to settle an order after it has become solvable before we alert. - min_order_solvable_time: Duration, - // Do not alert more often than this. - min_alert_interval: Duration, -} - -impl Alerter { - pub fn new( - orderbook_api: OrderBookApi, - zeroex_api: ZeroExApi, - config: AlertConfig, - api_get_order_min_interval: Duration, - ) -> Self { - let registry = observe::metrics::get_registry(); - let no_trades_but_matchable_order = - IntGauge::new("no_trades_but_matchable_order", "0 or 1").unwrap(); - registry - .register(Box::new(no_trades_but_matchable_order.clone())) - .unwrap(); - Self { - orderbook_api, - zeroex_api, - config, - last_observed_trade: Instant::now(), - last_alert: None, - open_orders: HashMap::new(), - no_trades_but_matchable_order, - api_get_order_min_interval, - } - } - - async fn update_open_orders(&mut self) -> Result<()> { - let mut orders = self - .orderbook_api - .solvable_orders() - .await - .context("solvable_orders")? - .into_iter() - .filter(|order| !order.is_liquidity_order() && !order.partially_fillable) - .map(|order| { - let existing_time = self.open_orders.get(&order.uid).and_then(|o| o.1); - (order.uid, (order, existing_time)) - }) - .collect::>(); - - tracing::debug!("found {} open orders", orders.len()); - - std::mem::swap(&mut self.open_orders, &mut orders); - let mut closed_orders: Vec = orders.into_values().map(|(order, _)| order).collect(); - // Keep only orders that were open last update and are not open this update. - closed_orders.retain(|order| !self.open_orders.contains_key(&order.uid)); - // We're trying to find an order that has been filled. Try market orders first - // because they are more likely to be. - closed_orders.sort_unstable_by_key(|order| match order.class { - OrderClass::Market => 0u8, - OrderClass::Limit => 1, - OrderClass::Liquidity => 2, - }); - for order in closed_orders { - let uid = &order.uid; - tracing::debug!(order =% uid, "found closed order"); - let start = Instant::now(); - let api_order = self.orderbook_api.order(uid).await.context("get order")?; - if api_order.status.unwrap() == OrderStatus::Fulfilled { - tracing::debug!( - "updating last observed trade because order {} was fulfilled", - uid - ); - self.last_observed_trade = Instant::now(); - break; - } - tokio::time::sleep_until((start + self.api_get_order_min_interval).into()).await; - } - tracing::debug!("found no fulfilled orders"); - Ok(()) - } - - pub async fn update(&mut self) -> Result<()> { - self.update_open_orders().await?; - if self.last_observed_trade.elapsed() <= self.config.time_without_trade { - self.no_trades_but_matchable_order.set(0); - // Delete all matchable timestamps. - // - // If we didn't do this what could happen is that first we mark an order as - // matchable at t0. Then a trade happens so we skip the matchable - // update loop below because if there was a recent trade we don't - // want to alert anyway. Then no trade happens for long enough that - // we want to alert and the order is again matchable. In this case - // we would alert immediately even though it could be the case that the - // order wasn't matchable and just now became matchable again. We would wrongly - // assume it has been matchable since t0 but we did not check this - // between now and then. - for (_, instant) in self.open_orders.values_mut() { - *instant = None; - } - return Ok(()); - } - - for (order, last_solvable) in self.open_orders.values_mut() { - let can_be_settled = self - .zeroex_api - .can_be_settled(order) - .await - .context("can_be_settled")?; - let now = Instant::now(); - if can_be_settled { - let solvable_since = *last_solvable.get_or_insert(now); - if now.duration_since(solvable_since) > self.config.min_order_solvable_time { - let should_alert = match self.last_alert { - None => true, - Some(instant) => instant.elapsed() >= self.config.min_alert_interval, - }; - if should_alert { - self.last_alert = Some(now); - self.config.alert(&order.uid); - } - self.no_trades_but_matchable_order.set(1); - } - return Ok(()); - } else { - *last_solvable = None; - } - } - - self.no_trades_but_matchable_order.set(0); - Ok(()) - } -} - -impl AlertConfig { - fn alert(&self, order_uid: &OrderUid) { - tracing::error!( - "No orders have been settled in the last {} seconds even though order {} is solvable \ - and has a price that allows it to be settled according to 0x.", - self.time_without_trade.as_secs(), - order_uid, - ); - } -} - -#[derive(Debug, Parser)] -struct Arguments { - /// Alerter update interval. - #[clap( - long, - env, - default_value = "30s", - value_parser = humantime::parse_duration, - )] - update_interval: Duration, - - /// Minimum time without a trade before alerting. - #[clap( - long, - env, - default_value = "10m", - value_parser = humantime::parse_duration, - )] - time_without_trade: Duration, - - /// Minimum time an order must have been matchable for before alerting. - #[clap( - long, - env, - default_value = "3m", - value_parser = humantime::parse_duration, - )] - min_order_age: Duration, - - /// Do not repeat the alert more often than this. - #[clap( - long, - env, - default_value = "30m", - value_parser = humantime::parse_duration, - )] - min_alert_interval: Duration, - - /// How many errors in the update loop (fetching solvable orders or querying - /// 0x) in a row must happen before we alert about them. - #[clap(long, env, default_value = "5")] - errors_in_a_row_before_alert: u32, - - #[clap(long, env, default_value = "https://api.cow.fi/mainnet/")] - orderbook_api: String, - - #[clap(long, env, default_value = "9588")] - metrics_port: u16, - - /// Minimum time between get order requests to the api. Without this the api - /// can rate limit us. - #[clap(long, env, default_value = "200ms", value_parser = humantime::parse_duration)] - api_get_order_min_interval: Duration, - - #[clap(long, env)] - zero_ex_api_key: String, - - /// Whether to use JSON format for the logs. - #[clap(long, env, default_value = "false")] - pub use_json_logs: bool, -} - -pub async fn start(args: impl Iterator) { - let args = Arguments::parse_from(args); - let obs_config = observe::Config::new( - "alerter=debug", - tracing::Level::ERROR.into(), - args.use_json_logs, - None, - ); - observe::tracing::initialize(&obs_config); - observe::panic_hook::install(); - observe::metrics::setup_registry(Some("gp_v2_alerter".to_string()), None); - tracing::info!("running alerter with {:#?}", args); - run(args).await; -} - -async fn run(args: Arguments) { - let filter = observe::metrics::handle_metrics(); - tokio::task::spawn(warp::serve(filter).bind(([0, 0, 0, 0], args.metrics_port))); - - let client = Client::builder() - .timeout(Duration::from_secs(10)) - .build() - .unwrap(); - - let mut alerter = Alerter::new( - OrderBookApi::new(client.clone(), &args.orderbook_api), - ZeroExApi::new(client, args.zero_ex_api_key), - AlertConfig { - time_without_trade: args.time_without_trade, - min_order_solvable_time: args.min_order_age, - min_alert_interval: args.min_alert_interval, - }, - args.api_get_order_min_interval, - ); - - let mut errors_in_a_row = 0; - loop { - match alerter.update().await { - Ok(()) => errors_in_a_row = 0, - Err(err) if errors_in_a_row < args.errors_in_a_row_before_alert => { - errors_in_a_row += 1; - tracing::warn!(?err, "alerter update error"); - } - Err(err) => { - errors_in_a_row = 0; - tracing::error!(?err, "alerter update error"); - } - } - tokio::time::sleep(args.update_interval).await; - } -} diff --git a/crates/alerter/src/main.rs b/crates/alerter/src/main.rs deleted file mode 100644 index 73a70ddf51..0000000000 --- a/crates/alerter/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -#[tokio::main] -async fn main() { - alerter::start(std::env::args()).await; -} diff --git a/crates/app-data/Cargo.toml b/crates/app-data/Cargo.toml index af274dceda..1658ab82e8 100644 --- a/crates/app-data/Cargo.toml +++ b/crates/app-data/Cargo.toml @@ -6,18 +6,18 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] -alloy = { workspace = true, features = ["serde"] } +alloy-primitives = { workspace = true, features = ["serde"] } anyhow = { workspace = true } bytes-hex = { workspace = true } const-hex = { workspace = true } -hex-literal = { workspace = true } +moka = { workspace = true, features = ["sync"] } number = { path = "../number" } serde = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } -tiny-keccak = { workspace = true, features = ["keccak"] } [dev-dependencies] +hex-literal = { workspace = true } [features] test_helpers = [] diff --git a/crates/app-data/src/app_data.rs b/crates/app-data/src/app_data.rs index 0f997acf51..ea27b2563d 100644 --- a/crates/app-data/src/app_data.rs +++ b/crates/app-data/src/app_data.rs @@ -1,8 +1,9 @@ use { crate::{AppDataHash, Hooks, app_data_hash::hash_full_app_data}, - alloy::primitives::{Address, U256}, - anyhow::{Context, Result, anyhow}, + alloy_primitives::{Address, U256}, + anyhow::{Result, anyhow}, bytes_hex::BytesHex, + moka::sync::Cache, number::serialization::HexOrDecimalU256, serde::{Deserialize, Deserializer, Serialize, Serializer, de}, serde_with::serde_as, @@ -137,45 +138,58 @@ impl<'de> Deserialize<'de> for FeePolicy { where D: Deserializer<'de>, { + // The untagged enum does not provide enough information when deserialization + // fails since it thinks that any unknown or mismatched fields are just + // an issue with the enum variant which the error will reflect — + // something among the lines of "did not match any variant of the untagged enum" + // This is an hacky way of ensuring we get proper behavior when failing to + // deserialize numbers, for example, when users send bps as floats #[derive(Deserialize)] - #[serde(untagged)] - enum Helper { - #[serde(rename_all = "camelCase")] - Surplus { - surplus_bps: u64, - max_volume_bps: u64, - }, - #[serde(rename_all = "camelCase")] - PriceImprovement { - price_improvement_bps: u64, - max_volume_bps: u64, - }, - #[serde(rename_all = "camelCase")] - Volume { volume_bps: u64 }, - // Originally only volume fees were allowed and they used the field `bps`. - // To stay backwards compatible with old appdata we still support this old - // format. - #[serde(rename_all = "camelCase")] - VolumeOld { bps: u64 }, + #[serde(rename_all = "camelCase")] + struct FeePolicyDeserializer { + surplus_bps: Option, + max_volume_bps: Option, + price_improvement_bps: Option, + volume_bps: Option, + bps: Option, } - match Helper::deserialize(deserializer)? { - Helper::Surplus { - surplus_bps, - max_volume_bps, + match FeePolicyDeserializer::deserialize(deserializer)? { + FeePolicyDeserializer { + surplus_bps: Some(surplus_bps), + max_volume_bps: Some(max_volume_bps), + price_improvement_bps: None, + volume_bps: None, + bps: None, } => Ok(FeePolicy::Surplus { bps: surplus_bps, max_volume_bps, }), - Helper::PriceImprovement { - price_improvement_bps, - max_volume_bps, + FeePolicyDeserializer { + surplus_bps: None, + max_volume_bps: Some(max_volume_bps), + price_improvement_bps: Some(price_improvement_bps), + volume_bps: None, + bps: None, } => Ok(FeePolicy::PriceImprovement { bps: price_improvement_bps, max_volume_bps, }), - Helper::Volume { volume_bps } => Ok(FeePolicy::Volume { bps: volume_bps }), - Helper::VolumeOld { bps } => Ok(FeePolicy::Volume { bps }), + FeePolicyDeserializer { + surplus_bps: None, + max_volume_bps: None, + price_improvement_bps: None, + volume_bps: Some(volume_bps), + bps: None, + } => Ok(FeePolicy::Volume { bps: volume_bps }), + FeePolicyDeserializer { + surplus_bps: None, + max_volume_bps: None, + price_improvement_bps: None, + volume_bps: None, + bps: Some(bps), + } => Ok(FeePolicy::Volume { bps }), + _ => Err(serde::de::Error::custom("unknown fee policy format")), } } } @@ -274,8 +288,8 @@ impl Validator { } } -pub fn parse(full_app_data: &[u8]) -> Result { - let root = serde_json::from_slice::(full_app_data).context("invalid app data json")?; +pub fn parse(full_app_data: &[u8]) -> Result { + let root = serde_json::from_slice::(full_app_data)?; let parsed = root .metadata .or_else(|| root.backend.map(ProtocolAppData::from)) @@ -341,6 +355,41 @@ impl Root { backend: None, } } + + pub fn wrappers(&self) -> &[WrapperCall] { + self.metadata + .as_ref() + .map(|metadata| metadata.wrappers.as_slice()) + .unwrap_or_default() + } +} + +/// Caches whether a given app data document contains wrappers, keyed by +/// hash. This avoids re-parsing the same JSON across orders and auction +/// cycles. We're using the default TinyLFU eviction policy, but the capacity is +/// large enough that we don't expect eviction to be a problem in practice, but +/// we limit the size to prevent potential memory exhaustion attacks. +pub struct WrapperCache(Cache); + +impl WrapperCache { + pub fn new(capacity: u64) -> Self { + Self(Cache::new(capacity)) + } + + /// Returns `true` if order appData contains non-empty wrappers + pub fn has_wrappers(&self, hash: &AppDataHash, document: Option<&str>) -> bool { + if let Some(cached) = self.0.get(hash) { + return cached; + } + let result = document.is_some_and(|doc| { + serde_json::from_str::(doc) + .ok() + .and_then(|root| root.metadata) + .is_some_and(|m| !m.wrappers.is_empty()) + }); + self.0.insert(*hash, result); + result + } } // uid as 56 bytes: 32 for orderDigest, 20 for ownerAddress and 4 for validTo @@ -434,17 +483,34 @@ impl<'de> Deserialize<'de> for PartnerFees { where D: Deserializer<'de>, { - #[derive(Deserialize)] - #[serde(untagged)] - enum Helper { - Single(PartnerFee), - Multiple(Vec), - } + struct PartnerFeesVisitor; + + impl<'de> de::Visitor<'de> for PartnerFeesVisitor { + type Value = PartnerFees; - match Helper::deserialize(deserializer)? { - Helper::Single(fee) => Ok(PartnerFees(vec![fee])), - Helper::Multiple(fees) => Ok(PartnerFees(fees)), + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a single partner fee object or an array of partner fees") + } + + fn visit_map(self, map: A) -> Result + where + A: de::MapAccess<'de>, + { + let fee = PartnerFee::deserialize(de::value::MapAccessDeserializer::new(map))?; + Ok(PartnerFees(vec![fee])) + } + + fn visit_seq(self, seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let fees = + Vec::::deserialize(de::value::SeqAccessDeserializer::new(seq))?; + Ok(PartnerFees(fees)) + } } + + deserializer.deserialize_any(PartnerFeesVisitor) } } @@ -770,6 +836,24 @@ mod tests { ); } + #[test] + fn wrapper_cache_detects_wrappers() { + let cache = WrapperCache::new(100); + let h = |b: u8| AppDataHash([b; 32]); + + assert!(!cache.has_wrappers(&h(1), None)); + assert!(!cache.has_wrappers(&h(2), Some("{}"))); + assert!(!cache.has_wrappers(&h(3), Some(r#"{"metadata": {}}"#))); + assert!(!cache.has_wrappers(&h(4), Some(r#"{"metadata": {"wrappers": []}}"#))); + assert!(cache.has_wrappers( + &h(5), + Some(r#"{"metadata": {"wrappers": [{"address": "0x0000000000000000000000000000000000000001", "data": "0x"}]}}"#), + )); + + // Second call hits the cache + assert!(cache.has_wrappers(&h(5), None)); + } + #[test] fn misc() { let mut validator = Validator::default(); diff --git a/crates/app-data/src/app_data_hash.rs b/crates/app-data/src/app_data_hash.rs index 90148e0cf1..b51b94e27e 100644 --- a/crates/app-data/src/app_data_hash.rs +++ b/crates/app-data/src/app_data_hash.rs @@ -22,14 +22,12 @@ //! [0]: https://github.com/cowprotocol/services/issues/1465 use { - serde::{Deserializer, Serializer, de}, - serde_with::serde::{Deserialize, Serialize}, + serde::{Deserialize, Deserializer, Serialize, Serializer, de}, std::{ borrow::Cow, fmt::{self, Debug, Formatter}, str::FromStr, }, - tiny_keccak::{Hasher, Keccak}, }; /// A JSON object used to represent app data documents for uploading and @@ -108,11 +106,7 @@ impl PartialEq<[u8; 32]> for AppDataHash { /// Hash full app data to get the bytes expected to be set as the contract level /// app data. pub fn hash_full_app_data(app_data: &[u8]) -> [u8; 32] { - let mut hasher = Keccak::v256(); - hasher.update(app_data); - let mut hash = [0u8; 32]; - hasher.finalize(&mut hash); - hash + alloy_primitives::keccak256(app_data).0 } /// Create an IPFS CIDv1 from a hash created by `hash_full_app_data`. diff --git a/crates/app-data/src/hooks.rs b/crates/app-data/src/hooks.rs index a37a0ba3a2..c61e971761 100644 --- a/crates/app-data/src/hooks.rs +++ b/crates/app-data/src/hooks.rs @@ -1,5 +1,5 @@ use { - alloy::primitives::Address, + alloy_primitives::Address, bytes_hex::BytesHex, serde::{Deserialize, Serialize}, serde_with::{DisplayFromStr, serde_as}, diff --git a/crates/autopilot/Cargo.toml b/crates/autopilot/Cargo.toml index 6471f4d7a0..528d23b3e0 100644 --- a/crates/autopilot/Cargo.toml +++ b/crates/autopilot/Cargo.toml @@ -6,71 +6,96 @@ edition = "2024" license = "GPL-3.0-or-later" [lib] +doctest = false name = "autopilot" path = "src/lib.rs" -doctest = false [[bin]] name = "autopilot" path = "src/main.rs" [dependencies] -alloy = { workspace = true } -app-data = { workspace = true } -bytes-hex = { workspace = true } # may get marked as unused but it's used with serde +account-balances = { workspace = true } +alloy = { workspace = true, features = ["provider-debug-api", "provider-trace-api", "rand", "signer-aws"] } anyhow = { workspace = true } +app-data = { workspace = true } async-trait = { workspace = true } +axum = { workspace = true } +bad-tokens = { workspace = true } bigdecimal = { workspace = true } +brotli = { workspace = true } +bytes = { workspace = true } +bytes-hex = { workspace = true } # may get marked as unused but it's used with serde chain = { workspace = true } chrono = { workspace = true } clap = { workspace = true } +configs = { workspace = true } +const-hex = { workspace = true } contracts = { workspace = true } cow-amm = { workspace = true } dashmap = { workspace = true } database = { workspace = true } derive_more = { workspace = true } -ethcontract = { workspace = true } +eth-domain-types = { workspace = true } ethrpc = { workspace = true } +event-indexing = { workspace = true } futures = { workspace = true } -observe = { workspace = true } -const-hex = { workspace = true } +gas-price-estimation = { workspace = true } hex-literal = { workspace = true } +http-client = { workspace = true } humantime = { workspace = true } +humantime-serde = { workspace = true } indexmap = { workspace = true } itertools = { workspace = true } -maplit = { workspace = true } -mimalloc = { workspace = true } +mimalloc = { workspace = true, optional = true } model = { workspace = true } num = { workspace = true } number = { workspace = true } +observe = { workspace = true } order-validation = { workspace = true } -primitive-types = { workspace = true } +price-estimation = { workspace = true, features = ["test-util"] } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } rand = { workspace = true } -reqwest = { workspace = true, features = ["gzip", "json"] } +reqwest = { workspace = true, features = ["gzip", "json", "stream"] } rust_decimal = { workspace = true } s3 = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } shared = { workspace = true } +simulator = { workspace = true } sqlx = { workspace = true } strum = { workspace = true } +tempfile = { workspace = true, optional = true } thiserror = { workspace = true } +tikv-jemallocator = { workspace = true } +token-info = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "sync", "time"] } +tokio-stream = { workspace = true } +toml = { workspace = true } +tower = { workspace = true } +tower-http = { workspace = true, features = ["trace"] } tracing = { workspace = true } -url = { workspace = true } -web3 = { workspace = true } +url = { workspace = true, features = ["serde"] } +winner-selection = { workspace = true } [dev-dependencies] +configs = { workspace = true, features = ["test-util"] } +maplit = { workspace = true } mockall = { workspace = true } -tokio = { workspace = true, features = ["test-util"] } shared = { workspace = true, features = ["test-util"] } +tempfile = { workspace = true } +tokio = { workspace = true, features = ["test-util"] } [build-dependencies] anyhow = { workspace = true } vergen = { workspace = true, features = ["git", "gitcl"] } +[features] +mimalloc-allocator = ["dep:mimalloc"] +test-util = ["configs/test-util", "dep:tempfile", "price-estimation/test-util"] +tokio-console = ["observe/tokio-console"] + [lints] workspace = true diff --git a/crates/autopilot/openapi.yml b/crates/autopilot/openapi.yml new file mode 100644 index 0000000000..7ab842300d --- /dev/null +++ b/crates/autopilot/openapi.yml @@ -0,0 +1,94 @@ +openapi: 3.0.3 +info: + title: Autopilot Native Price API + description: | + Internal API for retrieving native token prices from the autopilot service. + This API is intended to be used by orderbook instances to query the shared + native price cache maintained by autopilot. + version: 0.0.1 +paths: + /native_price/{token}: + get: + operationId: getNativePrice + summary: Get the native price for a token + description: | + Returns the price of the specified token denominated in the native token + (e.g., ETH on Ethereum mainnet, xDAI on Gnosis Chain). + parameters: + - in: path + name: token + description: The address of the token to get the price for. + schema: + $ref: "#/components/schemas/Address" + required: true + - in: query + name: timeout_ms + description: | + Optional timeout in milliseconds for the price estimation request. + If not provided, uses the default timeout configured for autopilot. + Values below 250ms are automatically clamped to the minimum (250ms). + Values exceeding the configured maximum are clamped to the maximum. + schema: + type: integer + format: int64 + minimum: 250 + example: 5000 + required: false + responses: + "200": + description: Native price retrieved successfully. + content: + application/json: + schema: + $ref: "#/components/schemas/NativeTokenPrice" + "400": + description: | + Bad request. Possible causes: + - Unsupported token + content: + text/plain: + schema: + type: string + example: "Unsupported token" + "404": + description: No liquidity available for this token. + content: + text/plain: + schema: + type: string + example: "No liquidity" + "429": + description: Rate limited by upstream price estimator. + content: + text/plain: + schema: + type: string + example: "Rate limited" + "500": + description: Internal server error. + content: + text/plain: + schema: + type: string + example: "Internal error" +components: + schemas: + Address: + description: | + An Ethereum address encoded as a hex with `0x` prefix. + type: string + example: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + NativeTokenPrice: + description: | + The price of a token denominated in the native token (e.g., ETH). + type: object + properties: + price: + type: number + format: double + description: | + The price of the token in terms of the native token. For example, if + 1 USDC = 0.0005 ETH, the price would be 0.0005. + example: 0.0005 + required: + - price diff --git a/crates/autopilot/src/arguments.rs b/crates/autopilot/src/arguments.rs index 6174b51c97..2030f872d5 100644 --- a/crates/autopilot/src/arguments.rs +++ b/crates/autopilot/src/arguments.rs @@ -1,879 +1,15 @@ -use { - crate::{domain::fee::FeeFactor, infra}, - alloy::primitives::Address, - anyhow::{Context, anyhow, ensure}, - chrono::{DateTime, Utc}, - clap::ValueEnum, - primitive_types::{H160, U256}, - shared::{ - arguments::{display_list, display_option, display_secret_option}, - bad_token::token_owner_finder, - http_client, - price_estimation::{self, NativePriceEstimators}, - }, - std::{ - fmt::{self, Display, Formatter}, - net::SocketAddr, - num::NonZeroUsize, - str::FromStr, - time::Duration, - }, - url::Url, -}; +use std::path::PathBuf; #[derive(clap::Parser)] -pub struct Arguments { - #[clap(flatten)] - pub shared: shared::arguments::Arguments, - - #[clap(flatten)] - pub order_quoting: shared::arguments::OrderQuotingArguments, - - #[clap(flatten)] - pub http_client: http_client::Arguments, - - #[clap(flatten)] - pub token_owner_finder: token_owner_finder::Arguments, - - #[clap(flatten)] - pub price_estimation: price_estimation::Arguments, - - /// Address of the ethflow contracts. If not specified, eth-flow orders are - /// disabled. - /// In general, one contract is sufficient for the service to function. - /// Support for multiple contract was added to support transition period for - /// integrators when the migration of the eth-flow contract happens. - #[clap(long, env, use_value_delimiter = true)] - pub ethflow_contracts: Vec
, - - /// Timestamp at which we should start indexing eth-flow contract events. - /// If there are already events in the database for a date later than this, - /// then this date is ignored and can be omitted. - #[clap(long, env)] - pub ethflow_indexing_start: Option, - - /// A tracing Ethereum node URL to connect to, allowing a separate node URL - /// to be used exclusively for tracing calls. - #[clap(long, env)] - pub tracing_node_url: Option, - - #[clap(long, env, default_value = "0.0.0.0:9589")] - pub metrics_address: SocketAddr, - - /// Url of the Postgres database. By default connects to locally running - /// postgres. - #[clap(long, env, default_value = "postgresql://")] - pub db_write_url: Url, - - /// Url of the Postgres database replica. By default it's the same as - /// db_write_url - #[clap(long, env)] - pub db_read_url: Option, - - /// The number of order events to insert in a single batch. - #[clap(long, env, default_value = "500")] - pub insert_batch_size: NonZeroUsize, - - /// Skip syncing past events (useful for local deployments) - #[clap(long, env, action = clap::ArgAction::Set, default_value = "false")] - pub skip_event_sync: bool, - - /// List of token addresses that should be allowed regardless of whether the - /// bad token detector thinks they are bad. Base tokens are - /// automatically allowed. - #[clap(long, env, use_value_delimiter = true)] - pub allowed_tokens: Vec
, - - /// List of token addresses to be ignored throughout service - #[clap(long, env, use_value_delimiter = true)] - pub unsupported_tokens: Vec
, - - /// Which estimators to use to estimate token prices in terms of the chain's - /// native token. Estimators with the same name need to also be specified as - /// built-in, legacy or external price estimators (lookup happens in this - /// order in case of name collisions) - #[clap(long, env)] - pub native_price_estimators: NativePriceEstimators, - - /// How many successful price estimates for each order will cause a native - /// price estimation to return its result early. It's possible to pass - /// values greater than the total number of enabled estimators but that - /// will not have any further effect. - #[clap(long, env, default_value = "2")] - pub native_price_estimation_results_required: NonZeroUsize, - - /// The minimum amount of time an order has to be valid for. - #[clap( - long, - env, - default_value = "1m", - value_parser = humantime::parse_duration, - )] - pub min_order_validity_period: Duration, - - /// List of account addresses to be denied from order creation - #[clap(long, env, use_value_delimiter = true)] - pub banned_users: Vec
, - - /// Maximum number of entries to keep in the banned users cache. - #[clap(long, env, default_value = "10000")] - pub banned_users_max_cache_size: NonZeroUsize, - - /// If the auction hasn't been updated in this amount of time the pod fails - /// the liveness check. Expects a value in seconds. - #[clap( - long, - env, - default_value = "5m", - value_parser = humantime::parse_duration, - )] - pub max_auction_age: Duration, - - /// Used to filter out limit orders with prices that are too far from the - /// market price. 0 means no filtering. - #[clap(long, env, default_value = "0")] - pub limit_order_price_factor: f64, - - /// The URL of a list of tokens our settlement contract is willing to - /// internalize. - #[clap(long, env)] - pub trusted_tokens_url: Option, - - /// Hardcoded list of trusted tokens to use in addition to - /// `trusted_tokens_url`. - #[clap(long, env, use_value_delimiter = true)] - pub trusted_tokens: Option>, - - /// Time interval after which the trusted tokens list needs to be updated. - #[clap( - long, - env, - default_value = "1h", - value_parser = humantime::parse_duration, - )] - pub trusted_tokens_update_interval: Duration, - - /// A list of drivers in the following format: - /// `|||` - #[clap(long, env, use_value_delimiter = true)] - pub drivers: Vec, - - /// The maximum number of blocks to wait for a settlement to appear on - /// chain. - #[clap(long, env, default_value = "5")] - pub submission_deadline: usize, - - /// The amount of time that the autopilot waits looking for a settlement - /// transaction onchain after the driver acknowledges the receipt of a - /// settlement. - #[clap( - long, - env, - default_value = "1m", - value_parser = humantime::parse_duration, - )] - pub max_settlement_transaction_wait: Duration, - - /// Run the autopilot in a shadow mode by specifying an upstream CoW - /// protocol deployment to pull auctions from. This will cause the autopilot - /// to start a run loop where it performs solver competition on driver, - /// and report and log the winner **without** requesting that any driver - /// actually executes any settlements. Note that many of the `autopilot`'s - /// typical features will be disabled in this mode, making many options - /// ignored. This assumes co-location is enabled and does not require it - /// being specified separately. - #[clap(long, env)] - pub shadow: Option, - - /// Time solvers have to compute a score per auction. - #[clap( - long, - env, - default_value = "15s", - value_parser = humantime::parse_duration, - )] - pub solve_deadline: Duration, - - /// Describes how the protocol fees should be calculated. - #[clap(flatten)] - pub fee_policies_config: FeePoliciesConfig, - - /// Arguments for uploading information to S3. - #[clap(flatten)] - pub s3: infra::persistence::cli::S3, - - /// Time interval in days between each cleanup operation of the - /// `order_events` database table. - #[clap(long, env, default_value = "1d", value_parser = humantime::parse_duration)] - pub order_events_cleanup_interval: Duration, - - /// Age threshold in days for order events to be eligible for cleanup in the - /// `order_events` database table. - #[clap(long, env, default_value = "30d", value_parser = humantime::parse_duration)] - pub order_events_cleanup_threshold: Duration, - - /// Configurations for indexing CoW AMMs. Supplied in the form of: - /// "||,|," - /// - factory is contract address emmiting CoW AMM deployment events. - /// - helper is a contract address to interface with pools deployed by the - /// factory - /// - block is the block at which indexing should start (should be 1 block - /// before the deployment of the factory) - #[clap(long, env, use_value_delimiter = true)] - pub cow_amm_configs: Vec, - - /// If a new run loop would start more than this amount of time after the - /// system noticed the latest block, wait for the next block to appear - /// before continuing the run loop. - #[clap(long, env, default_value = "2s", value_parser = humantime::parse_duration)] - pub max_run_loop_delay: Duration, - - /// Maximum timeout for fetching the native prices in the run loop - /// If the value is 0, the native prices are fetched from the cache - #[clap(long, env, default_value = "0s", value_parser = humantime::parse_duration)] - pub run_loop_native_price_timeout: Duration, - - #[clap(long, env, default_value = "20")] - /// The maximum number of winners per auction. Each winner will be allowed - /// to settle their winning orders at the same time. - pub max_winners_per_auction: NonZeroUsize, - - #[clap(long, env, default_value = "3")] - /// The maximum allowed number of solutions to be proposed from a single - /// solver, per auction. - pub max_solutions_per_solver: NonZeroUsize, - - /// Archive node URL used to index CoW AMM +pub struct CliArguments { #[clap(long, env)] - pub archive_node_url: Option, - - /// Configuration for the solver participation guard. - #[clap(flatten)] - pub db_based_solver_participation_guard: DbBasedSolverParticipationGuardConfig, - - /// Configures whether the autopilot filters out orders with insufficient - /// balances. - #[clap(long, env, default_value = "false", action = clap::ArgAction::Set)] - pub disable_order_balance_filter: bool, - - // Configures whether the autopilot filters out EIP-1271 orders even if their signatures are - // invalid. This is useful as a workaround to let flashloan orders go through as they rely - // on preHooks behing executed to make the signatures valid. - #[clap(long, env, default_value = "false", action = clap::ArgAction::Set)] - pub disable_1271_order_sig_filter: bool, - - /// Configures whether the autopilot skips balance checks for EIP-1271 - /// orders. - #[clap(long, env, default_value = "false", action = clap::ArgAction::Set)] - pub disable_1271_order_balance_filter: bool, - - /// Enables the usage of leader lock in the database - /// The second instance of autopilot will act as a follower - /// and not cut any auctions. - #[clap(long, env, default_value = "false", action = clap::ArgAction::Set)] - pub enable_leader_lock: bool, -} - -#[derive(Debug, clap::Parser)] -pub struct DbBasedSolverParticipationGuardConfig { - /// Enables or disables the solver participation guard - #[clap( - id = "db_enabled", - long = "db-based-solver-participation-guard-enabled", - env = "DB_BASED_SOLVER_PARTICIPATION_GUARD_ENABLED", - default_value = "true" - )] - pub enabled: bool, - - /// Sets the duration for which the solver remains blacklisted. - /// Technically, the time-to-live for the solver participation blacklist - /// cache. - #[clap(long, env, default_value = "5m", value_parser = humantime::parse_duration)] - pub solver_blacklist_cache_ttl: Duration, - - #[clap(flatten)] - pub non_settling_solvers_finder_config: NonSettlingSolversFinderConfig, - - #[clap(flatten)] - pub low_settling_solvers_finder_config: LowSettlingSolversFinderConfig, -} - -#[derive(Debug, clap::Parser)] -pub struct NonSettlingSolversFinderConfig { - /// Enables search of non-settling solvers. - #[clap( - id = "non_settling_solvers_blacklisting_enabled", - long = "non-settling-solvers-blacklisting-enabled", - env = "NON_SETTLING_SOLVERS_BLACKLISTING_ENABLED", - default_value = "true", - action = clap::ArgAction::Set, - )] - pub enabled: bool, - - /// The number of last auctions to check solver participation eligibility. - #[clap( - id = "non_settling_last_auctions_participation_count", - long = "non-settling-last-auctions-participation-count", - env = "NON_SETTLING_LAST_AUCTIONS_PARTICIPATION_COUNT", - default_value = "3" - )] - pub last_auctions_participation_count: u32, -} - -#[derive(Debug, clap::Parser)] -pub struct LowSettlingSolversFinderConfig { - /// Enables search of non-settling solvers. - #[clap( - id = "low_settling_solvers_blacklisting_enabled", - long = "low-settling-solvers-blacklisting-enabled", - env = "LOW_SETTLING_SOLVERS_BLACKLISTING_ENABLED", - default_value = "true", - action = clap::ArgAction::Set, - )] - pub enabled: bool, - - /// The number of last auctions to check solver participation eligibility. - #[clap( - id = "low_settling_last_auctions_participation_count", - long = "low-settling-last-auctions-participation-count", - env = "LOW_SETTLING_LAST_AUCTIONS_PARTICIPATION_COUNT", - default_value = "100" - )] - pub last_auctions_participation_count: u32, - - /// The minimum number of winning solutions to start considering the solver. - #[clap( - id = "low_settling_min_wins_threshold", - long = "low-settling-min-wins-threshold", - env = "LOW_SETTLING_MIN_WINS_THRESHOLD", - default_value = "3" - )] - pub min_wins_threshold: u32, - - /// A max failure rate for a solver to remain eligible for - /// participation in the competition. Otherwise, the solver will be - /// banned. - #[clap(long, env, default_value = "0.9")] - pub solver_max_settlement_failure_rate: f64, + pub config: PathBuf, } -impl std::fmt::Display for Arguments { +impl std::fmt::Display for CliArguments { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { - shared, - order_quoting, - http_client, - token_owner_finder, - price_estimation, - tracing_node_url, - ethflow_contracts, - ethflow_indexing_start, - metrics_address, - skip_event_sync, - allowed_tokens, - unsupported_tokens, - native_price_estimators, - min_order_validity_period, - banned_users, - banned_users_max_cache_size, - max_auction_age, - limit_order_price_factor, - trusted_tokens_url, - trusted_tokens, - trusted_tokens_update_interval, - drivers, - submission_deadline, - shadow, - solve_deadline, - fee_policies_config, - order_events_cleanup_interval, - order_events_cleanup_threshold, - db_write_url, - db_read_url, - insert_batch_size, - native_price_estimation_results_required, - max_settlement_transaction_wait, - s3, - cow_amm_configs, - max_run_loop_delay, - run_loop_native_price_timeout, - max_winners_per_auction, - archive_node_url, - max_solutions_per_solver, - db_based_solver_participation_guard, - disable_order_balance_filter, - disable_1271_order_balance_filter, - disable_1271_order_sig_filter, - enable_leader_lock, - } = self; - - write!(f, "{shared}")?; - write!(f, "{order_quoting}")?; - write!(f, "{http_client}")?; - write!(f, "{token_owner_finder}")?; - write!(f, "{price_estimation}")?; - display_option(f, "tracing_node_url", tracing_node_url)?; - writeln!(f, "ethflow_contracts: {ethflow_contracts:?}")?; - writeln!(f, "ethflow_indexing_start: {ethflow_indexing_start:?}")?; - writeln!(f, "metrics_address: {metrics_address}")?; - display_secret_option(f, "db_write_url", Some(&db_write_url))?; - display_secret_option(f, "db_read_url", db_read_url.as_ref())?; - writeln!(f, "skip_event_sync: {skip_event_sync}")?; - writeln!(f, "allowed_tokens: {allowed_tokens:?}")?; - writeln!(f, "unsupported_tokens: {unsupported_tokens:?}")?; - writeln!(f, "native_price_estimators: {native_price_estimators}")?; - writeln!( - f, - "min_order_validity_period: {min_order_validity_period:?}" - )?; - writeln!(f, "banned_users: {banned_users:?}")?; - writeln!( - f, - "banned_users_max_cache_size: {banned_users_max_cache_size:?}" - )?; - writeln!(f, "max_auction_age: {max_auction_age:?}")?; - writeln!(f, "limit_order_price_factor: {limit_order_price_factor:?}")?; - display_option(f, "trusted_tokens_url", trusted_tokens_url)?; - writeln!(f, "trusted_tokens: {trusted_tokens:?}")?; - writeln!( - f, - "trusted_tokens_update_interval: {trusted_tokens_update_interval:?}" - )?; - display_list(f, "drivers", drivers.iter())?; - writeln!(f, "submission_deadline: {submission_deadline}")?; - display_option(f, "shadow", shadow)?; - writeln!(f, "solve_deadline: {solve_deadline:?}")?; - writeln!(f, "fee_policies_config: {fee_policies_config:?}")?; - writeln!( - f, - "order_events_cleanup_interval: {order_events_cleanup_interval:?}" - )?; - writeln!( - f, - "order_events_cleanup_threshold: {order_events_cleanup_threshold:?}" - )?; - writeln!(f, "insert_batch_size: {insert_batch_size}")?; - writeln!( - f, - "native_price_estimation_results_required: {native_price_estimation_results_required}" - )?; - writeln!( - f, - "max_settlement_transaction_wait: {max_settlement_transaction_wait:?}" - )?; - writeln!(f, "s3: {s3:?}")?; - writeln!(f, "cow_amm_configs: {cow_amm_configs:?}")?; - writeln!(f, "max_run_loop_delay: {max_run_loop_delay:?}")?; - writeln!( - f, - "run_loop_native_price_timeout: {run_loop_native_price_timeout:?}" - )?; - writeln!(f, "max_winners_per_auction: {max_winners_per_auction:?}")?; - writeln!(f, "archive_node_url: {archive_node_url:?}")?; - writeln!(f, "max_solutions_per_solver: {max_solutions_per_solver:?}")?; - writeln!( - f, - "db_based_solver_participation_guard: {db_based_solver_participation_guard:?}" - )?; - writeln!( - f, - "disable_order_balance_filter: {disable_order_balance_filter}" - )?; - writeln!( - f, - "disable_1271_order_balance_filter: {disable_1271_order_balance_filter}" - )?; - writeln!( - f, - "disable_1271_order_sig_filter: {disable_1271_order_sig_filter}" - )?; - writeln!(f, "enable_leader_lock: {enable_leader_lock}")?; + let Self { config } = self; + write!(f, "{}", config.display())?; Ok(()) } } - -/// External solver driver configuration -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Solver { - pub name: String, - pub url: Url, - pub submission_account: Account, - pub fairness_threshold: Option, - pub requested_timeout_on_problems: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Account { - /// AWS KMS is used to retrieve the solver public key - Kms(Arn), - /// Solver public key - Address(H160), -} - -// Wrapper type for AWS ARN identifiers -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Arn(pub String); - -impl FromStr for Arn { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - // Could be more strict here, but this should suffice to catch unintended - // configuration mistakes - if s.starts_with("arn:aws:kms:") { - Ok(Self(s.to_string())) - } else { - Err(anyhow!("Invalid ARN identifier: {}", s)) - } - } -} - -impl Display for Solver { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}({})", self.name, self.url) - } -} - -impl FromStr for Solver { - type Err = anyhow::Error; - - fn from_str(solver: &str) -> anyhow::Result { - let parts: Vec<&str> = solver.split('|').collect(); - ensure!(parts.len() >= 3, "not enough arguments for external solver"); - let (name, url) = (parts[0], parts[1]); - let url: Url = url.parse()?; - let submission_account = match Arn::from_str(parts[2]) { - Ok(value) => Account::Kms(value), - _ => Account::Address(H160::from_str(parts[2]).context("failed to parse submission")?), - }; - - let mut fairness_threshold: Option = Default::default(); - let mut requested_timeout_on_problems = false; - - if let Some(value) = parts.get(3) { - match U256::from_dec_str(value) { - Ok(parsed_fairness_threshold) => { - fairness_threshold = Some(parsed_fairness_threshold); - } - Err(_) => { - requested_timeout_on_problems = - value.to_lowercase() == "requested-timeout-on-problems"; - } - } - }; - - if let Some(value) = parts.get(4) { - requested_timeout_on_problems = value.to_lowercase() == "requested-timeout-on-problems"; - } - - Ok(Self { - name: name.to_owned(), - url, - fairness_threshold, - submission_account, - requested_timeout_on_problems, - }) - } -} - -#[derive(clap::Parser, Debug, Clone)] -pub struct FeePoliciesConfig { - /// Describes how the protocol fees should be calculated. - #[clap(long, env, use_value_delimiter = true)] - pub fee_policies: Vec, - - /// Maximum partner fee allowed. If the partner fee specified is greater - /// than this maximum, the partner fee will be capped - #[clap(long, env, default_value = "0.01")] - pub fee_policy_max_partner_fee: FeeFactor, - - /// Volume fee policies that will become effective at a future timestamp. - #[clap(flatten)] - pub upcoming_fee_policies: UpcomingFeePolicies, -} - -/// A fee policy to be used for orders base on it's class. -/// Examples: -/// - Surplus with a high enough cap for limit orders: surplus:0.5:0.9:limit -/// -/// - Surplus with cap for market orders: surplus:0.5:0.06:market -/// -/// - Price improvement with a high enough cap for any order class: -/// price_improvement:0.5:0.9:any -/// -/// - Price improvement with cap for limit orders: -/// price_improvement:0.5:0.06:limit -/// -/// - Volume based fee for any order class: volume:0.1:any -#[derive(Debug, Clone)] -pub struct FeePolicy { - pub fee_policy_kind: FeePolicyKind, - pub fee_policy_order_class: FeePolicyOrderClass, -} - -/// Fee policies that will become effective at a future timestamp. -#[derive(clap::Parser, Debug, Clone)] -pub struct UpcomingFeePolicies { - #[clap( - id = "upcoming_fee_policies", - long = "upcoming-fee-policies", - env = "UPCOMING_FEE_POLICIES", - use_value_delimiter = true - )] - pub fee_policies: Vec, - - #[clap( - long = "upcoming-fee-policies-timestamp", - env = "UPCOMING_FEE_POLICIES_TIMESTAMP" - )] - pub effective_from_timestamp: Option>, -} - -#[derive(clap::Parser, Debug, Clone)] -pub enum FeePolicyKind { - /// How much of the order's surplus should be taken as a protocol fee. - Surplus { - factor: FeeFactor, - max_volume_factor: FeeFactor, - }, - /// How much of the order's price improvement should be taken as a protocol - /// fee where price improvement is a difference between the executed price - /// and the best quote. - PriceImprovement { - factor: FeeFactor, - max_volume_factor: FeeFactor, - }, - /// How much of the order's volume should be taken as a protocol fee. - Volume { factor: FeeFactor }, -} - -#[derive(clap::Parser, clap::ValueEnum, Clone, Debug)] -pub enum FeePolicyOrderClass { - /// If a fee policy needs to be applied to in-market orders. - Market, - /// If a fee policy needs to be applied to limit orders. - Limit, - /// If a fee policy needs to be applied regardless of the order class. - Any, -} - -impl FromStr for FeePolicy { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - let mut parts = s.split(':'); - let kind = parts.next().context("missing fee policy kind")?; - let fee_policy_kind = match kind { - "surplus" => { - let factor = parts - .next() - .context("missing surplus factor")? - .parse::() - .map_err(|e| anyhow::anyhow!("invalid surplus factor: {}", e))?; - let max_volume_factor = parts - .next() - .context("missing max volume factor")? - .parse::() - .map_err(|e| anyhow::anyhow!("invalid max volume factor: {}", e))?; - Ok(FeePolicyKind::Surplus { - factor: factor.try_into()?, - max_volume_factor: max_volume_factor.try_into()?, - }) - } - "priceImprovement" => { - let factor = parts - .next() - .context("missing price improvement factor")? - .parse::() - .map_err(|e| anyhow::anyhow!("invalid price improvement factor: {}", e))?; - let max_volume_factor = parts - .next() - .context("missing price improvement max volume factor")? - .parse::() - .map_err(|e| { - anyhow::anyhow!("invalid price improvement max volume factor: {}", e) - })?; - Ok(FeePolicyKind::PriceImprovement { - factor: factor.try_into()?, - max_volume_factor: max_volume_factor.try_into()?, - }) - } - "volume" => { - let factor = parts - .next() - .context("missing volume factor")? - .parse::() - .map_err(|e| anyhow::anyhow!("invalid volume factor: {}", e))?; - Ok(FeePolicyKind::Volume { - factor: factor.try_into()?, - }) - } - _ => Err(anyhow::anyhow!("invalid fee policy kind: {}", kind)), - }?; - let fee_policy_order_class = FeePolicyOrderClass::from_str( - parts.next().context("missing fee policy order class")?, - true, - ) - .map_err(|e| anyhow::anyhow!("invalid fee policy order class: {}", e))?; - - Ok(FeePolicy { - fee_policy_kind, - fee_policy_order_class, - }) - } -} - -#[derive(Debug, Clone)] -pub struct CowAmmConfig { - /// Which contract to index for CoW AMM deployment events. - pub factory: Address, - /// Which helper contract to use for interfacing with the indexed CoW AMMs. - pub helper: Address, - /// At which block indexing should start on the factory. - pub index_start: u64, -} - -impl FromStr for CowAmmConfig { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - let mut parts = s.split('|'); - let factory = parts - .next() - .context("config is missing factory")? - .parse() - .context("could not parse factory as H160")?; - let helper = parts - .next() - .context("config is missing helper")? - .parse() - .context("could not parse helper as H160")?; - let index_start = parts - .next() - .context("config is missing index_start")? - .parse() - .context("could not parse index_start as u64")?; - anyhow::ensure!( - parts.next().is_none(), - "supplied too many arguments for cow amm config" - ); - - Ok(Self { - factory, - helper, - index_start, - }) - } -} - -#[cfg(test)] -mod test { - use {super::*, hex_literal::hex}; - - #[test] - fn test_fee_factor_limits() { - let policies = vec![ - "volume:1.0:market", - "volume:-1.0:limit", - "surplus:1.0:0.5:any", - "surplus:0.5:1.0:limit", - "surplus:0.5:-1.0:market", - "surplus:-1.0:0.5:limit", - "priceImprovement:1.0:0.5:market", - "priceImprovement:-1.0:0.5:any", - "priceImprovement:0.5:1.0:market", - "priceImprovement:0.5:-1.0:limit", - ]; - - for policy in policies { - assert!( - FeePolicy::from_str(policy) - .err() - .unwrap() - .to_string() - .contains("Factor must be in the range [0, 1)"), - ) - } - } - - #[test] - fn parse_driver_submission_account_address() { - let argument = "name1|http://localhost:8080|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; - let driver = Solver::from_str(argument).unwrap(); - let expected = Solver { - name: "name1".into(), - url: Url::parse("http://localhost:8080").unwrap(), - fairness_threshold: None, - requested_timeout_on_problems: false, - submission_account: Account::Address(H160::from_slice(&hex!( - "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - ))), - }; - assert_eq!(driver, expected); - } - - #[test] - fn parse_driver_submission_account_arn() { - let argument = "name1|http://localhost:8080|arn:aws:kms:supersecretstuff"; - let driver = Solver::from_str(argument).unwrap(); - let expected = Solver { - name: "name1".into(), - url: Url::parse("http://localhost:8080").unwrap(), - fairness_threshold: None, - requested_timeout_on_problems: false, - submission_account: Account::Kms( - Arn::from_str("arn:aws:kms:supersecretstuff").unwrap(), - ), - }; - assert_eq!(driver, expected); - } - - #[test] - fn parse_driver_with_threshold() { - let argument = "name1|http://localhost:8080|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2|1000000000000000000"; - let driver = Solver::from_str(argument).unwrap(); - let expected = Solver { - name: "name1".into(), - url: Url::parse("http://localhost:8080").unwrap(), - submission_account: Account::Address(H160::from_slice(&hex!( - "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - ))), - fairness_threshold: Some(U256::exp10(18)), - requested_timeout_on_problems: false, - }; - assert_eq!(driver, expected); - } - - #[test] - fn parse_driver_with_accepts_unsettled_blocking_flag() { - let argument = - "name1|http://localhost:8080|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2|requested-timeout-on-problems"; - let driver = Solver::from_str(argument).unwrap(); - let expected = Solver { - name: "name1".into(), - url: Url::parse("http://localhost:8080").unwrap(), - submission_account: Account::Address(H160::from_slice(&hex!( - "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - ))), - fairness_threshold: None, - requested_timeout_on_problems: true, - }; - assert_eq!(driver, expected); - } - - #[test] - fn parse_driver_with_threshold_and_accepts_unsettled_blocking_flag() { - let argument = "name1|http://localhost:8080|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2|1000000000000000000|requested-timeout-on-problems"; - let driver = Solver::from_str(argument).unwrap(); - let expected = Solver { - name: "name1".into(), - url: Url::parse("http://localhost:8080").unwrap(), - submission_account: Account::Address(H160::from_slice(&hex!( - "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - ))), - fairness_threshold: Some(U256::exp10(18)), - requested_timeout_on_problems: true, - }; - assert_eq!(driver, expected); - } -} diff --git a/crates/autopilot/src/boundary/events/settlement.rs b/crates/autopilot/src/boundary/events/settlement.rs index 1520b67b21..846b1b68de 100644 --- a/crates/autopilot/src/boundary/events/settlement.rs +++ b/crates/autopilot/src/boundary/events/settlement.rs @@ -1,13 +1,16 @@ use { - crate::{database::Postgres, domain::settlement}, + crate::database::Postgres, alloy::{ primitives::Address, rpc::types::{Filter, Log}, }, anyhow::Result, - contracts::alloy::GPv2Settlement::GPv2Settlement::GPv2SettlementEvents, - ethrpc::{AlloyProvider, block_stream::RangeInclusive}, - shared::event_handling::{AlloyEventRetrieving, EventStoring}, + contracts::GPv2Settlement::GPv2Settlement::GPv2SettlementEvents, + ethrpc::AlloyProvider, + event_indexing::{ + block_retriever::RangeInclusive, + event_handler::{AlloyEventRetrieving, EventStoring}, + }, }; pub struct GPv2SettlementContract { @@ -28,23 +31,21 @@ impl AlloyEventRetrieving for GPv2SettlementContract { Filter::new().address(self.address) } - fn provider(&self) -> &contracts::alloy::Provider { + fn provider(&self) -> &alloy::providers::DynProvider { &self.provider } } pub struct Indexer { db: Postgres, - start_index: u64, - settlement_observer: settlement::Observer, + start_indexing_block: u64, } impl Indexer { - pub fn new(db: Postgres, settlement_observer: settlement::Observer, start_index: u64) -> Self { + pub fn new(db: Postgres, start_indexing_block: u64) -> Self { Self { db, - settlement_observer, - start_index, + start_indexing_block, } } } @@ -57,7 +58,7 @@ impl EventStoring<(GPv2SettlementEvents, Log)> for Indexer { async fn last_event_block(&self) -> Result { super::read_last_block_from_db(&self.db.pool, INDEX_NAME) .await - .map(|last_block| last_block.max(self.start_index)) + .map(|last_block| last_block.max(self.start_indexing_block)) } async fn persist_last_indexed_block(&mut self, latest_block: u64) -> Result<()> { @@ -74,8 +75,6 @@ impl EventStoring<(GPv2SettlementEvents, Log)> for Indexer { crate::database::events::replace_events(&mut transaction, events, from_block).await?; database::settlements::delete(&mut transaction, from_block).await?; transaction.commit().await?; - - self.settlement_observer.update().await; Ok(()) } @@ -83,8 +82,6 @@ impl EventStoring<(GPv2SettlementEvents, Log)> for Indexer { let mut transaction = self.db.pool.begin().await?; crate::database::events::append_events(&mut transaction, events).await?; transaction.commit().await?; - - self.settlement_observer.update().await; Ok(()) } } diff --git a/crates/autopilot/src/boundary/mod.rs b/crates/autopilot/src/boundary/mod.rs index 698b827ae5..42d3439d85 100644 --- a/crates/autopilot/src/boundary/mod.rs +++ b/crates/autopilot/src/boundary/mod.rs @@ -22,23 +22,24 @@ pub use { }, shared::order_validation::{Amounts, is_order_outside_market_price}, }; -use {crate::domain, ethrpc::Web3, std::collections::HashMap, url::Url}; +use { + crate::domain, + ethrpc::Web3, + std::{collections::HashMap, sync::Arc}, + url::Url, +}; pub mod events; pub mod order; /// Builds a web3 client based on the ethrpc args config. -pub fn web3_client(ethrpc: &Url, ethrpc_args: &shared::ethrpc::Arguments) -> Web3 { - let http_factory = - shared::http_client::HttpClientFactory::new(&shared::http_client::Arguments { - http_timeout: std::time::Duration::from_secs(10), - }); - shared::ethrpc::web3(ethrpc_args, &http_factory, ethrpc, "base") +pub fn web3_client(ethrpc: &Url, ethrpc_args: &shared::web3::Arguments) -> Web3 { + shared::web3::web3(ethrpc_args, ethrpc, "base") } pub struct SolvableOrders { - pub orders: HashMap, - pub quotes: HashMap, + pub orders: HashMap>, + pub quotes: HashMap>, pub latest_settlement_block: u64, /// Used as a checkpoint - meaning at this point in time /// **at least** the stored orders were present in the system. diff --git a/crates/autopilot/src/boundary/order.rs b/crates/autopilot/src/boundary/order.rs index 31cb5b5a15..6c8bf827f7 100644 --- a/crates/autopilot/src/boundary/order.rs +++ b/crates/autopilot/src/boundary/order.rs @@ -1,11 +1,7 @@ -use { - crate::domain::{self, eth}, - ethrpc::alloy::conversions::IntoLegacy, - shared::remaining_amounts, -}; +use {crate::domain, eth_domain_types as eth, shared::remaining_amounts}; pub fn to_domain( - order: model::order::Order, + order: &model::order::Order, protocol_fees: Vec, quote: Option, ) -> domain::Order { @@ -15,40 +11,43 @@ pub fn to_domain( domain::Order { uid: order.metadata.uid.into(), sell: eth::Asset { - token: order.data.sell_token.into_legacy().into(), - amount: order.data.sell_amount.into_legacy().into(), + token: order.data.sell_token.into(), + amount: order.data.sell_amount.into(), }, buy: eth::Asset { - token: order.data.buy_token.into_legacy().into(), - amount: order.data.buy_amount.into_legacy().into(), + token: order.data.buy_token.into(), + amount: order.data.buy_amount.into(), }, protocol_fees, created: u32::try_from(order.metadata.creation_date.timestamp()).unwrap_or(u32::MIN), valid_to: order.data.valid_to, side: order.data.kind.into(), - receiver: order - .data - .receiver - .map(IntoLegacy::into_legacy) - .map(Into::into), - owner: order.metadata.owner.into_legacy().into(), + receiver: order.data.receiver, + owner: order.metadata.owner, partially_fillable: order.data.partially_fillable, executed: remaining_order.executed_amount.into(), pre_interactions: if order_is_untouched { - order.interactions.pre.into_iter().map(Into::into).collect() + order + .interactions + .pre + .iter() + .cloned() + .map(Into::into) + .collect() } else { Default::default() }, post_interactions: order .interactions .post - .into_iter() + .iter() + .cloned() .map(Into::into) .collect(), sell_token_balance: order.data.sell_token_balance.into(), buy_token_balance: order.data.buy_token_balance.into(), app_data: order.data.app_data.into(), - signature: order.signature.into(), + signature: order.signature.clone().into(), quote, } } diff --git a/crates/autopilot/src/database/auction.rs b/crates/autopilot/src/database/auction.rs index 606f0ce765..f0c089195d 100644 --- a/crates/autopilot/src/database/auction.rs +++ b/crates/autopilot/src/database/auction.rs @@ -11,7 +11,7 @@ use { event_storing_helpers::{create_db_search_parameters, create_quote_row}, order_quoting::{QuoteData, QuoteSearchParameters, QuoteStoring}, }, - std::{collections::HashMap, ops::DerefMut}, + std::{collections::HashMap, ops::DerefMut, sync::Arc}, }; #[async_trait::async_trait] @@ -75,11 +75,11 @@ impl Postgres { sqlx::query("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ") .execute(ex.deref_mut()) .await?; - let orders: HashMap = + let orders: HashMap> = database::orders::solvable_orders(&mut ex, i64::from(min_valid_to)) .map(|result| match result { Ok(order) => full_order_into_model_order(order) - .map(|order| (domain::OrderUid(order.metadata.uid.0), order)), + .map(|order| (domain::OrderUid(order.metadata.uid.0), Arc::new(order))), Err(err) => Err(anyhow::Error::from(err)), }) .try_collect() @@ -88,7 +88,12 @@ impl Postgres { .await? .to_u64() .context("latest_settlement_block is not u64")?; - let quotes = self.read_quotes(orders.keys()).await?; + let quotes = self + .read_quotes(orders.keys()) + .await? + .into_iter() + .map(|(uid, quote)| (uid, Arc::new(quote))) + .collect(); Ok(boundary::SolvableOrders { orders, quotes, @@ -97,18 +102,35 @@ impl Postgres { }) } + pub async fn get_next_auction_id(&self) -> Result { + let _timer = super::Metrics::get() + .database_queries + .with_label_values(&["get_next_auction_id"]) + .start_timer(); + + let mut ex = self.pool.acquire().await?; + let id = database::auction::get_next_auction_id(&mut ex).await?; + Ok(id) + } + pub async fn replace_current_auction( &self, - auction: &dto::RawAuctionData, - ) -> Result { + new_auction_id: dto::AuctionId, + new_auction_data: dto::RawAuctionData, + ) -> Result<()> { let _timer = super::Metrics::get() .database_queries - .with_label_values(&["replace_current_auction"]) + .with_label_values(&["insert_auction_with_id"]) .start_timer(); - let data = serde_json::to_value(auction)?; + let data = tokio::task::spawn_blocking(move || { + serde_json::to_string(&new_auction_data).context("failed to serialize auction") + }) + .await + .context("auction serialization task panicked")??; + let mut ex = self.pool.acquire().await?; - let id = database::auction::replace_auction(&mut ex, &data).await?; - Ok(id) + database::auction::insert_auction_with_id(&mut ex, new_auction_id, &data).await?; + Ok(()) } } diff --git a/crates/autopilot/src/database/auction_prices.rs b/crates/autopilot/src/database/auction_prices.rs index 7411a8e0f5..19a0ae0145 100644 --- a/crates/autopilot/src/database/auction_prices.rs +++ b/crates/autopilot/src/database/auction_prices.rs @@ -1,13 +1,13 @@ use { super::Postgres, + alloy::primitives::Address, anyhow::Result, bigdecimal::BigDecimal, - primitive_types::H160, std::collections::HashMap, }; impl Postgres { - pub async fn fetch_latest_prices(&self) -> Result> { + pub async fn fetch_latest_prices(&self) -> Result> { let _timer = super::Metrics::get() .database_queries .with_label_values(&["fetch_latest_prices"]) @@ -17,7 +17,7 @@ impl Postgres { Ok(database::auction_prices::fetch_latest_prices(&mut ex) .await? .into_iter() - .map(|auction_price| (H160::from(auction_price.token.0), auction_price.price)) + .map(|auction_price| (Address::new(auction_price.token.0), auction_price.price)) .collect::>()) } } diff --git a/crates/autopilot/src/database/competition.rs b/crates/autopilot/src/database/competition.rs index 84e19ebb6e..50f75a01b3 100644 --- a/crates/autopilot/src/database/competition.rs +++ b/crates/autopilot/src/database/competition.rs @@ -1,8 +1,8 @@ use { - crate::domain::{competition::Score, eth}, + crate::domain::competition::Score, + alloy::primitives::{Address, U256}, anyhow::Context, database::{ - Address, auction::AuctionId, auction_prices::AuctionPrice, byte_array::ByteArray, @@ -11,19 +11,18 @@ use { derive_more::Debug, model::solver_competition::SolverCompetitionDB, number::conversions::u256_to_big_decimal, - primitive_types::{H160, U256}, std::collections::{BTreeMap, HashMap, HashSet}, }; #[derive(Clone, Default, Debug)] pub struct Competition { pub auction_id: AuctionId, - pub reference_scores: HashMap, + pub reference_scores: HashMap, /// Addresses to which the CIP20 participation rewards will be payed out. /// Usually the same as the solver addresses. - pub participants: HashSet, + pub participants: HashSet
, /// External prices for auction. - pub prices: BTreeMap, + pub prices: BTreeMap, /// Winner receives performance rewards if a settlement is finalized on /// chain before this block height. pub block_deadline: u64, @@ -67,7 +66,7 @@ impl super::Postgres { .into_iter() .map(|(token, price)| AuctionPrice { auction_id: competition.auction_id, - token: ByteArray(token.0), + token: ByteArray(token.0.0), price: u256_to_big_decimal(&price), }) .collect::>() @@ -91,7 +90,7 @@ impl super::Postgres { pub async fn save_surplus_capturing_jit_order_owners( &self, auction_id: AuctionId, - surplus_capturing_jit_order_owners: &[Address], + surplus_capturing_jit_order_owners: &[database::Address], ) -> anyhow::Result<()> { let mut ex = self.pool.acquire().await.context("acquire")?; diff --git a/crates/autopilot/src/database/ethflow_events/event_retriever.rs b/crates/autopilot/src/database/ethflow_events/event_retriever.rs index f4bcd5e4df..1278097c09 100644 --- a/crates/autopilot/src/database/ethflow_events/event_retriever.rs +++ b/crates/autopilot/src/database/ethflow_events/event_retriever.rs @@ -7,8 +7,9 @@ use { rpc::types::{Filter, FilterSet}, sol_types::SolEvent, }, - contracts::alloy::CoWSwapEthFlow::CoWSwapEthFlow, - shared::{ethrpc::Web3, event_handling::AlloyEventRetrieving}, + contracts::CoWSwapEthFlow::CoWSwapEthFlow, + ethrpc::Web3, + event_indexing::event_handler::AlloyEventRetrieving, }; pub struct EthFlowRefundRetriever { @@ -29,8 +30,8 @@ impl EthFlowRefundRetriever { impl AlloyEventRetrieving for EthFlowRefundRetriever { type Event = CoWSwapEthFlow::CoWSwapEthFlowEvents; - fn provider(&self) -> &contracts::alloy::Provider { - &self.web3.alloy + fn provider(&self) -> &alloy::providers::DynProvider { + &self.web3.provider } fn filter(&self) -> alloy::rpc::types::Filter { diff --git a/crates/autopilot/src/database/ethflow_events/event_storing.rs b/crates/autopilot/src/database/ethflow_events/event_storing.rs index d9046a9e3d..82e37ff484 100644 --- a/crates/autopilot/src/database/ethflow_events/event_storing.rs +++ b/crates/autopilot/src/database/ethflow_events/event_storing.rs @@ -4,10 +4,9 @@ use { crate::database::{Postgres, events::bytes_to_order_uid}, alloy::rpc::types::Log, anyhow::Result, - contracts::alloy::CoWSwapEthFlow::CoWSwapEthFlow::CoWSwapEthFlowEvents, + contracts::CoWSwapEthFlow::CoWSwapEthFlow::CoWSwapEthFlowEvents, database::ethflow_orders::Refund, - ethrpc::block_stream::RangeInclusive, - shared::event_handling::EventStoring, + event_indexing::{block_retriever::RangeInclusive, event_handler::EventStoring}, }; fn get_refunds(events: Vec<(CoWSwapEthFlowEvents, Log)>) -> Result> { diff --git a/crates/autopilot/src/database/events.rs b/crates/autopilot/src/database/events.rs index 47138a673b..fc46c257f7 100644 --- a/crates/autopilot/src/database/events.rs +++ b/crates/autopilot/src/database/events.rs @@ -1,7 +1,7 @@ use { alloy::rpc::types::Log, anyhow::{Context, Result}, - contracts::alloy::GPv2Settlement::GPv2Settlement::{self, GPv2SettlementEvents}, + contracts::GPv2Settlement::GPv2Settlement::{self, GPv2SettlementEvents}, database::{ OrderUid, PgTransaction, @@ -9,8 +9,6 @@ use { byte_array::ByteArray, events::{Event, EventIndex, Invalidation, PreSignature, Settlement, Trade}, }, - ethcontract::EventMetadata, - ethrpc::alloy::conversions::IntoLegacy, number::conversions::u256_to_big_decimal, std::convert::TryInto, }; @@ -114,13 +112,6 @@ pub async fn replace_events( Ok(()) } -pub fn meta_to_event_index(meta: &EventMetadata) -> EventIndex { - EventIndex { - block_number: i64::try_from(meta.block_number).unwrap_or(i64::MAX), - log_index: i64::try_from(meta.log_index).unwrap_or(i64::MAX), - } -} - pub fn log_to_event_index(log: &Log) -> Option { Some(EventIndex { block_number: log.block_number.and_then(|n| i64::try_from(n).ok())?, @@ -138,9 +129,9 @@ pub fn bytes_to_order_uid(bytes: &[u8]) -> Result { fn convert_trade(trade: &GPv2Settlement::Trade, log: ValidatedLog) -> Result<(EventIndex, Event)> { let event = Trade { order_uid: bytes_to_order_uid(&trade.orderUid.0)?, - sell_amount_including_fee: u256_to_big_decimal(&trade.sellAmount.into_legacy()), - buy_amount: u256_to_big_decimal(&trade.buyAmount.into_legacy()), - fee_amount: u256_to_big_decimal(&trade.feeAmount.into_legacy()), + sell_amount_including_fee: u256_to_big_decimal(&trade.sellAmount), + buy_amount: u256_to_big_decimal(&trade.buyAmount), + fee_amount: u256_to_big_decimal(&trade.feeAmount), }; Ok((log.into(), Event::Trade(event))) } diff --git a/crates/autopilot/src/database/mod.rs b/crates/autopilot/src/database/mod.rs index 38bd9a50aa..98f7c4bbb6 100644 --- a/crates/autopilot/src/database/mod.rs +++ b/crates/autopilot/src/database/mod.rs @@ -1,7 +1,11 @@ use { num::ToPrimitive, - sqlx::{Executor, PgConnection, PgPool}, - std::{num::NonZeroUsize, time::Duration}, + shared::arguments::DB_MAX_CONNECTIONS_DEFAULT, + sqlx::{Executor, PgConnection, PgPool, postgres::PgPoolOptions}, + std::{ + num::{NonZeroU32, NonZeroUsize}, + time::Duration, + }, tracing::Instrument, }; @@ -15,9 +19,21 @@ pub mod onchain_order_events; pub mod order_events; mod quotes; +pub const INSERT_BATCH_SIZE_DEFAULT: NonZeroUsize = NonZeroUsize::new(500).unwrap(); + #[derive(Debug, Clone)] pub struct Config { pub insert_batch_size: NonZeroUsize, + pub max_pool_size: NonZeroU32, +} + +impl Default for Config { + fn default() -> Self { + Self { + insert_batch_size: INSERT_BATCH_SIZE_DEFAULT, + max_pool_size: DB_MAX_CONNECTIONS_DEFAULT, + } + } } #[derive(Debug, Clone)] @@ -27,15 +43,15 @@ pub struct Postgres { } impl Postgres { - pub async fn new(url: &str, insert_batch_size: NonZeroUsize) -> sqlx::Result { - let pool = PgPool::connect(url).await?; + pub async fn new(url: &str, config: Config) -> sqlx::Result { + let pool = PgPoolOptions::new() + .max_connections(config.max_pool_size.get()) + .connect(url) + .await?; Self::start_db_metrics_job(pool.clone()); - Ok(Self { - pool, - config: Config { insert_batch_size }, - }) + Ok(Self { pool, config }) } fn start_db_metrics_job(pool: PgPool) { @@ -57,7 +73,7 @@ impl Postgres { } pub async fn with_defaults() -> sqlx::Result { - Self::new("postgresql://", NonZeroUsize::new(500).unwrap()).await + Self::new("postgresql://", Default::default()).await } pub async fn update_database_metrics(&self) -> sqlx::Result<()> { @@ -77,10 +93,6 @@ impl Postgres { metrics.table_rows.with_label_values(&[table]).set(count); } - // update unused app data metric - let count = count_unused_app_data(&mut ex).await?; - metrics.unused_app_data.set(count); - Ok(()) } @@ -109,32 +121,12 @@ async fn analyze_table(ex: &mut PgConnection, table: &str) -> sqlx::Result<()> { ex.execute(sqlx::query(&query)).await.map(|_| ()) } -async fn count_unused_app_data(ex: &mut PgConnection) -> sqlx::Result { - let query = r#" - SELECT - COUNT(*) - FROM app_data AS a - LEFT JOIN orders o - ON a.contract_app_data = o.app_data - WHERE - o.app_data IS NULL - ; - "#; - sqlx::query_scalar(query).fetch_one(ex).await -} - #[derive(prometheus_metric_storage::MetricStorage)] struct Metrics { /// Number of rows in db tables. #[metric(labels("table"))] table_rows: prometheus::IntGaugeVec, - /// Number of unused app data entries. - /// - /// These are entries in the `app_data` table that do not have a - /// corresponding order in the `orders` table. - unused_app_data: prometheus::IntGauge, - /// Timing of db queries. #[metric( name = "autopilot_database_queries", @@ -165,7 +157,6 @@ pub fn run_database_metrics_work(db: Postgres) { let span = tracing::info_span!("database_metrics"); // Spawn the task for updating large table statistics tokio::spawn(update_large_tables_stats(db.clone()).instrument(span.clone())); - // Spawn the task for database metrics tokio::task::spawn(database_metrics(db).instrument(span)); } diff --git a/crates/autopilot/src/database/onchain_order_events/ethflow_events.rs b/crates/autopilot/src/database/onchain_order_events/ethflow_events.rs index 9dd67203b7..9f6c545503 100644 --- a/crates/autopilot/src/database/onchain_order_events/ethflow_events.rs +++ b/crates/autopilot/src/database/onchain_order_events/ethflow_events.rs @@ -3,7 +3,7 @@ use { crate::database::events::log_to_event_index, alloy::{eips::BlockNumberOrTag, rpc::types::Log}, anyhow::{Context, Result, anyhow}, - contracts::alloy::{ + contracts::{ CoWSwapOnchainOrders::CoWSwapOnchainOrders::{ CoWSwapOnchainOrdersEvents as ContractEvent, OrderPlacement as ContractOrderPlacement, @@ -262,7 +262,7 @@ async fn find_indexing_start_block( if last_indexed_block > 0 { return block_number_to_block_number_hash( - &web3.alloy, + &web3.provider, BlockNumberOrTag::Number(last_indexed_block), ) .await @@ -271,7 +271,7 @@ async fn find_indexing_start_block( } if let Some(start_block) = fallback_start_block { return block_number_to_block_number_hash( - &web3.alloy, + &web3.provider, BlockNumberOrTag::Number(start_block), ) .await @@ -279,7 +279,7 @@ async fn find_indexing_start_block( .context("failed to fetch fallback indexing start block"); } if let Some(chain_id) = settlement_fallback_chain_id { - return settlement_deployment_block_number_hash(&web3.alloy, chain_id) + return settlement_deployment_block_number_hash(&web3.provider, chain_id) .await .map(Some) .context("failed to fetch settlement deployment block"); @@ -293,7 +293,7 @@ mod test { use { super::*, alloy::primitives::{Address, U256}, - contracts::alloy::CoWSwapOnchainOrders, + contracts::CoWSwapOnchainOrders, model::order::{BuyTokenDestination, OrderKind, SellTokenSource}, }; diff --git a/crates/autopilot/src/database/onchain_order_events/event_retriever.rs b/crates/autopilot/src/database/onchain_order_events/event_retriever.rs index ed99df97bf..4f7619e48b 100644 --- a/crates/autopilot/src/database/onchain_order_events/event_retriever.rs +++ b/crates/autopilot/src/database/onchain_order_events/event_retriever.rs @@ -4,8 +4,9 @@ use { rpc::types::{Filter, FilterSet}, sol_types::SolEvent, }, - contracts::alloy::CoWSwapOnchainOrders, - shared::{ethrpc::Web3, event_handling::AlloyEventRetrieving}, + contracts::CoWSwapOnchainOrders, + ethrpc::Web3, + event_indexing::event_handler::AlloyEventRetrieving, }; // Note: we use a custom implementation of `EventRetrieving` rather than using @@ -42,7 +43,7 @@ impl AlloyEventRetrieving for CoWSwapOnchainOrdersContract { ])) } - fn provider(&self) -> &contracts::alloy::Provider { - &self.web3.alloy + fn provider(&self) -> &alloy::providers::DynProvider { + &self.web3.provider } } diff --git a/crates/autopilot/src/database/onchain_order_events/mod.rs b/crates/autopilot/src/database/onchain_order_events/mod.rs index 52d9d578b5..289ae0fd5e 100644 --- a/crates/autopilot/src/database/onchain_order_events/mod.rs +++ b/crates/autopilot/src/database/onchain_order_events/mod.rs @@ -12,7 +12,7 @@ use { anyhow::{Context, Result, anyhow, bail}, app_data::AppDataHash, chrono::{TimeZone, Utc}, - contracts::alloy::{ + contracts::{ CoWSwapOnchainOrders::CoWSwapOnchainOrders::{ CoWSwapOnchainOrdersEvents as ContractEvent, OrderInvalidation, @@ -27,12 +27,8 @@ use { onchain_broadcasted_orders::{OnchainOrderPlacement, OnchainOrderPlacementError}, orders::{Order, OrderClass, insert_quotes}, }, - ethcontract::H160, - ethrpc::{ - Web3, - alloy::conversions::IntoLegacy, - block_stream::{RangeInclusive, timestamp_of_block_in_seconds}, - }, + ethrpc::{Web3, block_stream::timestamp_of_block_in_seconds}, + event_indexing::{block_retriever::RangeInclusive, event_handler::EventStoring}, futures::{StreamExt, stream}, itertools::{izip, multiunzip}, model::{ @@ -55,7 +51,6 @@ use { sell_token_source_into, signing_scheme_into, }, - event_handling::EventStoring, order_quoting::{OrderQuoting, Quote, QuoteSearchParameters}, order_validation::{ ValidationError, @@ -73,7 +68,7 @@ pub struct OnchainOrderParser { quoter: Arc, custom_onchain_data_parser: Box>, domain_separator: DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, metrics: &'static Metrics, trampoline: HooksTrampoline::Instance, } @@ -89,7 +84,7 @@ where quoter: Arc, custom_onchain_data_parser: Box>, domain_separator: DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, trampoline: HooksTrampoline::Instance, ) -> Self { OnchainOrderParser { @@ -395,9 +390,11 @@ async fn get_block_numbers_of_events( let futures = event_block_numbers .into_iter() .map(|block_number| async move { - let timestamp = - timestamp_of_block_in_seconds(&web3.alloy, BlockNumberOrTag::Number(block_number)) - .await?; + let timestamp = timestamp_of_block_in_seconds( + &web3.provider, + BlockNumberOrTag::Number(block_number), + ) + .await?; Ok((block_number, timestamp)) }); let block_number_timestamp_pair: Vec> = @@ -454,7 +451,7 @@ async fn parse_general_onchain_order_placement_data( quoter: &'_ dyn OrderQuoting, order_placement_events_and_quotes_zipped: I, domain_separator: DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, metrics: &'static Metrics, ) -> Vec where @@ -489,7 +486,7 @@ where order_data, signing_scheme, order_uid, - owner.into_legacy(), + owner, settlement_contract, metrics, ); @@ -501,7 +498,7 @@ where sell_token_price: quote.data.fee_parameters.sell_token_price, sell_amount: u256_to_big_decimal("e.sell_amount), buy_amount: u256_to_big_decimal("e.buy_amount), - solver: ByteArray(quote.data.solver.0), + solver: ByteArray(*quote.data.solver.0), verified: quote.data.verified, metadata: quote.data.metadata.try_into()?, }), @@ -550,11 +547,11 @@ async fn get_quote( .map_err(|_| OnchainOrderPlacementError::Other)?; let parameters = QuoteSearchParameters { - sell_token: order_data.sell_token.into_legacy(), - buy_token: order_data.buy_token.into_legacy(), - sell_amount: order_data.sell_amount.into_legacy(), - buy_amount: order_data.buy_amount.into_legacy(), - fee_amount: order_data.fee_amount.into_legacy(), + sell_token: order_data.sell_token, + buy_token: order_data.buy_token, + sell_amount: order_data.sell_amount, + buy_amount: order_data.buy_amount, + fee_amount: order_data.fee_amount, kind: order_data.kind, signing_scheme: quote_signing_scheme, additional_gas: 0, @@ -572,7 +569,7 @@ async fn get_quote( quoter, ¶meters.clone(), Some(*quote_id), - Some(order_data.fee_amount.into_legacy()), + Some(order_data.fee_amount), ) .await .map_err(|err| match err { @@ -590,8 +587,8 @@ fn convert_onchain_order_placement( order_data: OrderData, signing_scheme: SigningScheme, order_uid: OrderUid, - owner: H160, - settlement_contract: H160, + owner: Address, + settlement_contract: Address, metrics: &'static Metrics, ) -> (OnchainOrderPlacement, Order) { // eth flow orders are expected to be within the market price so they are @@ -609,21 +606,21 @@ fn convert_onchain_order_placement( let order = database::orders::Order { uid: ByteArray(order_uid.0), - owner: ByteArray(owner.0), + owner: ByteArray(owner.0.0), creation_timestamp: Utc.timestamp_opt(event_timestamp, 0).unwrap(), sell_token: ByteArray(order_data.sell_token.0.0), buy_token: ByteArray(order_data.buy_token.0.0), receiver: order_data.receiver.map(|addr| ByteArray(addr.0.0)), - sell_amount: u256_to_big_decimal(&order_data.sell_amount.into_legacy()), - buy_amount: u256_to_big_decimal(&order_data.buy_amount.into_legacy()), + sell_amount: u256_to_big_decimal(&order_data.sell_amount), + buy_amount: u256_to_big_decimal(&order_data.buy_amount), valid_to: order_data.valid_to as i64, app_data: ByteArray(order_data.app_data.0), - fee_amount: u256_to_big_decimal(&order_data.fee_amount.into_legacy()), + fee_amount: u256_to_big_decimal(&order_data.fee_amount), kind: order_kind_into(order_data.kind), partially_fillable: order_data.partially_fillable, signature: order_placement.signature.data.to_vec(), signing_scheme: signing_scheme_into(signing_scheme), - settlement_contract: ByteArray(settlement_contract.0), + settlement_contract: ByteArray(settlement_contract.0.0), sell_token_balance: sell_token_source_into(order_data.sell_token_balance), buy_token_balance: buy_token_destination_into(order_data.buy_token_balance), cancellation_timestamp: None, @@ -679,7 +676,7 @@ fn extract_order_data_from_onchain_order_placement_event( order_placement.order.buyTokenBalance.0, )?, }; - let order_uid = order_data.uid(&domain_separator, &owner.into_legacy()); + let order_uid = order_data.uid(&domain_separator, owner); Ok((order_data, owner, signing_scheme, order_uid)) } @@ -782,21 +779,16 @@ mod test { use { super::*, - crate::database::Config, alloy::primitives::U256, - contracts::alloy::{CoWSwapOnchainOrders, InstanceExt}, + contracts::CoWSwapOnchainOrders, database::{byte_array::ByteArray, onchain_broadcasted_orders::OnchainOrderPlacement}, - ethcontract::H160, ethrpc::Web3, model::{ DomainSeparator, order::{BuyTokenDestination, OrderData, OrderKind, SellTokenSource}, signature::SigningScheme, }, - number::conversions::{ - alloy::u256_to_big_decimal as alloy_u256_to_big_decimal, - u256_to_big_decimal, - }, + number::conversions::u256_to_big_decimal, shared::{ db_order_conversions::{ buy_token_destination_into, @@ -808,7 +800,6 @@ mod test { order_quoting::{MockOrderQuoting, Quote, QuoteData}, }, sqlx::PgPool, - std::num::NonZeroUsize, }; #[test] @@ -872,7 +863,7 @@ mod test { sell_token_balance: SellTokenSource::Erc20, buy_token_balance: BuyTokenDestination::Erc20, }; - let expected_uid = expected_order_data.uid(&domain_separator, &owner.into_legacy()); + let expected_uid = expected_order_data.uid(&domain_separator, owner); assert_eq!(sender, order_placement.sender); assert_eq!(signing_scheme, SigningScheme::Eip1271); assert_eq!(order_data, expected_order_data); @@ -957,7 +948,7 @@ mod test { let order_placement = ContractOrderPlacement { sender, - order: contracts::alloy::CoWSwapOnchainOrders::GPv2Order::Data { + order: contracts::CoWSwapOnchainOrders::GPv2Order::Data { sellToken: sell_token, buyToken: buy_token, receiver, @@ -971,14 +962,13 @@ mod test { sellTokenBalance: SellTokenSource::ERC20.into(), buyTokenBalance: BuyTokenDestination::ERC20.into(), }, - signature: - contracts::alloy::CoWSwapOnchainOrders::ICoWSwapOnchainOrders::OnchainSignature { - scheme: 0, - data: owner.0.into(), - }, + signature: contracts::CoWSwapOnchainOrders::ICoWSwapOnchainOrders::OnchainSignature { + scheme: 0, + data: owner.0.into(), + }, data: Default::default(), }; - let settlement_contract = H160::from([8u8; 20]); + let settlement_contract = Address::repeat_byte(8); let quote = Quote::default(); let order_uid = OrderUid([9u8; 56]); let signing_scheme = SigningScheme::Eip1271; @@ -990,7 +980,7 @@ mod test { order_data, signing_scheme, order_uid, - owner.into_legacy(), + owner, settlement_contract, Metrics::get(), ); @@ -1015,23 +1005,23 @@ mod test { }; let expected_order = database::orders::Order { uid: ByteArray(order_uid.0), - owner: ByteArray(owner.into_legacy().0), + owner: ByteArray(owner.0.0), creation_timestamp: order.creation_timestamp, /* Using the actual result to keep test * simple */ sell_token: ByteArray(expected_order_data.sell_token.0.0), buy_token: ByteArray(expected_order_data.buy_token.0.0), receiver: expected_order_data.receiver.map(|addr| ByteArray(addr.0.0)), - sell_amount: alloy_u256_to_big_decimal(&expected_order_data.sell_amount), - buy_amount: alloy_u256_to_big_decimal(&expected_order_data.buy_amount), + sell_amount: u256_to_big_decimal(&expected_order_data.sell_amount), + buy_amount: u256_to_big_decimal(&expected_order_data.buy_amount), valid_to: expected_order_data.valid_to as i64, app_data: ByteArray(expected_order_data.app_data.0), - fee_amount: alloy_u256_to_big_decimal(&expected_order_data.fee_amount), + fee_amount: u256_to_big_decimal(&expected_order_data.fee_amount), kind: order_kind_into(expected_order_data.kind), class: OrderClass::Market, partially_fillable: expected_order_data.partially_fillable, signature: order_placement.signature.data.to_vec(), signing_scheme: signing_scheme_into(SigningScheme::Eip1271), - settlement_contract: ByteArray(settlement_contract.0), + settlement_contract: ByteArray(settlement_contract.0.into()), sell_token_balance: sell_token_source_into(expected_order_data.sell_token_balance), buy_token_balance: buy_token_destination_into(expected_order_data.buy_token_balance), cancellation_timestamp: None, @@ -1050,7 +1040,7 @@ mod test { let buy_amount = U256::from(11); let valid_to = 1u32; let app_data = [11u8; 32]; - let fee_amount = U256::from(0); + let fee_amount = U256::ZERO; let owner = Address::from([5; 20]); let order_data = OrderData { sell_token, @@ -1068,7 +1058,7 @@ mod test { }; let order_placement = ContractOrderPlacement { sender, - order: contracts::alloy::CoWSwapOnchainOrders::GPv2Order::Data { + order: contracts::CoWSwapOnchainOrders::GPv2Order::Data { sellToken: sell_token, buyToken: buy_token, receiver, @@ -1082,17 +1072,16 @@ mod test { sellTokenBalance: SellTokenSource::ERC20.into(), buyTokenBalance: BuyTokenDestination::ERC20.into(), }, - signature: - contracts::alloy::CoWSwapOnchainOrders::ICoWSwapOnchainOrders::OnchainSignature { - scheme: 0, - data: owner.0.into(), - }, + signature: contracts::CoWSwapOnchainOrders::ICoWSwapOnchainOrders::OnchainSignature { + scheme: 0, + data: owner.0.into(), + }, data: Default::default(), }; - let settlement_contract = H160::from([8u8; 20]); + let settlement_contract = Address::repeat_byte(8); let quote = Quote { - sell_amount: sell_amount.into_legacy(), - buy_amount: (buy_amount / U256::from(2)).into_legacy(), + sell_amount, + buy_amount: buy_amount / U256::from(2), ..Default::default() }; let order_uid = OrderUid([9u8; 56]); @@ -1104,7 +1093,7 @@ mod test { order_data, signing_scheme, order_uid, - owner.into_legacy(), + owner, settlement_contract, Metrics::get(), ); @@ -1129,23 +1118,23 @@ mod test { }; let expected_order = database::orders::Order { uid: ByteArray(order_uid.0), - owner: ByteArray(owner.into_legacy().0), + owner: ByteArray(owner.0.0), creation_timestamp: order.creation_timestamp, /* Using the actual result to keep test * simple */ sell_token: ByteArray(expected_order_data.sell_token.0.0), buy_token: ByteArray(expected_order_data.buy_token.0.0), receiver: expected_order_data.receiver.map(|addr| ByteArray(addr.0.0)), - sell_amount: alloy_u256_to_big_decimal(&expected_order_data.sell_amount), - buy_amount: alloy_u256_to_big_decimal(&expected_order_data.buy_amount), + sell_amount: u256_to_big_decimal(&expected_order_data.sell_amount), + buy_amount: u256_to_big_decimal(&expected_order_data.buy_amount), valid_to: expected_order_data.valid_to as i64, app_data: ByteArray(expected_order_data.app_data.0), - fee_amount: u256_to_big_decimal(&fee_amount.into_legacy()), + fee_amount: u256_to_big_decimal(&fee_amount), kind: order_kind_into(expected_order_data.kind), class: OrderClass::Limit, partially_fillable: expected_order_data.partially_fillable, signature: order_placement.signature.data.to_vec(), signing_scheme: signing_scheme_into(SigningScheme::Eip1271), - settlement_contract: ByteArray(settlement_contract.0), + settlement_contract: ByteArray(settlement_contract.0.into()), sell_token_balance: sell_token_source_into(expected_order_data.sell_token_balance), buy_token_balance: buy_token_destination_into(expected_order_data.buy_token_balance), cancellation_timestamp: None, @@ -1169,7 +1158,7 @@ mod test { let owner = Address::from([6; 20]); let order_placement = ContractOrderPlacement { sender, - order: contracts::alloy::CoWSwapOnchainOrders::GPv2Order::Data { + order: contracts::CoWSwapOnchainOrders::GPv2Order::Data { sellToken: sell_token, buyToken: buy_token, receiver, @@ -1183,11 +1172,10 @@ mod test { sellTokenBalance: SellTokenSource::ERC20.into(), buyTokenBalance: BuyTokenDestination::ERC20.into(), }, - signature: - contracts::alloy::CoWSwapOnchainOrders::ICoWSwapOnchainOrders::OnchainSignature { - scheme: 0, - data: owner.0.into(), - }, + signature: contracts::CoWSwapOnchainOrders::ICoWSwapOnchainOrders::OnchainSignature { + scheme: 0, + data: owner.0.into(), + }, data: vec![0u8, 0u8, 1u8, 2u8, 0u8, 0u8, 1u8, 2u8, 0u8, 0u8, 1u8, 2u8].into(), }; @@ -1212,13 +1200,10 @@ mod test { let quote = Quote { id: Some(0i64), data: QuoteData { - sell_token: sell_token.into_legacy(), - buy_token: buy_token.into_legacy(), - quoted_sell_amount: sell_amount - .checked_sub(U256::from(1)) - .unwrap() - .into_legacy(), - quoted_buy_amount: buy_amount.checked_sub(U256::from(1)).unwrap().into_legacy(), + sell_token, + buy_token, + quoted_sell_amount: sell_amount.checked_sub(U256::from(1)).unwrap(), + quoted_buy_amount: buy_amount.checked_sub(U256::from(1)).unwrap(), fee_parameters: FeeParameters { gas_amount: 2.0f64, gas_price: 3.0f64, @@ -1226,9 +1211,9 @@ mod test { }, ..Default::default() }, - sell_amount: sell_amount.into_legacy(), - buy_amount: buy_amount.into_legacy(), - fee_amount: fee_amount.into_legacy(), + sell_amount, + buy_amount, + fee_amount, }; let cloned_quote = quote.clone(); order_quoter @@ -1259,18 +1244,16 @@ mod test { let onchain_order_parser = OnchainOrderParser { db: Postgres { pool: PgPool::connect_lazy("postgresql://").unwrap(), - config: Config { - insert_batch_size: NonZeroUsize::new(500).unwrap(), - }, + config: Default::default(), }, - trampoline: HooksTrampoline::Instance::deployed(&web3.alloy) + trampoline: HooksTrampoline::Instance::deployed(&web3.provider) .await .unwrap(), web3, quoter: Arc::new(order_quoter), custom_onchain_data_parser: Box::new(custom_onchain_order_parser), domain_separator, - settlement_contract: H160::zero(), + settlement_contract: Address::ZERO, metrics: Metrics::get(), }; let result = onchain_order_parser @@ -1294,7 +1277,7 @@ mod test { sell_token_balance: SellTokenSource::Erc20, buy_token_balance: BuyTokenDestination::Erc20, }; - let expected_uid = expected_order_data.uid(&domain_separator, &owner.into_legacy()); + let expected_uid = expected_order_data.uid(&domain_separator, owner); let expected_event_index = EventIndex { block_number: 1, log_index: 0, @@ -1306,7 +1289,7 @@ mod test { sell_token_price: quote.data.fee_parameters.sell_token_price, sell_amount: u256_to_big_decimal("e.sell_amount), buy_amount: u256_to_big_decimal("e.buy_amount), - solver: ByteArray(quote.data.solver.0), + solver: ByteArray(*quote.data.solver.0), verified: quote.data.verified, metadata: quote.data.metadata.try_into().unwrap(), }; diff --git a/crates/autopilot/src/database/order_events.rs b/crates/autopilot/src/database/order_events.rs index 4a32c05f25..52c7878378 100644 --- a/crates/autopilot/src/database/order_events.rs +++ b/crates/autopilot/src/database/order_events.rs @@ -1,12 +1,9 @@ -pub use database::order_events::OrderEventLabel; +pub use database::order_events::{OrderEventLabel, OrderFilterReason}; use { crate::domain, anyhow::Result, chrono::{DateTime, Utc}, - database::{ - byte_array::ByteArray, - order_events::{self, OrderEvent}, - }, + database::{byte_array::ByteArray, order_events}, sqlx::{Acquire, Error, PgConnection}, tokio::time::Instant, }; @@ -22,24 +19,18 @@ pub async fn store_order_events( ex: &mut PgConnection, order_uids: Vec, label: OrderEventLabel, + reason: Option, timestamp: DateTime, ) { let start = Instant::now(); + let order_uids: Vec<_> = order_uids.into_iter().map(|o| ByteArray(o.0)).collect(); let count = order_uids.len(); let insert = async move { let mut ex = ex.begin().await?; - - for uid in order_uids { - let event = OrderEvent { - order_uid: ByteArray(uid.0), - timestamp, - label, - }; - - order_events::insert_order_event(&mut ex, &event).await?; + for chunk in order_uids.chunks(1000) { + order_events::insert_order_events(&mut ex, chunk, timestamp, label, reason).await?; } - ex.commit().await }; diff --git a/crates/autopilot/src/database/quotes.rs b/crates/autopilot/src/database/quotes.rs index 4205f51780..23360505a2 100644 --- a/crates/autopilot/src/database/quotes.rs +++ b/crates/autopilot/src/database/quotes.rs @@ -4,22 +4,21 @@ use { domain::{self}, infra::persistence::dto, }, - anyhow::{Context, Result}, + anyhow::Result, database::byte_array::ByteArray, - shared::maintenance::Maintaining, - sqlx::types::chrono::{DateTime, Utc}, + sqlx::types::chrono::Utc, std::collections::HashMap, }; impl Postgres { - pub async fn remove_expired_quotes(&self, max_expiry: DateTime) -> Result<()> { + pub async fn remove_expired_quotes(&self) -> Result<()> { let _timer = super::Metrics::get() .database_queries .with_label_values(&["remove_expired_quotes"]) .start_timer(); let mut ex = self.pool.acquire().await?; - database::quotes::remove_expired_quotes(&mut ex, max_expiry).await?; + database::quotes::remove_expired_quotes(&mut ex, Utc::now()).await?; Ok(()) } @@ -61,16 +60,3 @@ impl Postgres { Ok(quotes) } } - -#[async_trait::async_trait] -impl Maintaining for Postgres { - async fn run_maintenance(&self) -> Result<()> { - self.remove_expired_quotes(Utc::now()) - .await - .context("fee measurement maintenance error") - } - - fn name(&self) -> &str { - "Postgres" - } -} diff --git a/crates/autopilot/src/domain/auction/mod.rs b/crates/autopilot/src/domain/auction/mod.rs index 4eb623df8c..c6a4ef36ec 100644 --- a/crates/autopilot/src/domain/auction/mod.rs +++ b/crates/autopilot/src/domain/auction/mod.rs @@ -1,5 +1,7 @@ use { - super::{Order, eth}, + super::Order, + alloy::primitives::{Address, U256}, + eth_domain_types as eth, std::collections::HashMap, }; @@ -15,7 +17,7 @@ pub struct RawAuctionData { pub block: u64, pub orders: Vec, pub prices: Prices, - pub surplus_capturing_jit_order_owners: Vec, + pub surplus_capturing_jit_order_owners: Vec
, } pub type Id = i64; @@ -26,7 +28,7 @@ pub struct Auction { pub block: u64, pub orders: Vec, pub prices: Prices, - pub surplus_capturing_jit_order_owners: Vec, + pub surplus_capturing_jit_order_owners: Vec
, } impl PartialEq for Auction { @@ -67,16 +69,22 @@ impl Price { /// Converting 1 ETH expressed in `eth::TokenAmount` into `eth::Ether` /// /// ``` - /// use autopilot::domain::{auction::Price, eth}; + /// use {autopilot::domain::auction::Price, eth_domain_types as eth}; /// - /// let amount = eth::TokenAmount::from(eth::U256::exp10(18)); - /// let price = Price::try_new(eth::Ether::from(eth::U256::exp10(15))).unwrap(); // 0.001 ETH + /// let amount = eth::TokenAmount::from(eth::U256::from(10).pow(eth::U256::from(18))); + /// let price = Price::try_new(eth::Ether::from( + /// eth::U256::from(10).pow(eth::U256::from(15)), // 0.001 ETH + /// )) + /// .unwrap(); /// /// let eth = price.in_eth(amount); - /// assert_eq!(eth, eth::Ether::from(eth::U256::exp10(15))); + /// assert_eq!( + /// eth, + /// eth::Ether::from(eth::U256::from(10).pow(eth::U256::from(15))) + /// ); /// ``` pub fn in_eth(self, amount: eth::TokenAmount) -> eth::Ether { - (amount.0 * self.0.0 / Self::BASE).into() + (amount.0 * self.0.0 / U256::from(Self::BASE)).into() } } diff --git a/crates/autopilot/src/domain/auction/order.rs b/crates/autopilot/src/domain/auction/order.rs index 24434c687e..abe39e90b4 100644 --- a/crates/autopilot/src/domain/auction/order.rs +++ b/crates/autopilot/src/domain/auction/order.rs @@ -1,9 +1,7 @@ use { - crate::{ - domain, - domain::{eth, fee}, - }, - primitive_types::{H160, H256, U256}, + crate::domain::{self, fee}, + alloy::primitives::{Address, B256, U256}, + eth_domain_types as eth, std::fmt::{self, Debug, Display, Formatter}, }; @@ -37,15 +35,15 @@ pub struct OrderUid(pub [u8; 56]); impl OrderUid { pub fn owner(&self) -> eth::Address { - self.parts().1.into() + eth::Address::from(self.parts().1.0) } /// Splits an order UID into its parts. - fn parts(&self) -> (H256, H160, u32) { + fn parts(&self) -> (B256, Address, u32) { ( - H256::from_slice(&self.0[0..32]), - H160::from_slice(&self.0[32..52]), - u32::from_le_bytes(self.0[52..].try_into().unwrap()), + B256::from_slice(&self.0[0..32]), + Address::from_slice(&self.0[32..52]), + u32::from_be_bytes(self.0[52..].try_into().unwrap()), ) } } @@ -76,7 +74,7 @@ pub enum Side { #[derive(Clone, Debug, PartialEq)] pub struct Interaction { - pub target: H160, + pub target: Address, pub value: U256, pub call_data: Vec, } @@ -178,8 +176,8 @@ pub enum SigningScheme { #[derive(Copy, Clone, Debug, PartialEq)] pub struct EcdsaSignature { - pub r: H256, - pub s: H256, + pub r: B256, + pub s: B256, pub v: u8, } @@ -187,8 +185,8 @@ impl EcdsaSignature { /// r + s + v pub fn to_bytes(self) -> [u8; 65] { let mut bytes = [0u8; 65]; - bytes[..32].copy_from_slice(self.r.as_bytes()); - bytes[32..64].copy_from_slice(self.s.as_bytes()); + bytes[..32].copy_from_slice(self.r.as_slice()); + bytes[32..64].copy_from_slice(self.s.as_slice()); bytes[64] = self.v; bytes } @@ -210,3 +208,66 @@ impl From for eth::U256 { value.0 } } + +#[cfg(test)] +mod tests { + use { + super::*, + alloy::primitives::{address, b256}, + }; + + // Canonical CoW Protocol order UID layout: 32B orderDigest || 20B owner || + // 4B big-endian validTo. These tests guard against regressions to + // little-endian decoding, which would silently corrupt validTo without + // affecting owner(). + #[test] + fn parts_decodes_valid_to_as_big_endian() { + let mut bytes = [0u8; 56]; + bytes[0..32].copy_from_slice(&[0x11; 32]); + bytes[32..52].copy_from_slice(&[0x22; 20]); + // valid_to = 0x12345678 encoded big-endian as 0x12, 0x34, 0x56, 0x78. + // Little-endian decoding would yield 0x78563412 — exercised by the + // assertion below. + bytes[52..56].copy_from_slice(&[0x12, 0x34, 0x56, 0x78]); + let uid = OrderUid(bytes); + + let (order_hash, owner, valid_to) = uid.parts(); + assert_eq!(order_hash, B256::from([0x11; 32])); + assert_eq!(owner, Address::repeat_byte(0x22)); + assert_eq!(valid_to, 0x1234_5678); + } + + #[test] + fn parts_matches_canonical_model_encoding() { + // Same fixture as model::order::tests::order_uid_parts to ensure + // autopilot's decoding agrees with the canonical OrderUid layout. + let uid = OrderUid( + const_hex::decode_to_array::<_, 56>( + b"5668997bd3fb981d1b3ec44e8483e7c369756df47d10241c1c7a26fde4d1090e89984d17af2f18f8c54873c0de68a56cc5a23e0f695ba915", + ) + .unwrap(), + ); + let (order_hash, owner, valid_to) = uid.parts(); + assert_eq!( + order_hash, + b256!("0x5668997bd3fb981d1b3ec44e8483e7c369756df47d10241c1c7a26fde4d1090e") + ); + assert_eq!( + owner, + address!("0x89984d17af2f18f8c54873c0de68a56cc5a23e0f") + ); + assert_eq!(valid_to, 1767614741); + } + + #[test] + fn owner_returns_address_slice() { + let mut bytes = [0u8; 56]; + bytes[32..52].copy_from_slice(&[0xab; 20]); + // Set the trailing 4 bytes to a value that would differ in LE vs BE + // interpretation, ensuring owner() is unaffected either way. + bytes[52..56].copy_from_slice(&[0xde, 0xad, 0xbe, 0xef]); + let uid = OrderUid(bytes); + + assert_eq!(uid.owner(), eth::Address::from([0xab; 20])); + } +} diff --git a/crates/autopilot/src/domain/blockchain.rs b/crates/autopilot/src/domain/blockchain.rs new file mode 100644 index 0000000000..05f3d709e2 --- /dev/null +++ b/crates/autopilot/src/domain/blockchain.rs @@ -0,0 +1,47 @@ +use eth_domain_types as eth; + +/// Originated from the blockchain transaction input data. +pub type Calldata = alloy::primitives::Bytes; + +/// Call frames of a transaction. +#[derive(Clone, Debug, Default)] +pub struct CallFrame { + /// The address of the call initiator. + pub from: eth::Address, + /// The address of the contract that was called. + pub to: Option, + /// Calldata input. + pub input: Calldata, + /// Recorded child calls. + pub calls: Vec, +} + +impl From for CallFrame { + fn from(value: alloy::rpc::types::trace::geth::CallFrame) -> Self { + Self { + from: value.from, + to: value.to, + input: value.input, + calls: value.calls.into_iter().map(Into::into).collect(), + } + } +} + +/// Any type of on-chain transaction. +#[derive(Debug, Clone, Default)] +pub struct Transaction { + /// The hash of the transaction. + pub hash: eth::TxId, + /// The address of the sender of the transaction. + pub from: eth::Address, + /// The block number of the block that contains the transaction. + pub block: eth::BlockNo, + /// The timestamp of the block that contains the transaction. + pub timestamp: u32, + /// The gas used by the transaction. + pub gas: eth::Gas, + /// The effective gas price of the transaction. + pub gas_price: eth::EffectiveGasPrice, + /// Traces of all Calls contained in the transaction. + pub trace_calls: CallFrame, +} diff --git a/crates/autopilot/src/domain/competition/bid.rs b/crates/autopilot/src/domain/competition/bid.rs new file mode 100644 index 0000000000..4bf089ee56 --- /dev/null +++ b/crates/autopilot/src/domain/competition/bid.rs @@ -0,0 +1,64 @@ +pub use state::{RankType, Unscored}; +use { + super::Score, + crate::{domain::competition::Solution, infra}, + ::winner_selection::state, + std::sync::Arc, +}; + +pub type Scored = state::Scored; +pub type Ranked = state::Ranked; + +/// A solver's auction bid, which includes solution and corresponding driver +/// data, progressing through the winner selection process. +/// +/// It uses the type-state pattern to enforce correct state +/// transitions at compile time. The state parameter tracks progression through +/// three phases: +/// +/// 1. **Unscored**: Initial state when the solution is received from the driver +/// 2. **Scored**: After computing surplus and fees for the solution +/// 3. **Ranked**: After winner selection determines if this is a winner +#[derive(Clone)] +pub struct Bid { + solution: Solution, + driver: Arc, + state: State, +} + +impl Bid { + pub fn solution(&self) -> &Solution { + &self.solution + } + + pub fn driver(&self) -> &Arc { + &self.driver + } +} + +impl state::HasState for Bid { + type Next = Bid; + type State = State; + + fn with_state(self, state: NewState) -> Self::Next { + Bid { + solution: self.solution, + driver: self.driver, + state, + } + } + + fn state(&self) -> &Self::State { + &self.state + } +} + +impl Bid { + pub fn new(solution: Solution, driver: Arc) -> Self { + Self { + solution, + driver, + state: Unscored, + } + } +} diff --git a/crates/autopilot/src/domain/competition/mod.rs b/crates/autopilot/src/domain/competition/mod.rs index bfdc8de5e5..e87f19efa2 100644 --- a/crates/autopilot/src/domain/competition/mod.rs +++ b/crates/autopilot/src/domain/competition/mod.rs @@ -1,19 +1,17 @@ use { super::auction::order, - crate::domain::{self, auction, eth}, + crate::domain, + alloy::primitives::Address, derive_more::Display, + eth_domain_types as eth, num::Saturating, std::collections::HashMap, }; -mod participant; -mod participation_guard; +mod bid; pub mod winner_selection; -pub use { - participant::{Participant, Ranked, Unranked}, - participation_guard::SolverParticipationGuard, -}; +pub use bid::{Bid, RankType, Ranked, Scored, Unscored}; type SolutionId = u64; @@ -21,51 +19,29 @@ type SolutionId = u64; pub struct Solution { /// A solution ID provided by the solver. id: SolutionId, - solver: eth::Address, - /// Score reported by the solver in their response. - score: Score, + solver: Address, orders: HashMap, - prices: auction::Prices, - /// Score computed by the autopilot based on the solution - /// of the solver. - // TODO: refactor this to compute the score in the constructor - computed_score: Option, } impl Solution { pub fn new( id: SolutionId, - solver: eth::Address, - score: Score, + solver: Address, orders: HashMap, - prices: auction::Prices, ) -> Self { - Self { - id, - solver, - score, - orders, - prices, - computed_score: None, - } + Self { id, solver, orders } } +} +impl Solution { pub fn id(&self) -> SolutionId { self.id } - pub fn solver(&self) -> eth::Address { + pub fn solver(&self) -> Address { self.solver } - pub fn score(&self) -> Score { - self.score - } - - pub fn computed_score(&self) -> Option<&Score> { - self.computed_score.as_ref() - } - pub fn order_ids(&self) -> impl Iterator + std::fmt::Debug { self.orders.keys() } @@ -73,10 +49,6 @@ impl Solution { pub fn orders(&self) -> &HashMap { &self.orders } - - pub fn prices(&self) -> &HashMap { - &self.prices - } } #[derive(Debug, Copy, Clone)] @@ -108,14 +80,6 @@ pub struct TradedOrder { pub struct Score(eth::Ether); impl Score { - pub fn try_new(score: eth::Ether) -> Result { - if score.0.is_zero() { - Err(ZeroScore) - } else { - Ok(Self(score)) - } - } - pub fn get(&self) -> ð::Ether { &self.0 } @@ -140,17 +104,3 @@ impl num::CheckedSub for Score { self.0.checked_sub(&v.0).map(Score) } } - -#[derive(Debug, thiserror::Error)] -#[error("the solver proposed a 0-score solution")] -pub struct ZeroScore; - -#[derive(Debug, thiserror::Error)] -pub enum SolutionError { - #[error(transparent)] - ZeroScore(#[from] ZeroScore), - #[error(transparent)] - InvalidPrice(#[from] auction::InvalidPrice), - #[error("the solver got deny listed")] - SolverDenyListed, -} diff --git a/crates/autopilot/src/domain/competition/participant.rs b/crates/autopilot/src/domain/competition/participant.rs deleted file mode 100644 index 0a5636c3b4..0000000000 --- a/crates/autopilot/src/domain/competition/participant.rs +++ /dev/null @@ -1,62 +0,0 @@ -use { - super::{Score, Solution}, - crate::infra, - std::sync::Arc, -}; - -#[derive(Clone)] -pub struct Participant { - solution: Solution, - driver: Arc, - state: State, -} - -#[derive(Clone)] -pub struct Unranked; -pub enum Ranked { - Winner, - NonWinner, - FilteredOut, -} - -impl Participant { - pub fn solution(&self) -> &Solution { - &self.solution - } - - pub fn set_computed_score(&mut self, score: Score) { - self.solution.computed_score = Some(score); - } - - pub fn driver(&self) -> &Arc { - &self.driver - } -} - -impl Participant { - pub fn new(solution: Solution, driver: Arc) -> Self { - Self { - solution, - driver, - state: Unranked, - } - } - - pub fn rank(self, rank: Ranked) -> Participant { - Participant:: { - state: rank, - solution: self.solution, - driver: self.driver, - } - } -} - -impl Participant { - pub fn is_winner(&self) -> bool { - matches!(self.state, Ranked::Winner) - } - - pub fn filtered_out(&self) -> bool { - matches!(self.state, Ranked::FilteredOut) - } -} diff --git a/crates/autopilot/src/domain/competition/participation_guard/db.rs b/crates/autopilot/src/domain/competition/participation_guard/db.rs deleted file mode 100644 index 4c7b0ba53b..0000000000 --- a/crates/autopilot/src/domain/competition/participation_guard/db.rs +++ /dev/null @@ -1,210 +0,0 @@ -use { - crate::{ - arguments::{ - DbBasedSolverParticipationGuardConfig, - LowSettlingSolversFinderConfig, - NonSettlingSolversFinderConfig, - }, - domain::{Metrics, eth}, - infra::{self, solvers::dto}, - }, - chrono::{DateTime, Utc}, - ethrpc::block_stream::CurrentBlockWatcher, - std::{ - collections::{HashMap, HashSet}, - sync::Arc, - time::{Duration, Instant}, - }, - tokio::join, -}; - -/// Checks the DB by searching for solvers that won N last consecutive auctions -/// and either never settled any of them or their settlement success rate is -/// lower than `min_settlement_success_rate`. -#[derive(Clone)] -pub(super) struct SolverValidator(Arc); - -struct Inner { - persistence: infra::Persistence, - banned_solvers: dashmap::DashMap, - ttl: Duration, - non_settling_config: NonSettlingSolversFinderConfig, - low_settling_config: LowSettlingSolversFinderConfig, - drivers_by_address: HashMap>, -} - -impl SolverValidator { - pub fn new( - persistence: infra::Persistence, - current_block: CurrentBlockWatcher, - competition_updates_receiver: tokio::sync::mpsc::UnboundedReceiver<()>, - db_based_validator_config: DbBasedSolverParticipationGuardConfig, - drivers_by_address: HashMap>, - ) -> Self { - let self_ = Self(Arc::new(Inner { - persistence, - banned_solvers: Default::default(), - ttl: db_based_validator_config.solver_blacklist_cache_ttl, - non_settling_config: db_based_validator_config.non_settling_solvers_finder_config, - low_settling_config: db_based_validator_config.low_settling_solvers_finder_config, - drivers_by_address, - })); - - self_.start_maintenance(competition_updates_receiver, current_block); - - self_ - } - - /// Update the internal cache only once the competition auctions table is - /// updated to avoid redundant DB queries on each block or any other - /// timeout. - fn start_maintenance( - &self, - mut competition_updates_receiver: tokio::sync::mpsc::UnboundedReceiver<()>, - current_block: CurrentBlockWatcher, - ) { - let self_ = self.clone(); - tokio::spawn(async move { - while competition_updates_receiver.recv().await.is_some() { - let current_block = current_block.borrow().number; - - let (non_settling_solvers, mut low_settling_solvers) = join!( - self_.find_non_settling_solvers(current_block), - self_.find_low_settling_solvers(current_block) - ); - // Non-settling issue has a higher priority, remove duplicates from low-settling - // solvers. - low_settling_solvers.retain(|solver| !non_settling_solvers.contains(solver)); - - let found_at = Instant::now(); - let banned_until = Utc::now() + self_.0.ttl; - - self_.post_process( - &non_settling_solvers, - dto::notify::BanReason::UnsettledConsecutiveAuctions, - found_at, - current_block, - banned_until, - ); - self_.post_process( - &low_settling_solvers, - dto::notify::BanReason::HighSettleFailureRate, - found_at, - current_block, - banned_until, - ); - } - tracing::error!("stream of settlement updates terminated unexpectedly"); - }); - } - - async fn find_non_settling_solvers(&self, current_block: u64) -> HashSet { - if !self.0.non_settling_config.enabled { - return Default::default(); - } - - match self - .0 - .persistence - .find_non_settling_solvers( - self.0.non_settling_config.last_auctions_participation_count, - current_block, - ) - .await - { - Ok(solvers) => solvers.into_iter().collect(), - Err(err) => { - tracing::warn!(?err, "error while searching for non-settling solvers"); - Default::default() - } - } - } - - async fn find_low_settling_solvers(&self, current_block: u64) -> HashSet { - if !self.0.low_settling_config.enabled { - return Default::default(); - } - - match self - .0 - .persistence - .find_low_settling_solvers( - self.0.low_settling_config.last_auctions_participation_count, - current_block, - self.0 - .low_settling_config - .solver_max_settlement_failure_rate, - self.0.low_settling_config.min_wins_threshold, - ) - .await - { - Ok(solvers) => solvers.into_iter().collect(), - Err(err) => { - tracing::warn!(?err, "error while searching for low-settling solvers"); - Default::default() - } - } - } - - /// Updates the cache and notifies the solvers. - fn post_process( - &self, - solvers: &HashSet, - ban_reason: dto::notify::BanReason, - found_at_timestamp: Instant, - found_at_block: u64, - banned_until: DateTime, - ) { - let non_settling_solver_names: Vec<&str> = solvers - .iter() - .filter_map(|solver| self.0.drivers_by_address.get(solver)) - .map(|driver| { - Metrics::get() - .banned_solver - .with_label_values(&[driver.name.as_ref(), ban_reason.as_str()]) - .inc(); - // Check if solver accepted this feature. This should be removed once the - // CIP making this mandatory has been approved. - if driver.requested_timeout_on_problems { - let is_absent_or_expired = self - .0 - .banned_solvers - .get(&driver.submission_address) - .is_none_or(|entry| entry.elapsed() >= self.0.ttl); - // The solver should try again once the cache is expired. - if is_absent_or_expired { - tracing::debug!(solver = ?driver.name, "disabling solver temporarily"); - infra::notify_banned_solver(driver.clone(), ban_reason, banned_until); - self.0 - .banned_solvers - .insert(driver.submission_address, found_at_timestamp); - } - } - driver.name.as_ref() - }) - .collect(); - - if non_settling_solver_names.is_empty() { - return; - } - - let log_message = match ban_reason { - dto::notify::BanReason::UnsettledConsecutiveAuctions => "found non-settling solvers", - dto::notify::BanReason::HighSettleFailureRate => { - "found high-failure-settlement solvers" - } - }; - tracing::debug!(solvers = ?non_settling_solver_names, ?found_at_block, log_message); - } -} - -#[async_trait::async_trait] -impl super::SolverValidator for SolverValidator { - async fn is_allowed(&self, solver: ð::Address) -> anyhow::Result { - if let Some(entry) = self.0.banned_solvers.get(solver) { - return Ok(entry.elapsed() >= self.0.ttl); - } - - Ok(true) - } -} diff --git a/crates/autopilot/src/domain/competition/participation_guard/mod.rs b/crates/autopilot/src/domain/competition/participation_guard/mod.rs deleted file mode 100644 index dcff407581..0000000000 --- a/crates/autopilot/src/domain/competition/participation_guard/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -mod db; -mod onchain; - -use { - crate::{arguments::DbBasedSolverParticipationGuardConfig, domain::eth, infra}, - std::sync::Arc, -}; - -/// This struct checks whether a solver can participate in the competition by -/// using different validators. -#[derive(Clone)] -pub struct SolverParticipationGuard(Arc); - -struct Inner { - /// Stores the validators in order they will be called. - validators: Vec>, -} - -impl SolverParticipationGuard { - pub fn new( - eth: infra::Ethereum, - persistence: infra::Persistence, - competition_updates_receiver: tokio::sync::mpsc::UnboundedReceiver<()>, - db_based_validator_config: DbBasedSolverParticipationGuardConfig, - drivers: impl IntoIterator>, - ) -> Self { - let mut validators: Vec> = Vec::new(); - - let current_block = eth.current_block().clone(); - let database_solver_participation_validator = db::SolverValidator::new( - persistence, - current_block, - competition_updates_receiver, - db_based_validator_config, - drivers - .into_iter() - .map(|driver| (driver.submission_address, driver.clone())) - .collect(), - ); - validators.push(Box::new(database_solver_participation_validator)); - - let onchain_solver_participation_validator = onchain::Validator { eth }; - validators.push(Box::new(onchain_solver_participation_validator)); - - Self(Arc::new(Inner { validators })) - } - - /// Checks if a solver can participate in the competition. - /// Sequentially asks internal validators to avoid redundant RPC calls in - /// the following order: - /// 1. DB-based validator: operates fast since it uses in-memory cache. - /// 2. Onchain-based validator: only then calls the Authenticator contract. - pub async fn can_participate(&self, solver: ð::Address) -> anyhow::Result { - for validator in &self.0.validators { - if !validator.is_allowed(solver).await? { - return Ok(false); - } - } - - Ok(true) - } -} - -#[async_trait::async_trait] -trait SolverValidator: Send + Sync { - async fn is_allowed(&self, solver: ð::Address) -> anyhow::Result; -} diff --git a/crates/autopilot/src/domain/competition/participation_guard/onchain.rs b/crates/autopilot/src/domain/competition/participation_guard/onchain.rs deleted file mode 100644 index bcdd7140db..0000000000 --- a/crates/autopilot/src/domain/competition/participation_guard/onchain.rs +++ /dev/null @@ -1,23 +0,0 @@ -use { - crate::{domain::eth, infra}, - ethrpc::alloy::conversions::IntoAlloy, -}; - -/// Calls Authenticator contract to check if a solver has a sufficient -/// permission. -pub(super) struct Validator { - pub eth: infra::Ethereum, -} - -#[async_trait::async_trait] -impl super::SolverValidator for Validator { - async fn is_allowed(&self, solver: ð::Address) -> anyhow::Result { - Ok(self - .eth - .contracts() - .authenticator() - .isSolver(solver.0.into_alloy()) - .call() - .await?) - } -} diff --git a/crates/autopilot/src/domain/competition/winner_selection.rs b/crates/autopilot/src/domain/competition/winner_selection.rs index ce6f796285..91aa1d01dc 100644 --- a/crates/autopilot/src/domain/competition/winner_selection.rs +++ b/crates/autopilot/src/domain/competition/winner_selection.rs @@ -1,5 +1,5 @@ //! Winner Selection: -//! Implements a winner selction algorithm which picks the **set** of solutions +//! Implements a winner selection algorithm which picks the **set** of solutions //! which maximize surplus while enforcing uniform **directional** clearing //! prices. That means all orders selling the same token must get executed at //! the same price for that token. But orders buying that same token may all be @@ -27,438 +27,253 @@ use { crate::domain::{ self, - OrderUid, - auction::{ - Prices, - order::{self, TargetAmount}, - }, - competition::{Participant, Ranked, Score, Solution, Unranked}, - eth::{self, WrappedNativeToken}, + auction::order, + competition::{Bid, RankType, Ranked, Score, Solution, TradedOrder, Unscored}, fee, - settlement::{ - math, - transaction::{self, ClearingPrices}, - }, }, - anyhow::{Context, Result}, - itertools::{Either, Itertools}, - num::Saturating, - std::collections::{HashMap, HashSet}, + ::winner_selection::state::{HasState, RankedItem, ScoredItem, UnscoredItem}, + eth_domain_types::{self as eth, Address, WrappedNativeToken}, + std::collections::HashMap, + tracing::instrument, + winner_selection::{self as winsel}, }; +pub struct Arbitrator(winsel::Arbitrator); + /// Implements auction arbitration in 3 phases: /// 1. filter unfair solutions /// 2. mark winners /// 3. compute reference scores /// /// The functions assume the `Arbitrator` is the only one -/// changing the ordering or the `participants`. +/// changing the ordering or the `bids`. impl Arbitrator { + pub fn new(max_winners: usize, wrapped_native_token: WrappedNativeToken) -> Self { + let token: eth::TokenAddress = *wrapped_native_token; + Self(winsel::Arbitrator { + max_winners, + weth: *token, + }) + } + /// Runs the entire auction mechanism on the passed in solutions. - pub fn arbitrate( - &self, - participants: Vec>, - auction: &domain::Auction, - ) -> Ranking { - let partitioned = self.partition_unfair_solutions(participants, auction); - let filtered_out = partitioned - .discarded + #[instrument(skip_all)] + pub fn arbitrate(&self, bids: Vec>, auction: &domain::Auction) -> Ranking { + let context = auction.into(); + let mut bid_by_key = HashMap::with_capacity(bids.len()); + let mut solutions = Vec::with_capacity(bids.len()); + + for bid in bids { + let key = SolutionKey::from(bid.solution()); + let solution = bid.solution().into(); + bid_by_key.insert(key, bid); + solutions.push(solution); + } + + let ws_ranking = self.0.arbitrate(solutions, &context); + + // Compute reference scores while we still have ws_ranking + let reference_scores: HashMap = self + .0 + .compute_reference_scores(&ws_ranking) .into_iter() - .map(|participant| participant.rank(Ranked::FilteredOut)) + .map(|(solver, score)| (solver, Score(eth::Ether(score)))) .collect(); - let mut ranked = self.mark_winners(partitioned.kept); - ranked.sort_by_key(|participant| { - ( - // winners before non-winners - std::cmp::Reverse(participant.is_winner()), - // high score before low score - std::cmp::Reverse(participant.solution().computed_score().cloned()), - ) - }); + let mut filtered_out = Vec::with_capacity(ws_ranking.filtered_out.len()); + for ws_solution in ws_ranking.filtered_out { + let key = SolutionKey::from(&ws_solution); + let bid = bid_by_key + .remove(&key) + .expect("every ranked solution has a matching bid"); + let score = ws_solution.score(); + filtered_out.push( + bid.with_score(Score(eth::Ether(score))) + .with_rank(RankType::FilteredOut), + ); + } + + let mut ranked = Vec::with_capacity(ws_ranking.ranked.len()); + for ranked_solution in ws_ranking.ranked { + let key = SolutionKey::from(&ranked_solution); + let bid = bid_by_key + .remove(&key) + .expect("every ranked solution has a matching bid"); + let score = ranked_solution.score(); + ranked.push( + bid.with_score(Score(eth::Ether(score))) + .with_rank(ranked_solution.state().rank_type), + ); + } + Ranking { filtered_out, ranked, + reference_scores, } } +} - /// Removes unfair solutions from the set of all solutions. - fn partition_unfair_solutions( - &self, - mut participants: Vec>, - auction: &domain::Auction, - ) -> PartitionedSolutions { - // Discard all solutions where we can't compute the aggregate scores - // accurately because the fairness guarantees heavily rely on them. - let scores_by_solution = compute_scores_by_solution(&mut participants, auction); - participants.sort_by_key(|participant| { - std::cmp::Reverse( - // we use the computed score to not trust the score provided by solvers - participant - .solution() - .computed_score() - .expect("every remaining participant has a computed score") - .get() - .0, - ) - }); - let baseline_scores = compute_baseline_scores(&scores_by_solution); - let (fair, unfair) = participants.into_iter().partition_map(|p| { - let aggregated_scores = scores_by_solution - .get(&SolutionKey { - driver: p.driver().submission_address, - solution_id: p.solution().id(), - }) - .expect("every remaining participant has an entry"); - // only keep solutions where each order execution is at least as good as - // the baseline solution. - // we only filter out unfair solutions with more than one token pair, - // to avoid reference scores set to 0. - // see https://github.com/fhenneke/comb_auctions/issues/2 - if aggregated_scores.len() == 1 - || aggregated_scores.iter().all(|(pair, score)| { - baseline_scores - .get(pair) - .is_none_or(|baseline| score >= baseline) +impl From<&domain::Auction> for winsel::AuctionContext { + fn from(auction: &domain::Auction) -> Self { + Self { + fee_policies: auction + .orders + .iter() + .map(|order| { + let uid = winsel::OrderUid(order.uid.0); + let policies = order + .protocol_fees + .iter() + .copied() + .map(winsel::primitives::FeePolicy::from) + .collect(); + (uid, policies) }) - { - Either::Left(p) - } else { - Either::Right(p) - } - }); - PartitionedSolutions { - kept: fair, - discarded: unfair, - } - } - - /// Picks winners and sorts all solutions where winners come before - /// non-winners and higher scores come before lower scores. - fn mark_winners(&self, participants: Vec>) -> Vec { - let winner_indexes = self.pick_winners(participants.iter().map(|p| p.solution())); - participants - .into_iter() - .enumerate() - .map(|(index, participant)| { - let rank = match winner_indexes.contains(&index) { - true => Ranked::Winner, - false => Ranked::NonWinner, - }; - participant.rank(rank) - }) - .collect() - } - - /// Computes the reference scores which are used to compute - /// rewards for the winning solvers. - pub fn compute_reference_scores(&self, ranking: &Ranking) -> HashMap { - let mut reference_scores = HashMap::default(); - - for participant in &ranking.ranked { - let solver = participant.driver().submission_address; - if reference_scores.len() >= self.max_winners { - // all winners have been processed - return reference_scores; - } - if reference_scores.contains_key(&solver) { - // we already computed this solver's reference score - continue; - } - if !participant.is_winner() { - // we only want to compute the reference score of winners - continue; - } - - let solutions_without_solver = ranking - .ranked + .collect(), + surplus_capturing_jit_order_owners: auction + .surplus_capturing_jit_order_owners .iter() - .filter(|p| p.driver().submission_address != solver) - .map(|p| p.solution()); - let winner_indices = self.pick_winners(solutions_without_solver.clone()); - - let score = solutions_without_solver - .enumerate() - .filter(|(index, _)| winner_indices.contains(index)) - .filter_map(|(_, solution)| solution.computed_score) - .reduce(Score::saturating_add) - .unwrap_or_default(); - reference_scores.insert(solver, score); + .copied() + .collect(), + native_prices: auction + .prices + .iter() + .map(|(token, price)| (Address::from(*token), price.get().0)) + .collect(), } - - reference_scores } +} - /// Returns indices of winning solutions. - /// Assumes that `solutions` is sorted by score descendingly. - /// This logic was moved into a helper function to avoid a ton of `.clone()` - /// operations in `compute_reference_scores()`. - fn pick_winners<'a>(&self, solutions: impl Iterator) -> HashSet { - // Winners are selected one by one, starting from the best solution, - // until `max_winners` are selected. A solution can only - // win if none of the (sell_token, buy_token) pairs of the executed - // orders have been covered by any previously selected winning solution. - // In other words this enforces a uniform **directional** clearing price. - let mut already_swapped_tokens_pairs = HashSet::new(); - let mut winners = HashSet::default(); - for (index, solution) in solutions.enumerate() { - if winners.len() >= self.max_winners { - return winners; - } - - let swapped_token_pairs = solution +impl From<&Solution> for winsel::Solution { + fn from(solution: &Solution) -> Self { + Self::new( + solution.id(), + solution.solver(), + solution .orders() - .values() - .map(|order| DirectedTokenPair { - sell: order.sell.token.as_erc20(self.weth), - buy: order.buy.token.as_erc20(self.weth), - }) - .collect::>(); - - if swapped_token_pairs.is_disjoint(&already_swapped_tokens_pairs) { - winners.insert(index); - already_swapped_tokens_pairs.extend(swapped_token_pairs); - } - } - winners + .iter() + .map(|(uid, order)| to_winsel_order(*uid, order)) + .collect(), + ) } } -/// Let's call a solution that only trades 1 directed token pair a baseline -/// solution. Returns the best baseline solution (highest score) for -/// each token pair if one exists. -fn compute_baseline_scores(scores_by_solution: &ScoresBySolution) -> ScoreByDirection { - let mut baseline_directional_scores = ScoreByDirection::default(); - for scores in scores_by_solution.values() { - let Ok((token_pair, score)) = scores.iter().exactly_one() else { - // base solutions must contain exactly 1 directed token pair - continue; - }; - let current_best_score = baseline_directional_scores - .entry(token_pair.clone()) - .or_default(); - if score > current_best_score { - *current_best_score = *score; - } +fn to_winsel_order(uid: domain::OrderUid, order: &TradedOrder) -> winsel::Order { + winsel::Order { + uid: winsel::OrderUid(uid.0), + sell_token: *order.sell.token, + buy_token: *order.buy.token, + sell_amount: order.sell.amount.0, + buy_amount: order.buy.amount.0, + executed_sell: order.executed_sell.0, + executed_buy: order.executed_buy.0, + side: match order.side { + order::Side::Buy => winsel::Side::Buy, + order::Side::Sell => winsel::Side::Sell, + }, } - baseline_directional_scores } -/// Computes the `DirectionalScores` for all solutions and discards -/// solutions as invalid whenever that computation is not possible. -/// Solutions get discarded because fairness guarantees heavily -/// depend on these scores being accurate. -fn compute_scores_by_solution( - participants: &mut Vec>, - auction: &domain::Auction, -) -> ScoresBySolution { - let auction = Auction::from(auction); - let mut scores = HashMap::default(); - - participants.retain_mut(|p| match score_by_token_pair(p.solution(), &auction) { - Ok(score) => { - let total_score = score - .values() - .fold(Score::default(), |acc, score| acc.saturating_add(*score)); - scores.insert( - SolutionKey { - driver: p.driver().submission_address, - solution_id: p.solution().id, - }, - score, - ); - p.set_computed_score(total_score); - true - } - Err(err) => { - tracing::warn!( - driver = p.driver().name, - ?err, - solution = ?p.solution(), - "discarding solution where scores could not be computed" - ); - false - } - }); - - scores -} - -/// Returns the total scores for each directed token pair of the solution. -/// E.g. if a solution contains 3 orders like: -/// sell A for B with a score of 10 -/// sell A for B with a score of 5 -/// sell B for C with a score of 5 -/// it will return a map like: -/// (A, B) => 15 -/// (B, C) => 5 -fn score_by_token_pair(solution: &Solution, auction: &Auction) -> Result { - let mut scores: HashMap = HashMap::default(); - for (uid, trade) in solution.orders() { - if !auction.contributes_to_score(uid) { - continue; - } - - let uniform_sell_price = solution - .prices() - .get(&trade.sell.token) - .context("no uniform clearing price for sell token")?; - let uniform_buy_price = solution - .prices() - .get(&trade.buy.token) - .context("no uniform clearing price for buy token")?; - - let trade = math::Trade { - uid: *uid, - sell: trade.sell, - buy: trade.buy, - side: trade.side, - executed: match trade.side { - order::Side::Buy => TargetAmount(trade.executed_buy.into()), - order::Side::Sell => TargetAmount(trade.executed_sell.into()), +impl From for winsel::primitives::FeePolicy { + fn from(policy: fee::Policy) -> Self { + match policy { + fee::Policy::Surplus { + factor, + max_volume_factor, + } => Self::Surplus { + factor: factor.get(), + max_volume_factor: max_volume_factor.get(), }, - prices: transaction::Prices { - // clearing prices are denominated in the same underlying - // unit so we assign sell to sell and buy to buy - uniform: ClearingPrices { - sell: uniform_sell_price.get().into(), - buy: uniform_buy_price.get().into(), - }, - // for custom clearing prices we only need to know how - // much the traded tokens are worth relative to each - // other so we can simply use the swapped executed - // amounts here - custom: ClearingPrices { - sell: trade.executed_buy.into(), - buy: trade.executed_sell.into(), + fee::Policy::PriceImprovement { + factor, + max_volume_factor, + quote, + } => Self::PriceImprovement { + factor: factor.get(), + max_volume_factor: max_volume_factor.get(), + quote: winsel::primitives::Quote { + sell_amount: quote.sell_amount, + buy_amount: quote.buy_amount, + fee: quote.fee, + solver: quote.solver, }, }, - }; - let score = trade - .score(&auction.fee_policies, auction.native_prices) - .context("failed to compute score")?; - - let token_pair = DirectedTokenPair { - sell: trade.sell.token, - buy: trade.buy.token, - }; - - scores - .entry(token_pair) - .or_default() - .saturating_add_assign(Score(score)); + fee::Policy::Volume { factor } => Self::Volume { + factor: factor.get(), + }, + } } - Ok(scores) -} - -pub struct Arbitrator { - pub max_winners: usize, - pub weth: WrappedNativeToken, } -/// Relevant data from `domain::Auction` but with data structures -/// optimized for the winner selection logic. -/// Avoids clones whenever possible. -struct Auction<'a> { - /// Fee policies for **all** orders that were in the original auction. - fee_policies: HashMap>, - surplus_capturing_jit_order_owners: HashSet, - native_prices: &'a Prices, +#[derive(Clone, Copy, Hash, Eq, PartialEq)] +struct SolutionKey { + solver: eth::Address, + solution_id: u64, } -impl Auction<'_> { - /// Returns whether an order is allowed to capture surplus and - /// therefore contributes to the total score of a solution. - fn contributes_to_score(&self, uid: &OrderUid) -> bool { - self.fee_policies.contains_key(uid) - || self - .surplus_capturing_jit_order_owners - .contains(&uid.owner()) +impl From<&Solution> for SolutionKey { + fn from(solution: &Solution) -> Self { + Self { + solver: solution.solver(), + solution_id: solution.id(), + } } } -impl<'a> From<&'a domain::Auction> for Auction<'a> { - fn from(original: &'a domain::Auction) -> Self { +impl From<&winsel::Solution> for SolutionKey { + fn from(solution: &winsel::Solution) -> Self { Self { - fee_policies: original - .orders - .iter() - .map(|o| (o.uid, &o.protocol_fees)) - .collect(), - native_prices: &original.prices, - surplus_capturing_jit_order_owners: original - .surplus_capturing_jit_order_owners - .iter() - .cloned() - .collect(), + solver: solution.solver(), + solution_id: solution.id(), } } } -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -struct DirectedTokenPair { - sell: eth::TokenAddress, - buy: eth::TokenAddress, -} - -/// Key to uniquely identify every solution. -#[derive(PartialEq, Eq, std::hash::Hash)] -struct SolutionKey { - driver: eth::Address, - solution_id: u64, -} - -/// Scores of all trades in a solution aggregated by the directional -/// token pair. E.g. all trades (WETH -> USDC) are aggregated into -/// one value and all trades (USDC -> WETH) into another. -type ScoreByDirection = HashMap; - -/// Mapping from solution to `DirectionalScores` for all solutions -/// of the auction. -type ScoresBySolution = HashMap; - pub struct Ranking { /// Solutions that were discarded because they were malformed /// in some way or deemed unfair by the selection mechanism. - filtered_out: Vec>, + filtered_out: Vec>, /// Final ranking of the solutions that passed the fairness /// check. Winners come before non-winners and higher total /// scores come before lower scores. - ranked: Vec>, + ranked: Vec>, + /// Reference scores for each winning solver, used to compute rewards. + reference_scores: HashMap, } impl Ranking { /// All solutions including the ones that got filtered out. - pub fn all(&self) -> impl Iterator> { + pub fn all(&self) -> impl Iterator> { self.ranked.iter().chain(&self.filtered_out) } /// Enumerates all solutions. The index is used as solution UID. - pub fn enumerated(&self) -> impl Iterator)> { + pub fn enumerated(&self) -> impl Iterator)> { self.all().enumerate() } /// All solutions that won the right to get executed. - pub fn winners(&self) -> impl Iterator> { - self.ranked.iter().filter(|p| p.is_winner()) + pub fn winners(&self) -> impl Iterator> { + self.ranked.iter().filter(|b| b.is_winner()) } /// All solutions that were not filtered out but also did not win. - pub fn non_winners(&self) -> impl Iterator> { - self.ranked.iter().filter(|p| !p.is_winner()) + pub fn non_winners(&self) -> impl Iterator> { + self.ranked.iter().filter(|b| !b.is_winner()) + } + + /// Reference scores for each winning solver, used to compute rewards. + pub fn reference_scores(&self) -> &HashMap { + &self.reference_scores } /// All solutions that passed the filtering step. - pub fn ranked(&self) -> impl Iterator> { + pub fn ranked(&self) -> impl Iterator> { self.ranked.iter() } } -struct PartitionedSolutions { - kept: Vec>, - discarded: Vec>, -} - #[cfg(test)] mod tests { use { @@ -471,12 +286,13 @@ mod tests { Price, order::{self, AppDataHash}, }, - competition::{Participant, Score, Solution, TradedOrder, Unranked}, - eth::{self, TokenAddress}, + competition::{Bid, Solution, TradedOrder, Unscored}, }, infra::Driver, }, - ethcontract::H160, + alloy::primitives::{Address, U160, U256, address}, + configs::autopilot::solver::Account, + eth_domain_types::{self as eth, TokenAddress}, hex_literal::hex, number::serialization::HexOrDecimalU256, serde::Deserialize, @@ -486,6 +302,7 @@ mod tests { collections::HashMap, hash::{DefaultHasher, Hash, Hasher}, }, + winner_selection::state::RankedItem, }; const DEFAULT_TOKEN_PRICE: u128 = 1_000; @@ -1096,10 +913,58 @@ mod tests { TestCase::from_json(case).validate().await; } + /// A solution settling no orders gets a score of 0 which disqualifies it + /// from the competition. + #[tokio::test] + async fn discards_solutions_with_zero_score() { + let case = json!({ + "tokens": [ + ["Token A", address(0)], + ["Token B", address(1)], + ], + "auction": { + "orders": { + "Order 1": { + "side": "sell", + "sell_token": "Token A", + "sell_amount": "32375066190000000000000000", + "buy_token": "Token B", + "buy_amount": "2161512119" + } + }, + "prices": { + "Token A": "32429355240", + "Token B": "480793239987749750742974464" + } + }, + "solutions": { + "Solution 1": { + "solver": "Solver 1", + "trades": {}, + }, + "Solution 2": { + "solver": "Solver 2", + "trades": { + "Order 1": { + "sell_amount": "32375066190000000000000000", + "buy_amount": "2205267875" + } + } + } + }, + "expected_fair_solutions": ["Solution 2"], + "expected_winners": ["Solution 2"], + "expected_reference_scores": { + "Solver 2": "0", + }, + }); + TestCase::from_json(case).validate().await; + } + #[serde_as] #[derive(Deserialize, Debug)] struct TestCase { - pub tokens: Vec<(String, H160)>, + pub tokens: Vec<(String, Address)>, pub auction: TestAuction, pub solutions: HashMap, pub expected_fair_solutions: Vec, @@ -1117,7 +982,12 @@ mod tests { let arbitrator = create_test_arbitrator(); // map (token id -> token address) for later reference during the test - let token_map: HashMap = self.tokens.iter().cloned().collect(); + let token_map: HashMap = self + .tokens + .iter() + .cloned() + .map(|(id, address)| (id, address.into())) + .collect(); // map (order id -> order) for later reference during the test let order_map: HashMap = self @@ -1156,7 +1026,7 @@ mod tests { prices .iter() .map(|(token_id, price)| { - let token_address = TokenAddress(*token_map.get(token_id).unwrap()); + let token_address = *token_map.get(token_id).unwrap(); let price = create_price(*price); (token_address, price) }) @@ -1168,7 +1038,7 @@ mod tests { // map (solver id -> solver address) for later reference during the test let mut solver_map = HashMap::new(); - // map (solution id -> participant) for later reference during the test + // map (solution id -> bid) for later reference during the test let mut solution_map = HashMap::new(); for (solution_id, solution) in &self.solutions { // generate solver address deterministically from the id @@ -1191,13 +1061,13 @@ mod tests { let solution_uid = hash(solution_id); solution_map.insert( solution_id, - create_solution(solution_uid, solver_address, trades, None).await, + create_bid(solution_uid, solver_address, trades).await, ); } // filter solutions - let participants = solution_map.values().cloned().collect(); - let ranking = arbitrator.arbitrate(participants, &auction); + let bids = solution_map.values().cloned().collect(); + let ranking = arbitrator.arbitrate(bids, &auction); assert_eq!(ranking.ranked.len(), self.expected_fair_solutions.len()); for solution_id in &self.expected_fair_solutions { let solution_uid = solution_map.get(&solution_id).unwrap().solution().id; @@ -1214,7 +1084,7 @@ mod tests { // winners before non-winners std::cmp::Reverse(a.is_winner()), // high score before low score - std::cmp::Reverse(a.solution().computed_score().unwrap()) + std::cmp::Reverse(a.score()) ))); assert_eq!(winners.len(), self.expected_winners.len()); for (actual, expected) in winners.iter().zip(&self.expected_winners) { @@ -1223,11 +1093,11 @@ mod tests { } // compute reference score - let reference_scores = arbitrator.compute_reference_scores(&ranking); + let reference_scores = ranking.reference_scores(); assert_eq!(reference_scores.len(), self.expected_reference_scores.len()); for (solver_id, expected_score) in &self.expected_reference_scores { - let solver_address: eth::Address = (*solver_map.get(solver_id).unwrap()).into(); - let score = reference_scores.get(&solver_address).unwrap(); + let solver_address = solver_map.get(solver_id).unwrap(); + let score = reference_scores.get(solver_address).unwrap(); assert_eq!(score.0, eth::Ether(*expected_score)) } } @@ -1271,21 +1141,21 @@ mod tests { } fn create_test_arbitrator() -> super::Arbitrator { - super::Arbitrator { - max_winners: 10, - weth: H160::from_slice(&hex!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")).into(), - } + super::Arbitrator::new( + 10, + address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").into(), + ) } - fn address(id: u64) -> H160 { - H160::from_low_u64_le(id) + fn address(id: u64) -> Address { + Address::from(U160::from(id)) } fn create_order( uid: u64, - sell_token: H160, + sell_token: TokenAddress, sell_amount: eth::U256, - buy_token: H160, + buy_token: TokenAddress, buy_amount: eth::U256, side: order::Side, ) -> Order { @@ -1293,18 +1163,18 @@ mod tests { uid: create_order_uid(uid), sell: eth::Asset { amount: sell_amount.into(), - token: sell_token.into(), + token: sell_token, }, buy: eth::Asset { amount: buy_amount.into(), - token: buy_token.into(), + token: buy_token, }, protocol_fees: vec![], side, receiver: None, owner: Default::default(), partially_fillable: false, - executed: eth::U256::zero().into(), + executed: eth::U256::ZERO.into(), pre_interactions: vec![], post_interactions: vec![], sell_token_balance: order::SellTokenSource::Erc20, @@ -1337,7 +1207,7 @@ mod tests { ) -> Auction { // Initialize the prices of the tokens if they are not specified let prices = prices.unwrap_or({ - let default_price = create_price(DEFAULT_TOKEN_PRICE.into()); + let default_price = create_price(U256::from(DEFAULT_TOKEN_PRICE)); let mut res = HashMap::new(); for order in &orders { res.insert(order.buy.token, default_price); @@ -1369,46 +1239,24 @@ mod tests { } } - async fn create_solution( + async fn create_bid( solution_id: u64, - solver_address: H160, + solver_address: Address, trades: Vec<(OrderUid, TradedOrder)>, - prices: Option>, - ) -> Participant { - // The prices of the tokens do not affect the result but they keys must exist - // for every token of every trade - let prices = prices.unwrap_or({ - let mut res = HashMap::new(); - for (_, trade) in &trades { - res.insert(trade.buy.token, create_price(eth::U256::one())); - res.insert(trade.sell.token, create_price(eth::U256::one())); - } - res - }); - + ) -> Bid { let trade_order_map: HashMap = trades.into_iter().collect(); - let solver_address = eth::Address(solver_address); - - let solution = Solution::new( - solution_id, - solver_address, - // provided score does not matter as it's computed automatically by the arbitrator - Score(eth::Ether(eth::U256::zero())), - trade_order_map, - prices, - ); + + let solution = Solution::new(solution_id, solver_address, trade_order_map); let driver = Driver::try_new( url::Url::parse("http://localhost").unwrap(), solver_address.to_string(), - None, - crate::arguments::Account::Address(solver_address.0), - false, + Account::Address(solver_address), ) .await .unwrap(); - Participant::new(solution, std::sync::Arc::new(driver)) + Bid::new(solution, std::sync::Arc::new(driver)) } fn amount(value: u128) -> String { @@ -1420,8 +1268,8 @@ mod tests { value * 10u128.pow(15) } - fn filter_winners(solutions: &[Participant]) -> Vec<&Participant> { - solutions.iter().filter(|s| s.is_winner()).collect() + fn filter_winners(bids: &[Bid]) -> Vec<&Bid> { + bids.iter().filter(|b| b.is_winner()).collect() } // Used to generate deterministic identifiers (e.g., UIDs, addresses) from diff --git a/crates/autopilot/src/domain/eth/mod.rs b/crates/autopilot/src/domain/eth/mod.rs deleted file mode 100644 index c0e773a4c5..0000000000 --- a/crates/autopilot/src/domain/eth/mod.rs +++ /dev/null @@ -1,359 +0,0 @@ -pub use primitive_types::{H160, H256, U256}; -use { - crate::{domain, util::conv::U256Ext}, - derive_more::{Display, From, Into}, -}; - -/// ERC20 token address for ETH. In reality, ETH is not an ERC20 token because -/// it does not implement the ERC20 interface, but this address is used by -/// convention across the Ethereum ecosystem whenever ETH is treated like an -/// ERC20 token. -/// Same address is also used for XDAI on Gnosis Chain. -pub const NATIVE_TOKEN: TokenAddress = TokenAddress(H160([0xee; 20])); - -/// An address. Can be an EOA or a smart contract address. -#[derive( - Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into, Display, -)] -pub struct Address(pub H160); - -/// Block number. -#[derive(Debug, Copy, Clone, From, PartialEq, PartialOrd, Default)] -pub struct BlockNo(pub u64); - -/// Adding blocks to a block number. -impl std::ops::Add for BlockNo { - type Output = BlockNo; - - fn add(self, rhs: u64) -> Self::Output { - Self(self.0 + rhs) - } -} - -/// A transaction ID, AKA transaction hash. -#[derive(Debug, Copy, Clone, From, Default)] -pub struct TxId(pub H256); - -/// An ERC20 token address. -/// -/// https://eips.ethereum.org/EIPS/eip-20 -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] -pub struct TokenAddress(pub H160); - -impl TokenAddress { - /// If the token is ETH/XDAI, return WETH/WXDAI, thereby converting it to - /// erc20. - pub fn as_erc20(self, wrapped: WrappedNativeToken) -> Self { - if self == NATIVE_TOKEN { - wrapped.into() - } else { - self - } - } -} - -/// ERC20 representation of the chain's native token (e.g. WETH on mainnet, -/// WXDAI on Gnosis Chain). -#[derive(Debug, Clone, Copy, From, Into)] -pub struct WrappedNativeToken(TokenAddress); - -impl From for WrappedNativeToken { - fn from(value: H160) -> Self { - WrappedNativeToken(value.into()) - } -} - -/// An ERC20 token amount. -/// -/// https://eips.ethereum.org/EIPS/eip-20 -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] -pub struct TokenAmount(pub U256); - -impl TokenAmount { - /// Applies a factor to the token amount. - pub fn apply_factor(&self, factor: f64) -> Option { - Some(self.0.checked_mul_f64(factor)?.into()) - } -} - -/// A value denominated in an order's surplus token (buy token for -/// sell orders and sell token for buy orders). -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] -pub struct SurplusTokenAmount(pub U256); - -/// An ERC20 sell token amount. -/// -/// https://eips.ethereum.org/EIPS/eip-20 -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] -pub struct SellTokenAmount(pub U256); - -impl From for SellTokenAmount { - fn from(value: TokenAmount) -> Self { - Self(value.0) - } -} - -impl From for TokenAmount { - fn from(value: SellTokenAmount) -> Self { - Self(value.0) - } -} - -impl std::ops::Add for SellTokenAmount { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) - } -} - -impl num::Zero for SellTokenAmount { - fn zero() -> Self { - Self(U256::zero()) - } - - fn is_zero(&self) -> bool { - self.0.is_zero() - } -} - -impl std::iter::Sum for SellTokenAmount { - fn sum>(iter: I) -> Self { - iter.fold(num::Zero::zero(), std::ops::Add::add) - } -} - -impl std::ops::Sub for SellTokenAmount { - type Output = SellTokenAmount; - - fn sub(self, rhs: Self) -> Self::Output { - self.0.sub(rhs.0).into() - } -} - -impl num::CheckedSub for SellTokenAmount { - fn checked_sub(&self, other: &Self) -> Option { - self.0.checked_sub(other.0).map(Into::into) - } -} - -impl num::Saturating for SellTokenAmount { - fn saturating_add(self, v: Self) -> Self { - self.0.saturating_add(v.0).into() - } - - fn saturating_sub(self, v: Self) -> Self { - self.0.saturating_sub(v.0).into() - } -} - -/// Gas amount in gas units. -/// -/// The amount of Ether that is paid in transaction fees is proportional to this -/// amount as well as the transaction's [`EffectiveGasPrice`]. -#[derive(Debug, Default, Display, Clone, Copy, Ord, Eq, PartialOrd, PartialEq, From, Into)] -pub struct Gas(pub U256); - -/// The `effective_gas_price` as defined by EIP-1559. -/// -/// https://eips.ethereum.org/EIPS/eip-1559#specification -#[derive(Debug, Clone, Copy, Display, Default)] -pub struct EffectiveGasPrice(pub Ether); - -impl From for EffectiveGasPrice { - fn from(value: U256) -> Self { - Self(value.into()) - } -} - -impl From for U256 { - fn from(value: EffectiveGasPrice) -> Self { - value.0.into() - } -} -impl std::ops::Sub for TokenAmount { - type Output = TokenAmount; - - fn sub(self, rhs: Self) -> Self::Output { - self.0.sub(rhs.0).into() - } -} - -impl num::CheckedSub for TokenAmount { - fn checked_sub(&self, other: &Self) -> Option { - self.0.checked_sub(other.0).map(Into::into) - } -} - -impl std::ops::Add for TokenAmount { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl num::CheckedAdd for TokenAmount { - fn checked_add(&self, other: &Self) -> Option { - self.0.checked_add(other.0).map(Into::into) - } -} - -impl std::ops::Mul for TokenAmount { - type Output = TokenAmount; - - fn mul(self, rhs: Self) -> Self::Output { - self.0.mul(rhs.0).into() - } -} - -impl num::CheckedMul for TokenAmount { - fn checked_mul(&self, other: &Self) -> Option { - self.0.checked_mul(other.0).map(Into::into) - } -} - -impl std::ops::Div for TokenAmount { - type Output = TokenAmount; - - fn div(self, rhs: Self) -> Self::Output { - self.0.div(rhs.0).into() - } -} - -impl num::CheckedDiv for TokenAmount { - fn checked_div(&self, other: &Self) -> Option { - self.0.checked_div(other.0).map(Into::into) - } -} - -impl std::ops::AddAssign for TokenAmount { - fn add_assign(&mut self, rhs: Self) { - self.0 += rhs.0; - } -} - -impl num::Zero for TokenAmount { - fn zero() -> Self { - Self(U256::zero()) - } - - fn is_zero(&self) -> bool { - self.0.is_zero() - } -} - -/// An asset on the Ethereum blockchain. Represents a particular amount of a -/// particular token. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct Asset { - pub amount: TokenAmount, - pub token: TokenAddress, -} - -/// An amount of native Ether tokens denominated in wei. -#[derive( - Clone, - Copy, - Debug, - Eq, - Ord, - PartialEq, - PartialOrd, - From, - Into, - Display, - Default, - derive_more::Add, - derive_more::Sub, -)] -pub struct Ether(pub U256); - -impl num::Saturating for Ether { - fn saturating_add(self, v: Self) -> Self { - Self(self.0.saturating_add(v.0)) - } - - fn saturating_sub(self, v: Self) -> Self { - Self(self.0.saturating_sub(v.0)) - } -} - -impl num::CheckedSub for Ether { - fn checked_sub(&self, v: &Self) -> Option { - self.0.checked_sub(v.0).map(Ether) - } -} - -impl num::Zero for Ether { - fn zero() -> Self { - Self(U256::zero()) - } - - fn is_zero(&self) -> bool { - self.0.is_zero() - } -} - -impl std::iter::Sum for Ether { - fn sum>(iter: I) -> Self { - iter.fold(num::Zero::zero(), num::Saturating::saturating_add) - } -} - -/// Domain separator used for signing. -/// -/// https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator -#[derive(Debug, Clone, Copy)] -pub struct DomainSeparator(pub [u8; 32]); - -/// Originated from the blockchain transaction input data. -pub type Calldata = crate::util::Bytes>; - -/// A settlement event emitted by a settlement smart contract. -#[derive(Debug, Clone, Copy)] -pub struct SettlementEvent { - pub block: BlockNo, - pub log_index: u64, - pub transaction: TxId, -} - -/// A trade event emitted by a settlement smart contract. -#[derive(Debug, Clone, Copy)] -pub struct TradeEvent { - pub block: BlockNo, - pub log_index: u64, - pub order_uid: domain::OrderUid, -} - -/// Call frames of a transaction. -#[derive(Clone, Debug, Default)] -pub struct CallFrame { - /// The address of the call initiator. - pub from: Address, - /// The address of the contract that was called. - pub to: Option
, - /// Calldata input. - pub input: Calldata, - /// Recorded child calls. - pub calls: Vec, -} - -/// Any type of on-chain transaction. -#[derive(Debug, Clone, Default)] -pub struct Transaction { - /// The hash of the transaction. - pub hash: TxId, - /// The address of the sender of the transaction. - pub from: Address, - /// The block number of the block that contains the transaction. - pub block: BlockNo, - /// The timestamp of the block that contains the transaction. - pub timestamp: u32, - /// The gas used by the transaction. - pub gas: Gas, - /// The effective gas price of the transaction. - pub gas_price: EffectiveGasPrice, - /// Traces of all Calls contained in the transaction. - pub trace_calls: CallFrame, -} diff --git a/crates/autopilot/src/domain/fee/mod.rs b/crates/autopilot/src/domain/fee/mod.rs index cc7bf5e06a..1ea60e7968 100644 --- a/crates/autopilot/src/domain/fee/mod.rs +++ b/crates/autopilot/src/domain/fee/mod.rs @@ -8,18 +8,24 @@ mod policy; use { crate::{ - arguments::{self}, boundary::{self}, - domain::{self, eth}, + domain, }, alloy::primitives::{Address, U256}, - app_data::Validator, chrono::{DateTime, Utc}, - derive_more::Into, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - primitive_types::H160, + configs::{ + autopilot::fee_policy::{ + FeePoliciesConfig, + FeePolicy, + FeePolicyOrderClass, + UpcomingFeePolicies, + }, + fee_factor::FeeFactor, + }, + eth_domain_types as eth, rust_decimal::Decimal, - std::{collections::HashSet, str::FromStr}, + shared::{arguments::TokenBucketFeeOverride, fee::VolumeFeePolicy}, + std::collections::HashSet, }; #[derive(Debug)] @@ -29,12 +35,12 @@ enum OrderClass { Any, } -impl From for OrderClass { - fn from(value: arguments::FeePolicyOrderClass) -> Self { +impl From for OrderClass { + fn from(value: FeePolicyOrderClass) -> Self { match value { - arguments::FeePolicyOrderClass::Market => Self::Market, - arguments::FeePolicyOrderClass::Limit => Self::Limit, - arguments::FeePolicyOrderClass::Any => Self::Any, + FeePolicyOrderClass::Market => Self::Market, + FeePolicyOrderClass::Limit => Self::Limit, + FeePolicyOrderClass::Any => Self::Any, } } } @@ -45,11 +51,11 @@ pub struct ProtocolFee { order_class: OrderClass, } -impl From for ProtocolFee { - fn from(value: arguments::FeePolicy) -> Self { +impl From for ProtocolFee { + fn from(value: FeePolicy) -> Self { Self { - policy: value.fee_policy_kind.into(), - order_class: value.fee_policy_order_class.into(), + policy: value.kind.into(), + order_class: value.order_class.into(), } } } @@ -59,15 +65,15 @@ pub struct UpcomingProtocolFees { effective_from_timestamp: DateTime, } -impl From for Option { - fn from(value: arguments::UpcomingFeePolicies) -> Self { +impl UpcomingProtocolFees { + fn from_config(value: UpcomingFeePolicies) -> Option { value // both config fields must be non-empty .effective_from_timestamp - .filter(|_| !value.fee_policies.is_empty()) + .filter(|_| !value.policies.is_empty()) .map(|effective_from_timestamp| UpcomingProtocolFees { fee_policies: value - .fee_policies + .policies .into_iter() .map(ProtocolFee::from) .collect::>(), @@ -76,25 +82,38 @@ impl From for Option { } } -pub type ProtocolFeeExemptAddresses = HashSet; +pub type ProtocolFeeExemptAddresses = HashSet
; pub struct ProtocolFees { fee_policies: Vec, max_partner_fee: FeeFactor, upcoming_fee_policies: Option, + volume_fee_policy: VolumeFeePolicy, } impl ProtocolFees { - pub fn new(config: &arguments::FeePoliciesConfig) -> Self { + pub fn new( + config: &FeePoliciesConfig, + volume_fee_bucket_overrides: Vec, + enable_sell_equals_buy_volume_fee: bool, + ) -> Self { + let volume_fee_policy = VolumeFeePolicy::new( + volume_fee_bucket_overrides, + None, // contained within FeePoliciesConfig; vol fee is passed in at callsite + enable_sell_equals_buy_volume_fee, + ); Self { fee_policies: config - .fee_policies + .policies .iter() .cloned() .map(ProtocolFee::from) .collect(), - max_partner_fee: config.fee_policy_max_partner_fee, - upcoming_fee_policies: config.upcoming_fee_policies.clone().into(), + max_partner_fee: config.max_partner_fee, + upcoming_fee_policies: UpcomingProtocolFees::from_config( + config.upcoming_policies.clone(), + ), + volume_fee_policy, } } @@ -136,7 +155,7 @@ impl ProtocolFees { // update the `accumulated` value *accumulated += value.min(cap - *accumulated); - FeeFactor(f64::try_from(value.max(Decimal::ZERO).min(remaining_factor)).unwrap()) + FeeFactor::new(f64::try_from(value.max(Decimal::ZERO).min(remaining_factor)).unwrap()) } fn fee_factor_from_bps(bps: u64) -> FeeFactor { @@ -152,14 +171,13 @@ impl ProtocolFees { let Some(full_app_data) = order.metadata.full_app_data.as_ref() else { return vec![]; }; - let Ok(validated) = Validator::new(usize::MAX).validate(full_app_data.as_bytes()) else { + let Ok(parsed_app_data) = app_data::parse(full_app_data.as_bytes()) else { return vec![]; }; let mut accumulated = Decimal::ZERO; - validated - .protocol + parsed_app_data .partner_fee .iter() .map(move |partner_fee| { @@ -207,9 +225,9 @@ impl ProtocolFees { factor, max_volume_factor, quote: Quote { - sell_amount: quote.sell_amount.0.into_alloy(), - buy_amount: quote.buy_amount.0.into_alloy(), - fee: quote.fee.0.into_alloy(), + sell_amount: quote.sell_amount.0, + buy_amount: quote.buy_amount.0, + fee: quote.fee.0, solver: quote.solver, }, } @@ -223,7 +241,7 @@ impl ProtocolFees { /// protocol fees if necessary. pub fn apply( &self, - order: boundary::Order, + order: &boundary::Order, quote: Option, surplus_capturing_jit_order_owners: &[eth::Address], ) -> domain::Order { @@ -231,16 +249,16 @@ impl ProtocolFees { // being considered out of market price. let reference_quote = quote.clone().unwrap_or(domain::Quote { order_uid: order.metadata.uid.into(), - sell_amount: order.data.sell_amount.into_legacy().into(), - buy_amount: U256::ZERO.into_legacy().into(), - fee: order.data.fee_amount.into_legacy().into(), + sell_amount: order.data.sell_amount.into(), + buy_amount: U256::ZERO.into(), + fee: order.data.fee_amount.into(), solver: Address::ZERO, }); let partner_fee = - Self::get_partner_fee(&order, &reference_quote, self.max_partner_fee.into()); + Self::get_partner_fee(order, &reference_quote, self.max_partner_fee.get()); - if surplus_capturing_jit_order_owners.contains(&order.metadata.owner.into_legacy().into()) { + if surplus_capturing_jit_order_owners.contains(&order.metadata.owner) { return boundary::order::to_domain(order, partner_fee, quote); } @@ -249,7 +267,7 @@ impl ProtocolFees { fn apply_policies( &self, - order: boundary::Order, + order: &boundary::Order, quote: domain::Quote, partner_fees: Vec, ) -> domain::Order { @@ -263,8 +281,8 @@ impl ProtocolFees { let protocol_fees = fee_policies .iter() - .filter_map(|fee_policy| Self::protocol_fee_into_policy(&order, "e, fee_policy)) - .flat_map(|policy| Self::variant_fee_apply(&order, "e, policy)) + .filter_map(|fee_policy| Self::protocol_fee_into_policy(order, "e, fee_policy)) + .flat_map(|policy| self.variant_fee_apply(order, "e, policy)) .chain(partner_fees) .collect::>(); @@ -272,6 +290,7 @@ impl ProtocolFees { } fn variant_fee_apply( + &self, order: &boundary::Order, quote: &domain::Quote, policy: &policy::Policy, @@ -279,7 +298,7 @@ impl ProtocolFees { match policy { policy::Policy::Surplus(variant) => variant.apply(order), policy::Policy::PriceImprovement(variant) => variant.apply(order, quote), - policy::Policy::Volume(variant) => variant.apply(order), + policy::Policy::Volume(variant) => variant.apply(order, &self.volume_fee_policy), } } @@ -334,30 +353,6 @@ pub enum Policy { }, } -#[derive(Debug, Clone, Copy, PartialEq, Into)] -pub struct FeeFactor(f64); - -/// TryFrom implementation for the cases we want to enforce the constrain [0, 1) -impl TryFrom for FeeFactor { - type Error = anyhow::Error; - - fn try_from(value: f64) -> Result { - anyhow::ensure!( - (0.0..1.0).contains(&value), - "Factor must be in the range [0, 1)" - ); - Ok(FeeFactor(value)) - } -} - -impl FromStr for FeeFactor { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - s.parse::().map(FeeFactor::try_from)? - } -} - #[derive(Debug, Copy, Clone, PartialEq)] pub struct Quote { /// The amount of the sell token. @@ -372,9 +367,9 @@ pub struct Quote { impl Quote { fn from_domain(value: &domain::Quote) -> Self { Self { - sell_amount: value.sell_amount.0.into_alloy(), - buy_amount: value.buy_amount.0.into_alloy(), - fee: value.fee.0.into_alloy(), + sell_amount: value.sell_amount.0, + buy_amount: value.buy_amount.0, + fee: value.fee.0, solver: value.solver, } } @@ -425,10 +420,10 @@ mod test { result, vec![ Policy::Volume { - factor: FeeFactor(0.05), + factor: FeeFactor::try_from(0.05).unwrap(), }, Policy::Volume { - factor: FeeFactor(0.2), + factor: FeeFactor::try_from(0.2).unwrap(), } ] ); @@ -499,7 +494,7 @@ mod test { assert_eq!( result, vec![Policy::Volume { - factor: FeeFactor(0.0), + factor: FeeFactor::try_from(0.0).unwrap(), }] ); } @@ -544,10 +539,10 @@ mod test { result, vec![ Policy::Volume { - factor: FeeFactor(0.0), + factor: FeeFactor::try_from(0.0).unwrap(), }, Policy::Volume { - factor: FeeFactor(0.0), + factor: FeeFactor::try_from(0.0).unwrap(), } ] ); @@ -588,7 +583,7 @@ mod test { assert_eq!( result, vec![Policy::Volume { - factor: FeeFactor(0.3), + factor: FeeFactor::try_from(0.3).unwrap(), }] ); } @@ -636,10 +631,10 @@ mod test { result, vec![ Policy::Volume { - factor: FeeFactor(0.1), + factor: FeeFactor::try_from(0.1).unwrap(), }, Policy::Volume { - factor: FeeFactor(0.18181818181818182), + factor: FeeFactor::try_from(0.18181818181818182).unwrap(), } ] ); @@ -693,13 +688,13 @@ mod test { result, vec![ Policy::Volume { - factor: FeeFactor(0.1), + factor: FeeFactor::try_from(0.1).unwrap(), }, Policy::Volume { - factor: FeeFactor(0.18181818181818182), + factor: FeeFactor::try_from(0.18181818181818182).unwrap(), }, Policy::Volume { - factor: FeeFactor(0.0), + factor: FeeFactor::try_from(0.0).unwrap(), } ] ); diff --git a/crates/autopilot/src/domain/fee/policy.rs b/crates/autopilot/src/domain/fee/policy.rs index 189d609cd1..f95feddf8d 100644 --- a/crates/autopilot/src/domain/fee/policy.rs +++ b/crates/autopilot/src/domain/fee/policy.rs @@ -1,10 +1,10 @@ -use crate::{ - arguments, - boundary, - domain::{ - self, - fee::{FeeFactor, Quote}, +use { + crate::{ + boundary, + domain::{self, fee::Quote}, }, + configs::{autopilot::fee_policy::FeePolicyKind, fee_factor::FeeFactor}, + shared::fee::VolumeFeePolicy, }; pub enum Policy { @@ -27,24 +27,24 @@ pub struct Volume { factor: FeeFactor, } -impl From for Policy { - fn from(policy_arg: arguments::FeePolicyKind) -> Self { +impl From for Policy { + fn from(policy_arg: FeePolicyKind) -> Self { match policy_arg { - arguments::FeePolicyKind::Surplus { + FeePolicyKind::Surplus { factor, max_volume_factor, } => Policy::Surplus(Surplus { factor, max_volume_factor, }), - arguments::FeePolicyKind::PriceImprovement { + FeePolicyKind::PriceImprovement { factor, max_volume_factor, } => Policy::PriceImprovement(PriceImprovement { factor, max_volume_factor, }), - arguments::FeePolicyKind::Volume { factor } => Policy::Volume(Volume { factor }), + FeePolicyKind::Volume { factor } => Policy::Volume(Volume { factor }), } } } @@ -84,13 +84,24 @@ impl PriceImprovement { } impl Volume { - pub fn apply(&self, order: &boundary::Order) -> Option { + pub fn apply( + &self, + order: &boundary::Order, + volume_fee_policy: &VolumeFeePolicy, + ) -> Option { match order.metadata.class { boundary::OrderClass::Market => None, boundary::OrderClass::Liquidity => None, - boundary::OrderClass::Limit => Some(domain::fee::Policy::Volume { - factor: self.factor, - }), + boundary::OrderClass::Limit => { + // Use shared function to determine applicable volume fee factor + let factor = volume_fee_policy.get_applicable_volume_fee_factor( + order.data.buy_token, + order.data.sell_token, + Some(self.factor), + )?; + + Some(domain::fee::Policy::Volume { factor }) + } } } } diff --git a/crates/autopilot/src/domain/mod.rs b/crates/autopilot/src/domain/mod.rs index df25fa082b..ed1eb17793 100644 --- a/crates/autopilot/src/domain/mod.rs +++ b/crates/autopilot/src/domain/mod.rs @@ -1,6 +1,6 @@ pub mod auction; +pub mod blockchain; pub mod competition; -pub mod eth; pub mod fee; pub mod quote; pub mod settlement; @@ -18,11 +18,6 @@ pub use { #[derive(prometheus_metric_storage::MetricStorage)] #[metric(subsystem = "domain")] pub struct Metrics { - /// How many times the solver marked as non-settling based on the database - /// statistics. - #[metric(labels("solver", "reason"))] - pub banned_solver: prometheus::IntCounterVec, - /// Tracks settlements that couldn't be matched to the database solutions. #[metric(labels("solver_address"))] pub inconsistent_settlements: prometheus::IntCounterVec, diff --git a/crates/autopilot/src/domain/quote/mod.rs b/crates/autopilot/src/domain/quote/mod.rs index 41131c37ef..603e431f55 100644 --- a/crates/autopilot/src/domain/quote/mod.rs +++ b/crates/autopilot/src/domain/quote/mod.rs @@ -1,7 +1,8 @@ use { super::OrderUid, - crate::{boundary::Amounts, domain::eth}, + crate::boundary::Amounts, alloy::primitives::Address, + eth_domain_types as eth, }; #[derive(Clone, Debug, PartialEq)] @@ -16,9 +17,9 @@ pub struct Quote { impl From<&Quote> for Amounts { fn from(quote: &Quote) -> Self { Self { - sell: quote.sell_amount.into(), - buy: quote.buy_amount.into(), - fee: quote.fee.into(), + sell: quote.sell_amount.0, + buy: quote.buy_amount.0, + fee: quote.fee.0, } } } diff --git a/crates/autopilot/src/domain/settlement/auction.rs b/crates/autopilot/src/domain/settlement/auction.rs index a1ce9ad618..abfeb95da4 100644 --- a/crates/autopilot/src/domain/settlement/auction.rs +++ b/crates/autopilot/src/domain/settlement/auction.rs @@ -1,7 +1,8 @@ //! Auction data related to the specific settlement. use { - crate::domain::{self}, + crate::domain, + eth_domain_types as eth, std::collections::{HashMap, HashSet}, }; @@ -13,7 +14,7 @@ use { pub struct Auction { pub id: domain::auction::Id, /// The block on top of which the auction was created. - pub block: domain::eth::BlockNo, + pub block: eth::BlockNo, /// All orders from a competition auction. Some of them may contain fee /// policies. pub orders: HashMap>, @@ -21,5 +22,5 @@ pub struct Auction { pub prices: domain::auction::Prices, /// JIT orders with surplus capturing JIT order owners should capture /// surplus if settled. - pub surplus_capturing_jit_order_owners: HashSet, + pub surplus_capturing_jit_order_owners: HashSet, } diff --git a/crates/autopilot/src/domain/settlement/mod.rs b/crates/autopilot/src/domain/settlement/mod.rs index ea01d27e12..6faeabcbf3 100644 --- a/crates/autopilot/src/domain/settlement/mod.rs +++ b/crates/autopilot/src/domain/settlement/mod.rs @@ -5,20 +5,15 @@ use { crate::{ - domain::{ - self, - Metrics, - OrderUid, - auction::order, - eth, - settlement::transaction::EncodedTrade, - }, + domain::{self, Metrics, OrderUid, auction::order, settlement::transaction::EncodedTrade}, infra::{self, persistence::dto::AuctionId}, }, chain::Chain, chrono::{DateTime, Utc}, database::{orders::OrderKind, solver_competition_v2::Solution}, + eth_domain_types as eth, futures::TryFutureExt, + num::Zero, number::conversions::big_decimal_to_u256, std::collections::{HashMap, HashSet}, }; @@ -30,10 +25,22 @@ pub mod transaction; pub use { auction::Auction, observer::Observer, - trade::{Trade, math}, + trade::{Trade, TradeEvent, math}, transaction::Transaction, }; +/// Summary of settlement metrics — used gas, gas price, surplus, fee, etc. +#[derive(Debug)] +pub(crate) struct SettlementMetrics<'a> { + pub(crate) gas: eth::Gas, + pub(crate) gas_price: eth::EffectiveGasPrice, + pub(crate) surplus: eth::Ether, + pub(crate) fee: eth::Ether, + /// Map between order and the respective fees. + pub(crate) fee_breakdown: HashMap, + pub(crate) jit_orders: Vec<&'a trade::Jit>, +} + /// A settled transaction together with the `Auction`, for which it was executed /// on-chain. /// @@ -81,11 +88,16 @@ impl Settlement { self.solution_uid } - /// Total surplus for all trades in the settlement. - pub fn surplus_in_ether(&self) -> eth::Ether { - self.trades - .iter() - .map(|trade| { + /// Summarizes settlement data required by the autopilot, see + /// [`SettlementMetrics`] for details. + pub(crate) fn summarize(&self) -> SettlementMetrics<'_> { + let mut surplus = eth::Ether::zero(); + let mut fee = eth::Ether::zero(); + let mut fee_breakdown = HashMap::with_capacity(self.trades.len()); + let mut jit_orders = Vec::new(); + + for trade in &self.trades { + let trade_surplus = trade .surplus_in_ether(&self.auction.prices) .unwrap_or_else(|err| { @@ -95,61 +107,50 @@ impl Settlement { "possible incomplete surplus calculation", ); num::zero() - }) - }) - .sum() - } - - /// Total fee taken for all the trades in the settlement. - pub fn fee_in_ether(&self) -> eth::Ether { - self.trades - .iter() - .map(|trade| { - trade - .fee_in_ether(&self.auction.prices) - .unwrap_or_else(|err| { - tracing::warn!( - ?err, - trade = %trade.uid(), - "possible incomplete fee calculation", - ); - num::zero() - }) - }) - .sum() - } + }); + surplus = surplus + trade_surplus; - /// Per order fees breakdown. Contains all orders from the settlement - pub fn fee_breakdown(&self) -> HashMap { - self.trades - .iter() - .map(|trade| { - let fee_breakdown = trade.fee_breakdown(&self.auction).unwrap_or_else(|err| { + let trade_fee = trade + .fee_in_ether(&self.auction.prices) + .unwrap_or_else(|err| { tracing::warn!( ?err, trade = %trade.uid(), - "possible incomplete fee breakdown calculation", + "possible incomplete fee calculation", ); - trade::FeeBreakdown { - total: eth::Asset { - // TODO surplus token - token: trade.sell_token(), - amount: num::zero(), - }, - protocol: vec![], - } + num::zero() }); - (*trade.uid(), fee_breakdown) - }) - .collect() - } + fee = fee + trade_fee; - /// Return all trades that are classified as Just-In-Time (JIT) orders. - pub fn jit_orders(&self) -> Vec<&trade::Jit> { - self.trades - .iter() - .filter_map(|trade| trade.as_jit()) - .collect() + let breakdown = trade.fee_breakdown(&self.auction).unwrap_or_else(|err| { + tracing::warn!( + ?err, + trade = %trade.uid(), + "possible incomplete fee breakdown calculation", + ); + trade::FeeBreakdown { + total: eth::Asset { + token: trade.sell_token(), + amount: num::zero(), + }, + protocol: vec![], + } + }); + fee_breakdown.insert(*trade.uid(), breakdown); + + if let Some(jit) = trade.as_jit() { + jit_orders.push(jit); + } + } + + SettlementMetrics { + gas: self.gas, + gas_price: self.gas_price, + surplus, + fee, + fee_breakdown, + jit_orders, + } } pub async fn new( @@ -207,6 +208,14 @@ impl Settlement { } } +/// A settlement event emitted by a settlement smart contract. +#[derive(Debug, Clone, Copy)] +pub struct SettlementEvent { + pub block: eth::BlockNo, + pub log_index: u64, + pub transaction: eth::TxId, +} + #[derive(Debug, Hash, Eq, PartialEq)] struct OrderMatchKey { uid: OrderUid, @@ -242,8 +251,8 @@ fn order_to_key(order: &database::solver_competition_v2::Order) -> OrderMatchKey OrderMatchKey { uid: OrderUid(order.uid.0), token: match order.side { - OrderKind::Sell => eth::H160(order.sell_token.0).into(), - OrderKind::Buy => eth::H160(order.buy_token.0).into(), + OrderKind::Sell => eth::Address::new(order.sell_token.0).into(), + OrderKind::Buy => eth::Address::new(order.buy_token.0).into(), }, executed: match order.side { OrderKind::Sell => big_decimal_to_u256(&order.executed_sell).unwrap_or_default(), @@ -351,12 +360,15 @@ mod tests { crate::domain::{ self, auction, - eth, + blockchain, settlement::{OrderMatchKey, trade_to_key}, }, - ethcontract::BlockId, + alloy::{eips::BlockId, primitives::address}, + eth_domain_types::{self as eth, Address}, hex_literal::hex, + number::u256_ext::U256Ext, std::collections::{HashMap, HashSet}, + winner_selection::{self as ws, state::RankedItem}, }; #[derive(Clone)] @@ -373,6 +385,119 @@ mod tests { } } + fn score_trade_with_winner_selection( + trade: &super::trade::Trade, + auction: &super::Auction, + ) -> eth::U256 { + let order = ws_order_from_trade(trade); + let prices = ws_prices_from_auction(auction); + let context = ws::AuctionContext { + fee_policies: auction + .orders + .iter() + .map(|(uid, policies)| { + let policies = policies.iter().copied().map(to_ws_fee_policy).collect(); + (ws::OrderUid(uid.0), policies) + }) + .collect(), + surplus_capturing_jit_order_owners: auction + .surplus_capturing_jit_order_owners + .iter() + .copied() + .collect(), + native_prices: prices.clone(), + }; + let solution = ws::Solution::new(0, ws::Address::ZERO, vec![order]); + let arbitrator = ws::Arbitrator { + max_winners: 1, + weth: ws::Address::ZERO, + }; + let ranking = arbitrator.arbitrate(vec![solution], &context); + + ranking + .ranked + .first() + .map(|solution| solution.score()) + .unwrap_or_default() + } + + fn ws_order_from_trade(trade: &super::trade::Trade) -> ws::Order { + let trade = super::trade::math::Trade::from(trade); + let (executed_sell, executed_buy) = ws_executed_amounts(&trade); + + ws::Order { + uid: ws::OrderUid(trade.uid.0), + sell_token: *trade.sell.token, + buy_token: *trade.buy.token, + sell_amount: trade.sell.amount.0, + buy_amount: trade.buy.amount.0, + executed_sell, + executed_buy, + side: match trade.side { + auction::order::Side::Buy => ws::Side::Buy, + auction::order::Side::Sell => ws::Side::Sell, + }, + } + } + + fn ws_executed_amounts(trade: &super::trade::math::Trade) -> (eth::U256, eth::U256) { + match trade.side { + auction::order::Side::Sell => { + let executed_sell = trade.executed.0; + let executed_buy = executed_sell + .checked_mul(trade.prices.custom.sell) + .and_then(|value| value.checked_ceil_div(&trade.prices.custom.buy)) + .expect("invalid sell trade executed amounts"); + (executed_sell, executed_buy) + } + auction::order::Side::Buy => { + let executed_buy = trade.executed.0; + let executed_sell = executed_buy + .checked_mul(trade.prices.custom.buy) + .and_then(|value| value.checked_div(trade.prices.custom.sell)) + .expect("invalid buy trade executed amounts"); + (executed_sell, executed_buy) + } + } + } + + fn ws_prices_from_auction(auction: &super::Auction) -> HashMap { + auction + .prices + .iter() + .map(|(token, price)| (Address::from(*token), price.get().0)) + .collect() + } + + fn to_ws_fee_policy(policy: domain::fee::Policy) -> ws::primitives::FeePolicy { + match policy { + domain::fee::Policy::Surplus { + factor, + max_volume_factor, + } => ws::primitives::FeePolicy::Surplus { + factor: factor.get(), + max_volume_factor: max_volume_factor.get(), + }, + domain::fee::Policy::PriceImprovement { + factor, + max_volume_factor, + quote, + } => ws::primitives::FeePolicy::PriceImprovement { + factor: factor.get(), + max_volume_factor: max_volume_factor.get(), + quote: ws::primitives::Quote { + sell_amount: quote.sell_amount, + buy_amount: quote.buy_amount, + fee: quote.fee, + solver: quote.solver, + }, + }, + domain::fee::Policy::Volume { factor } => ws::primitives::FeePolicy::Volume { + factor: factor.get(), + }, + } + } + // https://etherscan.io/tx/0x030623e438f28446329d8f4ff84db897907fcac59b9943b31b7be66f23c877af // A transfer transaction that emits a settlement event, but it's not actually a // swap. @@ -584,13 +709,11 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( - "9008d19f58aabd9ed0d60971565aa8510560ab41" - ))); + let settlement_contract = address!("9008d19f58aabd9ed0d60971565aa8510560ab41"); let transaction = super::transaction::Transaction::try_new( - &domain::eth::Transaction { - trace_calls: domain::eth::CallFrame { + &blockchain::Transaction { + trace_calls: blockchain::CallFrame { to: Some(settlement_contract), input: calldata.into(), ..Default::default() @@ -694,12 +817,10 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( - "9008d19f58aabd9ed0d60971565aa8510560ab41" - ))); + let settlement_contract = address!("9008d19f58aabd9ed0d60971565aa8510560ab41"); let transaction = super::transaction::Transaction::try_new( - &domain::eth::Transaction { - trace_calls: domain::eth::CallFrame { + &blockchain::Transaction { + trace_calls: blockchain::CallFrame { to: Some(settlement_contract), input: calldata.into(), ..Default::default() @@ -720,16 +841,12 @@ mod tests { // prices read from https://solver-instances.s3.eu-central-1.amazonaws.com/prod/mainnet/legacy/8655372.json prices: auction::Prices::from([ ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" - ))), + eth::TokenAddress::from(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), auction::Price::try_new(eth::U256::from(1000000000000000000u128).into()) .unwrap(), ), ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "c52fafdc900cb92ae01e6e4f8979af7f436e2eb2" - ))), + eth::TokenAddress::from(address!("c52fafdc900cb92ae01e6e4f8979af7f436e2eb2")), auction::Price::try_new(eth::U256::from(537359915436704u128).into()).unwrap(), ), ]), @@ -740,7 +857,7 @@ mod tests { let trade = super::trade::Trade::new(transaction.trades[0].clone(), &auction, 0); - // surplus (score) read from https://api.cow.fi/mainnet/api/v1/solver_competition/by_tx_hash/0xc48dc0d43ffb43891d8c3ad7bcf05f11465518a2610869b20b0b4ccb61497634 + // NOTE(historical): surplus (score) read from https://api.cow.fi/mainnet/api/v1/solver_competition/by_tx_hash/0xc48dc0d43ffb43891d8c3ad7bcf05f11465518a2610869b20b0b4ccb61497634 assert_eq!( trade.surplus_in_ether(&auction.prices).unwrap().0, eth::U256::from(52937525819789126u128) @@ -840,12 +957,10 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( - "9008d19f58aabd9ed0d60971565aa8510560ab41" - ))); + let settlement_contract = address!("9008d19f58aabd9ed0d60971565aa8510560ab41"); let transaction = super::transaction::Transaction::try_new( - &domain::eth::Transaction { - trace_calls: domain::eth::CallFrame { + &blockchain::Transaction { + trace_calls: blockchain::CallFrame { to: Some(settlement_contract), input: calldata.into(), ..Default::default() @@ -861,16 +976,12 @@ mod tests { let prices: auction::Prices = From::from([ ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "dac17f958d2ee523a2206206994597c13d831ec7" - ))), + eth::TokenAddress::from(address!("dac17f958d2ee523a2206206994597c13d831ec7")), auction::Price::try_new(eth::U256::from(321341140475275961528483840u128).into()) .unwrap(), ), ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "056fd409e1d7a124bd7017459dfea2f387b6d5cd" - ))), + eth::TokenAddress::from(address!("056fd409e1d7a124bd7017459dfea2f387b6d5cd")), auction::Price::try_new( eth::U256::from(3177764302250520038326415654912u128).into(), ) @@ -900,7 +1011,7 @@ mod tests { ); assert_eq!( - trade.score(&auction).unwrap().0, + score_trade_with_winner_selection(&trade, &auction), eth::U256::from(769018961144625u128) // 2 x surplus ); } @@ -1018,12 +1129,11 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( - "9008d19f58aabd9ed0d60971565aa8510560ab41" - ))); + let settlement_contract = + eth::Address::from_slice(&hex!("9008d19f58aabd9ed0d60971565aa8510560ab41")); let transaction = super::transaction::Transaction::try_new( - &domain::eth::Transaction { - trace_calls: domain::eth::CallFrame { + &blockchain::Transaction { + trace_calls: blockchain::CallFrame { to: Some(settlement_contract), input: calldata.into(), ..Default::default() @@ -1039,16 +1149,12 @@ mod tests { let prices: auction::Prices = From::from([ ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" - ))), + eth::TokenAddress::from(address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), auction::Price::try_new(eth::U256::from(374263465721452989998170112u128).into()) .unwrap(), ), ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" - ))), + eth::TokenAddress::from(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), auction::Price::try_new(eth::U256::from(1000000000000000000u128).into()).unwrap(), ), ]); @@ -1056,8 +1162,8 @@ mod tests { let auction = super::Auction { block: eth::BlockNo(0), prices, - surplus_capturing_jit_order_owners: HashSet::from([eth::Address( - eth::H160::from_slice(&hex!("f08d4dea369c456d26a3168ff0024b904f2d8b91")), + surplus_capturing_jit_order_owners: HashSet::from([address!( + "f08d4dea369c456d26a3168ff0024b904f2d8b91" )]), id: 0, orders: Default::default(), @@ -1202,12 +1308,10 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( - "9008d19f58aabd9ed0d60971565aa8510560ab41" - ))); + let settlement_contract = address!("9008d19f58aabd9ed0d60971565aa8510560ab41"); let transaction = super::transaction::Transaction::try_new( - &domain::eth::Transaction { - trace_calls: domain::eth::CallFrame { + &blockchain::Transaction { + trace_calls: blockchain::CallFrame { to: Some(settlement_contract), input: calldata.into(), ..Default::default() @@ -1223,21 +1327,15 @@ mod tests { let prices: auction::Prices = From::from([ ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "812Ba41e071C7b7fA4EBcFB62dF5F45f6fA853Ee" - ))), + eth::TokenAddress::from(address!("812Ba41e071C7b7fA4EBcFB62dF5F45f6fA853Ee")), auction::Price::try_new(eth::U256::from(400373909534592401408u128).into()).unwrap(), ), ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "a21Af1050F7B26e0cfF45ee51548254C41ED6b5c" - ))), + eth::TokenAddress::from(address!("a21Af1050F7B26e0cfF45ee51548254C41ED6b5c")), auction::Price::try_new(eth::U256::from(127910593u128).into()).unwrap(), ), ( - eth::TokenAddress(eth::H160::from_slice(&hex!( - "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" - ))), + eth::TokenAddress::from(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), auction::Price::try_new(eth::U256::from(1000000000000000000u128).into()).unwrap(), ), ]); @@ -1256,11 +1354,17 @@ mod tests { )]), }; let jit_trade = super::trade::Trade::new(transaction.trades[1].clone(), &auction, 0); - assert_eq!(jit_trade.fee_in_ether(&auction.prices).unwrap().0, 0.into()); - assert_eq!(jit_trade.score(&auction).unwrap().0, 0.into()); + assert_eq!( + jit_trade.fee_in_ether(&auction.prices).unwrap().0, + eth::U256::ZERO + ); + assert_eq!( + score_trade_with_winner_selection(&jit_trade, &auction), + eth::U256::ZERO + ); assert_eq!( jit_trade.fee_breakdown(&auction).unwrap().total.amount.0, - 0.into() + eth::U256::ZERO ); assert!( jit_trade @@ -1429,12 +1533,10 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "8f05589c4b810bc2f706854508d66d447cd971f8354a4bb0b3471ceb0a466bc7" )); - let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( - "9008d19f58aabd9ed0d60971565aa8510560ab41" - ))); + let settlement_contract = address!("9008d19f58aabd9ed0d60971565aa8510560ab41"); let transaction = super::transaction::Transaction::try_new( - &domain::eth::Transaction { - trace_calls: domain::eth::CallFrame { + &blockchain::Transaction { + trace_calls: blockchain::CallFrame { to: Some(settlement_contract), input: calldata.into(), ..Default::default() diff --git a/crates/autopilot/src/domain/settlement/observer.rs b/crates/autopilot/src/domain/settlement/observer.rs index fc9af2e653..ec4d758409 100644 --- a/crates/autopilot/src/domain/settlement/observer.rs +++ b/crates/autopilot/src/domain/settlement/observer.rs @@ -12,15 +12,13 @@ use { crate::{ - domain::{ - eth, - settlement::{self, Settlement}, - }, + domain::settlement::{self, Settlement}, infra, }, anyhow::{Context, Result, anyhow}, - ethrpc::alloy::conversions::IntoLegacy, - std::time::Duration, + eth_domain_types as eth, + futures::StreamExt, + shared::retry::retry_with_sleep, }; #[derive(Clone)] @@ -29,12 +27,6 @@ pub struct Observer { persistence: infra::Persistence, } -enum IndexSuccess { - NothingToDo, - IndexedSettlement, - SkippedInvalidTransaction, -} - impl Observer { /// Creates a new Observer and asynchronously schedules the first update /// run. @@ -42,67 +34,59 @@ impl Observer { Self { eth, persistence } } - /// Fetches all the available missing data needed for bookkeeping. - /// This needs to get called after indexing a new settlement event - /// since this code needs that data to already be present in the DB. - pub async fn update(&self) { - const MAX_RETRIES: usize = 5; - let mut attempts = 0; - while attempts < MAX_RETRIES { - match self.single_update().await { - Ok(IndexSuccess::IndexedSettlement) => { - tracing::debug!("on settlement event updater ran and processed event"); - } - Ok(IndexSuccess::SkippedInvalidTransaction) => { - tracing::warn!("stored default values for unindexable transaction"); - } - Ok(IndexSuccess::NothingToDo) => { - tracing::debug!("on settlement event updater ran without update"); + /// Post processes all outstanding settlements. This involves decoding the + /// settlement details from the transaction and associating it with a + /// solution proposed by a solver for the auction specified at the end of + /// the transaction call data. If no solution can be found a dummy mapping + /// gets saved to mark the settlement as processed. This can happen when a + /// solver submits a solution despite not winning or if the settlement + /// belongs to an auction that was arbitrated in another environment (i.e. + /// prod vs. staging). + pub async fn post_process_outstanding_settlement_transactions(&self) { + let settlements = + match retry_with_sleep(|| self.persistence.get_settlements_without_auction()).await { + Ok(settlements) => settlements, + Err(errs) => { + tracing::warn!(?errs, "failed to fetch unprocessed settlements"); return; } - Err(err) => { - tracing::debug!(?err, "encountered retryable error"); - // wait a little to give temporary errors a chance to resolve themselves - const TEMP_ERROR_BACK_OFF: Duration = Duration::from_millis(100); - tokio::time::sleep(TEMP_ERROR_BACK_OFF).await; - attempts += 1; - continue; - } - } + }; - // everything worked fine -> reset our attempts for the next settlement - attempts = 0; + if settlements.is_empty() { + tracing::debug!("no unprocessed settlements found"); + return; } - } - /// Update database for settlement events that have not been processed yet. - /// - /// Returns whether an update was performed. - async fn single_update(&self) -> Result { - // Find a settlement event that has not been processed yet. - let Some(event) = self - .persistence - .get_settlement_without_auction() - .await - .context("failed to fetch unprocessed tx from DB")? - else { - return Ok(IndexSuccess::NothingToDo); - }; - - tracing::debug!(tx = ?event.transaction, "found unprocessed settlement"); + // On mainnet it's common to have multiple settlements in the + // same block. So even if we process every block immediately, + // we should still post-process multiple settlements concurrently. + const MAX_CONCURRENCY: usize = 10; + futures::stream::iter(settlements) + .for_each_concurrent(MAX_CONCURRENCY, |settlement| async move { + tracing::debug!(tx = ?settlement.transaction, "start post processing of settlement"); + match retry_with_sleep(|| self.post_process_settlement(settlement)).await { + Ok(_) => tracing::debug!( + tx = ?settlement.transaction, + "successfully post-processed settlement" + ), + Err(errs) => tracing::warn!( + tx = ?settlement.transaction, + ?errs, + "gave up on post-processing settlement" + ), + } + }) + .await; + } + async fn post_process_settlement(&self, settlement: super::SettlementEvent) -> Result<()> { let settlement_data = self - .fetch_auction_data_for_transaction(event.transaction) + .fetch_auction_data_for_transaction(settlement.transaction) .await?; self.persistence - .save_settlement(event, settlement_data.as_ref()) + .save_settlement(settlement, settlement_data.as_ref()) .await - .context("failed to update settlement")?; - - match settlement_data { - None => Ok(IndexSuccess::SkippedInvalidTransaction), - Some(_) => Ok(IndexSuccess::IndexedSettlement), - } + .context("failed to update settlement") } /// Inspects the calldata of the transaction, decodes the arguments, and @@ -115,13 +99,7 @@ impl Observer { let transaction = match self.eth.transaction(tx).await { Ok(transaction) => { let separator = self.eth.contracts().settlement_domain_separator(); - let settlement_contract = self - .eth - .contracts() - .settlement() - .address() - .into_legacy() - .into(); + let settlement_contract = *self.eth.contracts().settlement().address(); settlement::Transaction::try_new( &transaction, separator, diff --git a/crates/autopilot/src/domain/settlement/trade/math.rs b/crates/autopilot/src/domain/settlement/trade/math.rs index c8635850da..bf2311c495 100644 --- a/crates/autopilot/src/domain/settlement/trade/math.rs +++ b/crates/autopilot/src/domain/settlement/trade/math.rs @@ -1,23 +1,17 @@ pub use error::Error; use { super::ExecutedProtocolFee, - crate::{ - domain::{ - self, - OrderUid, - auction::{ - self, - order::{self, Side}, - }, - eth, - fee, - settlement::transaction::{ClearingPrices, Prices}, - }, - util::conv::U256Ext, + crate::domain::{ + self, + OrderUid, + auction::{self, order}, + fee, + settlement::transaction::{ClearingPrices, Prices}, }, error::Math, - ethrpc::alloy::conversions::IntoLegacy, + eth_domain_types as eth, num::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub}, + number::u256_ext::U256Ext, std::collections::HashMap, }; @@ -34,66 +28,6 @@ pub struct Trade { } impl Trade { - /// Score defined as (surplus + protocol fees) first converted to buy - /// amounts and then converted to the native token. - /// - /// [CIP-38](https://forum.cow.fi/t/cip-38-solver-computed-fees-rank-by-surplus/2061>) as the - /// base of the score computation. - /// [Draft CIP](https://forum.cow.fi/t/cip-draft-updating-score-definition-for-buy-orders/2930) - /// as the latest revision to avoid edge cases for certain buy orders. - /// - /// Denominated in NATIVE token - pub fn score( - &self, - fee_policies: &HashMap>, - native_prices: &domain::auction::Prices, - ) -> Result { - let native_price_buy = native_prices - .get(&self.buy.token) - .ok_or(Error::MissingPrice(self.buy.token))?; - - let surplus_in_surplus_token = { - let user_surplus = self.surplus_over_limit_price()?.0; - let fees: eth::U256 = self.protocol_fees(fee_policies)?.into_iter().try_fold( - eth::U256::zero(), - |acc, i| { - acc.checked_add(i.fee.amount.0) - .ok_or(Error::Math(Math::Overflow)) - }, - )?; - user_surplus - .checked_add(fees) - .ok_or(Error::Math(Math::Overflow))? - }; - - let score = match self.side { - // `surplus` of sell orders is already in buy tokens so we simply convert it to ETH - Side::Sell => native_price_buy.in_eth(eth::TokenAmount(surplus_in_surplus_token)), - Side::Buy => { - // `surplus` of buy orders is in sell tokens. We start with following formula: - // buy_amount / sell_amount == buy_price / sell_price - // - // since `surplus` of buy orders is in sell tokens we convert to buy amount via: - // buy_amount == (buy_price / sell_price) * surplus - // - // to avoid loss of precision because we work with integers we first multiply - // and then divide: - // buy_amount = surplus * buy_price / sell_price - let surplus_in_buy_tokens: eth::U256 = surplus_in_surplus_token - .full_mul(self.buy.amount.0) - .checked_div(self.sell.amount.0.into()) - .ok_or(Error::Math(Math::DivisionByZero))? - .try_into() - .map_err(|_| Error::Math(Math::Overflow))?; - - // Afterwards we convert the buy token surplus to the native token. - native_price_buy.in_eth(surplus_in_buy_tokens.into()) - } - }; - - Ok(score) - } - /// A general surplus function. /// /// Can return different types of surplus based on the input parameters. @@ -320,8 +254,8 @@ impl Trade { } => { let surplus = self.surplus_over_limit_price()?; std::cmp::min( - self.surplus_fee(surplus, (*factor).into())?, - self.volume_fee((*max_volume_factor).into())?, + self.surplus_fee(surplus, (*factor).get())?, + self.volume_fee((*max_volume_factor).get())?, ) } fee::Policy::PriceImprovement { @@ -331,11 +265,11 @@ impl Trade { } => { let price_improvement = self.price_improvement(quote)?; std::cmp::min( - self.surplus_fee(price_improvement, (*factor).into())?, - self.volume_fee((*max_volume_factor).into())?, + self.surplus_fee(price_improvement, (*factor).get())?, + self.volume_fee((*max_volume_factor).get())?, ) } - fee::Policy::Volume { factor } => self.volume_fee((*factor).into())?, + fee::Policy::Volume { factor } => self.volume_fee((*factor).get())?, }; Ok(fee) } @@ -348,7 +282,7 @@ impl Trade { // negative surplus is not error in this case, as solutions often have no // improvement over quote which results in negative surplus if let Err(error::Math::Negative) = surplus { - return Ok(eth::SurplusTokenAmount(0.into())); + return Ok(eth::SurplusTokenAmount(eth::U256::ZERO)); } Ok(surplus?) } @@ -384,9 +318,9 @@ impl Trade { side: self.side, }, Quote { - sell: quote.sell_amount.into_legacy().into(), - buy: quote.buy_amount.into_legacy().into(), - fee: quote.fee.into_legacy().into(), + sell: quote.sell_amount.into(), + buy: quote.buy_amount.into(), + fee: quote.fee.into(), }, )?; self.surplus_over(&self.prices.custom, quote) @@ -596,7 +530,7 @@ impl From<&super::Trade> for Trade { } } pub mod error { - use crate::domain::eth; + use eth_domain_types as eth; #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/autopilot/src/domain/settlement/trade/mod.rs b/crates/autopilot/src/domain/settlement/trade/mod.rs index 7db1489024..bc6ac7827f 100644 --- a/crates/autopilot/src/domain/settlement/trade/mod.rs +++ b/crates/autopilot/src/domain/settlement/trade/mod.rs @@ -3,10 +3,10 @@ use { crate::domain::{ self, auction::{self, order}, - eth, fee, }, bigdecimal::Zero, + eth_domain_types as eth, }; pub mod math; @@ -40,11 +40,6 @@ impl Trade { } } - /// CIP38 score defined as surplus + protocol fee - pub fn score(&self, auction: &super::Auction) -> Result { - math::Trade::from(self).score(&auction.orders, &auction.prices) - } - /// Surplus of a trade. pub fn surplus_in_ether(&self, prices: &auction::Prices) -> Result { match self { @@ -137,6 +132,14 @@ impl Trade { } } +/// A trade event emitted by a settlement smart contract. +#[derive(Debug, Clone, Copy)] +pub struct TradeEvent { + pub block: eth::BlockNo, + pub log_index: u64, + pub order_uid: model::order::OrderUid, +} + /// A trade filling an order that was part of the auction. #[derive(Debug, Clone)] pub struct Fulfillment { diff --git a/crates/autopilot/src/domain/settlement/transaction/mod.rs b/crates/autopilot/src/domain/settlement/transaction/mod.rs index c1a673c4b4..5e8f67a3bf 100644 --- a/crates/autopilot/src/domain/settlement/transaction/mod.rs +++ b/crates/autopilot/src/domain/settlement/transaction/mod.rs @@ -1,12 +1,11 @@ use { crate::{ boundary, - domain::{self, auction::order, eth}, + domain::{self, auction::order, blockchain}, }, - alloy::sol_types::SolCall, - contracts::alloy::{GPv2AllowListAuthentication, GPv2Settlement}, - ethcontract::BlockId, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + alloy::{eips::BlockId, sol_types::SolCall}, + contracts::{GPv2AllowListAuthentication, GPv2Settlement}, + eth_domain_types as eth, std::collections::HashSet, }; @@ -37,8 +36,8 @@ impl Authenticator for GPv2AllowListAuthentication::Instance { // find an eligible caller in the callstack. To avoid this case the // underlying call needs to happen on the same block the transaction happened. Ok(self - .isSolver(prospective_solver.0.into_alloy()) - .block(block.into_alloy()) + .isSolver(prospective_solver) + .block(block) .call() .await .map_err(Error::Authentication)?) @@ -68,7 +67,7 @@ pub struct Transaction { impl Transaction { pub async fn try_new( - transaction: ð::Transaction, + transaction: &blockchain::Transaction, domain_separator: ð::DomainSeparator, settlement_contract: eth::Address, authenticator: &impl Authenticator, @@ -76,7 +75,7 @@ impl Transaction { // Find trace call to settlement contract let (calldata, callers) = find_settlement_trace_and_callers(&transaction.trace_calls, settlement_contract) .map(|(trace, path)| (trace.input.clone(), path.clone())) - // All transactions emitting settlement events should have a /settle call, + // All transactions emitting settlement events should have a /settle call, // otherwise it's an execution client bug .ok_or(Error::MissingCalldata)?; @@ -84,7 +83,7 @@ impl Transaction { // In cases of solvers using EOA to submit solutions, the address is the sender // of the transaction. In cases of solvers using a smart contract to // submit solutions, the address is deduced from the calldata. - let block = BlockId::Number(transaction.block.0.into()); + let block = BlockId::from(transaction.block.0); let solver = find_solver_address(authenticator, callers, block).await?; /// Number of bytes that may be appended to the calldata to store an @@ -121,7 +120,7 @@ impl Transaction { let mut trades = Vec::with_capacity(decoded_trades.len()); for trade in decoded_trades { - let flags = tokenized::TradeFlags(trade.flags.into_legacy()); + let flags = tokenized::TradeFlags(trade.flags); let sell_token_index = usize::try_from(trade.sellTokenIndex) .expect("SC was able to look up this index"); let buy_token_index = usize::try_from(trade.buyTokenIndex) @@ -138,18 +137,18 @@ impl Transaction { uid: tokenized::order_uid(&trade, &tokens, domain_separator) .map_err(Error::OrderUidRecover)?, sell: eth::Asset { - token: sell_token.into_legacy().into(), - amount: trade.sellAmount.into_legacy().into(), + token: sell_token.into(), + amount: trade.sellAmount.into(), }, buy: eth::Asset { - token: buy_token.into_legacy().into(), - amount: trade.buyAmount.into_legacy().into(), + token: buy_token.into(), + amount: trade.buyAmount.into(), }, side: flags.side(), - receiver: trade.receiver.into_legacy().into(), + receiver: trade.receiver, valid_to: trade.validTo, app_data: domain::auction::order::AppDataHash(trade.appData.into()), - fee_amount: trade.feeAmount.into_legacy().into(), + fee_amount: trade.feeAmount.into(), sell_token_balance: flags.sell_token_balance().into(), buy_token_balance: flags.buy_token_balance().into(), partially_fillable: flags.partially_fillable(), @@ -159,15 +158,15 @@ impl Transaction { ) .map_err(Error::SignatureRecover)?) .into(), - executed: trade.executedAmount.into_legacy().into(), + executed: trade.executedAmount.into(), prices: Prices { uniform: ClearingPrices { - sell: clearing_prices[uniform_sell_token_index].into_legacy(), - buy: clearing_prices[uniform_buy_token_index].into_legacy(), + sell: clearing_prices[uniform_sell_token_index], + buy: clearing_prices[uniform_buy_token_index], }, custom: ClearingPrices { - sell: clearing_prices[sell_token_index].into_legacy(), - buy: clearing_prices[buy_token_index].into_legacy(), + sell: clearing_prices[sell_token_index], + buy: clearing_prices[buy_token_index], }, }, }) @@ -179,9 +178,9 @@ impl Transaction { } fn find_settlement_trace_and_callers( - call_frame: ð::CallFrame, + call_frame: &blockchain::CallFrame, settlement_contract: eth::Address, -) -> Option<(ð::CallFrame, Vec)> { +) -> Option<(&blockchain::CallFrame, Vec)> { // Use a queue (VecDeque) to keep track of frames to process let mut queue = std::collections::VecDeque::new(); queue.push_back((call_frame, vec![call_frame.from])); @@ -201,7 +200,7 @@ fn find_settlement_trace_and_callers( None } -fn is_settlement_trace(trace: ð::CallFrame, settlement_contract: eth::Address) -> bool { +fn is_settlement_trace(trace: &blockchain::CallFrame, settlement_contract: eth::Address) -> bool { let settle_selector = &GPv2Settlement::GPv2Settlement::settleCall::SELECTOR; trace.to.unwrap_or_default() == settlement_contract && trace.input.0.starts_with(settle_selector) diff --git a/crates/autopilot/src/domain/settlement/transaction/tokenized.rs b/crates/autopilot/src/domain/settlement/transaction/tokenized.rs index c36e8d1b47..d7d66438e7 100644 --- a/crates/autopilot/src/domain/settlement/transaction/tokenized.rs +++ b/crates/autopilot/src/domain/settlement/transaction/tokenized.rs @@ -1,12 +1,12 @@ use { crate::{ boundary, - domain::{self, auction::order, eth}, + domain::{self, auction::order}, }, + alloy::primitives::U256, app_data::AppDataHash, - contracts::alloy::GPv2Settlement, - ethcontract::U256, - ethrpc::alloy::conversions::IntoLegacy, + contracts::GPv2Settlement, + eth_domain_types as eth, }; /// Recover order uid from order data and signature @@ -15,7 +15,7 @@ pub fn order_uid( tokens: &[alloy::primitives::Address], domain_separator: ð::DomainSeparator, ) -> Result { - let flags = TradeFlags(trade.flags.into_legacy()); + let flags = TradeFlags(trade.flags); let signature = crate::boundary::Signature::from_bytes(flags.signing_scheme(), &trade.signature.0) .map_err(error::Uid::Signature)?; @@ -43,7 +43,7 @@ pub fn order_uid( let owner = signature .recover_owner(&trade.signature.0, &domain_separator, &order.hash_struct()) .map_err(error::Uid::RecoverOwner)?; - Ok(order.uid(&domain_separator, &owner).into()) + Ok(order.uid(&domain_separator, owner).into()) } /// Trade flags are encoded in a 256-bit integer field. For more information on diff --git a/crates/autopilot/src/event_updater.rs b/crates/autopilot/src/event_updater.rs index 1a2117be45..6a926a6a79 100644 --- a/crates/autopilot/src/event_updater.rs +++ b/crates/autopilot/src/event_updater.rs @@ -1,8 +1,9 @@ use { anyhow::Result, - ethrpc::block_stream::{BlockNumberHash, BlockRetrieving}, - shared::{ - event_handling::{EventHandler, EventRetrieving, EventStoring}, + ethrpc::block_stream::BlockNumberHash, + event_indexing::{ + block_retriever::BlockRetrieving, + event_handler::{EventHandler, EventRetrieving, EventStoring}, maintenance::Maintaining, }, std::sync::Arc, diff --git a/crates/autopilot/src/infra/api.rs b/crates/autopilot/src/infra/api.rs new file mode 100644 index 0000000000..2c3a1127b2 --- /dev/null +++ b/crates/autopilot/src/infra/api.rs @@ -0,0 +1,178 @@ +use { + alloy::primitives::Address, + axum::{ + Router, + extract::{Path, Query, State as AxumState}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + routing::get, + }, + model::quote::NativeTokenPrice, + observe::tracing::distributed::axum::{make_span, record_trace_id}, + price_estimation::{PriceEstimationError, native::NativePriceEstimating}, + serde::Deserialize, + std::{ + net::SocketAddr, + ops::RangeInclusive, + sync::Arc, + time::{Duration, Instant}, + }, + tokio::sync::oneshot, +}; + +/// Minimum allowed timeout for price estimation requests. +/// Values below this are not useful as they don't give estimators enough time. +const MIN_TIMEOUT: Duration = Duration::from_millis(250); + +#[derive(Clone)] +struct State { + estimator: Arc, + allowed_timeout: RangeInclusive, +} + +#[derive(Debug, Deserialize)] +struct NativePriceQuery { + /// Optional timeout in milliseconds for the price estimation request. + /// If not provided, uses the default timeout configured for autopilot. + /// Values below 250ms are automatically clamped to the minimum (250ms). + /// Values exceeding the configured maximum are clamped to the maximum. + #[serde(default)] + timeout_ms: Option, +} + +pub async fn serve( + addr: SocketAddr, + estimator: Arc, + max_timeout: Duration, + shutdown: oneshot::Receiver<()>, +) -> Result<(), std::io::Error> { + let state = State { + estimator, + allowed_timeout: MIN_TIMEOUT..=max_timeout, + }; + + let app = Router::new() + .route("/native_price/{token}", get(get_native_price)) + .with_state(state) + .layer( + tower::ServiceBuilder::new() + .layer(tower_http::trace::TraceLayer::new_for_http().make_span_with(make_span)) + .map_request(record_trace_id), + ); + + let listener = tokio::net::TcpListener::bind(addr).await?; + tracing::info!(?addr, "serving HTTP API"); + + axum::serve(listener, app) + .with_graceful_shutdown(async { + shutdown.await.ok(); + }) + .await +} + +async fn get_native_price( + Path(token): Path
, + Query(query): Query, + AxumState(state): AxumState, +) -> Response { + let timeout = query + .timeout_ms + .map(Duration::from_millis) + .unwrap_or(*state.allowed_timeout.end()) + .clamp(*state.allowed_timeout.start(), *state.allowed_timeout.end()); + + let start = Instant::now(); + match state.estimator.estimate_native_price(token, timeout).await { + Ok(price) => Json(NativeTokenPrice { price }).into_response(), + Err(err) => { + let elapsed = start.elapsed(); + tracing::warn!( + ?err, + ?token, + ?timeout, + ?elapsed, + "failed to estimate native token price" + ); + error_to_response(err) + } + } +} + +fn error_to_response(err: PriceEstimationError) -> Response { + match err { + PriceEstimationError::NoLiquidity | PriceEstimationError::EstimatorInternal(_) => { + (StatusCode::NOT_FOUND, "No liquidity").into_response() + } + PriceEstimationError::UnsupportedToken { token: _, reason } => ( + StatusCode::BAD_REQUEST, + format!("Unsupported token, reason: {reason}"), + ) + .into_response(), + PriceEstimationError::RateLimited => { + (StatusCode::TOO_MANY_REQUESTS, "Rate limited").into_response() + } + PriceEstimationError::TradingOutsideAllowedWindow { message } + | PriceEstimationError::TokenTemporarilySuspended { message } + | PriceEstimationError::InsufficientLiquidity { message } + | PriceEstimationError::CustomSolverError { message } => { + (StatusCode::BAD_REQUEST, message).into_response() + } + PriceEstimationError::UnsupportedOrderType(reason) => ( + StatusCode::BAD_REQUEST, + format!("Unsupported order type, reason: {reason}"), + ) + .into_response(), + PriceEstimationError::ProtocolInternal(_) => { + (StatusCode::INTERNAL_SERVER_ERROR, "Internal error").into_response() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + async fn assert_bad_request_message(err: PriceEstimationError, expected_message: &str) { + let response = error_to_response(err); + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + let body = response.into_body(); + let body = axum::body::to_bytes(body, usize::MAX).await.unwrap(); + assert_eq!(std::str::from_utf8(&body).unwrap(), expected_message); + } + + #[tokio::test] + async fn maps_custom_solver_errors_to_bad_request_with_message() { + assert_bad_request_message( + PriceEstimationError::TradingOutsideAllowedWindow { + message: "outside window".to_string(), + }, + "outside window", + ) + .await; + + assert_bad_request_message( + PriceEstimationError::TokenTemporarilySuspended { + message: "token suspended".to_string(), + }, + "token suspended", + ) + .await; + + assert_bad_request_message( + PriceEstimationError::InsufficientLiquidity { + message: "insufficient".to_string(), + }, + "insufficient", + ) + .await; + + assert_bad_request_message( + PriceEstimationError::CustomSolverError { + message: "custom".to_string(), + }, + "custom", + ) + .await; + } +} diff --git a/crates/autopilot/src/infra/blockchain/contracts.rs b/crates/autopilot/src/infra/blockchain/contracts.rs index bae638ad3f..0b9a676214 100644 --- a/crates/autopilot/src/infra/blockchain/contracts.rs +++ b/crates/autopilot/src/infra/blockchain/contracts.rs @@ -1,45 +1,44 @@ use { - crate::domain, + alloy::primitives::Address, chain::Chain, - contracts::alloy::{ + contracts::{ ChainalysisOracle, + FlashLoanRouter, GPv2AllowListAuthentication, GPv2Settlement, HooksTrampoline, - InstanceExt, WETH9, support::Balances, }, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - }, - primitive_types::H160, + eth_domain_types as eth, + ethrpc::Web3, }; #[derive(Debug, Clone)] pub struct Contracts { settlement: GPv2Settlement::Instance, - signatures: contracts::alloy::support::Signatures::Instance, + signatures: contracts::support::Signatures::Instance, weth: WETH9::Instance, balances: Balances::Instance, chainalysis_oracle: Option, trampoline: HooksTrampoline::Instance, + flashloan_router: Address, /// The authenticator contract that decides which solver is allowed to /// submit settlements. authenticator: GPv2AllowListAuthentication::Instance, /// The domain separator for settlement contract used for signing orders. - settlement_domain_separator: domain::eth::DomainSeparator, + settlement_domain_separator: eth::DomainSeparator, } #[derive(Debug, Clone)] pub struct Addresses { - pub settlement: Option, - pub signatures: Option, - pub weth: Option, - pub balances: Option, - pub trampoline: Option, + pub settlement: Option
, + pub signatures: Option
, + pub weth: Option
, + pub balances: Option
, + pub trampoline: Option
, + pub flashloan_router: Option
, } impl Contracts { @@ -47,53 +46,53 @@ impl Contracts { let settlement = GPv2Settlement::Instance::new( addresses .settlement - .map(IntoAlloy::into_alloy) .or_else(|| GPv2Settlement::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); - let signatures = contracts::alloy::support::Signatures::Instance::new( + let signatures = contracts::support::Signatures::Instance::new( addresses .signatures - .map(IntoAlloy::into_alloy) - .or_else(|| contracts::alloy::support::Signatures::deployment_address(&chain.id())) + .or_else(|| contracts::support::Signatures::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); let weth = WETH9::Instance::new( addresses .weth - .map(IntoAlloy::into_alloy) .or_else(|| WETH9::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); let balances = Balances::Instance::new( addresses .balances - .map(IntoAlloy::into_alloy) .or_else(|| Balances::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); let trampoline = HooksTrampoline::Instance::new( addresses .trampoline - .map(IntoAlloy::into_alloy) .or_else(|| HooksTrampoline::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); - let chainalysis_oracle = ChainalysisOracle::Instance::deployed(&web3.alloy) + let flashloan_router = addresses + .flashloan_router + .or_else(|| FlashLoanRouter::deployment_address(&chain.id())) + .unwrap(); + + let chainalysis_oracle = ChainalysisOracle::Instance::deployed(&web3.provider) .await .ok(); - let settlement_domain_separator = domain::eth::DomainSeparator( + let settlement_domain_separator = eth::DomainSeparator( settlement .domainSeparator() .call() @@ -108,7 +107,7 @@ impl Contracts { .call() .await .expect("authenticator address"), - web3.alloy.clone(), + web3.provider.clone(), ); Self { @@ -120,6 +119,7 @@ impl Contracts { settlement_domain_separator, authenticator, trampoline, + flashloan_router, } } @@ -131,7 +131,7 @@ impl Contracts { &self.balances } - pub fn signatures(&self) -> &contracts::alloy::support::Signatures::Instance { + pub fn signatures(&self) -> &contracts::support::Signatures::Instance { &self.signatures } @@ -139,7 +139,7 @@ impl Contracts { &self.trampoline } - pub fn settlement_domain_separator(&self) -> &domain::eth::DomainSeparator { + pub fn settlement_domain_separator(&self) -> ð::DomainSeparator { &self.settlement_domain_separator } @@ -153,20 +153,15 @@ impl Contracts { /// Wrapped version of the native token (e.g. WETH for Ethereum, WXDAI for /// Gnosis Chain) - pub fn wrapped_native_token(&self) -> domain::eth::WrappedNativeToken { - self.weth.address().into_legacy().into() + pub fn wrapped_native_token(&self) -> eth::WrappedNativeToken { + (*self.weth.address()).into() } pub fn authenticator(&self) -> &GPv2AllowListAuthentication::Instance { &self.authenticator } -} -/// Returns the address of a contract for the specified chain, or `None` if -/// there is no known deployment for the contract on that chain. -pub fn deployment_address(contract: ðcontract::Contract, chain: &Chain) -> Option { - contract - .networks - .get(&chain.id().to_string()) - .map(|network| network.address) + pub fn flashloan_router(&self) -> Address { + self.flashloan_router + } } diff --git a/crates/autopilot/src/infra/blockchain/mod.rs b/crates/autopilot/src/infra/blockchain/mod.rs index c0c1275f62..1ffa89525d 100644 --- a/crates/autopilot/src/infra/blockchain/mod.rs +++ b/crates/autopilot/src/infra/blockchain/mod.rs @@ -1,10 +1,17 @@ use { self::contracts::Contracts, - crate::{boundary, domain::eth}, - alloy::providers::Provider, + crate::{boundary, domain}, + alloy::{ + providers::{Provider, ext::DebugApi}, + rpc::types::{ + TransactionReceipt, + trace::geth::{GethDebugBuiltInTracerType, GethDebugTracingOptions, GethTrace}, + }, + }, + anyhow::bail, chain::Chain, - ethrpc::{Web3, block_stream::CurrentBlockWatcher, extensions::DebugNamespace}, - primitive_types::U256, + eth_domain_types as eth, + ethrpc::{Web3, block_stream::CurrentBlockWatcher}, thiserror::Error, url::Url, }; @@ -21,12 +28,9 @@ pub struct Rpc { impl Rpc { /// Instantiate an RPC client to an Ethereum (or Ethereum-compatible) node /// at the specifed URL. - pub async fn new( - url: &url::Url, - ethrpc_args: &shared::ethrpc::Arguments, - ) -> Result { + pub async fn new(url: &url::Url, ethrpc_args: &shared::web3::Arguments) -> Result { let web3 = boundary::web3_client(url, ethrpc_args); - let chain = Chain::try_from(web3.alloy.get_chain_id().await?) + let chain = Chain::try_from(web3.provider.get_chain_id().await?) .map_err(|_| Error::UnsupportedChain)?; Ok(Self { @@ -81,7 +85,7 @@ impl Ethereum { Self { current_block: current_block_args - .stream(url, unbuffered_web3.alloy.clone()) + .stream(url, unbuffered_web3.provider.clone()) .await .expect("couldn't initialize current block stream"), web3, @@ -105,15 +109,20 @@ impl Ethereum { &self.contracts } - pub async fn transaction(&self, hash: eth::TxId) -> Result { - let (transaction, receipt, traces) = tokio::try_join!( - self.web3.eth().transaction(hash.0.into()), - self.web3.eth().transaction_receipt(hash.0), + pub async fn transaction( + &self, + hash: eth::TxId, + ) -> Result { + let (receipt, traces): (Option, GethTrace) = tokio::try_join!( + self.web3.provider.get_transaction_receipt(hash.0), // Use unbuffered transport for the Debug API since not all providers support // batched debug calls. - self.unbuffered_web3.debug().transaction(hash.0), + self.unbuffered_web3.provider.debug_trace_transaction( + hash.0, + GethDebugTracingOptions::new_tracer(GethDebugBuiltInTracerType::CallTracer), + ) )?; - let transaction = transaction.ok_or(Error::TransactionNotFound)?; + let receipt = receipt.ok_or(Error::TransactionNotFound)?; let block_hash = receipt @@ -123,60 +132,42 @@ impl Ethereum { )))?; let block = self .web3 - .eth() - .block(block_hash.into()) + .provider + .get_block_by_hash(block_hash) .await? .ok_or(Error::TransactionNotFound)?; - into_domain(transaction, receipt, traces, block.timestamp) + + into_domain(receipt, traces, block.header.timestamp) .map_err(Error::IncompleteTransactionData) } } fn into_domain( - transaction: web3::types::Transaction, - receipt: web3::types::TransactionReceipt, - trace_calls: ethrpc::extensions::CallFrame, - timestamp: U256, -) -> anyhow::Result { - Ok(eth::Transaction { - hash: transaction.hash.into(), - from: transaction - .from - .ok_or(anyhow::anyhow!("missing from"))? - .into(), + receipt: TransactionReceipt, + trace: GethTrace, + timestamp: u64, +) -> anyhow::Result { + let trace_calls = match trace { + GethTrace::CallTracer(call_frame) => call_frame.into(), + trace => bail!("unsupported trace call {trace:?}"), + }; + + Ok(domain::blockchain::Transaction { + hash: receipt.transaction_hash.into(), + from: receipt.from, block: receipt .block_number .ok_or(anyhow::anyhow!("missing block_number"))? - .0[0] - .into(), - gas: receipt - .gas_used - .ok_or(anyhow::anyhow!("missing gas_used"))? .into(), - gas_price: receipt - .effective_gas_price - .ok_or(anyhow::anyhow!("missing effective_gas_price"))? - .into(), - timestamp: timestamp.as_u32(), - trace_calls: trace_calls.into(), + gas: receipt.gas_used.into(), + gas_price: receipt.effective_gas_price.into(), + timestamp: u32::try_from(timestamp)?, + trace_calls, }) } -impl From for eth::CallFrame { - fn from(frame: ethrpc::extensions::CallFrame) -> Self { - eth::CallFrame { - from: frame.from.into(), - to: frame.to.map(Into::into), - input: frame.input.0.into(), - calls: frame.calls.into_iter().map(Into::into).collect(), - } - } -} - #[derive(Debug, Error)] pub enum Error { - #[error("web3 error: {0:?}")] - Web3(#[from] web3::error::Error), #[error("alloy transport error: {0:?}")] Alloy(#[from] alloy::transports::TransportError), #[error("missing field {0}, node client bug?")] diff --git a/crates/autopilot/src/infra/mod.rs b/crates/autopilot/src/infra/mod.rs index 52809890c3..4d34b214b7 100644 --- a/crates/autopilot/src/infra/mod.rs +++ b/crates/autopilot/src/infra/mod.rs @@ -1,3 +1,4 @@ +pub mod api; pub mod blockchain; pub mod persistence; pub mod shadow; @@ -7,5 +8,5 @@ pub use { blockchain::Ethereum, order_validation::banned, persistence::Persistence, - solvers::{Driver, notify_banned_solver}, + solvers::Driver, }; diff --git a/crates/autopilot/src/infra/persistence/cli.rs b/crates/autopilot/src/infra/persistence/cli.rs deleted file mode 100644 index 7365743b14..0000000000 --- a/crates/autopilot/src/infra/persistence/cli.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Command line arguments for persistence. - -use anyhow::Result; - -#[derive(clap::Parser, Debug, Clone)] -pub struct S3 { - #[clap(long, env)] - /// The s3_instance_upload_* arguments configure how auction instances - /// should be uploaded to AWS S3. - /// They must either all be set or all not set. - pub s3_instance_upload_bucket: Option, - - /// Prepended to the auction id to form the final instance filename on S3. - /// Something like "staging/mainnet/" - #[clap(long, env)] - pub s3_instance_upload_filename_prefix: Option, -} - -impl S3 { - pub fn into(self) -> Result> { - let s3_args = &[ - &self.s3_instance_upload_bucket, - &self.s3_instance_upload_filename_prefix, - ]; - let all_some = s3_args.iter().all(|arg| arg.is_some()); - let all_none = s3_args.iter().all(|arg| arg.is_none()); - anyhow::ensure!( - all_some || all_none, - "either set all s3_instance_upload bucket arguments or none" - ); - Ok(if all_some { - Some(s3::Config { - bucket: self.s3_instance_upload_bucket.unwrap(), - filename_prefix: self.s3_instance_upload_filename_prefix.unwrap(), - }) - } else { - None - }) - } -} diff --git a/crates/autopilot/src/infra/persistence/dto/auction.rs b/crates/autopilot/src/infra/persistence/dto/auction.rs index 6dfa8a4fc6..8629ce6fd3 100644 --- a/crates/autopilot/src/infra/persistence/dto/auction.rs +++ b/crates/autopilot/src/infra/persistence/dto/auction.rs @@ -1,11 +1,9 @@ use { super::order::Order, - crate::{ - domain, - domain::{auction::Price, eth}, - }, + crate::domain::{self, auction::Price}, + alloy::primitives::{Address, U256}, + eth_domain_types as eth, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, @@ -22,12 +20,11 @@ pub fn from_domain(auction: domain::RawAuctionData) -> RawAuctionData { prices: auction .prices .into_iter() - .map(|(key, value)| (key.into(), value.get().into())) + .map(|(key, value)| (*key, value.get().0)) .collect(), surplus_capturing_jit_order_owners: auction .surplus_capturing_jit_order_owners .into_iter() - .map(Into::into) .collect(), } } @@ -39,14 +36,13 @@ pub struct RawAuctionData { pub block: u64, pub orders: Vec, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub prices: BTreeMap, + pub prices: BTreeMap, #[serde(default)] - pub surplus_capturing_jit_order_owners: Vec, + pub surplus_capturing_jit_order_owners: Vec
, } pub type AuctionId = i64; -#[serde_as] #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Auction { @@ -71,14 +67,13 @@ impl Auction { .prices .into_iter() .map(|(key, value)| { - Price::try_new(value.into()).map(|price| (eth::TokenAddress(key), price)) + Price::try_new(value.into()).map(|price| (eth::TokenAddress::from(key), price)) }) .collect::>()?, surplus_capturing_jit_order_owners: self .auction .surplus_capturing_jit_order_owners .into_iter() - .map(Into::into) .collect(), }) } diff --git a/crates/autopilot/src/infra/persistence/dto/fee_policy.rs b/crates/autopilot/src/infra/persistence/dto/fee_policy.rs index b6700777bc..75692f2690 100644 --- a/crates/autopilot/src/infra/persistence/dto/fee_policy.rs +++ b/crates/autopilot/src/infra/persistence/dto/fee_policy.rs @@ -2,7 +2,6 @@ use { crate::{boundary, domain}, anyhow::Context, database::fee_policies::{FeePolicy, FeePolicyKind}, - ethrpc::alloy::conversions::IntoAlloy, }; pub fn from_domain( @@ -18,8 +17,8 @@ pub fn from_domain( auction_id, order_uid: boundary::database::byte_array::ByteArray(order_uid.0), kind: FeePolicyKind::Surplus, - surplus_factor: Some(factor.into()), - surplus_max_volume_factor: Some(max_volume_factor.into()), + surplus_factor: Some(factor.get()), + surplus_max_volume_factor: Some(max_volume_factor.get()), volume_factor: None, price_improvement_factor: None, price_improvement_max_volume_factor: None, @@ -30,7 +29,7 @@ pub fn from_domain( kind: FeePolicyKind::Volume, surplus_factor: None, surplus_max_volume_factor: None, - volume_factor: Some(factor.into()), + volume_factor: Some(factor.get()), price_improvement_factor: None, price_improvement_max_volume_factor: None, }, @@ -45,8 +44,8 @@ pub fn from_domain( surplus_factor: None, surplus_max_volume_factor: None, volume_factor: None, - price_improvement_factor: Some(factor.into()), - price_improvement_max_volume_factor: Some(max_volume_factor.into()), + price_improvement_factor: Some(factor.get()), + price_improvement_max_volume_factor: Some(max_volume_factor.get()), }, } } @@ -84,9 +83,9 @@ pub fn try_into_domain( quote: { let quote = quote.ok_or(Error::MissingQuote)?; domain::fee::Quote { - sell_amount: quote.sell_amount.0.into_alloy(), - buy_amount: quote.buy_amount.0.into_alloy(), - fee: quote.fee.0.into_alloy(), + sell_amount: quote.sell_amount.0, + buy_amount: quote.buy_amount.0, + fee: quote.fee.0, solver: quote.solver, } }, diff --git a/crates/autopilot/src/infra/persistence/dto/order.rs b/crates/autopilot/src/infra/persistence/dto/order.rs index 0f3c1745a6..78fd5e00e5 100644 --- a/crates/autopilot/src/infra/persistence/dto/order.rs +++ b/crates/autopilot/src/infra/persistence/dto/order.rs @@ -1,13 +1,13 @@ use { crate::{ boundary::{self}, - domain::{self, OrderUid, eth, fee::FeeFactor}, + domain::{self, OrderUid}, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, app_data::AppDataHash, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + configs::fee_factor::FeeFactor, + eth_domain_types as eth, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, serde::{Deserialize, Serialize}, serde_with::serde_as, }; @@ -17,8 +17,8 @@ use { #[serde(rename_all = "camelCase")] pub struct Order { pub uid: boundary::OrderUid, - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, #[serde_as(as = "HexOrDecimalU256")] pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] @@ -27,8 +27,8 @@ pub struct Order { pub created: u32, pub valid_to: u32, pub kind: boundary::OrderKind, - pub receiver: Option, - pub owner: H160, + pub receiver: Option
, + pub owner: Address, pub partially_fillable: bool, #[serde_as(as = "HexOrDecimalU256")] pub executed: U256, @@ -59,8 +59,8 @@ pub fn from_domain(order: domain::Order) -> Order { created: order.created, valid_to: order.valid_to, kind: order.side.into(), - receiver: order.receiver.map(Into::into), - owner: order.owner.into(), + receiver: order.receiver, + owner: order.owner, partially_fillable: order.partially_fillable, executed: order.executed.into(), pre_interactions: order.pre_interactions.into_iter().map(Into::into).collect(), @@ -97,8 +97,8 @@ pub fn to_domain(order: Order) -> domain::Order { created: order.created, valid_to: order.valid_to, side: order.kind.into(), - receiver: order.receiver.map(Into::into), - owner: order.owner.into(), + receiver: order.receiver, + owner: order.owner, partially_fillable: order.partially_fillable, executed: order.executed.into(), pre_interactions: order.pre_interactions.into_iter().map(Into::into).collect(), @@ -148,8 +148,8 @@ impl From for domain::auction::order::Side { impl From for boundary::InteractionData { fn from(interaction: domain::auction::order::Interaction) -> Self { Self { - target: interaction.target.into_alloy(), - value: interaction.value.into_alloy(), + target: interaction.target, + value: interaction.value, call_data: interaction.call_data, } } @@ -158,8 +158,8 @@ impl From for boundary::InteractionData { impl From for domain::auction::order::Interaction { fn from(interaction: boundary::InteractionData) -> Self { Self { - target: interaction.target.into_legacy(), - value: interaction.value.into_legacy(), + target: interaction.target, + value: interaction.value, call_data: interaction.call_data, } } @@ -279,16 +279,16 @@ impl FeePolicy { factor, max_volume_factor, } => Self::Surplus { - factor: factor.into(), - max_volume_factor: max_volume_factor.into(), + factor: factor.get(), + max_volume_factor: max_volume_factor.get(), }, domain::fee::Policy::PriceImprovement { factor, max_volume_factor, quote, } => Self::PriceImprovement { - factor: factor.into(), - max_volume_factor: max_volume_factor.into(), + factor: factor.get(), + max_volume_factor: max_volume_factor.get(), quote: Quote { sell_amount: quote.sell_amount, buy_amount: quote.buy_amount, @@ -297,7 +297,7 @@ impl FeePolicy { }, }, domain::fee::Policy::Volume { factor } => Self::Volume { - factor: factor.into(), + factor: factor.get(), }, } } @@ -348,9 +348,9 @@ pub struct Quote { impl Quote { fn from_domain(quote: domain::Quote) -> Self { Quote { - sell_amount: quote.sell_amount.0.into_alloy(), - buy_amount: quote.buy_amount.0.into_alloy(), - fee: quote.fee.0.into_alloy(), + sell_amount: quote.sell_amount.0, + buy_amount: quote.buy_amount.0, + fee: quote.fee.0, solver: quote.solver, } } @@ -358,9 +358,9 @@ impl Quote { pub fn to_domain(&self, order_uid: OrderUid) -> domain::Quote { domain::Quote { order_uid, - sell_amount: self.sell_amount.into_legacy().into(), - buy_amount: self.buy_amount.into_legacy().into(), - fee: self.fee.into_legacy().into(), + sell_amount: self.sell_amount.into(), + buy_amount: self.buy_amount.into(), + fee: self.fee.into(), solver: self.solver, } } diff --git a/crates/autopilot/src/infra/persistence/mod.rs b/crates/autopilot/src/infra/persistence/mod.rs index 13c2874fd6..f82491537a 100644 --- a/crates/autopilot/src/infra/persistence/mod.rs +++ b/crates/autopilot/src/infra/persistence/mod.rs @@ -2,33 +2,38 @@ use { crate::{ boundary, database::{Postgres, order_events::store_order_events}, - domain::{self, eth, settlement::transaction::EncodedTrade}, - infra::persistence::dto::AuctionId, + domain::{ + self, + settlement::{SettlementEvent, TradeEvent, transaction::EncodedTrade}, + }, + infra::persistence::dto::{AuctionId, RawAuctionData}, }, + ::winner_selection::state::RankedItem, + alloy::primitives::B256, anyhow::Context, - bigdecimal::ToPrimitive, + bigdecimal::{BigDecimal, ToPrimitive}, boundary::database::byte_array::ByteArray, chrono::{DateTime, Utc}, database::{ events::EventIndex, leader_pg_lock::LeaderLock, - order_events::OrderEventLabel, + order_events::{OrderEventLabel, OrderFilterReason}, order_execution::Asset, orders::{ BuyTokenDestination as DbBuyTokenDestination, SellTokenSource as DbSellTokenSource, SigningScheme as DbSigningScheme, }, - solver_competition_v2::{Order, Solution}, + solver_competition_v2::{self, Order, Solution}, }, domain::auction::order::{ BuyTokenDestination as DomainBuyTokenDestination, SellTokenSource as DomainSellTokenSource, SigningScheme as DomainSigningScheme, }, + eth_domain_types as eth, futures::{StreamExt, TryStreamExt}, - number::conversions::{alloy::u256_to_big_uint, big_decimal_to_u256, u256_to_big_decimal}, - primitive_types::H256, + number::conversions::{big_decimal_to_u256, u256_to_big_decimal, u256_to_big_uint}, shared::db_order_conversions::full_order_into_model_order, std::{ collections::{HashMap, HashSet}, @@ -36,54 +41,149 @@ use { sync::Arc, time::Duration, }, - tracing::Instrument, + tokio::sync::mpsc, + tracing::{Instrument, instrument}, }; -pub mod cli; pub mod dto; #[derive(Clone)] pub struct Persistence { s3: Option, postgres: Arc, + /// Writing into this channel will cause the auction to be written to the + /// DB in an orderly manner (FIFO). + upload_queue: mpsc::UnboundedSender, +} + +struct AuctionUpload { + auction_id: domain::auction::Id, + /// Contains everything buy the auction_id. + auction_data: RawAuctionData, } impl Persistence { pub async fn new(config: Option, postgres: Arc) -> Self { + let sender = Self::spawn_db_upload_task(postgres.clone()); + Self { s3: match config { Some(config) => Some(s3::Uploader::new(config).await), None => None, }, postgres, + upload_queue: sender, } } + /// Spawns a task that writes the most recent auction to the DB. Uploads + /// happen on a FIFO basis so the last write will always be the most + /// recent auction. + fn spawn_db_upload_task(db: Arc) -> mpsc::UnboundedSender { + let (sender, mut receiver) = mpsc::unbounded_channel::(); + tokio::task::spawn(async move { + while let Some(upload) = receiver.recv().await { + if let Err(err) = db + .replace_current_auction(upload.auction_id, upload.auction_data) + .await + { + tracing::error!(?err, "failed to replace auction in DB"); + } + } + tracing::error!("auction upload task terminated unexpectedly"); + }); + sender + } + pub async fn leader(&self, key: String) -> LeaderLock { LeaderLock::new(self.postgres.pool.clone(), key, Duration::from_millis(200)) } - /// There is always only one `current` auction. - /// - /// This method replaces the current auction with the given one. - /// - /// If the given auction is successfully saved, it is also archived. - pub async fn replace_current_auction( - &self, - auction: &domain::RawAuctionData, - ) -> Result { - let _timer = observe::metrics::metrics() - .on_auction_overhead_start("autopilot", "replace_auction_in_db"); - let auction = dto::auction::from_domain(auction.clone()); + /// Spawns a background task that listens for new order notifications from + /// PostgreSQL and notifies via the provided Notify. + pub fn spawn_order_listener(&self, notify: Arc) { + let pool = self.postgres.pool.clone(); + tokio::spawn(async move { + loop { + let mut listener = match sqlx::postgres::PgListener::connect_with(&pool).await { + Ok(listener) => listener, + Err(err) => { + tracing::error!(?err, "failed to create PostgreSQL listener"); + tokio::time::sleep(Duration::from_secs(5)).await; + continue; + } + }; + + tracing::info!("connected to PostgreSQL for order notifications"); + + if let Err(err) = listener.listen("new_order").await { + tracing::error!(?err, "failed to listen on 'new_order' channel"); + tokio::time::sleep(Duration::from_secs(5)).await; + continue; + } + + loop { + match listener.recv().await { + Ok(notification) => { + let order_uid = notification.payload(); + tracing::debug!(order_uid, "received order notification from postgres"); + notify.notify_one(); + } + Err(err) => { + tracing::error!(?err, "error receiving notification from postgres"); + break; + } + } + } + } + }); + } + + /// Fetches the ID that should be used for the next auction. + pub async fn get_next_auction_id(&self) -> Result { + let _timer = Metrics::get() + .database_queries + .with_label_values(&["get_next_auction_id"]) + .start_timer(); self.postgres - .replace_current_auction(&auction) + .get_next_auction_id() .await - .inspect(|&id| { - self.archive_auction(dto::auction::Auction { id, auction }); - }) .map_err(DatabaseError) } + /// Spawns a background task that replaces the current auction in the DB + /// with the new one. + pub fn replace_current_auction_in_db( + &self, + new_auction_id: domain::auction::Id, + new_auction_data: &domain::RawAuctionData, + ) { + self.upload_queue + .send(AuctionUpload { + auction_id: new_auction_id, + auction_data: dto::auction::from_domain(new_auction_data.clone()), + }) + .expect("upload queue should be alive at all times"); + } + + /// Spawns a background task that uploads the auction to S3. + pub fn upload_auction_to_s3(&self, id: domain::auction::Id, auction: &domain::RawAuctionData) { + if auction.orders.is_empty() { + return; + } + let Some(s3) = self.s3.clone() else { + return; + }; + let auction = auction.clone(); + tokio::task::spawn(async move { + let auction_dto = dto::auction::from_domain(auction); + match s3.upload(id.to_string(), auction_dto).await { + Ok(key) => tracing::info!(?key, "uploaded auction to s3"), + Err(err) => tracing::warn!(?err, "failed to upload auction to s3"), + } + }); + } + /// Finds solvable orders based on the order's min validity period. pub async fn all_solvable_orders( &self, @@ -95,35 +195,6 @@ impl Persistence { .context("failed to fetch all solvable orders") } - /// Saves the given auction to storage for debugging purposes. - /// - /// There is no intention to retrieve this data programmatically. - fn archive_auction(&self, instance: dto::auction::Auction) { - let Some(uploader) = self.s3.clone() else { - return; - }; - if instance.auction.orders.is_empty() { - tracing::info!("skip upload of empty auction"); - return; - } - tokio::spawn( - async move { - match uploader - .upload(instance.id.to_string(), &instance.auction) - .await - { - Ok(key) => { - tracing::info!(?key, "uploaded auction to s3"); - } - Err(err) => { - tracing::warn!(?err, "failed to upload auction to s3"); - } - } - } - .instrument(tracing::Span::current()), - ); - } - /// Saves the competition data to the DB pub async fn save_competition( &self, @@ -140,7 +211,7 @@ impl Persistence { pub async fn save_solutions( &self, auction_id: domain::auction::Id, - solutions: impl Iterator, + solutions: impl Iterator, ) -> Result<(), DatabaseError> { let _timer = Metrics::get() .database_queries @@ -154,22 +225,22 @@ impl Persistence { auction_id, &solutions .enumerate() - .map(|(uid, participant)| { + .map(|(uid, bid)| { let solution = Solution { uid: uid.try_into().context("uid overflow")?, - id: u256_to_big_decimal(&participant.solution().id().into()), - solver: ByteArray(participant.solution().solver().0.0), - is_winner: participant.is_winner(), - filtered_out: participant.filtered_out(), - score: u256_to_big_decimal(&participant.solution().score().get().0), - orders: participant + id: BigDecimal::from(bid.solution().id()), + solver: ByteArray(bid.solution().solver().0.0), + is_winner: bid.is_winner(), + filtered_out: bid.is_filtered_out(), + score: u256_to_big_decimal(&bid.score().get().0), + orders: bid .solution() .orders() .iter() .map(|(order_uid, order)| Order { uid: ByteArray(order_uid.0), - sell_token: ByteArray(order.sell.token.0.0), - buy_token: ByteArray(order.buy.token.0.0), + sell_token: ByteArray(order.sell.token.into_array()), + buy_token: ByteArray(order.buy.token.into_array()), limit_sell: u256_to_big_decimal(&order.sell.amount.0), limit_buy: u256_to_big_decimal(&order.buy.amount.0), executed_sell: u256_to_big_decimal(&order.executed_sell.0), @@ -177,18 +248,8 @@ impl Persistence { side: order.side.into(), }) .collect(), - price_tokens: participant - .solution() - .prices() - .keys() - .map(|token| ByteArray(token.0.0)) - .collect(), - price_values: participant - .solution() - .prices() - .values() - .map(|price| u256_to_big_decimal(&price.get().0)) - .collect(), + price_tokens: vec![], + price_values: vec![], }; Ok::<_, DatabaseError>(solution) }) @@ -203,7 +264,7 @@ impl Persistence { pub async fn save_surplus_capturing_jit_order_owners( &self, auction_id: AuctionId, - surplus_capturing_jit_order_owners: &[domain::eth::Address], + surplus_capturing_jit_order_owners: &[eth::Address], ) -> Result<(), DatabaseError> { self.postgres .save_surplus_capturing_jit_order_owners( @@ -227,12 +288,40 @@ impl Persistence { order_uids: impl IntoIterator, label: boundary::OrderEventLabel, ) { + let order_uids: Vec<_> = order_uids.into_iter().collect(); + self.store_order_events_owned(order_uids, std::convert::identity, label, None); + } + + /// A variants of [`store_order_events`] where [`items`] is already an owned + /// collection which allows us to move the logic to convert an item to a + /// [`domain::OrderUid`] into the background task as well. + #[instrument(skip_all)] + pub fn store_order_events_owned( + &self, + items: I, + convert: F, + label: boundary::OrderEventLabel, + reason: Option, + ) where + I: IntoIterator + Send + 'static, + I::Item: Send, + F: (Fn(I::Item) -> domain::OrderUid) + Send + 'static, + { let db = self.postgres.clone(); - let order_uids = order_uids.into_iter().collect(); tokio::spawn( async move { - let mut tx = db.pool.acquire().await.expect("failed to acquire tx"); - store_order_events(&mut tx, order_uids, label, Utc::now()).await; + let order_uids = items.into_iter().map(convert).collect(); + match db.pool.acquire().await { + Ok(mut tx) => { + store_order_events(&mut tx, order_uids, label, reason, Utc::now()).await; + } + Err(err) => { + tracing::error!( + ?err, + "failed to acquire a connection to store order events!" + ); + } + }; } .instrument(tracing::Span::current()), ); @@ -259,12 +348,13 @@ impl Persistence { ex.commit().await.context("commit") } - /// For a given auction and solver, tries to find the settlement - /// transaction. + /// Tries to find the transaction executing a given solution proposed + /// by the solver. pub async fn find_settlement_transaction( &self, auction_id: i64, solver: eth::Address, + solution_uid: usize, ) -> Result, DatabaseError> { let _timer = Metrics::get() .database_queries @@ -276,9 +366,12 @@ impl Persistence { &mut ex, auction_id, ByteArray(solver.0.0), + solution_uid + .try_into() + .context("could not convert solution id to i64")?, ) .await? - .map(|hash| H256(hash.0).into())) + .map(|hash| B256::new(hash.0).into())) } /// Save auction related data to the database. @@ -292,7 +385,13 @@ impl Persistence { .with_label_values(&["save_auction"]) .start_timer(); - let mut ex = self.postgres.pool.begin().await?; + let mut ex = self.postgres.pool.acquire().await?; + + let order_uids: Vec<_> = auction + .orders + .iter() + .map(|order| ByteArray(order.uid.0)) + .collect(); database::auction::save( &mut ex, @@ -300,15 +399,11 @@ impl Persistence { id: auction.id, block: i64::try_from(auction.block).context("block overflow")?, deadline: i64::try_from(deadline).context("deadline overflow")?, - order_uids: auction - .orders - .iter() - .map(|order| ByteArray(order.uid.0)) - .collect(), + order_uids: order_uids.clone(), price_tokens: auction .prices .keys() - .map(|token| ByteArray(token.0.0)) + .map(|token| ByteArray(token.into_array())) .collect(), price_values: auction .prices @@ -324,7 +419,9 @@ impl Persistence { ) .await?; - Ok(ex.commit().await?) + database::auction::save_auction_orders(&mut ex, auction.id, &order_uids).await?; + + Ok(()) } /// Get auction data to post-process the given trades. @@ -351,7 +448,7 @@ impl Persistence { .map_err(error::Auction::DatabaseError)? .ok_or(error::Auction::NotFound)? .into_iter() - .map(|owner| eth::H160(owner.0).into()) + .map(|owner| eth::Address::new(owner.0)) .collect(); let prices = database::auction_prices::fetch(&mut ex, auction_id) @@ -359,7 +456,7 @@ impl Persistence { .map_err(error::Auction::DatabaseError)? .into_iter() .map(|price| { - let token = eth::H160(price.token.0).into(); + let token = eth::Address::new(price.token.0).into(); let price = big_decimal_to_u256(&price.price) .ok_or(domain::auction::InvalidPrice) .and_then(|p| domain::auction::Price::try_new(p.into())) @@ -461,8 +558,8 @@ impl Persistence { /// order creation timestamp, and minimum validity period. pub async fn solvable_orders_after( &self, - mut current_orders: HashMap, - mut current_quotes: HashMap, + mut current_orders: HashMap>, + mut current_quotes: HashMap>, after_timestamp: DateTime, after_block: u64, min_valid_to: u32, @@ -490,7 +587,7 @@ impl Persistence { // Fetch the orders that were updated after the given block and were created or // cancelled after the given timestamp. - let next_orders: HashMap = { + let next_orders: HashMap> = { let _timer = Metrics::get() .database_queries .with_label_values(&["open_orders_after"]) @@ -503,7 +600,7 @@ impl Persistence { ) .map(|result| match result { Ok(order) => full_order_into_model_order(order) - .map(|order| (domain::OrderUid(order.metadata.uid.0), order)), + .map(|order| (domain::OrderUid(order.metadata.uid.0), Arc::new(order))), Err(err) => Err(anyhow::Error::from(err)), }) .try_collect() @@ -515,20 +612,9 @@ impl Persistence { .to_u64() .context("latest_settlement_block is not u64")?; - // Blindly insert all new orders into the cache. + // Insert new / updated orders or remove invalidated orders + // and the associated quote. for (uid, order) in next_orders { - current_orders.insert(uid, order); - } - - // Filter out all the invalid orders. - current_orders.retain(|_uid, order| { - let expired = order.data.valid_to < min_valid_to - || order - .metadata - .ethflow_data - .as_ref() - .is_some_and(|data| data.user_valid_to < i64::from(min_valid_to)); - let invalidated = order.metadata.invalidated; let onchain_error = order .metadata @@ -548,10 +634,30 @@ impl Persistence { } }; - !expired && !invalidated && !onchain_error && !fulfilled - }); + if invalidated || onchain_error || fulfilled { + current_orders.remove(&uid); + current_quotes.remove(&uid); + } else { + current_orders.insert(uid, order); + } + } - current_quotes.retain(|uid, _| current_orders.contains_key(uid)); + // Filter out all the expired orders and their quotes. + current_orders.retain(|uid, order| { + let expired = order.data.valid_to < min_valid_to + || order + .metadata + .ethflow_data + .as_ref() + .is_some_and(|data| data.user_valid_to < i64::from(min_valid_to)); + + if expired { + current_quotes.remove(uid); + false + } else { + true + } + }); { let _timer = Metrics::get() @@ -577,7 +683,7 @@ impl Persistence { let order_uid = domain::OrderUid(quote.order_uid.0); match dto::quote::into_domain(quote) { Ok(quote) => { - current_quotes.insert(order_uid, quote); + current_quotes.insert(order_uid, Arc::new(quote)); } Err(err) => tracing::warn!(?order_uid, ?err, "failed to convert quote from db"), } @@ -594,36 +700,37 @@ impl Persistence { /// Returns the oldest settlement event for which the accociated auction is /// not yet populated in the database. - pub async fn get_settlement_without_auction( + pub async fn get_settlements_without_auction( &self, - ) -> Result, DatabaseError> { + ) -> Result, DatabaseError> { let _timer = Metrics::get() .database_queries .with_label_values(&["get_settlement_without_auction"]) .start_timer(); let mut ex = self.postgres.pool.acquire().await?; - let event = database::settlements::get_settlement_without_auction(&mut ex) + let events = database::settlements::get_settlements_without_auction(&mut ex) .await? + .into_iter() .map(|event| { - let event = domain::eth::SettlementEvent { + let event = SettlementEvent { block: u64::try_from(event.block_number) .context("negative block")? .into(), log_index: u64::try_from(event.log_index).context("negative log index")?, - transaction: eth::TxId(H256(event.tx_hash.0)), + transaction: eth::TxId(B256::new(event.tx_hash.0)), }; Ok::<_, DatabaseError>(event) }) - .transpose()?; - Ok(event) + .collect::, _>>()?; + Ok(events) } /// Returns the trade events that are associated with the settlement event pub async fn get_trades_for_settlement( &self, - settlement: &domain::eth::SettlementEvent, - ) -> Result, DatabaseError> { + settlement: &SettlementEvent, + ) -> Result, DatabaseError> { let _timer = Metrics::get() .database_queries .with_label_values(&["get_trades_for_settlement"]) @@ -640,12 +747,12 @@ impl Persistence { .await? .into_iter() .map(|event| { - let event = domain::eth::TradeEvent { + let event = TradeEvent { block: u64::try_from(event.block_number) .context("negative block")? .into(), log_index: u64::try_from(event.log_index).context("negative log index")?, - order_uid: domain::OrderUid(event.order_uid.0), + order_uid: domain::OrderUid(event.order_uid.0).into(), }; Ok::<_, DatabaseError>(event) }) @@ -654,7 +761,7 @@ impl Persistence { pub async fn save_settlement( &self, - event: domain::eth::SettlementEvent, + event: SettlementEvent, settlement: Option<&domain::settlement::Settlement>, ) -> Result<(), DatabaseError> { let _timer = Metrics::get() @@ -678,12 +785,14 @@ impl Persistence { .await?; if let Some(settlement) = settlement { - let gas = settlement.gas(); - let gas_price = settlement.gas_price(); - let surplus = settlement.surplus_in_ether(); - let fee = settlement.fee_in_ether(); - let fee_breakdown = settlement.fee_breakdown(); - let jit_orders = settlement.jit_orders(); + let domain::settlement::SettlementMetrics { + gas, + gas_price, + surplus, + fee, + fee_breakdown, + jit_orders, + } = settlement.summarize(); let solver: database::Address = ByteArray(settlement.solver().0.0); tracing::debug!( @@ -712,6 +821,7 @@ impl Persistence { &mut ex, fee_breakdown.keys().cloned().collect(), OrderEventLabel::Traded, + None, Utc::now(), ) .await; @@ -723,14 +833,14 @@ impl Persistence { auction_id, block_number, Asset { - token: ByteArray(order_fee.total.token.0.0), + token: ByteArray(order_fee.total.token.into_array()), amount: u256_to_big_decimal(&order_fee.total.amount.0), }, &order_fee .protocol .into_iter() .map(|executed| Asset { - token: ByteArray(executed.fee.token.0.0), + token: ByteArray(executed.fee.token.into_array()), amount: u256_to_big_decimal(&executed.fee.amount.0), }) .collect::>(), @@ -751,7 +861,7 @@ impl Persistence { &mut ex, &jit_orders .into_iter() - .filter_map(|jit_order| match trade_events.get(&jit_order.uid) { + .filter_map(|jit_order| match trade_events.get(&jit_order.uid.into()) { Some((block_number, log_index)) => { Some(database::jit_orders::JitOrder { block_number: i64::try_from(block_number.0).ok()?, @@ -763,8 +873,8 @@ impl Persistence { 0, ) .unwrap_or_default(), - sell_token: ByteArray(jit_order.sell.token.0.0), - buy_token: ByteArray(jit_order.buy.token.0.0), + sell_token: ByteArray(jit_order.sell.token.into_array()), + buy_token: ByteArray(jit_order.buy.token.into_array()), sell_amount: u256_to_big_decimal(&jit_order.sell.amount.0), buy_amount: u256_to_big_decimal(&jit_order.buy.amount.0), valid_to: i64::from(jit_order.valid_to), @@ -874,63 +984,6 @@ impl Persistence { Ok(()) } - /// Finds solvers that won `last_auctions_count` consecutive auctions but - /// never settled any of them. The current block is used to prevent - /// selecting auctions with deadline after the current block since they - /// still can be settled. - pub async fn find_non_settling_solvers( - &self, - last_auctions_count: u32, - current_block: u64, - ) -> anyhow::Result> { - let mut ex = self.postgres.pool.acquire().await.context("acquire")?; - let _timer = Metrics::get() - .database_queries - .with_label_values(&["find_non_settling_solvers"]) - .start_timer(); - - Ok(database::solver_competition_v2::find_non_settling_solvers( - &mut ex, - last_auctions_count, - current_block, - ) - .await - .context("failed to fetch non-settling solvers")? - .into_iter() - .map(|solver| eth::Address(solver.0.into())) - .collect()) - } - - /// Finds solvers that have a failure settling rate above the given - /// ratio. The current block is used to prevent selecting auctions with - /// deadline after the current block since they still can be settled. - pub async fn find_low_settling_solvers( - &self, - last_auctions_count: u32, - current_block: u64, - max_failure_rate: f64, - min_wins_threshold: u32, - ) -> anyhow::Result> { - let mut ex = self.postgres.pool.acquire().await.context("acquire")?; - let _timer = Metrics::get() - .database_queries - .with_label_values(&["find_low_settling_solvers"]) - .start_timer(); - - Ok(database::solver_competition_v2::find_low_settling_solvers( - &mut ex, - last_auctions_count, - current_block, - max_failure_rate, - min_wins_threshold, - ) - .await - .context("solver_competition::find_low_settling_solvers")? - .into_iter() - .map(|solver| eth::Address(solver.0.into())) - .collect()) - } - pub async fn get_solver_winning_solutions( &self, auction_id: domain::auction::Id, @@ -952,6 +1005,28 @@ impl Persistence { .context("solver_competition::fetch_solver_winning_solutions")?, ) } + + /// Fetches orders which are currently inflight. Those orders should + /// be omitted from the current auction to avoid onchain reverts. + #[instrument(skip_all)] + pub async fn fetch_in_flight_orders( + &self, + current_block: u64, + ) -> anyhow::Result> { + let _timer = Metrics::get() + .database_queries + .with_label_values(&["inflight_orders"]) + .start_timer(); + + let mut ex = self.postgres.pool.acquire().await.context("acquire")?; + let orders = + solver_competition_v2::fetch_in_flight_orders(&mut ex, current_block.cast_signed()) + .await?; + Ok(orders + .into_iter() + .map(|o| crate::domain::OrderUid(o.0)) + .collect()) + } } #[derive(prometheus_metric_storage::MetricStorage)] diff --git a/crates/autopilot/src/infra/solvers/byte_stream.rs b/crates/autopilot/src/infra/solvers/byte_stream.rs new file mode 100644 index 0000000000..b36f77ce60 --- /dev/null +++ b/crates/autopilot/src/infra/solvers/byte_stream.rs @@ -0,0 +1,94 @@ +use { + bytes::Bytes, + futures::Stream, + std::{task::Poll, time::Instant}, +}; + +/// Thin wrapper around a payload that already exists fully serialized +/// in-memory. The purpose of converting that into a stream is to allow +/// measuring the data transfer of the request body (for debugging and +/// optimization purposes). +/// +/// Note that this measurement is only an approximation of the truth. +/// The reason is that this only measures how long it takes `hyper` +/// to load the last byte from the body into the buffer of the network +/// stack. However, given how big `/solve` requests are in practice +/// `hyper` should have to flush the buffer a couple of times so the +/// measured time should be reasonably accurate. +pub struct ByteStream { + data: Bytes, + created_at: Instant, + first_polled_at: Option, + span: tracing::Span, +} + +impl ByteStream { + pub fn new(data: Bytes) -> Self { + Self { + data, + created_at: Instant::now(), + first_polled_at: None, + span: tracing::Span::current(), + } + } +} + +// Since `hyper` uses `Bytes` under the hood which are reference counted +// the chunks we yield can be as big as we want. To minimize overhead +// that's only there for debugging purposes we always yield all the +// data at once. The measurements will still be accurate because `hyper` +// has to poll the stream once more to confirm that it's actually +// exhausted. +impl Stream for ByteStream { + type Item = Result; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> Poll> { + let this = self.as_mut().get_mut(); + + if this.first_polled_at.is_none() { + this.first_polled_at = Some(Instant::now()); + } + + if this.data.is_empty() { + let _span = this.span.enter(); + let first_poll = this.first_polled_at.expect("initialized at first poll"); + tracing::debug!( + to_transmission_start_ms = first_poll.duration_since(this.created_at).as_millis(), + transmission_ms = first_poll.elapsed().as_millis(), + "finished streaming http request body" + ); + Poll::Ready(None) + } else { + // steals all the data and leaves 0 bytes in self + let chunk = std::mem::take(&mut this.data); + Poll::Ready(Some(Ok(chunk))) + } + } +} + +#[cfg(test)] +mod tests { + use {super::*, futures::FutureExt, tokio_stream::StreamExt}; + + #[test] + fn byte_stream_yields_bytes() { + let original = Bytes::from_iter(0..100); + let mut stream = ByteStream::new(original.clone()); + + let chunk = stream + .next() + .now_or_never() + .expect("stream is always ready"); + // stream always yields all the data on the first poll + assert_eq!(chunk.unwrap().unwrap(), original); + + let chunk = stream + .next() + .now_or_never() + .expect("stream is always ready"); + assert!(chunk.is_none()); + } +} diff --git a/crates/autopilot/src/infra/solvers/dto/mod.rs b/crates/autopilot/src/infra/solvers/dto/mod.rs index 5365700ce8..d3a156294c 100644 --- a/crates/autopilot/src/infra/solvers/dto/mod.rs +++ b/crates/autopilot/src/infra/solvers/dto/mod.rs @@ -1,7 +1,6 @@ //! Types for communicating with drivers as defined in //! `crates/driver/openapi.yml`. -pub mod notify; pub mod reveal; pub mod settle; pub mod solve; diff --git a/crates/autopilot/src/infra/solvers/dto/notify.rs b/crates/autopilot/src/infra/solvers/dto/notify.rs deleted file mode 100644 index 7a63a0bc4a..0000000000 --- a/crates/autopilot/src/infra/solvers/dto/notify.rs +++ /dev/null @@ -1,34 +0,0 @@ -use { - chrono::{DateTime, Utc}, - serde::Serialize, - serde_with::serde_as, -}; - -#[serde_as] -#[derive(Clone, Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub enum Request { - Banned { - reason: BanReason, - until: DateTime, - }, -} - -#[serde_as] -#[derive(Clone, Copy, Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub enum BanReason { - /// The driver won multiple consecutive auctions but never settled them. - UnsettledConsecutiveAuctions, - /// Driver's settle failure rate is above the threshold. - HighSettleFailureRate, -} - -impl BanReason { - pub fn as_str(&self) -> &'static str { - match self { - BanReason::UnsettledConsecutiveAuctions => "non_settling", - BanReason::HighSettleFailureRate => "high_settle_failure_rate", - } - } -} diff --git a/crates/autopilot/src/infra/solvers/dto/solve.rs b/crates/autopilot/src/infra/solvers/dto/solve.rs index 06e0fb549d..a1bdfc36f8 100644 --- a/crates/autopilot/src/infra/solvers/dto/solve.rs +++ b/crates/autopilot/src/infra/solvers/dto/solve.rs @@ -1,18 +1,26 @@ use { crate::{ boundary, - domain::{self, eth}, - infra::persistence::dto::{self, order::Order}, + domain, + infra::{ + persistence::dto::{self, order::Order}, + solvers::{InjectIntoHttpRequest, byte_stream::ByteStream}, + }, }, + alloy::primitives::{Address, U256}, + brotli::enc::writer::CompressorWriter, + bytes::Bytes, chrono::{DateTime, Utc}, + eth_domain_types as eth, itertools::Itertools, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, + reqwest::{RequestBuilder, header::HeaderValue}, serde::{Deserialize, Serialize}, serde_with::{DisplayFromStr, serde_as}, std::{ + borrow::Cow, collections::{HashMap, HashSet}, - sync::Arc, + io::Write, time::Duration, }, }; @@ -21,20 +29,20 @@ use { /// request. The purpose of this is to make it ergonomic /// to serialize a request once and reuse the resulting /// string in multiple HTTP requests. -#[derive(Clone, Debug, Serialize, derive_more::Display)] -pub struct Request(Arc); - -impl Request { - pub fn as_str(&self) -> &str { - self.0.get() - } +#[derive(Clone, Debug)] +pub struct Request { + auction_id: i64, + body: bytes::Bytes, + content_encoding: Option, + deadline: chrono::DateTime, } impl Request { - pub fn new( + pub async fn new( auction: &domain::Auction, - trusted_tokens: &HashSet, - time_limit: Duration, + trusted_tokens: &HashSet
, + deadline: chrono::DateTime, + compress: bool, ) -> Self { let _timer = observe::metrics::metrics().on_auction_overhead_start("autopilot", "serialize_request"); @@ -50,9 +58,9 @@ impl Request { .prices .iter() .map(|(address, price)| Token { - address: address.to_owned().into(), - price: Some(price.get().into()), - trusted: trusted_tokens.contains(&(address.0)), + address: *address.to_owned(), + price: Some(price.get().0), + trusted: trusted_tokens.contains(&Address::from(*address)), }) .chain(trusted_tokens.iter().map(|&address| Token { address, @@ -61,23 +69,108 @@ impl Request { })) .unique_by(|token| token.address) .collect(), - deadline: Utc::now() + chrono::Duration::from_std(time_limit).unwrap(), - surplus_capturing_jit_order_owners: auction - .surplus_capturing_jit_order_owners - .iter() - .map(|address| address.0) - .collect::>(), + deadline, + surplus_capturing_jit_order_owners: auction.surplus_capturing_jit_order_owners.to_vec(), }; - Self(Arc::from(serde_json::value::to_raw_value(&helper).expect( - "only fails with non-string keys which we do not have", - ))) + let auction_id = auction.id; + + let (body, content_encoding) = tokio::task::spawn_blocking(move || { + let serialized = serde_json::to_vec(&helper).expect("type should be JSON serializable"); + + if !compress { + return (Bytes::from(serialized), None); + } + + // quality 1: fastest brotli level. Already beats gzip-3 on both + // ratio and speed for our JSON payloads. + // + // lgwin 22: LZ77 window = 2^22 - 16 ≈ 4 MB. How far back the + // compressor looks for repeated patterns. The decompressor must + // allocate up to this much memory. Aligns with our current auction size + // (~3-4mb). + // + // 4096: internal I/O buffer for flushing to the output Vec. + // Doesn't affect compression ratio. Tested 512 B to 256 KB with + // no meaningful difference; 4 KB is a standard default. + let mut encoder = CompressorWriter::new(Vec::new(), 4096, 1, 22); + match encoder.write_all(&serialized).and_then(|_| encoder.flush()) { + Ok(()) => ( + Bytes::from(encoder.into_inner()), + Some(HeaderValue::from_static("br")), + ), + Err(err) => { + tracing::error!( + ?err, + "brotli compression failed, falling back to uncompressed" + ); + (Bytes::from(serialized), None) + } + } + }) + .await + .expect("inner task should not panic as serialization should work for the given type"); + + Self { + body, + auction_id, + content_encoding, + deadline, + } + } + + pub fn body_size(&self) -> usize { + self.body.len() + } + + pub fn time_until_deadline(&self) -> Duration { + self.deadline + .signed_duration_since(Utc::now()) + .to_std() + .unwrap_or(Duration::ZERO) + } +} + +impl InjectIntoHttpRequest for Request { + fn inject(&self, request: RequestBuilder) -> RequestBuilder { + let request = request + .body(reqwest::Body::wrap_stream(ByteStream::new( + self.body.clone(), + ))) + // announce which auction this request is for in the + // headers to help the driver detect duplicated + // `/solve` requests before streaming the body + .header("X-Auction-Id", self.auction_id) + // manually set the content type header for JSON since + // we can't use `request.json(self)` + .header( + reqwest::header::CONTENT_TYPE, + reqwest::header::HeaderValue::from_static("application/json"), + ); + if let Some(encoding) = &self.content_encoding { + request.header(reqwest::header::CONTENT_ENCODING, encoding) + } else { + request + } + } + + fn body_to_string(&self) -> Cow<'_, str> { + if self.content_encoding.is_some() { + return Cow::Borrowed(""); + } + let string = str::from_utf8(self.body.as_ref()).unwrap(); + Cow::Borrowed(string) } } impl Response { - pub fn into_domain( - self, - ) -> Vec> { + pub fn into_domain(self) -> Vec { + if self + .solutions + .iter() + .any(|solution| !solution.clearing_prices.is_empty()) + { + tracing::debug!("driver sent deprecated clearingPrices field"); + } self.solutions .into_iter() .map(Solution::into_domain) @@ -94,38 +187,29 @@ struct RequestHelper { pub tokens: Vec, pub orders: Vec, pub deadline: DateTime, - pub surplus_capturing_jit_order_owners: Vec, + pub surplus_capturing_jit_order_owners: Vec
, } #[serde_as] #[derive(Clone, Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Token { - pub address: H160, + pub address: Address, #[serde_as(as = "Option")] pub price: Option, pub trusted: bool, } impl Solution { - pub fn into_domain( - self, - ) -> Result { - Ok(domain::competition::Solution::new( + pub fn into_domain(self) -> domain::competition::Solution { + domain::competition::Solution::new( self.solution_id, - self.submission_address.into(), - domain::competition::Score::try_new(self.score.into())?, + self.submission_address, self.orders .into_iter() .map(|(o, amounts)| (o.into(), amounts.into_domain())) .collect(), - self.clearing_prices - .into_iter() - .map(|(token, price)| { - domain::auction::Price::try_new(price.into()).map(|price| (token.into(), price)) - }) - .collect::>()?, - )) + ) } } @@ -138,13 +222,13 @@ impl Solution { #[serde(rename_all = "camelCase")] pub struct TradedOrder { side: Side, - sell_token: H160, - buy_token: H160, - #[serde_as(as = "HexOrDecimalU256")] + sell_token: Address, + buy_token: Address, /// Sell limit order amount. - limit_sell: U256, #[serde_as(as = "HexOrDecimalU256")] + limit_sell: U256, /// Buy limit order amount. + #[serde_as(as = "HexOrDecimalU256")] limit_buy: U256, /// The effective amount that left the user's wallet including all fees. #[serde_as(as = "HexOrDecimalU256")] @@ -190,13 +274,16 @@ pub struct Solution { /// Unique ID of the solution (per driver competition), used to identify /// it in subsequent requests (reveal, settle). pub solution_id: u64, - #[serde_as(as = "HexOrDecimalU256")] - pub score: U256, /// Address used by the driver to submit the settlement onchain. - pub submission_address: H160, + pub submission_address: Address, pub orders: HashMap, + /// Deprecated: uniform clearing prices are no longer used by the + /// autopilot. Kept here purely so we can detect and log drivers that + /// still send them, in order to chase them down before the field is + /// removed entirely. + #[serde(default)] #[serde_as(as = "HashMap<_, HexOrDecimalU256>")] - pub clearing_prices: HashMap, + pub clearing_prices: HashMap, pub gas: Option, } @@ -205,3 +292,79 @@ pub struct Solution { pub struct Response { pub solutions: Vec, } + +#[cfg(test)] +mod tests { + use super::*; + + fn make_test_json() -> Vec { + let json_value = serde_json::json!({ + "id": "1", + "tokens": (0..100).map(|i| { + serde_json::json!({ + "address": format!("0x{:040x}", i), + "price": format!("{}", i * 1000), + "trusted": i % 2 == 0 + }) + }).collect::>(), + "orders": [], + "deadline": "2025-01-01T00:00:00Z", + "surplusCapturingJitOrderOwners": [] + }); + serde_json::to_vec(&json_value).unwrap() + } + + fn uncompressed_request(json: Vec) -> Request { + Request { + auction_id: 1, + body: Bytes::from(json), + content_encoding: None, + deadline: Utc::now(), + } + } + + fn compressed_request(json: &[u8]) -> Request { + use brotli::enc::writer::CompressorWriter; + + let mut encoder = CompressorWriter::new(Vec::new(), 4096, 1, 22); + encoder.write_all(json).unwrap(); + encoder.flush().unwrap(); + let compressed = encoder.into_inner(); + Request { + auction_id: 1, + body: Bytes::from(compressed), + content_encoding: Some(HeaderValue::from_static("br")), + deadline: Utc::now(), + } + } + + #[test] + fn compressed_request_round_trips() { + let json = make_test_json(); + + let request = compressed_request(&json); + assert_eq!( + request.content_encoding.as_ref().map(|v| v.as_bytes()), + Some("br".as_bytes()) + ); + assert!( + request.body.len() < json.len(), + "compressed body {} should be smaller than original {}", + request.body.len(), + json.len(), + ); + + let mut decompressed = Vec::new(); + brotli::BrotliDecompress(&mut request.body.as_ref(), &mut decompressed).unwrap(); + assert_eq!(decompressed, json); + } + + #[test] + fn uncompressed_request_preserves_json() { + let json = make_test_json(); + let request = uncompressed_request(json.clone()); + + assert_eq!(request.content_encoding, None); + assert_eq!(request.body.as_ref(), json.as_slice()); + } +} diff --git a/crates/autopilot/src/infra/solvers/mod.rs b/crates/autopilot/src/infra/solvers/mod.rs index 7cbc99e755..6efb9bfd4f 100644 --- a/crates/autopilot/src/infra/solvers/mod.rs +++ b/crates/autopilot/src/infra/solvers/mod.rs @@ -1,16 +1,19 @@ use { self::dto::{reveal, settle, solve}, - crate::{arguments::Account, domain::eth, infra::solvers::dto::notify, util}, + crate::util, + alloy::signers::{Signer, aws::AwsSigner}, anyhow::{Context, Result, anyhow}, - chrono::{DateTime, Utc}, - observe::tracing::tracing_headers, - reqwest::{Client, StatusCode}, - std::{sync::Arc, time::Duration}, + configs::autopilot::solver::Account, + eth_domain_types as eth, + observe::tracing::{distributed::headers::tracing_headers, lazy::Lazy}, + reqwest::{Client, RequestBuilder, StatusCode}, + std::{borrow::Cow, time::Duration}, thiserror::Error, tracing::instrument, url::Url, }; +mod byte_stream; pub mod dto; const RESPONSE_SIZE_LIMIT: usize = 10_000_000; @@ -19,12 +22,7 @@ const RESPONSE_TIME_LIMIT: Duration = Duration::from_secs(60); pub struct Driver { pub name: String, pub url: Url, - // An optional threshold used to check "fairness" of provided solutions. If specified, a - // winning solution should be discarded if it contains at least one order, which - // another driver solved with surplus exceeding this driver's surplus by `threshold` - pub fairness_threshold: Option, pub submission_address: eth::Address, - pub requested_timeout_on_problems: bool, client: Client, } @@ -41,42 +39,33 @@ impl Driver { pub async fn try_new( url: Url, name: String, - fairness_threshold: Option, submission_account: Account, - requested_timeout_on_problems: bool, ) -> Result { let submission_address = match submission_account { Account::Kms(key_id) => { - let config = ethcontract::aws_config::load_from_env().await; - let account = - ethcontract::transaction::kms::Account::new((&config).into(), &key_id.0) - .await - .map_err(|_| { - tracing::error!(?name, ?key_id, "Unable to load KMS account"); - Error::UnableToLoadKmsAccount - })?; - account.public_address() + let config = alloy::signers::aws::aws_config::load_from_env().await; + let client = alloy::signers::aws::aws_sdk_kms::Client::new(&config); + let account = AwsSigner::new(client, key_id.0.clone(), None) + .await + .map_err(|_| { + tracing::error!(?name, ?key_id, "Unable to load KMS account"); + Error::UnableToLoadKmsAccount + })?; + account.address() } Account::Address(address) => address, }; - tracing::info!( - ?name, - ?url, - ?fairness_threshold, - ?submission_address, - "Creating solver" - ); + tracing::info!(?name, ?url, ?submission_address, "Creating solver"); Ok(Self { name, url, - fairness_threshold, client: Client::builder() .timeout(RESPONSE_TIME_LIMIT) + .tcp_keepalive(Duration::from_secs(60)) .build() .map_err(Error::FailedToBuildClient)?, - submission_address: submission_address.into(), - requested_timeout_on_problems, + submission_address, }) } @@ -121,37 +110,27 @@ impl Driver { Ok(()) } - pub async fn notify(&self, request: notify::Request) -> Result<()> { - self.request_response("notify", request).await - } - async fn request_response( &self, path: &str, - request: Request, + payload: Request, ) -> Result where Response: serde::de::DeserializeOwned, - Request: serde::Serialize + Send + Sync + 'static, + Request: InjectIntoHttpRequest, { let url = util::join(&self.url, path); + tracing::trace!( - path=&url.path(), - body=%serde_json::to_string_pretty(&request).unwrap(), + path = &url.path(), + body = %Lazy(|| payload.body_to_string()), "solver request", ); - let mut request = { - let builder = self.client.post(url.clone()).headers(tracing_headers()); - // If the payload is very big then serializing it will block the - // executor a long time (mostly relevant for solve requests). - // That's why we always do it on a thread specifically for - // running blocking tasks. - tokio::task::spawn_blocking(move || builder.json(&request)) - .await - .context("failed to build request")? - }; - if let Some(request_id) = observe::distributed_tracing::request_id::from_current_span() { + let request = self.client.post(url.clone()).headers(tracing_headers()); + let mut request = payload.inject(request); + + if let Some(request_id) = observe::tracing::distributed::request_id::from_current_span() { request = request.header("X-REQUEST-ID", request_id); } @@ -188,17 +167,21 @@ pub async fn response_body_with_size_limit( Ok(bytes) } -/// Notifies the non-settling driver in a fire-and-forget manner. -pub fn notify_banned_solver( - non_settling_driver: Arc, - reason: notify::BanReason, - banned_until: DateTime, -) { - let request = notify::Request::Banned { - reason, - until: banned_until, - }; - tokio::spawn(async move { - let _ = non_settling_driver.notify(request).await; - }); +trait InjectIntoHttpRequest { + fn inject(&self, request: RequestBuilder) -> RequestBuilder; + fn body_to_string(&self) -> Cow<'_, str>; +} + +impl InjectIntoHttpRequest for T +where + T: serde::ser::Serialize + Sized, +{ + fn inject(&self, request: RequestBuilder) -> RequestBuilder { + request.json(&self) + } + + fn body_to_string(&self) -> Cow<'_, str> { + let serialized = serde_json::to_string(&self).expect("type should be JSON serializable"); + Cow::Owned(serialized) + } } diff --git a/crates/autopilot/src/leader_lock_tracker.rs b/crates/autopilot/src/leader_lock_tracker.rs index 6bea9a6d3a..5c0458dfb9 100644 --- a/crates/autopilot/src/leader_lock_tracker.rs +++ b/crates/autopilot/src/leader_lock_tracker.rs @@ -2,7 +2,6 @@ use {database::leader_pg_lock::LeaderLock, observe::metrics}; /// Tracks the autopilot leader lock status. /// Leader lock status is tracked based on calls to try_acquire() -#[expect(clippy::large_enum_variant)] pub enum LeaderLockTracker { /// Leader lock mechanism is disabled. /// Only one autopilot instance should be running at all times. diff --git a/crates/autopilot/src/lib.rs b/crates/autopilot/src/lib.rs index a7742f2cb0..fad6e62fab 100644 --- a/crates/autopilot/src/lib.rs +++ b/crates/autopilot/src/lib.rs @@ -1,3 +1,5 @@ +#![recursion_limit = "160"] + pub mod arguments; pub mod boundary; pub mod database; diff --git a/crates/autopilot/src/main.rs b/crates/autopilot/src/main.rs index d3b40b5970..4597f2b554 100644 --- a/crates/autopilot/src/main.rs +++ b/crates/autopilot/src/main.rs @@ -1,6 +1,11 @@ +#[cfg(feature = "mimalloc-allocator")] #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +#[cfg(not(feature = "mimalloc-allocator"))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + #[tokio::main] async fn main() { autopilot::start(std::env::args()).await; diff --git a/crates/autopilot/src/maintenance.rs b/crates/autopilot/src/maintenance.rs index e23a042de5..4ba4148b04 100644 --- a/crates/autopilot/src/maintenance.rs +++ b/crates/autopilot/src/maintenance.rs @@ -3,90 +3,253 @@ use { boundary::events::settlement::{GPv2SettlementContract, Indexer}, database::{ Postgres, + ethflow_events::event_retriever::EthFlowRefundRetriever, onchain_order_events::{ OnchainOrderParser, ethflow_events::{EthFlowData, EthFlowDataForDb}, event_retriever::CoWSwapOnchainOrdersContract, }, }, + domain::settlement, event_updater::EventUpdater, }, anyhow::Result, ethrpc::block_stream::{BlockInfo, CurrentBlockWatcher, into_stream}, - futures::StreamExt, + event_indexing::maintenance::Maintaining, + futures::{FutureExt, StreamExt}, prometheus::{ HistogramVec, IntCounterVec, core::{AtomicU64, GenericGauge}, }, - shared::{event_handling::AlloyEventRetriever, maintenance::Maintaining}, - std::{future::Future, sync::Arc, time::Instant}, - tokio::sync::Mutex, + std::{ + future::Future, + sync::Arc, + time::{Duration, Instant}, + }, + tokio::sync::watch, + tokio_stream::wrappers::WatchStream, + tracing::{Instrument, instrument}, }; +/// Component to sync with the maintenance logic that runs in a background task. +/// This allows us to run the maintenance logic as soon as we see a new block +/// while still making the autopilot run loop only wait for updates that are +/// essential for building new auctions. +#[derive(Clone)] +pub struct MaintenanceSync { + /// How long the autopilot wants to wait at most. + timeout: Duration, + /// This is the last block where essential processing like indexing events + /// was completed. + partially_processed_block: watch::Receiver, + /// This is the last block that has been fully processed. + fully_processed_block: watch::Receiver, +} + +pub enum SyncTarget { + /// Essential processing (e.g. event indexing) of the given block is + /// sufficient, + PartiallyProcessed(u64), + /// The given block as to be fully processed. + FullyProcessed(u64), +} + +impl MaintenanceSync { + #[instrument(skip_all)] + pub async fn wait_until_block_processed(&self, target: SyncTarget) { + let _timer = observe::metrics::metrics() + .on_auction_overhead_start("autopilot", "wait_for_maintenance"); + + if let Err(_timeout) = tokio::time::timeout(self.timeout, self.wait_inner(target)).await { + tracing::debug!("timed out waiting for maintenance"); + } + } + + async fn wait_inner(&self, target: SyncTarget) { + let (relevant_updates, target_block) = match target { + SyncTarget::FullyProcessed(block) => (&self.fully_processed_block, block), + SyncTarget::PartiallyProcessed(block) => (&self.partially_processed_block, block), + }; + + if *relevant_updates.borrow() >= target_block { + return; + } + + let mut stream = WatchStream::new(relevant_updates.clone()); + loop { + let processed_block = stream.next().await.unwrap(); + if processed_block >= target_block { + return; + } + } + } +} + /// Coordinates all the updates that need to run a new block /// to ensure a consistent view of the system. pub struct Maintenance { /// Indexes and persists all events emited by the settlement contract. - settlement_indexer: EventUpdater>, + settlement_indexer: EventUpdater, /// Used for periodic cleanup tasks to not have the DB overflow with old /// data. db_cleanup: Postgres, /// All indexing tasks to keep cow amms up to date. cow_amm_indexer: Vec>, - /// On which block we last ran an update successfully. - last_processed: Mutex, + /// Tasks to index ethflow orders that were submitted onchain. + ethflow_order_indexer: Vec, + /// Tasks to index ethflow refunds. + ethflow_refund_indexer: Vec, + /// Component to correctly attribute a settlement to a proposed solution. + settlement_observer: settlement::Observer, } impl Maintenance { pub fn new( - settlement_indexer: EventUpdater>, + settlement_indexer: EventUpdater, db_cleanup: Postgres, + settlement_observer: settlement::Observer, ) -> Self { Self { settlement_indexer, db_cleanup, cow_amm_indexer: Default::default(), - last_processed: Default::default(), + ethflow_order_indexer: Default::default(), + ethflow_refund_indexer: Default::default(), + settlement_observer, } } - /// Runs all update tasks in a coordinated manner to ensure the system - /// has a consistent state. - pub async fn update(&self, new_block: &BlockInfo) { - let mut last_block = self.last_processed.lock().await; - metrics().last_seen_block.set(new_block.number); - if last_block.number > new_block.number || last_block.hash == new_block.hash { - // `new_block` is neither newer than `last_block` nor a reorg - return; + /// Spawns a background task continously processing the latest block. + /// Returns a `[MaintenanceSync]` that handles waiting for a specific + /// block to be processed. + pub fn spawn_maintenance_task( + self, + blocks: CurrentBlockWatcher, + timeout: Duration, + ) -> MaintenanceSync { + let (full_tx, full_rx) = watch::channel(blocks.borrow().number); + let (partial_tx, partial_rx) = watch::channel(blocks.borrow().number); + + tokio::task::spawn(async move { + let mut stream = into_stream(blocks); + loop { + let block = stream + .next() + .await + .expect("block stream terminated unexpectedly"); + self.index_until_block(block, &partial_tx, &full_tx) + .instrument(tracing::info_span!( + "autopilot_maintenance", + block = block.number + )) + .await; + } + }); + + MaintenanceSync { + partially_processed_block: partial_rx, + fully_processed_block: full_rx, + timeout, } + } + async fn index_until_block( + &self, + block: BlockInfo, + partially_processed_block: &watch::Sender, + fully_processed_block: &watch::Sender, + ) { + metrics().last_seen_block.set(block.number); let start = Instant::now(); - if let Err(err) = self.update_inner().await { - tracing::warn!(?err, block = new_block.number, "failed to run maintenance"); + + if let Err(err) = self.run_essential_maintenance().await { + tracing::warn!(?err, "failed to run essential maintenance"); metrics().updates.with_label_values(&["error"]).inc(); return; } + tracing::info!( - block = new_block.number, time = ?start.elapsed(), - "successfully ran maintenance task" + "successfully ran essential maintenance tasks" ); - + metrics().last_updated_block.set(block.number); metrics().updates.with_label_values(&["success"]).inc(); - metrics().last_updated_block.set(new_block.number); - *last_block = *new_block; + if let Err(err) = partially_processed_block.send(block.number) { + tracing::warn!( + ?err, + "nobody listening for partially processed blocks anymore" + ); + } + + // only after we informed the run_loop that the essential updates are done we + // kick off the optional maintenance tasks + let start = Instant::now(); + if let Err(err) = self.run_optional_maintenance().await { + tracing::warn!(?err, "failed to run optional maintenance"); + return; + } + if let Err(err) = fully_processed_block.send(block.number) { + tracing::warn!(?err, "nobody listening for fully processed blocks anymore"); + } + tracing::info!( + time = ?start.elapsed(), + "successfully ran optional maintenance tasks" + ); } - async fn update_inner(&self) -> Result<()> { - let _timer = - observe::metrics::metrics().on_auction_overhead_start("autopilot", "maintenance_total"); + /// Runs all the maintenance tasks that are needed to ensure the next + /// auction gets built using the most up-to-date information. + async fn run_essential_maintenance(&self) -> Result<()> { + let _timer = observe::metrics::metrics() + .on_auction_overhead_start("autopilot", "maintenance_essential"); tokio::try_join!( Self::timed_future( "settlement_indexer", self.settlement_indexer.run_maintenance() ), - Self::timed_future("db_cleanup", self.db_cleanup.run_maintenance()), + Self::timed_future( + "cow_amm_indexer", + futures::future::try_join_all( + self.cow_amm_indexer + .iter() + .map(|indexer| indexer.run_maintenance()), + ), + ), + Self::timed_future( + "ethflow_order_indexer", + futures::future::try_join_all( + self.ethflow_order_indexer + .iter() + .map(|indexer| indexer.run_maintenance()), + ), + ), + )?; + + Ok(()) + } + + /// Runs all the maintenance tasks that should run eventually but are not + /// very time sensitive. + async fn run_optional_maintenance(&self) -> Result<()> { + let _timer = observe::metrics::metrics() + .on_auction_overhead_start("autopilot", "maintenance_optional"); + tokio::try_join!( + Self::timed_future("db_cleanup", self.db_cleanup.remove_expired_quotes()), + Self::timed_future( + "ethflow_refund_indexer", + futures::future::try_join_all( + self.ethflow_refund_indexer + .iter() + .map(|indexer| indexer.run_maintenance()), + ), + ), + Self::timed_future( + "settlement_attribution", + self.settlement_observer + .post_process_outstanding_settlement_transactions() + .map(|_| Ok(())) + ) )?; Ok(()) @@ -94,18 +257,20 @@ impl Maintenance { /// Registers all maintenance tasks that are necessary to correctly support /// ethflow orders. - pub fn spawn_ethflow_indexer(&mut self, ethflow_indexer: EthflowIndexer) { - tokio::task::spawn(async move { - loop { - let _ = - Self::timed_future("ethflow_indexer", ethflow_indexer.run_maintenance()).await; - tokio::time::sleep(std::time::Duration::from_millis(1_000)).await; - } - }); + pub fn add_ethflow_indexing( + &mut self, + order_indexer: EthflowOrderIndexer, + refund_indexer: EthflowRefundIndexer, + ) { + self.ethflow_order_indexer.push(order_indexer); + self.ethflow_refund_indexer.push(refund_indexer); } - pub fn with_cow_amms(&mut self, registry: &cow_amm::Registry) { - self.cow_amm_indexer = registry.maintenance_tasks().clone(); + /// Registers all maintenance tasks that are necessary to correctly support + /// CoW AMMs. + pub fn add_cow_amm_indexer(&mut self, registry: &cow_amm::Registry) { + self.cow_amm_indexer + .extend(registry.maintenance_tasks().clone()); } /// Runs the future and collects runtime metrics. @@ -117,43 +282,12 @@ impl Maintenance { let _timer2 = observe::metrics::metrics().on_auction_overhead_start("autopilot", label); fut.await } - - /// Spawns a background task that runs on every new block but also - /// at least after every `update_interval`. - pub fn spawn_cow_amm_indexing_task(self_: Arc, current_block: CurrentBlockWatcher) { - tokio::task::spawn(async move { - let mut stream = into_stream(current_block); - loop { - let _ = match stream.next().await { - Some(block) => { - metrics().last_seen_block.set(block.number); - block - } - None => panic!("block stream terminated unexpectedly"), - }; - - // TODO: move this back into `Self::update_inner()` once we - // store cow amms in the DB to avoid incredibly slow restarts. - let _ = Self::timed_future( - "cow_amm_indexer", - futures::future::try_join_all( - self_ - .cow_amm_indexer - .iter() - .cloned() - .map(|indexer| async move { indexer.run_maintenance().await }), - ), - ) - .await; - } - }); - } } -type EthflowIndexer = EventUpdater< - OnchainOrderParser, - AlloyEventRetriever, ->; +type EthflowOrderIndexer = + EventUpdater, CoWSwapOnchainOrdersContract>; + +type EthflowRefundIndexer = EventUpdater; #[derive(prometheus_metric_storage::MetricStorage)] #[metric(subsystem = "autopilot_maintenance")] diff --git a/crates/autopilot/src/periodic_db_cleanup.rs b/crates/autopilot/src/periodic_db_cleanup.rs index a2c76b86ea..f6810f9ed3 100644 --- a/crates/autopilot/src/periodic_db_cleanup.rs +++ b/crates/autopilot/src/periodic_db_cleanup.rs @@ -93,6 +93,7 @@ mod tests { order_uid: ByteArray([1; 56]), timestamp: now - chrono::Duration::milliseconds(300), label: OrderEventLabel::Created, + reason: None, }; database::order_events::insert_order_event(&mut ex, &event_a) .await @@ -101,6 +102,7 @@ mod tests { order_uid: ByteArray([2; 56]), timestamp: now - chrono::Duration::milliseconds(100), label: OrderEventLabel::Created, + reason: None, }; database::order_events::insert_order_event(&mut ex, &event_b) .await @@ -109,6 +111,7 @@ mod tests { order_uid: ByteArray([3; 56]), timestamp: now, label: OrderEventLabel::Created, + reason: None, }; database::order_events::insert_order_event(&mut ex, &event_c) .await diff --git a/crates/autopilot/src/run.rs b/crates/autopilot/src/run.rs index e59bd23a98..2960fe2287 100644 --- a/crates/autopilot/src/run.rs +++ b/crates/autopilot/src/run.rs @@ -1,6 +1,6 @@ use { crate::{ - arguments::{Account, Arguments}, + arguments::CliArguments, boundary, database::{ Postgres, @@ -15,7 +15,7 @@ use { event_retriever::CoWSwapOnchainOrdersContract, }, }, - domain::{self, competition::SolverParticipationGuard}, + domain, event_updater::EventUpdater, infra, maintenance::Maintenance, @@ -24,46 +24,33 @@ use { shutdown_controller::ShutdownController, solvable_orders::SolvableOrdersCache, }, - alloy::eips::BlockNumberOrTag, + account_balances::{self, BalanceSimulator}, + alloy::{eips::BlockNumberOrTag, primitives::Address, providers::Provider}, + bad_tokens::list_based::DenyListedTokens, chain::Chain, clap::Parser, - contracts::alloy::{BalancerV2Vault, GPv2Settlement, IUniswapV3Factory, InstanceExt, WETH9}, - ethcontract::H160, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::block_number_to_block_number_hash, - }, - futures::StreamExt, + configs::autopilot::{Configuration, solver::Account}, + contracts::{BalancerV2Vault, GPv2Settlement, WETH9}, + ethrpc::{Web3, block_stream::block_number_to_block_number_hash}, + event_indexing::block_retriever::BlockRetriever, + http_client::HttpClientFactory, model::DomainSeparator, num::ToPrimitive, - observe::metrics::LivenessChecking, + observe::{config::EventBusConfig, metrics::LivenessChecking}, + price_estimation::{ + config::price_estimation::BalanceOverridesConfigExt, + factory::{self, PriceEstimatorFactory}, + native::NativePriceEstimating, + }, shared::{ - account_balances::{self, BalanceSimulator}, - arguments::tracing_config, - bad_token::{ - cache::CachingDetector, - instrumented::InstrumentedBadTokenDetectorExt, - list_based::{ListBasedDetector, UnknownTokenStrategy}, - token_owner_finder, - trace_call::TraceCallDetector, - }, - baseline_solver::BaseTokens, - code_fetching::CachedCodeFetcher, - event_handling::AlloyEventRetriever, - http_client::HttpClientFactory, - maintenance::ServiceMaintenance, order_quoting::{self, OrderQuoter}, - price_estimation::factory::{self, PriceEstimatorFactory}, - signature_validator, - sources::{BaselineSource, uniswap_v2::UniV2BaselineSourceParameters}, - token_info::{CachedTokenInfoFetcher, TokenInfoFetcher}, token_list::{AutoUpdatingTokenList, TokenListConfiguration}, }, std::{ sync::{Arc, RwLock, atomic::AtomicBool}, time::{Duration, Instant}, }, + token_info::{CachedTokenInfoFetcher, TokenInfoFetcher}, tracing::{Instrument, info_span, instrument}, url::Url, }; @@ -97,7 +84,7 @@ impl Liveness { /// Creates Web3 transport based on the given config. #[instrument(skip_all)] -async fn ethrpc(url: &Url, ethrpc_args: &shared::ethrpc::Arguments) -> infra::blockchain::Rpc { +async fn ethrpc(url: &Url, ethrpc_args: &shared::web3::Arguments) -> infra::blockchain::Rpc { infra::blockchain::Rpc::new(url, ethrpc_args) .await .expect("connect ethereum RPC") @@ -107,7 +94,7 @@ async fn ethrpc(url: &Url, ethrpc_args: &shared::ethrpc::Arguments) -> infra::bl async fn unbuffered_ethrpc(url: &Url) -> infra::blockchain::Rpc { ethrpc( url, - &shared::ethrpc::Arguments { + &shared::web3::Arguments { ethrpc_max_batch_size: 0, ethrpc_max_concurrent_requests: 0, ethrpc_batch_delay: Default::default(), @@ -137,102 +124,122 @@ async fn ethereum( } pub async fn start(args: impl Iterator) { - let args = Arguments::parse_from(args); + let args = CliArguments::parse_from(args); + + let config = Configuration::from_path(&args.config) + .await + .expect("failed to load configuration file") + .validate() + .expect("failed to validate configuration file"); + + let tracing_config = config + .shared + .tracing + .collector_endpoint + .as_ref() + .map(|endpoint| { + observe::TracingConfig::new( + endpoint.clone(), + "autopilot".into(), + config.shared.tracing.exporter_timeout, + config.shared.tracing.level, + ) + }); let obs_config = observe::Config::new( - args.shared.logging.log_filter.as_str(), - args.shared.logging.log_stderr_threshold, - args.shared.logging.use_json_logs, - tracing_config(&args.shared.tracing, "autopilot".into()), + config.shared.logging.filter.as_str(), + config.shared.logging.stderr_threshold, + config.shared.logging.use_json, + tracing_config, ); - observe::tracing::initialize(&obs_config); + observe::tracing::init::initialize(&obs_config); observe::panic_hook::install(); + if let Some(event_bus) = &config.shared.event_bus { + observe::event_bus::init(EventBusConfig { + url: event_bus.url.clone(), + stream_name: event_bus.channel.clone(), + // Presence of `chain-id` alongside `event_bus` is enforced by + // `SharedConfig::validate` at startup. + chain_id: config.shared.chain_id.unwrap(), + }) + .await; + } + #[cfg(unix)] + observe::heap_dump_handler::spawn_heap_dump_handler(); let commit_hash = option_env!("VERGEN_GIT_SHA").unwrap_or("COMMIT_INFO_NOT_FOUND"); tracing::info!(%commit_hash, "running autopilot with validated arguments:\n{}", args); + tracing::info!("file configuration:\n{:#?}", config); observe::metrics::setup_registry(Some("gp_v2_autopilot".into()), None); - if args.drivers.is_empty() { - panic!("colocation is enabled but no drivers are configured"); - } - - if args.shadow.is_some() { - shadow_mode(args).await; + if config.shadow.is_some() { + shadow_mode(config).await; } else { - run(args, ShutdownController::default()).await; + run(config, ShutdownController::default()).await; } } /// Assumes tracing and metrics registry have already been set up. -pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { - assert!(args.shadow.is_none(), "cannot run in shadow mode"); - let db_write = Postgres::new(args.db_write_url.as_str(), args.insert_batch_size) - .await - .unwrap(); - - let db_read = if let Some(db_read_url) = args.db_read_url - && args.db_write_url != db_read_url - { - Postgres::new(db_read_url.as_str(), args.insert_batch_size) - .await - .expect("failed to create read replica database") - } else { - db_write.clone() - }; +pub async fn run(config: Configuration, shutdown_controller: ShutdownController) { + assert!(config.shadow.is_none(), "cannot run in shadow mode"); + let db_write = Postgres::new( + config.database.write_url.as_str(), + crate::database::Config { + insert_batch_size: config.database.insert_batch_size, + max_pool_size: config.database.max_connections, + }, + ) + .await + .unwrap(); - crate::database::run_database_metrics_work(db_read.clone()); + // If the DB is in read-only mode, running ANALYZE is not possible and will + // trigger and error https://www.postgresql.org/docs/current/hot-standby.html + crate::database::run_database_metrics_work(db_write.clone()); - let http_factory = HttpClientFactory::new(&args.http_client); - let web3 = shared::ethrpc::web3( - &args.shared.ethrpc, - &http_factory, - &args.shared.node_url, - "base", - ); - let simulation_web3 = args.shared.simulation_node_url.as_ref().map(|node_url| { - shared::ethrpc::web3(&args.shared.ethrpc, &http_factory, node_url, "simulation") - }); + let http_factory = HttpClientFactory::from(config.http_client); + let ethrpc_args = shared::web3::Arguments::from(&config.shared.ethrpc); + let web3 = shared::web3::web3(ðrpc_args, &config.shared.node_url, "base"); + let simulation_web3 = config + .shared + .simulation_node_url + .as_ref() + .map(|node_url| shared::web3::web3(ðrpc_args, node_url, "simulation")); let chain_id = web3 - .eth() - .chain_id() + .provider + .get_chain_id() .instrument(info_span!("chain_id")) .await - .expect("Could not get chainId") - .as_u64(); - if let Some(expected_chain_id) = args.shared.chain_id { + .expect("Could not get chainId"); + if let Some(expected_chain_id) = config.shared.chain_id { assert_eq!( chain_id, expected_chain_id, "connected to node with incorrect chain ID", ); } - let unbuffered_ethrpc = unbuffered_ethrpc(&args.shared.node_url).await; - let ethrpc = ethrpc(&args.shared.node_url, &args.shared.ethrpc).await; + let unbuffered_ethrpc = unbuffered_ethrpc(&config.shared.node_url).await; + let ethrpc = ethrpc(&config.shared.node_url, ðrpc_args).await; let chain = ethrpc.chain(); let web3 = ethrpc.web3().clone(); let url = ethrpc.url().clone(); let contracts = infra::blockchain::contracts::Addresses { - settlement: args.shared.settlement_contract_address, - signatures: args.shared.signatures_contract_address, - weth: args - .shared - .native_token_address - .map(IntoLegacy::into_legacy), - balances: args - .shared - .balances_contract_address - .map(IntoLegacy::into_legacy), - trampoline: args.shared.hooks_contract_address, + settlement: config.shared.contracts.settlement, + signatures: config.shared.contracts.signatures, + weth: config.shared.contracts.native_token, + balances: config.shared.contracts.balances, + trampoline: config.shared.contracts.hooks, + flashloan_router: config.shared.contracts.flashloan_router, }; + let current_block_args = shared::current_block::Arguments::from(&config.shared.current_block); let eth = ethereum( web3.clone(), unbuffered_ethrpc.web3().clone(), &chain, url, contracts.clone(), - &args.shared.current_block, + ¤t_block_args, ) .await; @@ -242,10 +249,9 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { .vaultRelayer() .call() .await - .expect("Couldn't get vault relayer address") - .into_legacy(); + .expect("Couldn't get vault relayer address"); - let vault_address = args.shared.balancer_v2_vault_address.or_else(|| { + let vault_address = config.shared.contracts.balancer_v2_vault.or_else(|| { let chain_id = chain.id(); let addr = BalancerV2Vault::deployment_address(&chain_id); if addr.is_none() { @@ -256,27 +262,10 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { } addr }); - let vault = - vault_address.map(|address| BalancerV2Vault::Instance::new(address, web3.alloy.clone())); - - let uniswapv3_factory = IUniswapV3Factory::Instance::deployed(&web3.alloy) - .instrument(info_span!("uniswapv3_deployed")) - .await - .inspect_err(|err| tracing::warn!(%err, "error while fetching IUniswapV3Factory instance")) - .ok(); let chain = Chain::try_from(chain_id).expect("incorrect chain ID"); - let balance_overrider = args.price_estimation.balance_overrides.init(web3.clone()); - let signature_validator = signature_validator::validator( - &web3, - signature_validator::Contracts { - settlement: eth.contracts().settlement().clone(), - signatures: eth.contracts().signatures().clone(), - vault_relayer, - }, - balance_overrider.clone(), - ); + let balance_overrider = config.price_estimation.balance_overrides.init(web3.clone()); let balance_fetcher = account_balances::cached( &web3, @@ -284,160 +273,133 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { eth.contracts().settlement().clone(), eth.contracts().balances().clone(), vault_relayer, - vault_address.map(IntoLegacy::into_legacy), + vault_address, balance_overrider, ), eth.current_block().clone(), ); + let gas_estimators: Vec = config + .shared + .gas_estimators + .iter() + .map(shared::arguments::gas_estimator_type_from_config) + .collect(); let gas_price_estimator = Arc::new( - shared::gas_price_estimation::create_priority_estimator( - &http_factory, + gas_price_estimation::create_priority_estimator( + http_factory.create(), &web3, - args.shared.gas_estimators.as_slice(), + &gas_estimators, ) .await .expect("failed to create gas price estimator"), ); - let baseline_sources = args - .shared - .baseline_sources - .clone() - .unwrap_or_else(|| shared::sources::defaults_for_network(&chain)); - tracing::info!(?baseline_sources, "using baseline sources"); - let univ2_sources = baseline_sources - .iter() - .filter_map(|source: &BaselineSource| { - UniV2BaselineSourceParameters::from_baseline_source(*source, &chain_id.to_string()) - }) - .chain(args.shared.custom_univ2_baseline_sources.iter().copied()); - let pair_providers: Vec<_> = futures::stream::iter(univ2_sources) - .then(|source: UniV2BaselineSourceParameters| { - let web3 = &web3; - async move { source.into_source(web3).await.unwrap().pair_provider } - }) - .collect() - .instrument(info_span!("pair_providers")) - .await; - - let base_tokens = Arc::new(BaseTokens::new( - eth.contracts().weth().address().into_legacy(), - &args.shared.base_tokens, - )); - let mut allowed_tokens = args.allowed_tokens.clone(); - allowed_tokens.extend(base_tokens.tokens().iter().map(|t| t.into_alloy())); - allowed_tokens.push(model::order::BUY_ETH_ADDRESS.into_alloy()); - let unsupported_tokens = args.unsupported_tokens.clone(); - - let finder = token_owner_finder::init( - &args.token_owner_finder, - web3.clone(), - &chain, - &http_factory, - &pair_providers, - vault.as_ref(), - uniswapv3_factory.as_ref(), - &base_tokens, - eth.contracts().settlement().address().into_legacy(), - ) - .instrument(info_span!("token_owner_finder_init")) - .await - .expect("failed to initialize token owner finders"); - - let trace_call_detector = args.tracing_node_url.as_ref().map(|tracing_node_url| { - CachingDetector::new( - Box::new(TraceCallDetector::new( - shared::ethrpc::web3( - &args.shared.ethrpc, - &http_factory, - tracing_node_url, - "trace", - ), - eth.contracts().settlement().address().into_legacy(), - finder, - )), - args.shared.token_quality_cache_expiry, - args.shared.token_quality_cache_prefetch_time, - ) - }); - let bad_token_detector = Arc::new( - ListBasedDetector::new( - allowed_tokens, - unsupported_tokens, - trace_call_detector - .map(|detector| UnknownTokenStrategy::Forward(detector)) - .unwrap_or(UnknownTokenStrategy::Allow), - ) - .instrumented(), - ); + let deny_listed_tokens = DenyListedTokens::new(config.unsupported_tokens.clone()); let token_info_fetcher = Arc::new(CachedTokenInfoFetcher::new(Arc::new(TokenInfoFetcher { web3: web3.clone(), }))); - let block_retriever = Arc::new(web3.alloy.clone()); - - let code_fetcher = Arc::new(CachedCodeFetcher::new(Arc::new(web3.clone()))); + let block_retriever = Arc::new(BlockRetriever { + provider: web3.provider.clone(), + block_stream: eth.current_block().clone(), + }); let mut price_estimator_factory = PriceEstimatorFactory::new( - &args.price_estimation, - &args.shared, + &config.price_estimation, + &config.native_price_estimation.shared, factory::Network { web3: web3.clone(), simulation_web3, chain, - settlement: eth.contracts().settlement().address().into_legacy(), - native_token: eth.contracts().weth().address().into_legacy(), + settlement: *eth.contracts().settlement().address(), + native_token: *eth.contracts().weth().address(), authenticator: eth .contracts() .settlement() .authenticator() .call() .await - .expect("failed to query solver authenticator address") - .into_legacy(), - base_tokens: base_tokens.clone(), + .expect("failed to query solver authenticator address"), block_stream: eth.current_block().clone(), + flash_loan_router: eth.contracts().flashloan_router(), + hooks_trampoline: *eth.contracts().trampoline().address(), }, factory::Components { - http_factory: http_factory.clone(), - bad_token_detector: bad_token_detector.clone(), + http_factory: http_client::HttpClientFactory::new(&configs::http_client::HttpClient { + timeout: http_factory.timeout, + }), + deny_listed_tokens: deny_listed_tokens.clone(), tokens: token_info_fetcher.clone(), - code_fetcher: code_fetcher.clone(), }, ) .instrument(info_span!("price_estimator_factory")) .await .expect("failed to initialize price estimator factory"); - let native_price_estimator = price_estimator_factory - .native_price_estimator( - args.native_price_estimators.as_slice(), - args.native_price_estimation_results_required, - eth.contracts().weth().clone(), - ) - .instrument(info_span!("native_price_estimator")) - .await - .unwrap(); + let weth = eth.contracts().weth().clone(); let prices = db_write.fetch_latest_prices().await.unwrap(); - native_price_estimator.initialize_cache(prices); + let shared_cache = price_estimation::native_price_cache::Cache::new( + config.native_price_estimation.shared.cache.max_age, + prices, + ); + let api_sources = config + .native_price_estimation + .api_estimators + .as_ref() + .unwrap_or(&config.native_price_estimation.estimators); + let api_native_price_estimator: Arc = Arc::new( + price_estimator_factory + .caching_native_price_estimator( + api_sources.as_slice(), + config.native_price_estimation.shared.results_required, + &weth, + shared_cache.clone(), + config.native_price_estimation.eip4626, + ) + .instrument(info_span!("api_native_price_estimator")) + .await, + ); + + let competition_native_price_updater = { + let caching = price_estimator_factory + .caching_native_price_estimator( + config.native_price_estimation.estimators.as_slice(), + config.native_price_estimation.shared.results_required, + &weth, + shared_cache.clone(), + config.native_price_estimation.eip4626, + ) + .instrument(info_span!("competition_native_price_updater")) + .await; + price_estimation::native_price_cache::NativePriceUpdater::new( + caching, + config.native_price_estimation.cache_refresh_interval, + config.native_price_estimation.prefetch_time, + ) + }; let price_estimator = price_estimator_factory .price_estimator( - &args + &config .order_quoting .price_estimation_drivers .iter() - .map(|price_estimator_driver| price_estimator_driver.clone().into()) + .map( + |price_estimator_driver| configs::native_price_estimators::ExternalSolver { + name: price_estimator_driver.name.clone(), + url: price_estimator_driver.url.clone(), + }, + ) .collect::>(), - native_price_estimator.clone(), + api_native_price_estimator.clone(), gas_price_estimator.clone(), ) .unwrap(); - let skip_event_sync_start = if args.skip_event_sync { + let skip_event_sync_start = if config.ethflow.skip_event_sync { Some( - block_number_to_block_number_hash(&web3.alloy, BlockNumberOrTag::Latest) + block_number_to_block_number_hash(&web3.provider, BlockNumberOrTag::Latest) .await .expect("Failed to fetch latest block"), ) @@ -445,15 +407,10 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { None }; - let (competition_updates_sender, competition_updates_receiver) = - tokio::sync::mpsc::unbounded_channel(); - let persistence = - infra::persistence::Persistence::new(args.s3.into().unwrap(), Arc::new(db_write.clone())) + infra::persistence::Persistence::new(config.s3.map(Into::into), Arc::new(db_write.clone())) .instrument(info_span!("persistence_init")) .await; - let settlement_observer = - crate::domain::settlement::Observer::new(eth.clone(), persistence.clone()); let settlement_contract_start_index = match GPv2Settlement::deployment_block(&chain_id) { Some(block) => { tracing::debug!(block, "found settlement contract deployment"); @@ -469,30 +426,34 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { } }; let settlement_event_indexer = EventUpdater::new( - AlloyEventRetriever(boundary::events::settlement::GPv2SettlementContract::new( - web3.alloy.clone(), + boundary::events::settlement::GPv2SettlementContract::new( + web3.provider.clone(), *eth.contracts().settlement().address(), - )), + ), boundary::events::settlement::Indexer::new( db_write.clone(), - settlement_observer, settlement_contract_start_index, ), block_retriever.clone(), skip_event_sync_start, ); - let archive_node_web3 = args.archive_node_url.as_ref().map_or(web3.clone(), |url| { - boundary::web3_client(url, &args.shared.ethrpc) - }); - - let mut cow_amm_registry = cow_amm::Registry::new(archive_node_web3); - for config in &args.cow_amm_configs { + let archive_node_web3 = config + .cow_amm + .archive_node_url + .as_ref() + .map_or(web3.clone(), |url| boundary::web3_client(url, ðrpc_args)); + + let mut cow_amm_registry = cow_amm::Registry::new(Arc::new(BlockRetriever { + provider: archive_node_web3.provider, + block_stream: eth.current_block().clone(), + })); + for cow_amm_config in &config.cow_amm.contracts { cow_amm_registry .add_listener( - config.index_start, - config.factory, - config.helper, + cow_amm_config.index_start, + cow_amm_config.factory, + cow_amm_config.helper, db_write.pool.clone(), ) .await; @@ -500,65 +461,85 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { let quoter = Arc::new(OrderQuoter::new( price_estimator, - native_price_estimator.clone(), + api_native_price_estimator.clone(), gas_price_estimator, Arc::new(db_write.clone()), order_quoting::Validity { eip1271_onchain_quote: chrono::Duration::from_std( - args.order_quoting.eip1271_onchain_quote_validity, + config.order_quoting.eip1271_onchain_quote_validity, ) .unwrap(), presign_onchain_quote: chrono::Duration::from_std( - args.order_quoting.presign_onchain_quote_validity, + config.order_quoting.presign_onchain_quote_validity, ) .unwrap(), standard_quote: chrono::Duration::from_std( - args.order_quoting.standard_offchain_quote_validity, + config.order_quoting.standard_offchain_quote_validity, ) .unwrap(), }, - balance_fetcher.clone(), - args.price_estimation.quote_verification, - args.price_estimation.quote_timeout, + config.price_estimation.quote_timeout, + config.price_estimation.max_quote_timeout, )); let solvable_orders_cache = SolvableOrdersCache::new( - args.min_order_validity_period, + config.min_order_validity_period, persistence.clone(), infra::banned::Users::new( eth.contracts().chainalysis_oracle().clone(), - args.banned_users, - args.banned_users_max_cache_size.get().to_u64().unwrap(), + config + .banned_users + .hermod + .clone() + .map(|hermod| infra::banned::HermodConfig { + url: hermod.url, + hmac_key: hermod.hmac_key, + api_key: hermod.api_key, + }), + config.banned_users.addresses, + config.banned_users.max_cache_size.get().to_u64().unwrap(), ), balance_fetcher.clone(), - bad_token_detector.clone(), - native_price_estimator.clone(), - signature_validator.clone(), - eth.contracts().weth().address().into_legacy(), - args.limit_order_price_factor - .try_into() - .expect("limit order price factor can't be converted to BigDecimal"), - domain::ProtocolFees::new(&args.fee_policies_config), + deny_listed_tokens.clone(), + competition_native_price_updater.clone(), + *eth.contracts().weth().address(), + domain::ProtocolFees::new( + &config.fee_policies, + config + .shared + .volume_fee_bucket_overrides + .iter() + .map(Into::into) + .collect(), + config.shared.enable_sell_equals_buy_volume_fee, + ), cow_amm_registry.clone(), - args.run_loop_native_price_timeout, - eth.contracts().settlement().address().into_legacy(), - args.disable_order_balance_filter, - args.disable_1271_order_sig_filter, - args.disable_1271_order_balance_filter, + config.native_price_timeout, + *eth.contracts().settlement().address(), + config.disable_order_balance_filter, ); - let liveness = Arc::new(Liveness::new(args.max_auction_age)); + let liveness = Arc::new(Liveness::new(config.max_auction_age)); let startup = Arc::new(Some(AtomicBool::new(false))); + + let (api_shutdown_sender, api_shutdown_receiver) = tokio::sync::oneshot::channel(); + let api_task = tokio::spawn(infra::api::serve( + config.api_address, + api_native_price_estimator, + config.price_estimation.quote_timeout, + api_shutdown_receiver, + )); + observe::metrics::serve_metrics( liveness.clone(), - args.metrics_address, + config.metrics_address, Default::default(), startup.clone(), ); let order_events_cleaner_config = crate::periodic_db_cleanup::OrderEventsCleanerConfig::new( - args.order_events_cleanup_interval, - args.order_events_cleanup_threshold, + config.order_events_cleanup.cleanup_interval, + config.order_events_cleanup.cleanup_threshold, ); let order_events_cleaner = crate::periodic_db_cleanup::OrderEventsCleaner::new( order_events_cleaner_config, @@ -572,23 +553,29 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { ); let market_makable_token_list_configuration = TokenListConfiguration { - url: args.trusted_tokens_url, - update_interval: args.trusted_tokens_update_interval, + url: config.trusted_tokens.url.clone(), + update_interval: config.trusted_tokens.update_interval, chain_id, client: http_factory.create(), - hardcoded: args.trusted_tokens.unwrap_or_default(), + hardcoded: config.trusted_tokens.tokens.clone(), }; // updated in background task let trusted_tokens = AutoUpdatingTokenList::from_configuration(market_makable_token_list_configuration).await; + let settlement_observer = + crate::domain::settlement::Observer::new(eth.clone(), persistence.clone()); - let mut maintenance = Maintenance::new(settlement_event_indexer, db_write.clone()); - maintenance.with_cow_amms(&cow_amm_registry); + let mut maintenance = Maintenance::new( + settlement_event_indexer, + db_write.clone(), + settlement_observer, + ); + maintenance.add_cow_amm_indexer(&cow_amm_registry); - if !args.ethflow_contracts.is_empty() { + if !config.ethflow.contracts.is_empty() { let ethflow_refund_start_block = determine_ethflow_refund_indexing_start( &skip_event_sync_start, - args.ethflow_indexing_start, + config.ethflow.indexing_start, &web3, chain_id, db_write.clone(), @@ -598,10 +585,7 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { let refund_event_handler = EventUpdater::new_skip_blocks_before( // This cares only about ethflow refund events because all the other ethflow // events are already indexed by the OnchainOrderParser. - AlloyEventRetriever(EthFlowRefundRetriever::new( - web3.clone(), - args.ethflow_contracts.clone(), - )), + EthFlowRefundRetriever::new(web3.clone(), config.ethflow.contracts.clone()), db_write.clone(), block_retriever.clone(), ethflow_refund_start_block, @@ -616,17 +600,14 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { web3.clone(), quoter.clone(), Box::new(custom_ethflow_order_parser), - DomainSeparator::new( - chain_id, - eth.contracts().settlement().address().into_legacy(), - ), - eth.contracts().settlement().address().into_legacy(), + DomainSeparator::new(chain_id, *eth.contracts().settlement().address()), + *eth.contracts().settlement().address(), eth.contracts().trampoline().clone(), ); let ethflow_start_block = determine_ethflow_indexing_start( &skip_event_sync_start, - args.ethflow_indexing_start, + config.ethflow.indexing_start, &web3, chain_id, &db_write, @@ -636,10 +617,7 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { let onchain_order_indexer = EventUpdater::new_skip_blocks_before( // The events from the ethflow contract are read with the more generic contract // interface called CoWSwapOnchainOrders. - AlloyEventRetriever(CoWSwapOnchainOrdersContract::new( - web3.clone(), - args.ethflow_contracts, - )), + CoWSwapOnchainOrdersContract::new(web3.clone(), config.ethflow.contracts), onchain_order_event_parser, block_retriever, ethflow_start_block, @@ -648,39 +626,19 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { .await .expect("Should be able to initialize event updater. Database read issues?"); - maintenance.spawn_ethflow_indexer(onchain_order_indexer); - // refunds are not critical for correctness and can therefore be indexed - // sporadically in a background task - let service_maintainer = ServiceMaintenance::new(vec![Arc::new(refund_event_handler)]); - tokio::task::spawn( - service_maintainer.run_maintenance_on_new_block(eth.current_block().clone()), - ); + maintenance.add_ethflow_indexing(onchain_order_indexer, refund_event_handler); } - let run_loop_config = run_loop::Config { - submission_deadline: args.submission_deadline as u64, - max_settlement_transaction_wait: args.max_settlement_transaction_wait, - solve_deadline: args.solve_deadline, - max_run_loop_delay: args.max_run_loop_delay, - max_winners_per_auction: args.max_winners_per_auction, - max_solutions_per_solver: args.max_solutions_per_solver, - enable_leader_lock: args.enable_leader_lock, - }; + let run_loop_config = run_loop::Config::from(config.run_loop); - let drivers_futures = args + let drivers_futures = config .drivers .into_iter() .map(|driver| async move { - infra::Driver::try_new( - driver.url, - driver.name.clone(), - driver.fairness_threshold.map(Into::into), - driver.submission_account, - driver.requested_timeout_on_problems, - ) - .await - .map(Arc::new) - .expect("failed to load solver configuration") + infra::Driver::try_new(driver.url, driver.name.clone(), driver.submission_account) + .await + .map(Arc::new) + .expect("failed to load solver configuration") }) .collect::>(); @@ -690,48 +648,43 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { .into_iter() .collect(); - let solver_participation_guard = SolverParticipationGuard::new( - eth.clone(), - persistence.clone(), - competition_updates_receiver, - args.db_based_solver_participation_guard, - drivers.iter().cloned(), - ); + let awaiter = maintenance + .spawn_maintenance_task(eth.current_block().clone(), config.max_maintenance_timeout); let run = RunLoop::new( run_loop_config, eth, persistence.clone(), drivers, - solver_participation_guard, solvable_orders_cache, trusted_tokens, run_loop::Probes { liveness: liveness.clone(), startup, }, - Arc::new(maintenance), - competition_updates_sender, + awaiter, ); run.run_forever(shutdown_controller).await; + + api_shutdown_sender.send(()).ok(); + api_task.await.ok(); } -async fn shadow_mode(args: Arguments) -> ! { - let http_factory = HttpClientFactory::new(&args.http_client); +async fn shadow_mode(config: Configuration) -> ! { + let http_factory = HttpClientFactory::from(config.http_client); let orderbook = infra::shadow::Orderbook::new( http_factory.create(), - args.shadow.expect("missing shadow mode configuration"), + config.shadow.expect("missing shadow mode configuration"), ); - let drivers_futures = args + let drivers_futures = config .drivers .into_iter() .map(|driver| async move { infra::Driver::try_new( driver.url, driver.name.clone(), - driver.fairness_threshold.map(Into::into), // HACK: the auction logic expects all drivers // to use a different submission address. But // in the shadow environment all drivers use @@ -740,8 +693,7 @@ async fn shadow_mode(args: Arguments) -> ! { // Luckily the shadow autopilot doesn't use // this address for anything important so we // can simply generate random addresses here. - Account::Address(H160::random()), - driver.requested_timeout_on_problems, + Account::Address(Address::random()), ) .await .map(Arc::new) @@ -754,24 +706,19 @@ async fn shadow_mode(args: Arguments) -> ! { .into_iter() .collect(); - let web3 = shared::ethrpc::web3( - &args.shared.ethrpc, - &http_factory, - &args.shared.node_url, - "base", - ); - let weth = WETH9::Instance::deployed(&web3.alloy) + let ethrpc_args = shared::web3::Arguments::from(&config.shared.ethrpc); + let web3 = shared::web3::web3(ðrpc_args, &config.shared.node_url, "base"); + let weth = WETH9::Instance::deployed(&web3.provider) .await .expect("couldn't find deployed WETH contract"); let trusted_tokens = { let chain_id = web3 - .eth() - .chain_id() + .provider + .get_chain_id() .await - .expect("Could not get chainId") - .as_u64(); - if let Some(expected_chain_id) = args.shared.chain_id { + .expect("Could not get chainId"); + if let Some(expected_chain_id) = config.shared.chain_id { assert_eq!( chain_id, expected_chain_id, "connected to node with incorrect chain ID", @@ -779,27 +726,26 @@ async fn shadow_mode(args: Arguments) -> ! { } AutoUpdatingTokenList::from_configuration(TokenListConfiguration { - url: args.trusted_tokens_url, - update_interval: args.trusted_tokens_update_interval, + url: config.trusted_tokens.url, + update_interval: config.trusted_tokens.update_interval, chain_id, client: http_factory.create(), - hardcoded: args.trusted_tokens.unwrap_or_default(), + hardcoded: config.trusted_tokens.tokens, }) .await }; - let liveness = Arc::new(Liveness::new(args.max_auction_age)); + let liveness = Arc::new(Liveness::new(config.max_auction_age)); observe::metrics::serve_metrics( liveness.clone(), - args.metrics_address, + config.metrics_address, Default::default(), Default::default(), ); - let current_block = args - .shared - .current_block - .stream(args.shared.node_url, web3.alloy.clone()) + let current_block_args = shared::current_block::Arguments::from(&config.shared.current_block); + let current_block = current_block_args + .stream(config.shared.node_url, web3.provider.clone()) .await .expect("couldn't initialize current block stream"); @@ -807,11 +753,12 @@ async fn shadow_mode(args: Arguments) -> ! { orderbook, drivers, trusted_tokens, - args.solve_deadline, + config.run_loop.min_solve_time, + config.run_loop.compress_solve_request, liveness.clone(), current_block, - args.max_winners_per_auction, - weth.address().into_legacy().into(), + config.run_loop.max_winners_per_auction, + (*weth.address()).into(), ); shadow.run_forever().await; } diff --git a/crates/autopilot/src/run_loop.rs b/crates/autopilot/src/run_loop.rs index 24c196eaf6..4603e999ab 100644 --- a/crates/autopilot/src/run_loop.rs +++ b/crates/autopilot/src/run_loop.rs @@ -3,17 +3,13 @@ use { database::competition::Competition, domain::{ self, - OrderUid, auction::Id, competition::{ self, Solution, - SolutionError, - SolverParticipationGuard, - Unranked, + Unscored, winner_selection::{self, Ranking}, }, - eth::{self, TxId}, settlement::{ExecutionEnded, ExecutionStarted}, }, infra::{ @@ -21,15 +17,19 @@ use { solvers::dto::{settle, solve}, }, leader_lock_tracker::LeaderLockTracker, - maintenance::Maintenance, + maintenance::{MaintenanceSync, SyncTarget}, run::Liveness, shutdown_controller::ShutdownController, solvable_orders::SolvableOrdersCache, }, ::observe::metrics, + ::winner_selection::state::RankedItem, + alloy::primitives::B256, anyhow::{Context, Result}, + chrono::{DateTime, Utc}, database::order_events::OrderEventLabel, - ethrpc::{alloy::conversions::IntoLegacy, block_stream::BlockInfo}, + eth_domain_types::{self as eth, Address, TxId}, + ethrpc::block_stream::BlockInfo, futures::{FutureExt, TryFutureExt}, itertools::Itertools, model::solver_competition::{ @@ -40,7 +40,6 @@ use { SolverSettlement, }, num::ToPrimitive, - primitive_types::H256, rand::seq::SliceRandom, shared::token_list::AutoUpdatingTokenList, std::{ @@ -52,14 +51,14 @@ use { }, time::{Duration, Instant}, }, - tokio::sync::Mutex, tracing::{Instrument, instrument}, }; pub struct Config { pub submission_deadline: u64, pub max_settlement_transaction_wait: Duration, - pub solve_deadline: Duration, + pub min_solve_time: Duration, + pub sync_solve_deadline_to_blockchain: Option, /// How much time past observing the current block the runloop is /// allowed to start before it has to re-synchronize to the blockchain /// by waiting for the next block to appear. @@ -67,6 +66,35 @@ pub struct Config { pub max_winners_per_auction: NonZeroUsize, pub max_solutions_per_solver: NonZeroUsize, pub enable_leader_lock: bool, + pub compress_solve_request: bool, +} + +impl From for Config { + fn from(value: configs::autopilot::run_loop::RunLoopConfig) -> Self { + Self { + submission_deadline: value.submission_deadline, + max_settlement_transaction_wait: value.max_settlement_transaction_wait, + min_solve_time: value.min_solve_time, + max_run_loop_delay: value.max_delay, + max_winners_per_auction: value.max_winners_per_auction, + max_solutions_per_solver: value.max_solutions_per_solver, + enable_leader_lock: value.enable_leader_lock, + compress_solve_request: value.compress_solve_request, + sync_solve_deadline_to_blockchain: value.sync_solve_deadline_to_blockchain.map(|cfg| { + SlotConfig { + slot_length: cfg.slot_length, + tx_propagation_latency: cfg.tx_propagation_latency, + } + }), + } + } +} + +/// Specifies the timing of the block timings of PoS chains +/// and how to synchronize tx submission to it. +pub struct SlotConfig { + pub slot_length: Duration, + pub tx_propagation_latency: Duration, } pub struct Probes { @@ -79,16 +107,15 @@ pub struct RunLoop { eth: infra::Ethereum, persistence: infra::Persistence, drivers: Vec>, - solver_participation_guard: SolverParticipationGuard, solvable_orders_cache: Arc, trusted_tokens: AutoUpdatingTokenList, - in_flight_orders: Arc>>, probes: Probes, /// Maintenance tasks that should run before every runloop to have /// the most recent data available. - maintenance: Arc, - competition_updates_sender: tokio::sync::mpsc::UnboundedSender<()>, + maintenance: MaintenanceSync, winner_selection: winner_selection::Arbitrator, + /// Notifier that wakes the main loop on new blocks or orders + wake_notify: Arc, } impl RunLoop { @@ -98,38 +125,36 @@ impl RunLoop { eth: infra::Ethereum, persistence: infra::Persistence, drivers: Vec>, - solver_participation_guard: SolverParticipationGuard, solvable_orders_cache: Arc, trusted_tokens: AutoUpdatingTokenList, probes: Probes, - maintenance: Arc, - competition_updates_sender: tokio::sync::mpsc::UnboundedSender<()>, + maintenance: MaintenanceSync, ) -> Self { let max_winners = config.max_winners_per_auction.get(); let weth = eth.contracts().wrapped_native_token(); + // Create notifier that wakes the main loop on new blocks or orders + let wake_notify = Arc::new(tokio::sync::Notify::new()); + + // Spawn background tasks to listen for events + persistence.spawn_order_listener(wake_notify.clone()); + Self::spawn_block_listener(eth.current_block().clone(), wake_notify.clone()); + Self { config, eth, persistence, drivers, - solver_participation_guard, solvable_orders_cache, trusted_tokens, - in_flight_orders: Default::default(), probes, maintenance, - competition_updates_sender, - winner_selection: winner_selection::Arbitrator { max_winners, weth }, + winner_selection: winner_selection::Arbitrator::new(max_winners, weth), + wake_notify, } } pub async fn run_forever(self, mut control: ShutdownController) { - Maintenance::spawn_cow_amm_indexing_task( - self.maintenance.clone(), - self.eth.current_block().clone(), - ); - let mut last_auction = None; let mut last_block = None; @@ -149,6 +174,10 @@ impl RunLoop { while !control.should_shutdown() { leader_lock_tracker.try_acquire().await; + // Wait for notify about some significant state change (e.g. new + // order, new block). We only update the cache afterwards to update + // to the most recent state. + self_arc.wake_notify.notified().await; let start_block = self_arc .update_caches(&mut last_block, leader_lock_tracker.is_leader()) .await; @@ -178,7 +207,34 @@ impl RunLoop { leader_lock_tracker.release().await; } - async fn update_caches(&self, prev_block: &mut Option, is_leader: bool) -> BlockInfo { + /// Spawns a background task that listens for new blocks from the + /// blockchain. + fn spawn_block_listener( + current_block: ethrpc::block_stream::CurrentBlockWatcher, + notify: Arc, + ) { + tokio::spawn(async move { + loop { + ethrpc::block_stream::next_block(¤t_block).await; + tracing::debug!("received new block"); + notify.notify_one(); + } + }); + } + + fn pick_solve_deadline(&self) -> DateTime { + let now = chrono::Utc::now(); + let last_block = *self.eth.current_block().borrow(); + pick_solve_deadline_impl( + now, + self.config.min_solve_time, + self.config.sync_solve_deadline_to_blockchain.as_ref(), + last_block, + ) + } + + #[instrument(skip_all)] + async fn update_caches(&self, prev_block: &mut Option, is_leader: bool) -> BlockInfo { let current_block = *self.eth.current_block().borrow(); let time_since_last_block = current_block.observed_at.elapsed(); let auction_block = if time_since_last_block > self.config.max_run_loop_delay { @@ -194,7 +250,12 @@ impl RunLoop { current_block }; - self.run_maintenance(&auction_block).await; + { + let _timer = Metrics::get().service_maintenance_time.start_timer(); + self.maintenance + .wait_until_block_processed(SyncTarget::PartiallyProcessed(auction_block.number)) + .await; + } match self .solvable_orders_cache @@ -215,12 +276,12 @@ impl RunLoop { /// Sleeps until the next auction is supposed to start, builds it and /// returns it. - #[instrument(skip(self, prev_auction), fields(prev_auction = prev_auction.as_ref().map(|a| a.id)))] + #[instrument(skip_all)] async fn next_auction( &self, start_block: BlockInfo, prev_auction: &mut Option, - prev_block: &mut Option, + prev_block: &mut Option, ) -> Option { // wait for appropriate time to start building the auction let auction = self.cut_auction().await?; @@ -234,40 +295,28 @@ impl RunLoop { return None; } - observe::log_auction_delta(&previous, &auction); + observe::log_auction_delta(&previous, &auction, &start_block); self.probes.liveness.auction(); Metrics::auction_ready(start_block.observed_at); Some(auction) } - /// Runs maintenance on all components to ensure the system uses - /// the latest available state. - async fn run_maintenance(&self, block: &BlockInfo) { - let start = Instant::now(); - self.maintenance.update(block).await; - Metrics::ran_maintenance(start.elapsed()); - } - async fn cut_auction(&self) -> Option { - let auction = match self.solvable_orders_cache.current_auction().await { - Some(auction) => auction, - None => { - tracing::debug!("no current auction"); - return None; - } + let Some(auction) = self.solvable_orders_cache.current_auction().await else { + tracing::debug!("no current auction"); + return None; }; - let auction = self.remove_in_flight_orders(auction).await; + let id = self + .persistence + .get_next_auction_id() + .await + .inspect_err(|err| tracing::error!(?err, "failed to get next auction id")) + .ok()?; + Metrics::auction(id); - let id = match self.persistence.replace_current_auction(&auction).await { - Ok(id) => { - Metrics::auction(id); - id - } - Err(err) => { - tracing::error!(?err, "failed to replace current auction"); - return None; - } - }; + // always update the auction because the tests use this as a readiness probe + self.persistence.replace_current_auction_in_db(id, &auction); + self.persistence.upload_auction_to_s3(id, &auction); if auction.orders.is_empty() { // Updating liveness probe to not report unhealthy due to this optimization @@ -275,7 +324,6 @@ impl RunLoop { tracing::debug!("skipping empty auction"); return None; } - Some(domain::Auction { id, block: auction.block, @@ -285,7 +333,7 @@ impl RunLoop { }) } - #[instrument(skip_all, fields(auction_id = auction.id, auction_block = auction.block, auction_orders = auction.orders.len()))] + #[instrument(skip_all)] async fn single_run(self: &Arc, auction: domain::Auction) { let single_run_start = Instant::now(); tracing::info!(auction_id = ?auction.id, "solving"); @@ -297,7 +345,7 @@ impl RunLoop { // Collect valid solutions from all drivers let solutions = self.fetch_solutions(&auction).await; - observe::solutions(&solutions); + observe::bids(&solutions); if solutions.is_empty() { return; } @@ -321,7 +369,6 @@ impl RunLoop { competition_simulation_block, &ranking, block_deadline, - &self.winner_selection, ) .await { @@ -333,7 +380,7 @@ impl RunLoop { // Mark all winning orders as `Executing` let winning_orders = ranking .winners() - .flat_map(|p| p.solution().order_ids().copied()) + .flat_map(|b| b.solution().order_ids().copied()) .collect::>(); self.persistence .store_order_events(winning_orders.clone(), OrderEventLabel::Executing); @@ -342,16 +389,13 @@ impl RunLoop { self.persistence.store_order_events( ranking .non_winners() - .flat_map(|p| p.solution().order_ids().copied()) + .flat_map(|b| b.solution().order_ids().copied()) .filter(|order_id| !winning_orders.contains(order_id)), OrderEventLabel::Considered, ); tracing::trace!(auction_id = ?auction.id, "orders marked as considered"); - for (solution_uid, winner) in ranking - .enumerated() - .filter(|(_, participant)| participant.is_winner()) - { + for (solution_uid, winner) in ranking.enumerated().filter(|(_, bid)| bid.is_winner()) { let (driver, solution) = (winner.driver(), winner.solution()); tracing::info!(driver = %driver.name, solution = %solution.id(), "winner"); @@ -362,8 +406,7 @@ impl RunLoop { solution, solution_uid, block_deadline, - ) - .await; + ); } tracing::trace!(auction_id = ?auction.id, "settlement execution started"); observe::unsettled(&ranking, &auction); @@ -371,7 +414,7 @@ impl RunLoop { /// Starts settlement execution in a background task. The function is async /// only to get access to the locks. - async fn start_settlement_execution( + fn start_settlement_execution( self: &Arc, auction_id: Id, single_run_start: Instant, @@ -381,11 +424,6 @@ impl RunLoop { block_deadline: u64, ) { let solved_order_uids: HashSet<_> = solution.orders().keys().cloned().collect(); - self.in_flight_orders - .lock() - .await - .extend(solved_order_uids.clone()); - let solution_id = solution.id(); let solver = solution.solver(); let self_ = self.clone(); @@ -398,7 +436,6 @@ impl RunLoop { match self_ .settle( &driver_, - solved_order_uids.clone(), solver, auction_id, solution_id, @@ -434,14 +471,13 @@ impl RunLoop { competition_simulation_block: u64, ranking: &Ranking, block_deadline: u64, - winner_selection: &winner_selection::Arbitrator, ) -> Result<()> { let start = Instant::now(); - let reference_scores = winner_selection.compute_reference_scores(ranking); + let reference_scores = ranking.reference_scores().clone(); let participants = ranking .all() - .map(|participant| participant.solution().solver().into()) + .map(|bid| bid.solution().solver()) .collect::>(); let order_lookup: std::collections::HashMap<_, _> = auction .orders @@ -451,7 +487,7 @@ impl RunLoop { let fee_policies: Vec<_> = ranking .ranked() - .flat_map(|participant| participant.solution().order_ids()) + .flat_map(|bid| bid.solution().order_ids()) .unique() .filter_map(|order_id| match order_lookup.get(order_id) { Some(auction_order) => { @@ -466,29 +502,28 @@ impl RunLoop { let mut solutions: Vec<_> = ranking .enumerated() - .map(|(index, participant)| SolverSettlement { - solver: participant.driver().name.clone(), - solver_address: participant.solution().solver().0, - score: Some(Score::Solver(participant.solution().score().get().0)), + .map(|(index, bid)| SolverSettlement { + solver: bid.driver().name.clone(), + solver_address: bid.solution().solver(), + score: Some(Score::Solver(bid.score().get().0)), ranking: index + 1, - orders: participant + orders: bid .solution() .orders() .iter() .map(|(id, order)| Order::Colocated { id: (*id).into(), - sell_amount: order.executed_sell.into(), - buy_amount: order.executed_buy.into(), + sell_amount: order.executed_sell.0, + buy_amount: order.executed_buy.0, }) .collect(), - clearing_prices: participant - .solution() - .prices() - .iter() - .map(|(token, price)| (token.0, price.get().into())) - .collect(), - is_winner: participant.is_winner(), - filtered_out: participant.filtered_out(), + // Always empty — kept to avoid breaking the solver competition + // API (`/api/v1/solver_competition`). + // NOTE: since the v1 has been removed, + // we'll probably be able to remove this soon too + clearing_prices: Default::default(), + is_winner: bid.is_winner(), + filtered_out: bid.is_filtered_out(), }) .collect(); // reverse as solver competition table is sorted from worst to best, @@ -507,7 +542,7 @@ impl RunLoop { prices: auction .prices .iter() - .map(|(key, value)| ((*key).into(), value.get().into())) + .map(|(key, value)| (Address::from(*key), value.get().0)) .collect(), }, solutions, @@ -520,38 +555,22 @@ impl RunLoop { .prices .clone() .into_iter() - .map(|(key, value)| (key.into(), value.get().into())) + .map(|(key, value)| (*key, value.get().0)) .collect(), block_deadline, competition_simulation_block, competition_table, }; - match futures::try_join!( + tracing::trace!(?competition, "saving competition"); + + futures::try_join!( self.persistence .save_auction(auction, block_deadline) .map_err(|e| e.0.context("failed to save auction")), self.persistence .save_solutions(auction.id, ranking.all()) .map_err(|e| e.0.context("failed to save solutions")), - ) { - Ok(_) => { - // Notify the solver participation guard that the proposed solutions have been - // saved. - if let Err(err) = self.competition_updates_sender.send(()) { - tracing::error!(?err, "failed to notify solver participation guard"); - } - } - Err(err) => { - // Don't error if saving of auction and solution fails, until stable. - // Various edge cases with JIT orders verifiable only in production. - tracing::warn!(?err, "failed to save new competition data"); - } - } - tracing::trace!(auction_id = ?auction.id, "auction saved"); - - tracing::trace!(?competition, "saving competition"); - futures::try_join!( self.persistence .save_competition(competition) .map_err(|e| e.0.context("failed to save competition")), @@ -564,8 +583,10 @@ impl RunLoop { self.persistence .store_fee_policies(auction.id, fee_policies) .map_err(|e| e.context("failed to fee_policies")), - )?; - tracing::trace!(auction_id = ?auction.id, "competition saved"); + ) + .inspect_err(|err| tracing::warn!(?err, "failed to write post processed data to DB"))?; + + tracing::debug!(time = ?start.elapsed(), "post-processing done"); Metrics::post_processed(start.elapsed()); Ok(()) @@ -574,22 +595,19 @@ impl RunLoop { /// Runs the solver competition, making all configured drivers participate. /// Returns all fair solutions sorted by their score (best to worst). #[instrument(skip_all)] - async fn fetch_solutions( - &self, - auction: &domain::Auction, - ) -> Vec> { + async fn fetch_solutions(&self, auction: &domain::Auction) -> Vec> { + let deadline = self.pick_solve_deadline(); + let request = solve::Request::new( auction, - &self - .trusted_tokens - .all() - .into_iter() - .map(IntoLegacy::into_legacy) - .collect(), - self.config.solve_deadline, - ); + &self.trusted_tokens.all(), + deadline, + self.config.compress_solve_request, + ) + .await; + Metrics::solve_request_body_size(request.body_size()); - let mut solutions = futures::future::join_all( + let mut bids = futures::future::join_all( self.drivers .iter() .map(|driver| self.solve(driver.clone(), request.clone())), @@ -600,15 +618,15 @@ impl RunLoop { .collect::>(); let mut counter = HashMap::new(); - solutions.retain(|participant| { - let submission_address = participant.driver().submission_address; - let is_solution_from_driver = participant.solution().solver() == submission_address; + bids.retain(|bid| { + let submission_address = bid.driver().submission_address; + let is_solution_from_driver = bid.solution().solver() == submission_address; // Filter out solutions that don't come from their corresponding submission // address if !is_solution_from_driver { tracing::warn!( - driver = participant.driver().name, + driver = bid.driver().name, ?submission_address, "the solution received is not from the driver submission address" ); @@ -616,15 +634,15 @@ impl RunLoop { } // limit number of solutions per solver - let driver = participant.driver().name.clone(); + let driver = bid.driver().name.clone(); let count = counter.entry(driver).or_insert(0); *count += 1; *count <= self.config.max_solutions_per_solver.get() }); // Shuffle so that sorting randomly splits ties. - solutions.shuffle(&mut rand::thread_rng()); - solutions + bids.shuffle(&mut rand::rng()); + bids } /// Sends a `/solve` request to the driver and manages all error cases and @@ -634,7 +652,7 @@ impl RunLoop { &self, driver: Arc, request: solve::Request, - ) -> Vec> { + ) -> Vec> { let start = Instant::now(); let result = self.try_solve(Arc::clone(&driver), request).await; let solutions = match result { @@ -651,16 +669,9 @@ impl RunLoop { solutions .into_iter() - .filter_map(|solution| match solution { - Ok(solution) => { - Metrics::solution_ok(&driver); - Some(competition::Participant::new(solution, driver.clone())) - } - Err(err) => { - Metrics::solution_err(&driver, &err); - tracing::debug!(?err, driver = %driver.name, "invalid proposed solution"); - None - } + .map(|solution| { + Metrics::solution_ok(&driver); + competition::Bid::new(solution, driver.clone()) }) .collect() } @@ -670,17 +681,23 @@ impl RunLoop { &self, driver: Arc, request: solve::Request, - ) -> Result>, SolveError> - { + ) -> Result, SolveError> { let (can_participate, response) = { let driver = driver.clone(); - let guard = self.solver_participation_guard.clone(); - let mut handle = tokio::task::spawn(async move { - let fetch_response = driver.solve(request); - let check_allowed = guard.can_participate(&driver.submission_address); - tokio::join!(check_allowed, fetch_response) - }); - tokio::time::timeout(self.config.solve_deadline, &mut handle) + let eth = self.eth.clone(); + let timeout = request.time_until_deadline(); + let mut handle = tokio::task::spawn( + async move { + let fetch_response = driver.solve(request); + let check_allowed = eth + .contracts() + .authenticator() + .isSolver(driver.submission_address); + tokio::join!(check_allowed.call(), fetch_response) + } + .in_current_span(), + ); + tokio::time::timeout(timeout, &mut handle) .await .map_err(|_| { // Abort the background task to prevent memory leaks @@ -714,11 +731,10 @@ impl RunLoop { /// Execute the solver's solution. Returns Ok when the corresponding /// transaction has been mined. - #[expect(clippy::too_many_arguments)] + #[instrument(skip_all, fields(driver = driver.name, solution_uid))] async fn settle( &self, driver: &infra::Driver, - solved_order_uids: HashSet, solver: eth::Address, auction_id: i64, solution_id: u64, @@ -752,7 +768,12 @@ impl RunLoop { .boxed(); let wait_for_settlement_transaction = self - .wait_for_settlement_transaction(auction_id, solver, submission_deadline_latest_block) + .wait_for_settlement_transaction( + auction_id, + solver, + submission_deadline_latest_block, + solution_uid, + ) .boxed(); // Wait for either the settlement transaction to be mined or the driver returned @@ -769,12 +790,6 @@ impl RunLoop { self.store_execution_ended(solver, auction_id, solution_uid, &result); - // Clean up the in-flight orders regardless the result. - self.in_flight_orders - .lock() - .await - .retain(|order| !solved_order_uids.contains(order)); - result } @@ -855,6 +870,7 @@ impl RunLoop { auction_id: i64, solver: eth::Address, submission_deadline_latest_block: u64, + solution_uid: usize, ) -> Result { let current = self.eth.current_block().borrow().number; tracing::debug!(%current, deadline=%submission_deadline_latest_block, %auction_id, "waiting for tag"); @@ -862,11 +878,13 @@ impl RunLoop { let block = ethrpc::block_stream::next_block(self.eth.current_block()).await; // Run maintenance to ensure the system processed the last available block so // it's possible to find the tx in the DB in the next line. - self.run_maintenance(&block).await; + self.maintenance + .wait_until_block_processed(SyncTarget::FullyProcessed(block.number)) + .await; match self .persistence - .find_settlement_transaction(auction_id, solver) + .find_settlement_transaction(auction_id, solver, solution_uid) .await { Ok(Some(transaction)) => return Ok(transaction), @@ -886,29 +904,60 @@ impl RunLoop { } Err(SettleError::Timeout) } +} - /// Removes orders that are currently being settled to avoid solvers trying - /// to fill an order a second time. - async fn remove_in_flight_orders( - &self, - mut auction: domain::RawAuctionData, - ) -> domain::RawAuctionData { - let in_flight = &*self.in_flight_orders.lock().await; - if in_flight.is_empty() { - return auction; - }; - - auction.orders.retain(|o| !in_flight.contains(&o.uid)); - auction - .surplus_capturing_jit_order_owners - .retain(|owner| !in_flight.iter().any(|i| i.owner() == *owner)); - tracing::debug!( - orders = ?in_flight, - "filtered out in-flight orders and surplus_capturing_jit_order_owners" - ); +/// Picks a `/solve` deadline that ends shortly before a block gets +/// mined to maximize the chance that solutions get mined instantly. +/// If the auction needs to cross block boundaries solvers just get +/// a lot more time for proposing a solution. +/// +/// This function panics if any of the time computations over- or +/// underflow. This should not happen as we deal with times within +/// seconds of the current time. +fn pick_solve_deadline_impl( + now: chrono::DateTime, + min_solve_time: Duration, + slot_config: Option<&SlotConfig>, + current_block: BlockInfo, +) -> chrono::DateTime { + let minimum_deadline = now + min_solve_time; + + let Some(SlotConfig { + slot_length, + tx_propagation_latency, + }) = slot_config + else { + return minimum_deadline; + }; - auction + let current_block_time = + DateTime::from_timestamp_secs(current_block.timestamp.try_into().unwrap()).unwrap(); + + for delay_in_blocks in 1..10 { + let target = current_block_time + slot_length.saturating_mul(delay_in_blocks) + - *tx_propagation_latency; + if target >= minimum_deadline { + if delay_in_blocks == 1 { + tracing::debug!( + deadline = target.to_string(), + current_block = current_block.number, + "optimal solve deadline is before next block" + ); + } else { + tracing::debug!( + delay_in_blocks, + deadline = target.to_string(), + current_block = current_block.number, + "delay auction for optimal deadline" + ); + } + // first timestamp that gives at least the required amount of time + // and is aligned with the chain's block production + return target; + } } + + minimum_deadline } #[derive(Debug, thiserror::Error)] @@ -995,6 +1044,12 @@ struct Metrics { /// function is started. #[metric(buckets(0, 0.25, 0.5, 0.75, 1, 1.5, 2, 2.5, 3, 4, 5, 6))] current_block_delay: prometheus::Histogram, + + /// Tracks the size of the `/solve` request body in bytes. + #[metric(buckets( + 1_000, 5_000, 10_000, 50_000, 100_000, 500_000, 1_000_000, 2_000_000, 3_000_000, 4_000_000 + ))] + solve_request_body_size: prometheus::Histogram, } impl Metrics { @@ -1009,7 +1064,7 @@ impl Metrics { fn solve_ok(driver: &infra::Driver, elapsed: Duration) { Self::get() .solve - .with_label_values(&[&driver.name, "success"]) + .with_label_values(&[driver.name.as_str(), "success"]) .observe(elapsed.as_secs_f64()) } @@ -1022,33 +1077,21 @@ impl Metrics { }; Self::get() .solve - .with_label_values(&[&driver.name, label]) + .with_label_values(&[driver.name.as_str(), label]) .observe(elapsed.as_secs_f64()) } fn solution_ok(driver: &infra::Driver) { Self::get() .solutions - .with_label_values(&[&driver.name, "success"]) - .inc(); - } - - fn solution_err(driver: &infra::Driver, err: &SolutionError) { - let label = match err { - SolutionError::ZeroScore(_) => "zero_score", - SolutionError::InvalidPrice(_) => "invalid_price", - SolutionError::SolverDenyListed => "solver_deny_listed", - }; - Self::get() - .solutions - .with_label_values(&[&driver.name, label]) + .with_label_values(&[driver.name.as_str(), "success"]) .inc(); } fn settle_ok(driver: &infra::Driver, settled_order_count: usize, elapsed: Duration) { Self::get() .settle - .with_label_values(&[&driver.name, "success"]) + .with_label_values(&[driver.name.as_str(), "success"]) .observe(elapsed.as_secs_f64()); Self::get() .settled @@ -1063,7 +1106,7 @@ impl Metrics { }; Self::get() .settle - .with_label_values(&[&driver.name, label]) + .with_label_values(&[driver.name.as_str(), label]) .observe(elapsed.as_secs_f64()); } @@ -1080,12 +1123,6 @@ impl Metrics { .observe(elapsed.as_secs_f64()); } - fn ran_maintenance(elapsed: Duration) { - Self::get() - .service_maintenance_time - .observe(elapsed.as_secs_f64()); - } - fn single_run_completed(elapsed: Duration) { Self::get().single_run_time.observe(elapsed.as_secs_f64()); } @@ -1095,18 +1132,27 @@ impl Metrics { .current_block_delay .observe(init_block_timestamp.elapsed().as_secs_f64()) } + + fn solve_request_body_size(size: usize) { + Self::get().solve_request_body_size.observe(size as f64) + } } pub mod observe { use { crate::domain::{ self, - competition::{Unranked, winner_selection::Ranking}, + competition::{Unscored, winner_selection::Ranking}, }, + ethrpc::block_stream::BlockInfo, std::collections::HashSet, }; - pub fn log_auction_delta(previous: &Option, current: &domain::Auction) { + pub fn log_auction_delta( + previous: &Option, + current: &domain::Auction, + start_block: &BlockInfo, + ) { let previous_uids = match previous { Some(previous) => previous .orders @@ -1132,17 +1178,18 @@ pub mod observe { removed = ?removed, "Orders no longer in auction" ); + tracing::debug!(auction_id = current.id, ?start_block); } - pub fn solutions(solutions: &[domain::competition::Participant]) { - if solutions.is_empty() { + pub fn bids(bids: &[domain::competition::Bid]) { + if bids.is_empty() { tracing::info!("no solutions for auction"); } - for participant in solutions { + for bid in bids { tracing::debug!( - driver = %participant.driver().name, - orders = ?participant.solution().order_ids(), - solution = %participant.solution().id(), + driver = %bid.driver().name, + orders = ?bid.solution().order_ids(), + solution = %bid.solution().id(), "proposed solution" ); } @@ -1153,11 +1200,11 @@ pub mod observe { let mut non_winning_orders = { let winning_orders = ranking .winners() - .flat_map(|p| p.solution().order_ids()) + .flat_map(|b| b.solution().order_ids()) .collect::>(); ranking .ranked() - .flat_map(|p| p.solution().order_ids()) + .flat_map(|b| b.solution().order_ids()) .filter(|uid| !winning_orders.contains(uid)) .collect::>() }; @@ -1168,3 +1215,78 @@ pub mod observe { super::Metrics::matched_unsettled(non_winning_orders); } } + +#[cfg(test)] +mod tests { + use super::*; + + fn block_with_timestamp(unix_timestamp: u64) -> BlockInfo { + BlockInfo { + timestamp: unix_timestamp, + number: Default::default(), + hash: Default::default(), + parent_hash: Default::default(), + gas_limit: Default::default(), + gas_price: Default::default(), + base_fee: Default::default(), + observed_at: Instant::now(), + } + } + + #[test] + fn solve_deadline_aligned_with_blockchain() { + let min_solve_time = Duration::from_secs(9); + + type Ts = chrono::DateTime; + let last_block_timestamp = "2026-06-01T12:00:00Z".parse::().unwrap().timestamp() as u64; + let last_block = block_with_timestamp(last_block_timestamp); + let now = "2026-06-01T12:00:01Z".parse::().unwrap(); + + // default deadline is `now + min_solve_time` (now + 9s) + let standard_deadline = "2026-06-01T12:00:10Z".parse::().unwrap(); + + // syncing to blockchain is not configured -> deadline = now + min_solve_time + let deadline = pick_solve_deadline_impl(now, min_solve_time, None, last_block); + assert_eq!(deadline, standard_deadline); + + // both sync parameters provided -> deadline gets synced to expected block + // production + let slot_config = Some(SlotConfig { + slot_length: Duration::from_secs(12), + tx_propagation_latency: Duration::from_secs(2), + }); + let deadline = + pick_solve_deadline_impl(now, min_solve_time, slot_config.as_ref(), last_block); + // now is 1s after the last block (n), 11s left before the slot ends, 9s before + // we are supposed to submit a solution, 9s minimum solve time => synced + // deadline is equal to standard deadline (2s before block n+1) + assert_eq!(deadline, standard_deadline); + + // now is 2s after the last block (n), 10s left before the slot ends, 8s before + // we are supposed to submit a solution for this slot, 9s minimum solve + // time => we barely missed the deadline of the current slot so now + // solvers get until 2s before the block n+2 + let deadline = pick_solve_deadline_impl( + now + Duration::from_secs(1), + min_solve_time, + slot_config.as_ref(), + last_block, + ); + assert_eq!(deadline, "2026-06-01T12:00:22Z".parse::().unwrap()); + + // let's move to gnosis chain where 1 block is 5s (1 block is not enough for + // the solve deadline) + let slot_config = Some(SlotConfig { + slot_length: Duration::from_secs(5), + tx_propagation_latency: Duration::from_secs(2), + }); + let last_block_time = "2026-06-01T12:00:00Z".parse::().unwrap().timestamp() as u64; + let last_block = block_with_timestamp(last_block_time); + let now = "2026-06-01T12:00:01Z".parse::().unwrap(); + // now is 1s after the last block n, 4s left in the block, we need to submit 2s + // before a block, min_solve_time 9s => deadline is 2s before block n+3 + let deadline = + pick_solve_deadline_impl(now, min_solve_time, slot_config.as_ref(), last_block); + assert_eq!(deadline, "2026-06-01T12:00:13Z".parse::().unwrap()); + } +} diff --git a/crates/autopilot/src/shadow.rs b/crates/autopilot/src/shadow.rs index e0a5b67e4a..aed38bdd27 100644 --- a/crates/autopilot/src/shadow.rs +++ b/crates/autopilot/src/shadow.rs @@ -11,8 +11,7 @@ use { crate::{ domain::{ self, - competition::{Participant, Score, Unranked, winner_selection}, - eth::WrappedNativeToken, + competition::{Bid, Score, Unscored, winner_selection}, }, infra::{ self, @@ -22,9 +21,11 @@ use { run_loop::observe, }, ::observe::metrics, + ::winner_selection::state::RankedItem, anyhow::Context, - ethrpc::{alloy::conversions::IntoLegacy, block_stream::CurrentBlockWatcher}, - itertools::Itertools, + chrono::Utc, + eth_domain_types::WrappedNativeToken, + ethrpc::block_stream::CurrentBlockWatcher, num::{CheckedSub, Saturating}, shared::token_list::AutoUpdatingTokenList, std::{num::NonZeroUsize, sync::Arc, time::Duration}, @@ -38,6 +39,7 @@ pub struct RunLoop { auction: domain::auction::Id, block: u64, solve_deadline: Duration, + compress_solve_request: bool, liveness: Arc, current_block: CurrentBlockWatcher, winner_selection: winner_selection::Arbitrator, @@ -50,22 +52,24 @@ impl RunLoop { drivers: Vec>, trusted_tokens: AutoUpdatingTokenList, solve_deadline: Duration, + compress_solve_request: bool, liveness: Arc, current_block: CurrentBlockWatcher, max_winners_per_auction: NonZeroUsize, weth: WrappedNativeToken, ) -> Self { Self { - winner_selection: winner_selection::Arbitrator { - max_winners: max_winners_per_auction.get(), + winner_selection: winner_selection::Arbitrator::new( + max_winners_per_auction.get(), weth, - }, + ), orderbook, drivers, trusted_tokens, auction: 0, block: 0, solve_deadline, + compress_solve_request, liveness, current_block, } @@ -76,12 +80,12 @@ impl RunLoop { loop { // We use this as a synchronization mechanism to sync the run loop starts with // the next mined block - let _ = ethrpc::block_stream::next_block(&self.current_block).await; + let start_block = ethrpc::block_stream::next_block(&self.current_block).await; let Some(auction) = self.next_auction().await else { tokio::time::sleep(Duration::from_secs(1)).await; continue; }; - observe::log_auction_delta(&previous, &auction); + observe::log_auction_delta(&previous, &auction, &start_block); self.liveness.auction(); self.single_run(&auction) @@ -131,18 +135,18 @@ impl RunLoop { let solutions = self.competition(auction).await; let ranking = self.winner_selection.arbitrate(solutions, auction); - let scores = self.winner_selection.compute_reference_scores(&ranking); + let scores = ranking.reference_scores(); let total_score = ranking .winners() - .map(|p| p.solution().score()) + .map(|b| b.score()) .reduce(Score::saturating_add) .unwrap_or_default(); - for participant in ranking.ranked() { - let is_winner = participant.is_winner(); - let reference_score = scores.get(&participant.driver().submission_address); - let driver = participant.driver(); + for bid in ranking.ranked() { + let is_winner = bid.is_winner(); + let reference_score = scores.get(&bid.driver().submission_address); + let driver = bid.driver(); let reward = reference_score .map(|reference| { total_score.checked_sub(reference).unwrap_or_else(|| { @@ -167,7 +171,7 @@ impl RunLoop { Metrics::get() .performance_rewards .with_label_values(&[&driver.name]) - .inc_by(reward.get().0.to_f64_lossy()); + .inc_by(f64::from(reward.get().0)); Metrics::get() .wins .with_label_values(&[&driver.name]) @@ -177,17 +181,14 @@ impl RunLoop { /// Runs the solver competition, making all configured drivers participate. #[instrument(skip_all)] - async fn competition(&self, auction: &domain::Auction) -> Vec> { + async fn competition(&self, auction: &domain::Auction) -> Vec> { let request = solve::Request::new( auction, - &self - .trusted_tokens - .all() - .into_iter() - .map(IntoLegacy::into_legacy) - .collect(), - self.solve_deadline, - ); + &self.trusted_tokens.all(), + Utc::now() + self.solve_deadline, + self.compress_solve_request, + ) + .await; futures::future::join_all( self.drivers @@ -207,30 +208,25 @@ impl RunLoop { driver: Arc, request: solve::Request, auction_id: i64, - ) -> Vec> { + ) -> Vec> { let solutions = match self.fetch_solutions(&driver, request).await { Ok(response) => { Metrics::get() .results - .with_label_values(&[&driver.name, "ok"]) + .with_label_values(&[driver.name.as_str(), "ok"]) .inc(); response.into_domain() } Err(err) => { Metrics::get() .results - .with_label_values(&[&driver.name, "error"]) + .with_label_values(&[driver.name.as_str(), "error"]) .inc(); tracing::debug!(driver = driver.name, %err, "failed to fetch solutions"); return vec![]; } }; - let (solutions, errs): (Vec<_>, Vec<_>) = solutions.into_iter().partition_result(); - if !errs.is_empty() { - tracing::debug!(len = errs.len(), ?errs, "dropping solutions with errors"); - } - futures::future::join_all(solutions.iter().map(|s| async { let response = driver.reveal(reveal::Request { solution_id: s.id(), @@ -258,7 +254,7 @@ impl RunLoop { solutions .into_iter() - .map(|s| Participant::new(s, Arc::clone(&driver))) + .map(|s| Bid::new(s, Arc::clone(&driver))) .collect() } diff --git a/crates/autopilot/src/shutdown_controller.rs b/crates/autopilot/src/shutdown_controller.rs index 28ebda88f6..912349db59 100644 --- a/crates/autopilot/src/shutdown_controller.rs +++ b/crates/autopilot/src/shutdown_controller.rs @@ -20,22 +20,31 @@ impl ShutdownController { } async fn wait_for_signal(shutdown: ShutdownSignal) { - use tokio::signal; - // On Unix-like systems, we can listen for SIGTERM. #[cfg(unix)] - let mut sigterm = signal::unix::signal(signal::unix::SignalKind::terminate()).unwrap(); - - // On all platforms, we can listen for Ctrl+C. - let ctrl_c = signal::ctrl_c(); - - tokio::select! { - _ = ctrl_c => { - tracing::info!("Received SIGINT"); - }, - _ = sigterm.recv() => { - tracing::info!("Received SIGTERM."); - }, + { + use tokio::{signal, signal::unix}; + // On Unix-like systems, we can listen for SIGTERM. + let mut sigterm = unix::signal(unix::SignalKind::terminate()).unwrap(); + + // Equivalent to SIGINT + let ctrl_c = signal::ctrl_c(); + tokio::select! { + _ = ctrl_c => { + tracing::info!("Received SIGINT"); + }, + _ = sigterm.recv() => { + tracing::info!("Received SIGTERM"); + }, + } + } + #[cfg(not(unix))] + { + tokio::signal::ctrl_c() + .await + .expect("failed to install CTRL+C handler"); + tracing::info!("Received SIGINT"); } + shutdown.shutdown(); } diff --git a/crates/autopilot/src/solvable_orders.rs b/crates/autopilot/src/solvable_orders.rs index 835c875ac0..dd3007b7e1 100644 --- a/crates/autopilot/src/solvable_orders.rs +++ b/crates/autopilot/src/solvable_orders.rs @@ -1,45 +1,46 @@ use { crate::{ boundary::{self, SolvableOrders}, - domain::{self, auction::Price, eth}, + domain::{self, auction::Price}, infra::{self, banned}, }, - alloy::primitives::Address, + account_balances::{BalanceFetching, Query}, + alloy::primitives::{Address, U256}, anyhow::{Context, Result}, - bigdecimal::BigDecimal, - database::order_events::OrderEventLabel, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - futures::{FutureExt, StreamExt, future::join_all, stream::FuturesUnordered}, - indexmap::IndexSet, + bad_tokens::list_based::DenyListedTokens, + database::order_events::{ + OrderEventLabel, + OrderFilterReason::{ + self, + BannedUser, + DustOrder, + InFlight, + InsufficientBalance, + InvalidSignature, + MissingNativePrice, + UnsupportedToken, + }, + }, + futures::FutureExt, itertools::Itertools, model::{ order::{Order, OrderClass, OrderUid}, signature::Signature, time::now_in_epoch_seconds, }, - number::conversions::alloy::u256_to_big_decimal, - primitive_types::{H160, H256, U256}, + price_estimation::{native::to_normalized_price, native_price_cache::NativePriceUpdater}, prometheus::{Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec}, - shared::{ - account_balances::{BalanceFetching, Query}, - bad_token::BadTokenDetecting, - price_estimation::{ - native::{NativePriceEstimating, to_normalized_price}, - native_price_cache::CachingNativePriceEstimator, - }, - remaining_amounts, - signature_validator::{SignatureCheck, SignatureValidating}, - }, + shared::remaining_amounts, std::{ - collections::{BTreeMap, HashMap, HashSet, btree_map::Entry}, + collections::{BTreeMap, HashMap, HashSet}, future::Future, sync::Arc, time::{Duration, Instant}, }, strum::VariantNames, tokio::sync::Mutex, + tracing::instrument, }; - #[derive(prometheus_metric_storage::MetricStorage)] pub struct Metrics { /// Tracks success and failure of the solvable orders cache update task. @@ -80,6 +81,47 @@ pub struct Metrics { auction_market_order_missing_price: IntGauge, } +impl Metrics { + fn get() -> &'static Self { + Metrics::instance(observe::metrics::get_storage_registry()).unwrap() + } + + #[instrument(skip_all)] + fn track_filtered_orders(reason: OrderFilterReason, invalid_orders: &[OrderUid]) { + if invalid_orders.is_empty() { + return; + } + + Metrics::get() + .auction_filtered_orders + .with_label_values(&[reason.as_str()]) + .set(i64::try_from(invalid_orders.len()).unwrap_or(i64::MAX)); + + tracing::debug!( + %reason, + count = invalid_orders.len(), + orders = ?invalid_orders, "filtered orders" + ); + } + + #[instrument(skip_all)] + fn track_orders_in_final_auction(orders: &[&Order]) { + let metrics = Metrics::get(); + metrics.auction_creations.inc(); + + let remaining_counts = orders + .iter() + .counts_by(|order| order.metadata.class.as_ref()); + for class in OrderClass::VARIANTS { + let count = remaining_counts.get(class).copied().unwrap_or_default(); + metrics + .auction_solvable_orders + .with_label_values(&[class]) + .set(i64::try_from(count).unwrap_or(i64::MAX)); + } + } +} + /// Keeps track and updates the set of currently solvable orders. /// For this we also need to keep track of user sell token balances for open /// orders so this is retrievable as well. @@ -91,20 +133,16 @@ pub struct SolvableOrdersCache { persistence: infra::Persistence, banned_users: banned::Users, balance_fetcher: Arc, - bad_token_detector: Arc, + deny_listed_tokens: DenyListedTokens, cache: Mutex>, - native_price_estimator: Arc, - signature_validator: Arc, - metrics: &'static Metrics, - weth: H160, - limit_order_price_factor: BigDecimal, + native_price_estimator: Arc, + weth: Address, protocol_fees: domain::ProtocolFees, cow_amm_registry: cow_amm::Registry, native_price_timeout: Duration, - settlement_contract: H160, + settlement_contract: Address, disable_order_balance_filter: bool, - disable_1271_order_sig_filter: bool, - disable_1271_order_balance_filter: bool, + wrapper_cache: app_data::WrapperCache, } type Balances = HashMap; @@ -121,38 +159,30 @@ impl SolvableOrdersCache { persistence: infra::Persistence, banned_users: banned::Users, balance_fetcher: Arc, - bad_token_detector: Arc, - native_price_estimator: Arc, - signature_validator: Arc, - weth: H160, - limit_order_price_factor: BigDecimal, + deny_listed_tokens: DenyListedTokens, + native_price_estimator: Arc, + weth: Address, protocol_fees: domain::ProtocolFees, cow_amm_registry: cow_amm::Registry, native_price_timeout: Duration, - settlement_contract: H160, + settlement_contract: Address, disable_order_balance_filter: bool, - disable_1271_order_sig_filter: bool, - disable_1271_order_balance_filter: bool, ) -> Arc { Arc::new(Self { min_order_validity_period, persistence, banned_users, balance_fetcher, - bad_token_detector, + deny_listed_tokens, cache: Mutex::new(None), native_price_estimator, - signature_validator, - metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), weth, - limit_order_price_factor, protocol_fees, cow_amm_registry, native_price_timeout, settlement_contract, disable_order_balance_filter, - disable_1271_order_sig_filter, - disable_1271_order_balance_filter, + wrapper_cache: app_data::WrapperCache::new(20_000), }) } @@ -170,6 +200,7 @@ impl SolvableOrdersCache { /// Usually this method is called from update_task. If it isn't, which is /// the case in unit tests, then concurrent calls might overwrite each /// other's results. + #[instrument(skip_all)] pub async fn update(&self, block: u64, store_events: bool) -> Result<()> { let start = Instant::now(); @@ -179,109 +210,119 @@ impl SolvableOrdersCache { let db_solvable_orders = self.get_solvable_orders().await?; tracing::trace!("fetched solvable orders from db"); - let orders = db_solvable_orders + let orders: Vec<&Order> = db_solvable_orders .orders .values() - .cloned() - .collect::>(); + .map(|order| order.as_ref()) + .collect(); + + let mut invalid_order_uids = HashMap::new(); + let mut filtered_order_events: Vec<(OrderUid, OrderFilterReason)> = Vec::new(); - let mut counter = OrderFilterCounter::new(self.metrics, &orders); - let mut invalid_order_uids = HashSet::new(); - let mut filtered_order_events = Vec::new(); + let balance_filter_exempt_orders: HashSet<_> = orders + .iter() + .filter(|order| { + self.wrapper_cache.has_wrappers( + &order.data.app_data, + order.metadata.full_app_data.as_deref(), + ) + }) + .map(|order| order.metadata.uid) + .collect(); - let (balances, orders, cow_amms) = { - let queries = orders.iter().map(Query::from_order).collect::>(); + let (balances, orders, cow_amms, in_flight) = { + let queries = orders + .iter() + .map(|o| Query::from_order(o)) + .collect::>(); tokio::join!( self.fetch_balances(queries), - self.filter_invalid_orders(orders, &mut counter, &mut invalid_order_uids,), + self.filter_invalid_orders(orders, &mut invalid_order_uids), self.timed_future("cow_amm_registry", self.cow_amm_registry.amms()), + self.fetch_in_flight_orders(block), ) }; + // Remove in-flight orders - already won a previous auction, being settled + // on-chain. + let (orders, removed) = filter_out_in_flight_orders(orders, &in_flight); + Metrics::track_filtered_orders(InFlight, &removed); + filtered_order_events.extend(removed.into_iter().map(|uid| (uid, InFlight))); + // It's possible that some orders got marked as invalid due to missing balance + // or so, but the order is perfectly fine if it's in-flight + invalid_order_uids.retain(|uid, _| !in_flight.contains(uid)); + let orders = if self.disable_order_balance_filter { orders } else { - let orders = orders_with_balance( + let (orders, removed) = orders_with_balance( orders, &balances, - self.settlement_contract.into_alloy(), - self.disable_1271_order_balance_filter, + self.settlement_contract, + &balance_filter_exempt_orders, ); - let removed = counter.checkpoint("insufficient_balance", &orders); - invalid_order_uids.extend(removed); + Metrics::track_filtered_orders(InsufficientBalance, &removed); + invalid_order_uids.extend(removed.into_iter().map(|uid| (uid, InsufficientBalance))); - let orders = filter_dust_orders(orders, &balances); - let removed = counter.checkpoint("dust_order", &orders); - filtered_order_events.extend(removed); + let (orders, removed) = filter_dust_orders(orders, &balances); + Metrics::track_filtered_orders(DustOrder, &removed); + filtered_order_events.extend(removed.into_iter().map(|uid| (uid, DustOrder))); orders }; let cow_amm_tokens = cow_amms .iter() - .flat_map(|cow_amm| cow_amm.traded_tokens().iter().map(|t| t.into_legacy())) + .flat_map(|cow_amm| cow_amm.traded_tokens().iter().copied()) .collect::>(); // create auction - let (orders, mut prices) = self + let (orders, removed, mut prices) = self .timed_future( "get_orders_with_native_prices", get_orders_with_native_prices( orders, &self.native_price_estimator, - self.metrics, cow_amm_tokens, self.native_price_timeout, ), ) .await; tracing::trace!("fetched native prices for solvable orders"); - // Add WETH price if it's not already there to support ETH wrap when required. - if let Entry::Vacant(entry) = prices.entry(self.weth) { - let weth_price = self - .timed_future( - "weth_price_fetch", - self.native_price_estimator - .estimate_native_price(self.weth.into_alloy(), Default::default()), - ) - .await - .expect("weth price fetching can never fail"); - let weth_price = to_normalized_price(weth_price) - .expect("weth price can never be outside of U256 range"); - - entry.insert(weth_price); - } + // WETH's native price is 1 by definition — insert it directly to + // support ETH wrap when required. + prices + .entry(self.weth) + .or_insert_with(|| to_normalized_price(1.0).unwrap()); + Metrics::track_filtered_orders(MissingNativePrice, &removed); + filtered_order_events.extend(removed.into_iter().map(|uid| (uid, MissingNativePrice))); - let removed = counter.checkpoint("missing_price", &orders); - filtered_order_events.extend(removed); - - let orders = filter_mispriced_limit_orders(orders, &prices, &self.limit_order_price_factor); - let removed = counter.checkpoint("out_of_market", &orders); - filtered_order_events.extend(removed); - - let removed = counter.record(&orders); - filtered_order_events.extend(removed); + Metrics::track_orders_in_final_auction(&orders); if store_events { - // spawning a background task since `order_events` table insert operation takes - // a while and the result is ignored. - self.persistence.store_order_events( - invalid_order_uids.iter().map(|id| domain::OrderUid(id.0)), - OrderEventLabel::Invalid, - ); - self.persistence.store_order_events( - filtered_order_events - .iter() - .map(|id| domain::OrderUid(id.0)), - OrderEventLabel::Filtered, - ); + self.store_events_by_reason(invalid_order_uids, OrderEventLabel::Invalid); + self.store_events_by_reason(filtered_order_events, OrderEventLabel::Filtered); } - let surplus_capturing_jit_order_owners = cow_amms + let in_flight_owners: HashSet<_> = in_flight + .iter() + .map(|uid| domain::OrderUid(uid.0).owner()) + .collect(); + let surplus_capturing_jit_order_owners: Vec<_> = cow_amms .iter() .filter(|cow_amm| { + // Orders rebalancing cow amms revert when the cow amm does not have exactly the + // state the order was crafted for so having multiple orders in-flight for the + // same cow amm is an issue. Additionally an amm can be rebalanced in many + // different ways which would all result in different order UIDs so filtering + // based on that is not sufficient. That's way we check if there is any order + // in-flight for that amm based on the owner of the order (i.e. the cow amm) and + // then discard that amm altogether for that auction. + if in_flight_owners.contains(cow_amm.address()) { + return false; + } cow_amm.traded_tokens().iter().all(|token| { - let price_exist = prices.contains_key(&token.into_legacy()); + let price_exist = prices.contains_key(token); if !price_exist { tracing::debug!( cow_amm = ?cow_amm.address(), @@ -292,26 +333,26 @@ impl SolvableOrdersCache { price_exist }) }) - .map(|cow_amm| eth::Address::from(cow_amm.address().into_legacy())) - .collect::>(); + .map(|cow_amm| *cow_amm.address()) + .collect(); let auction = domain::RawAuctionData { block, - orders: orders - .into_iter() - .map(|order| { - let quote = db_solvable_orders - .quotes - .get(&order.metadata.uid.into()) - .cloned(); - self.protocol_fees - .apply(order, quote, &surplus_capturing_jit_order_owners) - }) - .collect(), + orders: tracing::info_span!("assemble_orders").in_scope(|| { + orders + .into_iter() + .map(|order| { + let quote = db_solvable_orders + .quotes + .get(&order.metadata.uid.into()) + .map(|quote| quote.as_ref().clone()); + self.protocol_fees + .apply(order, quote, &surplus_capturing_jit_order_owners) + }) + .collect() + }), prices: prices .into_iter() - .map(|(key, value)| { - Price::try_new(value.into()).map(|price| (eth::TokenAddress(key), price)) - }) + .map(|(key, value)| Price::try_new(value.into()).map(|price| (key.into(), price))) .collect::>()?, surplus_capturing_jit_order_owners, }; @@ -322,12 +363,23 @@ impl SolvableOrdersCache { }); tracing::debug!(%block, "updated current auction cache"); - self.metrics + Metrics::get() .auction_update_total_time .observe(start.elapsed().as_secs_f64()); Ok(()) } + async fn fetch_in_flight_orders(&self, block: u64) -> HashSet { + self.persistence + .fetch_in_flight_orders(block) + .await + .inspect_err(|err| tracing::warn!(?err, "failed to fetch in-flight orders")) + .unwrap_or_default() + .into_iter() + .map(|uid| OrderUid(uid.0)) + .collect() + } + async fn fetch_balances(&self, queries: Vec) -> HashMap { let fetched_balances = self .timed_future( @@ -395,44 +447,44 @@ impl SolvableOrdersCache { } /// Executed orders filtering in parallel. - async fn filter_invalid_orders( + #[instrument(skip_all)] + async fn filter_invalid_orders<'a>( &self, - mut orders: Vec, - counter: &mut OrderFilterCounter, - invalid_order_uids: &mut HashSet, - ) -> Vec { - let filter_invalid_signatures = find_invalid_signature_orders( - &orders, - self.signature_validator.as_ref(), - self.disable_1271_order_sig_filter, - ); + mut orders: Vec<&'a Order>, + invalid_order_uids: &mut HashMap, + ) -> Vec<&'a Order> { + let presignature_pending_orders = find_presignature_pending_orders(&orders); - let (banned_user_orders, invalid_signature_orders, unsupported_token_orders) = tokio::join!( - self.timed_future( + let unsupported_token_orders = find_unsupported_tokens(&orders, &self.deny_listed_tokens); + let banned_user_orders = self + .timed_future( "banned_user_filtering", - find_banned_user_orders(&orders, &self.banned_users) - ), - self.timed_future("invalid_signature_filtering", filter_invalid_signatures), - self.timed_future( - "unsupported_token_filtering", - find_unsupported_tokens(&orders, self.bad_token_detector.clone()) - ), - ); + find_banned_user_orders(&orders, &self.banned_users), + ) + .await; tracing::trace!("filtered invalid orders"); - counter.checkpoint_by_invalid_orders("banned_user", &banned_user_orders); - counter.checkpoint_by_invalid_orders("invalid_signature", &invalid_signature_orders); - counter.checkpoint_by_invalid_orders("unsupported_token", &unsupported_token_orders); - invalid_order_uids.extend(banned_user_orders); - invalid_order_uids.extend(invalid_signature_orders); - invalid_order_uids.extend(unsupported_token_orders); + Metrics::track_filtered_orders(BannedUser, &banned_user_orders); + Metrics::track_filtered_orders(InvalidSignature, &presignature_pending_orders); + Metrics::track_filtered_orders(UnsupportedToken, &unsupported_token_orders); + invalid_order_uids.extend(banned_user_orders.into_iter().map(|uid| (uid, BannedUser))); + invalid_order_uids.extend( + presignature_pending_orders + .into_iter() + .map(|uid| (uid, InvalidSignature)), + ); + invalid_order_uids.extend( + unsupported_token_orders + .into_iter() + .map(|uid| (uid, UnsupportedToken)), + ); - orders.retain(|order| !invalid_order_uids.contains(&order.metadata.uid)); + orders.retain(|order| !invalid_order_uids.contains_key(&order.metadata.uid)); orders } pub fn track_auction_update(&self, result: &str) { - self.metrics + Metrics::get() .auction_update .with_label_values(&[result]) .inc(); @@ -440,18 +492,36 @@ impl SolvableOrdersCache { /// Runs the future and collects runtime metrics. async fn timed_future(&self, label: &str, fut: impl Future) -> T { - let _timer = self - .metrics + let _timer = Metrics::get() .auction_update_stage_time .with_label_values(&[label]) .start_timer(); fut.await } + + fn store_events_by_reason( + &self, + orders: impl IntoIterator, + label: OrderEventLabel, + ) { + let mut by_reason: HashMap> = HashMap::new(); + for (uid, reason) in orders { + by_reason.entry(reason).or_default().push(uid); + } + for (reason, uids) in by_reason { + self.persistence.store_order_events_owned( + uids, + |uid| domain::OrderUid(uid.0), + label, + Some(reason), + ); + } + } } /// Finds all orders whose owners or receivers are in the set of "banned" /// users. -async fn find_banned_user_orders(orders: &[Order], banned_users: &banned::Users) -> Vec { +async fn find_banned_user_orders(orders: &[&Order], banned_users: &banned::Users) -> Vec { let banned = banned_users .banned( orders @@ -471,12 +541,12 @@ async fn find_banned_user_orders(orders: &[Order], banned_users: &banned::Users) } async fn get_native_prices( - tokens: &[H160], - native_price_estimator: &CachingNativePriceEstimator, + tokens: HashSet
, + native_price_estimator: &NativePriceUpdater, timeout: Duration, -) -> BTreeMap { +) -> BTreeMap { native_price_estimator - .estimate_native_prices_with_timeout(tokens, timeout) + .update_tokens_and_fetch_prices(tokens, timeout) .await .into_iter() .flat_map(|(token, result)| { @@ -486,73 +556,40 @@ async fn get_native_prices( .collect() } -/// Finds unsigned PreSign and EIP-1271 orders whose signatures are no longer -/// validating. -async fn find_invalid_signature_orders( - orders: &[Order], - signature_validator: &dyn SignatureValidating, - disable_1271_order_sig_filter: bool, -) -> Vec { - let mut invalid_orders = vec![]; - let mut signature_check_futures = FuturesUnordered::new(); - - for order in orders { - if let Signature::Eip1271(_) = &order.signature - && disable_1271_order_sig_filter - { - continue; - } - if matches!( - order.metadata.status, - model::order::OrderStatus::PresignaturePending - ) { - invalid_orders.push(order.metadata.uid); - continue; - } - - if let Signature::Eip1271(signature) = &order.signature { - signature_check_futures.push(async { - let (H256(hash), signer, _) = order.metadata.uid.parts(); - match signature_validator - .validate_signature(SignatureCheck { - signer, - hash, - signature: signature.clone(), - interactions: order.interactions.pre.clone(), - // TODO delete balance and signature logic in the autopilot - // altogether - balance_override: None, - }) - .await - { - Ok(_) => None, - Err(_) => Some(order.metadata.uid), - } - }); - } - } - - while let Some(res) = signature_check_futures.next().await { - if let Some(invalid_order_uid) = res { - invalid_orders.push(invalid_order_uid); - } - } - - invalid_orders +/// Finds orders with pending presignatures. EIP-1271 signature validation is +/// skipped entirely - the driver validates signatures before settlement. +fn find_presignature_pending_orders(orders: &[&Order]) -> Vec { + orders + .iter() + .filter(|order| { + matches!( + order.metadata.status, + model::order::OrderStatus::PresignaturePending + ) + }) + .map(|order| order.metadata.uid) + .collect() } /// Removes orders that can't possibly be settled because there isn't enough /// balance. -fn orders_with_balance( - mut orders: Vec, +#[instrument(skip_all)] +fn orders_with_balance<'a>( + mut orders: Vec<&'a Order>, balances: &Balances, settlement_contract: Address, - disable_1271_order_balance_filter: bool, -) -> Vec { + filter_bypass_orders: &HashSet, +) -> (Vec<&'a Order>, Vec) { // Prefer newer orders over older ones. orders.sort_by_key(|order| std::cmp::Reverse(order.metadata.creation_date)); - orders.retain(|order| { - if disable_1271_order_balance_filter && matches!(order.signature, Signature::Eip1271(_)) { + let mut filtered_orders = vec![]; + let keep = |order: &Order| { + // Skip balance check for all EIP-1271 orders (they can rely on pre-interactions + // to unlock funds) or orders with wrappers (wrappers produce the required + // balance at settlement time). + if matches!(order.signature, Signature::Eip1271(_)) + || filter_bypass_orders.contains(&order.metadata.uid) + { return true; } @@ -570,7 +607,7 @@ fn orders_with_balance( Some(balance) => *balance, }; - if order.data.partially_fillable && balance >= 1.into() { + if order.data.partially_fillable && balance >= U256::ONE { return true; } @@ -578,15 +615,28 @@ fn orders_with_balance( None => return false, Some(balance) => balance, }; - balance.into_alloy() >= needed_balance + balance >= needed_balance + }; + + orders.retain(|order| { + if keep(order) { + true + } else { + filtered_orders.push(order.metadata.uid); + false + } }); - orders + (orders, filtered_orders) } /// Filters out dust orders i.e. partially fillable orders that, when scaled /// have a 0 buy or sell amount. -fn filter_dust_orders(mut orders: Vec, balances: &Balances) -> Vec { - orders.retain(|order| { +fn filter_dust_orders<'a>( + mut orders: Vec<&'a Order>, + balances: &Balances, +) -> (Vec<&'a Order>, Vec) { + let mut removed = vec![]; + let keep = |order: &Order| { if !order.data.partially_fillable { return true; } @@ -604,331 +654,118 @@ fn filter_dust_orders(mut orders: Vec, balances: &Balances) -> Vec }; let (Ok(sell_amount), Ok(buy_amount)) = ( - remaining.remaining(order.data.sell_amount.into_legacy()), - remaining.remaining(order.data.buy_amount.into_legacy()), + remaining.remaining(order.data.sell_amount), + remaining.remaining(order.data.buy_amount), ) else { return false; }; !sell_amount.is_zero() && !buy_amount.is_zero() + }; + + orders.retain(|order| { + if keep(order) { + true + } else { + removed.push(order.metadata.uid); + false + } }); - orders + (orders, removed) } -async fn get_orders_with_native_prices( - orders: Vec, - native_price_estimator: &CachingNativePriceEstimator, - metrics: &Metrics, - additional_tokens: impl IntoIterator, +#[instrument(skip_all)] +async fn get_orders_with_native_prices<'a>( + orders: Vec<&'a Order>, + native_price_estimator: &NativePriceUpdater, + additional_tokens: impl IntoIterator, timeout: Duration, -) -> (Vec, BTreeMap) { +) -> ( + Vec<&'a Order>, + Vec, + BTreeMap, +) { let traded_tokens = orders .iter() - .flat_map(|order| { - [ - order.data.sell_token.into_legacy(), - order.data.buy_token.into_legacy(), - ] - }) + .flat_map(|order| [order.data.sell_token, order.data.buy_token]) .chain(additional_tokens) .collect::>(); - let prices = get_native_prices( - &traded_tokens.into_iter().collect::>(), - native_price_estimator, - timeout, - ) - .await; + let prices = get_native_prices(traded_tokens, native_price_estimator, timeout).await; // Filter orders so that we only return orders that have prices - let mut filtered_market_orders = 0_i64; - let (usable, filtered): (Vec<_>, Vec<_>) = orders.into_iter().partition(|order| { - let (t0, t1) = (&order.data.sell_token, &order.data.buy_token); - match (prices.get(&t0.into_legacy()), prices.get(&t1.into_legacy())) { - (Some(_), Some(_)) => true, - _ => { - filtered_market_orders += i64::from(order.metadata.class == OrderClass::Market); - false - } + let mut removed_market_orders = 0_i64; + let mut removed_orders = vec![]; + let mut orders = orders; + orders.retain(|order| { + let both_prices_present = prices.contains_key(&order.data.sell_token) + && prices.contains_key(&order.data.buy_token); + if both_prices_present { + true + } else { + removed_orders.push(order.metadata.uid); + removed_market_orders += i64::from(order.metadata.class == OrderClass::Market); + false } }); - let tokens_by_priority = prioritize_missing_prices(filtered); - native_price_estimator.replace_high_priority(tokens_by_priority); - // Record separate metrics just for missing native token prices for market - // orders, as they should be prioritized. - metrics + Metrics::get() .auction_market_order_missing_price - .set(filtered_market_orders); + .set(removed_market_orders); - (usable, prices) + (orders, removed_orders, prices) } -/// Computes which missing native prices are the most urgent to fetch. -/// Prices for recent orders have the highest priority because those are most -/// likely market orders which users expect to get settled ASAP. -/// For the remaining orders we prioritize token prices that are needed the most -/// often. That way we have the chance to make a majority of orders solvable -/// with very few fetch requests. -fn prioritize_missing_prices(mut orders: Vec) -> IndexSet { - /// How old an order can be at most to be considered a market order. - const MARKET_ORDER_AGE: chrono::Duration = chrono::Duration::minutes(30); - let now = chrono::Utc::now(); - - // newer orders at the start - orders.sort_by_key(|o| std::cmp::Reverse(o.metadata.creation_date)); - - let mut high_priority_tokens = IndexSet::new(); - let mut most_used_tokens = HashMap::::new(); - for order in orders { - let sell_token = order.data.sell_token.into_legacy(); - let buy_token = order.data.buy_token.into_legacy(); - let is_market = now.signed_duration_since(order.metadata.creation_date) <= MARKET_ORDER_AGE; - - if is_market { - // already correct priority because orders were sorted by creation_date - high_priority_tokens.extend([sell_token, buy_token]); - } else { - // count how often tokens are used to prioritize popular tokens - *most_used_tokens.entry(sell_token).or_default() += 1; - *most_used_tokens.entry(buy_token).or_default() += 1; - } - } - - // popular tokens at the start - let most_used_tokens = most_used_tokens - .into_iter() - .sorted_by_key(|entry| std::cmp::Reverse(entry.1)) - .map(|(token, _)| token); - - high_priority_tokens.extend(most_used_tokens); - high_priority_tokens -} - -async fn find_unsupported_tokens( - orders: &[Order], - bad_token: Arc, +fn find_unsupported_tokens( + orders: &[&Order], + deny_listed_tokens: &DenyListedTokens, ) -> Vec { - let bad_tokens = join_all( - orders - .iter() - .flat_map(|o| o.data.token_pair().into_iter().flatten()) - .unique() - .map(|token| { - let bad_token = bad_token.clone(); - async move { - match bad_token.detect(token).await { - Ok(quality) => (!quality.is_good()).then_some(token), - Err(err) => { - tracing::warn!( - ?token, - ?err, - "unable to determine token quality, assume good" - ); - Some(token) - } - } - } - }), - ) - .await - .into_iter() - .flatten() - .collect::>(); - orders .iter() .filter_map(|order| { - order - .data - .token_pair() - .into_iter() - .flatten() - .any(|token| bad_tokens.contains(&token)) + [&order.data.buy_token, &order.data.sell_token] + .iter() + .any(|token| deny_listed_tokens.contains(token)) .then_some(order.metadata.uid) }) .collect() } -/// Filter out limit orders which are far enough outside the estimated native -/// token price. -fn filter_mispriced_limit_orders( - mut orders: Vec, - prices: &BTreeMap, - price_factor: &BigDecimal, -) -> Vec { +fn filter_out_in_flight_orders<'a>( + mut orders: Vec<&'a Order>, + in_flight: &HashSet, +) -> (Vec<&'a Order>, Vec) { + let mut removed = vec![]; orders.retain(|order| { - if !order.is_limit_order() { - return true; + if in_flight.contains(&order.metadata.uid) { + removed.push(order.metadata.uid); + false + } else { + true } - - let sell_price = prices - .get(&order.data.sell_token.into_legacy()) - .unwrap() - .into_alloy(); - let buy_price = prices - .get(&order.data.buy_token.into_legacy()) - .unwrap() - .into_alloy(); - - // Convert the sell and buy price to the native token (ETH) and make sure that - // sell is higher than buy with the configurable price factor. - let (sell_native, buy_native) = match ( - order.data.sell_amount.checked_mul(sell_price), - order.data.buy_amount.checked_mul(buy_price), - ) { - (Some(sell), Some(buy)) => (sell, buy), - _ => { - tracing::warn!( - order_uid = %order.metadata.uid, - "limit order overflow computing native amounts", - ); - return false; - } - }; - - let sell_native = u256_to_big_decimal(&sell_native); - let buy_native = u256_to_big_decimal(&buy_native); - - sell_native >= buy_native * price_factor }); - orders -} - -/// Order filtering state for recording filtered orders over the course of -/// building an auction. -struct OrderFilterCounter { - metrics: &'static Metrics, - - /// Mapping of remaining order UIDs to their classes. - orders: HashMap, - /// Running tally for counts of filtered orders. - counts: HashMap, -} - -type Reason = &'static str; - -impl OrderFilterCounter { - fn new(metrics: &'static Metrics, orders: &[Order]) -> Self { - // Eagerly store the candidate orders. This ensures that that gauge is - // always up to date even if there are errors in the auction building - // process. - let initial_counts = orders - .iter() - .counts_by(|order| order.metadata.class.as_ref()); - for class in OrderClass::VARIANTS { - let count = initial_counts.get(class).copied().unwrap_or_default(); - metrics - .auction_candidate_orders - .with_label_values(&[class]) - .set(i64::try_from(count).unwrap_or(i64::MAX)); - } - - Self { - metrics, - orders: orders - .iter() - .map(|order| (order.metadata.uid, order.metadata.class)) - .collect(), - counts: HashMap::new(), - } - } - - /// Creates a new checkpoint from the current remaining orders. - fn checkpoint(&mut self, reason: Reason, orders: &[Order]) -> Vec { - let filtered_orders = orders - .iter() - .fold(self.orders.clone(), |mut order_uids, order| { - order_uids.remove(&order.metadata.uid); - order_uids - }); - - *self.counts.entry(reason).or_default() += filtered_orders.len(); - for order_uid in filtered_orders.keys() { - self.orders.remove(order_uid).unwrap(); - } - if !filtered_orders.is_empty() { - tracing::debug!( - %reason, - count = filtered_orders.len(), - orders = ?filtered_orders, "filtered orders" - ); - } - filtered_orders.into_keys().collect() - } - - /// Creates a new checkpoint based on the found invalid orders. - fn checkpoint_by_invalid_orders(&mut self, reason: Reason, invalid_orders: &[OrderUid]) { - if invalid_orders.is_empty() { - return; - } - - let mut counter = 0; - for order_uid in invalid_orders { - if self.orders.remove(order_uid).is_some() { - counter += 1; - } - } - *self.counts.entry(reason).or_default() += counter; - if counter > 0 { - tracing::debug!( - %reason, - count = invalid_orders.len(), - orders = ?invalid_orders, "filtered orders" - ); - } - } - - /// Records the filter counter to metrics. - /// If there are orders that have been filtered out since the last - /// checkpoint these orders will get recorded with the readon "other". - /// Returns these catch-all orders. - fn record(mut self, orders: &[Order]) -> Vec { - let removed = self.checkpoint("other", orders); - - self.metrics.auction_creations.inc(); - - let remaining_counts = self.orders.iter().counts_by(|(_, class)| class.as_ref()); - for class in OrderClass::VARIANTS { - let count = remaining_counts.get(class).copied().unwrap_or_default(); - self.metrics - .auction_solvable_orders - .with_label_values(&[class]) - .set(i64::try_from(count).unwrap_or(i64::MAX)); - } - - for (reason, count) in self.counts { - self.metrics - .auction_filtered_orders - .with_label_values(&[reason]) - .set(i64::try_from(count).unwrap_or(i64::MAX)); - } - - removed - } + (orders, removed) } #[cfg(test)] mod tests { use { super::*, - alloy::primitives::Address, + alloy::primitives::{Address, B256}, + bad_tokens::list_based::DenyListedTokens, futures::FutureExt, maplit::{btreemap, hashset}, - mockall::predicate::eq, - model::{ - interaction::InteractionData, - order::{Interactions, OrderBuilder, OrderData, OrderMetadata, OrderUid}, - }, - primitive_types::H160, - shared::{ - bad_token::list_based::ListBasedDetector, - price_estimation::{ - HEALTHY_PRICE_ESTIMATION_TIME, - PriceEstimationError, - native::MockNativePriceEstimating, + model::order::{OrderBuilder, OrderData, OrderMetadata, OrderUid}, + price_estimation::{ + HEALTHY_PRICE_ESTIMATION_TIME, + PriceEstimationError, + native::MockNativePriceEstimating, + native_price_cache::{ + ApproximationToken, + Cache, + CachingNativePriceEstimator, + NativePriceUpdater, }, - signature_validator::{MockSignatureValidating, SignatureValidationError}, }, }; @@ -938,19 +775,23 @@ mod tests { let token2 = Address::repeat_byte(2); let token3 = Address::repeat_byte(3); - let orders = vec![ - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token2) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token3) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), + let orders = [ + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token2) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token3) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), ]; let mut native_price_estimator = MockNativePriceEstimating::new(); @@ -969,32 +810,31 @@ mod tests { .withf(move |token, _| *token == token3) .returning(|_, _| async { Ok(0.25) }.boxed()); - let native_price_estimator = CachingNativePriceEstimator::new( + let cache = Cache::new(Duration::from_secs(10), Default::default()); + let caching_estimator = CachingNativePriceEstimator::new( Box::new(native_price_estimator), - Duration::from_secs(10), - Duration::MAX, - None, - Default::default(), + cache, 3, Default::default(), HEALTHY_PRICE_ESTIMATION_TIME, ); - let metrics = Metrics::instance(observe::metrics::get_storage_registry()).unwrap(); + let native_price_estimator = + NativePriceUpdater::new(caching_estimator, Duration::MAX, Default::default()); - let (filtered_orders, prices) = get_orders_with_native_prices( - orders.clone(), + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let (filtered_orders, _removed, prices) = get_orders_with_native_prices( + orders_ref, &native_price_estimator, - metrics, vec![], Duration::from_millis(100), ) .await; - assert_eq!(filtered_orders, [orders[1].clone()]); + assert_eq!(filtered_orders, [orders[1].as_ref()]); assert_eq!( prices, btreemap! { - token1.into_legacy() => U256::from(2_000_000_000_000_000_000_u128), - token3.into_legacy() => U256::from(250_000_000_000_000_000_u128), + token1 => alloy::primitives::U256::from(2_000_000_000_000_000_000_u128), + token3 => alloy::primitives::U256::from(250_000_000_000_000_000_u128), } ); } @@ -1007,31 +847,39 @@ mod tests { let token4 = Address::repeat_byte(4); let token5 = Address::repeat_byte(5); - let orders = vec![ - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token2) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), - OrderBuilder::default() - .with_sell_token(token2) - .with_buy_token(token3) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token3) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), - OrderBuilder::default() - .with_sell_token(token2) - .with_buy_token(token4) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), + let orders = [ + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token2) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token2) + .with_buy_token(token3) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token3) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token2) + .with_buy_token(token4) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), ]; let mut native_price_estimator = MockNativePriceEstimating::new(); @@ -1060,52 +908,53 @@ mod tests { .withf(move |token, _| *token == token5) .returning(|_, _| async { Ok(5.) }.boxed()); - let native_price_estimator = CachingNativePriceEstimator::new( + let cache = Cache::new(Duration::from_secs(10), Default::default()); + let caching_estimator = CachingNativePriceEstimator::new( Box::new(native_price_estimator), - Duration::from_secs(10), - Duration::MAX, - None, - Default::default(), + cache, 1, Default::default(), HEALTHY_PRICE_ESTIMATION_TIME, ); - let metrics = Metrics::instance(observe::metrics::get_storage_registry()).unwrap(); + let native_price_estimator = NativePriceUpdater::new( + caching_estimator, + Duration::from_millis(5), + Default::default(), + ); - // We'll have no native prices in this call. But this call will cause a - // background task to fetch the missing prices so we'll have them in the - // next call. - let (filtered_orders, prices) = get_orders_with_native_prices( - orders.clone(), + // We'll have no native prices in this call. But set_tokens_to_update + // will cause the background task to fetch them in the next cycle. + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let (alive_orders, _removed_orders, prices) = get_orders_with_native_prices( + orders_ref, &native_price_estimator, - metrics, - vec![token5.into_legacy()], + vec![token5], Duration::ZERO, ) .await; - assert!(filtered_orders.is_empty()); + assert!(alive_orders.is_empty()); assert!(prices.is_empty()); - // Wait for native prices to get fetched. - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + // Wait for native prices to get fetched by the background task. + tokio::time::sleep(tokio::time::Duration::from_millis(30)).await; // Now we have all the native prices we want. - let (filtered_orders, prices) = get_orders_with_native_prices( - orders.clone(), + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let (alive_orders, _removed_orders, prices) = get_orders_with_native_prices( + orders_ref, &native_price_estimator, - metrics, - vec![token5.into_legacy()], + vec![token5], Duration::ZERO, ) .await; - assert_eq!(filtered_orders, [orders[2].clone()]); + assert_eq!(alive_orders, [orders[2].as_ref()]); assert_eq!( prices, btreemap! { - token1.into_legacy() => U256::from(2_000_000_000_000_000_000_u128), - token3.into_legacy() => U256::from(250_000_000_000_000_000_u128), - token5.into_legacy() => U256::from(5_000_000_000_000_000_000_u128), + token1 => alloy::primitives::U256::from(2_000_000_000_000_000_000_u128), + token3 => alloy::primitives::U256::from(250_000_000_000_000_000_u128), + token5 => alloy::primitives::U256::from(5_000_000_000_000_000_000_u128), } ); } @@ -1116,28 +965,34 @@ mod tests { let token2 = Address::repeat_byte(2); let token3 = Address::repeat_byte(3); - let token_approx1 = H160([4; 20]); - let token_approx2 = H160([5; 20]); - - let orders = vec![ - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token2) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token2) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token3) - .with_buy_amount(alloy::primitives::U256::ONE) - .with_sell_amount(alloy::primitives::U256::ONE) - .build(), + let token_approx1 = Address::repeat_byte(4); + let token_approx2 = Address::repeat_byte(5); + + let orders = [ + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token2) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token2) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token3) + .with_buy_amount(alloy::primitives::U256::ONE) + .with_sell_amount(alloy::primitives::U256::ONE) + .build(), + ), ]; let mut native_price_estimator = MockNativePriceEstimating::new(); @@ -1149,45 +1004,49 @@ mod tests { native_price_estimator .expect_estimate_native_price() .times(1) - .withf(move |token, _| *token == token_approx1.into_alloy()) + .withf(move |token, _| *token == token_approx1) .returning(|_, _| async { Ok(40.) }.boxed()); native_price_estimator .expect_estimate_native_price() .times(1) - .withf(move |token, _| *token == token_approx2.into_alloy()) + .withf(move |token, _| *token == token_approx2) .returning(|_, _| async { Ok(50.) }.boxed()); - let native_price_estimator = CachingNativePriceEstimator::new( + let cache = Cache::new(Duration::from_secs(10), Default::default()); + let caching_estimator = CachingNativePriceEstimator::new( Box::new(native_price_estimator), - Duration::from_secs(10), - Duration::MAX, - None, - Default::default(), + cache, 3, // Set to use native price approximations for the following tokens HashMap::from([ - (token1.into_legacy(), token_approx1), - (token2.into_legacy(), token_approx2), + (token1, ApproximationToken::same_decimals(token_approx1)), + (token2, ApproximationToken::same_decimals(token_approx2)), ]), HEALTHY_PRICE_ESTIMATION_TIME, ); - let metrics = Metrics::instance(observe::metrics::get_storage_registry()).unwrap(); + let native_price_estimator = + NativePriceUpdater::new(caching_estimator, Duration::MAX, Default::default()); - let (filtered_orders, prices) = get_orders_with_native_prices( - orders.clone(), + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let (alive_orders, _removed_orders, prices) = get_orders_with_native_prices( + orders_ref, &native_price_estimator, - metrics, vec![], Duration::from_secs(10), ) .await; - assert_eq!(filtered_orders, orders); + assert!( + alive_orders + .iter() + .copied() + .eq(orders.iter().map(Arc::as_ref)) + ); assert_eq!( prices, btreemap! { - token1.into_legacy() => U256::from(40_000_000_000_000_000_000_u128), - token2.into_legacy() => U256::from(50_000_000_000_000_000_000_u128), - token3.into_legacy() => U256::from(3_000_000_000_000_000_000_u128), + token1 => alloy::primitives::U256::from(40_000_000_000_000_000_000_u128), + token2 => alloy::primitives::U256::from(50_000_000_000_000_000_000_u128), + token3 => alloy::primitives::U256::from(3_000_000_000_000_000_000_u128), } ); } @@ -1196,33 +1055,36 @@ mod tests { async fn filters_banned_users() { let banned_users = hashset!(Address::from([0xba; 20]), Address::from([0xbb; 20])); let orders = [ - H160([1; 20]), - H160([1; 20]), - H160([0xba; 20]), - H160([2; 20]), - H160([0xba; 20]), - H160([0xbb; 20]), - H160([3; 20]), + Address::repeat_byte(1), + Address::repeat_byte(1), + Address::repeat_byte(0xba), + Address::repeat_byte(2), + Address::repeat_byte(0xba), + Address::repeat_byte(0xbb), + Address::repeat_byte(3), ] .into_iter() .enumerate() - .map(|(i, owner)| Order { - metadata: OrderMetadata { - owner: owner.into_alloy(), - uid: OrderUid([i as u8; 56]), - ..Default::default() - }, - data: OrderData { - buy_amount: alloy::primitives::U256::ONE, - sell_amount: alloy::primitives::U256::ONE, + .map(|(i, owner)| { + Arc::new(Order { + metadata: OrderMetadata { + owner, + uid: OrderUid([i as u8; 56]), + ..Default::default() + }, + data: OrderData { + buy_amount: alloy::primitives::U256::ONE, + sell_amount: alloy::primitives::U256::ONE, + ..Default::default() + }, ..Default::default() - }, - ..Default::default() + }) }) .collect::>(); + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); let banned_user_orders = find_banned_user_orders( - &orders, + &orders_ref, &order_validation::banned::Users::from_set(banned_users), ) .await; @@ -1232,120 +1094,41 @@ mod tests { ); } - #[tokio::test] - async fn filters_invalidated_eip1271_signatures() { - let orders = vec![ - Order { + #[test] + fn finds_presignature_pending_orders() { + let presign_uid = OrderUid::from_parts(B256::repeat_byte(1), Address::repeat_byte(11), 1); + let orders = [ + // PresignaturePending order - should be found + Arc::new(Order { metadata: OrderMetadata { - uid: OrderUid::from_parts(H256([1; 32]), H160([11; 20]), 1), + uid: presign_uid, + status: model::order::OrderStatus::PresignaturePending, ..Default::default() }, - interactions: Interactions { - pre: vec![InteractionData { - target: Address::from_slice(&[0xe1; 20]), - value: alloy::primitives::U256::ZERO, - call_data: vec![1, 2], - }], - post: vec![InteractionData { - target: Address::from_slice(&[0xe2; 20]), - value: alloy::primitives::U256::ZERO, - call_data: vec![3, 4], - }], - }, ..Default::default() - }, - Order { + }), + // EIP-1271 order - not PresignaturePending + Arc::new(Order { metadata: OrderMetadata { - uid: OrderUid::from_parts(H256([2; 32]), H160([22; 20]), 2), + uid: OrderUid::from_parts(B256::repeat_byte(2), Address::repeat_byte(22), 2), ..Default::default() }, signature: Signature::Eip1271(vec![2, 2]), - interactions: Interactions { - pre: vec![InteractionData { - target: Address::from_slice(&[0xe3; 20]), - value: alloy::primitives::U256::ZERO, - call_data: vec![5, 6], - }], - post: vec![InteractionData { - target: Address::from_slice(&[0xe4; 20]), - value: alloy::primitives::U256::ZERO, - call_data: vec![7, 9], - }], - }, - ..Default::default() - }, - Order { - metadata: OrderMetadata { - uid: OrderUid::from_parts(H256([3; 32]), H160([33; 20]), 3), - ..Default::default() - }, ..Default::default() - }, - Order { - metadata: OrderMetadata { - uid: OrderUid::from_parts(H256([4; 32]), H160([44; 20]), 4), - ..Default::default() - }, - signature: Signature::Eip1271(vec![4, 4, 4, 4]), - ..Default::default() - }, - Order { + }), + // Regular order - not PresignaturePending + Arc::new(Order { metadata: OrderMetadata { - uid: OrderUid::from_parts(H256([5; 32]), H160([55; 20]), 5), + uid: OrderUid::from_parts(B256::repeat_byte(3), Address::repeat_byte(33), 3), ..Default::default() }, - signature: Signature::Eip1271(vec![5, 5, 5, 5, 5]), ..Default::default() - }, + }), ]; - let mut signature_validator = MockSignatureValidating::new(); - signature_validator - .expect_validate_signature() - .with(eq(SignatureCheck { - signer: H160([22; 20]), - hash: [2; 32], - signature: vec![2, 2], - interactions: vec![InteractionData { - target: Address::from_slice(&[0xe3; 20]), - value: alloy::primitives::U256::ZERO, - call_data: vec![5, 6], - }], - balance_override: None, - })) - .returning(|_| Ok(())); - signature_validator - .expect_validate_signature() - .with(eq(SignatureCheck { - signer: H160([44; 20]), - hash: [4; 32], - signature: vec![4, 4, 4, 4], - interactions: vec![], - balance_override: None, - })) - .returning(|_| Err(SignatureValidationError::Invalid)); - signature_validator - .expect_validate_signature() - .with(eq(SignatureCheck { - signer: H160([55; 20]), - hash: [5; 32], - signature: vec![5, 5, 5, 5, 5], - interactions: vec![], - balance_override: None, - })) - .returning(|_| Ok(())); - - let invalid_signature_orders = - find_invalid_signature_orders(&orders, &signature_validator, false).await; - assert_eq!( - invalid_signature_orders, - vec![OrderUid::from_parts(H256([4; 32]), H160([44; 20]), 4)] - ); - let invalid_signature_orders_with_1271_filter_disabled = - find_invalid_signature_orders(&orders, &signature_validator, true).await; - // if we switch off the 1271 filter no orders should be returned as containing - // invalid signatures - assert_eq!(invalid_signature_orders_with_1271_filter_disabled, vec![]); + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let pending_orders = find_presignature_pending_orders(&orders_ref); + assert_eq!(pending_orders, vec![presign_uid]); } #[test] @@ -1353,95 +1136,41 @@ mod tests { let token0 = Address::with_last_byte(0); let token1 = Address::with_last_byte(1); let token2 = Address::with_last_byte(2); - let bad_token = Arc::new(ListBasedDetector::deny_list(vec![token0])); - let orders = vec![ - OrderBuilder::default() - .with_sell_token(token0) - .with_buy_token(token1) - .build(), - OrderBuilder::default() - .with_sell_token(token1) - .with_buy_token(token2) - .build(), - OrderBuilder::default() - .with_sell_token(token0) - .with_buy_token(token2) - .build(), + let deny_listed_tokens = DenyListedTokens::new(vec![token0]); + let orders = [ + Arc::new( + OrderBuilder::default() + .with_sell_token(token0) + .with_buy_token(token1) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token1) + .with_buy_token(token2) + .build(), + ), + Arc::new( + OrderBuilder::default() + .with_sell_token(token0) + .with_buy_token(token2) + .build(), + ), ]; - let unsupported_tokens_orders = find_unsupported_tokens(&orders, bad_token) - .now_or_never() - .unwrap(); + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let unsupported_tokens_orders = find_unsupported_tokens(&orders_ref, &deny_listed_tokens); assert_eq!( unsupported_tokens_orders, [orders[0].metadata.uid, orders[2].metadata.uid] ); } - #[test] - fn filters_mispriced_orders() { - let sell_token = H160([1; 20]); - let buy_token = H160([2; 20]); - - // Prices are set such that 1 sell token is equivalent to 2 buy tokens. - // Additionally, they are scaled to large values to allow for overflows. - let prices = btreemap! { - sell_token => U256::MAX / 100, - buy_token => U256::MAX / 200, - }; - let price_factor = "0.95".parse().unwrap(); - - let order = |sell_amount: u8, buy_amount: u8| Order { - data: OrderData { - sell_token: sell_token.into_alloy(), - sell_amount: alloy::primitives::U256::from(sell_amount), - buy_token: buy_token.into_alloy(), - buy_amount: alloy::primitives::U256::from(buy_amount), - ..Default::default() - }, - metadata: OrderMetadata { - class: OrderClass::Limit, - ..Default::default() - }, - ..Default::default() - }; - - let valid_orders = vec![ - // Reasonably priced order, doesn't get filtered. - order(100, 200), - // Slightly out of price order, doesn't get filtered. - order(10, 21), - ]; - - let invalid_orders = vec![ - // Out of price order gets filtered out. - order(10, 100), - // Overflow sell value gets filtered. - order(255, 1), - // Overflow buy value gets filtered. - order(100, 255), - ]; - - let orders = [valid_orders.clone(), invalid_orders].concat(); - assert_eq!( - filter_mispriced_limit_orders(orders, &prices, &price_factor), - valid_orders, - ); - - let mut order = order(10, 21); - order.data.partially_fillable = true; - let orders = vec![order]; - assert_eq!( - filter_mispriced_limit_orders(orders, &prices, &price_factor).len(), - 1 - ); - } - #[test] fn orders_with_balance_() { let settlement_contract = Address::repeat_byte(1); - let orders = vec![ + let orders = [ // enough balance for sell and fee - Order { + Arc::new(Order { data: OrderData { sell_token: Address::with_last_byte(2), sell_amount: alloy::primitives::U256::ONE, @@ -1450,9 +1179,9 @@ mod tests { ..Default::default() }, ..Default::default() - }, + }), // missing fee balance - Order { + Arc::new(Order { data: OrderData { sell_token: Address::with_last_byte(3), sell_amount: alloy::primitives::U256::ONE, @@ -1461,9 +1190,9 @@ mod tests { ..Default::default() }, ..Default::default() - }, + }), // at least 1 partially fillable balance - Order { + Arc::new(Order { data: OrderData { sell_token: Address::with_last_byte(4), sell_amount: alloy::primitives::U256::from(2), @@ -1472,9 +1201,9 @@ mod tests { ..Default::default() }, ..Default::default() - }, + }), // 0 partially fillable balance - Order { + Arc::new(Order { data: OrderData { sell_token: Address::with_last_byte(5), sell_amount: alloy::primitives::U256::from(2), @@ -1483,9 +1212,9 @@ mod tests { ..Default::default() }, ..Default::default() - }, + }), // considered flashloan order because of special receiver - Order { + Arc::new(Order { data: OrderData { sell_token: Address::with_last_byte(6), sell_amount: alloy::primitives::U256::from(200), @@ -1495,31 +1224,36 @@ mod tests { ..Default::default() }, ..Default::default() - }, + }), ]; let balances = [ - (Query::from_order(&orders[0]), 2.into()), - (Query::from_order(&orders[1]), 1.into()), - (Query::from_order(&orders[2]), 1.into()), - (Query::from_order(&orders[3]), 0.into()), - (Query::from_order(&orders[4]), 0.into()), + (Query::from_order(&orders[0]), U256::from(2)), + (Query::from_order(&orders[1]), U256::from(1)), + (Query::from_order(&orders[2]), U256::from(1)), + (Query::from_order(&orders[3]), U256::from(0)), + (Query::from_order(&orders[4]), U256::from(0)), ] .into_iter() .collect(); let expected = &[0, 2, 4]; - let filtered = orders_with_balance(orders.clone(), &balances, settlement_contract, false); - assert_eq!(filtered.len(), expected.len()); + let no_bypass: HashSet = HashSet::new(); + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let (alive_orders, _removed_orders) = + orders_with_balance(orders_ref, &balances, settlement_contract, &no_bypass); + assert_eq!(alive_orders.len(), expected.len()); for index in expected { - let found = filtered.iter().any(|o| o.data == orders[*index].data); + let found = alive_orders.iter().any(|o| o.data == orders[*index].data); assert!(found, "{}", index); } } #[test] - fn eip1271_orders_can_skip_balance_filtering() { + fn eip1271_and_wrapper_orders_skip_balance_filtering() { let settlement_contract = Address::repeat_byte(1); - let eip1271_order = Order { + + // EIP-1271 order (should skip balance check) + let eip1271_order = Arc::new(Order { data: OrderData { sell_token: Address::with_last_byte(7), sell_amount: alloy::primitives::U256::from(10), @@ -1528,9 +1262,17 @@ mod tests { ..Default::default() }, signature: Signature::Eip1271(vec![1, 2, 3]), + metadata: OrderMetadata { + uid: OrderUid::from_parts(B256::repeat_byte(6), Address::repeat_byte(66), 6), + ..Default::default() + }, ..Default::default() - }; - let regular_order = Order { + }); + + // Order with wrappers in bypass set (should skip balance check) + let wrapper_order_uid = + OrderUid::from_parts(B256::repeat_byte(7), Address::repeat_byte(77), 7); + let wrapper_order = Arc::new(Order { data: OrderData { sell_token: Address::with_last_byte(8), sell_amount: alloy::primitives::U256::from(10), @@ -1538,57 +1280,59 @@ mod tests { partially_fillable: false, ..Default::default() }, - ..Default::default() - }; - - let orders = vec![regular_order.clone(), eip1271_order.clone()]; - let balances: Balances = Default::default(); - - let filtered = orders_with_balance(orders.clone(), &balances, settlement_contract, true); - // 1271 filter is disabled, only the regular order is filtered out - assert_eq!(filtered.len(), 1); - assert!(matches!(filtered[0].signature, Signature::Eip1271(_))); - - let filtered_without_override = - orders_with_balance(orders, &balances, settlement_contract, false); - assert!(filtered_without_override.is_empty()); - } - - #[test] - fn prioritizes_missing_prices() { - let now = chrono::Utc::now(); - let token = H160::from_low_u64_be; - - let order = |sell_token, buy_token, age| Order { metadata: OrderMetadata { - creation_date: now - chrono::Duration::minutes(age), + uid: wrapper_order_uid, ..Default::default() }, + ..Default::default() + }); + + // Regular ECDSA order without wrappers (should be filtered) + let regular_order = Arc::new(Order { data: OrderData { - sell_token, - buy_token, + sell_token: Address::with_last_byte(9), + sell_amount: alloy::primitives::U256::from(10), + fee_amount: alloy::primitives::U256::from(5), + partially_fillable: false, + ..Default::default() + }, + metadata: OrderMetadata { + uid: OrderUid::from_parts(B256::repeat_byte(8), Address::repeat_byte(88), 8), ..Default::default() }, ..Default::default() - }; + }); - let orders = vec![ - order(Address::with_last_byte(4), Address::with_last_byte(6), 31), - order(Address::with_last_byte(4), Address::with_last_byte(6), 31), - // older market order - order(Address::with_last_byte(1), Address::with_last_byte(2), 29), - order(Address::with_last_byte(5), Address::with_last_byte(6), 31), - // youngest market order - order(Address::with_last_byte(1), Address::with_last_byte(3), 1), + let orders = [ + regular_order.clone(), + eip1271_order.clone(), + wrapper_order.clone(), ]; - let result = prioritize_missing_prices(orders); - assert!(result.into_iter().eq([ - token(1), // coming from youngest market order - token(3), // coming from youngest market order - token(2), // coming from older market order - token(6), // coming from limit order (part of 3 orders) - token(4), // coming from limit order (part of 2 orders) - token(5), // coming from limit order (part of 1 orders) - ])); + let balances: Balances = Default::default(); // No balances + + // EIP-1271 order and wrapper order should be retained, regular order filtered + let wrapper_set = HashSet::from([wrapper_order_uid]); + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let (alive_orders, _removed_orders) = + orders_with_balance(orders_ref, &balances, settlement_contract, &wrapper_set); + assert_eq!(alive_orders.len(), 2); + assert!( + alive_orders + .iter() + .any(|o| o.metadata.uid == eip1271_order.metadata.uid) + ); + assert!( + alive_orders + .iter() + .any(|o| o.metadata.uid == wrapper_order.metadata.uid) + ); + + // Without wrapper set, only EIP-1271 order should be retained + let empty_set: HashSet = HashSet::new(); + let orders_ref = orders.iter().map(|o| o.as_ref()).collect::>(); + let (alive_orders, _removed_orders) = + orders_with_balance(orders_ref, &balances, settlement_contract, &empty_set); + assert_eq!(alive_orders.len(), 1); + assert_eq!(alive_orders[0].metadata.uid, eip1271_order.metadata.uid); } } diff --git a/crates/autopilot/src/util/bytes.rs b/crates/autopilot/src/util/bytes.rs deleted file mode 100644 index c8b2d0992a..0000000000 --- a/crates/autopilot/src/util/bytes.rs +++ /dev/null @@ -1,18 +0,0 @@ -/// A thin wrapper around a collection of bytes. Provides hex debug formatting. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] -pub struct Bytes(pub T); - -impl std::fmt::Debug for Bytes -where - T: AsRef<[u8]>, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", const_hex::encode_prefixed(&self.0)) - } -} - -impl From for Bytes { - fn from(value: T) -> Self { - Self(value) - } -} diff --git a/crates/autopilot/src/util/conv.rs b/crates/autopilot/src/util/conv.rs deleted file mode 100644 index d3fa44f96a..0000000000 --- a/crates/autopilot/src/util/conv.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::domain::eth; - -pub trait U256Ext: Sized { - fn checked_ceil_div(&self, other: &Self) -> Option; - fn checked_mul_f64(&self, factor: f64) -> Option; -} - -impl U256Ext for eth::U256 { - fn checked_ceil_div(&self, other: &Self) -> Option { - self.checked_add(other.checked_sub(1.into())?)? - .checked_div(*other) - } - - fn checked_mul_f64(&self, factor: f64) -> Option { - // `factor` is first multiplied by the conversion factor to convert - // it to integer, to avoid rounding to 0. Then, the result is divided - // by the conversion factor to convert it back to the original scale. - // - // The higher the conversion factor (10^18) the precision is higher. E.g. - // 0.123456789123456789 will be converted to 123456789123456789. - // TODO: consider doing the computation with `BigRational` instead but - // that requires to double check and adjust a few tests due to tiny - // changes in rounding. - const CONVERSION_FACTOR: f64 = 1_000_000_000_000_000_000.; - let multiplied = self.checked_mul(Self::from_f64_lossy(factor * CONVERSION_FACTOR))? - / Self::from_f64_lossy(CONVERSION_FACTOR); - Some(multiplied) - } -} diff --git a/crates/autopilot/src/util/mod.rs b/crates/autopilot/src/util/mod.rs index ad88895c16..bb1babe21b 100644 --- a/crates/autopilot/src/util/mod.rs +++ b/crates/autopilot/src/util/mod.rs @@ -1,10 +1,5 @@ use url::Url; -mod bytes; -pub mod conv; - -pub use self::bytes::Bytes; - /// Joins a path with a URL, ensuring that there is only one slash between them. /// It doesn't matter if the URL ends with a slash or the path starts with one. pub fn join(url: &Url, mut path: &str) -> Url { diff --git a/crates/bad-tokens/Cargo.toml b/crates/bad-tokens/Cargo.toml new file mode 100644 index 0000000000..e40391f8f6 --- /dev/null +++ b/crates/bad-tokens/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "bad-tokens" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-json-rpc = { workspace = true } +alloy-primitives = { workspace = true, features = ["rand"] } +alloy-provider = { workspace = true, features = ["trace-api"] } +alloy-rpc-types = { workspace = true } +alloy-rpc-types-trace = { workspace = true } +alloy-sol-types = { workspace = true } +alloy-transport = { workspace = true } +anyhow = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +model = { workspace = true } +tracing = { workspace = true } + +[lints] +workspace = true diff --git a/crates/bad-tokens/LICENSE-APACHE b/crates/bad-tokens/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/bad-tokens/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/bad-tokens/LICENSE-MIT b/crates/bad-tokens/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/bad-tokens/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/shared/src/bad_token/mod.rs b/crates/bad-tokens/src/lib.rs similarity index 52% rename from crates/shared/src/bad_token/mod.rs rename to crates/bad-tokens/src/lib.rs index 4cb030db2a..6fed7b5306 100644 --- a/crates/shared/src/bad_token/mod.rs +++ b/crates/bad-tokens/src/lib.rs @@ -1,11 +1,6 @@ -pub mod cache; -pub mod instrumented; pub mod list_based; -pub mod token_owner_finder; pub mod trace_call; -use {alloy::primitives::Address, anyhow::Result}; - /// How well behaved a token is. #[derive(Debug, Clone, Eq, PartialEq)] pub enum TokenQuality { @@ -24,10 +19,3 @@ impl TokenQuality { } } } - -/// Detect how well behaved a token is. -#[cfg_attr(any(test, feature = "test-util"), mockall::automock)] -#[async_trait::async_trait] -pub trait BadTokenDetecting: Send + Sync { - async fn detect(&self, token: Address) -> Result; -} diff --git a/crates/bad-tokens/src/list_based.rs b/crates/bad-tokens/src/list_based.rs new file mode 100644 index 0000000000..297e33c42c --- /dev/null +++ b/crates/bad-tokens/src/list_based.rs @@ -0,0 +1,26 @@ +use { + alloy_primitives::Address, + std::{collections::HashSet, sync::Arc}, +}; + +/// Explicitly deny listed tokens. +#[derive(Default, Clone)] +pub struct DenyListedTokens(Arc); + +#[derive(Default)] +struct Inner { + deny_list: HashSet
, +} + +impl DenyListedTokens { + pub fn new(deny_list: Vec
) -> Self { + let deny_list = deny_list.into_iter().collect(); + Self(Arc::new(Inner { deny_list })) + } +} + +impl DenyListedTokens { + pub fn contains(&self, token: &Address) -> bool { + self.0.deny_list.contains(token) + } +} diff --git a/crates/bad-tokens/src/trace_call.rs b/crates/bad-tokens/src/trace_call.rs new file mode 100644 index 0000000000..3147a0f502 --- /dev/null +++ b/crates/bad-tokens/src/trace_call.rs @@ -0,0 +1,460 @@ +use { + super::TokenQuality, + alloy_json_rpc::ErrorPayload, + alloy_primitives::{Address, U256}, + alloy_provider::ext::TraceApi, + alloy_rpc_types::TransactionRequest, + alloy_rpc_types_trace::parity::{TraceOutput, TraceResults, TraceType}, + alloy_sol_types::SolCall, + alloy_transport::{RpcError, TransportErrorKind}, + anyhow::{Context, Result, bail, ensure}, + contracts::ERC20, + ethrpc::Web3, + model::interaction::InteractionData, +}; + +const METHOD_NOT_FOUND_CODE: i64 = -32601; + +/// Detects whether a token is "bad" (works in unexpected ways that are +/// problematic for solving) by simulating several transfers of a token. +#[derive(Debug, Clone)] +pub struct TraceCallDetectorRaw { + pub web3: Web3, + pub settlement_contract: Address, +} + +impl TraceCallDetectorRaw { + pub fn new(web3: Web3, settlement: Address) -> Self { + Self { + web3, + settlement_contract: settlement, + } + } + + pub async fn test_transfer( + &self, + take_from: Address, + token: Address, + amount: U256, + pre_interactions: &[InteractionData], + ) -> Result { + let mut request: Vec<_> = pre_interactions + .iter() + .map(|i| { + TransactionRequest::default() + .to(i.target) + .value(i.value) + .input(i.call_data.clone().into()) + }) + .collect(); + // We transfer the full available amount of the token from the amm pool into the + // settlement contract and then to an arbitrary address. + // Note that gas use can depend on the recipient because for the standard + // implementation sending to an address that does not have any balance + // yet (implicitly 0) causes an allocation. + request.append(&mut self.create_trace_request(token, amount, take_from)); + let traces = match trace_many(&self.web3, request).await { + Ok(result) => result, + Err(RpcError::UnsupportedFeature(err)) => { + tracing::warn!(error = ?err, "node does not support trace_callMany"); + return Ok(TokenQuality::Good); + } + Err(RpcError::ErrorResp(ErrorPayload { + code: METHOD_NOT_FOUND_CODE, + message, + .. + })) => { + tracing::warn!(error = %message, "node does not support trace_callMany"); + return Ok(TokenQuality::Good); + } + Err(RpcError::Transport(TransportErrorKind::HttpError(err))) if err.status == 400 => { + tracing::warn!( + error=?err, + "unable to perform trace call with configured node, assume good quality" + ); + return Ok(TokenQuality::Good); + } + Err(e) => { + return Err(e).context("trace_many"); + } + }; + let relevant_traces = &traces[pre_interactions.len()..]; + Self::handle_response(relevant_traces, amount, take_from) + } + + // For the out transfer we use an arbitrary address without balance to detect + // tokens that usually apply fees but not if the the sender or receiver is + // specifically exempt like their own uniswap pools. + fn arbitrary_recipient() -> Address { + Address::random() + } + + fn create_trace_request( + &self, + token: Address, + amount: U256, + take_from: Address, + ) -> Vec { + let mut requests = Vec::new(); + let recipient = Self::arbitrary_recipient(); + let settlement_contract = self.settlement_contract; + + // 0 + let calldata = ERC20::ERC20::balanceOfCall { + account: settlement_contract, + } + .abi_encode(); + requests.push( + TransactionRequest::default() + .to(token) + .input(calldata.into()), + ); + // 1 + let calldata = ERC20::ERC20::transferCall { + recipient: settlement_contract, + amount, + } + .abi_encode(); + requests.push( + TransactionRequest::default() + .from(take_from) + .to(token) + .input(calldata.into()), + ); + // 2 + let calldata = ERC20::ERC20::balanceOfCall { + account: settlement_contract, + } + .abi_encode(); + requests.push( + TransactionRequest::default() + .to(token) + .input(calldata.into()), + ); + // 3 + let calldata = ERC20::ERC20::balanceOfCall { account: recipient }.abi_encode(); + requests.push( + TransactionRequest::default() + .to(token) + .input(calldata.into()), + ); + // 4 + let calldata = ERC20::ERC20::transferCall { recipient, amount }.abi_encode(); + requests.push( + TransactionRequest::default() + .from(self.settlement_contract) + .to(token) + .input(calldata.into()), + ); + // 5 + let calldata = ERC20::ERC20::balanceOfCall { + account: settlement_contract, + } + .abi_encode(); + requests.push( + TransactionRequest::default() + .to(token) + .input(calldata.into()), + ); + // 6 + let calldata = ERC20::ERC20::balanceOfCall { account: recipient }.abi_encode(); + requests.push( + TransactionRequest::default() + .to(token) + .input(calldata.into()), + ); + + // 7 + let calldata = ERC20::ERC20::approveCall { + spender: recipient, + amount: U256::MAX, + } + .abi_encode(); + requests.push( + TransactionRequest::default() + .from(self.settlement_contract) + .to(token) + .input(calldata.into()), + ); + + requests + } + + fn handle_response( + traces: &[TraceResults], + amount: U256, + take_from: Address, + ) -> Result { + ensure!(traces.len() == 8, "unexpected number of traces"); + + let gas_in = match ensure_transaction_ok_and_get_gas(&traces[1])? { + Ok(gas) => gas, + Err(reason) => { + return Ok(TokenQuality::bad(format!( + "Transfer of token from on chain source {take_from:?} into settlement \ + contract failed: {reason}" + ))); + } + }; + let arbitrary = Self::arbitrary_recipient(); + let gas_out = match ensure_transaction_ok_and_get_gas(&traces[4])? { + Ok(gas) => gas, + Err(reason) => { + return Ok(TokenQuality::bad(format!( + "Transfer token out of settlement contract to arbitrary recipient \ + {arbitrary:?} failed: {reason}", + ))); + } + }; + + let message = "\ + Failed to decode the token's balanceOf response because it did not \ + return 32 bytes. A common cause of this is a bug in the Vyper \ + smart contract compiler. See \ + https://github.com/cowprotocol/services/pull/781 for more \ + information.\ + "; + let bad = TokenQuality::Bad { + reason: message.to_string(), + }; + let balance_before_in = match u256_from_be_bytes_strict(&traces[0].output) { + Some(balance) => balance, + None => return Ok(bad), + }; + let balance_after_in = match u256_from_be_bytes_strict(&traces[2].output) { + Some(balance) => balance, + None => return Ok(bad), + }; + let balance_after_out = match u256_from_be_bytes_strict(&traces[5].output) { + Some(balance) => balance, + None => return Ok(bad), + }; + let balance_recipient_before = match u256_from_be_bytes_strict(&traces[3].output) { + Some(balance) => balance, + None => return Ok(bad), + }; + let balance_recipient_after = match u256_from_be_bytes_strict(&traces[6].output) { + Some(balance) => balance, + None => return Ok(bad), + }; + + tracing::debug!(%amount, %balance_before_in, %balance_after_in, %balance_after_out); + + let computed_balance_after_in = match balance_before_in.checked_add(amount) { + Some(amount) => amount, + None => { + return Ok(TokenQuality::bad(format!( + "Transferring {amount} into settlement contract would overflow its balance." + ))); + } + }; + // Allow for a small discrepancy (1 wei) in the balance after the transfer which + // may come from rounding discrepancies in tokens that track balances + // with "shares" (e.g. eUSD). + if balance_after_in < computed_balance_after_in.saturating_sub(U256::ONE) { + return Ok(TokenQuality::bad(format!( + "Transferring {amount} into settlement contract was expected to result in a \ + balance of {computed_balance_after_in} but actually resulted in \ + {balance_after_in}. A common cause for this is that the token takes a fee on \ + transfer." + ))); + } + if balance_after_out != balance_before_in { + return Ok(TokenQuality::bad(format!( + "Transferring {amount} out of settlement contract was expected to result in the \ + original balance of {balance_before_in} but actually resulted in \ + {balance_after_out}." + ))); + } + let computed_balance_recipient_after = match balance_recipient_before.checked_add(amount) { + Some(amount) => amount, + None => { + return Ok(TokenQuality::bad(format!( + "Transferring {amount} into arbitrary recipient {arbitrary:?} would overflow \ + its balance." + ))); + } + }; + // Allow for a small discrepancy (1 wei) in the balance after the transfer + // which may come from rounding discrepancies in tokens that track + // balances with "shares" (e.g. eUSD). + if computed_balance_recipient_after < balance_recipient_after.saturating_sub(U256::ONE) { + return Ok(TokenQuality::bad(format!( + "Transferring {amount} into arbitrary recipient {arbitrary:?} was expected to \ + result in a balance of {computed_balance_recipient_after} but actually resulted \ + in {balance_recipient_after}. A common cause for this is that the token takes a \ + fee on transfer." + ))); + } + + if let Err(err) = ensure_transaction_ok_and_get_gas(&traces[7])? { + return Ok(TokenQuality::bad(format!( + "Approval of U256::MAX failed: {err}" + ))); + } + + let _gas_per_transfer = (gas_in + gas_out) / U256::from(2); + Ok(TokenQuality::Good) + } +} + +/// The outer result signals communication failure with the node. +/// The inner result is Ok(gas_price) or Err if the transaction failed. +fn ensure_transaction_ok_and_get_gas(trace: &TraceResults) -> Result> { + let first = trace.trace.first().context("expected at least one trace")?; + if let Some(error) = &first.error { + return Ok(Err(format!("transaction failed: {error}"))); + } + let call_result = match &first.result { + Some(TraceOutput::Call(call)) => call, + _ => bail!("no error but also no call result"), + }; + Ok(Ok(U256::from(call_result.gas_used))) +} + +/// Decodes a `U256` from a big-endian encoded slice. +/// The slice's length MUST be 32 bytes. +fn u256_from_be_bytes_strict(b: &[u8]) -> Option { + if b.len() != 32 { + return None; + } + U256::try_from_be_slice(b) +} + +/// Use the trace_callMany API () +/// to simulate these call requests applied together one after another. +/// +/// Returns `Err` if communication with the node failed. +async fn trace_many( + web3: &Web3, + requests: Vec, +) -> Result, RpcError> { + let r: Vec<_> = requests + .into_iter() + .zip(std::iter::repeat([TraceType::Trace].as_slice())) + .collect(); + + web3.provider.trace_call_many(r.as_slice()).latest().await +} + +#[cfg(test)] +mod tests { + use { + super::*, + alloy_primitives::Bytes, + alloy_rpc_types_trace::parity::{ + Action, + CallAction, + CallOutput, + CallType, + TransactionTrace, + }, + }; + + #[test] + fn handle_response_ok() { + let traces = &[ + TraceResults { + output: U256::ZERO.to_be_bytes::<32>().to_vec().into(), + trace: vec![], + vm_trace: None, + state_diff: None, + }, + TraceResults { + output: Default::default(), + trace: vec![TransactionTrace { + trace_address: Vec::new(), + subtraces: 0, + action: Action::Call(CallAction { + from: Address::ZERO, + to: Address::ZERO, + value: U256::ZERO, + gas: 0, + input: Bytes::new(), + call_type: CallType::None, + }), + result: Some(TraceOutput::Call(CallOutput { + gas_used: 1, + output: Bytes::new(), + })), + error: None, + }], + vm_trace: None, + state_diff: None, + }, + TraceResults { + output: U256::ONE.to_be_bytes::<32>().to_vec().into(), + trace: vec![], + vm_trace: None, + state_diff: None, + }, + TraceResults { + output: U256::ZERO.to_be_bytes::<32>().to_vec().into(), + trace: vec![], + vm_trace: None, + state_diff: None, + }, + TraceResults { + output: Default::default(), + trace: vec![TransactionTrace { + trace_address: Vec::new(), + subtraces: 0, + action: Action::Call(CallAction { + from: Address::ZERO, + to: Address::ZERO, + value: U256::ZERO, + gas: 0, + input: Bytes::new(), + call_type: CallType::None, + }), + result: Some(TraceOutput::Call(CallOutput { + gas_used: 3, + output: Bytes::new(), + })), + error: None, + }], + vm_trace: None, + state_diff: None, + }, + TraceResults { + output: U256::ZERO.to_be_bytes::<32>().to_vec().into(), + trace: vec![], + vm_trace: None, + state_diff: None, + }, + TraceResults { + output: U256::ONE.to_be_bytes::<32>().to_vec().into(), + trace: vec![], + vm_trace: None, + state_diff: None, + }, + TraceResults { + output: Default::default(), + trace: vec![TransactionTrace { + trace_address: Vec::new(), + subtraces: 0, + action: Action::Call(CallAction { + from: Address::ZERO, + to: Address::ZERO, + value: U256::ZERO, + gas: 0, + input: Bytes::new(), + call_type: CallType::None, + }), + result: Some(TraceOutput::Call(CallOutput { + gas_used: 1, + output: Bytes::new(), + })), + error: None, + }], + vm_trace: None, + state_diff: None, + }, + ]; + + let result = + TraceCallDetectorRaw::handle_response(traces, U256::ONE, Address::ZERO).unwrap(); + let expected = TokenQuality::Good; + assert_eq!(result, expected); + } +} diff --git a/crates/balance-overrides/Cargo.toml b/crates/balance-overrides/Cargo.toml new file mode 100644 index 0000000000..c7fe722559 --- /dev/null +++ b/crates/balance-overrides/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "balance-overrides" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[lib] +doctest = false + +[dependencies] +alloy-contract = { workspace = true } +alloy-eips = { workspace = true } +alloy-primitives = { workspace = true, features = ["rand"] } +alloy-provider = { workspace = true, features = ["debug-api", "trace-api"] } +alloy-rpc-types = { workspace = true, features = ["trace"] } +alloy-sol-types = { workspace = true } +alloy-transport = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +clap = { workspace = true } +configs = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +moka = { workspace = true, features = ["sync"] } +serde = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +ethrpc = { workspace = true, features = ["test-util"] } +maplit = { workspace = true } +serde_json = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[lints] +workspace = true diff --git a/crates/balance-overrides/LICENSE-APACHE b/crates/balance-overrides/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/balance-overrides/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/balance-overrides/LICENSE-MIT b/crates/balance-overrides/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/balance-overrides/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/balance-overrides/src/approval/mod.rs b/crates/balance-overrides/src/approval/mod.rs new file mode 100644 index 0000000000..61d27a5522 --- /dev/null +++ b/crates/balance-overrides/src/approval/mod.rs @@ -0,0 +1,661 @@ +use { + crate::detector::{DetectionError, SimulationError, extract_sload_slots, mapping_slot_hash}, + alloy_eips::BlockId, + alloy_primitives::{Address, B256, TxKind, U256, keccak256, map::AddressMap}, + alloy_provider::ext::DebugApi, + alloy_rpc_types::{ + TransactionInput, + TransactionRequest, + state::AccountOverride, + trace::geth::GethDebugTracingCallOptions, + }, + alloy_sol_types::SolCall, + alloy_transport::TransportErrorKind, + contracts::ERC20, + ethrpc::Web3, + moka::sync::Cache, + std::{iter, time::Duration}, +}; + +/// These are the solady magic bytes for user allowances +/// +const ALLOWANCE_SLOT_SEED: &[u8] = &[0x7f, 0x5e, 0x9f, 0x20]; + +/// Produces approval strategy candidates from a list of SLOAD-accessed slots. +/// This function assumes SLOAD-accessed slots are returned in order that they +/// were accessed in the relevant call (`balanceOf()`, or `allowance()`). +/// Since it's most likely that the last slots are the important ones this +/// function returns strategies for the slots in **reverse** order. +/// +/// Tries Solady and both Solidity double-mapping orderings (owner→spender and +/// spender→owner, for each base map_slot index 0..depth). If `depth == 0` +/// **no** such strategies will be tried and returned. +/// In that case this function can only return `DirectSlot` or `SoladyMapping` +/// strategies. +pub(crate) fn find_plausible_strategies_for_slots( + storage_slots: &[(Address, B256)], + owner: &Address, + spender: &Address, + heuristic_depth: usize, +) -> Vec { + let mut heuristic_candidates = Vec::new(); + let mut fallback_candidates = Vec::new(); + + for (contract, observed_slot) in storage_slots.iter().rev() { + let solady = ApprovalStrategy::SoladyMapping { + target_contract: *contract, + }; + if solady.slot(*owner, *spender).1 == *observed_slot { + heuristic_candidates.push(solady); + continue; + } + + let mut matched = false; + for i in 0..heuristic_depth { + let map_slot = U256::from(i); + + let owner_to_spender = ApprovalStrategy::SolidityMappingOwnerToSpender { + target_contract: *contract, + map_slot, + }; + if owner_to_spender.slot(*owner, *spender).1 == *observed_slot { + heuristic_candidates.push(owner_to_spender); + matched = true; + break; + } + + let spender_to_owner = ApprovalStrategy::SolidityMappingSpenderToOwner { + target_contract: *contract, + map_slot, + }; + if spender_to_owner.slot(*owner, *spender).1 == *observed_slot { + heuristic_candidates.push(spender_to_owner); + matched = true; + break; + } + } + + if !matched { + fallback_candidates.push(ApprovalStrategy::DirectSlot { + target_contract: *contract, + slot: *observed_slot, + }); + } + } + + heuristic_candidates.extend(fallback_candidates); + heuristic_candidates +} + +/// Parameters for computing an approval state override. +#[derive(Clone, Debug)] +pub struct ApprovalOverrideRequest { + pub token: Address, + pub owner: Address, + pub spender: Address, + pub amount: U256, +} + +/// Detected allowance storage strategy for a token. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ApprovalStrategy { + /// Standard Solidity double mapping with owner as the outer key: + /// `mapping(address owner => mapping(address spender => uint256))` at + /// `map_slot`. + SolidityMappingOwnerToSpender { + target_contract: Address, + map_slot: U256, + }, + /// Solidity double mapping with spender as the outer key: + /// `mapping(address spender => mapping(address owner => uint256))` at + /// `map_slot`. + SolidityMappingSpenderToOwner { + target_contract: Address, + map_slot: U256, + }, + /// Solady ERC-20 packed allowance layout. + SoladyMapping { target_contract: Address }, + /// Fallback for tokens with non-standard allowance storage: the exact slot + /// observed during tracing is stored and used verbatim. Because the slot + /// was observed for a specific `(owner, spender)` pair and may encode them + /// in an unknown way, this strategy is treated as pair-specific. + DirectSlot { + target_contract: Address, + slot: B256, + }, +} + +impl ApprovalStrategy { + /// Computes the `(contract, storage_slot)` pair for a specific + /// `(owner, spender)` pair. + pub(crate) fn slot(&self, owner: Address, spender: Address) -> (Address, B256) { + match self { + Self::SolidityMappingOwnerToSpender { + target_contract, + map_slot, + } => { + let inner = mapping_slot_hash(&owner, &map_slot.to_be_bytes::<32>()); + let slot = mapping_slot_hash(&spender, &inner.0); + (*target_contract, slot) + } + Self::SolidityMappingSpenderToOwner { + target_contract, + map_slot, + } => { + let inner = mapping_slot_hash(&spender, &map_slot.to_be_bytes::<32>()); + let slot = mapping_slot_hash(&owner, &inner.0); + (*target_contract, slot) + } + Self::SoladyMapping { target_contract } => { + // keccak256(owner_20 ‖ 0x00×8 ‖ 0x7f5e9f20 ‖ spender_20) [52 bytes] + let mut buf = [0u8; 52]; + buf[0..20].copy_from_slice(owner.as_slice()); + buf[28..32].copy_from_slice(ALLOWANCE_SLOT_SEED); + buf[32..52].copy_from_slice(spender.as_slice()); + (*target_contract, keccak256(buf)) + } + Self::DirectSlot { + target_contract, + slot, + } => (*target_contract, *slot), + } + } + + pub(crate) fn is_valid_for_all_pairs(&self) -> bool { + matches!( + self, + Self::SolidityMappingOwnerToSpender { .. } + | Self::SolidityMappingSpenderToOwner { .. } + | Self::SoladyMapping { .. } + ) + } + + /// Builds the state override for `(owner, spender, amount)`. + pub(crate) fn state_override( + &self, + owner: Address, + spender: Address, + amount: U256, + ) -> AddressMap { + let (target_contract, slot) = self.slot(owner, spender); + let account_override = AccountOverride::default() + .with_state_diff(iter::once((slot, B256::new(amount.to_be_bytes::<32>())))); + iter::once((target_contract, account_override)).collect() + } +} + +// NOTE(jmg-duarte): ideally these would be new types, but this is simpler in +// the current context (PR #4418) and doesn't require large refactors +type Token = Address; +type Holder = Address; +type Spender = Address; +type OverrideDetectorCacheKey = (Token, Option<(Holder, Spender)>); + +/// Heuristic approval override detector with integrated caching. +/// +/// Owns the Web3 handle, detection parameters, and the per-token strategy +/// cache. Strategies that can compute the correct slot for any `(owner, +/// spender)` pair (Solidity mappings, Solady) are cached under `(token, None)`. +/// `DirectSlot` strategies, which encode a specific observed slot, are cached +/// under `(token, Some((owner, spender)))`. +pub(crate) struct Detector { + web3: Web3, + probing_depth: u8, + verification_timeout: Duration, + pub(crate) cache: Cache>, +} + +impl Detector { + pub fn new( + web3: Web3, + probing_depth: u8, + verification_timeout: Duration, + cache_size: u64, + ) -> Self { + Self { + web3, + probing_depth, + verification_timeout, + cache: Cache::builder().max_capacity(cache_size).build(), + } + } + + /// Returns the cached detection result for `(token, owner, spender)`, + /// running detection if not yet cached. + /// + /// Pair-agnostic strategies (Solidity mappings, Solady) are cached under + /// `(token, None)` and returned for any pair. `DirectSlot` strategies are + /// cached under `(token, Some((owner, spender)))` because the observed slot + /// may encode the specific pair. + pub(crate) async fn detect( + &self, + token: Address, + owner: Address, + spender: Address, + ) -> Option { + tracing::trace!(?token, "attempting to auto-detect approval slot"); + + { + if let Some(strategy_opt) = self.cache.get(&(token, None)) { + tracing::trace!(?token, "cache hit (strategy valid for all pairs)"); + return strategy_opt; + } + if let Some(strategy_opt) = self.cache.get(&(token, Some((owner, spender)))) { + tracing::trace!( + ?token, + ?owner, + ?spender, + "cache hit (pair-specific strategy)" + ); + return strategy_opt; + } + } + + let result = self.uncached_detect(token, owner, spender).await; + + if matches!(&result, Ok(_) | Err(DetectionError::NotFound)) { + tracing::debug!(?token, ?result, "caching auto-detected approval strategy"); + if let Ok(strategy) = result.as_ref() { + let cache_key = ( + token, + (!strategy.is_valid_for_all_pairs()).then_some((owner, spender)), + ); + self.cache.insert(cache_key, Some(strategy.clone())); + } else { + self.cache.insert((token, Some((owner, spender))), None); + } + } else { + tracing::warn!(?token, ?result, "error auto-detecting approval strategy"); + } + + result.ok() + } + + async fn uncached_detect( + &self, + token: Address, + owner: Address, + spender: Address, + ) -> Result> { + let allowance_call = ERC20::ERC20::allowanceCall { owner, spender }; + let calldata = allowance_call.abi_encode(); + + let call_request = TransactionRequest { + to: Some(TxKind::Call(token)), + input: TransactionInput::new(calldata.into()), + ..Default::default() + }; + + let trace = self + .web3 + .provider + .debug_trace_call( + call_request, + BlockId::latest(), + GethDebugTracingCallOptions::default(), + ) + .await + .map_err(|err| { + tracing::debug!(?token, ?err, "debug_traceCall not supported for token"); + DetectionError::Rpc(err) + })?; + + let storage_slots = extract_sload_slots(trace, token); + + if storage_slots.is_empty() { + tracing::debug!(?token, "no SLOAD operations in allowance trace"); + return Err(DetectionError::NotFound); + } + + let strategies = find_plausible_strategies_for_slots( + &storage_slots, + &owner, + &spender, + self.probing_depth.into(), + ); + + for (i, strategy) in strategies + .iter() + .take(self.probing_depth.into()) + .enumerate() + { + let fut = self.verify_approval_strategy(token, owner, spender, strategy); + let result = tokio::time::timeout(self.verification_timeout, fut).await; + + match result { + Ok(Ok(())) => { + tracing::debug!( + ?token, + ?owner, + ?spender, + ?strategy, + iterations = i + 1, + "verified approval strategy", + ); + return Ok(strategy.clone()); + } + Err(_) => { + tracing::warn!( + ?token, + ?strategy, + "approval strategy verification timed out, skipping", + ); + } + Ok(Err(_)) => {} + } + } + + tracing::debug!(?token, "no approval slot found for token"); + Err(DetectionError::NotFound) + } + + async fn verify_approval_strategy( + &self, + token: Address, + owner: Address, + spender: Address, + strategy: &ApprovalStrategy, + ) -> Result<(), DetectionError> { + let test_amount = U256::from(0x1337_1337_1337_1337_u64); + + let (target_contract, slot) = strategy.slot(owner, spender); + let state_override = AccountOverride { + state_diff: Some( + iter::once(( + slot, + alloy_primitives::B256::new(test_amount.to_be_bytes::<32>()), + )) + .collect(), + ), + ..Default::default() + }; + let overrides: alloy_primitives::map::AddressMap = + iter::once((target_contract, state_override)).collect(); + + let token_contract = ERC20::Instance::new(token, self.web3.provider.clone()); + let allowance = token_contract + .allowance(owner, spender) + .state(overrides) + .call() + .await + .map_err(|e| { + DetectionError::Simulation(SimulationError::Other(anyhow::anyhow!( + "allowance call failed during strategy verification: {e}" + ))) + })?; + + (allowance == test_amount) + .then_some(()) + .ok_or(DetectionError::NotFound) + } +} + +impl std::fmt::Debug for Detector { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("approval::Detector") + .field("probing_depth", &self.probing_depth) + .field("verification_timeout", &self.verification_timeout) + .finish() + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{StateOverrides, StateOverriding}, + alloy_primitives::address, + alloy_rpc_types::state::StateOverride, + contracts::ERC20::ERC20, + ethrpc::Web3, + }; + + #[test] + fn solidity_mapping_owner_to_spender_slot() { + let token = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let owner = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let spender = Address::with_last_byte(1); + + let strategy = ApprovalStrategy::SolidityMappingOwnerToSpender { + target_contract: token, + map_slot: U256::ONE, + }; + + let (contract, slot) = strategy.slot(owner, spender); + assert_eq!(contract, token); + + let inner = mapping_slot_hash(&owner, &U256::from(1u64).to_be_bytes::<32>()); + let expected = mapping_slot_hash(&spender, &inner.0); + assert_eq!(slot, expected); + } + + #[test] + fn solidity_mapping_spender_to_owner_slot() { + let token = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let owner = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let spender = Address::with_last_byte(1); + + let strategy = ApprovalStrategy::SolidityMappingSpenderToOwner { + target_contract: token, + map_slot: U256::ONE, + }; + + let (contract, slot) = strategy.slot(owner, spender); + assert_eq!(contract, token); + + let inner = mapping_slot_hash(&spender, &U256::ONE.to_be_bytes::<32>()); + let expected = mapping_slot_hash(&owner, &inner.0); + assert_eq!(slot, expected); + } + + #[test] + fn solady_approval_slot() { + let token = address!("0000000000c5dc95539589fbd24be07c6c14eca4"); + let owner = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let spender = Address::with_last_byte(1); + + let strategy = ApprovalStrategy::SoladyMapping { + target_contract: token, + }; + + let (contract, slot) = strategy.slot(owner, spender); + assert_eq!(contract, token); + + // Compute expected: keccak256(owner_20 ‖ 0x00×8 ‖ 0x7f5e9f20 ‖ spender_20) + let mut buf = [0u8; 52]; + buf[0..20].copy_from_slice(owner.as_slice()); + buf[28..32].copy_from_slice(&[0x7f, 0x5e, 0x9f, 0x20]); + buf[32..52].copy_from_slice(spender.as_slice()); + assert_eq!(slot, keccak256(buf)); + } + + #[ignore] + #[tokio::test] + async fn override_allowance_simple() { + let token = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let owner = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let spender = Address::with_last_byte(1); + let amount = U256::from(123123123); + + let web3 = Web3::new_from_env(); + let helper = StateOverrides::new(web3.clone()); + + let state_overrides: StateOverride = helper + .approval_override(ApprovalOverrideRequest { + owner, + spender, + token, + amount, + }) + .await + .into_iter() + .collect(); + + let erc20 = ERC20::new(token, &web3.provider); + let allowance_with_override = erc20 + .allowance(owner, spender) + .state(state_overrides) + .call() + .await + .unwrap(); + + assert_eq!(allowance_with_override, amount); + } + + #[ignore] + #[tokio::test] + async fn override_allowance_solady() { + let token = address!("0000000000c5dc95539589fbd24be07c6c14eca4"); + let owner = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let spender = Address::with_last_byte(1); + let amount = U256::from(123123123); + + let web3 = Web3::new_from_env(); + let helper = StateOverrides::new(web3.clone()); + + let state_overrides: StateOverride = helper + .approval_override(ApprovalOverrideRequest { + owner, + spender, + token, + amount, + }) + .await + .into_iter() + .collect(); + + let erc20 = ERC20::new(token, &web3.provider); + let allowance_with_override = erc20 + .allowance(owner, spender) + .state(state_overrides) + .call() + .await + .unwrap(); + + assert_eq!(allowance_with_override, amount); + } + + #[ignore] + #[tokio::test] + async fn override_balance_solady() { + let token = address!("0000000000c5dc95539589fbd24be07c6c14eca4"); + let holder = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let amount = U256::from(123123123); + + let web3 = Web3::new_from_env(); + let helper = StateOverrides::new(web3.clone()); + + let state_overrides: StateOverride = helper + .balance_override(crate::BalanceOverrideRequest { + token, + holder, + amount, + }) + .await + .into_iter() + .collect(); + + let erc20 = ERC20::new(token, &web3.provider); + let allowance_with_override = erc20 + .balanceOf(holder) + .state(state_overrides) + .call() + .await + .unwrap(); + + assert_eq!(allowance_with_override, amount); + } + + #[test] + fn test_unmatched_slots_become_direct_slot() { + let contract = Address::with_last_byte(2); + let owner = Address::repeat_byte(1); + let spender = Address::repeat_byte(2); + + let slot1 = B256::with_last_byte(0xe1); + let slot2 = B256::with_last_byte(0xe2); + let slots = vec![(contract, slot1), (contract, slot2)]; + + let strategies = find_plausible_strategies_for_slots(&slots, &owner, &spender, 10); + + assert_eq!( + strategies, + vec![ + ApprovalStrategy::DirectSlot { + target_contract: contract, + slot: slot2, + }, + ApprovalStrategy::DirectSlot { + target_contract: contract, + slot: slot1, + }, + ] + ); + } + + #[test] + fn test_heuristic_before_direct_slot_fallback() { + let contract = Address::with_last_byte(2); + let owner = Address::repeat_byte(1); + let spender = Address::repeat_byte(2); + + // Compute a real Solidity OwnerToSpender slot with map_slot = 1 + let heuristic_strategy = ApprovalStrategy::SolidityMappingOwnerToSpender { + target_contract: contract, + map_slot: U256::ONE, + }; + let heuristic_slot = heuristic_strategy.slot(owner, spender).1; + let fallback_slot = B256::with_last_byte(0xff); + + let slots = vec![(contract, fallback_slot), (contract, heuristic_slot)]; + + let strategies = find_plausible_strategies_for_slots(&slots, &owner, &spender, 10); + + assert_eq!( + strategies, + vec![ + ApprovalStrategy::SolidityMappingOwnerToSpender { + target_contract: contract, + map_slot: U256::ONE, + }, + ApprovalStrategy::DirectSlot { + target_contract: contract, + slot: fallback_slot, + }, + ] + ); + } + + #[test] + fn test_zero_heuristic_depth_all_direct_slot() { + let contract = Address::with_last_byte(2); + let owner = Address::repeat_byte(1); + let spender = Address::repeat_byte(2); + + // Compute a real Solidity slot — with depth 0 it must NOT match + let heuristic_strategy = ApprovalStrategy::SolidityMappingOwnerToSpender { + target_contract: contract, + map_slot: U256::from(1), + }; + let heuristic_slot = heuristic_strategy.slot(owner, spender).1; + let other_slot = B256::with_last_byte(0x42); + + let slots = vec![(contract, other_slot), (contract, heuristic_slot)]; + + let strategies = find_plausible_strategies_for_slots(&slots, &owner, &spender, 0); + + assert_eq!( + strategies, + vec![ + ApprovalStrategy::DirectSlot { + target_contract: contract, + slot: heuristic_slot, + }, + ApprovalStrategy::DirectSlot { + target_contract: contract, + slot: other_slot, + }, + ] + ); + } +} diff --git a/crates/balance-overrides/src/balance/aave.rs b/crates/balance-overrides/src/balance/aave.rs new file mode 100644 index 0000000000..2a06abb701 --- /dev/null +++ b/crates/balance-overrides/src/balance/aave.rs @@ -0,0 +1,377 @@ +//! Helpers shared between the `BalanceOverrides` override builder and the +//! `Detector` probe/verify for Aave v3 aTokens. +//! +//! aTokens break the usual "balanceOf = storage[slot]" assumption twice: +//! - `balanceOf` returns `scaled_balance × getReserveNormalizedIncome / RAY`, +//! not the raw slot value. +//! - Storage is packed `UserState { uint128 balance; uint128 additionalData }` +//! in a single slot per holder. + +use { + crate::detector::mapping_slot_hash, + alloy_primitives::{Address, B256, U256}, + alloy_rpc_types::state::AccountOverride, + alloy_sol_types::sol, + ethrpc::Web3, + std::iter, +}; + +sol! { + /// Mirrors Aave v3's `DataTypes.ReserveConfigurationMap`. + /// + /// Source: + struct ReserveConfigurationMap { + uint256 data; + } + + /// Mirrors Aave v3's `DataTypes.ReserveData`. Only the `aTokenAddress` + /// field is consumed here; the rest are present to keep the ABI layout + /// exactly matched so decoding doesn't go off the rails. + /// + /// Source: + struct ReserveData { + ReserveConfigurationMap configuration; + uint128 liquidityIndex; + uint128 currentLiquidityRate; + uint128 variableBorrowIndex; + uint128 currentVariableBorrowRate; + uint128 currentStableBorrowRate; + uint40 lastUpdateTimestamp; + uint16 id; + address aTokenAddress; + address stableDebtTokenAddress; + address variableDebtTokenAddress; + address interestRateStrategyAddress; + uint128 accruedToTreasury; + uint128 unbacked; + uint128 isolationModeTotalDebt; + } + + /// Minimal interface for the Aave v3 `Pool`. `getReserveNormalizedIncome` + /// gives the accrued liquidity index used when scaling `balanceOf`; + /// `getReserveData` returns the full reserve record which we use to + /// confirm a probed token really is the registered aToken for its + /// underlying. + /// + /// Source: + #[sol(rpc)] + interface IAaveV3Pool { + function getReserveNormalizedIncome(address asset) external view returns (uint256); + function getReserveData(address asset) external view returns (ReserveData memory); + } + + /// Minimal interface for an Aave v3 `AToken`; used by the detector to + /// decide whether a token is an aToken without any hardcoded list. + /// + /// Source: + #[sol(rpc)] + interface IAaveV3AToken { + function UNDERLYING_ASSET_ADDRESS() external view returns (address); + function POOL() external view returns (address); + } +} + +/// Ray (1e27) — Aave's 27-decimal fixed-point unit. +/// +/// Source: +const RAY: U256 = U256::from_limbs([0x9fd0803ce8000000, 0x33b2e3c, 0, 0]); + +/// Storage slot index of `_userState` in the Aave v3 `IncentivizedERC20` +/// base contract. All canonical v3 aTokens inherit this layout, so the +/// detector can try this slot directly without a `debug_traceCall`. +/// +/// Source: +const USER_STATE_SLOT: u64 = 52; + +/// Small sentinel for verifying an aToken override, the counterpart to the +/// detector's full-width sentinel. aTokens scale the balance and pack it into a +/// `uint128` (see `pack_user_state`), so the full-width value would overflow +/// the ray multiply and not fit the slot. This stays small enough to round-trip +/// through both. +pub(crate) const SENTINEL: [u8; 32] = + alloy_primitives::hex!("0x0000000000000000000000000000000000000000000000000102030405060708"); + +/// Ray-division: `(a * RAY + b/2) / b`, round-half-up. Matches Aave's +/// `WadRayMath.rayDiv` bit-for-bit so the scaled amount we write into +/// storage equals the one Aave will itself compute during a subsequent +/// `_transfer`. Returns `None` if `b == 0` or the intermediate product +/// overflows `U256`. +fn ray_div(a: U256, b: U256) -> Option { + if b.is_zero() { + return None; + } + let half_b = b >> 1; + a.checked_mul(RAY) + .and_then(|prod| prod.checked_add(half_b)) + .map(|num| num / b) +} + +/// Packs a `UserState { uint128 balance; uint128 additionalData }` into a +/// 32-byte word. The balance occupies the lower 128 bits; `additional_data` +/// sits in the upper 128 bits. +fn pack_user_state(balance: U256, additional_data: U256) -> B256 { + let mask = (U256::from(1u64) << 128) - U256::from(1u64); + let packed: U256 = ((additional_data & mask) << 128) | (balance & mask); + B256::new(packed.to_be_bytes::<32>()) +} + +/// Probes whether `token` is an Aave v3 aToken and returns its `(pool, +/// underlying)` pair. Accepts the token iff the pool registers it as the +/// aToken for its declared underlying — rogue contracts implementing the +/// aToken selectors aren't enough. +pub async fn probe_aave_token(web3: &Web3, token: Address) -> Option<(Address, Address)> { + let a_token = IAaveV3AToken::new(token, web3.provider.clone()); + let underlying_call = a_token.UNDERLYING_ASSET_ADDRESS(); + let pool_call = a_token.POOL(); + let (underlying, pool) = tokio::try_join!(underlying_call.call(), pool_call.call()).ok()?; + let reserve = IAaveV3Pool::new(pool, web3.provider.clone()) + .getReserveData(underlying) + .call() + .await + .ok()?; + (reserve.aTokenAddress == token).then_some((pool, underlying)) +} + +/// Builds a state override that makes `balanceOf(holder)` on the aToken +/// report approximately `amount`. Writes into the canonical `_userState` +/// slot (`USER_STATE_SLOT`) shared by all Aave v3 aTokens. Returns `None` +/// if we can't reach the pool or the math overflows. +pub async fn build_override( + web3: &Web3, + a_token: Address, + pool: Address, + underlying: Address, + holder: Address, + amount: U256, +) -> Option<(Address, AccountOverride)> { + let Ok(index) = IAaveV3Pool::new(pool, web3.provider.clone()) + .getReserveNormalizedIncome(underlying) + .call() + .await + else { + tracing::warn!( + ?pool, + ?underlying, + "failed to fetch Aave reserve normalized income" + ); + return None; + }; + + let Some(scaled) = ray_div(amount, index) else { + // Either `amount * RAY` overflowed U256 (only possible for an + // astronomically large requested amount) or the pool returned a + // zero index (never should happen for a live reserve). Either way, + // surface it explicitly so we don't silently drop the override. + tracing::warn!( + ?a_token, + %amount, + %index, + "ray_div overflow computing AaveV3AToken scaled balance" + ); + return None; + }; + let slot = mapping_slot_hash(&holder, &U256::from(USER_STATE_SLOT).to_be_bytes()); + let value = pack_user_state(scaled, U256::ZERO); + + tracing::trace!( + ?a_token, + ?holder, + %amount, + %index, + %scaled, + "computed AaveV3AToken balance override" + ); + + let state_override = AccountOverride { + state_diff: Some(iter::once((slot, value)).collect()), + ..Default::default() + }; + Some((a_token, state_override)) +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::balance::Strategy, + alloy_primitives::{address, b256, hex}, + alloy_provider::mock::Asserter, + alloy_sol_types::SolValue, + }; + + fn encode_address(addr: Address) -> String { + hex::encode_prefixed(addr.into_word()) + } + + /// Encodes a `ReserveData` struct as the ABI return payload the pool + /// would produce. All fields other than `aTokenAddress` are zero — we + /// only care about that one for the probe. + fn encode_reserve_data(a_token: Address) -> String { + let data = ReserveData { + configuration: ReserveConfigurationMap { data: U256::ZERO }, + liquidityIndex: 0, + currentLiquidityRate: 0, + variableBorrowIndex: 0, + currentVariableBorrowRate: 0, + currentStableBorrowRate: 0, + lastUpdateTimestamp: alloy_primitives::Uint::ZERO, + id: 0, + aTokenAddress: a_token, + stableDebtTokenAddress: Address::ZERO, + variableDebtTokenAddress: Address::ZERO, + interestRateStrategyAddress: Address::ZERO, + accruedToTreasury: 0, + unbacked: 0, + isolationModeTotalDebt: 0, + }; + hex::encode_prefixed(data.abi_encode()) + } + + /// Builds an `Asserter` primed with the three responses the probe + /// expects, in order: `UNDERLYING_ASSET_ADDRESS()`, `POOL()`, and + /// `getReserveData(underlying)`. `None` maps to a reverted call; `Some` + /// maps to a success response containing the given value. + fn probe_asserter( + underlying: Option
, + pool: Option
, + reserve_a_token: Option
, + ) -> Asserter { + let asserter = Asserter::new(); + match underlying { + Some(u) => asserter.push_success(&encode_address(u)), + None => asserter.push_failure_msg("execution reverted"), + } + match pool { + Some(p) => asserter.push_success(&encode_address(p)), + None => asserter.push_failure_msg("execution reverted"), + } + match reserve_a_token { + Some(a) => asserter.push_success(&encode_reserve_data(a)), + None => asserter.push_failure_msg("execution reverted"), + } + asserter + } + + #[test] + fn ray_div_edge_cases() { + let index = U256::from_str_radix("1063000000000000000000000000", 10).unwrap(); + assert_eq!(ray_div(U256::ZERO, index).unwrap(), U256::ZERO); + assert_eq!( + ray_div(U256::from(1_000_000_000_000_000_000u128), U256::ZERO), + None, + ); + } + + #[test] + fn pack_user_state_leaves_additional_data_intact() { + let balance = U256::from(0x1234_5678u64); + let extra = U256::from(0xabcd_ef01u64); + let packed = pack_user_state(balance, extra); + let word = U256::from_be_bytes(packed.0); + + let mask = (U256::from(1u64) << 128) - U256::from(1u64); + assert_eq!(word & mask, balance); + assert_eq!(word >> 128, extra); + } + + #[test] + fn pack_user_state_truncates_to_uint128() { + let overflow = (U256::from(1u64) << 128) + U256::from(7u64); + let packed = pack_user_state(overflow, U256::ZERO); + let word = U256::from_be_bytes(packed.0); + assert_eq!(word, U256::from(7u64)); + } + + #[test] + fn mapping_slot_hash_matches_solidity_layout() { + let holder = address!("18709E89BD403F470088aBDAcEbE86CC60dda12e"); + let slot = mapping_slot_hash(&holder, &U256::from(52).to_be_bytes::<32>()); + assert_eq!( + slot, + b256!("6785743a4ad9de6e692f819936c9d0b94b199ed36f2660e82404737b769718e5") + ); + } + + /// A contract that doesn't expose the aToken selectors — `balanceOf` + /// throws when the probe calls `UNDERLYING_ASSET_ADDRESS()` — is + /// cleanly rejected so non-aToken ERC-20s don't accidentally pick up + /// the Aave strategy. + #[tokio::test] + async fn probe_aave_token_rejects_when_underlying_call_reverts() { + let token = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); + let web3 = Web3::with_asserter(probe_asserter(None, None, None)); + assert_eq!(probe_aave_token(&web3, token).await, None); + } + + /// The probe bails if the claimed pool doesn't respond to + /// `getReserveData` — guards against a contract exposing both + /// `UNDERLYING_ASSET_ADDRESS()` and `POOL()` while pointing at + /// something that isn't actually an Aave v3 pool. + #[tokio::test] + async fn probe_aave_token_rejects_when_pool_is_not_aave() { + let token = address!("1111111111111111111111111111111111111111"); + let pool = address!("2222222222222222222222222222222222222222"); + let underlying = address!("3333333333333333333333333333333333333333"); + let web3 = Web3::with_asserter(probe_asserter(Some(underlying), Some(pool), None)); + assert_eq!(probe_aave_token(&web3, token).await, None); + } + + /// A rogue contract that impersonates the aToken interface and points + /// at a real Aave pool is rejected: the pool registers a *different* + /// `aTokenAddress` for the underlying, so the identity check fails. + #[tokio::test] + async fn probe_aave_token_rejects_when_pool_registers_a_different_atoken() { + let rogue = address!("bad000000000000000000000000000000000cafe"); + let real_a_token = address!("4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8"); + let pool = address!("87870bca3f3fd6335c3f4ce8392d69350b4fa4e2"); + let underlying = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); + let web3 = Web3::with_asserter(probe_asserter( + Some(underlying), + Some(pool), + // Pool agrees on the pair but names the *real* aToken, not the rogue. + Some(real_a_token), + )); + assert_eq!(probe_aave_token(&web3, rogue).await, None); + } + + #[tokio::test] + async fn aave_v3_a_token_override_scales_amount_and_writes_low_128() { + let a_token = address!("4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8"); + let pool = address!("87870bca3f3fd6335c3f4ce8392d69350b4fa4e2"); + let underlying = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); + let holder = address!("18709E89BD403F470088aBDAcEbE86CC60dda12e"); + let amount = U256::from(1_000_000_000_000_000_000u128); + + let asserter = Asserter::new(); + let index = U256::from_str_radix("1063000000000000000000000000", 10).unwrap(); + asserter.push_success(&format!("0x{:064x}", index)); + + let web3 = Web3::with_asserter(asserter); + let strategy = Strategy::AaveV3AToken { + target_contract: a_token, + pool, + underlying, + web3, + }; + + let (addr, override_) = strategy + .state_override(&holder, &amount) + .await + .into_iter() + .last() + .expect("override computed"); + + assert_eq!(addr, a_token); + + let diff = override_.state_diff.expect("state diff present"); + assert_eq!(diff.len(), 1); + let (slot, value) = diff.into_iter().next().unwrap(); + assert_eq!( + slot, + b256!("6785743a4ad9de6e692f819936c9d0b94b199ed36f2660e82404737b769718e5") + ); + let word = U256::from_be_bytes(value.0); + assert_eq!(word >> 128, U256::ZERO); + assert_eq!(word, ray_div(amount, index).unwrap()); + } +} diff --git a/crates/balance-overrides/src/balance/mod.rs b/crates/balance-overrides/src/balance/mod.rs new file mode 100644 index 0000000000..dcd9f0b4b0 --- /dev/null +++ b/crates/balance-overrides/src/balance/mod.rs @@ -0,0 +1,870 @@ +pub(crate) mod aave; + +use { + crate::detector::{DetectionError, SimulationError, extract_sload_slots, mapping_slot_hash}, + alloy_eips::BlockId, + alloy_primitives::{Address, B256, TxKind, U256, keccak256, map::AddressMap}, + alloy_provider::ext::DebugApi, + alloy_rpc_types::{ + TransactionInput, + TransactionRequest, + state::AccountOverride, + trace::geth::GethDebugTracingCallOptions, + }, + alloy_sol_types::SolCall, + alloy_transport::TransportErrorKind, + contracts::ERC20, + ethrpc::Web3, + moka::sync::Cache, + std::{collections::HashMap, iter, time::Duration}, +}; + +/// These are the solady magic bytes for user balances +/// https://github.com/Vectorized/solady/blob/main/src/tokens/ERC20.sol#L81 +const BALANCE_SLOT_SEED: &[u8] = &[0x87, 0xa2, 0x11, 0xa2]; + +/// Distinct-byte sentinel written to a candidate balance slot during +/// verification. Every byte is distinct and non-zero, so the value `balanceOf` +/// reads back is a unique contiguous byte-slice of it (see `detect_shift`). Its +/// position gives the packing shift for a balance stored above lower-order +/// fields, e.g. AUSD packs `isFrozen` in the low byte, so the balance is the +/// high 248 bits and `shift_bits == 8`. A readback that is not a slice means +/// the slot is not the balance. The full 32 bytes cover any byte-aligned shift, +/// including narrow fields: a `uint96` balance (UNI, COMP) reads back as the +/// low-byte suffix and resolves to `shift_bits == 0`. +const SENTINEL: [u8; 32] = + alloy_primitives::hex!("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"); + +/// Used by Detector when there are multiple slots to increase the chances we +/// find the correct storage slot quickly. +/// +/// Note: does not emit `AaveV3AToken` candidates — Aave is handled by the +/// fast-path in `Detector::uncached_detect` which tries the canonical +/// `_userState` slot directly. +pub(crate) fn find_plausible_strategies_for_slots( + storage_slots: &[(Address, B256)], + holder: &Address, + heuristic_depth: usize, +) -> Vec { + // Build a map from heuristic slot hash to the map_slot index + let mut solidity_mapping_slot_to_index = HashMap::new(); + + let mut buf = [0; 64]; + buf[12..32].copy_from_slice(holder.as_slice()); + for i in 0..heuristic_depth { + buf[32..64].copy_from_slice(&U256::from(i).to_be_bytes::<32>()); + let slot_hash = keccak256(buf); + solidity_mapping_slot_to_index.insert(slot_hash, i); + } + + buf[0..20].copy_from_slice(holder.as_slice()); + buf[20..28].copy_from_slice(&[0x0; 8]); // zeroize dirtied section of buffer + buf[28..32].copy_from_slice(BALANCE_SLOT_SEED); + let solady_slot = keccak256(&buf[0..32]); + + let mut heuristic_strategies = Vec::new(); + let mut fallback_strategies = Vec::new(); + for (contract, slot) in storage_slots.iter().rev() { + if let Some(&map_slot_index) = solidity_mapping_slot_to_index.get(slot) { + heuristic_strategies.push(Strategy::SolidityMapping { + target_contract: *contract, + map_slot: U256::from(map_slot_index), + shift_bits: 0, + }); + } else if *slot == solady_slot { + heuristic_strategies.push(Strategy::SoladyMapping { + target_contract: *contract, + shift_bits: 0, + }); + } else { + fallback_strategies.push(Strategy::DirectSlot { + target_contract: *contract, + slot: *slot, + shift_bits: 0, + }); + }; + } + + heuristic_strategies.extend(fallback_strategies); + heuristic_strategies +} + +/// Parameters for computing a balance state override. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct BalanceOverrideRequest { + /// The token for the override. + pub token: Address, + /// The account to override the balance for. + pub holder: Address, + /// The token amount (in atoms) to set the balance to. + pub amount: U256, +} + +/// Resolved balance override strategy. +/// +/// `shift_bits` is how far the balance is left-shifted within its slot, for +/// tokens that pack the balance above lower-order fields. E.g. AUSD stores +/// `{ bool isFrozen; uint248 balance }` in one slot, so the balance is the high +/// 248 bits and `shift_bits == 8`. It is `0` for the common unpacked case. +/// +/// The `AaveV3AToken` variant owns a cloned `Web3` handle, so it computes its +/// override without an external web3 reference threaded through. +#[derive(Clone, Debug)] +pub(crate) enum Strategy { + SolidityMapping { + target_contract: Address, + map_slot: U256, + shift_bits: usize, + }, + SoladyMapping { + target_contract: Address, + shift_bits: usize, + }, + DirectSlot { + target_contract: Address, + slot: B256, + shift_bits: usize, + }, + AaveV3AToken { + target_contract: Address, + pool: Address, + underlying: Address, + web3: Web3, + }, +} + +impl Strategy { + pub(crate) async fn state_override( + &self, + holder: &Address, + amount: &U256, + ) -> AddressMap { + let (target_contract, key, shift_bits) = match self { + Self::SolidityMapping { + target_contract, + map_slot, + shift_bits, + } => ( + *target_contract, + mapping_slot_hash(holder, &map_slot.to_be_bytes()), + *shift_bits, + ), + Self::SoladyMapping { + target_contract, + shift_bits, + } => { + let mut buf = [0; 32]; + buf[0..20].copy_from_slice(holder.as_slice()); + buf[28..32].copy_from_slice(&[0x87, 0xa2, 0x11, 0xa2]); + (*target_contract, keccak256(buf), *shift_bits) + } + Self::DirectSlot { + target_contract, + slot, + shift_bits, + } => (*target_contract, *slot, *shift_bits), + Self::AaveV3AToken { + target_contract, + pool, + underlying, + web3, + } => { + return match aave::build_override( + web3, + *target_contract, + *pool, + *underlying, + *holder, + *amount, + ) + .await + { + Some((addr, override_)) => iter::once((addr, override_)).collect(), + None => AddressMap::default(), + }; + } + }; + + // Pack the balance into its slot position. `checked_shl` returns `None` + // only when the balance is too large to fit above the lower-order + // fields, which a real balance never is, so log it if it ever happens. + let Some(value) = amount.checked_shl(shift_bits) else { + tracing::warn!( + ?target_contract, + ?holder, + %amount, + shift_bits, + "balance does not fit packed slot, skipping override", + ); + return AddressMap::default(); + }; + + let state_override = AccountOverride { + state_diff: Some(iter::once((key, B256::new(value.to_be_bytes::<32>()))).collect()), + ..Default::default() + }; + + iter::once((target_contract, state_override)).collect() + } + + /// Returns whether the strategy can cheaply compute the necessary state + /// override for any given holder or if it only works for the original + /// holder it was generated for. + pub(crate) fn can_be_applied_to_any_holder(&self) -> bool { + !matches!(self, Self::DirectSlot { .. }) + } + + /// Sets the packing shift on a balance strategy. No-op for `AaveV3AToken`, + /// which is never packed. + fn with_shift(mut self, shift_bits: usize) -> Self { + match &mut self { + Self::SolidityMapping { shift_bits: s, .. } + | Self::SoladyMapping { shift_bits: s, .. } + | Self::DirectSlot { shift_bits: s, .. } => *s = shift_bits, + Self::AaveV3AToken { .. } => {} + } + self + } +} + +/// Compare by addresses only; `web3` is intentionally excluded since two +/// strategies for the same token/pool/underlying are semantically equivalent +/// regardless of which web3 handle they carry. +impl PartialEq for Strategy { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ( + Self::SolidityMapping { + target_contract: tc1, + map_slot: ms1, + shift_bits: sb1, + }, + Self::SolidityMapping { + target_contract: tc2, + map_slot: ms2, + shift_bits: sb2, + }, + ) => tc1 == tc2 && ms1 == ms2 && sb1 == sb2, + ( + Self::SoladyMapping { + target_contract: tc1, + shift_bits: sb1, + }, + Self::SoladyMapping { + target_contract: tc2, + shift_bits: sb2, + }, + ) => tc1 == tc2 && sb1 == sb2, + ( + Self::DirectSlot { + target_contract: tc1, + slot: s1, + shift_bits: sb1, + }, + Self::DirectSlot { + target_contract: tc2, + slot: s2, + shift_bits: sb2, + }, + ) => tc1 == tc2 && s1 == s2 && sb1 == sb2, + ( + Self::AaveV3AToken { + target_contract: tc1, + pool: p1, + underlying: u1, + .. + }, + Self::AaveV3AToken { + target_contract: tc2, + pool: p2, + underlying: u2, + .. + }, + ) => tc1 == tc2 && p1 == p2 && u1 == u2, + _ => false, + } + } +} + +impl Eq for Strategy {} + +/// Heuristic balance override detector with integrated caching. +/// +/// Owns the Web3 handle, detection parameters, and the per-token strategy +/// cache. `AaveV3AToken` strategies in the cache carry a cloned `Web3` handle +/// so they can compute overrides without any external dependency. +pub(crate) struct Detector { + web3: Web3, + probing_depth: u8, + verification_timeout: Duration, + pub(crate) cache: Cache<(Address, Option
), Option>, +} + +impl Detector { + pub fn new( + web3: Web3, + probing_depth: u8, + verification_timeout: Duration, + cache_size: u64, + ) -> Self { + Self { + web3, + probing_depth, + verification_timeout, + cache: Cache::builder().max_capacity(cache_size).build(), + } + } + + /// Returns the cached detection result for `(token, holder)`, running + /// detection if not yet cached. + pub async fn detect(&self, token: Address, holder: Address) -> Option { + tracing::trace!(?token, "attempting to auto-detect balance slot"); + + { + if let Some(strategy_opt) = self.cache.get(&(token, None)) { + tracing::trace!(?token, "cache hit (strategy valid for all holders)"); + return strategy_opt; + } + if let Some(strategy_opt) = self.cache.get(&(token, Some(holder))) { + tracing::trace!(?token, ?holder, "cache hit (holder-specific strategy)"); + return strategy_opt; + } + } + + let strategy = self.uncached_detect(token, holder).await; + + match strategy.as_ref() { + Ok(strategy) => { + let cache_key = ( + token, + (!strategy.can_be_applied_to_any_holder()).then_some(holder), + ); + tracing::debug!(?token, ?strategy, "caching auto-detected balance strategy"); + self.cache.insert(cache_key, Some(strategy.clone())); + } + Err(DetectionError::NotFound) => { + tracing::debug!(?token, "caching token as unsupported"); + self.cache.insert((token, Some(holder)), None); + } + Err(err) => { + tracing::warn!( + ?token, + ?strategy, + ?err, + "error auto-detecting token balance override strategy" + ); + } + } + + strategy.ok() + } + + async fn uncached_detect( + &self, + token: Address, + holder: Address, + ) -> Result> { + // Aave fast-path. If the token self-identifies as a v3 aToken and + // the pool confirms it, try the canonical `_userState` slot + // directly — no `debug_traceCall` needed. An Aave v3 fork that + // moved `_userState` to a different slot won't verify here and + // will fall through to the generic trace-based path, which only + // ever returns non-Aave strategies; such a fork needs an explicit + // hardcoded config entry. + if let Some((pool, underlying)) = aave::probe_aave_token(&self.web3, token).await { + let candidate = Strategy::AaveV3AToken { + target_contract: token, + pool, + underlying, + web3: self.web3.clone(), + }; + if let Ok(resolved) = self.verify_strategy(token, holder, candidate).await { + tracing::debug!(?token, "detected Aave v3 aToken"); + return Ok(resolved); + } + tracing::debug!( + ?token, + "Aave probe succeeded but canonical slot didn't verify; falling back to trace" + ); + } + + let balance_of_call = ERC20::ERC20::balanceOfCall { account: holder }; + let calldata = balance_of_call.abi_encode(); + + let call_request = TransactionRequest { + to: Some(TxKind::Call(token)), + input: TransactionInput::new(calldata.into()), + ..Default::default() + }; + + let trace = self + .web3 + .provider + .debug_trace_call( + call_request, + BlockId::latest(), + GethDebugTracingCallOptions::default(), + ) + .await + .map_err(|err| { + tracing::debug!(?token, ?err, "debug_traceCall not supported for token"); + DetectionError::Rpc(err) + })?; + + let storage_slots = extract_sload_slots(trace, token); + + if storage_slots.is_empty() { + tracing::debug!("no SLOAD operations found in trace for token {:?}", token); + return Err(DetectionError::NotFound); + } + + let strategies = + find_plausible_strategies_for_slots(&storage_slots, &holder, self.probing_depth.into()); + + tracing::debug!( + ?token, + total = storage_slots.len(), + "testing candidate balance slots", + ); + + for (i, strategy) in strategies.into_iter().enumerate() { + // Some tokens (e.g. reflection tokens like LuckyBlock) have + // `balanceOf` implementations that iterate over storage arrays. + // During verification we override storage slots with a test value — + // if that value lands on an array-length slot the EVM loops until + // the node's execution timeout. A per-strategy timeout prevents one + // slow slot from blocking the entire detection. + let result = tokio::time::timeout( + self.verification_timeout, + self.verify_strategy(token, holder, strategy.clone()), + ) + .await; + + match result { + Ok(Ok(verified)) => { + tracing::debug!( + ?token, + ?holder, + strategy = ?verified, + iterations = i + 1, + total = storage_slots.len(), + "verified balance strategy via testing", + ); + return Ok(verified); + } + Err(_) => { + tracing::warn!( + ?token, + ?holder, + ?strategy, + "balance override strategy verification timed out, skipping", + ); + } + Ok(Err(err)) => { + tracing::trace!( + ?token, + ?holder, + ?strategy, + ?err, + "balance override strategy was not correct", + ); + } + } + } + + tracing::debug!( + "none of the SLOAD slots appear to be the balance slot for token {:?}", + token + ); + + Err(DetectionError::NotFound) + } + + /// Verifies that a strategy controls the balance by writing a sentinel to + /// its slot and reading `balanceOf` back, returning the confirmed strategy. + /// + /// Generic strategies use the full [`SENTINEL`]: `detect_shift` finds the + /// readback as a byte-slice of it, which verifies the slot and recovers the + /// packing shift (0 when unpacked) from the same readback, no extra RPC. + /// The `AaveV3AToken` variant never packs and stores its scaled balance + /// in a `uint128`, so it uses the small [`aave::SENTINEL`] and accepts a + /// round-trip within 1 wei of Aave's ray rounding. + async fn verify_strategy( + &self, + token: Address, + holder: Address, + strategy: Strategy, + ) -> Result> { + let is_aave = matches!(strategy, Strategy::AaveV3AToken { .. }); + let sentinel = if is_aave { + U256::from_be_bytes(aave::SENTINEL) + } else { + U256::from_be_bytes(SENTINEL) + }; + + let overrides = strategy.state_override(&holder, &sentinel).await; + if overrides.is_empty() { + return Err(DetectionError::NotFound); + } + + let balance = ERC20::Instance::new(token, self.web3.provider.clone()) + .balanceOf(holder) + .state(overrides) + .call() + .await + .map_err(|e| { + DetectionError::Simulation(SimulationError::Other(anyhow::anyhow!( + "balanceOf call failed during strategy verification: {e}" + ))) + })?; + + if is_aave { + // Aave's ray-div / ray-mul round-trip is not identity, so allow 1 + // wei of difference. + return (balance.abs_diff(sentinel) <= U256::ONE) + .then_some(strategy) + .ok_or(DetectionError::NotFound); + } + + // Locate the readback as a contiguous byte-slice of the sentinel. Its + // position gives the packing shift, 0 when unpacked. A non-match means + // this slot is not the balance. + match detect_shift(balance) { + Some(shift_bits) => Ok(strategy.with_shift(shift_bits)), + None => Err(DetectionError::NotFound), + } + } +} + +impl std::fmt::Debug for Detector { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("balance::Detector") + .field("probing_depth", &self.probing_depth) + .field("verification_timeout", &self.verification_timeout) + .finish() + } +} + +/// Recovers the packing shift by locating the `balanceOf` readback as a +/// contiguous byte-slice of [`SENTINEL`]. The sentinel's bytes are distinct and +/// non-zero, so the slice is unique: the number of bytes sitting below it is +/// the shift, and a readback that is not a slice means the slot is not the +/// balance. Returns the left-shift in bits (0 for an unpacked balance). +fn detect_shift(observed: U256) -> Option { + // Strip leading zero bytes to get the field's bytes. The field is a slice of + // the all-non-zero sentinel, so its top byte is non-zero and trimming never + // eats into it. An all-zero readback has no non-zero byte (the write never + // reached `balanceOf`), so `position` returns None and we bail. + let bytes = observed.to_be_bytes::<32>(); + let needle = &bytes[bytes.iter().position(|&b| b != 0)?..]; + let start = SENTINEL.windows(needle.len()).position(|w| w == needle)?; + Some(SENTINEL.len().checked_sub(start + needle.len())? * 8) +} + +#[cfg(test)] +mod tests { + use {super::*, alloy_primitives::address}; + + #[test] + fn detect_shift_locates_packed_balance() { + let sentinel = U256::from_be_bytes(SENTINEL); + // Unpacked: the full sentinel reads back as-is. + assert_eq!(detect_shift(sentinel), Some(0)); + // AUSD-style: isFrozen in the low byte, balance in the high 248 bits, so + // `balanceOf == slot >> 8`. + assert_eq!(detect_shift(sentinel >> 8usize), Some(8)); + assert_eq!(detect_shift(sentinel >> 24usize), Some(24)); + // Narrow uint96 field (UNI/COMP): the low 12 bytes, the sentinel's + // suffix, still resolve to shift 0. + let mask96 = (U256::from(1u64) << 96) - U256::from(1u64); + assert_eq!(detect_shift(sentinel & mask96), Some(0)); + // Middle field: a 96-bit balance at bit offset 8 (lower-order fields + // below, more above). balanceOf reads it shifted down to the low bits, + // so the readback is `(slot >> 8) & mask`, recovered as shift 8. + assert_eq!(detect_shift((sentinel >> 8usize) & mask96), Some(8)); + // A zero readback means the write never reached `balanceOf`. + assert_eq!(detect_shift(U256::ZERO), None); + // Unrelated value is not a byte-slice of the sentinel. + assert_eq!(detect_shift(U256::from(0xdeadu64)), None); + } + + #[test] + fn test_create_strategies_reverses_order() { + let contract = Address::with_last_byte(2); + let contract2 = Address::with_last_byte(2); + let slot1 = B256::with_last_byte(1); + let slot2 = B256::with_last_byte(2); + let slot3 = B256::with_last_byte(3); + let slots = vec![ + (contract, slot1), + (contract2, slot3), + (contract, slot2), + (contract, slot3), + (contract2, slot1), + ]; + let holder = Address::with_last_byte(1); + + let strategies = find_plausible_strategies_for_slots(&slots, &holder, 5); + + assert_eq!( + strategies, + vec![ + Strategy::DirectSlot { + target_contract: contract2, + slot: slot1, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot3, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot2, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract2, + slot: slot3, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot1, + shift_bits: 0, + }, + ] + ); + } + + #[test] + fn test_create_strategies_with_heuristic_slots_stable() { + let contract = Address::with_last_byte(2); + let holder = address!("1111111111111111111111111111111111111111"); + + let mut buf = [0u8; 64]; + buf[12..32].copy_from_slice(holder.as_slice()); + buf[32..64].copy_from_slice(&U256::ZERO.to_be_bytes::<32>()); + let heuristic_slot1 = keccak256(buf); + buf[32..64].copy_from_slice(&U256::from(5).to_be_bytes::<32>()); + let heuristic_slot2 = keccak256(buf); + buf[0..20].copy_from_slice(holder.as_slice()); + buf[20..28].copy_from_slice(&[0x0; 8]); + buf[28..32].copy_from_slice(BALANCE_SLOT_SEED); + let heuristic_slot3 = keccak256(&buf[0..32]); + + let slot1 = B256::with_last_byte(0xe7); + let slot2 = B256::with_last_byte(0xe6); + let slot3 = B256::with_last_byte(0xe3); + + let slots = vec![ + (contract, slot1), + (contract, slot3), + (contract, heuristic_slot2), + (contract, heuristic_slot3), + (contract, slot2), + (contract, heuristic_slot1), + ]; + + let strategies = find_plausible_strategies_for_slots(&slots, &holder, 100); + + assert_eq!( + strategies, + vec![ + Strategy::SolidityMapping { + target_contract: contract, + map_slot: U256::ZERO, + shift_bits: 0, + }, + Strategy::SoladyMapping { + target_contract: contract, + shift_bits: 0, + }, + Strategy::SolidityMapping { + target_contract: contract, + map_slot: U256::from(5), + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot2, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot3, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot1, + shift_bits: 0, + }, + ] + ); + } + + #[test] + fn test_create_strategies_zero_heuristic_depth() { + let contract = Address::with_last_byte(2); + let holder = address!("5555555555555555555555555555555555555555"); + + let slot1 = B256::with_last_byte(1); + let slot2 = B256::with_last_byte(2); + let slot3 = B256::with_last_byte(3); + + let mut buf = [0u8; 64]; + buf[12..32].copy_from_slice(holder.as_slice()); + buf[32..64].copy_from_slice(&U256::ZERO.to_be_bytes::<32>()); + let heuristic_slot = keccak256(buf); + + let slots = vec![ + (contract, slot1), + (contract, slot2), + (contract, heuristic_slot), + (contract, slot3), + ]; + + let strategies = find_plausible_strategies_for_slots(&slots, &holder, 0); + + assert_eq!( + strategies, + vec![ + Strategy::DirectSlot { + target_contract: contract, + slot: slot3, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: heuristic_slot, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot2, + shift_bits: 0, + }, + Strategy::DirectSlot { + target_contract: contract, + slot: slot1, + shift_bits: 0, + }, + ] + ); + } + + const OPEN_ZEPPELIN_ERC20_UPGRADEABLE: B256 = + alloy_primitives::b256!("52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00"); + + #[ignore] + #[tokio::test] + async fn detects_storage_slots_mainnet() { + use crate::detector::DEFAULT_VERIFICATION_TIMEOUT; + + let detector = Detector::new(Web3::new_from_env(), 60, DEFAULT_VERIFICATION_TIMEOUT, 100); + + let storage = detector + .detect( + address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), + Address::with_last_byte(1), + ) + .await + .unwrap(); + assert_eq!( + storage, + Strategy::SolidityMapping { + target_contract: address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), + map_slot: U256::from(3), + shift_bits: 0, + } + ); + + let storage = detector + .detect( + address!("4956b52ae2ff65d74ca2d61207523288e4528f96"), + Address::with_last_byte(1), + ) + .await + .unwrap(); + assert_eq!( + storage, + Strategy::SolidityMapping { + target_contract: address!("4956b52ae2ff65d74ca2d61207523288e4528f96"), + map_slot: >::from(OPEN_ZEPPELIN_ERC20_UPGRADEABLE), + shift_bits: 0, + } + ); + + let storage = detector + .detect( + address!("0000000000c5dc95539589fbd24be07c6c14eca4"), + Address::with_last_byte(1), + ) + .await + .unwrap(); + assert_eq!( + storage, + Strategy::SoladyMapping { + target_contract: address!("0000000000c5dc95539589fbd24be07c6c14eca4"), + shift_bits: 0, + } + ); + } + + #[ignore] + #[tokio::test] + async fn detects_storage_slots_arbitrum() { + use crate::detector::DEFAULT_VERIFICATION_TIMEOUT; + + let detector = Detector::new(Web3::new_from_env(), 60, DEFAULT_VERIFICATION_TIMEOUT, 100); + + let storage = detector + .detect( + address!("ff970a61a04b1ca14834a43f5de4533ebddb5cc8"), + Address::with_last_byte(1), + ) + .await + .unwrap(); + assert_eq!( + storage, + Strategy::SolidityMapping { + target_contract: address!("ff970a61a04b1ca14834a43f5de4533ebddb5cc8"), + map_slot: U256::from(51), + shift_bits: 0, + } + ); + } + + // AUSD packs `{ bool isFrozen; uint248 balance }` into one slot, so the + // balance is the high 248 bits and `balanceOf == slot >> 8`. Its balance + // lives at an ERC-7201-namespaced base slot, so the detector resolves it to + // a `DirectSlot` and verification recovers the 8-bit packing shift. Requires + // an avalanche node (set the node URL `Web3::new_from_env` reads). + #[ignore] + #[tokio::test] + async fn detects_packed_balance_slot_avalanche() { + use crate::detector::DEFAULT_VERIFICATION_TIMEOUT; + + let ausd = address!("00000000efe302beaa2b3e6e1b18d08d69a9012a"); + let detector = Detector::new(Web3::new_from_env(), 60, DEFAULT_VERIFICATION_TIMEOUT, 100); + + let strategy = detector + .detect(ausd, Address::with_last_byte(1)) + .await + .unwrap(); + + match strategy { + Strategy::DirectSlot { + target_contract, + shift_bits, + .. + } => { + assert_eq!(target_contract, ausd); + assert_eq!(shift_bits, 8); + } + other => panic!("expected DirectSlot with shift, got {other:?}"), + } + } +} diff --git a/crates/balance-overrides/src/detector.rs b/crates/balance-overrides/src/detector.rs new file mode 100644 index 0000000000..245a1a2e70 --- /dev/null +++ b/crates/balance-overrides/src/detector.rs @@ -0,0 +1,96 @@ +use { + alloy_primitives::{Address, B256, keccak256}, + alloy_rpc_types::trace::geth::GethTrace, + alloy_transport::RpcError, + std::{collections::HashSet, time::Duration}, + thiserror::Error, + tracing::instrument, +}; + +pub(crate) const DEFAULT_VERIFICATION_TIMEOUT: Duration = Duration::from_secs(1); + +#[derive(Debug, Error)] +pub enum SimulationError { + #[error("simulation reverted {0:?}")] + Revert(Option), + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +#[derive(Debug, Error)] +pub enum DetectionError { + #[error("could not detect a balance override strategy")] + NotFound, + #[error("error returned by the RPC server")] + Rpc(#[from] RpcError), + #[error(transparent)] + Simulation(#[from] SimulationError), +} + +/// Extracts storage slots accessed via SLOAD operations from a geth trace. +/// Returns slots in first-access order, keyed by the storage context +/// (contract). +#[instrument(skip_all, level = "trace")] +pub(crate) fn extract_sload_slots( + trace: GethTrace, + initial_storage_context: Address, +) -> Vec<(Address, B256)> { + let mut storage_context = vec![initial_storage_context]; + let mut slots = Vec::new(); + let mut seen = HashSet::new(); + + for log in &trace + .try_into_default_frame() + .unwrap_or_default() + .struct_logs + { + let stack = log.stack.clone().unwrap_or_default(); + match log.op.as_ref() { + "CALL" | "STATICCALL" if stack.len() >= 2 => { + tracing::trace!("Detected CALL into nested contract"); + storage_context.push(Address::from_word(stack[stack.len() - 2].into())); + } + "DELEGATECALL" if stack.len() >= 2 => { + storage_context.push(*storage_context.last().unwrap()); + } + "RETURN" => { + tracing::trace!("Detected RETURN from nested contract"); + if storage_context.is_empty() { + tracing::debug!( + "Too many RETURN opcodes (is there something wrong with the struct log?)" + ); + break; + } + storage_context.pop(); + } + "SLOAD" if !stack.is_empty() => { + if let Some(current_storage) = storage_context.last() { + tracing::trace!(?stack, "Detected SLOAD"); + let slot = *stack.last().unwrap(); + if seen.insert((*current_storage, slot)) { + slots.push((*current_storage, slot.into())); + } + } else { + tracing::debug!( + ?stack, + "SLOAD called when not in a call context (is something wrong with the \ + struct log?)" + ); + break; + } + } + _ => {} + } + } + + slots +} + +/// `keccak256(pad32(holder) ++ map_slot)` — the storage slot of +/// `mapping(address => _)` entries in Solidity. +pub(crate) fn mapping_slot_hash(holder: &Address, map_slot: &[u8; 32]) -> B256 { + let mut buf = [0u8; 64]; + buf[12..32].copy_from_slice(holder.as_slice()); + buf[32..64].copy_from_slice(map_slot); + keccak256(buf) +} diff --git a/crates/balance-overrides/src/lib.rs b/crates/balance-overrides/src/lib.rs new file mode 100644 index 0000000000..688295a50f --- /dev/null +++ b/crates/balance-overrides/src/lib.rs @@ -0,0 +1,391 @@ +pub mod approval; +pub mod balance; +pub mod detector; + +use {alloy_primitives::Address, alloy_rpc_types::state::AccountOverride}; +pub use { + approval::{ApprovalOverrideRequest, ApprovalStrategy}, + balance::BalanceOverrideRequest, +}; + +/// A component that can provide ERC-20 balance and allowance state overrides. +/// +/// This allows a wider range of verified quotes to work, even when balances or +/// approvals are not available for the quoter. +#[async_trait::async_trait] +pub trait StateOverriding: Send + Sync + 'static { + async fn balance_override( + &self, + request: BalanceOverrideRequest, + ) -> Option<(Address, AccountOverride)>; + + async fn approval_override( + &self, + request: ApprovalOverrideRequest, + ) -> Option<(Address, AccountOverride)>; +} + +/// The default state override provider, handling both ERC-20 balance and +/// allowance overrides. +#[derive(Debug)] +pub struct StateOverrides { + pub(crate) balance_detector: balance::Detector, + pub(crate) approval_detector: approval::Detector, +} + +impl StateOverrides { + /// Creates a new instance with default detection parameters. + pub fn new(web3: ethrpc::Web3) -> Self { + Self::with_config(web3, 60, detector::DEFAULT_VERIFICATION_TIMEOUT, 1000) + } + + /// Creates a new instance with custom detection parameters. + pub fn with_config( + web3: ethrpc::Web3, + probing_depth: u8, + verification_timeout: std::time::Duration, + cache_size: u64, + ) -> Self { + Self { + balance_detector: balance::Detector::new( + web3.clone(), + probing_depth, + verification_timeout, + cache_size, + ), + approval_detector: approval::Detector::new( + web3, + probing_depth, + verification_timeout, + cache_size, + ), + } + } +} + +#[async_trait::async_trait] +impl StateOverriding for StateOverrides { + async fn balance_override( + &self, + request: BalanceOverrideRequest, + ) -> Option<(Address, AccountOverride)> { + let strategy = self + .balance_detector + .detect(request.token, request.holder) + .await?; + + strategy + .state_override(&request.holder, &request.amount) + .await + .into_iter() + .last() + } + + async fn approval_override( + &self, + request: ApprovalOverrideRequest, + ) -> Option<(Address, AccountOverride)> { + let strategy = self + .approval_detector + .detect(request.token, request.owner, request.spender) + .await?; + strategy + .state_override(request.owner, request.spender, request.amount) + .into_iter() + .last() + } +} + +/// State overrider that always returns `None`. Useful for testing. +pub struct DummyStateOverrider; + +#[async_trait::async_trait] +impl StateOverriding for DummyStateOverrider { + async fn balance_override( + &self, + _request: BalanceOverrideRequest, + ) -> Option<(Address, AccountOverride)> { + None + } + + async fn approval_override( + &self, + _request: ApprovalOverrideRequest, + ) -> Option<(Address, AccountOverride)> { + None + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::balance::Strategy, + alloy_primitives::{B256, U256, address, b256}, + ethrpc::mock, + }; + + #[tokio::test] + async fn balance_override_computation() { + let cow = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let holder = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let amount = U256::from(0x42); + let strategy = Strategy::SolidityMapping { + target_contract: cow, + map_slot: U256::from(0), + shift_bits: 0, + }; + + let result = strategy + .state_override(&holder, &amount) + .await + .into_iter() + .last(); + assert_eq!( + result, + Some(( + cow, + AccountOverride { + state_diff: Some( + std::iter::once(( + b256!( + "fca351f4d96129454cfc8ef7930b638ac71fea35eb69ee3b8d959496beb04a33" + ), + b256!( + "0000000000000000000000000000000000000000000000000000000000000042" + ) + )) + .collect() + ), + ..Default::default() + } + )), + ); + } + + #[tokio::test] + async fn balance_overrides_none_for_unknown_tokens() { + let state_overrides = DummyStateOverrider; + assert_eq!( + state_overrides + .balance_override(BalanceOverrideRequest { + token: address!("0000000000000000000000000000000000000000"), + holder: address!("0000000000000000000000000000000000000001"), + amount: U256::ZERO, + }) + .await, + None, + ); + } + + #[tokio::test] + async fn balance_override_computation_solady() { + let token = address!("0000000000c5dc95539589fbd24be07c6c14eca4"); + let holder = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let amount = U256::from(0x42); + let strategy = Strategy::SoladyMapping { + target_contract: address!("0000000000c5dc95539589fbd24be07c6c14eca4"), + shift_bits: 0, + }; + + let result = strategy + .state_override(&holder, &amount) + .await + .into_iter() + .last(); + assert_eq!( + result, + Some(( + token, + AccountOverride { + state_diff: Some({ + std::iter::once(( + b256!( + "f6a6656ed2d14bad3cdd3e8871db3f535a136a1b6cd5ae2dced8eb813f3d4e4f" + ), + b256!( + "0000000000000000000000000000000000000000000000000000000000000042" + ), + )) + .collect() + }), + ..Default::default() + } + )), + ); + } + + #[tokio::test] + async fn cached_detection_caches_holder_agnostic_strategies_without_holder() { + let token = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let holder1 = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let holder2 = address!("0000000000000000000000000000000000000001"); + let target_contract = address!("0000000000000000000000000000000000000002"); + + let strategy = Strategy::SolidityMapping { + target_contract, + map_slot: U256::from(3), + shift_bits: 0, + }; + + let mock_web3 = mock::web3(); + let state_overrides = StateOverrides::new(mock_web3); + + state_overrides + .balance_detector + .cache + .insert((token, None), Some(strategy.clone())); + + assert_eq!( + state_overrides + .balance_detector + .detect(token, holder1) + .await, + Some(strategy.clone()) + ); + assert_eq!( + state_overrides + .balance_detector + .detect(token, holder2) + .await, + Some(strategy) + ); + } + + #[tokio::test] + async fn cached_detection_caches_holder_specific_strategies_with_holder() { + let token = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let holder1 = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let holder2 = address!("0000000000000000000000000000000000000001"); + let target_contract = address!("0000000000000000000000000000000000000002"); + + let strategy_h1 = Strategy::DirectSlot { + target_contract, + slot: B256::repeat_byte(1), + shift_bits: 0, + }; + let strategy_h2 = Strategy::DirectSlot { + target_contract, + slot: B256::repeat_byte(2), + shift_bits: 0, + }; + + let mock_web3 = mock::web3(); + let state_overrides = StateOverrides::new(mock_web3); + + state_overrides + .balance_detector + .cache + .insert((token, Some(holder1)), Some(strategy_h1.clone())); + state_overrides + .balance_detector + .cache + .insert((token, Some(holder2)), Some(strategy_h2.clone())); + + assert_eq!( + state_overrides + .balance_detector + .detect(token, holder1) + .await, + Some(strategy_h1) + ); + assert_eq!( + state_overrides + .balance_detector + .detect(token, holder2) + .await, + Some(strategy_h2) + ); + } + + /// Universal strategies can be used to compute the state override for + /// any spender or owner inputs. This test asserts that we cache those + /// with the key (token, None). + #[tokio::test] + async fn caches_universal_approval_strategy_without_inputs() { + let token = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let owner1 = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let spender1 = Address::with_last_byte(1); + let owner2 = Address::with_last_byte(2); + let spender2 = Address::with_last_byte(3); + let target_contract = Address::with_last_byte(4); + + let strategy = ApprovalStrategy::SolidityMappingOwnerToSpender { + target_contract, + map_slot: U256::from(1), + }; + + let mock_web3 = mock::web3(); + let state_overrides = StateOverrides::new(mock_web3); + + state_overrides + .approval_detector + .cache + .insert((token, None), Some(strategy.clone())); + + assert_eq!( + state_overrides + .approval_detector + .detect(token, owner1, spender1) + .await, + Some(strategy.clone()) + ); + assert_eq!( + state_overrides + .approval_detector + .detect(token, owner2, spender2) + .await, + Some(strategy) + ); + } + + /// Some strategies can not be used to compute the state override for + /// any spender or owner inputs. This test asserts that we cache those + /// with the key (token, (owner, spender)) as they only work for those + /// specific inputs. + #[tokio::test] + async fn caches_input_specific_approval_strategy_with_inputs() { + let token = address!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); + let owner1 = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + let spender1 = Address::with_last_byte(1); + let owner2 = Address::with_last_byte(2); + let spender2 = Address::with_last_byte(3); + let target_contract = Address::with_last_byte(4); + + let strategy_p1 = ApprovalStrategy::DirectSlot { + target_contract, + slot: alloy_primitives::B256::repeat_byte(1), + }; + let strategy_p2 = ApprovalStrategy::DirectSlot { + target_contract, + slot: alloy_primitives::B256::repeat_byte(2), + }; + + let mock_web3 = mock::web3(); + let state_overrides = StateOverrides::new(mock_web3); + + state_overrides + .approval_detector + .cache + .insert((token, Some((owner1, spender1))), Some(strategy_p1.clone())); + state_overrides + .approval_detector + .cache + .insert((token, Some((owner2, spender2))), Some(strategy_p2.clone())); + + assert_eq!( + state_overrides + .approval_detector + .detect(token, owner1, spender1) + .await, + Some(strategy_p1) + ); + assert_eq!( + state_overrides + .approval_detector + .detect(token, owner2, spender2) + .await, + Some(strategy_p2) + ); + } +} diff --git a/crates/byos/Cargo.toml b/crates/byos/Cargo.toml new file mode 100644 index 0000000000..dd4f8bf5fd --- /dev/null +++ b/crates/byos/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "byos" +version = "0.1.0" +edition = "2024" + +[lib] +doctest = false +name = "byos" +path = "src/lib.rs" + +[[bin]] +name = "byos" +path = "src/main.rs" + +[dependencies] +alloy-primitives = { workspace = true } +alloy-sol-types = { workspace = true } +axum = { workspace = true } +chrono = { workspace = true, default-features = false, features = ["serde"] } +clap = { workspace = true, features = ["derive", "env"] } +const-hex = { workspace = true } +number = { workspace = true } +observe = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +serde_with = { workspace = true } +serde-ext = { workspace = true } +solvers-dto = { workspace = true } +tikv-jemallocator = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "sync"] } +toml = { workspace = true } +tower = { workspace = true } +tower-http = { workspace = true, features = ["limit", "trace"] } +tracing = { workspace = true } + +# TODO: re-evaluate these dependencies as the crate stabilizes +shared = { workspace = true } + +[dev-dependencies] +alloy-signer = { workspace = true } +alloy-signer-local = { workspace = true } + +[build-dependencies] +anyhow = { workspace = true } +vergen = { workspace = true, features = ["git", "gitcl"] } + +[lints] +workspace = true diff --git a/crates/byos/build.rs b/crates/byos/build.rs new file mode 100644 index 0000000000..4d2899eaf0 --- /dev/null +++ b/crates/byos/build.rs @@ -0,0 +1,5 @@ +fn main() { + if let Err(err) = vergen::EmitBuilder::builder().git_sha(true).emit() { + eprintln!("WARN: vergen failed: {err:?}"); + } +} diff --git a/crates/byos/config/example.toml b/crates/byos/config/example.toml new file mode 100644 index 0000000000..d04d9daa96 --- /dev/null +++ b/crates/byos/config/example.toml @@ -0,0 +1 @@ +chain-id = 1 diff --git a/crates/byos/src/api/mod.rs b/crates/byos/src/api/mod.rs new file mode 100644 index 0000000000..57e84e9c55 --- /dev/null +++ b/crates/byos/src/api/mod.rs @@ -0,0 +1,62 @@ +use { + crate::domain::proposal::ProposalStore, + alloy_sol_types::Eip712Domain, + observe::tracing::distributed::axum::{make_span, record_trace_id}, + std::{future::Future, net::SocketAddr, sync::Arc}, + tokio::sync::oneshot, +}; + +mod routes; + +const REQUEST_BODY_LIMIT: usize = 10 * 1024 * 1024; + +pub struct AppState { + pub store: ProposalStore, + pub domain: Eip712Domain, +} + +pub struct Api { + pub addr: SocketAddr, + pub state: AppState, +} + +impl Api { + pub async fn serve( + self, + bind: Option>, + shutdown: impl Future + Send + 'static, + ) -> Result<(), std::io::Error> { + let app = axum::Router::new() + .layer(tower::ServiceBuilder::new().layer( + tower_http::limit::RequestBodyLimitLayer::new(REQUEST_BODY_LIMIT), + )) + .route("/metrics", axum::routing::get(routes::metrics)) + .route("/healthz", axum::routing::get(routes::healthz)) + .route("/solve", axum::routing::post(routes::solve)) + .route("/proposals", axum::routing::post(routes::submit_proposal)) + .route( + "/proposals/{order_uid}", + axum::routing::get(routes::get_proposals), + ) + .route( + "/proposals/{id}/cancel", + axum::routing::delete(routes::cancel_proposal), + ) + .layer( + tower::ServiceBuilder::new() + .layer(tower_http::trace::TraceLayer::new_for_http().make_span_with(make_span)) + .map_request(record_trace_id), + ) + .with_state(Arc::new(self.state)) + .layer(axum::extract::DefaultBodyLimit::disable()); + + let listener = tokio::net::TcpListener::bind(self.addr).await?; + if let Some(bind) = bind { + let _ = bind.send(listener.local_addr()?); + } + + axum::serve(listener, app) + .with_graceful_shutdown(shutdown) + .await + } +} diff --git a/crates/byos/src/api/routes/mod.rs b/crates/byos/src/api/routes/mod.rs new file mode 100644 index 0000000000..7ba11dcc13 --- /dev/null +++ b/crates/byos/src/api/routes/mod.rs @@ -0,0 +1,16 @@ +mod proposals; +mod solve; + +pub use { + proposals::{cancel_proposal, get_proposals, submit_proposal}, + solve::solve, +}; + +pub async fn healthz() -> &'static str { + "OK" +} + +pub async fn metrics() -> String { + let registry = observe::metrics::get_registry(); + observe::metrics::encode(registry) +} diff --git a/crates/byos/src/api/routes/proposals.rs b/crates/byos/src/api/routes/proposals.rs new file mode 100644 index 0000000000..5529210ac4 --- /dev/null +++ b/crates/byos/src/api/routes/proposals.rs @@ -0,0 +1,150 @@ +use { + crate::{ + api::AppState, + domain::{ + eip712::{self, ProposalData, order_uid_hash}, + proposal::{Interaction, Proposal}, + }, + }, + alloy_primitives::U256, + axum::{ + Json, + extract::{Path, State}, + http::StatusCode, + response::IntoResponse, + }, + number::serialization::HexOrDecimalU256, + serde::{Deserialize, Serialize}, + serde_with::serde_as, + std::sync::Arc, +}; + +#[serde_as] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SubmitProposalRequest { + #[serde_as(as = "serde_ext::Hex")] + pub order_uid: Vec, + #[serde_as(as = "HexOrDecimalU256")] + pub sell_amount: U256, + #[serde_as(as = "HexOrDecimalU256")] + pub buy_amount: U256, + pub interactions: Vec, + pub valid_until: u64, + #[serde_as(as = "HexOrDecimalU256")] + pub nonce: U256, + #[serde_as(as = "serde_ext::Hex")] + pub signature: Vec, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SubmitProposalResponse { + pub id: u64, +} + +pub async fn submit_proposal( + State(state): State>, + Json(request): Json, +) -> impl IntoResponse { + let order_uid: [u8; 56] = match request.order_uid.try_into() { + Ok(uid) => uid, + Err(_) => { + return ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!({"error": "order_uid must be 56 bytes"})), + ); + } + }; + + let signature: [u8; 65] = match request.signature.try_into() { + Ok(sig) => sig, + Err(_) => { + return ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!({"error": "signature must be 65 bytes"})), + ); + } + }; + + let proposal_data = ProposalData { + orderUidHash: order_uid_hash(&order_uid), + sellAmount: request.sell_amount, + buyAmount: request.buy_amount, + validUntil: U256::from(request.valid_until), + nonce: request.nonce, + }; + + let solver = match eip712::recover_signer(&proposal_data, &signature, &state.domain) { + Some(addr) => addr, + None => { + return ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!({"error": "invalid signature"})), + ); + } + }; + + let proposal = Proposal { + id: 0, // will be set by store + order_uid, + sell_amount: request.sell_amount, + buy_amount: request.buy_amount, + interactions: request.interactions, + solver, + valid_until: request.valid_until, + nonce: request.nonce, + }; + + let id = state.store.insert(proposal).await; + tracing::info!(%id, %solver, "proposal accepted"); + + ( + StatusCode::CREATED, + Json(serde_json::json!(SubmitProposalResponse { id })), + ) +} + +pub async fn get_proposals( + State(state): State>, + Path(order_uid_hex): Path, +) -> impl IntoResponse { + let uid_bytes = match const_hex::decode(&order_uid_hex) { + Ok(bytes) => bytes, + Err(_) => { + return ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!({"error": "invalid order_uid hex"})), + ); + } + }; + + let order_uid: [u8; 56] = match uid_bytes.try_into() { + Ok(uid) => uid, + Err(_) => { + return ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!({"error": "order_uid must be 56 bytes"})), + ); + } + }; + + match state.store.get_metadata(&order_uid).await { + Some(meta) => (StatusCode::OK, Json(serde_json::to_value(meta).unwrap())), + None => ( + StatusCode::NOT_FOUND, + Json(serde_json::json!({"error": "no proposals for this order"})), + ), + } +} + +pub async fn cancel_proposal( + State(state): State>, + Path(id): Path, +) -> impl IntoResponse { + if state.store.remove(id).await { + StatusCode::NO_CONTENT + } else { + StatusCode::NOT_FOUND + } +} diff --git a/crates/byos/src/api/routes/solve.rs b/crates/byos/src/api/routes/solve.rs new file mode 100644 index 0000000000..5e2a97f69e --- /dev/null +++ b/crates/byos/src/api/routes/solve.rs @@ -0,0 +1,99 @@ +use { + crate::api::AppState, + axum::{Json, extract::State, http::StatusCode, response::IntoResponse}, + solvers_dto::solution::{ + CustomInteraction, + Fulfillment, + Interaction, + OrderUid, + Solution, + SolverResponse, + Trade, + }, + std::sync::Arc, + tracing::Instrument, +}; + +pub async fn solve( + State(state): State>, + Json(auction): Json, +) -> impl IntoResponse { + let handle_request = async { + let auction_id = auction.id.unwrap_or(-1); + tracing::info!(%auction_id, orders = auction.orders.len(), "received /solve"); + + let mut solutions = Vec::new(); + + for (i, order) in auction.orders.iter().enumerate() { + let Some(proposal) = state.store.get_best(&order.uid).await else { + continue; + }; + + tracing::debug!( + order_uid = %const_hex::encode_prefixed(order.uid), + solver = %proposal.solver, + sell_amount = %proposal.sell_amount, + buy_amount = %proposal.buy_amount, + "matched proposal to order", + ); + + let executed_amount = match order.kind { + solvers_dto::auction::Kind::Sell => proposal.sell_amount, + solvers_dto::auction::Kind::Buy => proposal.buy_amount, + }; + + let solution = Solution { + id: i as u64, + prices: [ + (order.sell_token, proposal.buy_amount), + (order.buy_token, proposal.sell_amount), + ] + .into_iter() + .collect(), + trades: vec![Trade::Fulfillment(Fulfillment { + order: OrderUid(order.uid), + executed_amount, + fee: Some(alloy_primitives::U256::ZERO), + })], + interactions: proposal + .interactions + .iter() + .map(|i| { + Interaction::Custom(CustomInteraction { + internalize: false, + target: i.target, + value: i.value, + calldata: i.calldata.clone(), + allowances: vec![], + inputs: vec![], + outputs: vec![], + }) + }) + .collect(), + pre_interactions: vec![], + post_interactions: vec![], + gas: None, + gas_fee_override: None, + flashloans: None, + wrappers: vec![], + }; + + solutions.push(solution); + } + + tracing::info!( + %auction_id, + matched = solutions.len(), + "returning solutions", + ); + + ( + StatusCode::OK, + Json(SolverResponse::Solutions { solutions }), + ) + }; + + handle_request + .instrument(tracing::info_span!("/solve")) + .await +} diff --git a/crates/byos/src/domain/eip712.rs b/crates/byos/src/domain/eip712.rs new file mode 100644 index 0000000000..d7fe9b1ce6 --- /dev/null +++ b/crates/byos/src/domain/eip712.rs @@ -0,0 +1,74 @@ +use { + alloy_primitives::{Address, B256, keccak256}, + alloy_sol_types::{Eip712Domain, SolStruct, sol}, +}; + +sol! { + /// EIP-712 typed data for BYOS proposals. + #[derive(Default)] + struct ProposalData { + /// keccak256 of the 56-byte order UID + bytes32 orderUidHash; + uint256 sellAmount; + uint256 buyAmount; + uint256 validUntil; + uint256 nonce; + } +} + +pub fn byos_domain(chain_id: u64) -> Eip712Domain { + Eip712Domain { + name: Some("BYOS".into()), + version: Some("1".into()), + chain_id: Some(alloy_primitives::U256::from(chain_id)), + verifying_contract: None, + salt: None, + } +} + +/// Recovers the signer address from a signed proposal. +pub fn recover_signer( + proposal: &ProposalData, + signature: &[u8; 65], + domain: &Eip712Domain, +) -> Option
{ + let signing_hash = proposal.eip712_signing_hash(domain); + let sig = alloy_primitives::Signature::from_raw(signature).ok()?; + sig.recover_address_from_prehash(&signing_hash).ok() +} + +/// Computes the order UID hash used in the EIP-712 struct. +pub fn order_uid_hash(order_uid: &[u8; 56]) -> B256 { + keccak256(order_uid) +} + +#[cfg(test)] +mod tests { + use { + super::*, + alloy_primitives::U256, + alloy_signer::SignerSync, + alloy_signer_local::PrivateKeySigner, + }; + + #[test] + fn sign_and_recover_proposal() { + let signer = PrivateKeySigner::random(); + let domain = byos_domain(1); + + let proposal = ProposalData { + orderUidHash: B256::ZERO, + sellAmount: U256::from(1000), + buyAmount: U256::from(2000), + validUntil: U256::from(u64::MAX), + nonce: U256::ZERO, + }; + + let signing_hash = proposal.eip712_signing_hash(&domain); + let sig = signer.sign_hash_sync(&signing_hash).unwrap(); + let sig_bytes: [u8; 65] = sig.as_bytes(); + + let recovered = recover_signer(&proposal, &sig_bytes, &domain).unwrap(); + assert_eq!(recovered, signer.address()); + } +} diff --git a/crates/byos/src/domain/mod.rs b/crates/byos/src/domain/mod.rs new file mode 100644 index 0000000000..c179d8f944 --- /dev/null +++ b/crates/byos/src/domain/mod.rs @@ -0,0 +1,2 @@ +pub mod eip712; +pub mod proposal; diff --git a/crates/byos/src/domain/proposal.rs b/crates/byos/src/domain/proposal.rs new file mode 100644 index 0000000000..a6e6ce236b --- /dev/null +++ b/crates/byos/src/domain/proposal.rs @@ -0,0 +1,183 @@ +use { + alloy_primitives::{Address, U256}, + std::{ + collections::HashMap, + sync::atomic::{AtomicU64, Ordering}, + }, + tokio::sync::RwLock, +}; + +#[derive(Debug, Clone)] +pub struct Proposal { + pub id: u64, + pub order_uid: [u8; 56], + pub sell_amount: U256, + pub buy_amount: U256, + pub interactions: Vec, + pub solver: Address, + pub valid_until: u64, + pub nonce: U256, +} + +#[serde_with::serde_as] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Interaction { + pub target: Address, + #[serde_as(as = "number::serialization::HexOrDecimalU256")] + pub value: U256, + #[serde_as(as = "serde_ext::Hex")] + pub calldata: Vec, +} + +pub struct ProposalStore { + proposals: RwLock>>, + next_id: AtomicU64, +} + +impl ProposalStore { + pub fn new() -> Self { + Self { + proposals: RwLock::new(HashMap::new()), + next_id: AtomicU64::new(1), + } + } + + pub async fn insert(&self, mut proposal: Proposal) -> u64 { + let id = self.next_id.fetch_add(1, Ordering::Relaxed); + proposal.id = id; + let order_uid = proposal.order_uid; + self.proposals + .write() + .await + .entry(order_uid) + .or_default() + .push(proposal); + id + } + + /// Returns the best proposal for the given order UID (highest + /// buy_amount/sell_amount ratio = best surplus for the user). + pub async fn get_best(&self, order_uid: &[u8; 56]) -> Option { + let proposals = self.proposals.read().await; + let candidates = proposals.get(order_uid)?; + let now = chrono::Utc::now().timestamp() as u64; + candidates + .iter() + .filter(|p| p.valid_until > now) + .max_by(|a, b| { + // Compare surplus: a.buy/a.sell vs b.buy/b.sell + // Cross-multiply to avoid division: a.buy * b.sell vs b.buy * a.sell + let lhs = a.buy_amount.wrapping_mul(b.sell_amount); + let rhs = b.buy_amount.wrapping_mul(a.sell_amount); + lhs.cmp(&rhs) + }) + .cloned() + } + + pub async fn get_metadata(&self, order_uid: &[u8; 56]) -> Option { + let proposals = self.proposals.read().await; + let candidates = proposals.get(order_uid)?; + let now = chrono::Utc::now().timestamp() as u64; + let active: Vec<_> = candidates.iter().filter(|p| p.valid_until > now).collect(); + if active.is_empty() { + return None; + } + Some(ProposalMetadata { + count: active.len(), + }) + } + + pub async fn remove(&self, id: u64) -> bool { + let mut proposals = self.proposals.write().await; + for candidates in proposals.values_mut() { + if let Some(pos) = candidates.iter().position(|p| p.id == id) { + candidates.remove(pos); + return true; + } + } + false + } +} + +#[derive(Debug, serde::Serialize)] +pub struct ProposalMetadata { + pub count: usize, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn insert_and_get_best() { + let store = ProposalStore::new(); + let uid = [0u8; 56]; + + let p1 = Proposal { + id: 0, + order_uid: uid, + sell_amount: U256::from(1000), + buy_amount: U256::from(2000), + interactions: vec![], + solver: Address::ZERO, + valid_until: u64::MAX, + nonce: U256::ZERO, + }; + let p2 = Proposal { + id: 0, + order_uid: uid, + sell_amount: U256::from(1000), + buy_amount: U256::from(3000), // better surplus + interactions: vec![], + solver: Address::ZERO, + valid_until: u64::MAX, + nonce: U256::from(1), + }; + + store.insert(p1).await; + store.insert(p2).await; + + let best = store.get_best(&uid).await.unwrap(); + assert_eq!(best.buy_amount, U256::from(3000)); + } + + #[tokio::test] + async fn expired_proposals_filtered() { + let store = ProposalStore::new(); + let uid = [0u8; 56]; + + let p = Proposal { + id: 0, + order_uid: uid, + sell_amount: U256::from(1000), + buy_amount: U256::from(2000), + interactions: vec![], + solver: Address::ZERO, + valid_until: 0, // already expired + nonce: U256::ZERO, + }; + store.insert(p).await; + assert!(store.get_best(&uid).await.is_none()); + } + + #[tokio::test] + async fn remove_proposal() { + let store = ProposalStore::new(); + let uid = [0u8; 56]; + + let p = Proposal { + id: 0, + order_uid: uid, + sell_amount: U256::from(1000), + buy_amount: U256::from(2000), + interactions: vec![], + solver: Address::ZERO, + valid_until: u64::MAX, + nonce: U256::ZERO, + }; + let id = store.insert(p).await; + assert!(store.remove(id).await); + assert!(store.get_best(&uid).await.is_none()); + } +} diff --git a/crates/byos/src/infra/cli.rs b/crates/byos/src/infra/cli.rs new file mode 100644 index 0000000000..39a54d6d30 --- /dev/null +++ b/crates/byos/src/infra/cli.rs @@ -0,0 +1,29 @@ +use { + clap::Parser, + shared::arguments::TracingArguments, + std::{net::SocketAddr, path::PathBuf}, +}; + +/// Run the BYOS (Bring Your Own Solver) engine +#[derive(Parser, Debug)] +#[command(version)] +pub struct Args { + /// The log filter. + #[arg(long, env, default_value = "warn,byos=debug")] + pub log: String, + + /// Whether to use JSON format for the logs. + #[clap(long, env, default_value = "false")] + pub use_json_logs: bool, + + #[clap(flatten)] + pub tracing: TracingArguments, + + /// The socket address to bind to. + #[arg(long, env, default_value = "127.0.0.1:7872")] + pub addr: SocketAddr, + + /// Path to the BYOS configuration file (TOML). + #[arg(long, env)] + pub config: PathBuf, +} diff --git a/crates/byos/src/infra/config.rs b/crates/byos/src/infra/config.rs new file mode 100644 index 0000000000..6a9a44a27c --- /dev/null +++ b/crates/byos/src/infra/config.rs @@ -0,0 +1,15 @@ +use {serde::Deserialize, std::path::Path, tokio::fs}; + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Config { + pub chain_id: u64, +} + +pub async fn load(path: &Path) -> Config { + let data = fs::read_to_string(path) + .await + .unwrap_or_else(|e| panic!("I/O error while reading {path:?}: {e:?}")); + toml::de::from_str::(&data) + .unwrap_or_else(|e| panic!("invalid BYOS config {path:?}: {e:?}")) +} diff --git a/crates/byos/src/infra/mod.rs b/crates/byos/src/infra/mod.rs new file mode 100644 index 0000000000..0eb3da5dbd --- /dev/null +++ b/crates/byos/src/infra/mod.rs @@ -0,0 +1,2 @@ +pub mod cli; +pub mod config; diff --git a/crates/byos/src/lib.rs b/crates/byos/src/lib.rs new file mode 100644 index 0000000000..eaa67cbded --- /dev/null +++ b/crates/byos/src/lib.rs @@ -0,0 +1,6 @@ +pub mod api; +pub mod domain; +mod infra; +mod run; + +pub use self::run::{run, start}; diff --git a/crates/byos/src/main.rs b/crates/byos/src/main.rs new file mode 100644 index 0000000000..c05a4d19eb --- /dev/null +++ b/crates/byos/src/main.rs @@ -0,0 +1,7 @@ +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +#[tokio::main] +async fn main() { + byos::start(std::env::args()).await; +} diff --git a/crates/byos/src/run.rs b/crates/byos/src/run.rs new file mode 100644 index 0000000000..8902cecec8 --- /dev/null +++ b/crates/byos/src/run.rs @@ -0,0 +1,71 @@ +#[cfg(unix)] +use tokio::signal::unix::{self, SignalKind}; +use { + crate::{ + api::{Api, AppState}, + domain::{eip712, proposal::ProposalStore}, + infra::{cli, config}, + }, + clap::Parser, + shared::arguments::tracing_config, + std::net::SocketAddr, + tokio::sync::oneshot, +}; + +pub async fn start(args: impl IntoIterator) { + observe::panic_hook::install(); + let args = cli::Args::parse_from(args); + run_with(args, None).await; +} + +pub async fn run( + args: impl IntoIterator, + bind: Option>, +) { + let args = cli::Args::parse_from(args); + run_with(args, bind).await; +} + +async fn run_with(args: cli::Args, bind: Option>) { + let obs_config = observe::Config::new( + &args.log, + tracing::Level::ERROR.into(), + args.use_json_logs, + tracing_config(&args.tracing, "byos".into()), + ); + observe::tracing::init::initialize_reentrant(&obs_config); + + let commit_hash = option_env!("VERGEN_GIT_SHA").unwrap_or("COMMIT_INFO_NOT_FOUND"); + tracing::info!(%commit_hash, "running BYOS engine with {args:#?}"); + + let config = config::load(&args.config).await; + let domain = eip712::byos_domain(config.chain_id); + + tracing::info!(chain_id = config.chain_id, "BYOS configured"); + + Api { + addr: args.addr, + state: AppState { + store: ProposalStore::new(), + domain, + }, + } + .serve(bind, shutdown_signal()) + .await + .unwrap(); +} + +#[cfg(unix)] +async fn shutdown_signal() { + let mut interrupt = unix::signal(SignalKind::interrupt()).unwrap(); + let mut terminate = unix::signal(SignalKind::terminate()).unwrap(); + tokio::select! { + _ = interrupt.recv() => (), + _ = terminate.recv() => (), + }; +} + +#[cfg(windows)] +async fn shutdown_signal() { + std::future::pending().await +} diff --git a/crates/bytes-hex/Cargo.toml b/crates/bytes-hex/Cargo.toml index dcfaee348b..65e36a7902 100644 --- a/crates/bytes-hex/Cargo.toml +++ b/crates/bytes-hex/Cargo.toml @@ -8,10 +8,12 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +const-hex = { workspace = true } serde = { workspace = true } -serde_json = { workspace = true } serde_with = { workspace = true } -const-hex = { workspace = true } + +[dev-dependencies] +serde_json = { workspace = true } [lints] workspace = true diff --git a/crates/chain/Cargo.toml b/crates/chain/Cargo.toml index 1da8b517e3..4bbdb1d21d 100644 --- a/crates/chain/Cargo.toml +++ b/crates/chain/Cargo.toml @@ -6,10 +6,8 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] -alloy = { workspace = true } -derive_more = { workspace = true } +alloy-primitives = { workspace = true } serde = { workspace = true } -thiserror = { workspace = true } [dev-dependencies] serde_json = { workspace = true } diff --git a/crates/chain/src/lib.rs b/crates/chain/src/lib.rs index 2833e2a5eb..fd098d7ddc 100644 --- a/crates/chain/src/lib.rs +++ b/crates/chain/src/lib.rs @@ -1,8 +1,7 @@ use { - alloy::primitives::U256, + alloy_primitives::U256, serde::{Deserialize, Deserializer, de}, - std::time::Duration, - thiserror::Error, + std::{error::Error, fmt::Display, time::Duration}, }; /// Represents each available chain @@ -10,7 +9,6 @@ use { #[repr(u64)] pub enum Chain { Mainnet = 1, - Goerli = 5, Gnosis = 100, Sepolia = 11155111, ArbitrumOne = 42161, @@ -20,9 +18,9 @@ pub enum Chain { Avalanche = 43114, Optimism = 10, Polygon = 137, - Lens = 232, Linea = 59144, Plasma = 9745, + Ink = 57073, } impl Chain { @@ -37,7 +35,6 @@ impl Chain { // https://chainid.network/chains.json match &self { Self::Mainnet => "Ethereum / Mainnet", - Self::Goerli => "Ethereum / Goerli", Self::Gnosis => "xDAI", Self::Sepolia => "Ethereum / Sepolia", Self::ArbitrumOne => "Arbitrum One", @@ -47,9 +44,29 @@ impl Chain { Self::Avalanche => "Avalanche", Self::Optimism => "Optimism", Self::Polygon => "Polygon", - Self::Lens => "Lens", Self::Linea => "Linea", Self::Plasma => "Plasma", + Self::Ink => "Ink", + } + } + + /// Kebab-case slug used in URLs and per-network configs (pool-indexer API + /// routes, DB database names, etc). Stable — other services parse it. + pub fn as_str(&self) -> &'static str { + match &self { + Self::Mainnet => "mainnet", + Self::Gnosis => "gnosis", + Self::Sepolia => "sepolia", + Self::ArbitrumOne => "arbitrum-one", + Self::Base => "base", + Self::Hardhat => "hardhat", + Self::Bnb => "bnb", + Self::Avalanche => "avalanche", + Self::Optimism => "optimism", + Self::Polygon => "polygon", + Self::Linea => "linea", + Self::Plasma => "plasma", + Self::Ink => "ink", } } @@ -57,14 +74,14 @@ impl Chain { pub fn default_amount_to_estimate_native_prices_with(&self) -> U256 { match &self { Self::Mainnet - | Self::Goerli | Self::Sepolia | Self::ArbitrumOne | Self::Base | Self::Bnb | Self::Linea - | Self::Optimism => U256::from(10u128.pow(17)), - Self::Gnosis | Self::Avalanche | Self::Lens => U256::from(10u128.pow(18)), + | Self::Optimism + | Self::Ink => U256::from(10u128.pow(17)), + Self::Gnosis | Self::Avalanche => U256::from(10u128.pow(18)), Self::Polygon | Self::Plasma => U256::from(10u128.pow(20)), Self::Hardhat => { panic!("unsupported chain for default amount to estimate native prices with") @@ -76,7 +93,6 @@ impl Chain { pub fn block_time_in_ms(&self) -> Duration { match self { Self::Mainnet => Duration::from_millis(12_000), - Self::Goerli => Duration::from_millis(12_000), Self::Gnosis => Duration::from_millis(5_000), Self::Sepolia => Duration::from_millis(12_000), Self::ArbitrumOne => Duration::from_millis(250), @@ -86,9 +102,9 @@ impl Chain { Self::Avalanche => Duration::from_millis(2_000), Self::Optimism => Duration::from_millis(2_000), Self::Polygon => Duration::from_millis(2_000), - Self::Lens => Duration::from_millis(2_000), Self::Linea => Duration::from_millis(2_000), Self::Plasma => Duration::from_millis(1_000), + Self::Ink => Duration::from_millis(1_000), } } @@ -107,7 +123,6 @@ impl TryFrom for Chain { fn try_from(value: u64) -> Result { let network = match value { x if x == Self::Mainnet as u64 => Self::Mainnet, - x if x == Self::Goerli as u64 => Self::Goerli, x if x == Self::Gnosis as u64 => Self::Gnosis, x if x == Self::Sepolia as u64 => Self::Sepolia, x if x == Self::ArbitrumOne as u64 => Self::ArbitrumOne, @@ -117,9 +132,9 @@ impl TryFrom for Chain { x if x == Self::Avalanche as u64 => Self::Avalanche, x if x == Self::Optimism as u64 => Self::Optimism, x if x == Self::Polygon as u64 => Self::Polygon, - x if x == Self::Lens as u64 => Self::Lens, x if x == Self::Linea as u64 => Self::Linea, x if x == Self::Plasma as u64 => Self::Plasma, + x if x == Self::Ink as u64 => Self::Ink, _ => Err(ChainIdNotSupported)?, }; Ok(network) @@ -172,10 +187,17 @@ impl<'de> Deserialize<'de> for Chain { } } -#[derive(Error, Debug)] -#[error("chain id not supported")] +#[derive(Debug)] pub struct ChainIdNotSupported; +impl Display for ChainIdNotSupported { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "chain id not supported") + } +} + +impl Error for ChainIdNotSupported {} + #[cfg(test)] mod test { use super::*; @@ -186,7 +208,6 @@ mod test { assert_eq!(Chain::Mainnet.blocks_in(TARGET_AGE).round(), 1800.0); assert_eq!(Chain::Sepolia.blocks_in(TARGET_AGE).round(), 1800.0); - assert_eq!(Chain::Goerli.blocks_in(TARGET_AGE).round(), 1800.0); assert_eq!(Chain::Gnosis.blocks_in(TARGET_AGE).round(), 4320.0); assert_eq!(Chain::Base.blocks_in(TARGET_AGE).round(), 10800.0); assert_eq!(Chain::ArbitrumOne.blocks_in(TARGET_AGE).round(), 86400.0); @@ -199,10 +220,6 @@ mod test { let network: Chain = serde_json::from_str(json_data).unwrap(); assert_eq!(network, Chain::Mainnet); - let json_data = "5"; // Should deserialize to Network::Goerli - let network: Chain = serde_json::from_str(json_data).unwrap(); - assert_eq!(network, Chain::Goerli); - let json_data = "100"; // Should deserialize to Network::Gnosis let network: Chain = serde_json::from_str(json_data).unwrap(); assert_eq!(network, Chain::Gnosis); @@ -220,10 +237,6 @@ mod test { let network: Chain = serde_json::from_str(json_data).unwrap(); assert_eq!(network, Chain::Mainnet); - let json_data = "\"5\""; // Should parse to u64 5 and then to Network::Goerli - let network: Chain = serde_json::from_str(json_data).unwrap(); - assert_eq!(network, Chain::Goerli); - let json_data = "\"100\""; // Should parse to u64 100 and then to Network::Gnosis let network: Chain = serde_json::from_str(json_data).unwrap(); assert_eq!(network, Chain::Gnosis); diff --git a/crates/configs/Cargo.toml b/crates/configs/Cargo.toml new file mode 100644 index 0000000000..1e363b8d99 --- /dev/null +++ b/crates/configs/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "configs" +version = "0.1.0" +edition = "2024" + +[dependencies] +alloy = { workspace = true, features = ["signer-aws"] } +anyhow = { workspace = true } +bigdecimal = { workspace = true, features = ["serde"] } +chrono = { workspace = true, features = ["serde"] } +humantime-serde = { workspace = true } +s3 = { workspace = true } +serde = { workspace = true } +tempfile = { workspace = true, optional = true } +thiserror = { workspace = true } +tokio = { workspace = true } +toml = { workspace = true } +tracing = { workspace = true } +url = { workspace = true, features = ["serde"] } + +[dev-dependencies] +rate-limit = { workspace = true, features = ["test-util"] } +serde_json = { workspace = true } +tempfile = { workspace = true } + +[features] +test-util = ["dep:tempfile", "rate-limit/test-util"] + +[lints] +workspace = true diff --git a/crates/configs/src/autopilot/cow_amm.rs b/crates/configs/src/autopilot/cow_amm.rs new file mode 100644 index 0000000000..009317e570 --- /dev/null +++ b/crates/configs/src/autopilot/cow_amm.rs @@ -0,0 +1,70 @@ +use {alloy::primitives::Address, serde::Deserialize, url::Url}; + +/// Configuration for indexing CoW AMMs. +#[derive(Debug, Clone, Default, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct CowAmmGroupConfig { + /// List of CoW AMM factory/helper/start-block configurations. + #[serde(default)] + pub contracts: Vec, + + /// Archive node URL used to index CoW AMMs. + pub archive_node_url: Option, +} + +/// A single CoW AMM factory configuration. +#[derive(Debug, Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct CowAmmConfig { + /// Contract address emitting CoW AMM deployment events. + pub factory: Address, + + /// Contract address to interface with pools deployed by the factory. + pub helper: Address, + + /// Block at which indexing should start (1 block before factory + /// deployment). + pub index_start: u64, +} + +#[cfg(test)] +mod tests { + use {super::*, alloy::primitives::address}; + + #[test] + fn deserialize_defaults() { + let config: CowAmmGroupConfig = toml::from_str("").unwrap(); + assert!(config.contracts.is_empty()); + assert!(config.archive_node_url.is_none()); + } + + #[test] + fn deserialize_full() { + let toml = r#" + archive-node-url = "http://archive.example.com" + + [[contracts]] + factory = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + helper = "0xdAC17F958D2ee523a2206206994597C13D831ec7" + index-start = 12345678 + + [[contracts]] + factory = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + helper = "0x6B175474E89094C44Da98b954EedeAC495271d0F" + index-start = 99999999 + "#; + let config: CowAmmGroupConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.contracts.len(), 2); + assert_eq!( + config.contracts[0].factory, + address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + ); + assert_eq!(config.contracts[0].index_start, 12345678); + assert_eq!( + config.archive_node_url.unwrap().as_str(), + "http://archive.example.com/" + ); + } +} diff --git a/crates/configs/src/autopilot/ethflow.rs b/crates/configs/src/autopilot/ethflow.rs new file mode 100644 index 0000000000..9ee9cc10af --- /dev/null +++ b/crates/configs/src/autopilot/ethflow.rs @@ -0,0 +1,58 @@ +use {alloy::primitives::Address, serde::Deserialize}; + +/// Configuration for eth-flow order indexing and processing. +#[derive(Debug, Clone, Default, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct EthflowConfig { + /// Address of the ethflow contracts. If empty, eth-flow orders are + /// disabled. Multiple contracts supported for migration transition + /// periods. + #[serde(default)] + pub contracts: Vec
, + + /// Timestamp at which we should start indexing eth-flow contract events. + /// Ignored if events already exist in the database for a later date. + pub indexing_start: Option, + + /// Skip syncing past events (useful for local deployments). + #[serde(default)] + pub skip_event_sync: bool, +} + +#[cfg(any(test, feature = "test-util"))] +impl crate::test_util::TestDefault for EthflowConfig { + fn test_default() -> Self { + Self { + skip_event_sync: true, + // In E2E tests the contracts are added later + ..Default::default() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_defaults() { + let config: EthflowConfig = toml::from_str("").unwrap(); + assert!(config.contracts.is_empty()); + assert!(config.indexing_start.is_none()); + assert!(!config.skip_event_sync); + } + + #[test] + fn deserialize_full() { + let toml = r#" + contracts = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + indexing-start = 12345678 + skip-event-sync = true + "#; + let config: EthflowConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.contracts.len(), 1); + assert_eq!(config.indexing_start, Some(12345678)); + assert!(config.skip_event_sync); + } +} diff --git a/crates/configs/src/autopilot/fee_policy.rs b/crates/configs/src/autopilot/fee_policy.rs new file mode 100644 index 0000000000..d0eb13cc33 --- /dev/null +++ b/crates/configs/src/autopilot/fee_policy.rs @@ -0,0 +1,188 @@ +use { + crate::fee_factor::FeeFactor, + chrono::{DateTime, Utc}, + serde::{Deserialize, Serialize}, +}; + +pub const fn default_max_partner_fee() -> FeeFactor { + FeeFactor::new(0.01) +} + +/// Protocol fee configuration: which fee model to apply per order class. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct FeePoliciesConfig { + /// Describes how the protocol fees should be calculated. + #[serde(default)] + pub policies: Vec, + + /// Maximum partner fee allowed. If the partner fee specified is greater + /// than this maximum, the partner fee will be capped. + #[serde(default = "default_max_partner_fee")] + pub max_partner_fee: FeeFactor, + + /// Fee policies that will become effective at a future timestamp. + #[serde(default)] + pub upcoming_policies: UpcomingFeePolicies, +} + +impl Default for FeePoliciesConfig { + fn default() -> Self { + Self { + policies: Default::default(), + max_partner_fee: default_max_partner_fee(), + upcoming_policies: Default::default(), + } + } +} + +/// A fee policy to be used for orders based on its class. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct FeePolicy { + /// The fee calculation method (surplus, price-improvement, or volume). + pub kind: FeePolicyKind, + /// Which order class this policy applies to. + pub order_class: FeePolicyOrderClass, +} + +/// Fee policies that will become effective at a future timestamp. +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct UpcomingFeePolicies { + /// Policies that will replace the current ones at the effective timestamp. + #[serde(default)] + pub policies: Vec, + + /// Timestamp from which the `policies` will become active. + pub effective_from_timestamp: Option>, +} + +/// Method used to calculate the protocol fee for an order. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum FeePolicyKind { + /// How much of the order's surplus should be taken as a protocol fee. + #[serde(rename_all = "kebab-case")] + Surplus { + factor: FeeFactor, + max_volume_factor: FeeFactor, + }, + /// How much of the order's price improvement should be taken as a protocol + /// fee where price improvement is a difference between the executed price + /// and the best quote. + #[serde(rename_all = "kebab-case")] + PriceImprovement { + factor: FeeFactor, + max_volume_factor: FeeFactor, + }, + /// How much of the order's volume should be taken as a protocol fee. + Volume { factor: FeeFactor }, +} + +/// Which order class a fee policy targets. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum FeePolicyOrderClass { + /// If a fee policy needs to be applied to in-market orders. + Market, + /// If a fee policy needs to be applied to limit orders. + Limit, + /// If a fee policy needs to be applied regardless of the order class. + Any, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_fee_policy_surplus() { + let toml = r#" + kind.surplus = { factor = 0.5, max-volume-factor = 0.9 } + order-class = "limit" + "#; + let policy: FeePolicy = toml::from_str(toml).unwrap(); + assert!(matches!( + policy.kind, + FeePolicyKind::Surplus { factor, max_volume_factor } + if factor.get() == 0.5 && max_volume_factor.get() == 0.9 + )); + assert!(matches!(policy.order_class, FeePolicyOrderClass::Limit)); + } + + #[test] + fn deserialize_fee_policy_volume() { + let toml = r#" + kind.volume = { factor = 0.1 } + order-class = "any" + "#; + let policy: FeePolicy = toml::from_str(toml).unwrap(); + assert!(matches!( + policy.kind, + FeePolicyKind::Volume { factor } if factor.get() == 0.1 + )); + assert!(matches!(policy.order_class, FeePolicyOrderClass::Any)); + } + + #[test] + fn deserialize_fee_policy_price_improvement() { + let toml = r#" + kind.price-improvement = { factor = 0.5, max-volume-factor = 0.06 } + order-class = "market" + "#; + let policy: FeePolicy = toml::from_str(toml).unwrap(); + assert!(matches!( + policy.kind, + FeePolicyKind::PriceImprovement { factor, max_volume_factor } + if factor.get() == 0.5 && max_volume_factor.get() == 0.06 + )); + assert!(matches!(policy.order_class, FeePolicyOrderClass::Market)); + } + + #[test] + fn deserialize_fee_policies_config_defaults() { + let toml = ""; + let config: FeePoliciesConfig = toml::from_str(toml).unwrap(); + assert!(config.policies.is_empty()); + assert_eq!(config.max_partner_fee.get(), 0.01); + assert!(config.upcoming_policies.policies.is_empty()); + assert!(config.upcoming_policies.effective_from_timestamp.is_none()); + } + + #[test] + fn deserialize_fee_policies_config_full() { + let toml = r#" + max-partner-fee = 0.005 + + [[policies]] + kind.surplus = { factor = 0.5, max-volume-factor = 0.9 } + order-class = "limit" + + [[policies]] + kind.volume = { factor = 0.1 } + order-class = "any" + + [upcoming-policies] + effective-from-timestamp = "2025-06-01T00:00:00Z" + + [[upcoming-policies.policies]] + kind.volume = { factor = 0.2 } + order-class = "any" + "#; + let config: FeePoliciesConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.policies.len(), 2); + assert_eq!(config.max_partner_fee.get(), 0.005); + assert_eq!(config.upcoming_policies.policies.len(), 1); + assert!(config.upcoming_policies.effective_from_timestamp.is_some()); + } + + #[test] + fn deserialize_invalid_fee_factor() { + let toml = r#" + kind.volume = { factor = 1.5 } + order-class = "any" + "#; + assert!(toml::from_str::(toml).is_err()); + } +} diff --git a/crates/configs/src/autopilot/mod.rs b/crates/configs/src/autopilot/mod.rs new file mode 100644 index 0000000000..8dd4492e1d --- /dev/null +++ b/crates/configs/src/autopilot/mod.rs @@ -0,0 +1,544 @@ +use { + crate::{ + autopilot::{ + cow_amm::CowAmmGroupConfig, + ethflow::EthflowConfig, + fee_policy::FeePoliciesConfig, + native_price::NativePriceConfig, + order_events_cleanup::OrderEventsCleanupConfig, + run_loop::RunLoopConfig, + s3::S3Config, + solver::Solver, + trusted_tokens::TrustedTokensConfig, + }, + banned_users::BannedUsersConfig, + database::DatabasePoolConfig, + http_client::HttpClient, + order_quoting::OrderQuoting, + price_estimation::PriceEstimation, + shared::SharedConfig, + }, + alloy::primitives::Address, + anyhow::{anyhow, ensure}, + serde::Deserialize, + std::{net::SocketAddr, path::Path, time::Duration}, + url::Url, +}; + +pub mod cow_amm; +pub mod ethflow; +pub mod fee_policy; +pub mod native_price; +pub mod order_events_cleanup; +pub mod run_loop; +pub mod s3; +pub mod solver; +pub mod trusted_tokens; + +fn default_metrics_address() -> SocketAddr { + "0.0.0.0:9589".parse().unwrap() +} + +fn default_api_address() -> SocketAddr { + "0.0.0.0:12088".parse().unwrap() +} + +const fn default_max_maintenance_timeout() -> Duration { + Duration::from_secs(5) +} + +const fn default_min_order_validity_period() -> Duration { + Duration::from_mins(1) +} + +const fn default_max_auction_age() -> Duration { + Duration::from_mins(5) +} + +// Does not implement Default because `native_price_estimation` *cannot* have +// empty `estimators`, as such, we cannot provide a proper default value for +// this structure. +/// Top-level autopilot service configuration. +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Configuration { + /// Shared settings (node URL, gas estimators, logging, etc.). + #[serde(flatten)] + pub shared: SharedConfig, + + /// Solver drivers to dispatch auctions to. + pub drivers: Vec, + + /// Describes how the protocol fees should be calculated. + pub fee_policies: FeePoliciesConfig, + + /// Configuration for trusted tokens that the settlement contract is willing + /// to internalize. + #[serde(default)] + pub trusted_tokens: TrustedTokensConfig, + + /// Configuration for periodic cleanup of order events. + #[serde(default)] + pub order_events_cleanup: OrderEventsCleanupConfig, + + /// Configuration for order validation rules. + #[serde(default)] + pub banned_users: BannedUsersConfig, + + /// Configuration for uploading auction instances to S3. + /// If absent, S3 uploads are disabled. + pub s3: Option, + + /// Configuration for native token price estimation strategies. + pub native_price_estimation: NativePriceConfig, + + /// Database connection pool settings. + #[serde(default)] + pub database: DatabasePoolConfig, + + /// Configuration for eth-flow order indexing and processing. + #[serde(default)] + pub ethflow: EthflowConfig, + + /// Run the autopilot in shadow mode by specifying an upstream CoW protocol + /// deployment to pull auctions from. The autopilot performs solver + /// competition and logs the winner without executing settlements. + pub shadow: Option, + + /// Address to bind the metrics server. + #[serde(default = "default_metrics_address")] + pub metrics_address: SocketAddr, + + /// Address to bind the HTTP API server. + #[serde(default = "default_api_address")] + pub api_address: SocketAddr, + + /// Configuration for CoW AMM indexing and archive node access. + #[serde(default)] + pub cow_amm: CowAmmGroupConfig, + + /// Configuration for the autopilot's main auction run loop. + #[serde(default)] + pub run_loop: RunLoopConfig, + + /// Maximum timeout for fetching native prices in the run loop. + /// If 0, native prices are fetched from cache. + #[serde(with = "humantime_serde", default)] + pub native_price_timeout: Duration, + + /// Whether to skip filtering out orders with insufficient balances. + #[serde(default)] + pub disable_order_balance_filter: bool, + + /// Maximum time the autopilot may spend on maintenance logic between + /// two auctions. When exceeded, a not-fully-updated auction runs instead + /// of stalling. + #[serde(with = "humantime_serde", default = "default_max_maintenance_timeout")] + pub max_maintenance_timeout: Duration, + + /// List of token addresses to be ignored throughout service + #[serde(default)] + pub unsupported_tokens: Vec
, + + /// The minimum amount of time an order has to be valid for. + #[serde( + with = "humantime_serde", + default = "default_min_order_validity_period" + )] + pub min_order_validity_period: Duration, + + /// If the auction hasn't been updated in this amount of time the pod fails + /// the liveness check. Expects a value in seconds. + #[serde(with = "humantime_serde", default = "default_max_auction_age")] + pub max_auction_age: Duration, + + /// Configurations for the HTTP client (e.g. HTTP timeout). + #[serde(default)] + pub http_client: HttpClient, + + /// Configurations for the order creation process. + pub order_quoting: OrderQuoting, + + /// Configurations for price estimation (tenderly, rate limiting, CoinGecko, + /// 1inch, quote verification, balance overrides, etc.). + #[serde(default)] + pub price_estimation: PriceEstimation, +} + +impl Configuration { + pub async fn from_path>(path: P) -> anyhow::Result { + match toml::from_str(&tokio::fs::read_to_string(&path).await?) { + Ok(self_) => Ok(self_), + Err(err) if std::env::var("TOML_TRACE_ERROR").is_ok_and(|v| v == "1") => Err(anyhow!( + "failed to parse TOML config at {}: {err:#?}", + path.as_ref().display() + )), + Err(_) => Err(anyhow!( + "failed to parse TOML config at: {}. Set TOML_TRACE_ERROR=1 to print parsing \ + error but this may leak secrets.", + path.as_ref().display() + )), + } + } + + // Note for reviewers: if this and other validations are always applied, + // we should instead move them to the deserialization stage + // https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ + pub fn validate(self) -> anyhow::Result { + ensure!( + !self.drivers.is_empty(), + "colocation is enabled but no drivers are configured" + ); + self.shared.validate()?; + Ok(self) + } +} + +#[cfg(any(test, feature = "test-util"))] +impl Configuration { + /// This function *does not* return a valid configuration! + /// It is rather useful for tests where drivers are setup separately or not + /// actually used (like the `order_cancellation` test). + pub fn test_no_drivers() -> Self { + use crate::test_util::TestDefault; + + Self { + shared: Default::default(), + drivers: vec![], + fee_policies: Default::default(), + trusted_tokens: Default::default(), + order_events_cleanup: Default::default(), + banned_users: Default::default(), + s3: Default::default(), + native_price_estimation: NativePriceConfig::test_default(), + database: DatabasePoolConfig::test_default(), + ethflow: TestDefault::test_default(), + shadow: Default::default(), + metrics_address: default_metrics_address(), + api_address: default_api_address(), + cow_amm: Default::default(), + run_loop: TestDefault::test_default(), + disable_order_balance_filter: false, + max_maintenance_timeout: default_max_maintenance_timeout(), + native_price_timeout: Duration::from_millis(500), + unsupported_tokens: Default::default(), + min_order_validity_period: default_min_order_validity_period(), + max_auction_age: default_max_auction_age(), + http_client: Default::default(), + order_quoting: TestDefault::test_default(), + price_estimation: TestDefault::test_default(), + } + } + + pub fn test(name: &str, solver_address: alloy::primitives::Address) -> Self { + use crate::test_util::TestDefault; + + Self { + shared: Default::default(), + drivers: vec![Solver::test(name, solver_address)], + fee_policies: Default::default(), + trusted_tokens: Default::default(), + order_events_cleanup: Default::default(), + banned_users: Default::default(), + s3: Default::default(), + native_price_estimation: NativePriceConfig::test_default(), + database: DatabasePoolConfig::test_default(), + ethflow: TestDefault::test_default(), + shadow: Default::default(), + metrics_address: default_metrics_address(), + api_address: default_api_address(), + cow_amm: Default::default(), + run_loop: TestDefault::test_default(), + disable_order_balance_filter: false, + max_maintenance_timeout: default_max_maintenance_timeout(), + native_price_timeout: Duration::from_millis(500), + unsupported_tokens: Default::default(), + min_order_validity_period: default_min_order_validity_period(), + max_auction_age: default_max_auction_age(), + http_client: Default::default(), + order_quoting: TestDefault::test_default(), + price_estimation: TestDefault::test_default(), + } + } + + pub fn to_temp_path(&self) -> tempfile::NamedTempFile { + use std::io::Write; + + let mut file = tempfile::NamedTempFile::new().expect("temp file creation should not fail"); + file.write_all( + toml::to_string_pretty(self) + .expect("serialization should not fail") + .as_bytes(), + ) + .expect("writing to temp file should not fail"); + file + } + + pub fn to_cli_args(&self) -> (tempfile::NamedTempFile, String) { + // Must return the temp_file because it gets deleted on drop + // disabling the cleanup will lead to a bunch of artifacts laying around + let named_temp_file = self.to_temp_path(); + let cli_arg = format!("--config={}", named_temp_file.path().display()); + (named_temp_file, cli_arg) + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + autopilot::{ + fee_policy::{FeePolicy, FeePolicyKind, FeePolicyOrderClass, UpcomingFeePolicies}, + solver::Account, + }, + native_price_estimators::{ExternalSolver, NativePriceEstimator}, + }, + alloy::primitives::address, + std::time::Duration, + }; + + #[test] + fn deserialize_full_configuration() { + let toml = r#" + unsupported-tokens = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + min-order-validity-period = "2m" + max-auction-age = "10m" + native-price-timeout = "3s" + + [[drivers]] + name = "solver1" + url = "http://localhost:8080" + address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + + [[drivers]] + name = "solver2" + url = "http://localhost:8081" + kms = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" + + [fee-policies] + max-partner-fee = 0.005 + + [[fee-policies.policies]] + kind.surplus = { factor = 0.5, max-volume-factor = 0.9 } + order-class = "limit" + + [[fee-policies.policies]] + kind.volume = { factor = 0.1 } + order-class = "any" + + [fee-policies.upcoming-policies] + effective-from-timestamp = "2025-06-01T00:00:00Z" + + [[fee-policies.upcoming-policies.policies]] + kind.volume = { factor = 0.2 } + order-class = "any" + + [trusted-tokens] + url = "https://example.com/tokens.json" + tokens = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + update-interval = "30m" + + [order-events-cleanup] + cleanup-interval = "12h" + cleanup-threshold = "7d" + + [banned-users] + addresses = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + max-cache-size = 5000 + + [s3] + bucket = "my-bucket" + filename-prefix = "staging/mainnet/" + + [native-price-estimation] + estimators = [ + [{type = "CoinGecko"}, {type = "OneInchSpotPriceApi"}], + [{type = "Driver", name = "solver1", url = "http://localhost:8080"}], + [{type = "Forwarder", url = "http://localhost:12088"}], + ] + + [order-quoting] + price-estimation-drivers = [] + "#; + + let config: Configuration = toml::from_str(toml).unwrap(); + + assert_eq!(config.drivers.len(), 2); + assert_eq!(config.drivers[0].name, "solver1"); + assert_eq!( + config.drivers[0].submission_account, + Account::Address(address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")) + ); + assert_eq!(config.drivers[1].name, "solver2"); + + assert_eq!(config.fee_policies.max_partner_fee.get(), 0.005); + assert_eq!(config.fee_policies.policies.len(), 2); + assert!(matches!( + config.fee_policies.policies[0].kind, + FeePolicyKind::Surplus { .. } + )); + assert!(matches!( + config.fee_policies.policies[0].order_class, + FeePolicyOrderClass::Limit + )); + assert!(matches!( + config.fee_policies.policies[1].kind, + FeePolicyKind::Volume { .. } + )); + assert!(matches!( + config.fee_policies.policies[1].order_class, + FeePolicyOrderClass::Any + )); + + assert_eq!(config.fee_policies.upcoming_policies.policies.len(), 1); + assert!( + config + .fee_policies + .upcoming_policies + .effective_from_timestamp + .is_some() + ); + + assert!(config.trusted_tokens.url.is_some()); + assert_eq!(config.trusted_tokens.tokens.len(), 1); + assert_eq!( + config.trusted_tokens.update_interval, + Duration::from_secs(1800) + ); + + assert_eq!( + config.order_events_cleanup.cleanup_interval, + Duration::from_secs(43200) + ); + assert_eq!( + config.order_events_cleanup.cleanup_threshold, + Duration::from_secs(604800) + ); + + assert_eq!(config.banned_users.addresses.len(), 1); + assert_eq!(config.banned_users.max_cache_size.get(), 5000); + + let s3 = config.s3.unwrap(); + assert_eq!(s3.bucket, "my-bucket"); + assert_eq!(s3.filename_prefix, "staging/mainnet/"); + + assert_eq!( + config.native_price_estimation.estimators.as_slice(), + vec![ + vec![ + NativePriceEstimator::CoinGecko, + NativePriceEstimator::OneInchSpotPriceApi, + ], + vec![NativePriceEstimator::Driver(ExternalSolver { + name: "solver1".to_string(), + url: "http://localhost:8080".parse().unwrap(), + })], + vec![NativePriceEstimator::Forwarder { + url: "http://localhost:12088".parse().unwrap(), + }], + ] + ); + + assert_eq!(config.unsupported_tokens.len(), 1); + assert_eq!( + config.unsupported_tokens[0], + address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + ); + assert_eq!(config.min_order_validity_period, Duration::from_secs(120)); + assert_eq!(config.max_auction_age, Duration::from_secs(600)); + assert_eq!(config.native_price_timeout, Duration::from_secs(3)); + } + + #[test] + fn deserialize_configuration_defaults() { + let toml = r#" + [[drivers]] + name = "solver1" + url = "http://localhost:8080" + address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + + [fee-policies] + + [native-price-estimation] + estimators = [[{type = "CoinGecko"}]] + + [order-quoting] + price-estimation-drivers = [] + "#; + + let config: Configuration = toml::from_str(toml).unwrap(); + + assert_eq!(config.drivers.len(), 1); + assert_eq!( + config.native_price_estimation.estimators.as_slice().len(), + 1 + ); + assert!(config.fee_policies.policies.is_empty()); + assert_eq!(config.fee_policies.max_partner_fee.get(), 0.01); + assert!(config.fee_policies.upcoming_policies.policies.is_empty()); + assert!( + config + .fee_policies + .upcoming_policies + .effective_from_timestamp + .is_none() + ); + + assert!(config.trusted_tokens.url.is_none()); + assert!(config.trusted_tokens.tokens.is_empty()); + assert_eq!( + config.trusted_tokens.update_interval, + Duration::from_secs(3600) + ); + + assert_eq!( + config.order_events_cleanup.cleanup_interval, + Duration::from_secs(86400) + ); + assert_eq!( + config.order_events_cleanup.cleanup_threshold, + Duration::from_secs(2592000) + ); + + assert!(config.banned_users.addresses.is_empty()); + assert_eq!(config.banned_users.max_cache_size.get(), 10000); + + assert!(config.s3.is_none()); + + assert!(config.unsupported_tokens.is_empty()); + assert_eq!(config.min_order_validity_period, Duration::from_secs(60)); + assert_eq!(config.max_auction_age, Duration::from_secs(300)); + assert_eq!(config.native_price_timeout, Duration::ZERO); + } + + #[test] + fn roundtrip_serialization() { + let config = Configuration { + drivers: vec![Solver::test( + "solver1", + address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + )], + fee_policies: FeePoliciesConfig { + policies: vec![FeePolicy { + kind: FeePolicyKind::Surplus { + factor: 0.5.try_into().unwrap(), + max_volume_factor: 0.9.try_into().unwrap(), + }, + order_class: FeePolicyOrderClass::Limit, + }], + max_partner_fee: 0.02.try_into().unwrap(), + upcoming_policies: UpcomingFeePolicies::default(), + }, + ..Configuration::test_no_drivers() + }; + + let serialized = toml::to_string_pretty(&config).unwrap(); + let deserialized: Configuration = toml::from_str(&serialized).unwrap(); + + assert_eq!(deserialized.drivers.len(), 1); + assert_eq!(deserialized.fee_policies.policies.len(), 1); + assert_eq!(deserialized.fee_policies.max_partner_fee.get(), 0.02); + } +} diff --git a/crates/configs/src/autopilot/native_price.rs b/crates/configs/src/autopilot/native_price.rs new file mode 100644 index 0000000000..7ebf0f77bc --- /dev/null +++ b/crates/configs/src/autopilot/native_price.rs @@ -0,0 +1,115 @@ +use { + crate::native_price_estimators::NativePriceEstimators, + serde::Deserialize, + std::time::Duration, +}; + +const fn default_native_price_cache_refresh() -> Duration { + Duration::from_secs(1) +} + +const fn default_native_price_prefetch_time() -> Duration { + Duration::from_secs(80) +} + +// Does not implement Default because `estimators` *cannot* be empty, +// as such, we cannot provide a proper default value for this structure. +/// Native price estimation configuration. +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub struct NativePriceConfig { + /// Which estimators to use to estimate token prices in terms of the chain's + /// native token. Estimators with the same name need to also be specified as + /// built-in, legacy or external price estimators (lookup happens in this + /// order in case of name collisions) + pub estimators: NativePriceEstimators, + + /// Estimators for the API endpoint. Falls back to + /// `--native-price-estimators` if unset. + pub api_estimators: Option, + + /// How often the native price estimator should check for prices that need + /// to be udpated. + #[serde( + with = "humantime_serde", + default = "default_native_price_cache_refresh" + )] + pub cache_refresh_interval: Duration, + + /// How long before expiry the native price cache should try to update the + /// price in the background. This value has to be smaller than + /// `--native-price-cache-max-age`. + #[serde( + with = "humantime_serde", + default = "default_native_price_prefetch_time" + )] + pub prefetch_time: Duration, + + /// Enable EIP-4626 vault token pricing. When enabled, the native price + /// estimator will attempt to price vault tokens by querying their + /// underlying asset and conversion rate on-chain. + #[serde(default)] + pub eip4626: bool, + + /// Shared native price settings (cache, approximation tokens, etc.). + #[serde(flatten)] + pub shared: crate::native_price::NativePriceConfig, +} + +#[cfg(any(test, feature = "test-util"))] +impl NativePriceConfig { + /// Test configuration for [`NativePriceConfig`], must always be able to do + /// a serialization/deserialization roundtrip, as otherwise it may not + /// be loadable in end-to-end tests. + pub fn test_default() -> Self { + Self { + estimators: NativePriceEstimators::test_default(), + api_estimators: Default::default(), + cache_refresh_interval: default_native_price_cache_refresh(), + prefetch_time: Duration::from_millis(500), + eip4626: false, + shared: crate::native_price::NativePriceConfig { + cache: crate::native_price::CacheConfig { + max_age: Duration::from_secs(2), + ..Default::default() + }, + ..Default::default() + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_full() { + let toml = r#" + estimators = [[{type = "CoinGecko"}]] + api-estimators = [[{type = "OneInchSpotPriceApi"}]] + cache-refresh-interval = "30s" + prefetch-time = "2m" + "#; + let config: NativePriceConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.estimators.as_slice().len(), 1); + assert!(config.api_estimators.is_some()); + assert_eq!(config.cache_refresh_interval, Duration::from_secs(30)); + assert_eq!(config.prefetch_time, Duration::from_secs(120)); + } + + #[test] + fn missing_estimators_fails() { + let toml = ""; + assert!(toml::from_str::(toml).is_err()); + } + + // This test keeps the sanity of `test_default` upon which other tests rely! + #[test] + fn test_default_roundtrip() { + let config = NativePriceConfig::test_default(); + let serialized = toml::to_string(&config).unwrap(); + let _: NativePriceConfig = toml::from_str(&serialized).unwrap(); + } +} diff --git a/crates/configs/src/autopilot/order_events_cleanup.rs b/crates/configs/src/autopilot/order_events_cleanup.rs new file mode 100644 index 0000000000..2c9d656617 --- /dev/null +++ b/crates/configs/src/autopilot/order_events_cleanup.rs @@ -0,0 +1,60 @@ +use { + serde::{Deserialize, Serialize}, + std::time::Duration, +}; + +fn default_cleanup_interval() -> Duration { + Duration::from_secs(86400) // 1d +} + +fn default_cleanup_threshold() -> Duration { + Duration::from_secs(2592000) // 30d +} + +/// Periodic cleanup settings for the `order_events` database table. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct OrderEventsCleanupConfig { + /// Time interval between each cleanup operation of the `order_events` + /// database table. + #[serde(with = "humantime_serde", default = "default_cleanup_interval")] + pub cleanup_interval: Duration, + + /// Age threshold for order events to be eligible for cleanup in the + /// `order_events` database table. + #[serde(with = "humantime_serde", default = "default_cleanup_threshold")] + pub cleanup_threshold: Duration, +} + +impl Default for OrderEventsCleanupConfig { + fn default() -> Self { + Self { + cleanup_interval: default_cleanup_interval(), + cleanup_threshold: default_cleanup_threshold(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_defaults() { + let toml = ""; + let config: OrderEventsCleanupConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.cleanup_interval, Duration::from_secs(86400)); + assert_eq!(config.cleanup_threshold, Duration::from_secs(2592000)); + } + + #[test] + fn deserialize_full() { + let toml = r#" + cleanup-interval = "12h" + cleanup-threshold = "7d" + "#; + let config: OrderEventsCleanupConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.cleanup_interval, Duration::from_secs(43200)); + assert_eq!(config.cleanup_threshold, Duration::from_secs(604800)); + } +} diff --git a/crates/configs/src/autopilot/run_loop.rs b/crates/configs/src/autopilot/run_loop.rs new file mode 100644 index 0000000000..43ef61df84 --- /dev/null +++ b/crates/configs/src/autopilot/run_loop.rs @@ -0,0 +1,165 @@ +use { + serde::Deserialize, + std::{num::NonZeroUsize, time::Duration}, +}; + +const fn default_max_delay() -> Duration { + Duration::from_secs(2) +} + +const fn default_max_winners_per_auction() -> NonZeroUsize { + NonZeroUsize::new(20).unwrap() +} + +const fn default_max_solutions_per_solver() -> NonZeroUsize { + NonZeroUsize::new(3).unwrap() +} + +const fn default_submission_deadline() -> u64 { + 5 +} + +const fn default_max_settlement_transaction_wait() -> Duration { + Duration::from_mins(1) +} + +const fn default_min_solve_time() -> Duration { + Duration::from_secs(10) +} + +/// Configuration for the autopilot run loop timing. +#[derive(Debug, Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct RunLoopConfig { + /// If a new run loop iteration would start more than this duration after + /// the latest block was noticed, wait for the next block before continuing. + #[serde(with = "humantime_serde", default = "default_max_delay")] + pub max_delay: Duration, + + /// Maximum number of winners per auction. Each winner settles their + /// winning orders concurrently. + #[serde(default = "default_max_winners_per_auction")] + pub max_winners_per_auction: NonZeroUsize, + + /// Maximum number of solutions a single solver may propose per auction. + #[serde(default = "default_max_solutions_per_solver")] + pub max_solutions_per_solver: NonZeroUsize, + + /// Enable leader lock in the database; the follower instance will not + /// cut auctions. + #[serde(default)] + pub enable_leader_lock: bool, + + /// Enable brotli compression of `/solve` request bodies sent to drivers. + #[serde(default)] + pub compress_solve_request: bool, + + /// The maximum number of blocks to wait for a settlement to appear on + /// chain. + #[serde(default = "default_submission_deadline")] + pub submission_deadline: u64, + + /// The amount of time that the autopilot waits looking for a settlement + /// transaction onchain after the driver acknowledges the receipt of a + /// settlement. + #[serde( + with = "humantime_serde", + default = "default_max_settlement_transaction_wait" + )] + pub max_settlement_transaction_wait: Duration, + + /// Lower bound of time solvers have to compute solutions per auction. + #[serde( + with = "humantime_serde", + rename = "solve-deadline", + default = "default_min_solve_time" + )] + pub min_solve_time: Duration, + + /// If this is configured the `/solve` deadline will be picked + /// to end shortly before a new block gets mined. + /// This should not be configured on chains with variable block + /// production rates (including test chains). + #[serde(default)] + pub sync_solve_deadline_to_blockchain: Option, +} + +#[derive(Debug, Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct SlotConfig { + /// How long each slot on a PoS chain is. + #[serde(with = "humantime_serde")] + pub slot_length: Duration, + + /// Minimum amount of time one has to submit a tx BEFORE the slot's end + /// to still have it included in the next block. + #[serde(with = "humantime_serde")] + pub tx_propagation_latency: Duration, +} + +impl Default for RunLoopConfig { + fn default() -> Self { + Self { + max_delay: default_max_delay(), + max_winners_per_auction: default_max_winners_per_auction(), + max_solutions_per_solver: default_max_solutions_per_solver(), + enable_leader_lock: false, + compress_solve_request: false, + submission_deadline: default_submission_deadline(), + max_settlement_transaction_wait: default_max_settlement_transaction_wait(), + min_solve_time: default_min_solve_time(), + sync_solve_deadline_to_blockchain: None, + } + } +} + +#[cfg(any(test, feature = "test-util"))] +impl crate::test_util::TestDefault for RunLoopConfig { + fn test_default() -> Self { + Self { + max_delay: Duration::from_millis(100), + ..Default::default() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_defaults() { + let config: RunLoopConfig = toml::from_str("").unwrap(); + assert_eq!(config.max_delay, Duration::from_secs(2)); + } + + #[test] + fn deserialize_full() { + let toml = r#" + max-delay = "5s" + [sync-solve-deadline-to-blockchain] + slot-length = "12s" + tx-propagation-latency = "2s" + "#; + let config: RunLoopConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.max_delay, Duration::from_secs(5)); + assert_eq!( + config + .sync_solve_deadline_to_blockchain + .as_ref() + .unwrap() + .slot_length, + Duration::from_secs(12) + ); + assert_eq!( + config + .sync_solve_deadline_to_blockchain + .as_ref() + .unwrap() + .tx_propagation_latency, + Duration::from_secs(2) + ); + } +} diff --git a/crates/configs/src/autopilot/s3.rs b/crates/configs/src/autopilot/s3.rs new file mode 100644 index 0000000000..c8a024f5b2 --- /dev/null +++ b/crates/configs/src/autopilot/s3.rs @@ -0,0 +1,57 @@ +use serde::{Deserialize, Serialize}; + +/// Settings for uploading auction instances to S3. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct S3Config { + /// The S3 bucket where auction instances should be uploaded. + pub bucket: String, + + /// Prepended to the auction id to form the final instance filename on S3. + /// Something like "staging/mainnet/" + pub filename_prefix: String, +} + +impl From for s3::Config { + fn from(config: S3Config) -> Self { + Self { + bucket: config.bucket, + filename_prefix: config.filename_prefix, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_full() { + let toml = r#" + bucket = "my-bucket" + filename-prefix = "staging/mainnet/" + "#; + let config: S3Config = toml::from_str(toml).unwrap(); + assert_eq!(config.bucket, "my-bucket"); + assert_eq!(config.filename_prefix, "staging/mainnet/"); + } + + #[test] + fn missing_field_fails() { + let toml = r#" + bucket = "my-bucket" + "#; + assert!(toml::from_str::(toml).is_err()); + } + + #[test] + fn into_s3_config() { + let config = S3Config { + bucket: "my-bucket".to_string(), + filename_prefix: "prefix/".to_string(), + }; + let s3_config: s3::Config = config.into(); + assert_eq!(s3_config.bucket, "my-bucket"); + assert_eq!(s3_config.filename_prefix, "prefix/"); + } +} diff --git a/crates/configs/src/autopilot/solver.rs b/crates/configs/src/autopilot/solver.rs new file mode 100644 index 0000000000..bec879e29c --- /dev/null +++ b/crates/configs/src/autopilot/solver.rs @@ -0,0 +1,198 @@ +use { + alloy::primitives::Address, + core::fmt, + serde::{Deserialize, Deserializer, Serialize}, + std::fmt::{Display, Formatter}, + url::Url, +}; + +/// External solver driver configuration +#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct Solver { + /// Human-readable solver name (used in logs and metrics). + pub name: String, + /// Base URL of the solver's driver API. + pub url: Url, + /// Account used to submit settlement transactions on-chain. + #[serde(flatten)] + pub submission_account: Account, +} + +impl Solver { + pub fn new(name: String, url: Url, account: Account) -> Self { + Self { + name, + url, + submission_account: account, + } + } +} + +impl Display for Solver { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}({})", self.name, self.url) + } +} + +/// How the solver's on-chain submission key is specified. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum Account { + /// AWS KMS is used to retrieve the solver public key. + #[serde(deserialize_with = "deserialize_arn")] + Kms(Arn), + /// Solver public key specified directly. + Address(Address), +} + +/// Wrapper type for AWS KMS ARN identifiers. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] +pub struct Arn(pub String); + +fn deserialize_arn<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let raw_arn = String::deserialize(deserializer)?; + if raw_arn.starts_with("arn:aws:kms:") { + Ok(Arn(raw_arn)) + } else { + Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Str(raw_arn.as_str()), + &"expected value starting with \"arn:aws:kms\"", + )) + } +} + +#[cfg(any(test, feature = "test-util"))] +impl Solver { + pub fn test(name: &str, address: Address) -> Self { + Self { + name: name.to_string(), + url: format!("http://localhost:11088/{name}").parse().unwrap(), + submission_account: Account::Address(address), + } + } +} + +#[cfg(test)] +mod test { + use {super::*, alloy::primitives::address}; + + #[test] + fn parse_driver_submission_account_address() { + let toml = r#" + name = "name1" + url = "http://localhost:8080" + address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + "#; + let driver = toml::from_str::(toml).unwrap(); + + let expected = Solver::new( + "name1".into(), + Url::parse("http://localhost:8080").unwrap(), + Account::Address(address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")), + ); + assert_eq!(driver, expected); + } + + #[test] + fn parse_driver_submission_account_arn() { + let toml = r#" + name = "name1" + url = "http://localhost:8080" + kms = "arn:aws:kms:supersecretstuff" + "#; + let driver = toml::from_str::(toml).unwrap(); + + let expected = Solver::new( + "name1".into(), + Url::parse("http://localhost:8080").unwrap(), + Account::Kms(Arn("arn:aws:kms:supersecretstuff".into())), + ); + assert_eq!(driver, expected); + } + + #[test] + fn deserialize_valid_arn() { + let toml = r#"kms = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012""#; + let account = toml::from_str::(toml).unwrap(); + + let expected = Account::Kms(Arn("arn:aws:kms:us-east-1:123456789012:key/\ + 12345678-1234-1234-1234-123456789012" + .into())); + assert_eq!(account, expected); + } + + #[test] + fn deserialize_invalid_arn_wrong_prefix() { + let toml = r#"kms = "arn:aws:s3:us-east-1:123456789012:bucket/mybucket""#; + let result = toml::from_str::(toml); + + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!( + err.to_string() + .contains("expected value starting with \"arn:aws:kms\""), + "Error message: {}", + err + ); + } + + #[test] + fn deserialize_invalid_arn_not_arn() { + let toml = r#"kms = "not-an-arn""#; + let result = toml::from_str::(toml); + + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!( + err.to_string() + .contains("expected value starting with \"arn:aws:kms\""), + "Error message: {}", + err + ); + } + + #[test] + fn parse_multiple_solvers() { + let toml = r#" + [[drivers]] + name = "solver1" + url = "http://localhost:8080" + address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + + [[drivers]] + name = "solver2" + url = "http://localhost:8081" + kms = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" + "#; + + #[derive(Deserialize)] + struct Config { + drivers: Vec, + } + + let config = toml::from_str::(toml).unwrap(); + + assert_eq!(config.drivers.len(), 2); + + let expected_solver1 = Solver::new( + "solver1".into(), + Url::parse("http://localhost:8080").unwrap(), + Account::Address(address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")), + ); + + let expected_solver2 = Solver::new( + "solver2".into(), + Url::parse("http://localhost:8081").unwrap(), + Account::Kms(Arn("arn:aws:kms:us-east-1:123456789012:key/\ + 12345678-1234-1234-1234-123456789012" + .into())), + ); + + assert_eq!(config.drivers[0], expected_solver1); + assert_eq!(config.drivers[1], expected_solver2); + } +} diff --git a/crates/configs/src/autopilot/trusted_tokens.rs b/crates/configs/src/autopilot/trusted_tokens.rs new file mode 100644 index 0000000000..8d7907f84e --- /dev/null +++ b/crates/configs/src/autopilot/trusted_tokens.rs @@ -0,0 +1,64 @@ +use { + alloy::primitives::Address, + serde::{Deserialize, Serialize}, + std::time::Duration, + url::Url, +}; + +fn default_update_interval() -> Duration { + Duration::from_secs(3600) // 1h +} + +/// Tokens that the settlement contract is allowed to internalize. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct TrustedTokensConfig { + /// The URL of a list of tokens our settlement contract is willing to + /// internalize. + pub url: Option, + + /// Hardcoded list of trusted tokens to use in addition to `url`. + #[serde(default)] + pub tokens: Vec
, + + /// Time interval after which the trusted tokens list needs to be updated. + #[serde(with = "humantime_serde", default = "default_update_interval")] + pub update_interval: Duration, +} + +impl Default for TrustedTokensConfig { + fn default() -> Self { + Self { + url: None, + tokens: Vec::new(), + update_interval: default_update_interval(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_defaults() { + let toml = ""; + let config: TrustedTokensConfig = toml::from_str(toml).unwrap(); + assert!(config.url.is_none()); + assert!(config.tokens.is_empty()); + assert_eq!(config.update_interval, Duration::from_secs(3600)); + } + + #[test] + fn deserialize_full() { + let toml = r#" + url = "https://example.com/tokens.json" + tokens = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + update-interval = "30m" + "#; + let config: TrustedTokensConfig = toml::from_str(toml).unwrap(); + assert!(config.url.is_some()); + assert_eq!(config.tokens.len(), 1); + assert_eq!(config.update_interval, Duration::from_secs(1800)); + } +} diff --git a/crates/configs/src/banned_users.rs b/crates/configs/src/banned_users.rs new file mode 100644 index 0000000000..2c1b8e708f --- /dev/null +++ b/crates/configs/src/banned_users.rs @@ -0,0 +1,155 @@ +use { + crate::deserialize_env::{deserialize_optional_string_from_env, deserialize_string_from_env}, + alloy::primitives::Address, + serde::Deserialize, + std::{fmt::Debug, num::NonZeroUsize}, + url::Url, +}; + +fn default_max_cache_size() -> NonZeroUsize { + // Note that this default value does not apply to both the orderbook and + // autopilot! Remember to explicitly change it in the infra repo. + NonZeroUsize::new(10000).unwrap() +} + +/// Addresses banned from creating orders, with a local cache. +#[derive(Debug, Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct BannedUsersConfig { + /// List of account addresses to be denied from order creation. + #[serde(default)] + pub addresses: Vec
, + + /// Maximum number of entries to keep in the banned users cache. + #[serde(default = "default_max_cache_size")] + pub max_cache_size: NonZeroUsize, + + /// Optional Hermod (zeroShadow) sanctioned address checker. + #[serde(default)] + pub hermod: Option, +} + +impl Default for BannedUsersConfig { + fn default() -> Self { + Self { + addresses: Vec::new(), + max_cache_size: default_max_cache_size(), + hermod: None, + } + } +} + +/// Hermod is zeroShadow's self-hosted sanctioned-address checker. Queries +/// are made against an HMAC-SHA256 obfuscated form of the address using a +/// per-customer key. +#[derive(Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct HermodConfig { + /// Base URL of the Hermod agent (e.g. `http://hermod:3000`). + pub url: Url, + + /// Per-customer HMAC key used to obfuscate addresses before sending. + #[serde(deserialize_with = "deserialize_string_from_env")] + pub hmac_key: String, + + /// Optional API key sent as a Bearer token, if the agent was started + /// with `API_KEY` set. + #[serde(default, deserialize_with = "deserialize_optional_string_from_env")] + pub api_key: Option, +} + +impl Debug for HermodConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("HermodConfig") + .field("url", &self.url) + .field("hmac_key", &"") + .field("api_key", &self.api_key.as_ref().map(|_| "")) + .finish() + } +} + +#[cfg(test)] +mod tests { + use {super::*, alloy::primitives::address}; + + #[test] + fn deserialize_defaults() { + let toml = ""; + let config: BannedUsersConfig = toml::from_str(toml).unwrap(); + assert!(config.addresses.is_empty()); + assert_eq!(config.max_cache_size.get(), 10000); + assert!(config.hermod.is_none()); + } + + #[test] + fn deserialize_full() { + let toml = r#" + addresses = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + max-cache-size = 5000 + "#; + let config: BannedUsersConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.addresses.len(), 1); + assert_eq!( + config.addresses[0], + address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + ); + assert_eq!(config.max_cache_size.get(), 5000); + } + + #[test] + fn deserialize_with_hermod() { + let toml = r#" + [hermod] + url = "http://hermod:3000" + hmac-key = "key" + api-key = "secret" + "#; + let config: BannedUsersConfig = toml::from_str(toml).unwrap(); + let hermod = config.hermod.unwrap(); + assert_eq!(hermod.url.as_str(), "http://hermod:3000/"); + assert_eq!(hermod.hmac_key, "key"); + assert_eq!(hermod.api_key.as_deref(), Some("secret")); + } + + #[test] + fn hermod_secrets_redacted() { + let config = HermodConfig { + url: "http://hermod:3000".parse().unwrap(), + hmac_key: "hmac-secret-value".to_string(), + api_key: Some("api-secret-value".to_string()), + }; + let debug = format!("{:?}", config); + assert!(debug.contains(r#"hmac_key: """#)); + assert!(debug.contains(r#"api_key: Some("")"#)); + assert!(!debug.contains("hmac-secret-value")); + assert!(!debug.contains("api-secret-value")); + } + + #[test] + fn hermod_secrets_from_env() { + let hmac_var = "TEST_HERMOD_HMAC_KEY"; + let api_var = "TEST_HERMOD_API_KEY"; + // SAFETY: no other threads access these env vars. + unsafe { std::env::set_var(hmac_var, "env-hmac") }; + unsafe { std::env::set_var(api_var, "env-api") }; + + let toml = format!( + r#" + [hermod] + url = "http://hermod:3000" + hmac-key = "%{hmac_var}" + api-key = "%{api_var}" + "#, + ); + let config: BannedUsersConfig = toml::from_str(&toml).unwrap(); + let hermod = config.hermod.unwrap(); + assert_eq!(hermod.hmac_key, "env-hmac"); + assert_eq!(hermod.api_key.as_deref(), Some("env-api")); + + // SAFETY: no other threads access these env vars. + unsafe { std::env::remove_var(hmac_var) }; + unsafe { std::env::remove_var(api_var) }; + } +} diff --git a/crates/configs/src/database.rs b/crates/configs/src/database.rs new file mode 100644 index 0000000000..0c9190e04a --- /dev/null +++ b/crates/configs/src/database.rs @@ -0,0 +1,114 @@ +use { + std::{ + fmt::Debug, + num::{NonZeroU32, NonZeroUsize}, + str::FromStr, + time::Duration, + }, + url::Url, +}; + +const fn default_db_max_connections() -> NonZeroU32 { + // Matches SQLx default connection pool size. + NonZeroU32::new(10).expect("value should be greater than 0") +} + +fn default_db_write_url() -> Url { + Url::from_str("postgresql://").expect("url should be valid") +} + +const fn default_statement_timeout() -> Duration { + Duration::from_secs(30) +} + +const fn default_insert_batch_size() -> NonZeroUsize { + NonZeroUsize::new(500).expect("value should be greater than 0") +} + +/// PostgreSQL connection pool settings. +#[derive(serde::Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct DatabasePoolConfig { + /// Url of the Postgres database. By default connects to `postgresql://`. + /// Supports reading from an environment variable by prefixing the + /// environment variable name with '%', for example — `%DB_WRITE_URL` — + /// will read the environment variable named `DB_WRITE_URL`. + #[serde( + default = "default_db_write_url", + deserialize_with = "crate::deserialize_env::deserialize_url_from_env" + )] + pub write_url: Url, + + /// Url of the Postgres database replica. If not provided, the URL from + /// `write_url` will be used. Supports reading from an environment + /// variable by prefixing the environment variable name with '%', + /// for example — `%DB_READ_URL` — will read the environment variable named + /// `DB_READ_URL`. + #[serde( + default, + deserialize_with = "crate::deserialize_env::deserialize_optional_url_from_env" + )] + pub read_url: Option, + + /// Maximum number of connections in the database connection pool. + #[serde(default = "default_db_max_connections")] + pub max_connections: NonZeroU32, + + /// The number of order events to insert in a single batch. + #[serde(default = "default_insert_batch_size")] + pub insert_batch_size: NonZeroUsize, + + /// Timeout for database read queries. Defaults to 30 seconds. + #[serde(default = "default_statement_timeout", with = "humantime_serde")] + pub statement_timeout: Duration, +} + +impl Default for DatabasePoolConfig { + fn default() -> Self { + Self { + write_url: default_db_write_url(), + read_url: Default::default(), + max_connections: default_db_max_connections(), + insert_batch_size: default_insert_batch_size(), + statement_timeout: default_statement_timeout(), + } + } +} + +impl Debug for DatabasePoolConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DatabasePoolConfig") + .field("write_url", &"REDACTED") + .field("read_url", &"REDACTED") + .field("max_connections", &self.max_connections) + .field("insert_batch_size", &self.insert_batch_size) + .field("statement_timeout", &self.statement_timeout) + .finish() + } +} + +#[cfg(any(test, feature = "test-util"))] +pub mod test_util { + use { + crate::{database::DatabasePoolConfig, test_util::TestDefault}, + std::str::FromStr, + url::Url, + }; + + impl TestDefault for DatabasePoolConfig { + fn test_default() -> Self { + Self { + write_url: Url::from_str("postgresql://").unwrap(), + read_url: Some( + Url::from_str(&format!( + "postgresql://readonly@localhost/{db}", + db = std::env::var("USER").unwrap() + )) + .unwrap(), + ), + ..Self::default() + } + } + } +} diff --git a/crates/configs/src/deserialize_env.rs b/crates/configs/src/deserialize_env.rs new file mode 100644 index 0000000000..47c48c95ad --- /dev/null +++ b/crates/configs/src/deserialize_env.rs @@ -0,0 +1,202 @@ +//! Some variables are injected by 1Password directly into the Pod's +//! environment, completely bypassing Pulumi and making it unusable in the +//! configuration file. Since the token does not contain `%` this is a +//! workaround to allow the token to be read from the environment. +//! +//! Due to handling several kinds of types + +use { + serde::{Deserialize, Deserializer}, + std::str::FromStr, + url::{ParseError, Url}, +}; + +const ENV_VAR_PREFIX: char = '%'; + +/// Returns a deserialization error mentioning that the target environment +/// variable could not be found. +fn invalid_value_env_var_missing(var_name: &str) -> E { + serde::de::Error::invalid_value( + serde::de::Unexpected::Str(var_name), + &"expected environment variable to be available", + ) +} + +/// Returns a deserialization error mentioning that either the environment +/// variable contents or the field value is not a valid URL. +fn invalid_value_unable_to_parse_url(err: ParseError) -> E { + serde::de::Error::invalid_value( + serde::de::Unexpected::Other(err.to_string().as_str()), + &"expected environment variable contents or passed field value to be a valid URL", + ) +} + +/// Deserializes an URL from *either* an environment variable — with the format +/// `%` — or interpreting a String as a URL. +pub fn deserialize_url_from_env<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let env_var_name = String::deserialize(deserializer)?; + + let raw_url = match env_var_name.strip_prefix(ENV_VAR_PREFIX) { + Some(env_var_name) => std::env::var(env_var_name) + .inspect_err(|err| { + tracing::error!(%err, %env_var_name, "failed to load env var"); + }) + .map_err(|_| invalid_value_env_var_missing(env_var_name))?, + None => env_var_name, + }; + + Url::from_str(&raw_url).map_err(invalid_value_unable_to_parse_url) +} + +/// Deserializes a String from *either* an environment variable — +/// with the format `%` — or directly from the field value. +pub fn deserialize_string_from_env<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let value = String::deserialize(deserializer)?; + match value.strip_prefix(ENV_VAR_PREFIX) { + Some(env_var_name) => Ok(std::env::var(env_var_name) + .inspect_err(|err| { + tracing::error!(%err, %env_var_name, "failed to load env var"); + }) + .map_err(|_| invalid_value_env_var_missing(env_var_name))?), + None => Ok(value), + } +} + +/// Deserializes an optional String from *either* an environment variable — +/// with the format `%` — or directly from the field value. +/// Missing field or missing env var (when referenced) → `None`. +pub fn deserialize_optional_string_from_env<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let Some(value) = Option::::deserialize(deserializer)? else { + return Ok(None); + }; + match value.strip_prefix(ENV_VAR_PREFIX) { + Some(env_var_name) => Ok(std::env::var(env_var_name).ok()), + None => Ok(Some(value)), + } +} + +/// Deserializes an optional URL from *either* an environment variable — with +/// the format `%` — or interpreting a String as a URL. +pub fn deserialize_optional_url_from_env<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let Some(env_var_name) = Option::::deserialize(deserializer)? else { + return Ok(None); + }; + let raw_url = match env_var_name.strip_prefix(ENV_VAR_PREFIX) { + // In the case of optional variables, we assume a missing env var as empty + Some(env_var_name) => match std::env::var(env_var_name).ok() { + Some(raw_url) => raw_url, + None => return Ok(None), + }, + + None => env_var_name, + }; + + Ok(Some( + Url::from_str(raw_url.as_str()).map_err(invalid_value_unable_to_parse_url)?, + )) +} + +#[cfg(test)] +mod tests { + use {serde::Deserialize, url::Url}; + + #[derive(Deserialize)] + struct Required { + #[serde(deserialize_with = "super::deserialize_url_from_env")] + url: Url, + } + + #[derive(Deserialize)] + struct Optional { + #[serde(default, deserialize_with = "super::deserialize_optional_url_from_env")] + url: Option, + } + + #[test] + fn required_direct_url() { + let json = r#"{"url": "http://localhost:8080"}"#; + let parsed: Required = serde_json::from_str(json).unwrap(); + assert_eq!(parsed.url.as_str(), "http://localhost:8080/"); + } + + #[test] + fn required_from_env_var() { + let var = "TEST_DESER_REQ_FROM_ENV"; + // Safety: test-only, using unique env var names to avoid conflicts + unsafe { std::env::set_var(var, "http://example.com") }; + let json = format!(r#"{{"url": "%{var}"}}"#); + let parsed: Required = serde_json::from_str(&json).unwrap(); + assert_eq!(parsed.url.as_str(), "http://example.com/"); + unsafe { std::env::remove_var(var) }; + } + + #[test] + fn required_missing_env_var_is_error() { + let json = r#"{"url": "%NONEXISTENT_TEST_VAR_12345"}"#; + assert!(serde_json::from_str::(json).is_err()); + } + + #[test] + fn required_invalid_url_is_error() { + let json = r#"{"url": "not a url"}"#; + assert!(serde_json::from_str::(json).is_err()); + } + + #[test] + fn optional_none_when_absent() { + let json = r#"{}"#; + let parsed: Optional = serde_json::from_str(json).unwrap(); + assert!(parsed.url.is_none()); + } + + #[test] + fn optional_none_when_null() { + let json = r#"{"url": null}"#; + let parsed: Optional = serde_json::from_str(json).unwrap(); + assert!(parsed.url.is_none()); + } + + #[test] + fn optional_direct_url() { + let json = r#"{"url": "http://localhost:9090"}"#; + let parsed: Optional = serde_json::from_str(json).unwrap(); + assert_eq!(parsed.url.unwrap().as_str(), "http://localhost:9090/"); + } + + #[test] + fn optional_from_env_var() { + let var = "TEST_DESER_OPT_FROM_ENV"; + unsafe { std::env::set_var(var, "http://opt.example.com") }; + let json = format!(r#"{{"url": "%{var}"}}"#); + let parsed: Optional = serde_json::from_str(&json).unwrap(); + assert_eq!(parsed.url.unwrap().as_str(), "http://opt.example.com/"); + unsafe { std::env::remove_var(var) }; + } + + #[test] + fn optional_missing_env_var_returns_none() { + let json = r#"{"url": "%NONEXISTENT_OPT_TEST_VAR_12345"}"#; + let parsed: Optional = serde_json::from_str(json).unwrap(); + assert!(parsed.url.is_none()); + } + + #[test] + fn optional_invalid_url_is_error() { + let json = r#"{"url": "not a url"}"#; + assert!(serde_json::from_str::(json).is_err()); + } +} diff --git a/crates/configs/src/fee_factor.rs b/crates/configs/src/fee_factor.rs new file mode 100644 index 0000000000..ba26383d7c --- /dev/null +++ b/crates/configs/src/fee_factor.rs @@ -0,0 +1,146 @@ +use { + anyhow::{Context, ensure}, + serde::{Deserialize, Deserializer, Serialize, de::Unexpected}, + std::str::FromStr, +}; + +/// Fee factor representing a percentage in range [0, 1) +#[derive(Debug, Clone, Copy, PartialEq, Serialize)] +pub struct FeeFactor(f64); + +impl FeeFactor { + /// High precision scale factor (1 million) for sub-basis-point precision. + /// Allows representing factors like 0.00003 (0.3 BPS) without rounding to + /// 0. Also used for converting to BPS string with 2 decimal precision + /// (1_000_000 / 100 = 10_000 BPS scale). + pub const HIGH_PRECISION_SCALE: u64 = 1_000_000; + + pub const fn new(factor: f64) -> Self { + Self(factor) + } + + /// Converts the fee factor to basis points (BPS). + /// Supports fractional BPS values (e.g., 0.00003 -> "0.3") + /// Rounds to 2 decimal places to avoid floating point representation + /// issues. + pub fn to_bps_str(&self) -> String { + let bps = (self.0 * Self::HIGH_PRECISION_SCALE as f64).round() / 100.0; + format!("{bps}") + } + + /// Converts the fee factor to a high precision scaled integer. + /// For example, 0.00003 -> 30 (with scale of 1_000_000) + /// This allows sub-basis-point precision in calculations. + pub fn to_high_precision(&self) -> u64 { + (self.0 * Self::HIGH_PRECISION_SCALE as f64).round() as u64 + } + + /// Get the inner value + pub fn get(&self) -> f64 { + self.0 + } +} + +impl TryFrom for FeeFactor { + type Error = anyhow::Error; + + fn try_from(value: f64) -> Result { + ensure!( + (0.0..1.0).contains(&value), + "Factor must be in the range [0, 1)" + ); + Ok(FeeFactor(value)) + } +} + +impl FromStr for FeeFactor { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let value: f64 = s.parse().context("failed to parse fee factor as f64")?; + value.try_into() + } +} + +impl<'de> Deserialize<'de> for FeeFactor { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let raw_fee_factor = f64::deserialize(deserializer)?; + FeeFactor::try_from(raw_fee_factor).map_err(|_| { + serde::de::Error::invalid_value( + Unexpected::Float(raw_fee_factor), + &"expected fee factor to be in interval [0, 1)", + ) + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn fee_factor_to_bps() { + assert_eq!(FeeFactor::new(0.0001).to_bps_str(), "1"); + assert_eq!(FeeFactor::new(0.001).to_bps_str(), "10"); + + // Fractional BPS values (sub-basis-point precision) + assert_eq!(FeeFactor::new(0.00003).to_bps_str(), "0.3"); + assert_eq!(FeeFactor::new(0.00005).to_bps_str(), "0.5"); + assert_eq!(FeeFactor::new(0.000025).to_bps_str(), "0.25"); + assert_eq!(FeeFactor::new(0.000075).to_bps_str(), "0.75"); + assert_eq!(FeeFactor::new(0.00015).to_bps_str(), "1.5"); + + assert_eq!(FeeFactor::new(0.0).to_bps_str(), "0"); + } + + #[test] + fn fee_factor_to_high_precision() { + // Verify high precision scaling + assert_eq!(FeeFactor::new(0.00003).to_high_precision(), 30); + assert_eq!(FeeFactor::new(0.0001).to_high_precision(), 100); + assert_eq!(FeeFactor::new(0.001).to_high_precision(), 1000); + assert_eq!(FeeFactor::new(0.01).to_high_precision(), 10_000); + assert_eq!(FeeFactor::new(0.1).to_high_precision(), 100_000); + } + + #[test] + fn deserialize_valid_fee_factors() { + assert_eq!( + serde_json::from_str::("0.0").unwrap(), + FeeFactor::new(0.0) + ); + assert_eq!( + serde_json::from_str::("0.5").unwrap(), + FeeFactor::new(0.5) + ); + assert_eq!( + serde_json::from_str::("0.99").unwrap(), + FeeFactor::new(0.99) + ); + assert_eq!( + serde_json::from_str::("0.00003").unwrap(), + FeeFactor::new(0.00003) + ); + } + + #[test] + fn deserialize_invalid_fee_factors() { + for value in ["1.0", "1.5", "-0.1", "-1.0"] { + let err = serde_json::from_str::(value).unwrap_err(); + assert!( + err.to_string() + .contains("expected fee factor to be in interval [0, 1)"), + "unexpected error for {value}: {err}" + ); + } + } + + #[test] + fn deserialize_wrong_type() { + assert!(serde_json::from_str::("\"not a number\"").is_err()); + assert!(serde_json::from_str::("true").is_err()); + } +} diff --git a/crates/configs/src/gas_price_estimation.rs b/crates/configs/src/gas_price_estimation.rs new file mode 100644 index 0000000000..ed5f4dc931 --- /dev/null +++ b/crates/configs/src/gas_price_estimation.rs @@ -0,0 +1,15 @@ +#[derive(Debug, Clone, Copy)] +pub struct EstimatorConfig { + /// Number of blocks to look back for fee history + pub past_blocks: u64, + /// Percentile of rewards to use for priority fee estimation + pub reward_percentile: f64, +} + +pub fn default_past_blocks() -> u64 { + 10 +} + +pub fn default_reward_percentile() -> f64 { + 20.0 +} diff --git a/crates/configs/src/http_client.rs b/crates/configs/src/http_client.rs new file mode 100644 index 0000000000..d212b21120 --- /dev/null +++ b/crates/configs/src/http_client.rs @@ -0,0 +1,23 @@ +use {serde::Deserialize, std::time::Duration}; + +const fn default_timeout() -> Duration { + Duration::from_secs(10) +} + +/// Global HTTP client settings shared across all outgoing requests. +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub struct HttpClient { + /// Request timeout for outgoing HTTP calls. + #[serde(with = "humantime_serde", default = "default_timeout")] + pub timeout: Duration, +} + +impl Default for HttpClient { + fn default() -> Self { + Self { + timeout: default_timeout(), + } + } +} diff --git a/crates/configs/src/lib.rs b/crates/configs/src/lib.rs new file mode 100644 index 0000000000..97edddb2ab --- /dev/null +++ b/crates/configs/src/lib.rs @@ -0,0 +1,31 @@ +pub mod autopilot; +pub mod banned_users; +pub mod database; +pub mod deserialize_env; +pub mod fee_factor; +pub mod gas_price_estimation; +pub mod http_client; +pub mod native_price; +pub mod native_price_estimators; +pub mod order_quoting; +pub mod orderbook; +pub mod price_estimation; +pub mod rate_limit; +pub mod shared; +pub mod simulator; + +#[cfg(any(test, feature = "test-util"))] +pub mod test_util { + /// Provides standard test defaults while keeping separate from the regular + /// `Default` trait. + pub trait TestDefault { + /// Returns a test specific default. + /// + /// For example, when providing a default for a database connection for + /// tests, this can return a `localhost` connection. + fn test_default() -> Self; + } + + // No blanket implementation due to lack of specialization features: + // https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md +} diff --git a/crates/configs/src/native_price.rs b/crates/configs/src/native_price.rs new file mode 100644 index 0000000000..427cbefed6 --- /dev/null +++ b/crates/configs/src/native_price.rs @@ -0,0 +1,157 @@ +use { + alloy::primitives::Address, + serde::Deserialize, + std::{num::NonZeroUsize, time::Duration}, +}; + +const fn default_cache_max_age() -> Duration { + Duration::from_mins(10) +} + +const fn default_cache_concurrent_requests() -> NonZeroUsize { + NonZeroUsize::new(1).expect("value should be greater than 0") +} + +const fn default_results_required() -> NonZeroUsize { + NonZeroUsize::new(2).expect("value should not be zero") +} + +#[derive(Debug, Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct NativePriceConfig { + /// List of mappings of native price tokens substitutions with approximated: + /// - the first is a token address for which we get the native token price + /// - the second is a token address used for the price approximation + #[serde(default)] + pub approximation_tokens: Vec<(Address, Address)>, + + /// Configuration for the native price caching mechanism. + #[serde(default)] + pub cache: CacheConfig, + + /// How many successful price estimates for each order will cause a native + /// price estimation to return its result early. + /// + /// As this value increases, the fast estimator behavior will approximate + /// the behavior of the optimal estimator. + /// + /// It's possible to pass values greater than the total number of enabled + /// estimators but that will not have any further effect. + #[serde(default = "default_results_required")] + pub results_required: NonZeroUsize, +} + +impl Default for NativePriceConfig { + fn default() -> Self { + Self { + approximation_tokens: Default::default(), + cache: Default::default(), + results_required: default_results_required(), + } + } +} + +#[derive(Debug, Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct CacheConfig { + /// How long cached native prices stay valid. + #[serde(default = "default_cache_max_age", with = "humantime_serde")] + pub max_age: Duration, + + /// How many price estimation requests can be executed concurrently in the + /// maintenance task. + #[serde(default = "default_cache_concurrent_requests")] + pub concurrent_requests: NonZeroUsize, +} + +impl Default for CacheConfig { + fn default() -> Self { + Self { + max_age: default_cache_max_age(), + concurrent_requests: default_cache_concurrent_requests(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_full() { + let toml = r#" + approximation-tokens = [ + ["0x0000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000002"], + ] + + [cache] + max-age = "5m" + concurrent-requests = 4 + "#; + let config: NativePriceConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.approximation_tokens.len(), 1); + assert_eq!(config.cache.max_age, Duration::from_secs(300)); + assert_eq!( + config.cache.concurrent_requests, + NonZeroUsize::new(4).unwrap() + ); + } + + #[test] + fn cache_defaults() { + let toml = r#" + approximation-tokens = [] + [cache] + "#; + let config: NativePriceConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.cache.max_age, Duration::from_mins(10)); + assert_eq!( + config.cache.concurrent_requests, + NonZeroUsize::new(1).unwrap() + ); + } + + #[test] + fn multiple_approximation_tokens() { + let toml = r#" + approximation-tokens = [ + ["0x0000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000002"], + ["0x0000000000000000000000000000000000000003", "0x0000000000000000000000000000000000000004"], + ] + [cache] + "#; + let config: NativePriceConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.approximation_tokens.len(), 2); + assert_eq!( + config.approximation_tokens[0].0, + Address::from_slice(&[0; 19].into_iter().chain([1]).collect::>()), + ); + } + + #[test] + fn roundtrip_serialization() { + let config = NativePriceConfig { + approximation_tokens: vec![(Address::repeat_byte(1), Address::repeat_byte(2))], + cache: CacheConfig { + max_age: Duration::from_secs(120), + concurrent_requests: NonZeroUsize::new(8).unwrap(), + }, + results_required: default_results_required(), + }; + + let serialized = toml::to_string_pretty(&config).unwrap(); + let deserialized: NativePriceConfig = toml::from_str(&serialized).unwrap(); + + assert_eq!( + config.approximation_tokens, + deserialized.approximation_tokens, + ); + assert_eq!(config.cache.max_age, deserialized.cache.max_age); + assert_eq!( + config.cache.concurrent_requests, + deserialized.cache.concurrent_requests, + ); + } +} diff --git a/crates/configs/src/native_price_estimators.rs b/crates/configs/src/native_price_estimators.rs new file mode 100644 index 0000000000..52577ef818 --- /dev/null +++ b/crates/configs/src/native_price_estimators.rs @@ -0,0 +1,120 @@ +use { + serde::Deserialize, + std::fmt::{self, Display, Formatter}, + url::Url, +}; + +/// Ordered stages of native-price estimators. Each stage is tried in order; +/// within a stage estimators run concurrently. +#[derive(Clone, Debug, Default)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct NativePriceEstimators(Vec>); + +impl<'de> Deserialize<'de> for NativePriceEstimators { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + let estimators = >>::deserialize(deserializer)?; + if estimators.is_empty() { + return Err(serde::de::Error::invalid_length( + 0, + &"expected native price estimator stages to be configured", + )); + } + match estimators + .iter() + .enumerate() + .find_map(|(n, stage)| stage.is_empty().then_some(n)) + { + Some(n) => Err(serde::de::Error::invalid_length( + 0, + &format!("stage {} is empty, all stages must not be empty", n).as_str(), + )), + None => Ok(Self(estimators)), + } + } +} + +impl NativePriceEstimators { + pub fn new(estimators: Vec>) -> Self { + Self(estimators) + } + + pub fn as_slice(&self) -> &[Vec] { + &self.0 + } +} + +#[cfg(any(test, feature = "test-util"))] +impl NativePriceEstimators { + pub fn test_default() -> Self { + use std::str::FromStr; + NativePriceEstimators::new(vec![vec![NativePriceEstimator::driver( + "test_quoter".to_string(), + Url::from_str("http://localhost:11088/test_solver").unwrap(), + )]]) + } +} + +impl Display for NativePriceEstimators { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + for (i, stage) in self.as_slice().iter().enumerate() { + if i > 0 { + write!(f, ";")?; + } + for (j, estimator) in stage.iter().enumerate() { + if j > 0 { + write!(f, ",")?; + } + write!(f, "{estimator}")?; + } + } + Ok(()) + } +} + +/// Reference to an external solver by name and URL. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(deny_unknown_fields)] +pub struct ExternalSolver { + pub name: String, + pub url: Url, +} + +/// A single native-price estimation backend. +#[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(tag = "type")] +pub enum NativePriceEstimator { + /// Query an external solver driver for native prices. + Driver(ExternalSolver), + /// Forward requests to another service (e.g. autopilot). + Forwarder { url: Url }, + /// Use the 1inch spot-price API. + OneInchSpotPriceApi, + /// Use the CoinGecko API. + CoinGecko, +} + +impl NativePriceEstimator { + pub const fn driver(name: String, url: Url) -> Self { + Self::Driver(ExternalSolver { name, url }) + } + + pub const fn forwarder(url: Url) -> Self { + Self::Forwarder { url } + } +} + +impl Display for NativePriceEstimator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + NativePriceEstimator::Driver(s) => write!(f, "Driver|{}|{}", &s.name, s.url), + NativePriceEstimator::Forwarder { url } => write!(f, "Forwarder|{}", url), + NativePriceEstimator::OneInchSpotPriceApi => write!(f, "OneInchSpotPriceApi"), + NativePriceEstimator::CoinGecko => write!(f, "CoinGecko"), + } + } +} diff --git a/crates/configs/src/order_quoting.rs b/crates/configs/src/order_quoting.rs new file mode 100644 index 0000000000..8fafb7d1fc --- /dev/null +++ b/crates/configs/src/order_quoting.rs @@ -0,0 +1,196 @@ +use {serde::Deserialize, std::time::Duration, url::Url}; + +const fn default_eip1271_onchain_quote_validity() -> Duration { + Duration::from_mins(10) +} +const fn default_presign_onchain_quote_validity() -> Duration { + Duration::from_mins(10) +} +const fn default_standard_offchain_quote_validity() -> Duration { + Duration::from_mins(1) +} + +/// Reference to an external solver used for price estimation during quoting. +#[derive(Debug, Clone, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub struct ExternalSolver { + pub name: String, + pub url: Url, +} + +/// Configuration for the order quoting / creation process. +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub struct OrderQuoting { + /// A list of external drivers used for price estimation. + pub price_estimation_drivers: Vec, + + /// The time period an EIP1271-quote request is valid. + #[serde( + with = "humantime_serde", + default = "default_eip1271_onchain_quote_validity" + )] + pub eip1271_onchain_quote_validity: Duration, + + /// The time period an PRESIGN-quote request is valid. + #[serde( + with = "humantime_serde", + default = "default_presign_onchain_quote_validity" + )] + pub presign_onchain_quote_validity: Duration, + + /// The time period a regular offchain-quote request (ethsign/eip712) is + /// valid. + #[serde( + with = "humantime_serde", + default = "default_standard_offchain_quote_validity" + )] + pub standard_offchain_quote_validity: Duration, +} + +#[cfg(any(test, feature = "test-util"))] +impl ExternalSolver { + pub fn new(name: &str, url: &str) -> Self { + Self { + name: name.to_string(), + url: url.parse().unwrap(), + } + } +} + +#[cfg(any(test, feature = "test-util"))] +impl OrderQuoting { + pub fn test_with_drivers(drivers: Vec) -> Self { + Self { + price_estimation_drivers: drivers, + ..crate::test_util::TestDefault::test_default() + } + } +} + +#[cfg(any(test, feature = "test-util"))] +impl crate::test_util::TestDefault for OrderQuoting { + fn test_default() -> Self { + Self { + price_estimation_drivers: vec![], + eip1271_onchain_quote_validity: default_eip1271_onchain_quote_validity(), + presign_onchain_quote_validity: default_presign_onchain_quote_validity(), + standard_offchain_quote_validity: default_standard_offchain_quote_validity(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_defaults() { + let toml = r#" + price-estimation-drivers = [] + "#; + let config: OrderQuoting = toml::from_str(toml).unwrap(); + assert!(config.price_estimation_drivers.is_empty()); + assert_eq!( + config.eip1271_onchain_quote_validity, + Duration::from_mins(10) + ); + assert_eq!( + config.presign_onchain_quote_validity, + Duration::from_mins(10) + ); + assert_eq!( + config.standard_offchain_quote_validity, + Duration::from_mins(1) + ); + } + + #[test] + fn deserialize_full() { + let toml = r#" + eip1271-onchain-quote-validity = "5m" + presign-onchain-quote-validity = "20m" + standard-offchain-quote-validity = "30s" + + [[price-estimation-drivers]] + name = "test-solver" + url = "http://localhost:8080" + "#; + let config: OrderQuoting = toml::from_str(toml).unwrap(); + assert_eq!(config.price_estimation_drivers.len(), 1); + assert_eq!(config.price_estimation_drivers[0].name, "test-solver"); + assert_eq!( + config.price_estimation_drivers[0].url.as_str(), + "http://localhost:8080/" + ); + assert_eq!( + config.eip1271_onchain_quote_validity, + Duration::from_mins(5) + ); + assert_eq!( + config.presign_onchain_quote_validity, + Duration::from_mins(20) + ); + assert_eq!( + config.standard_offchain_quote_validity, + Duration::from_secs(30) + ); + } + + #[test] + fn deserialize_multiple_drivers() { + let toml = r#" + [[price-estimation-drivers]] + name = "solver-a" + url = "http://solver-a:8080" + + [[price-estimation-drivers]] + name = "solver-b" + url = "http://solver-b:9090" + "#; + let config: OrderQuoting = toml::from_str(toml).unwrap(); + assert_eq!(config.price_estimation_drivers.len(), 2); + assert_eq!(config.price_estimation_drivers[0].name, "solver-a"); + assert_eq!(config.price_estimation_drivers[1].name, "solver-b"); + } + + #[test] + fn deserialize_missing_required_field() { + let toml = ""; + let result = toml::from_str::(toml); + assert!(result.is_err()); + } + + #[test] + fn roundtrip_serialization() { + let config = OrderQuoting { + price_estimation_drivers: vec![ExternalSolver { + name: "test".to_string(), + url: "http://localhost:1234".parse().unwrap(), + }], + eip1271_onchain_quote_validity: Duration::from_secs(300), + presign_onchain_quote_validity: Duration::from_secs(600), + standard_offchain_quote_validity: Duration::from_secs(60), + }; + let serialized = toml::to_string(&config).unwrap(); + let deserialized: OrderQuoting = toml::from_str(&serialized).unwrap(); + assert_eq!( + config.eip1271_onchain_quote_validity, + deserialized.eip1271_onchain_quote_validity + ); + assert_eq!( + config.presign_onchain_quote_validity, + deserialized.presign_onchain_quote_validity + ); + assert_eq!( + config.standard_offchain_quote_validity, + deserialized.standard_offchain_quote_validity + ); + assert_eq!( + config.price_estimation_drivers.len(), + deserialized.price_estimation_drivers.len() + ); + } +} diff --git a/crates/configs/src/orderbook/ipfs.rs b/crates/configs/src/orderbook/ipfs.rs new file mode 100644 index 0000000000..6b710b8c1c --- /dev/null +++ b/crates/configs/src/orderbook/ipfs.rs @@ -0,0 +1,119 @@ +use { + serde::{Deserialize, Deserializer, Serialize}, + std::fmt::Debug, + url::Url, +}; + +/// The IPFS authentication token is injected by 1Password directly into the +/// Pod's environment, completely bypassing Pulumi and making it unusable in the +/// configuration file. Since the token does not contain `%` this is a +/// workaround to allow the token to be read from the environment. +fn deserialize_auth_token<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let Some(raw_auth_token) = Option::::deserialize(deserializer)? else { + return Ok(None); + }; + if let Some(env_var_name) = raw_auth_token.strip_prefix("%") { + let env_var_contents = std::env::var(env_var_name).map_err(|err| { + tracing::error!(%err, %env_var_name, "failed to load env var"); + serde::de::Error::invalid_value( + serde::de::Unexpected::Str(env_var_name), + &"expected environment variable to be available", + ) + })?; + Ok(Some(env_var_contents)) + } else { + Ok(Some(raw_auth_token)) + } +} + +#[derive(Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct IpfsConfig { + /// IPFS gateway to fetch full app data for orders that only specify the + /// contract app data hash. + pub gateway: Url, + + /// Authentication key for Pinata IPFS gateway. + #[serde(deserialize_with = "deserialize_auth_token")] + pub auth_token: Option, +} + +impl Debug for IpfsConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("IpfsConfig") + .field("gateway", &self.gateway) + .field("auth_token", &"") + .finish() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn auth_token_is_redacted() { + let config = IpfsConfig { + gateway: Url::parse("https://google.com").unwrap(), + auth_token: None, + }; + assert!(format!("{:?}", config).contains(r#"auth_token: """#)); + + let config = IpfsConfig { + gateway: Url::parse("https://google.com").unwrap(), + auth_token: Some("SOME_TOKEN".to_string()), + }; + assert!(format!("{:?}", config).contains(r#"auth_token: """#)); + } + + #[test] + fn deserialize_full() { + let toml = r#" + gateway = "https://gateway.pinata.cloud/ipfs/" + auth-token = "my-secret-key" + "#; + let config: IpfsConfig = toml::from_str(toml).unwrap(); + assert_eq!( + config.gateway.as_str(), + "https://gateway.pinata.cloud/ipfs/" + ); + assert_eq!(config.auth_token.unwrap(), "my-secret-key"); + } + + #[test] + fn deserialize_auth_token_from_env() { + let env_var_name = "TEST_IPFS_AUTH_TOKEN_SECRET"; + let env_var_value = "my-secret-from-env"; + // SAFETY: no other threads access this env var. + unsafe { std::env::set_var(env_var_name, env_var_value) }; + + let toml = format!( + r#" + gateway = "https://gateway.pinata.cloud/ipfs/" + auth-token = "%{env_var_name}" + "#, + ); + let config: IpfsConfig = toml::from_str(&toml).unwrap(); + assert_eq!(config.auth_token.as_deref(), Some(env_var_value)); + + // SAFETY: no other threads access this env var. + unsafe { std::env::remove_var(env_var_name) }; + } + + #[test] + fn roundtrip_serialization() { + let config = IpfsConfig { + gateway: "https://gateway.pinata.cloud/ipfs/".parse().unwrap(), + auth_token: Some("my-secret-key".to_string()), + }; + + let serialized = toml::to_string_pretty(&config).unwrap(); + let deserialized: IpfsConfig = toml::from_str(&serialized).unwrap(); + + assert_eq!(config.gateway.as_str(), deserialized.gateway.as_str()); + assert_eq!(config.auth_token, deserialized.auth_token); + } +} diff --git a/crates/configs/src/orderbook/mod.rs b/crates/configs/src/orderbook/mod.rs new file mode 100644 index 0000000000..3f063ebfd6 --- /dev/null +++ b/crates/configs/src/orderbook/mod.rs @@ -0,0 +1,422 @@ +use { + crate::{ + banned_users::BannedUsersConfig, + database::DatabasePoolConfig, + fee_factor::FeeFactor, + http_client::HttpClient, + order_quoting::OrderQuoting, + orderbook::{ + ipfs::IpfsConfig, + native_price::NativePriceConfig, + order_validation::OrderValidationConfig, + }, + price_estimation::PriceEstimation, + shared::SharedConfig, + }, + alloy::primitives::Address, + anyhow::anyhow, + chrono::{DateTime, Utc}, + serde::{Deserialize, Serialize}, + std::{ + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + path::Path, + time::Duration, + }, +}; + +pub mod ipfs; +pub mod native_price; +pub mod order_validation; + +const fn default_bind_address() -> SocketAddr { + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 8080)) +} + +const fn default_app_data_size_limit() -> usize { + 8192 +} + +const fn default_active_order_competition_threshold() -> u32 { + 5 +} + +const fn default_simulation_timeout() -> Duration { + Duration::from_secs(2) +} + +/// Volume-based protocol fee applied to orders. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct VolumeFeeConfig { + /// Fee as a fraction of the order volume (e.g. 0.0002 = 0.02%). + pub factor: Option, + /// Timestamp from which this fee configuration becomes effective. + pub effective_from_timestamp: Option>, +} + +/// Top-level orderbook service configuration. +// NOTE: cannot add deny_unknown_fields during the config migration +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Configuration { + /// Shared settings (node URL, gas estimators, logging, etc.). + #[serde(default)] + pub shared: SharedConfig, + + /// Bind address for the Orderbook. + #[serde(default = "default_bind_address")] + pub bind_address: SocketAddr, + + /// Configuration for the order validation system. + #[serde(default)] + pub order_validation: OrderValidationConfig, + + /// Configuration for the banned users mechanism, + /// such as their addresses and the size of the banned user's cache. + #[serde(default)] + pub banned_users: BannedUsersConfig, + + /// Configuration for the IPFS gateway, supports token authentication. + pub ipfs: Option, + + /// Configuration for the volume fee. + pub volume_fee: Option, + + /// Maximum allowed size (in bytes) for order app-data. + #[serde(default = "default_app_data_size_limit")] + pub app_data_size_limit: usize, + + /// Missed auctions threshold after which an order is no longer "active". + #[serde(default = "default_active_order_competition_threshold")] + pub active_order_competition_threshold: u32, + + /// Denylist of tokens (due to lack of support, or other reason). + #[serde(default)] + pub unsupported_tokens: Vec
, + + /// Whether to skip EIP-1271 signature validation. + #[serde(default)] + pub eip1271_skip_creation_validation: bool, + + /// Configuration for the native price estimation mechanism. + pub native_price_estimation: NativePriceConfig, + + /// Database connection pool settings. + #[serde(default)] + pub database: DatabasePoolConfig, + + /// Configurations for the HTTP client (e.g. HTTP timeout). + #[serde(default)] + pub http_client: HttpClient, + + /// Configurations for the order creation process. + pub order_quoting: OrderQuoting, + + /// Configurations for price estimation (tenderly, rate limiting, CoinGecko, + /// 1inch, quote verification, balance overrides, etc.). + #[serde(default)] + pub price_estimation: PriceEstimation, + + /// Per-call timeout for order-creation simulation. + #[serde(default = "default_simulation_timeout", with = "humantime_serde")] + pub order_simulation_timeout: Duration, + + /// When enabled, solver competition endpoints return 404 until the + /// auction's submission deadline block has been reached. + #[serde(default)] + pub hide_competition_before_deadline: bool, +} + +impl Configuration { + pub async fn from_path>(path: P) -> anyhow::Result { + match toml::from_str(&tokio::fs::read_to_string(&path).await?) { + Ok(self_) => Ok(self_), + Err(err) if std::env::var("TOML_TRACE_ERROR").is_ok_and(|v| v == "1") => Err(anyhow!( + "failed to parse TOML config at {}: {err:#?}", + path.as_ref().display() + )), + Err(_) => Err(anyhow!( + "failed to parse TOML config at: {}. Set TOML_TRACE_ERROR=1 to print parsing \ + error but this may leak secrets.", + path.as_ref().display() + )), + } + } + + pub fn validate(self) -> anyhow::Result { + self.shared.validate()?; + Ok(self) + } +} + +#[cfg(any(test, feature = "test-util"))] +pub mod test_util { + use { + crate::{ + orderbook::{ + Configuration, + default_active_order_competition_threshold, + default_app_data_size_limit, + default_bind_address, + native_price::NativePriceConfig, + }, + price_estimation::PriceEstimation, + test_util::TestDefault, + }, + std::{path::Path, time::Duration}, + }; + + impl Configuration { + pub async fn to_path>(&self, path: P) -> anyhow::Result<()> { + Ok(tokio::fs::write(path, toml::to_string_pretty(self)?).await?) + } + + pub fn to_temp_path(&self) -> tempfile::NamedTempFile { + use std::io::Write; + let mut file = + tempfile::NamedTempFile::new().expect("temp file creation should not fail"); + file.write_all( + toml::to_string_pretty(self) + .expect("serialization should not fail") + .as_bytes(), + ) + .expect("writing to temp file should not fail"); + file + } + + pub fn to_cli_args(&self) -> (tempfile::NamedTempFile, String) { + let named_temp_file = self.to_temp_path(); + let cli_arg = format!("--config={}", named_temp_file.path().display()); + (named_temp_file, cli_arg) + } + } + + impl TestDefault for Configuration { + fn test_default() -> Self { + use crate::test_util::TestDefault; + + Self { + shared: Default::default(), + bind_address: default_bind_address(), + order_validation: Default::default(), + banned_users: Default::default(), + ipfs: Default::default(), + volume_fee: Default::default(), + app_data_size_limit: default_app_data_size_limit(), + active_order_competition_threshold: default_active_order_competition_threshold(), + unsupported_tokens: Default::default(), + eip1271_skip_creation_validation: Default::default(), + // NOTE: NativePriceConfig needs to be moved to the config crate and then it can + // have the test_default trait impl + native_price_estimation: NativePriceConfig::test_default(), + database: TestDefault::test_default(), + http_client: Default::default(), + order_quoting: TestDefault::test_default(), + price_estimation: PriceEstimation::test_default(), + order_simulation_timeout: Duration::from_secs(2), + hide_competition_before_deadline: false, + } + } + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + native_price_estimators::{NativePriceEstimator, NativePriceEstimators}, + orderbook::order_validation::SameTokensPolicy, + test_util::TestDefault, + }, + std::time::Duration, + }; + + #[test] + fn deserialize_full_configuration() { + let toml = r#" + app-data-size-limit = 4096 + active-order-competition-threshold = 10 + unsupported-tokens = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + eip1271-skip-creation-validation = true + hide-competition-before-deadline = true + order-simulation-timeout = "3s" + + [banned-users] + addresses = ["0xdead000000000000000000000000000000000000"] + + [order-validation] + min-order-validity-period = "2m" + max-order-validity-period = "6h" + max-limit-order-validity-period = "30d" + max-limit-orders-per-user = 5 + max-gas-per-order = 5000000 + same-tokens-policy = "allow-sell" + + [ipfs] + gateway = "https://gateway.pinata.cloud/ipfs/" + auth-token = "my-secret-key" + + [volume-fee] + factor = 0.0002 + effective-from-timestamp = "2025-06-01T00:00:00Z" + + [native-price-estimation] + estimators = [[{type = "CoinGecko"}]] + + [order-quoting] + price-estimation-drivers = [] + "#; + + let config: Configuration = toml::from_str(toml).unwrap(); + + assert_eq!(config.app_data_size_limit, 4096); + assert_eq!(config.active_order_competition_threshold, 10); + assert_eq!(config.unsupported_tokens.len(), 1); + assert_eq!(config.banned_users.addresses.len(), 1); + assert!(config.eip1271_skip_creation_validation); + assert!(config.hide_competition_before_deadline); + assert_eq!(config.order_simulation_timeout, Duration::from_secs(3)); + + assert!(matches!( + config.order_validation.same_tokens_policy, + SameTokensPolicy::AllowSell + )); + assert_eq!(config.order_validation.max_limit_orders_per_user, 5); + + assert_eq!( + config.order_validation.min_order_validity_period, + Duration::from_secs(120) + ); + assert_eq!( + config.order_validation.max_order_validity_period, + Duration::from_secs(21600) + ); + assert_eq!( + config.order_validation.max_limit_order_validity_period, + Duration::from_secs(2_592_000) + ); + + let ipfs = config.ipfs.unwrap(); + assert_eq!(ipfs.gateway.as_str(), "https://gateway.pinata.cloud/ipfs/"); + assert_eq!(ipfs.auth_token.unwrap(), "my-secret-key"); + + let vol_fee = config.volume_fee.unwrap(); + assert_eq!(vol_fee.factor.unwrap().get(), 0.0002); + assert!(vol_fee.effective_from_timestamp.is_some()); + } + + #[test] + fn deserialize_configuration_defaults() { + let toml = r#" + [native-price-estimation] + estimators = [[{type = "CoinGecko"}]] + + [order-quoting] + price-estimation-drivers = [] + "#; + let config: Configuration = toml::from_str(toml).unwrap(); + + assert_eq!(config.app_data_size_limit, 8192); + assert_eq!(config.active_order_competition_threshold, 5); + + assert_eq!( + config.order_validation.min_order_validity_period, + Duration::from_secs(60) + ); + assert_eq!( + config.order_validation.max_order_validity_period, + Duration::from_secs(10800) + ); + assert_eq!( + config.order_validation.max_limit_order_validity_period, + Duration::from_secs(31_536_000) + ); + + assert!(config.ipfs.is_none()); + assert!(config.volume_fee.is_none()); + assert!(config.unsupported_tokens.is_empty()); + assert!(config.banned_users.addresses.is_empty()); + assert!(!config.eip1271_skip_creation_validation); + assert!(!config.hide_competition_before_deadline); + } + + #[test] + fn roundtrip_serialization() { + let config = Configuration { + shared: Default::default(), + bind_address: default_bind_address(), + order_validation: OrderValidationConfig { + min_order_validity_period: Duration::from_secs(120), + max_order_validity_period: Duration::from_secs(7200), + max_limit_order_validity_period: Duration::from_secs(86400), + max_limit_orders_per_user: 5, + max_gas_per_order: 6_000_000, + same_tokens_policy: SameTokensPolicy::AllowSell, + }, + ipfs: Some(IpfsConfig { + gateway: "https://gateway.pinata.cloud/ipfs/".parse().unwrap(), + auth_token: Some("secret".to_string()), + }), + app_data_size_limit: 4096, + active_order_competition_threshold: 10, + volume_fee: Some(VolumeFeeConfig { + factor: Some(0.0002.try_into().unwrap()), + effective_from_timestamp: None, + }), + unsupported_tokens: vec![ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + .parse() + .unwrap(), + ], + banned_users: Default::default(), + eip1271_skip_creation_validation: true, + hide_competition_before_deadline: true, + native_price_estimation: NativePriceConfig { + estimators: NativePriceEstimators::new(vec![vec![NativePriceEstimator::CoinGecko]]), + fallback_estimators: None, + ..NativePriceConfig::test_default() + }, + order_quoting: TestDefault::test_default(), + database: TestDefault::test_default(), + http_client: Default::default(), + price_estimation: Default::default(), + order_simulation_timeout: default_simulation_timeout(), + }; + + let serialized = toml::to_string_pretty(&config).unwrap(); + let deserialized: Configuration = toml::from_str(&serialized).unwrap(); + + assert_eq!(config.app_data_size_limit, deserialized.app_data_size_limit); + assert_eq!( + config.active_order_competition_threshold, + deserialized.active_order_competition_threshold + ); + assert!(deserialized.volume_fee.is_some()); + assert_eq!( + config.volume_fee.as_ref().unwrap().factor.unwrap().get(), + deserialized + .volume_fee + .as_ref() + .unwrap() + .factor + .unwrap() + .get() + ); + assert_eq!(config.unsupported_tokens, deserialized.unsupported_tokens); + assert_eq!( + config.banned_users.addresses, + deserialized.banned_users.addresses + ); + assert_eq!( + config.eip1271_skip_creation_validation, + deserialized.eip1271_skip_creation_validation + ); + assert_eq!( + config.hide_competition_before_deadline, + deserialized.hide_competition_before_deadline + ); + assert_eq!(config.http_client.timeout, deserialized.http_client.timeout) + } +} diff --git a/crates/configs/src/orderbook/native_price.rs b/crates/configs/src/orderbook/native_price.rs new file mode 100644 index 0000000000..a12959e82d --- /dev/null +++ b/crates/configs/src/orderbook/native_price.rs @@ -0,0 +1,98 @@ +use { + crate::{ + native_price::NativePriceConfig as SharedNativePriceConfig, + native_price_estimators::NativePriceEstimators, + }, + serde::Deserialize, +}; + +/// Orderbook-specific native price estimation configuration. +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub struct NativePriceConfig { + /// Which estimators to use to estimate token prices in terms of the chain's + /// native token. + pub estimators: NativePriceEstimators, + + /// Fallback native price estimators to use when all primary estimators + /// are down. + pub fallback_estimators: Option, + + /// Shared native price settings (cache, approximation tokens, etc.). + #[serde(flatten)] + pub shared: SharedNativePriceConfig, +} + +#[cfg(any(test, feature = "test-util"))] +impl NativePriceConfig { + /// The orderbook forwards native price requests to the autopilot. + pub fn test_default() -> Self { + use crate::native_price_estimators::NativePriceEstimator; + Self { + estimators: NativePriceEstimators::new(vec![vec![NativePriceEstimator::forwarder( + "http://localhost:12088".parse().unwrap(), + )]]), + fallback_estimators: Default::default(), + shared: Default::default(), + } + } +} + +#[cfg(test)] +mod tests { + use {super::*, crate::native_price_estimators::NativePriceEstimator}; + + #[test] + fn deserialize_defaults() { + let config: NativePriceConfig = + toml::from_str(r#"estimators = [[{type = "CoinGecko"}]]"#).unwrap(); + assert_eq!(config.estimators.as_slice().len(), 1); + assert!(config.fallback_estimators.is_none()); + } + + #[test] + fn deserialize_full() { + let toml = r#" + estimators = [[{ type = "CoinGecko" }, { type = "OneInchSpotPriceApi" }]] + fallback-estimators = [[{ type = "CoinGecko" }]] + results-required = 3 + "#; + let config: NativePriceConfig = toml::from_str(toml).unwrap(); + assert!(config.fallback_estimators.is_some()); + } + + #[test] + fn deserialize_driver_estimator() { + let toml = r#" + estimators = [[{ type = "Driver", name = "test", url = "http://localhost:8080" }]] + "#; + let config: NativePriceConfig = toml::from_str(toml).unwrap(); + assert!(!config.estimators.as_slice().is_empty()); + } + + #[test] + fn roundtrip_serialization() { + let config = NativePriceConfig { + estimators: NativePriceEstimators::new(vec![vec![NativePriceEstimator::CoinGecko]]), + fallback_estimators: Some(NativePriceEstimators::new(vec![vec![ + NativePriceEstimator::OneInchSpotPriceApi, + ]])), + shared: Default::default(), + }; + + let serialized = toml::to_string_pretty(&config).unwrap(); + let deserialized: NativePriceConfig = toml::from_str(&serialized).unwrap(); + assert_eq!( + deserialized.estimators.as_slice(), + config.estimators.as_slice(), + ); + assert_eq!( + deserialized + .fallback_estimators + .as_ref() + .map(|e| e.as_slice()), + config.fallback_estimators.as_ref().map(|e| e.as_slice()), + ); + } +} diff --git a/crates/configs/src/orderbook/order_validation.rs b/crates/configs/src/orderbook/order_validation.rs new file mode 100644 index 0000000000..f9244a8f0f --- /dev/null +++ b/crates/configs/src/orderbook/order_validation.rs @@ -0,0 +1,163 @@ +use { + serde::{Deserialize, Serialize}, + std::time::Duration, +}; + +/// Policy controlling whether orders with identical buy and sell tokens are +/// accepted. +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum SameTokensPolicy { + /// Reject orders where buy token equals sell token. + #[default] + Disallow, + /// Allow sell orders where buy token equals sell token. + AllowSell, + /// Allow both sell and buy orders where buy token equals sell token. + Allow, +} + +const fn default_min_order_validity_period() -> Duration { + Duration::from_secs(60) // 1m +} + +const fn default_max_order_validity_period() -> Duration { + Duration::from_secs(10800) // 3h +} + +const fn default_max_limit_order_validity_period() -> Duration { + Duration::from_secs(31_536_000) // 1y +} + +const fn default_max_limit_orders_per_user() -> u64 { + 10 +} + +const fn default_max_gas_per_order() -> u64 { + 8_000_000 +} + +/// Rules governing order validity periods, gas limits, and token policies. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct OrderValidationConfig { + /// The minimum amount of time an order has to be valid for. + #[serde( + with = "humantime_serde", + default = "default_min_order_validity_period" + )] + pub min_order_validity_period: Duration, + + /// The maximum amount of time a market order can be valid for. + /// This restriction does not apply to liquidity owner orders or presign + /// orders. + #[serde( + with = "humantime_serde", + default = "default_max_order_validity_period" + )] + pub max_order_validity_period: Duration, + + /// The maximum amount of time a limit order can be valid for. + #[serde( + with = "humantime_serde", + default = "default_max_limit_order_validity_period" + )] + pub max_limit_order_validity_period: Duration, + + /// The maximum number of limit orders a user can have open. + #[serde(default = "default_max_limit_orders_per_user")] + pub max_limit_orders_per_user: u64, + + /// Maximum gas value that can be spent per order. + #[serde(default = "default_max_gas_per_order")] + pub max_gas_per_order: u64, + + /// Policy for orders where the buy and sell tokens are equal. + #[serde(default)] + pub same_tokens_policy: SameTokensPolicy, +} + +impl Default for OrderValidationConfig { + fn default() -> Self { + Self { + min_order_validity_period: default_min_order_validity_period(), + max_order_validity_period: default_max_order_validity_period(), + max_limit_order_validity_period: default_max_limit_order_validity_period(), + max_limit_orders_per_user: default_max_limit_orders_per_user(), + max_gas_per_order: default_max_gas_per_order(), + same_tokens_policy: Default::default(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_defaults() { + let config: OrderValidationConfig = toml::from_str("").unwrap(); + assert_eq!(config.min_order_validity_period, Duration::from_secs(60)); + assert_eq!(config.max_order_validity_period, Duration::from_secs(10800)); + assert_eq!( + config.max_limit_order_validity_period, + Duration::from_secs(31_536_000) + ); + } + + #[test] + fn deserialize_full() { + let toml = r#" + min-order-validity-period = "2m" + max-order-validity-period = "6h" + max-limit-order-validity-period = "30d" + max-limit-orders-per-user = 10 + max-gas-per-order = 5000000 + same-tokens-policy = "allow-sell" + "#; + let config: OrderValidationConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.min_order_validity_period, Duration::from_secs(120)); + assert_eq!(config.max_order_validity_period, Duration::from_secs(21600)); + assert_eq!( + config.max_limit_order_validity_period, + Duration::from_secs(2_592_000) + ); + assert_eq!(config.max_limit_orders_per_user, 10); + assert_eq!(config.max_gas_per_order, 5_000_000); + assert_eq!(config.same_tokens_policy, SameTokensPolicy::AllowSell); + } + + #[test] + fn roundtrip_serialization() { + let config = OrderValidationConfig { + min_order_validity_period: Duration::from_secs(120), + max_order_validity_period: Duration::from_secs(7200), + max_limit_order_validity_period: Duration::from_secs(86400), + max_limit_orders_per_user: 5, + max_gas_per_order: 5_000_000, + same_tokens_policy: SameTokensPolicy::AllowSell, + }; + + let serialized = toml::to_string_pretty(&config).unwrap(); + let deserialized: OrderValidationConfig = toml::from_str(&serialized).unwrap(); + + assert_eq!( + config.min_order_validity_period, + deserialized.min_order_validity_period + ); + assert_eq!( + config.max_order_validity_period, + deserialized.max_order_validity_period + ); + assert_eq!( + config.max_limit_order_validity_period, + deserialized.max_limit_order_validity_period + ); + assert_eq!( + config.max_limit_orders_per_user, + deserialized.max_limit_orders_per_user + ); + assert_eq!(config.max_gas_per_order, deserialized.max_gas_per_order); + assert_eq!(config.same_tokens_policy, deserialized.same_tokens_policy); + } +} diff --git a/crates/configs/src/price_estimation.rs b/crates/configs/src/price_estimation.rs new file mode 100644 index 0000000000..84cda1c9f8 --- /dev/null +++ b/crates/configs/src/price_estimation.rs @@ -0,0 +1,435 @@ +use { + crate::rate_limit::Strategy, + alloy::primitives::{Address, U256, map::HashSet}, + bigdecimal::BigDecimal, + serde::Deserialize, + std::{str::FromStr, time::Duration}, + url::Url, +}; + +/// Controls which level of quote verification gets applied. +#[derive(Copy, Clone, Debug, Default, serde::Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub enum QuoteVerificationMode { + /// Quotes do not get verified. + #[default] + Unverified, + /// Quotes get verified whenever possible and verified + /// quotes are preferred over unverified ones. + Prefer, +} + +const fn default_quote_timeout() -> Duration { + Duration::from_secs(5) +} + +const fn default_max_quote_timeout() -> Duration { + Duration::from_secs(10) +} + +fn default_quote_inaccuracy_limit() -> BigDecimal { + BigDecimal::from(1) +} + +const fn default_max_gas_per_tx() -> u64 { + 16777215 +} + +#[derive(Deserialize, Debug)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct PriceEstimation { + /// Configures the back off strategy for price estimators when requests take + /// too long. Requests issued while back off is active get dropped + /// entirely. + pub price_estimation_rate_limiter: Option, + + /// The amount in native token atoms to use for price estimation. Should be + /// reasonably large so that small pools do not influence the prices. If + /// not set, a reasonable default is used based on network id. + pub amount_to_estimate_prices_with: Option, + + /// How inaccurate a quote must be before it gets discarded, provided as a + /// factor. E.g. a value of `0.01` means at most 1 percent of the sell or + /// buy tokens can be paid out of the settlement contract buffers. + #[serde(default = "default_quote_inaccuracy_limit")] + pub quote_inaccuracy_limit: BigDecimal, + + /// How strict quote verification should be. + #[serde(default)] + pub quote_verification: QuoteVerificationMode, + + /// Default timeout for quote requests. + #[serde(with = "humantime_serde", default = "default_quote_timeout")] + pub quote_timeout: Duration, + + /// Maximum timeout a user may request for a quote. User-provided timeouts + /// are clamped to `[0, max_quote_timeout]`. + #[serde(with = "humantime_serde", default = "default_max_quote_timeout")] + pub max_quote_timeout: Duration, + + #[serde(default)] + pub balance_overrides: BalanceOverridesConfig, + + /// Tokens for which quote verification should not be attempted. This is an + /// escape hatch when there is a very bad but verifiable liquidity source + /// that would win against a very good but unverifiable liquidity source + /// (e.g. private liquidity that exists but can't be verified). + #[serde(default)] + pub tokens_without_verification: HashSet
, + + /// How much gas a single tx may consume at most. Any quote using more than + /// this will fail during the verification. + /// Defaults to the maximum transaction gas limit Ethereum introduced in the + /// Fusaka hardfork. + #[serde(default = "default_max_gas_per_tx")] + pub max_gas_per_tx: u64, + + /// Minimum gas amount for unverified quotes. When an unverified quote + /// reports less gas than this, the floor is used instead. Verified quotes + /// are unaffected. Defaults to 0 (disabled). + /// + /// Some tokens (e.g. Ondo RWA tokens) have high transfer costs that + /// solvers underestimate in unverified quotes, leading to fees that don't + /// cover execution gas and causing small orders to expire unfilled. + #[serde(default)] + pub min_gas_amount_for_unverified_quotes: u32, + + /// Maximum gas amount for unverified quotes. When an unverified quote + /// reports more gas than this, the ceiling is used instead. Verified + /// quotes are unaffected. Defaults to u32::MAX (disabled). + /// + /// This is a hack to alleviate tsolver issues where they report extremely + /// high gas for RWA tokens. + #[serde(default = "default_max_gas_amount_for_unverified_quotes")] + pub max_gas_amount_for_unverified_quotes: u32, + + /// Tenderly configuration (URL, project & API key). + #[serde(default)] + pub tenderly: Option, + + /// The CoinGecko native price configuration. + pub coin_gecko: Option, + + /// 1-inch API connection settings (URL & key). + pub one_inch: Option, +} + +impl Default for PriceEstimation { + fn default() -> Self { + Self { + tenderly: Default::default(), + price_estimation_rate_limiter: None, + amount_to_estimate_prices_with: None, + one_inch: Default::default(), + coin_gecko: Default::default(), + quote_inaccuracy_limit: default_quote_inaccuracy_limit(), + quote_verification: Default::default(), + quote_timeout: default_quote_timeout(), + max_quote_timeout: default_max_quote_timeout(), + balance_overrides: Default::default(), + tokens_without_verification: Default::default(), + max_gas_per_tx: default_max_gas_per_tx(), + min_gas_amount_for_unverified_quotes: 0, + max_gas_amount_for_unverified_quotes: u32::MAX, + } + } +} + +#[cfg(any(test, feature = "test-util"))] +impl crate::test_util::TestDefault for PriceEstimation { + fn test_default() -> Self { + Self { + amount_to_estimate_prices_with: Some(alloy::primitives::U256::from( + 1_000_000_000_000_000_000u64, + )), + quote_timeout: Duration::from_secs(10), + quote_verification: QuoteVerificationMode::Prefer, + ..Default::default() + } + } +} + +fn default_coin_gecko_url() -> Url { + Url::from_str("https://api.coingecko.com/api/v3/simple/token_price") + .expect("url should be valid") +} + +#[derive(Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct CoinGeckoConfig { + /// The API key for the CoinGecko API. + #[serde( + default, + deserialize_with = "crate::deserialize_env::deserialize_string_from_env" + )] + pub api_key: String, + + /// The base URL for the CoinGecko API. + #[serde(default = "default_coin_gecko_url")] + pub url: Url, + + pub buffered: Option, +} + +impl std::fmt::Debug for CoinGeckoConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CoinGeckoConfig") + .field("api_key", &"") + .field("url", &self.url) + .field("buffered", &self.buffered) + .finish() + } +} + +#[cfg(any(test, feature = "test-util"))] +impl crate::test_util::TestDefault for CoinGeckoConfig { + fn test_default() -> Self { + Self { + api_key: "test-api-key".to_string(), + url: default_coin_gecko_url(), + buffered: None, + } + } +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct CoinGeckoBufferedConfig { + /// An additional minimum delay to wait for collecting CoinGecko requests. + /// + /// The delay to start counting after receiving the first request. + #[serde(with = "humantime_serde")] + pub debouncing_time: Duration, + + /// Maximum capacity of the broadcast channel to store the CoinGecko native + /// prices results + pub broadcast_channel_capacity: usize, +} + +const fn default_probing_depth() -> u8 { + 60 +} + +const fn default_cache_size() -> u64 { + 1000 +} + +fn default_detection_timeout() -> Duration { + Duration::from_secs(1) +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct BalanceOverridesConfig { + /// Controls how many storage slots get probed per storage entry point + /// for automatically detecting how to override the balances of a token. + #[serde(default = "default_probing_depth")] + pub probing_depth: u8, + + /// Controls for how many tokens we store the result of the automatic + /// balance override detection before evicting less used entries. + #[serde(default = "default_cache_size")] + pub cache_size: u64, + + /// Maximum time to wait for each balance override strategy verification + /// before giving up. Some tokens (e.g. reflection tokens) can cause the + /// node to loop during verification, so this prevents stalling the quote + /// pipeline. + #[serde(default = "default_detection_timeout", with = "humantime_serde")] + pub detection_timeout: Duration, +} + +impl Default for BalanceOverridesConfig { + fn default() -> Self { + Self { + probing_depth: default_probing_depth(), + cache_size: default_cache_size(), + detection_timeout: default_detection_timeout(), + } + } +} + +fn default_one_inch_url() -> Url { + Url::from_str("https://api.1inch.dev/").expect("url should be valid") +} + +fn default_max_gas_amount_for_unverified_quotes() -> u32 { + u32::MAX +} + +#[derive(Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub struct OneInchApi { + /// The base URL for the 1Inch API. + #[serde(default = "default_one_inch_url")] + pub url: Url, + + /// The API key for the 1Inch API. + #[serde(default)] + pub api_key: String, +} + +impl std::fmt::Debug for OneInchApi { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("OneInchApi") + .field("url", &self.url) + .field("api_key", &"") + .finish() + } +} + +#[cfg(any(test, feature = "test-util"))] +impl crate::test_util::TestDefault for OneInchApi { + fn test_default() -> Self { + Self { + url: default_one_inch_url(), + api_key: "test-api-key".to_string(), + } + } +} + +#[cfg(test)] +mod tests { + use {super::*, crate::test_util::TestDefault}; + + #[test] + fn deserialize_defaults() { + let toml = ""; + let config: PriceEstimation = toml::from_str(toml).unwrap(); + assert!(config.tenderly.is_none()); + assert!(config.price_estimation_rate_limiter.is_none()); + assert!(config.amount_to_estimate_prices_with.is_none()); + assert!(config.one_inch.is_none()); + assert!(config.coin_gecko.is_none()); + assert_eq!(config.quote_inaccuracy_limit, BigDecimal::from(1)); + assert!(matches!( + config.quote_verification, + QuoteVerificationMode::Unverified + )); + assert_eq!(config.quote_timeout, Duration::from_secs(5)); + assert_eq!(config.balance_overrides.probing_depth, 60); + assert_eq!(config.balance_overrides.cache_size, 1000); + assert!(config.tokens_without_verification.is_empty()); + assert_eq!(config.min_gas_amount_for_unverified_quotes, 0); + assert_eq!(config.max_gas_amount_for_unverified_quotes, u32::MAX); + } + + #[test] + fn deserialize_full() { + let toml = r#" + quote-inaccuracy-limit = "0.01" + quote-verification = "prefer" + quote-timeout = "10s" + max-quote-timeout = "20s" + tokens-without-verification = ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"] + amount-to-estimate-prices-with = "1000000000000000000" + min-gas-amount-for-unverified-quotes = 400000 + max-gas-amount-for-unverified-quotes = 800000 + + [price-estimation-rate-limiter] + back-off-growth-factor = 2.0 + min-back-off = "1s" + max-back-off = "30s" + + [tenderly] + user = "my-user" + project = "my-project" + api-key = "my-tenderly-key" + + [one-inch] + api-key = "my-1inch-key" + url = "https://custom.1inch.dev/" + + [coin-gecko] + api-key = "my-cg-key" + url = "https://pro-api.coingecko.com/api/v3/simple/token_price" + + [coin-gecko.buffered] + debouncing-time = "500ms" + broadcast-channel-capacity = 100 + + [balance-overrides] + probing-depth = 30 + cache-size = 500 + "#; + let config: PriceEstimation = toml::from_str(toml).unwrap(); + + let tenderly = config.tenderly.as_ref().unwrap(); + assert_eq!(tenderly.user, "my-user"); + assert_eq!(tenderly.project, "my-project"); + assert_eq!(tenderly.api_key, "my-tenderly-key"); + assert!(config.price_estimation_rate_limiter.is_some()); + assert_eq!( + config.amount_to_estimate_prices_with, + Some(alloy::primitives::U256::from(1_000_000_000_000_000_000u64)) + ); + let one_inch = config.one_inch.as_ref().unwrap(); + assert_eq!(one_inch.api_key, "my-1inch-key"); + assert_eq!(one_inch.url.as_str(), "https://custom.1inch.dev/"); + let coin_gecko = config.coin_gecko.as_ref().unwrap(); + assert_eq!(coin_gecko.api_key, "my-cg-key"); + assert_eq!( + coin_gecko.url.as_str(), + "https://pro-api.coingecko.com/api/v3/simple/token_price" + ); + let buffered = coin_gecko.buffered.as_ref().unwrap(); + assert_eq!(buffered.debouncing_time, Duration::from_millis(500)); + assert_eq!(buffered.broadcast_channel_capacity, 100); + assert_eq!(config.quote_inaccuracy_limit.to_string(), "0.01"); + assert!(matches!( + config.quote_verification, + QuoteVerificationMode::Prefer + )); + assert_eq!(config.quote_timeout, Duration::from_secs(10)); + assert_eq!(config.max_quote_timeout, Duration::from_secs(20)); + assert_eq!(config.balance_overrides.probing_depth, 30); + assert_eq!(config.balance_overrides.cache_size, 500); + assert_eq!(config.tokens_without_verification.len(), 1); + assert_eq!(config.min_gas_amount_for_unverified_quotes, 400_000); + assert_eq!(config.max_gas_amount_for_unverified_quotes, 800_000); + } + + #[test] + fn roundtrip_serialization() { + let config = PriceEstimation { + quote_timeout: Duration::from_secs(10), + quote_verification: QuoteVerificationMode::Prefer, + ..Default::default() + }; + let serialized = toml::to_string_pretty(&config).unwrap(); + let deserialized: PriceEstimation = toml::from_str(&serialized).unwrap(); + assert_eq!(config.quote_timeout, deserialized.quote_timeout); + assert!(matches!( + deserialized.quote_verification, + QuoteVerificationMode::Prefer + )); + } + + #[test] + fn debug_redacts_secrets() { + let config = PriceEstimation { + one_inch: Some(OneInchApi { + api_key: "secret".to_string(), + ..TestDefault::test_default() + }), + coin_gecko: Some(CoinGeckoConfig { + api_key: "secret".to_string(), + ..TestDefault::test_default() + }), + tenderly: Some(crate::simulator::TenderlyConfig { + api_key: "secret".to_string(), + ..TestDefault::test_default() + }), + ..Default::default() + }; + let debug = format!("{config:?}"); + assert!(!debug.contains("secret")); + assert!(debug.contains("")); + } +} diff --git a/crates/configs/src/rate_limit.rs b/crates/configs/src/rate_limit.rs new file mode 100644 index 0000000000..96ac208b37 --- /dev/null +++ b/crates/configs/src/rate_limit.rs @@ -0,0 +1,73 @@ +use { + anyhow::ensure, + std::{ + fmt::{Display, Formatter}, + time::{Duration, Instant}, + }, +}; + +#[derive(Debug, Clone, serde::Deserialize)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +#[serde(rename_all = "kebab-case")] +pub struct Strategy { + /// Point in time until which incoming requests are dropped due to + /// active rate limiting. + #[serde(skip, default = "Instant::now")] + pub drop_requests_until: Instant, + /// How many requests got rate limited in a row. + #[serde(skip)] + pub times_rate_limited: u64, + /// Multiplier applied to the back-off duration after each successive + /// rate-limited response. Must be >= 1.0. + pub back_off_growth_factor: f64, + /// Initial back-off duration used after the first rate-limited response. + #[serde(with = "humantime_serde")] + pub min_back_off: Duration, + /// Upper bound for the back-off duration regardless of growth factor. + #[serde(with = "humantime_serde")] + pub max_back_off: Duration, +} + +impl Strategy { + pub fn try_new( + back_off_growth_factor: f64, + min_back_off: Duration, + max_back_off: Duration, + ) -> anyhow::Result { + ensure!( + back_off_growth_factor.is_normal(), + "back_off_growth_factor must be a normal f64" + ); + ensure!( + back_off_growth_factor >= 1.0, + "back_off_growth_factor needs to be at least 1.0" + ); + ensure!( + min_back_off <= max_back_off, + "min_back_off needs to be <= max_back_off" + ); + Ok(Self { + drop_requests_until: Instant::now(), + times_rate_limited: 0, + back_off_growth_factor, + min_back_off, + max_back_off, + }) + } +} + +impl Default for Strategy { + fn default() -> Self { + Self::try_new(1.0, Duration::default(), Duration::default()).unwrap() + } +} + +impl Display for Strategy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "RateLimitingStrategy{{ min_back_off: {:?}, max_back_off: {:?}, growth_factor: {:?} }}", + self.min_back_off, self.max_back_off, self.back_off_growth_factor + ) + } +} diff --git a/crates/configs/src/shared.rs b/crates/configs/src/shared.rs new file mode 100644 index 0000000000..c6737c5cdf --- /dev/null +++ b/crates/configs/src/shared.rs @@ -0,0 +1,545 @@ +use { + crate::fee_factor::FeeFactor, + alloy::primitives::Address, + anyhow::ensure, + serde::{Deserialize, Deserializer, Serialize, de::Unexpected}, + std::{collections::HashSet, str::FromStr, time::Duration}, + tracing::Level, + url::Url, +}; + +#[cfg(any(test, feature = "test-util"))] +use crate::test_util::TestDefault; + +fn default_node_url() -> Url { + "http://localhost:8545".parse().unwrap() +} + +fn default_gas_estimators() -> Vec { + vec![GasEstimatorType::Web3] +} + +const fn default_ethrpc_max_batch_size() -> usize { + 100 +} + +const fn default_ethrpc_max_concurrent_requests() -> usize { + 10 +} + +fn default_log_filter() -> String { + String::from( + "info,autopilot=debug,driver=debug,observe=info,orderbook=debug,solver=debug,shared=debug,\ + cow_amm=debug", + ) +} + +const fn default_tracing_level() -> tracing::Level { + tracing::Level::INFO +} + +const fn default_tracing_exporter_timeout() -> Duration { + Duration::from_secs(10) +} + +/// Configuration shared across all services (orderbook, autopilot, driver, +/// etc.). Covers node connectivity, gas estimation, logging, tracing, and +/// protocol-level fee overrides. +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct SharedConfig { + /// Tuning parameters for the batching Ethereum RPC layer. + #[serde(default)] + pub ethrpc: EthRpcConfig, + + /// Configuration for the current-block stream that tracks chain head. + #[serde(default)] + pub current_block: CurrentBlockConfig, + + /// Log filter, output format, and stderr threshold. + #[serde(default)] + pub logging: LoggingConfig, + + /// OpenTelemetry tracing export settings. + #[serde(default)] + pub tracing: TracingConfig, + + /// The Ethereum node URL to connect to. + #[serde(default = "default_node_url")] + pub node_url: Url, + + /// An Ethereum node URL that supports `eth_call`s with state overrides + /// to be used for simulations. + pub simulation_node_url: Option, + + /// The expected chain ID that the services are expected to run against. + /// This can be optionally specified in order to check at startup whether + /// the connected nodes match to detect misconfigurations. + pub chain_id: Option, + + /// Which gas estimators to use. Multiple estimators are used in sequence + /// if a previous one fails. Individual estimators support different + /// networks. `Web3` supports every network. + #[serde(default = "default_gas_estimators")] + pub gas_estimators: Vec, + + #[serde(default)] + pub contracts: ContractAddresses, + + /// Custom volume fee factors for token buckets. Orders where both tokens + /// are in the bucket will use the custom fee. Useful for + /// stablecoin-to-stablecoin trades or specific token pairs. + #[serde(default)] + pub volume_fee_bucket_overrides: Vec, + + /// Enable volume fees for trades where sell token equals buy token. + /// By default, volume fees are NOT applied to same-token trades. + #[serde(default)] + pub enable_sell_equals_buy_volume_fee: bool, + + /// Enables publishing events to a global events bus. + pub event_bus: Option, +} + +impl SharedConfig { + /// Cross-field invariants that cannot be expressed in the serde schema. + pub fn validate(&self) -> anyhow::Result<()> { + ensure!( + self.event_bus.is_none() || self.chain_id.is_some(), + "`chain-id` is required when the event bus is configured", + ); + Ok(()) + } +} + +impl Default for SharedConfig { + fn default() -> Self { + Self { + ethrpc: Default::default(), + current_block: Default::default(), + logging: Default::default(), + tracing: Default::default(), + node_url: default_node_url(), + simulation_node_url: None, + chain_id: None, + gas_estimators: default_gas_estimators(), + contracts: Default::default(), + volume_fee_bucket_overrides: Vec::new(), + enable_sell_equals_buy_volume_fee: false, + event_bus: None, + } + } +} + +/// Tuning parameters for the batching Ethereum RPC layer. +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct EthRpcConfig { + /// Maximum number of RPC calls in a single batch request. + #[serde(default = "default_ethrpc_max_batch_size")] + pub max_batch_size: usize, + + /// Maximum number of concurrent batch requests to the node. + #[serde(default = "default_ethrpc_max_concurrent_requests")] + pub max_concurrent_requests: usize, + + /// Artificial delay before sending a batch, allowing more calls to be + /// grouped together. + #[serde(with = "humantime_serde", default)] + pub batch_delay: Duration, +} + +impl Default for EthRpcConfig { + fn default() -> Self { + Self { + max_batch_size: default_ethrpc_max_batch_size(), + max_concurrent_requests: default_ethrpc_max_concurrent_requests(), + batch_delay: Duration::ZERO, + } + } +} + +/// Configuration for the current-block stream that tracks chain head. +#[derive(Debug, Default, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct CurrentBlockConfig { + /// How often to poll the node for the latest block. + #[serde(with = "humantime_serde", default)] + pub poll_interval: Option, + + /// Optional WebSocket URL for block-header subscriptions (faster than + /// polling). + pub ws_url: Option, +} + +/// Optional address overrides for protocol contracts. When `None`, the +/// canonical deployment addresses for the detected chain are used. +#[derive(Debug, Default, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct ContractAddresses { + /// The `GPv2Settlement` contract. + pub settlement: Option
, + + /// The `BalancerV2VaultRelayer`-style allowance manager contract. + pub balances: Option
, + + /// The `SignatureValidator` contract used for EIP-1271 verification. + pub signatures: Option
, + + /// The wrapped native token (e.g. WETH) for the target chain. + pub native_token: Option
, + + /// The `CowHooks` trampoline contract. + pub hooks: Option
, + + /// The Balancer V2 Vault contract used for liquidity sourcing. + pub balancer_v2_vault: Option
, + + /// The flashloan router contract. + pub flashloan_router: Option
, +} + +/// Logging configuration (log filter, output format). +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct LoggingConfig { + /// `tracing` filter directive (e.g. `"info,shared=debug"`). + #[serde(default = "default_log_filter")] + pub filter: String, + + #[serde(default, deserialize_with = "deserialize_optional_level")] + #[cfg_attr( + any(test, feature = "test-util"), + serde( + skip_serializing_if = "Option::is_none", + serialize_with = "serialize_optional_level" + ) + )] + pub stderr_threshold: Option, + + /// Emit structured JSON logs instead of human-readable text. + #[serde(default)] + pub use_json: bool, +} + +fn deserialize_optional_level<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let Some(raw_level) = Option::::deserialize(deserializer)? else { + return Ok(None); + }; + Ok(Some(tracing::Level::from_str(&raw_level).map_err( + |_| { + serde::de::Error::invalid_value( + Unexpected::Str(&raw_level), + // Since exp must be 'static, this string is copied from ParseLevelError::Display + &"error parsing level: expected one of \"error\", \"warn\", \"info\", \"debug\", \ + \"trace\", or a number 1-5", + ) + }, + )?)) +} + +#[cfg(any(test, feature = "test-util"))] +fn serialize_optional_level( + level: &Option, + serializer: S, +) -> Result +where + S: serde::Serializer, +{ + match level { + Some(level) => serializer.serialize_str(level.as_str()), + None => serializer.serialize_none(), + } +} + +impl Default for LoggingConfig { + fn default() -> Self { + Self { + filter: default_log_filter(), + stderr_threshold: None, + use_json: false, + } + } +} + +/// OpenTelemetry tracing configuration. +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct TracingConfig { + /// OTLP collector endpoint (e.g. `"http://jaeger:4317"`). + pub collector_endpoint: Option, + + /// Minimum span level to export. + #[serde( + deserialize_with = "deserialize_level", + default = "default_tracing_level" + )] + #[cfg_attr( + any(test, feature = "test-util"), + serde(serialize_with = "serialize_level") + )] + pub level: Level, + + /// Timeout for the OTLP exporter when flushing spans. + #[serde(with = "humantime_serde", default = "default_tracing_exporter_timeout")] + pub exporter_timeout: Duration, +} + +impl Default for TracingConfig { + fn default() -> Self { + Self { + collector_endpoint: None, + level: default_tracing_level(), + exporter_timeout: default_tracing_exporter_timeout(), + } + } +} + +fn deserialize_level<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let raw_level = String::deserialize(deserializer)?; + tracing::Level::from_str(&raw_level).map_err(|_| { + serde::de::Error::invalid_value( + Unexpected::Str(&raw_level), + // Since exp must be 'static, this string is copied from ParseLevelError::Display + &"error parsing level: expected one of \"error\", \"warn\", \"info\", \"debug\", \ + \"trace\", or a number 1-5", + ) + }) +} + +#[cfg(any(test, feature = "test-util"))] +fn serialize_level(level: &tracing::Level, serializer: S) -> Result +where + S: serde::Serializer, +{ + serializer.serialize_str(level.as_str()) +} + +/// Event bus configuration for a backend service. +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub struct EventBusConfig { + /// Url of the event bus service. + pub url: Url, + /// Name of the channel to post events to. Must not contain spaces, tabs, + /// or `.` — NATS uses `.` as its subject hierarchy separator and disallows + /// whitespace in stream/subject names. + #[serde(deserialize_with = "deserialize_channel_name")] + pub channel: String, +} + +fn deserialize_channel_name<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let raw = String::deserialize(deserializer)?; + if raw.contains([' ', '\t', '.']) { + return Err(serde::de::Error::invalid_value( + Unexpected::Str(&raw), + &"a channel name without spaces, tabs, or '.'", + )); + } + Ok(raw) +} + +/// Gas price estimation strategy. +#[derive(Debug, Clone, Deserialize)] +#[serde(tag = "type")] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub enum GasEstimatorType { + /// Use the node's `eth_gasPrice` / EIP-1559 fee history RPCs. + Web3, + /// Fetch gas price from an external driver endpoint. + Driver { url: Url }, + /// Use Alloy's built-in gas estimation. + Alloy, +} + +#[cfg(any(test, feature = "test-util"))] +impl TestDefault for GasEstimatorType { + fn test_default() -> Self { + Self::Driver { + url: "http://localhost:11088/gasprice" + .parse() + .expect("URL should be valid"), + } + } +} + +/// Overrides the volume fee factor for orders where both tokens belong to +/// the specified set (e.g. stablecoin-to-stablecoin trades). +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[cfg_attr(any(test, feature = "test-util"), derive(serde::Serialize))] +pub struct TokenBucketFeeOverride { + pub tokens: HashSet
, + pub factor: FeeFactor, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_shared_config_defaults() { + let toml = ""; + let config: SharedConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.node_url.as_str(), "http://localhost:8545/"); + assert!(config.chain_id.is_none()); + assert_eq!(config.gas_estimators.len(), 1); + assert!(matches!(config.gas_estimators[0], GasEstimatorType::Web3)); + assert!(config.volume_fee_bucket_overrides.is_empty()); + assert!(!config.enable_sell_equals_buy_volume_fee); + } + + #[test] + fn deserialize_shared_config_full() { + let toml = r#" + node-url = "http://mainnet.example.com:8545" + chain-id = 1 + enable-sell-equals-buy-volume-fee = true + + [contracts] + settlement = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + + [ethrpc] + max-batch-size = 200 + max-concurrent-requests = 20 + batch-delay = "1s" + + [current-block] + poll-interval = "2s" + ws-url = "ws://localhost:8546" + + [logging] + filter = "debug" + stderr-threshold = "warn" + use-json = true + + [tracing] + collector-endpoint = "http://jaeger:4317" + level = "debug" + exporter-timeout = "5s" + + [[gas-estimators]] + type = "Web3" + + [[gas-estimators]] + type = "Driver" + url = "http://localhost:8080" + + [[volume-fee-bucket-overrides]] + factor = 0.5 + tokens = [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0x6B175474E89094C44Da98b954EedeAC495271d0F", + ] + + [event-bus] + url = "localhost:4222" + channel = "main" + "#; + + let config: SharedConfig = toml::from_str(toml).unwrap(); + assert_eq!(config.node_url.as_str(), "http://mainnet.example.com:8545/"); + assert_eq!(config.chain_id, Some(1)); + assert_eq!(config.ethrpc.max_batch_size, 200); + assert_eq!(config.ethrpc.max_concurrent_requests, 20); + assert_eq!(config.ethrpc.batch_delay, Duration::from_secs(1)); + assert_eq!( + config.current_block.poll_interval, + Some(Duration::from_secs(2)) + ); + assert!(config.current_block.ws_url.is_some()); + assert_eq!(config.logging.filter, "debug"); + assert_eq!(config.logging.stderr_threshold, Some(tracing::Level::WARN)); + assert!(config.logging.use_json); + assert_eq!( + config.tracing.collector_endpoint.as_deref(), + Some("http://jaeger:4317") + ); + assert_eq!(config.tracing.level, tracing::Level::DEBUG); + assert_eq!(config.tracing.exporter_timeout, Duration::from_secs(5)); + assert_eq!(config.gas_estimators.len(), 2); + assert!(config.contracts.settlement.is_some()); + assert!(config.enable_sell_equals_buy_volume_fee); + assert_eq!(config.volume_fee_bucket_overrides.len(), 1); + assert_eq!(config.volume_fee_bucket_overrides[0].tokens.len(), 2); + assert_eq!( + config.event_bus.as_ref().unwrap().url, + "localhost:4222".parse().unwrap() + ); + assert_eq!(config.event_bus.as_ref().unwrap().channel, "main"); + } + + #[test] + fn rejects_invalid_event_bus_channel_at_deserialization() { + for bad in ["with space", "with\ttab", "with.dot"] { + let toml = format!( + r#" + chain-id = 1 + + [event-bus] + url = "localhost:4222" + channel = "{bad}" + "#, + ); + assert!( + toml::from_str::(&toml).is_err(), + "channel {bad:?} should be rejected", + ); + } + + let ok = toml::from_str::( + r#" + chain-id = 1 + + [event-bus] + url = "localhost:4222" + channel = "main" + "#, + ) + .unwrap(); + assert_eq!(ok.event_bus.unwrap().channel, "main"); + } + + #[test] + fn validate_event_bus_requires_chain_id() { + let with_event_bus_only = toml::from_str::( + r#" + [event-bus] + url = "localhost:4222" + channel = "main" + "#, + ) + .unwrap(); + assert!(with_event_bus_only.validate().is_err()); + + let with_both = toml::from_str::( + r#" + chain-id = 1 + + [event-bus] + url = "localhost:4222" + channel = "main" + "#, + ) + .unwrap(); + with_both.validate().unwrap(); + + // Default config has neither set; validation should pass. + SharedConfig::default().validate().unwrap(); + } +} diff --git a/crates/configs/src/simulator.rs b/crates/configs/src/simulator.rs new file mode 100644 index 0000000000..78263ac8c0 --- /dev/null +++ b/crates/configs/src/simulator.rs @@ -0,0 +1,210 @@ +use { + crate::gas_price_estimation::{default_past_blocks, default_reward_percentile}, + alloy::primitives::Address, + serde::{Deserialize, Serialize}, + std::time::Duration, + url::Url, +}; + +#[derive(Debug, Default, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Config { + /// Maximum batch size for Ethereum RPC requests. Use '0' to disable + /// batching. + #[serde(default = "default_ethrpc_max_batch_size")] + pub ethrpc_max_batch_size: usize, + + /// Maximum number of concurrent requests to send to the node. Use '0' for + /// no limit on concurrency. + #[serde(default = "default_ethrpc_max_concurrent_requests")] + pub ethrpc_max_concurrent_requests: usize, + + /// Buffering "nagle" delay to wait for additional requests before sending + /// out an incomplete batch. + // #[clap(long, env, value_parser = humantime::parse_duration, default_value = "0s")] + #[serde(with = "humantime_serde", default = "default_ethrpc_batch_delay")] + pub ethrpc_batch_delay: Duration, + + /// Kind of simulator that should be used. Can be either of + /// - ethereum + /// - tenderly (using TenderlyConfig) + #[serde(default)] + pub kind: SimulatorKind, +} + +fn default_ethrpc_batch_delay() -> Duration { + Duration::from_secs(0) +} +fn default_ethrpc_max_batch_size() -> usize { + 100 +} +fn default_ethrpc_max_concurrent_requests() -> usize { + 10 +} + +#[derive(Debug, Default, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +pub enum SimulatorKind { + #[default] + Ethereum, + Tenderly(Box), +} + +/// Tenderly API arguments. +#[derive(Default, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct TenderlyConfig { + /// The Tenderly user associated with the API key. + #[serde(default)] + pub user: String, + + /// The Tenderly project associated with the API key. + #[serde(default)] + pub project: String, + + /// Tenderly requires api key to work. Optional since Tenderly could be + /// skipped in access lists estimators. + /// Supports reading from an environment variable with the `%ENV_VAR` + /// format. + #[serde( + default, + deserialize_with = "crate::deserialize_env::deserialize_string_from_env" + )] + pub api_key: String, + + /// The URL of the Tenderly API. + #[serde(default)] + pub url: Option, + + /// The URL of the Tenderly dashboard + #[serde(default)] + pub dashboard: Option, + + /// Save the transaction on Tenderly for later inspection, e.g. via the + /// dashboard. + #[serde(default)] + pub save: bool, + + /// Save the transaction even in the case of failure. + #[serde(default)] + pub save_if_fails: bool, +} + +impl std::fmt::Debug for TenderlyConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TenderlyConfig") + .field("user", &self.user) + .field("project", &self.project) + .field("api_key", &"") + .field("url", &self.url) + .field("dashboard", &self.dashboard) + .field("save", &self.save) + .field("save_if_fails", &self.save_if_fails) + .finish() + } +} + +#[cfg(any(test, feature = "test-util"))] +impl crate::test_util::TestDefault for TenderlyConfig { + fn test_default() -> Self { + Self { + ..Default::default() + } + } +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields, tag = "estimator")] +pub enum GasEstimatorType { + Web3, + /// EIP-1559 gas estimator using alloy's algorithm. + /// Optionally configure the fee history query parameters. + #[serde(rename_all = "kebab-case")] + Alloy { + /// Number of blocks to look back for fee history (default: 10) + #[serde(default = "default_past_blocks")] + past_blocks: u64, + /// Percentile of rewards to use for priority fee estimation (default: + /// 20.0). This is what Metamask uses as medium priority: + /// https://github.com/MetaMask/core/blob/0fd4b397e7237f104d1c81579a0c4321624d076b/packages/gas-fee-controller/src/fetchGasEstimatesViaEthFeeHistory/calculateGasFeeEstimatesForPriorityLevels.ts#L14-L45 + #[serde(default = "default_reward_percentile")] + reward_percentile: f64, + }, +} + +impl Default for GasEstimatorType { + fn default() -> Self { + Self::Alloy { + past_blocks: default_past_blocks(), + reward_percentile: default_reward_percentile(), + } + } +} + +#[derive(Debug, Default, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Addresses { + pub settlement: Option
, + pub weth: Option
, +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_empty_config() { + let config: Config = toml::from_str("").unwrap(); + assert!(matches!(config.kind, SimulatorKind::Ethereum)); + } + + #[test] + fn deserialize_simulator_kind() { + let toml = r#" + [kind] + type = "Tenderly" + user = "test-user" + project = "test-project" + api-key = "test-api-key" + "#; + let config: Config = toml::from_str(toml).unwrap(); + + match config.kind { + SimulatorKind::Tenderly(tenderly) => { + assert_eq!(tenderly.user, "test-user"); + assert_eq!(tenderly.project, "test-project"); + assert_eq!(tenderly.api_key, "test-api-key"); + } + _ => panic!("Config should be of type Tenderly"), + }; + let toml = r#" + [kind] + type = "Ethereum" + "#; + let config: Config = toml::from_str(toml).unwrap(); + assert!(matches!(config.kind, SimulatorKind::Ethereum)) + } + + #[derive(Deserialize)] + struct TestConfigContainingSimulator { + simulator: Config, + } + + #[test] + fn deserialize_full_config() { + let toml = r#" + [simulator.kind] + type = "Tenderly" + user = "test-user" + api-key = "test-api-key" + "#; + let config: TestConfigContainingSimulator = toml::from_str(toml).unwrap(); + + match config.simulator.kind { + SimulatorKind::Tenderly(tenderly) => { + assert_eq!(tenderly.user, "test-user"); + assert_eq!(tenderly.api_key, "test-api-key"); + } + _ => panic!("Config should be of type Tenderly"), + }; + } +} diff --git a/crates/contracts/Cargo.toml b/crates/contracts/Cargo.toml deleted file mode 100644 index dbd069dbe8..0000000000 --- a/crates/contracts/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "contracts" -version = "0.1.0" -authors = ["Gnosis Developers ", "Cow Protocol Developers "] -edition = "2024" -license = "MIT OR Apache-2.0" - -[lib] -doctest = false - -[[bin]] -name = "vendor" -required-features = ["bin"] - -[features] -default = [] -bin = [ - "ethcontract-generate", - "tracing", - "tracing-subscriber", -] - -[dependencies] -alloy = { workspace = true, features = ["sol-types", "json", "contract", "json-abi"] } -paste = { workspace = true } -ethcontract = { workspace = true } -serde_json = { workspace = true } - -# [bin-dependencies] -anyhow = { workspace = true } -ethcontract-generate = { workspace = true, optional = true, features = ["http"] } -tracing = { workspace = true, optional = true } -tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"], optional = true } - -[build-dependencies] -ethcontract = { workspace = true } -ethcontract-generate = { workspace = true } - -[lints] -workspace = true diff --git a/crates/contracts/LICENSE-APACHE b/crates/contracts/LICENSE-APACHE deleted file mode 120000 index 1cd601d0a3..0000000000 --- a/crates/contracts/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/contracts/LICENSE-MIT b/crates/contracts/LICENSE-MIT deleted file mode 120000 index b2cfbdc7b0..0000000000 --- a/crates/contracts/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE-MIT \ No newline at end of file diff --git a/crates/contracts/README.md b/crates/contracts/README.md deleted file mode 100644 index 719ddf139e..0000000000 --- a/crates/contracts/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# contracts - -The library part of this crate contains `ethcontract` generated bindings to the smart contracts we use. - -## `vendor` script - -A `[[bin]]` script for vendoring smart contract json artifacts that ethcontract uses to generate its bindings. We keep these in the repository to make the build more deterministic and robust. - -## Steps to add a new contract - -- In `vendor.rs` extend `ARTIFACTS` with the package and contract name. -- Run the vendor binary for example with `(cd crates/contracts; cargo run --bin vendor --features bin)`. This creates a new json file for this contract in the `artifacts` folder. -- In `build.rs` add a `generate_contract` call for the contract. This creates the ethcontract generated rust code file. -- In `lib.rs` add an `include!` call for the contract. This imports the rust code into the library. diff --git a/crates/contracts/artifacts/AnyoneAuthenticator.json b/crates/contracts/artifacts/AnyoneAuthenticator.json deleted file mode 100644 index 8d4b391d45..0000000000 --- a/crates/contracts/artifacts/AnyoneAuthenticator.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "isSolver", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b50609a8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806302cc250d14602d575b600080fd5b603e60383660046052565b50600190565b604051901515815260200160405180910390f35b600060208284031215606357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114608657600080fd5b939250505056fea164736f6c6343000811000a", - "deployedBytecode": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c806302cc250d14602d575b600080fd5b603e60383660046052565b50600190565b604051901515815260200160405180910390f35b600060208284031215606357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114608657600080fd5b939250505056fea164736f6c6343000811000a", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV3.json b/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV3.json deleted file mode 120000 index eb797bfd90..0000000000 --- a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV3.json +++ /dev/null @@ -1 +0,0 @@ -BalancerV2ComposableStablePoolFactory.json \ No newline at end of file diff --git a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV4.json b/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV4.json deleted file mode 120000 index eb797bfd90..0000000000 --- a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV4.json +++ /dev/null @@ -1 +0,0 @@ -BalancerV2ComposableStablePoolFactory.json \ No newline at end of file diff --git a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV5.json b/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV5.json deleted file mode 120000 index eb797bfd90..0000000000 --- a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV5.json +++ /dev/null @@ -1 +0,0 @@ -BalancerV2ComposableStablePoolFactory.json \ No newline at end of file diff --git a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV6.json b/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV6.json deleted file mode 120000 index eb797bfd90..0000000000 --- a/crates/contracts/artifacts/BalancerV2ComposableStablePoolFactoryV6.json +++ /dev/null @@ -1 +0,0 @@ -BalancerV2ComposableStablePoolFactory.json \ No newline at end of file diff --git a/crates/contracts/artifacts/BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory.json b/crates/contracts/artifacts/BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory.json deleted file mode 120000 index feca9d5f06..0000000000 --- a/crates/contracts/artifacts/BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory.json +++ /dev/null @@ -1 +0,0 @@ -BalancerV2LiquidityBootstrappingPoolFactory.json \ No newline at end of file diff --git a/crates/contracts/artifacts/BalancerV2WeightedPoolFactoryV4.json b/crates/contracts/artifacts/BalancerV2WeightedPoolFactoryV4.json deleted file mode 120000 index 744617e3de..0000000000 --- a/crates/contracts/artifacts/BalancerV2WeightedPoolFactoryV4.json +++ /dev/null @@ -1 +0,0 @@ -BalancerV2WeightedPoolFactoryV3.json \ No newline at end of file diff --git a/crates/contracts/artifacts/Balances.json b/crates/contracts/artifacts/Balances.json deleted file mode 100644 index c8056855c3..0000000000 --- a/crates/contracts/artifacts/Balances.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISettlement", - "name": "settlement", - "type": "address" - }, - { - "internalType": "contract IVaultRelayer", - "name": "vaultRelayer", - "type": "address" - }, - { - "internalType": "contract IVault", - "name": "vault", - "type": "address" - } - ], - "internalType": "struct Balances.Contracts", - "name": "contracts", - "type": "tuple" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "source", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ], - "internalType": "struct Interaction[]", - "name": "interactions", - "type": "tuple[]" - } - ], - "name": "balance", - "outputs": [ - { - "internalType": "uint256", - "name": "tokenBalance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "allowance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "effectiveBalance", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "canTransfer", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x6080604052348015600e575f5ffd5b506113a98061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063f88cf6db1461002d575b5f5ffd5b61004760048036038101906100429190610c1f565b610060565b6040516100579493929190610cf3565b60405180910390f35b5f5f5f5f61006f8b8787610702565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98703610195578873ffffffffffffffffffffffffffffffffffffffff166370a082318b6040518263ffffffff1660e01b81526004016100cf9190610d45565b602060405180830381865afa1580156100ea573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061010e9190610d72565b93508873ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8b8d602001516040518363ffffffff1660e01b815260040161014f929190610d9d565b602060405180830381865afa15801561016a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061018e9190610d72565b925061059a565b7fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328703610348578873ffffffffffffffffffffffffffffffffffffffff166370a082318b6040518263ffffffff1660e01b81526004016101f59190610d45565b602060405180830381865afa158015610210573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102349190610d72565b93508a6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728b8d602001516040518363ffffffff1660e01b8152600401610279929190610d9d565b602060405180830381865afa158015610294573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b89190610dee565b6102c2575f610341565b8873ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8b8d604001516040518363ffffffff1660e01b8152600401610301929190610d9d565b602060405180830381865afa15801561031c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103409190610d72565b5b9250610599565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce870361055d575f600167ffffffffffffffff81111561038b5761038a610939565b5b6040519080825280602002602001820160405280156103b95781602001602082028036833780820191505090505b50905089815f815181106103d0576103cf610e19565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508b6040015173ffffffffffffffffffffffffffffffffffffffff16630f5a6efa8c836040518363ffffffff1660e01b8152600401610449929190610efd565b5f60405180830381865afa158015610463573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061048b9190610feb565b5f8151811061049d5761049c610e19565b5b602002602001015194508b6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728c8e602001516040518363ffffffff1660e01b81526004016104ea929190610d9d565b602060405180830381865afa158015610505573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105299190610dee565b610533575f610555565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b935050610598565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058f9061108c565b60405180910390fd5b5b5b828411156105a857826105aa565b835b91505f600167ffffffffffffffff8111156105c8576105c7610939565b5b60405190808252806020026020018201604052801561060157816020015b6105ee6108c4565b8152602001906001900390816105e65790505b50905060405180608001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020015f8b036106545784610656565b8a5b815260200189815250815f8151811061067257610671610e19565b5b60200260200101819052508b6020015173ffffffffffffffffffffffffffffffffffffffff16637d10d11f826040518263ffffffff1660e01b81526004016106ba91906111c3565b5f604051808303815f87803b1580156106d1575f5ffd5b505af19250505080156106e2575060015b6106ee575f91506106f3565b600191505b50975097509750979350505050565b825f015173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614610773576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161076a9061122d565b60405180910390fd5b5f5b828290508110156108be575f83838381811061079457610793610e19565b5b90506020028101906107a69190611257565b5f0160208101906107b7919061127e565b90505f8484848181106107cd576107cc610e19565b5b90506020028101906107df9190611257565b602001359050365f8686868181106107fa576107f9610e19565b5b905060200281019061080c9190611257565b806040019061081b91906112a9565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610891576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088890611355565b60405180910390fd5b604051818382375f5f838387895af16108ac573d5f5f3e3d5ffd5b50505050508080600101915050610775565b50505050565b60405180608001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020015f81525090565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61096f82610929565b810181811067ffffffffffffffff8211171561098e5761098d610939565b5b80604052505050565b5f6109a0610914565b90506109ac8282610966565b919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6109da826109b1565b9050919050565b5f6109eb826109d0565b9050919050565b6109fb816109e1565b8114610a05575f5ffd5b50565b5f81359050610a16816109f2565b92915050565b5f610a26826109d0565b9050919050565b610a3681610a1c565b8114610a40575f5ffd5b50565b5f81359050610a5181610a2d565b92915050565b5f610a61826109d0565b9050919050565b610a7181610a57565b8114610a7b575f5ffd5b50565b5f81359050610a8c81610a68565b92915050565b5f60608284031215610aa757610aa6610925565b5b610ab16060610997565b90505f610ac084828501610a08565b5f830152506020610ad384828501610a43565b6020830152506040610ae784828501610a7e565b60408301525092915050565b610afc816109d0565b8114610b06575f5ffd5b50565b5f81359050610b1781610af3565b92915050565b5f610b27826109d0565b9050919050565b610b3781610b1d565b8114610b41575f5ffd5b50565b5f81359050610b5281610b2e565b92915050565b5f819050919050565b610b6a81610b58565b8114610b74575f5ffd5b50565b5f81359050610b8581610b61565b92915050565b5f819050919050565b610b9d81610b8b565b8114610ba7575f5ffd5b50565b5f81359050610bb881610b94565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610bdf57610bde610bbe565b5b8235905067ffffffffffffffff811115610bfc57610bfb610bc2565b5b602083019150836020820283011115610c1857610c17610bc6565b5b9250929050565b5f5f5f5f5f5f5f610100888a031215610c3b57610c3a61091d565b5b5f610c488a828b01610a92565b9750506060610c598a828b01610b09565b9650506080610c6a8a828b01610b44565b95505060a0610c7b8a828b01610b77565b94505060c0610c8c8a828b01610baa565b93505060e088013567ffffffffffffffff811115610cad57610cac610921565b5b610cb98a828b01610bca565b925092505092959891949750929550565b610cd381610b58565b82525050565b5f8115159050919050565b610ced81610cd9565b82525050565b5f608082019050610d065f830187610cca565b610d136020830186610cca565b610d206040830185610cca565b610d2d6060830184610ce4565b95945050505050565b610d3f816109d0565b82525050565b5f602082019050610d585f830184610d36565b92915050565b5f81519050610d6c81610b61565b92915050565b5f60208284031215610d8757610d8661091d565b5b5f610d9484828501610d5e565b91505092915050565b5f604082019050610db05f830185610d36565b610dbd6020830184610d36565b9392505050565b610dcd81610cd9565b8114610dd7575f5ffd5b50565b5f81519050610de881610dc4565b92915050565b5f60208284031215610e0357610e0261091d565b5b5f610e1084828501610dda565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b610e78816109d0565b82525050565b5f610e898383610e6f565b60208301905092915050565b5f602082019050919050565b5f610eab82610e46565b610eb58185610e50565b9350610ec083610e60565b805f5b83811015610ef0578151610ed78882610e7e565b9750610ee283610e95565b925050600181019050610ec3565b5085935050505092915050565b5f604082019050610f105f830185610d36565b8181036020830152610f228184610ea1565b90509392505050565b5f67ffffffffffffffff821115610f4557610f44610939565b5b602082029050602081019050919050565b5f610f68610f6384610f2b565b610997565b90508083825260208201905060208402830185811115610f8b57610f8a610bc6565b5b835b81811015610fb45780610fa08882610d5e565b845260208401935050602081019050610f8d565b5050509392505050565b5f82601f830112610fd257610fd1610bbe565b5b8151610fe2848260208601610f56565b91505092915050565b5f6020828403121561100057610fff61091d565b5b5f82015167ffffffffffffffff81111561101d5761101c610921565b5b61102984828501610fbe565b91505092915050565b5f82825260208201905092915050565b7f696e76616c696420746f6b656e20736f757263650000000000000000000000005f82015250565b5f611076601483611032565b915061108182611042565b602082019050919050565b5f6020820190508181035f8301526110a38161106a565b9050919050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6110dc81610b58565b82525050565b6110eb81610b8b565b82525050565b608082015f8201516111055f850182610e6f565b5060208201516111186020850182610e6f565b50604082015161112b60408501826110d3565b50606082015161113e60608501826110e2565b50505050565b5f61114f83836110f1565b60808301905092915050565b5f602082019050919050565b5f611171826110aa565b61117b81856110b4565b9350611186836110c4565b805f5b838110156111b657815161119d8882611144565b97506111a88361115b565b925050600181019050611189565b5085935050505092915050565b5f6020820190508181035f8301526111db8184611167565b905092915050565b7f696e636f72726563742063616c6c696e6720636f6e74657874000000000000005f82015250565b5f611217601983611032565b9150611222826111e3565b602082019050919050565b5f6020820190508181035f8301526112448161120b565b9050919050565b5f5ffd5b5f5ffd5b5f5ffd5b5f823560016060038336030381126112725761127161124b565b5b80830191505092915050565b5f602082840312156112935761129261091d565b5b5f6112a084828501610b09565b91505092915050565b5f5f833560016020038436030381126112c5576112c461124b565b5b80840192508235915067ffffffffffffffff8211156112e7576112e661124f565b5b60208301925060018202360383131561130357611302611253565b5b509250929050565b7f475076323a20666f7262696464656e20696e746572616374696f6e00000000005f82015250565b5f61133f601b83611032565b915061134a8261130b565b602082019050919050565b5f6020820190508181035f83015261136c81611333565b905091905056fea26469706673582212201c998e2688bc874aadf8ba625ee663c3f7d65374650800b24013b6d211210fbc64736f6c634300081e0033", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063f88cf6db1461002d575b5f5ffd5b61004760048036038101906100429190610c1f565b610060565b6040516100579493929190610cf3565b60405180910390f35b5f5f5f5f61006f8b8787610702565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc98703610195578873ffffffffffffffffffffffffffffffffffffffff166370a082318b6040518263ffffffff1660e01b81526004016100cf9190610d45565b602060405180830381865afa1580156100ea573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061010e9190610d72565b93508873ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8b8d602001516040518363ffffffff1660e01b815260040161014f929190610d9d565b602060405180830381865afa15801561016a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061018e9190610d72565b925061059a565b7fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328703610348578873ffffffffffffffffffffffffffffffffffffffff166370a082318b6040518263ffffffff1660e01b81526004016101f59190610d45565b602060405180830381865afa158015610210573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102349190610d72565b93508a6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728b8d602001516040518363ffffffff1660e01b8152600401610279929190610d9d565b602060405180830381865afa158015610294573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b89190610dee565b6102c2575f610341565b8873ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8b8d604001516040518363ffffffff1660e01b8152600401610301929190610d9d565b602060405180830381865afa15801561031c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103409190610d72565b5b9250610599565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce870361055d575f600167ffffffffffffffff81111561038b5761038a610939565b5b6040519080825280602002602001820160405280156103b95781602001602082028036833780820191505090505b50905089815f815181106103d0576103cf610e19565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508b6040015173ffffffffffffffffffffffffffffffffffffffff16630f5a6efa8c836040518363ffffffff1660e01b8152600401610449929190610efd565b5f60405180830381865afa158015610463573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061048b9190610feb565b5f8151811061049d5761049c610e19565b5b602002602001015194508b6040015173ffffffffffffffffffffffffffffffffffffffff1663fec90d728c8e602001516040518363ffffffff1660e01b81526004016104ea929190610d9d565b602060405180830381865afa158015610505573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105299190610dee565b610533575f610555565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b935050610598565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058f9061108c565b60405180910390fd5b5b5b828411156105a857826105aa565b835b91505f600167ffffffffffffffff8111156105c8576105c7610939565b5b60405190808252806020026020018201604052801561060157816020015b6105ee6108c4565b8152602001906001900390816105e65790505b50905060405180608001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020015f8b036106545784610656565b8a5b815260200189815250815f8151811061067257610671610e19565b5b60200260200101819052508b6020015173ffffffffffffffffffffffffffffffffffffffff16637d10d11f826040518263ffffffff1660e01b81526004016106ba91906111c3565b5f604051808303815f87803b1580156106d1575f5ffd5b505af19250505080156106e2575060015b6106ee575f91506106f3565b600191505b50975097509750979350505050565b825f015173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614610773576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161076a9061122d565b60405180910390fd5b5f5b828290508110156108be575f83838381811061079457610793610e19565b5b90506020028101906107a69190611257565b5f0160208101906107b7919061127e565b90505f8484848181106107cd576107cc610e19565b5b90506020028101906107df9190611257565b602001359050365f8686868181106107fa576107f9610e19565b5b905060200281019061080c9190611257565b806040019061081b91906112a9565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610891576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088890611355565b60405180910390fd5b604051818382375f5f838387895af16108ac573d5f5f3e3d5ffd5b50505050508080600101915050610775565b50505050565b60405180608001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81526020015f81525090565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61096f82610929565b810181811067ffffffffffffffff8211171561098e5761098d610939565b5b80604052505050565b5f6109a0610914565b90506109ac8282610966565b919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6109da826109b1565b9050919050565b5f6109eb826109d0565b9050919050565b6109fb816109e1565b8114610a05575f5ffd5b50565b5f81359050610a16816109f2565b92915050565b5f610a26826109d0565b9050919050565b610a3681610a1c565b8114610a40575f5ffd5b50565b5f81359050610a5181610a2d565b92915050565b5f610a61826109d0565b9050919050565b610a7181610a57565b8114610a7b575f5ffd5b50565b5f81359050610a8c81610a68565b92915050565b5f60608284031215610aa757610aa6610925565b5b610ab16060610997565b90505f610ac084828501610a08565b5f830152506020610ad384828501610a43565b6020830152506040610ae784828501610a7e565b60408301525092915050565b610afc816109d0565b8114610b06575f5ffd5b50565b5f81359050610b1781610af3565b92915050565b5f610b27826109d0565b9050919050565b610b3781610b1d565b8114610b41575f5ffd5b50565b5f81359050610b5281610b2e565b92915050565b5f819050919050565b610b6a81610b58565b8114610b74575f5ffd5b50565b5f81359050610b8581610b61565b92915050565b5f819050919050565b610b9d81610b8b565b8114610ba7575f5ffd5b50565b5f81359050610bb881610b94565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610bdf57610bde610bbe565b5b8235905067ffffffffffffffff811115610bfc57610bfb610bc2565b5b602083019150836020820283011115610c1857610c17610bc6565b5b9250929050565b5f5f5f5f5f5f5f610100888a031215610c3b57610c3a61091d565b5b5f610c488a828b01610a92565b9750506060610c598a828b01610b09565b9650506080610c6a8a828b01610b44565b95505060a0610c7b8a828b01610b77565b94505060c0610c8c8a828b01610baa565b93505060e088013567ffffffffffffffff811115610cad57610cac610921565b5b610cb98a828b01610bca565b925092505092959891949750929550565b610cd381610b58565b82525050565b5f8115159050919050565b610ced81610cd9565b82525050565b5f608082019050610d065f830187610cca565b610d136020830186610cca565b610d206040830185610cca565b610d2d6060830184610ce4565b95945050505050565b610d3f816109d0565b82525050565b5f602082019050610d585f830184610d36565b92915050565b5f81519050610d6c81610b61565b92915050565b5f60208284031215610d8757610d8661091d565b5b5f610d9484828501610d5e565b91505092915050565b5f604082019050610db05f830185610d36565b610dbd6020830184610d36565b9392505050565b610dcd81610cd9565b8114610dd7575f5ffd5b50565b5f81519050610de881610dc4565b92915050565b5f60208284031215610e0357610e0261091d565b5b5f610e1084828501610dda565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b610e78816109d0565b82525050565b5f610e898383610e6f565b60208301905092915050565b5f602082019050919050565b5f610eab82610e46565b610eb58185610e50565b9350610ec083610e60565b805f5b83811015610ef0578151610ed78882610e7e565b9750610ee283610e95565b925050600181019050610ec3565b5085935050505092915050565b5f604082019050610f105f830185610d36565b8181036020830152610f228184610ea1565b90509392505050565b5f67ffffffffffffffff821115610f4557610f44610939565b5b602082029050602081019050919050565b5f610f68610f6384610f2b565b610997565b90508083825260208201905060208402830185811115610f8b57610f8a610bc6565b5b835b81811015610fb45780610fa08882610d5e565b845260208401935050602081019050610f8d565b5050509392505050565b5f82601f830112610fd257610fd1610bbe565b5b8151610fe2848260208601610f56565b91505092915050565b5f6020828403121561100057610fff61091d565b5b5f82015167ffffffffffffffff81111561101d5761101c610921565b5b61102984828501610fbe565b91505092915050565b5f82825260208201905092915050565b7f696e76616c696420746f6b656e20736f757263650000000000000000000000005f82015250565b5f611076601483611032565b915061108182611042565b602082019050919050565b5f6020820190508181035f8301526110a38161106a565b9050919050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6110dc81610b58565b82525050565b6110eb81610b8b565b82525050565b608082015f8201516111055f850182610e6f565b5060208201516111186020850182610e6f565b50604082015161112b60408501826110d3565b50606082015161113e60608501826110e2565b50505050565b5f61114f83836110f1565b60808301905092915050565b5f602082019050919050565b5f611171826110aa565b61117b81856110b4565b9350611186836110c4565b805f5b838110156111b657815161119d8882611144565b97506111a88361115b565b925050600181019050611189565b5085935050505092915050565b5f6020820190508181035f8301526111db8184611167565b905092915050565b7f696e636f72726563742063616c6c696e6720636f6e74657874000000000000005f82015250565b5f611217601983611032565b9150611222826111e3565b602082019050919050565b5f6020820190508181035f8301526112448161120b565b9050919050565b5f5ffd5b5f5ffd5b5f5ffd5b5f823560016060038336030381126112725761127161124b565b5b80830191505092915050565b5f602082840312156112935761129261091d565b5b5f6112a084828501610b09565b91505092915050565b5f5f833560016020038436030381126112c5576112c461124b565b5b80840192508235915067ffffffffffffffff8211156112e7576112e661124f565b5b60208301925060018202360383131561130357611302611253565b5b509250929050565b7f475076323a20666f7262696464656e20696e746572616374696f6e00000000005f82015250565b5f61133f601b83611032565b915061134a8261130b565b602082019050919050565b5f6020820190508181035f83015261136c81611333565b905091905056fea26469706673582212201c998e2688bc874aadf8ba625ee663c3f7d65374650800b24013b6d211210fbc64736f6c634300081e0033" -} diff --git a/crates/contracts/artifacts/BaoswapRouter.json b/crates/contracts/artifacts/BaoswapRouter.json deleted file mode 120000 index e485e1a596..0000000000 --- a/crates/contracts/artifacts/BaoswapRouter.json +++ /dev/null @@ -1 +0,0 @@ -IUniswapLikeRouter.json \ No newline at end of file diff --git a/crates/contracts/artifacts/Counter.json b/crates/contracts/artifacts/Counter.json deleted file mode 100644 index 2ed98a28f8..0000000000 --- a/crates/contracts/artifacts/Counter.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "name": "counters", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "key", - "type": "string" - } - ], - "name": "incrementCounter", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "key", - "type": "string" - }, - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "setCounterToBalance", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x6080604052348015600e575f5ffd5b506105b28061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80630931831e1461004357806357cedf401461005f5780639424c8c81461008f575b5f5ffd5b61005d60048036038101906100589190610353565b6100ab565b005b610079600480360381019061007491906103bf565b610149565b604051610086919061041e565b60405180910390f35b6100a960048036038101906100a491906103bf565b610175565b005b8173ffffffffffffffffffffffffffffffffffffffff166370a08231826040518263ffffffff1660e01b81526004016100e49190610446565b602060405180830381865afa1580156100ff573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101239190610489565b5f846040516101329190610506565b908152602001604051809103902081905550505050565b5f818051602081018201805184825260208301602085012081835280955050505050505f915090505481565b60015f826040516101869190610506565b90815260200160405180910390205f8282546101a29190610549565b9250508190555050565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61020b826101c5565b810181811067ffffffffffffffff8211171561022a576102296101d5565b5b80604052505050565b5f61023c6101ac565b90506102488282610202565b919050565b5f67ffffffffffffffff821115610267576102666101d5565b5b610270826101c5565b9050602081019050919050565b828183375f83830152505050565b5f61029d6102988461024d565b610233565b9050828152602081018484840111156102b9576102b86101c1565b5b6102c484828561027d565b509392505050565b5f82601f8301126102e0576102df6101bd565b5b81356102f084826020860161028b565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610322826102f9565b9050919050565b61033281610318565b811461033c575f5ffd5b50565b5f8135905061034d81610329565b92915050565b5f5f5f6060848603121561036a576103696101b5565b5b5f84013567ffffffffffffffff811115610387576103866101b9565b5b610393868287016102cc565b93505060206103a48682870161033f565b92505060406103b58682870161033f565b9150509250925092565b5f602082840312156103d4576103d36101b5565b5b5f82013567ffffffffffffffff8111156103f1576103f06101b9565b5b6103fd848285016102cc565b91505092915050565b5f819050919050565b61041881610406565b82525050565b5f6020820190506104315f83018461040f565b92915050565b61044081610318565b82525050565b5f6020820190506104595f830184610437565b92915050565b61046881610406565b8114610472575f5ffd5b50565b5f815190506104838161045f565b92915050565b5f6020828403121561049e5761049d6101b5565b5b5f6104ab84828501610475565b91505092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6104e0826104b4565b6104ea81856104be565b93506104fa8185602086016104c8565b80840191505092915050565b5f61051182846104d6565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61055382610406565b915061055e83610406565b92508282019050808211156105765761057561051c565b5b9291505056fea2646970667358221220b3c7d0a5e5f5cd95f33dc4460b7fa401be388a78b39fe8050b0c00217bad3a8264736f6c634300081e0033", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80630931831e1461004357806357cedf401461005f5780639424c8c81461008f575b5f5ffd5b61005d60048036038101906100589190610353565b6100ab565b005b610079600480360381019061007491906103bf565b610149565b604051610086919061041e565b60405180910390f35b6100a960048036038101906100a491906103bf565b610175565b005b8173ffffffffffffffffffffffffffffffffffffffff166370a08231826040518263ffffffff1660e01b81526004016100e49190610446565b602060405180830381865afa1580156100ff573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101239190610489565b5f846040516101329190610506565b908152602001604051809103902081905550505050565b5f818051602081018201805184825260208301602085012081835280955050505050505f915090505481565b60015f826040516101869190610506565b90815260200160405180910390205f8282546101a29190610549565b9250508190555050565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61020b826101c5565b810181811067ffffffffffffffff8211171561022a576102296101d5565b5b80604052505050565b5f61023c6101ac565b90506102488282610202565b919050565b5f67ffffffffffffffff821115610267576102666101d5565b5b610270826101c5565b9050602081019050919050565b828183375f83830152505050565b5f61029d6102988461024d565b610233565b9050828152602081018484840111156102b9576102b86101c1565b5b6102c484828561027d565b509392505050565b5f82601f8301126102e0576102df6101bd565b5b81356102f084826020860161028b565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610322826102f9565b9050919050565b61033281610318565b811461033c575f5ffd5b50565b5f8135905061034d81610329565b92915050565b5f5f5f6060848603121561036a576103696101b5565b5b5f84013567ffffffffffffffff811115610387576103866101b9565b5b610393868287016102cc565b93505060206103a48682870161033f565b92505060406103b58682870161033f565b9150509250925092565b5f602082840312156103d4576103d36101b5565b5b5f82013567ffffffffffffffff8111156103f1576103f06101b9565b5b6103fd848285016102cc565b91505092915050565b5f819050919050565b61041881610406565b82525050565b5f6020820190506104315f83018461040f565b92915050565b61044081610318565b82525050565b5f6020820190506104595f830184610437565b92915050565b61046881610406565b8114610472575f5ffd5b50565b5f815190506104838161045f565b92915050565b5f6020828403121561049e5761049d6101b5565b5b5f6104ab84828501610475565b91505092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6104e0826104b4565b6104ea81856104be565b93506104fa8185602086016104c8565b80840191505092915050565b5f61051182846104d6565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61055382610406565b915061055e83610406565b92508282019050808211156105765761057561051c565b5b9291505056fea2646970667358221220b3c7d0a5e5f5cd95f33dc4460b7fa401be388a78b39fe8050b0c00217bad3a8264736f6c634300081e0033", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/artifacts/GasHog.json b/crates/contracts/artifacts/GasHog.json deleted file mode 100644 index ce586fb433..0000000000 --- a/crates/contracts/artifacts/GasHog.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "contract ERC20", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "order", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "isValidSignature", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b50610318806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80631626ba7e1461003b578063e1f21c6714610083575b600080fd5b61004e6100493660046101d0565b610098565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b610096610091366004610271565b610143565b005b6000805a905060006100ac848601866102b2565b90507fce7d7369855be79904099402d83db6d6ab8840dcd5c086e062cd1ca0c8111dfc5b815a6100dc90856102cb565b101561010b576040805160208101839052016040516020818303038152906040528051906020012090506100d0565b86810361011757600080fd5b507f1626ba7e000000000000000000000000000000000000000000000000000000009695505050505050565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063095ea7b390604401600060405180830381600087803b1580156101b357600080fd5b505af11580156101c7573d6000803e3d6000fd5b50505050505050565b6000806000604084860312156101e557600080fd5b83359250602084013567ffffffffffffffff8082111561020457600080fd5b818601915086601f83011261021857600080fd5b81358181111561022757600080fd5b87602082850101111561023957600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8116811461026e57600080fd5b50565b60008060006060848603121561028657600080fd5b83356102918161024c565b925060208401356102a18161024c565b929592945050506040919091013590565b6000602082840312156102c457600080fd5b5035919050565b81810381811115610305577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000811000a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80631626ba7e1461003b578063e1f21c6714610083575b600080fd5b61004e6100493660046101d0565b610098565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b610096610091366004610271565b610143565b005b6000805a905060006100ac848601866102b2565b90507fce7d7369855be79904099402d83db6d6ab8840dcd5c086e062cd1ca0c8111dfc5b815a6100dc90856102cb565b101561010b576040805160208101839052016040516020818303038152906040528051906020012090506100d0565b86810361011757600080fd5b507f1626ba7e000000000000000000000000000000000000000000000000000000009695505050505050565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063095ea7b390604401600060405180830381600087803b1580156101b357600080fd5b505af11580156101c7573d6000803e3d6000fd5b50505050505050565b6000806000604084860312156101e557600080fd5b83359250602084013567ffffffffffffffff8082111561020457600080fd5b818601915086601f83011261021857600080fd5b81358181111561022757600080fd5b87602082850101111561023957600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8116811461026e57600080fd5b50565b60008060006060848603121561028657600080fd5b83356102918161024c565b925060208401356102a18161024c565b929592945050506040919091013590565b6000602082840312156102c457600080fd5b5035919050565b81810381811115610305577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000811000a", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/artifacts/HoneyswapRouter.json b/crates/contracts/artifacts/HoneyswapRouter.json deleted file mode 120000 index e485e1a596..0000000000 --- a/crates/contracts/artifacts/HoneyswapRouter.json +++ /dev/null @@ -1 +0,0 @@ -IUniswapLikeRouter.json \ No newline at end of file diff --git a/crates/contracts/artifacts/LiquoriceSettlement.json b/crates/contracts/artifacts/LiquoriceSettlement.json deleted file mode 100644 index f34c403bdf..0000000000 --- a/crates/contracts/artifacts/LiquoriceSettlement.json +++ /dev/null @@ -1,4191 +0,0 @@ -{ - "abi": [ - { - "type": "constructor", - "inputs": [ - { - "name": "authenticator_", - "type": "address", - "internalType": "contract IAllowListAuthentication" - }, - { - "name": "repository_", - "type": "address", - "internalType": "contract IRepository" - }, - { - "name": "permit2_", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "receive", - "stateMutability": "payable" - }, - { - "type": "function", - "name": "AUTHENTICATOR", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract IAllowListAuthentication" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "BALANCE_MANAGER", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract IBalanceManager" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "DOMAIN_SEPARATOR", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "REPOSITORY", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "contract IRepository" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "cancelLimitOrder", - "inputs": [ - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "hashBaseTokenData", - "inputs": [ - { - "name": "_baseTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRecipient", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRepay", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toSupply", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "hashOrder", - "inputs": [ - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Order", - "components": [ - { - "name": "market", - "type": "address", - "internalType": "address" - }, - { - "name": "chainId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "baseTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRecipient", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRepay", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toSupply", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "quoteTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toTrader", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toWithdraw", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toBorrow", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ] - } - ], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "hashQuoteTokenData", - "inputs": [ - { - "name": "_quoteTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toTrader", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toWithdraw", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toBorrow", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "hashSingleOrder", - "inputs": [ - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Single", - "components": [ - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "baseToken", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteToken", - "type": "address", - "internalType": "address" - }, - { - "name": "baseTokenAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "quoteTokenAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - } - ] - } - ], - "outputs": [ - { - "name": "", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "isValidSignature", - "inputs": [ - { - "name": "_hash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "_signature", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [ - { - "name": "", - "type": "bytes4", - "internalType": "bytes4" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "settle", - "inputs": [ - { - "name": "_signer", - "type": "address", - "internalType": "address" - }, - { - "name": "_filledTakerAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Order", - "components": [ - { - "name": "market", - "type": "address", - "internalType": "address" - }, - { - "name": "chainId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "baseTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRecipient", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRepay", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toSupply", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "quoteTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toTrader", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toWithdraw", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toBorrow", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ] - }, - { - "name": "_interactions", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_hooks", - "type": "tuple", - "internalType": "struct GPv2Interaction.Hooks", - "components": [ - { - "name": "beforeSettle", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "afterSettle", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "_makerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_takerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "settleSingle", - "inputs": [ - { - "name": "_signer", - "type": "address", - "internalType": "address" - }, - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Single", - "components": [ - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "baseToken", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteToken", - "type": "address", - "internalType": "address" - }, - { - "name": "baseTokenAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "quoteTokenAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - } - ] - }, - { - "name": "_makerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_filledTakerAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "_takerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "settleSingleWithPermitsSignatures", - "inputs": [ - { - "name": "_signer", - "type": "address", - "internalType": "address" - }, - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Single", - "components": [ - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "baseToken", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteToken", - "type": "address", - "internalType": "address" - }, - { - "name": "baseTokenAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "quoteTokenAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - } - ] - }, - { - "name": "_makerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_filledTakerAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "_takerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_takerPermitInfo", - "type": "tuple", - "internalType": "struct Signature.TakerPermitInfo", - "components": [ - { - "name": "signature", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "nonce", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "deadline", - "type": "uint48", - "internalType": "uint48" - } - ] - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "settleWithPermitsSignatures", - "inputs": [ - { - "name": "_signer", - "type": "address", - "internalType": "address" - }, - { - "name": "_filledTakerAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Order", - "components": [ - { - "name": "market", - "type": "address", - "internalType": "address" - }, - { - "name": "chainId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "baseTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRecipient", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRepay", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toSupply", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "quoteTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toTrader", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toWithdraw", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toBorrow", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ] - }, - { - "name": "_interactions", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_hooks", - "type": "tuple", - "internalType": "struct GPv2Interaction.Hooks", - "components": [ - { - "name": "beforeSettle", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "afterSettle", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - }, - { - "name": "_makerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_takerSignature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "_takerPermitInfo", - "type": "tuple", - "internalType": "struct Signature.TakerPermitInfo", - "components": [ - { - "name": "signature", - "type": "bytes", - "internalType": "bytes" - }, - { - "name": "nonce", - "type": "uint48", - "internalType": "uint48" - }, - { - "name": "deadline", - "type": "uint48", - "internalType": "uint48" - } - ] - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "function", - "name": "validateHooks", - "inputs": [ - { - "name": "_repository", - "type": "address", - "internalType": "contract IRepository" - }, - { - "name": "_hooks", - "type": "tuple", - "internalType": "struct GPv2Interaction.Hooks", - "components": [ - { - "name": "beforeSettle", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - }, - { - "name": "afterSettle", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ] - } - ], - "outputs": [], - "stateMutability": "view" - }, - { - "type": "function", - "name": "validateInteractions", - "inputs": [ - { - "name": "_repository", - "type": "address", - "internalType": "contract IRepository" - }, - { - "name": "_signer", - "type": "address", - "internalType": "address" - }, - { - "name": "_isPartialFill", - "type": "bool", - "internalType": "bool" - }, - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Order", - "components": [ - { - "name": "market", - "type": "address", - "internalType": "address" - }, - { - "name": "chainId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "baseTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRecipient", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRepay", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toSupply", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "quoteTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toTrader", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toWithdraw", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toBorrow", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ] - }, - { - "name": "_interactions", - "type": "tuple[]", - "internalType": "struct GPv2Interaction.Data[]", - "components": [ - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "callData", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "outputs": [], - "stateMutability": "view" - }, - { - "type": "function", - "name": "validateOrderAmounts", - "inputs": [ - { - "name": "_order", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.Order", - "components": [ - { - "name": "market", - "type": "address", - "internalType": "address" - }, - { - "name": "chainId", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "rfqId", - "type": "string", - "internalType": "string" - }, - { - "name": "nonce", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "trader", - "type": "address", - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "internalType": "address" - }, - { - "name": "quoteExpiry", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "minFillAmount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "baseTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRecipient", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toRepay", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toSupply", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "name": "quoteTokenData", - "type": "tuple", - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "components": [ - { - "name": "addr", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toTrader", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toWithdraw", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "toBorrow", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ] - } - ], - "outputs": [], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "validateSignature", - "inputs": [ - { - "name": "_validationAddress", - "type": "address", - "internalType": "address" - }, - { - "name": "_hash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "_signature", - "type": "tuple", - "internalType": "struct Signature.TypedSignature", - "components": [ - { - "name": "signatureType", - "type": "uint8", - "internalType": "enum Signature.Type" - }, - { - "name": "transferCommand", - "type": "uint8", - "internalType": "enum Signature.TransferCommand" - }, - { - "name": "signatureBytes", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "outputs": [], - "stateMutability": "view" - }, - { - "type": "event", - "name": "Interaction", - "inputs": [ - { - "name": "target", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "selector", - "type": "bytes4", - "indexed": false, - "internalType": "bytes4" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "TradeOrder", - "inputs": [ - { - "name": "rfqId", - "type": "string", - "indexed": true, - "internalType": "string" - }, - { - "name": "trader", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "effectiveTrader", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "baseToken", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "quoteToken", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "baseTokenAmount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "quoteTokenAmount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "recipient", - "type": "address", - "indexed": false, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "ECDSAInvalidSignature", - "inputs": [] - }, - { - "type": "error", - "name": "ECDSAInvalidSignatureLength", - "inputs": [ - { - "name": "length", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ECDSAInvalidSignatureS", - "inputs": [ - { - "name": "s", - "type": "bytes32", - "internalType": "bytes32" - } - ] - }, - { - "type": "error", - "name": "InvalidAmount", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidAsset", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidBaseTokenAmounts", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidDestination", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidEIP1271Signature", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidEIP712Signature", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidETHSignSignature", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidFillAmount", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidHooksTarget", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidInteractionsBaseTokenAmounts", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidInteractionsQuoteTokenAmounts", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidLendingPoolInteraction", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidQuoteTokenAmounts", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidSignatureType", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidSigner", - "inputs": [] - }, - { - "type": "error", - "name": "InvalidSource", - "inputs": [] - }, - { - "type": "error", - "name": "NonceInvalid", - "inputs": [] - }, - { - "type": "error", - "name": "NotMaker", - "inputs": [] - }, - { - "type": "error", - "name": "NotSolver", - "inputs": [] - }, - { - "type": "error", - "name": "OrderExpired", - "inputs": [] - }, - { - "type": "error", - "name": "PartialFillNotSupported", - "inputs": [] - }, - { - "type": "error", - "name": "ReceiverNotManager", - "inputs": [] - }, - { - "type": "error", - "name": "ReentrancyGuardReentrantCall", - "inputs": [] - }, - { - "type": "error", - "name": "SafeERC20FailedOperation", - "inputs": [ - { - "name": "token", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "SignatureIsExpired", - "inputs": [] - }, - { - "type": "error", - "name": "SignatureIsNotEmpty", - "inputs": [] - }, - { - "type": "error", - "name": "UpdatedMakerAmountsTooLow", - "inputs": [] - }, - { - "type": "error", - "name": "ZeroMakerAmount", - "inputs": [] - } - ], - "bytecode": { - "object": "0x61012060405234801562000011575f80fd5b5060405162004ef638038062004ef6833981016040819052620000349162000175565b4660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201526080810192909252309082015260c00160408051601f19818403018152908290528051602090910120608052600180556001600160a01b03841660c05230908290620000fe906200014f565b6001600160a01b03928316815291166020820152604001604051809103905ff0801580156200012f573d5f803e3d5ffd5b506001600160a01b0390811660e052919091166101005250620001c69050565b610963806200459383390190565b6001600160a01b038116811462000172575f80fd5b50565b5f805f6060848603121562000188575f80fd5b835162000195816200015d565b6020850151909350620001a8816200015d565b6040850151909250620001bb816200015d565b809150509250925092565b60805160a05160c05160e0516101005161432d620002665f395f81816102570152818161078401526116dc01525f8181610197015281816107ba0152818161188c01528181611e2c01528181611f1e0152818161202c0152818161230b01528181612427015261303c01525f818161033801528181610412015281816106a70152818161152001526115ff01525f6104da01525f6105a4015261432d5ff3fe608060405260043610610126575f3560e01c8063a5cdc8fc116100a1578063c618618111610071578063db58772811610057578063db58772814610379578063e242924e1461038c578063fa5cd56c146103ab575f80fd5b8063c618618114610327578063cba673a71461035a575f80fd5b8063a5cdc8fc146102ab578063a7ab49bc146102ca578063ae80c584146102e9578063b11f126214610308575f80fd5b806351d46815116100f65780636f35d2d2116100dc5780636f35d2d214610246578063875530ff146102795780639935c86814610298575f80fd5b806351d46815146102125780635aa0e95d14610227575f80fd5b80631626ba7e1461013157806329bcdc95146101865780633644e515146101d15780634c9e03d3146101f3575f80fd5b3661012d57005b5f80fd5b34801561013c575f80fd5b5061015061014b366004613595565b6103ca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610191575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161017d565b3480156101dc575f80fd5b506101e56104d7565b60405190815260200161017d565b3480156101fe575f80fd5b506101e561020d366004613620565b6105c6565b6102256102203660046136d7565b610667565b005b348015610232575f80fd5b506102256102413660046137e1565b6109e8565b348015610251575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610284575f80fd5b506101e5610293366004613620565b610c30565b6102256102a636600461383f565b610c5f565b3480156102b6575f80fd5b506102256102c53660046138dd565b610c7f565b3480156102d5575f80fd5b506102256102e4366004613901565b610c8c565b3480156102f4575f80fd5b5061022561030336600461399d565b611067565b348015610313575f80fd5b506101e56103223660046139f2565b6112eb565b348015610332575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610365575f80fd5b50610225610374366004613a24565b6114ea565b610225610387366004613b0b565b611878565b348015610397575f80fd5b506101e56103a6366004613bc9565b61194c565b3480156103b6575f80fd5b506102256103c5366004613bc9565b611a8e565b5f806103d7858585611b50565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063e75600c390602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190613bfb565b156104ab577f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150506104d0565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b9392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000046146105a157604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f7f68b8e94dc077458241d6c8d89f0a7665c7cda2cfe70c9eb4437efee1663c66fe6105f56020840184613c16565b836020013584604001358560600135866080013560405160200161064a969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b61066f611bdb565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa1580156106ec573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107109190613bfb565b610746576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610200870135881580159061076057506101608801358911155b1561077f5761077c896102008a01356101608b01356001611c1e565b90505b6107b07f00000000000000000000000000000000000000000000000000000000000000008b838b8b8b8b8b8b611c69565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66107ef60c08b0160a08c01613c16565b6108016101408c016101208d01613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108449291906101608e0135908890600401613c8d565b5f604051808303815f87803b15801561085b575f80fd5b505af115801561086d573d5f803e3d5ffd5b505050506108b4888b838c5f148061088957506101608c01358d115b610893578c61089a565b6101608c01355b898c8c60026108af60408e0160208f01613d61565b611e01565b6108c16040890189613d7f565b6040516108cf929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661090960a08b0160808c01613c16565b61091960c08c0160a08d01613c16565b61092b6101408d016101208e01613c16565b61093d6101e08e016101c08f01613c16565b8e158061094e57506101608e01358f115b610958578e61095f565b6101408e01355b6102008f013588146109715787610978565b6101e08f01355b8f60e001602081019061098b9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a2506109dd60018055565b505050505050505050565b5f5b6109f48280613def565b9050811015610b065736610a088380613def565b83818110610a1857610a18613e53565b9050602002810190610a2a9190613e80565b90506001600160a01b03841663a8c4bc95610a486020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610aa2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac69190613bfb565b15610afd576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016109ea565b505f5b610b166020830183613def565b9050811015610c2b5736610b2d6020840184613def565b83818110610b3d57610b3d613e53565b9050602002810190610b4f9190613e80565b90506001600160a01b03841663a8c4bc95610b6d6020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610bc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610beb9190613bfb565b15610c22576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101610b09565b505050565b5f7fae676bf6913ac2689b7331293c989fe7723124faf8b5d275f06fbcebc77950096105f56020840184613c16565b610c698482612212565b610c78858585856001806122c9565b5050505050565b610c89338261261e565b50565b610cbf6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f5b828110156110535736848483818110610cdc57610cdc613e53565b9050602002810190610cee9190613e80565b9050365f610cff6040840184613d7f565b90925090506001600160a01b038b1663a8c4bc95610d206020860186613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9e9190613bfb565b15611045575f8915610ddc576040517f7d617bb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048210610de8575081355b7fc03a9de9000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610e5657610e3d83838d8c6126c4565b86602001818151610e4e9190613ebc565b905250611043565b7f243a4b7f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610ebc57610eab83838d8c6127da565b86606001818151610e4e9190613ebc565b7f7dc4f458000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f4757610f1183838d8c61294e565b60a088015260808701819052606087018051610f2e908390613ebc565b90525060a0860151602087018051610e4e908390613ebc565b7f68931b6b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610fab57610f9c83838d8c612bb6565b86518790610e4e908390613ebc565b7f0c9be7e4000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016110115761100083838d8c612cc0565b86604001818151610e4e9190613ebc565b6040517f0561d8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050806001019050610cc1565b5061105e8482612e29565b50505050505050565b60036110766020830183613f21565b600381111561108757611087613ef4565b036110ec576001600160a01b0383166110ac836110a76040850185613d7f565b611b50565b6001600160a01b031614610c2b576040517fb81d58e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016110fb6020830183613f21565b600381111561110c5761110c613ef4565b036111a0577f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c839052603c90206001600160a01b03841661115a826110a76040860186613d7f565b6001600160a01b03161461119a576040517f644ae6c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60026111af6020830183613f21565b60038111156111c0576111c0613ef4565b036112b9577f1626ba7e000000000000000000000000000000000000000000000000000000006001600160a01b038416631626ba7e846112036040860186613d7f565b6040518463ffffffff1660e01b815260040161122193929190613f3f565b602060405180830381865afa15801561123c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112609190613f58565b7fffffffff000000000000000000000000000000000000000000000000000000001614610c2b576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f60cd402d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112f46104d7565b7fd28e809b708f5ee38be8347d6d869d8232493c094ab2dde98369e4102369a99d61131f8480613d7f565b604051602001611330929190613f97565b60405160208183030381529060405280519060200120846020013585604001602081019061135e9190613c16565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526113c46080850160608601613c16565b6113d460a0860160808701613c16565b6113e460c0870160a08801613c16565b60c087013560e08801356101008901356101208a013561140c6101608c016101408d01613c16565b604080516001600160a01b03998a166020820152978916908801529487166060870152608086019390935260a085019190915260c084015260e083015290911661010082015261012001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526114929291602001613fd7565b6040516020818303038152906040528051906020012060405160200161064a9291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6114f2611bdb565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906302cc250d90602401602060405180830381865afa15801561156d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115919190613bfb565b6115c7576040517fc139eabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa158015611644573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116689190613bfb565b61169e576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61020086013587158015906116b857506101608701358811155b156116d7576116d4886102008901356101608a01356001611c1e565b90505b6117087f00000000000000000000000000000000000000000000000000000000000000008a838a8a8a8a8a8a611c69565b611745878a838b158061171f57506101608b01358c115b611729578b611730565b6101608b01355b888b8b60016108af60408d0160208e01613d61565b6117526040880188613d7f565b604051611760929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661179a60a08a0160808b01613c16565b6117aa60c08b0160a08c01613c16565b6117bc6101408c016101208d01613c16565b6117ce6101e08d016101c08e01613c16565b8d15806117df57506101608d01358e115b6117e9578d6117f0565b6101408d01355b6102008e013588146118025787611809565b6101e08e01355b8e60e001602081019061181c9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a25061186e60018055565b5050505050505050565b6118828583612212565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66118c16080880160608901613c16565b6118d160a0890160808a01613c16565b8860c00135856040518563ffffffff1660e01b81526004016118f69493929190613c8d565b5f604051808303815f87803b15801561190d575f80fd5b505af115801561191f573d5f803e3d5ffd5b5050505061194486868686600289602001602081019061193f9190613d61565b6122c9565b505050505050565b5f6119556104d7565b7fc994d2ca0375d6d473785e0ce0b1d203f069121bac1314f72c5c0fe601eb39106119836040850185613d7f565b604051602001611994929190613f97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060608501356119df60a0870160808801613c16565b6119ef60c0880160a08901613c16565b60c0880135611a056101008a0160e08b01613c16565b60408051602081019890985287019590955260608601939093526001600160a01b039182166080860152811660a085015260c08401919091521660e0820152610100808501359082015261012001604051602081830303815290604052611a6f8461012001610c30565b611a7c856101c0016105c6565b60405160200161149293929190613feb565b6101a0810135611aa8610180830135610160840135613ebc565b611ab29190613ebc565b61014082013514611aef576040517fc04377d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610240810135611b09610220830135610200840135613ebc565b611b139190613ebc565b6101e082013514610c89576040517f877630be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ed692505050565b90506001600160a01b038116611bd3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b600260015403611c17576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600155565b5f611c4b611c2b83612f00565b8015611c4657505f8480611c4157611c41614008565b868809115b151590565b611c56868686612f2c565b611c609190613ebc565b95945050505050565b5f611c738761194c565b9050611c80898285611067565b611c9060c0880160a08901613c16565b6001600160a01b0316336001600160a01b031614611cc757611cc2611cbb60c0890160a08a01613c16565b8284611067565b611d0e565b611cd46040830183613d7f565b90505f03611d0e576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d2b611d2160c0890160a08a01613c16565b886060013561261e565b8660c00135421115611d69576040517f133df02900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f88118015611d7c575086610100013588105b15611db3576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dbc87611a8e565b611dc68a856109e8565b611de78a8a5f8b118015611ddf57506102008a01358b14155b8a8a8a610c8c565b611df589886060013561261e565b50505050505050505050565b611e13611e0e8680613def565b613001565b5f611e286101808b01356101a08c0135613ebc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611e779190613c16565b6001600160a01b03168152602001306001600160a01b031681526020018d610120015f016020810190611eaa9190613c16565b6001600160a01b03168152602001848152602001866002811115611ed057611ed0613ef4565b8152506040518263ffffffff1660e01b8152600401611eef9190614035565b5f604051808303815f87803b158015611f06575f80fd5b505af1158015611f18573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611f699190613c16565b6001600160a01b031681526020018d60e0016020810190611f8a9190613c16565b6001600160a01b031681526020018d610120015f016020810190611fae9190613c16565b6001600160a01b031681526020018a8152602001866002811115611fd457611fd4613ef4565b8152506040518263ffffffff1660e01b8152600401611ff39190614035565b5f604051808303815f87803b15801561200a575f80fd5b505af115801561201c573d5f803e3d5ffd5b5050505061202a8585613001565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808c6001600160a01b031681526020018d60800160208101906120869190613c16565b6001600160a01b031681526020018d6101c0015f0160208101906120aa9190613c16565b6001600160a01b031681526020018b81526020018560028111156120d0576120d0613ef4565b8152506040518263ffffffff1660e01b81526004016120ef9190614035565b5f604051808303815f87803b158015612106575f80fd5b505af1158015612118573d5f803e3d5ffd5b5061212e9250611e0e9150506020880188613def565b5f6121416101408c016101208d01613c16565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561219e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c291906140b4565b90508015612205576122056121de6101008d0160e08e01613c16565b828d610120015f0160208101906121f59190613c16565b6001600160a01b03169190613139565b5050505050505050505050565b6122226080830160608401613c16565b6001600160a01b0316336001600160a01b0316146122615761225c61224d6080840160608501613c16565b612256846112eb565b83611067565b6122a8565b61226e6040820182613d7f565b90505f036122a8576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122c56122bb6080840160608501613c16565b836020013561261e565b5050565b60e085013583158015906122e057508560c0013584105b156122fd576122fa848760e001358860c001356001611c1e565b90505b612309878288886131b9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808960600160208101906123569190613c16565b6001600160a01b031681526020016123766101608b016101408c01613c16565b6001600160a01b0316815260200161239460a08b0160808c01613c16565b6001600160a01b031681526020018715806123b257508960c0013588115b6123bc57876123c2565b8960c001355b81526020018660028111156123d9576123d9613ef4565b8152506040518263ffffffff1660e01b81526004016123f89190614035565b5f604051808303815f87803b15801561240f575f80fd5b505af1158015612421573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808a6001600160a01b031681526020018960400160208101906124819190613c16565b6001600160a01b0316815260200161249f60c08b0160a08c01613c16565b6001600160a01b031681526020018481526020018560028111156124c5576124c5613ef4565b8152506040518263ffffffff1660e01b81526004016124e49190614035565b5f604051808303815f87803b1580156124fb575f80fd5b505af115801561250d573d5f803e3d5ffd5b5061251e9250889150819050613d7f565b60405161252c929190613de0565b60405180910390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b68760400160208101906125689190613c16565b61257860808a0160608b01613c16565b61258860a08b0160808c01613c16565b61259860c08c0160a08d01613c16565b8915806125a857508b60c001358a115b6125b257896125b8565b8b60c001355b878d6101400160208101906125cd9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a250505050505050565b6001600160a01b0382165f9081526020818152604080832084845290915290205460ff1615612679576040517fbc0da7d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b039091165f908152602081815260408083209383529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f8080806126d5876004818b6140cb565b8101906126e291906140f2565b50919450925090506126fc61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612746576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612791576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b979650505050505050565b5f808080806127ec886004818c6140cb565b8101906127f99190614142565b929650909450925090506128156101e087016101c08801613c16565b6001600160a01b0316846001600160a01b03161461285f576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b0316146128aa576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128ba60a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612904576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b98975050505050505050565b5f805f805f805f805f8c8c600490809261296a939291906140cb565b8101906129779190614190565b959c50939a50919850965094509250905061299a6101e08b016101c08c01613c16565b6001600160a01b0316876001600160a01b0316146129e4576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856001600160a01b03168b6001600160a01b031614612a2f576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385163014612a71576040517f8154374b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612a8160a08b0160808c01613c16565b6001600160a01b0316846001600160a01b031614612acb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408a01358314612b09576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b1b6101408b016101208c01613c16565b6001600160a01b0316826001600160a01b031614612b65576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a08a01358114612ba3576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919c919b50909950505050505050505050565b5f808080612bc7876004818b6140cb565b810190612bd4919061420f565b91945092509050612bed61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612c37576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612c82576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61018085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808080612cd2886004818c6140cb565b810190612cdf919061424d565b5092965090945092509050612cfc6101e087016101c08801613c16565b6001600160a01b0316846001600160a01b031614612d46576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614612d91576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612da160a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612deb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102208601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051610180830135141580612e47575060208101516101a083013514155b15612e7e576040517f4a55da2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610220830135141580612e9f5750606081015161024083013514155b156122c5576040517f77a5920300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f80612ee4868661325c565b925092509250612ef482826132a5565b50909150505b92915050565b5f6002826003811115612f1557612f15613ef4565b612f1f91906142b1565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03612f7f57838281612f7557612f75614008565b04925050506104d0565b808411612f9657612f9660038515026011186133ad565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f5b81811015610c2b573683838381811061301e5761301e613e53565b90506020028101906130309190613e80565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130696020830183613c16565b6001600160a01b0316036130a9576040517f79a1bff000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130b2816133be565b6130bf6020820182613c16565b6001600160a01b03167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356130f784613401565b604080519283527fffffffff0000000000000000000000000000000000000000000000000000000090911660208301520160405180910390a250600101613003565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610c2b90849061342a565b5f831180156131cc575081610100013583105b15613203576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61321084612256846112eb565b61321e84836020013561261e565b428261012001351161119a576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f8351604103613293576020840151604085015160608601515f1a613285888285856134af565b95509550955050505061329e565b505081515f91506002905b9250925092565b5f8260038111156132b8576132b8613ef4565b036132c1575050565b60018260038111156132d5576132d5613ef4565b0361330c576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561332057613320613ef4565b0361335f576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600382600381111561337357613373613ef4565b036122c5576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401613356565b634e487b715f52806020526024601cfd5b5f6133cc6020830183613c16565b90506020820135365f6133e26040860186613d7f565b91509150604051818382375f80838387895af1611944573d5f803e3d5ffd5b5f36816134116040850185613d7f565b90925090506004811061342357813592505b5050919050565b5f8060205f8451602086015f885af180613449576040513d5f823e3d81fd5b50505f513d9150811561346057806001141561346d565b6001600160a01b0384163b155b1561119a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613356565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156134e857505f9150600390508261358b565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613539573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811661358257505f92506001915082905061358b565b92505f91508190505b9450945094915050565b5f805f604084860312156135a7575f80fd5b83359250602084013567ffffffffffffffff808211156135c5575f80fd5b818601915086601f8301126135d8575f80fd5b8135818111156135e6575f80fd5b8760208285010111156135f7575f80fd5b6020830194508093505050509250925092565b5f60a0828403121561361a575f80fd5b50919050565b5f60a08284031215613630575f80fd5b6104d0838361360a565b6001600160a01b0381168114610c89575f80fd5b80356136598161363a565b919050565b5f610260828403121561361a575f80fd5b5f8083601f84011261367f575f80fd5b50813567ffffffffffffffff811115613696575f80fd5b6020830191508360208260051b85010111156136b0575f80fd5b9250929050565b5f6040828403121561361a575f80fd5b5f6060828403121561361a575f80fd5b5f805f805f805f805f6101008a8c0312156136f0575f80fd5b6136f98a61364e565b985060208a0135975060408a013567ffffffffffffffff8082111561371c575f80fd5b6137288d838e0161365e565b985060608c013591508082111561373d575f80fd5b6137498d838e0161366f565b909850965060808c0135915080821115613761575f80fd5b61376d8d838e016136b7565b955060a08c0135915080821115613782575f80fd5b61378e8d838e016136c7565b945060c08c01359150808211156137a3575f80fd5b6137af8d838e016136c7565b935060e08c01359150808211156137c4575f80fd5b506137d18c828d016136c7565b9150509295985092959850929598565b5f80604083850312156137f2575f80fd5b82356137fd8161363a565b9150602083013567ffffffffffffffff811115613818575f80fd5b613824858286016136b7565b9150509250929050565b5f610160828403121561361a575f80fd5b5f805f805f60a08688031215613853575f80fd5b853561385e8161363a565b9450602086013567ffffffffffffffff8082111561387a575f80fd5b61388689838a0161382e565b9550604088013591508082111561389b575f80fd5b6138a789838a016136c7565b94506060880135935060808801359150808211156138c3575f80fd5b506138d0888289016136c7565b9150509295509295909350565b5f602082840312156138ed575f80fd5b5035919050565b8015158114610c89575f80fd5b5f805f805f8060a08789031215613916575f80fd5b86356139218161363a565b955060208701356139318161363a565b94506040870135613941816138f4565b9350606087013567ffffffffffffffff8082111561395d575f80fd5b6139698a838b0161365e565b9450608089013591508082111561397e575f80fd5b5061398b89828a0161366f565b979a9699509497509295939492505050565b5f805f606084860312156139af575f80fd5b83356139ba8161363a565b925060208401359150604084013567ffffffffffffffff8111156139dc575f80fd5b6139e8868287016136c7565b9150509250925092565b5f60208284031215613a02575f80fd5b813567ffffffffffffffff811115613a18575f80fd5b611bd38482850161382e565b5f805f805f805f8060e0898b031215613a3b575f80fd5b613a448961364e565b975060208901359650604089013567ffffffffffffffff80821115613a67575f80fd5b613a738c838d0161365e565b975060608b0135915080821115613a88575f80fd5b613a948c838d0161366f565b909750955060808b0135915080821115613aac575f80fd5b613ab88c838d016136b7565b945060a08b0135915080821115613acd575f80fd5b613ad98c838d016136c7565b935060c08b0135915080821115613aee575f80fd5b50613afb8b828c016136c7565b9150509295985092959890939650565b5f805f805f8060c08789031215613b20575f80fd5b613b298761364e565b9550602087013567ffffffffffffffff80821115613b45575f80fd5b613b518a838b0161382e565b96506040890135915080821115613b66575f80fd5b613b728a838b016136c7565b9550606089013594506080890135915080821115613b8e575f80fd5b613b9a8a838b016136c7565b935060a0890135915080821115613baf575f80fd5b50613bbc89828a016136c7565b9150509295509295509295565b5f60208284031215613bd9575f80fd5b813567ffffffffffffffff811115613bef575f80fd5b611bd38482850161365e565b5f60208284031215613c0b575f80fd5b81516104d0816138f4565b5f60208284031215613c26575f80fd5b81356104d08161363a565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b803565ffffffffffff81168114613659575f80fd5b5f6001600160a01b0380871683528086166020840152508360408301526080606083015282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ce2575f80fd5b830160208101903567ffffffffffffffff811115613cfe575f80fd5b803603821315613d0c575f80fd5b60606080850152613d2160e085018284613c31565b915050613d3060208501613c78565b65ffffffffffff80821660a086015280613d4c60408801613c78565b1660c086015250508091505095945050505050565b5f60208284031215613d71575f80fd5b8135600381106104d0575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db2575f80fd5b83018035915067ffffffffffffffff821115613dcc575f80fd5b6020019150368190038213156136b0575f80fd5b818382375f9101908152919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e22575f80fd5b83018035915067ffffffffffffffff821115613e3c575f80fd5b6020019150600581901b36038213156136b0575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112613eb2575f80fd5b9190910192915050565b80820180821115612efa577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613f31575f80fd5b8135600481106104d0575f80fd5b838152604060208201525f611c60604083018486613c31565b5f60208284031215613f68575f80fd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146104d0575f80fd5b602081525f611bd3602083018486613c31565b5f81515f5b81811015613fc95760208185018101518683015201613faf565b505f93019283525090919050565b5f611bd3613fe58386613faa565b84613faa565b5f613ff68286613faa565b93845250506020820152604001919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60a0820190506001600160a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151600381106140a7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8060808401525092915050565b5f602082840312156140c4575f80fd5b5051919050565b5f80858511156140d9575f80fd5b838611156140e5575f80fd5b5050820193919092039150565b5f805f8060808587031215614105575f80fd5b84356141108161363a565b935060208501356141208161363a565b9250604085013591506060850135614137816138f4565b939692955090935050565b5f805f8060808587031215614155575f80fd5b84356141608161363a565b935060208501356141708161363a565b925060408501356141808161363a565b9396929550929360600135925050565b5f805f805f805f60e0888a0312156141a6575f80fd5b87356141b18161363a565b965060208801356141c18161363a565b955060408801356141d18161363a565b945060608801356141e18161363a565b93506080880135925060a08801356141f88161363a565b8092505060c0880135905092959891949750929550565b5f805f60608486031215614221575f80fd5b833561422c8161363a565b9250602084013561423c8161363a565b929592945050506040919091013590565b5f805f805f60a08688031215614261575f80fd5b853561426c8161363a565b9450602086013561427c8161363a565b9350604086013561428c8161363a565b92506060860135915060808601356142a3816138f4565b809150509295509295909350565b5f60ff8316806142e8577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff8416069150509291505056fea26469706673582212209be58acada353061a2a202cc7011f3c91393e0f2e305e9202445b042fc4a4ce664736f6c6343000817003360c060405234801561000f575f80fd5b5060405161096338038061096383398101604081905261002e91610060565b6001600160a01b039182166080521660a052610091565b80516001600160a01b038116811461005b575f80fd5b919050565b5f8060408385031215610071575f80fd5b61007a83610045565b915061008860208401610045565b90509250929050565b60805160a05161089e6100c55f395f81816048015281816101f2015261038101525f818160d30152610327015261089e5ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c80636afdd85014610043578063b519d36914610093578063bc1178e6146100a8575b5f80fd5b61006a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100a66100a136600461060a565b6100bb565b005b6100a66100b6366004610648565b61030f565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016811461012b576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820135156101af57600161014760a08401608085016106dd565b6002811115610158576101586106b0565b036101b3576101af61016d6020840184610702565b61017d6040850160208601610702565b606085018035906101919060408801610702565b73ffffffffffffffffffffffffffffffffffffffff169291906104cc565b5050565b60026101c560a08401608085016106dd565b60028111156101d6576101d66106b0565b036102dd5773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166336c785166102246020850185610702565b6102346040860160208701610702565b606086018035906102489060408901610702565b60405160e086901b7fffffffff0000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff94851660048201529284166024840152908316604483015290911660648201526084015f604051808303815f87803b1580156102c3575f80fd5b505af11580156102d5573d5f803e3d5ffd5b505050505050565b6040517fc79aaa4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016811461037f576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632b67b57086604051806060016040528060405180608001604052808a73ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff16815260200188604001602081019061041d919061071b565b65ffffffffffff16815260200188602001602081019061043d919061071b565b65ffffffffffff1690528152306020820152604090810190610465906060890190890161071b565b65ffffffffffff1690526104798680610740565b6040518563ffffffff1660e01b815260040161049894939291906107a8565b5f604051808303815f87803b1580156104af575f80fd5b505af11580156104c1573d5f803e3d5ffd5b505050505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610561908590610567565b50505050565b5f8060205f8451602086015f885af180610586576040513d5f823e3d81fd5b50505f513d9150811561059d5780600114156105b7565b73ffffffffffffffffffffffffffffffffffffffff84163b155b15610561576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240160405180910390fd5b5f60a0828403121561061a575f80fd5b50919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610643575f80fd5b919050565b5f805f806080858703121561065b575f80fd5b61066485610620565b935061067260208601610620565b925060408501359150606085013567ffffffffffffffff811115610694575f80fd5b8501606081880312156106a5575f80fd5b939692955090935050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f602082840312156106ed575f80fd5b8135600381106106fb575f80fd5b9392505050565b5f60208284031215610712575f80fd5b6106fb82610620565b5f6020828403121561072b575f80fd5b813565ffffffffffff811681146106fb575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610773575f80fd5b83018035915067ffffffffffffffff82111561078d575f80fd5b6020019150368190038213156107a1575f80fd5b9250929050565b5f61010073ffffffffffffffffffffffffffffffffffffffff80881684528651818151166020860152816020820151166040860152604081015165ffffffffffff80821660608801528060608401511660808801525050508060208801511660a085015250604086015160c08401528060e08401528381840152506101208385828501375f838501820152601f9093017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910190910194935050505056fea2646970667358221220f3565f6589500276fcbb6fb33d3ee3b534d9566c5b2732fe10a6039b753c3a0764736f6c63430008170033", - "sourceMap": "975:10890:90:-:0;;;2483:234;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3749:13:91;3730:32;;;;3811:93;;;1026:66;3811:93;;;1092:25:169;879:32:91;1133:18:169;;;1126:34;;;;957:14:91;1176:18:169;;;1169:34;1219:18;;;1212:34;;;;3898:4:91;1262:19:169;;;1255:61;1064:19;;3811:93:91;;;-1:-1:-1;;3811:93:91;;;;;;;;;;3801:104;;3811:93;3801:104;;;;3768:137;;1857:1:44;2061:21;;-1:-1:-1;;;;;2585:30:90;;;;2666:4;;2673:8;;2639:43;;;:::i;:::-;-1:-1:-1;;;;;1557:15:169;;;1539:34;;1609:15;;1604:2;1589:18;;1582:43;1489:2;1474:18;2639:43:90;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2621:61:90;;;;;2688:24;;;;;;-1:-1:-1;975:10890:90;;-1:-1:-1;975:10890:90;;;;;;;;;:::o;14:157:169:-;-1:-1:-1;;;;;115:31:169;;105:42;;95:70;;161:1;158;151:12;95:70;14:157;:::o;176:652::-;319:6;327;335;388:2;376:9;367:7;363:23;359:32;356:52;;;404:1;401;394:12;356:52;436:9;430:16;455:57;506:5;455:57;:::i;:::-;581:2;566:18;;560:25;531:5;;-1:-1:-1;594:59:169;560:25;594:59;:::i;:::-;724:2;709:18;;703:25;672:7;;-1:-1:-1;737:59:169;703:25;737:59;:::i;:::-;815:7;805:17;;;176:652;;;;;:::o;1327:304::-;975:10890:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", - "linkReferences": {} - }, - "deployedBytecode": { - "object": "0x608060405260043610610126575f3560e01c8063a5cdc8fc116100a1578063c618618111610071578063db58772811610057578063db58772814610379578063e242924e1461038c578063fa5cd56c146103ab575f80fd5b8063c618618114610327578063cba673a71461035a575f80fd5b8063a5cdc8fc146102ab578063a7ab49bc146102ca578063ae80c584146102e9578063b11f126214610308575f80fd5b806351d46815116100f65780636f35d2d2116100dc5780636f35d2d214610246578063875530ff146102795780639935c86814610298575f80fd5b806351d46815146102125780635aa0e95d14610227575f80fd5b80631626ba7e1461013157806329bcdc95146101865780633644e515146101d15780634c9e03d3146101f3575f80fd5b3661012d57005b5f80fd5b34801561013c575f80fd5b5061015061014b366004613595565b6103ca565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610191575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161017d565b3480156101dc575f80fd5b506101e56104d7565b60405190815260200161017d565b3480156101fe575f80fd5b506101e561020d366004613620565b6105c6565b6102256102203660046136d7565b610667565b005b348015610232575f80fd5b506102256102413660046137e1565b6109e8565b348015610251575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610284575f80fd5b506101e5610293366004613620565b610c30565b6102256102a636600461383f565b610c5f565b3480156102b6575f80fd5b506102256102c53660046138dd565b610c7f565b3480156102d5575f80fd5b506102256102e4366004613901565b610c8c565b3480156102f4575f80fd5b5061022561030336600461399d565b611067565b348015610313575f80fd5b506101e56103223660046139f2565b6112eb565b348015610332575f80fd5b506101b97f000000000000000000000000000000000000000000000000000000000000000081565b348015610365575f80fd5b50610225610374366004613a24565b6114ea565b610225610387366004613b0b565b611878565b348015610397575f80fd5b506101e56103a6366004613bc9565b61194c565b3480156103b6575f80fd5b506102256103c5366004613bc9565b611a8e565b5f806103d7858585611b50565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063e75600c390602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190613bfb565b156104ab577f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150506104d0565b507fffffffff0000000000000000000000000000000000000000000000000000000090505b9392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000046146105a157604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f64afec7be651c92f86754beb2bd5eeaf2fa95e83faf4aee989877dde08e4498c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f7f68b8e94dc077458241d6c8d89f0a7665c7cda2cfe70c9eb4437efee1663c66fe6105f56020840184613c16565b836020013584604001358560600135866080013560405160200161064a969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b61066f611bdb565b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa1580156106ec573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107109190613bfb565b610746576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610200870135881580159061076057506101608801358911155b1561077f5761077c896102008a01356101608b01356001611c1e565b90505b6107b07f00000000000000000000000000000000000000000000000000000000000000008b838b8b8b8b8b8b611c69565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66107ef60c08b0160a08c01613c16565b6108016101408c016101208d01613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526108449291906101608e0135908890600401613c8d565b5f604051808303815f87803b15801561085b575f80fd5b505af115801561086d573d5f803e3d5ffd5b505050506108b4888b838c5f148061088957506101608c01358d115b610893578c61089a565b6101608c01355b898c8c60026108af60408e0160208f01613d61565b611e01565b6108c16040890189613d7f565b6040516108cf929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661090960a08b0160808c01613c16565b61091960c08c0160a08d01613c16565b61092b6101408d016101208e01613c16565b61093d6101e08e016101c08f01613c16565b8e158061094e57506101608e01358f115b610958578e61095f565b6101408e01355b6102008f013588146109715787610978565b6101e08f01355b8f60e001602081019061098b9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a2506109dd60018055565b505050505050505050565b5f5b6109f48280613def565b9050811015610b065736610a088380613def565b83818110610a1857610a18613e53565b9050602002810190610a2a9190613e80565b90506001600160a01b03841663a8c4bc95610a486020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610aa2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ac69190613bfb565b15610afd576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016109ea565b505f5b610b166020830183613def565b9050811015610c2b5736610b2d6020840184613def565b83818110610b3d57610b3d613e53565b9050602002810190610b4f9190613e80565b90506001600160a01b03841663a8c4bc95610b6d6020840184613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610bc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610beb9190613bfb565b15610c22576040517fc99e887200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101610b09565b505050565b5f7fae676bf6913ac2689b7331293c989fe7723124faf8b5d275f06fbcebc77950096105f56020840184613c16565b610c698482612212565b610c78858585856001806122c9565b5050505050565b610c89338261261e565b50565b610cbf6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f5b828110156110535736848483818110610cdc57610cdc613e53565b9050602002810190610cee9190613e80565b9050365f610cff6040840184613d7f565b90925090506001600160a01b038b1663a8c4bc95610d206020860186613c16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d7a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9e9190613bfb565b15611045575f8915610ddc576040517f7d617bb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048210610de8575081355b7fc03a9de9000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610e5657610e3d83838d8c6126c4565b86602001818151610e4e9190613ebc565b905250611043565b7f243a4b7f000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610ebc57610eab83838d8c6127da565b86606001818151610e4e9190613ebc565b7f7dc4f458000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f4757610f1183838d8c61294e565b60a088015260808701819052606087018051610f2e908390613ebc565b90525060a0860151602087018051610e4e908390613ebc565b7f68931b6b000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610fab57610f9c83838d8c612bb6565b86518790610e4e908390613ebc565b7f0c9be7e4000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016110115761100083838d8c612cc0565b86604001818151610e4e9190613ebc565b6040517f0561d8b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050806001019050610cc1565b5061105e8482612e29565b50505050505050565b60036110766020830183613f21565b600381111561108757611087613ef4565b036110ec576001600160a01b0383166110ac836110a76040850185613d7f565b611b50565b6001600160a01b031614610c2b576040517fb81d58e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016110fb6020830183613f21565b600381111561110c5761110c613ef4565b036111a0577f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c839052603c90206001600160a01b03841661115a826110a76040860186613d7f565b6001600160a01b03161461119a576040517f644ae6c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60026111af6020830183613f21565b60038111156111c0576111c0613ef4565b036112b9577f1626ba7e000000000000000000000000000000000000000000000000000000006001600160a01b038416631626ba7e846112036040860186613d7f565b6040518463ffffffff1660e01b815260040161122193929190613f3f565b602060405180830381865afa15801561123c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112609190613f58565b7fffffffff000000000000000000000000000000000000000000000000000000001614610c2b576040517f5d52cbe300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f60cd402d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6112f46104d7565b7fd28e809b708f5ee38be8347d6d869d8232493c094ab2dde98369e4102369a99d61131f8480613d7f565b604051602001611330929190613f97565b60405160208183030381529060405280519060200120846020013585604001602081019061135e9190613c16565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526113c46080850160608601613c16565b6113d460a0860160808701613c16565b6113e460c0870160a08801613c16565b60c087013560e08801356101008901356101208a013561140c6101608c016101408d01613c16565b604080516001600160a01b03998a166020820152978916908801529487166060870152608086019390935260a085019190915260c084015260e083015290911661010082015261012001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526114929291602001613fd7565b6040516020818303038152906040528051906020012060405160200161064a9291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6114f2611bdb565b6040517f02cc250d0000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906302cc250d90602401602060405180830381865afa15801561156d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115919190613bfb565b6115c7576040517fc139eabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe75600c30000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e75600c390602401602060405180830381865afa158015611644573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116689190613bfb565b61169e576040517fb331e42100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61020086013587158015906116b857506101608701358811155b156116d7576116d4886102008901356101608a01356001611c1e565b90505b6117087f00000000000000000000000000000000000000000000000000000000000000008a838a8a8a8a8a8a611c69565b611745878a838b158061171f57506101608b01358c115b611729578b611730565b6101608b01355b888b8b60016108af60408d0160208e01613d61565b6117526040880188613d7f565b604051611760929190613de0565b6040519081900390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b661179a60a08a0160808b01613c16565b6117aa60c08b0160a08c01613c16565b6117bc6101408c016101208d01613c16565b6117ce6101e08d016101c08e01613c16565b8d15806117df57506101608d01358e115b6117e9578d6117f0565b6101408d01355b6102008e013588146118025787611809565b6101e08e01355b8e60e001602081019061181c9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a25061186e60018055565b5050505050505050565b6118828583612212565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bc1178e66118c16080880160608901613c16565b6118d160a0890160808a01613c16565b8860c00135856040518563ffffffff1660e01b81526004016118f69493929190613c8d565b5f604051808303815f87803b15801561190d575f80fd5b505af115801561191f573d5f803e3d5ffd5b5050505061194486868686600289602001602081019061193f9190613d61565b6122c9565b505050505050565b5f6119556104d7565b7fc994d2ca0375d6d473785e0ce0b1d203f069121bac1314f72c5c0fe601eb39106119836040850185613d7f565b604051602001611994929190613f97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060608501356119df60a0870160808801613c16565b6119ef60c0880160a08901613c16565b60c0880135611a056101008a0160e08b01613c16565b60408051602081019890985287019590955260608601939093526001600160a01b039182166080860152811660a085015260c08401919091521660e0820152610100808501359082015261012001604051602081830303815290604052611a6f8461012001610c30565b611a7c856101c0016105c6565b60405160200161149293929190613feb565b6101a0810135611aa8610180830135610160840135613ebc565b611ab29190613ebc565b61014082013514611aef576040517fc04377d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610240810135611b09610220830135610200840135613ebc565b611b139190613ebc565b6101e082013514610c89576040517f877630be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80611b918585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612ed692505050565b90506001600160a01b038116611bd3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b600260015403611c17576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600155565b5f611c4b611c2b83612f00565b8015611c4657505f8480611c4157611c41614008565b868809115b151590565b611c56868686612f2c565b611c609190613ebc565b95945050505050565b5f611c738761194c565b9050611c80898285611067565b611c9060c0880160a08901613c16565b6001600160a01b0316336001600160a01b031614611cc757611cc2611cbb60c0890160a08a01613c16565b8284611067565b611d0e565b611cd46040830183613d7f565b90505f03611d0e576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d2b611d2160c0890160a08a01613c16565b886060013561261e565b8660c00135421115611d69576040517f133df02900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f88118015611d7c575086610100013588105b15611db3576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dbc87611a8e565b611dc68a856109e8565b611de78a8a5f8b118015611ddf57506102008a01358b14155b8a8a8a610c8c565b611df589886060013561261e565b50505050505050505050565b611e13611e0e8680613def565b613001565b5f611e286101808b01356101a08c0135613ebc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611e779190613c16565b6001600160a01b03168152602001306001600160a01b031681526020018d610120015f016020810190611eaa9190613c16565b6001600160a01b03168152602001848152602001866002811115611ed057611ed0613ef4565b8152506040518263ffffffff1660e01b8152600401611eef9190614035565b5f604051808303815f87803b158015611f06575f80fd5b505af1158015611f18573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808d60a0016020810190611f699190613c16565b6001600160a01b031681526020018d60e0016020810190611f8a9190613c16565b6001600160a01b031681526020018d610120015f016020810190611fae9190613c16565b6001600160a01b031681526020018a8152602001866002811115611fd457611fd4613ef4565b8152506040518263ffffffff1660e01b8152600401611ff39190614035565b5f604051808303815f87803b15801561200a575f80fd5b505af115801561201c573d5f803e3d5ffd5b5050505061202a8585613001565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808c6001600160a01b031681526020018d60800160208101906120869190613c16565b6001600160a01b031681526020018d6101c0015f0160208101906120aa9190613c16565b6001600160a01b031681526020018b81526020018560028111156120d0576120d0613ef4565b8152506040518263ffffffff1660e01b81526004016120ef9190614035565b5f604051808303815f87803b158015612106575f80fd5b505af1158015612118573d5f803e3d5ffd5b5061212e9250611e0e9150506020880188613def565b5f6121416101408c016101208d01613c16565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561219e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121c291906140b4565b90508015612205576122056121de6101008d0160e08e01613c16565b828d610120015f0160208101906121f59190613c16565b6001600160a01b03169190613139565b5050505050505050505050565b6122226080830160608401613c16565b6001600160a01b0316336001600160a01b0316146122615761225c61224d6080840160608501613c16565b612256846112eb565b83611067565b6122a8565b61226e6040820182613d7f565b90505f036122a8576040517f0e364efc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122c56122bb6080840160608501613c16565b836020013561261e565b5050565b60e085013583158015906122e057508560c0013584105b156122fd576122fa848760e001358860c001356001611c1e565b90505b612309878288886131b9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808960600160208101906123569190613c16565b6001600160a01b031681526020016123766101608b016101408c01613c16565b6001600160a01b0316815260200161239460a08b0160808c01613c16565b6001600160a01b031681526020018715806123b257508960c0013588115b6123bc57876123c2565b8960c001355b81526020018660028111156123d9576123d9613ef4565b8152506040518263ffffffff1660e01b81526004016123f89190614035565b5f604051808303815f87803b15801561240f575f80fd5b505af1158015612421573d5f803e3d5ffd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b519d3696040518060a001604052808a6001600160a01b031681526020018960400160208101906124819190613c16565b6001600160a01b0316815260200161249f60c08b0160a08c01613c16565b6001600160a01b031681526020018481526020018560028111156124c5576124c5613ef4565b8152506040518263ffffffff1660e01b81526004016124e49190614035565b5f604051808303815f87803b1580156124fb575f80fd5b505af115801561250d573d5f803e3d5ffd5b5061251e9250889150819050613d7f565b60405161252c929190613de0565b60405180910390207f0fce007c38c6c8ed9e545b3a148095762738618f8c21b673222613e4d45734b68760400160208101906125689190613c16565b61257860808a0160608b01613c16565b61258860a08b0160808c01613c16565b61259860c08c0160a08d01613c16565b8915806125a857508b60c001358a115b6125b257896125b8565b8b60c001355b878d6101400160208101906125cd9190613c16565b604080516001600160a01b0398891681529688166020880152948716948601949094529185166060850152608084015260a083015290911660c082015260e00160405180910390a250505050505050565b6001600160a01b0382165f9081526020818152604080832084845290915290205460ff1615612679576040517fbc0da7d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b039091165f908152602081815260408083209383529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5f8080806126d5876004818b6140cb565b8101906126e291906140f2565b50919450925090506126fc61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612746576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612791576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b979650505050505050565b5f808080806127ec886004818c6140cb565b8101906127f99190614142565b929650909450925090506128156101e087016101c08801613c16565b6001600160a01b0316846001600160a01b03161461285f576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b0316146128aa576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128ba60a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612904576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b98975050505050505050565b5f805f805f805f805f8c8c600490809261296a939291906140cb565b8101906129779190614190565b959c50939a50919850965094509250905061299a6101e08b016101c08c01613c16565b6001600160a01b0316876001600160a01b0316146129e4576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856001600160a01b03168b6001600160a01b031614612a2f576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385163014612a71576040517f8154374b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612a8160a08b0160808c01613c16565b6001600160a01b0316846001600160a01b031614612acb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102408a01358314612b09576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b1b6101408b016101208c01613c16565b6001600160a01b0316826001600160a01b031614612b65576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101a08a01358114612ba3576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919c919b50909950505050505050505050565b5f808080612bc7876004818b6140cb565b810190612bd4919061420f565b91945092509050612bed61014086016101208701613c16565b6001600160a01b0316836001600160a01b031614612c37576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816001600160a01b0316866001600160a01b031614612c82576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61018085013581146127cf576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80808080612cd2886004818c6140cb565b810190612cdf919061424d565b5092965090945092509050612cfc6101e087016101c08801613c16565b6001600160a01b0316846001600160a01b031614612d46576040517fc891add200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316876001600160a01b031614612d91576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612da160a0870160808801613c16565b6001600160a01b0316826001600160a01b031614612deb576040517fac6b05f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102208601358114612942576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051610180830135141580612e47575060208101516101a083013514155b15612e7e576040517f4a55da2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610220830135141580612e9f5750606081015161024083013514155b156122c5576040517f77a5920300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f80612ee4868661325c565b925092509250612ef482826132a5565b50909150505b92915050565b5f6002826003811115612f1557612f15613ef4565b612f1f91906142b1565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03612f7f57838281612f7557612f75614008565b04925050506104d0565b808411612f9657612f9660038515026011186133ad565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f5b81811015610c2b573683838381811061301e5761301e613e53565b90506020028101906130309190613e80565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130696020830183613c16565b6001600160a01b0316036130a9576040517f79a1bff000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130b2816133be565b6130bf6020820182613c16565b6001600160a01b03167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356130f784613401565b604080519283527fffffffff0000000000000000000000000000000000000000000000000000000090911660208301520160405180910390a250600101613003565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610c2b90849061342a565b5f831180156131cc575081610100013583105b15613203576040517f9469744400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61321084612256846112eb565b61321e84836020013561261e565b428261012001351161119a576040517fc56873ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f8351604103613293576020840151604085015160608601515f1a613285888285856134af565b95509550955050505061329e565b505081515f91506002905b9250925092565b5f8260038111156132b8576132b8613ef4565b036132c1575050565b60018260038111156132d5576132d5613ef4565b0361330c576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561332057613320613ef4565b0361335f576040517ffce698f7000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b600382600381111561337357613373613ef4565b036122c5576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401613356565b634e487b715f52806020526024601cfd5b5f6133cc6020830183613c16565b90506020820135365f6133e26040860186613d7f565b91509150604051818382375f80838387895af1611944573d5f803e3d5ffd5b5f36816134116040850185613d7f565b90925090506004811061342357813592505b5050919050565b5f8060205f8451602086015f885af180613449576040513d5f823e3d81fd5b50505f513d9150811561346057806001141561346d565b6001600160a01b0384163b155b1561119a576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401613356565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156134e857505f9150600390508261358b565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015613539573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811661358257505f92506001915082905061358b565b92505f91508190505b9450945094915050565b5f805f604084860312156135a7575f80fd5b83359250602084013567ffffffffffffffff808211156135c5575f80fd5b818601915086601f8301126135d8575f80fd5b8135818111156135e6575f80fd5b8760208285010111156135f7575f80fd5b6020830194508093505050509250925092565b5f60a0828403121561361a575f80fd5b50919050565b5f60a08284031215613630575f80fd5b6104d0838361360a565b6001600160a01b0381168114610c89575f80fd5b80356136598161363a565b919050565b5f610260828403121561361a575f80fd5b5f8083601f84011261367f575f80fd5b50813567ffffffffffffffff811115613696575f80fd5b6020830191508360208260051b85010111156136b0575f80fd5b9250929050565b5f6040828403121561361a575f80fd5b5f6060828403121561361a575f80fd5b5f805f805f805f805f6101008a8c0312156136f0575f80fd5b6136f98a61364e565b985060208a0135975060408a013567ffffffffffffffff8082111561371c575f80fd5b6137288d838e0161365e565b985060608c013591508082111561373d575f80fd5b6137498d838e0161366f565b909850965060808c0135915080821115613761575f80fd5b61376d8d838e016136b7565b955060a08c0135915080821115613782575f80fd5b61378e8d838e016136c7565b945060c08c01359150808211156137a3575f80fd5b6137af8d838e016136c7565b935060e08c01359150808211156137c4575f80fd5b506137d18c828d016136c7565b9150509295985092959850929598565b5f80604083850312156137f2575f80fd5b82356137fd8161363a565b9150602083013567ffffffffffffffff811115613818575f80fd5b613824858286016136b7565b9150509250929050565b5f610160828403121561361a575f80fd5b5f805f805f60a08688031215613853575f80fd5b853561385e8161363a565b9450602086013567ffffffffffffffff8082111561387a575f80fd5b61388689838a0161382e565b9550604088013591508082111561389b575f80fd5b6138a789838a016136c7565b94506060880135935060808801359150808211156138c3575f80fd5b506138d0888289016136c7565b9150509295509295909350565b5f602082840312156138ed575f80fd5b5035919050565b8015158114610c89575f80fd5b5f805f805f8060a08789031215613916575f80fd5b86356139218161363a565b955060208701356139318161363a565b94506040870135613941816138f4565b9350606087013567ffffffffffffffff8082111561395d575f80fd5b6139698a838b0161365e565b9450608089013591508082111561397e575f80fd5b5061398b89828a0161366f565b979a9699509497509295939492505050565b5f805f606084860312156139af575f80fd5b83356139ba8161363a565b925060208401359150604084013567ffffffffffffffff8111156139dc575f80fd5b6139e8868287016136c7565b9150509250925092565b5f60208284031215613a02575f80fd5b813567ffffffffffffffff811115613a18575f80fd5b611bd38482850161382e565b5f805f805f805f8060e0898b031215613a3b575f80fd5b613a448961364e565b975060208901359650604089013567ffffffffffffffff80821115613a67575f80fd5b613a738c838d0161365e565b975060608b0135915080821115613a88575f80fd5b613a948c838d0161366f565b909750955060808b0135915080821115613aac575f80fd5b613ab88c838d016136b7565b945060a08b0135915080821115613acd575f80fd5b613ad98c838d016136c7565b935060c08b0135915080821115613aee575f80fd5b50613afb8b828c016136c7565b9150509295985092959890939650565b5f805f805f8060c08789031215613b20575f80fd5b613b298761364e565b9550602087013567ffffffffffffffff80821115613b45575f80fd5b613b518a838b0161382e565b96506040890135915080821115613b66575f80fd5b613b728a838b016136c7565b9550606089013594506080890135915080821115613b8e575f80fd5b613b9a8a838b016136c7565b935060a0890135915080821115613baf575f80fd5b50613bbc89828a016136c7565b9150509295509295509295565b5f60208284031215613bd9575f80fd5b813567ffffffffffffffff811115613bef575f80fd5b611bd38482850161365e565b5f60208284031215613c0b575f80fd5b81516104d0816138f4565b5f60208284031215613c26575f80fd5b81356104d08161363a565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b803565ffffffffffff81168114613659575f80fd5b5f6001600160a01b0380871683528086166020840152508360408301526080606083015282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ce2575f80fd5b830160208101903567ffffffffffffffff811115613cfe575f80fd5b803603821315613d0c575f80fd5b60606080850152613d2160e085018284613c31565b915050613d3060208501613c78565b65ffffffffffff80821660a086015280613d4c60408801613c78565b1660c086015250508091505095945050505050565b5f60208284031215613d71575f80fd5b8135600381106104d0575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613db2575f80fd5b83018035915067ffffffffffffffff821115613dcc575f80fd5b6020019150368190038213156136b0575f80fd5b818382375f9101908152919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e22575f80fd5b83018035915067ffffffffffffffff821115613e3c575f80fd5b6020019150600581901b36038213156136b0575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112613eb2575f80fd5b9190910192915050565b80820180821115612efa577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613f31575f80fd5b8135600481106104d0575f80fd5b838152604060208201525f611c60604083018486613c31565b5f60208284031215613f68575f80fd5b81517fffffffff00000000000000000000000000000000000000000000000000000000811681146104d0575f80fd5b602081525f611bd3602083018486613c31565b5f81515f5b81811015613fc95760208185018101518683015201613faf565b505f93019283525090919050565b5f611bd3613fe58386613faa565b84613faa565b5f613ff68286613faa565b93845250506020820152604001919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f60a0820190506001600160a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151600381106140a7577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8060808401525092915050565b5f602082840312156140c4575f80fd5b5051919050565b5f80858511156140d9575f80fd5b838611156140e5575f80fd5b5050820193919092039150565b5f805f8060808587031215614105575f80fd5b84356141108161363a565b935060208501356141208161363a565b9250604085013591506060850135614137816138f4565b939692955090935050565b5f805f8060808587031215614155575f80fd5b84356141608161363a565b935060208501356141708161363a565b925060408501356141808161363a565b9396929550929360600135925050565b5f805f805f805f60e0888a0312156141a6575f80fd5b87356141b18161363a565b965060208801356141c18161363a565b955060408801356141d18161363a565b945060608801356141e18161363a565b93506080880135925060a08801356141f88161363a565b8092505060c0880135905092959891949750929550565b5f805f60608486031215614221575f80fd5b833561422c8161363a565b9250602084013561423c8161363a565b929592945050506040919091013590565b5f805f805f60a08688031215614261575f80fd5b853561426c8161363a565b9450602086013561427c8161363a565b9350604086013561428c8161363a565b92506060860135915060808601356142a3816138f4565b809150509295509295909350565b5f60ff8316806142e8577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b8060ff8416069150509291505056fea26469706673582212209be58acada353061a2a202cc7011f3c91393e0f2e305e9202445b042fc4a4ce664736f6c63430008170033", - "sourceMap": "975:10890:90:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7809:308;;;;;;;;;;-1:-1:-1;7809:308:90;;;;;:::i;:::-;;:::i;:::-;;;852:66:169;840:79;;;822:98;;810:2;795:18;7809:308:90;;;;;;;;1318:57;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;1102:74;;1090:2;1075:18;1318:57:90;931:251:169;6790:255:91;;;;;;;;;;;;;:::i;:::-;;;1333:25:169;;;1321:2;1306:18;6790:255:91;1187:177:169;5478:391:91;;;;;;;;;;-1:-1:-1;5478:391:91;;;;;:::i;:::-;;:::i;5859:1907:90:-;;;;;;:::i;:::-;;:::i;:::-;;14436:563:91;;;;;;;;;;-1:-1:-1;14436:563:91;;;;;:::i;:::-;;:::i;1440:48:90:-;;;;;;;;;;;;;;;5092:382:91;;;;;;;;;;-1:-1:-1;5092:382:91;;;;;:::i;:::-;;:::i;4627:523:90:-;;;;;;:::i;:::-;;:::i;4091:109:91:-;;;;;;;;;;-1:-1:-1;4091:109:91;;;;;:::i;:::-;;:::i;7272:1606::-;;;;;;;;;;-1:-1:-1;7272:1606:91;;;;;:::i;:::-;;:::i;15182:1005::-;;;;;;;;;;-1:-1:-1;15182:1005:91;;;;;:::i;:::-;;:::i;6025:761::-;;;;;;;;;;-1:-1:-1;6025:761:91;;;;;:::i;:::-;;:::i;1196:64:90:-;;;;;;;;;;;;;;;2894:1690;;;;;;;;;;-1:-1:-1;2894:1690:90;;;;;:::i;:::-;;:::i;5154:701::-;;;;;;:::i;:::-;;:::i;4336:752:91:-;;;;;;;;;;-1:-1:-1;4336:752:91;;;;;:::i;:::-;;:::i;13818:485::-;;;;;;;;;;-1:-1:-1;13818:485:91;;;;;:::i;:::-;;:::i;7809:308:90:-;7909:6;7923:23;7949:35;7966:5;7973:10;;7949:16;:35::i;:::-;7994:38;;;;;-1:-1:-1;;;;;1120:55:169;;;7994:38:90;;;1102:74:169;7923:61:90;;-1:-1:-1;7994:13:90;:21;;;;;;1075:18:169;;7994:38:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7990:123;;;1905:44:91;8042:26:90;;;;;7990:123;-1:-1:-1;8089:17:90;;-1:-1:-1;7809:308:90;;;;;;:::o;6790:255:91:-;6839:7;6878:16;6861:13;:33;:179;;6946:93;;;1026:66;6946:93;;;13746:25:169;879:32:91;13787:18:169;;;13780:34;;;;957:14:91;13830:18:169;;;13823:34;7010:13:91;13873:18:169;;;13866:34;7033:4:91;13916:19:169;;;13909:84;13718:19;;6946:93:91;;;;;;;;;;;;6936:104;;;;;;6854:186;;6790:255;:::o;6861:179::-;-1:-1:-1;6903:24:91;;6790:255::o;5478:391::-;5597:7;2314:68;5694:20;;;;:15;:20;:::i;:::-;5724:15;:22;;;5756:15;:24;;;5790:15;:26;;;5826:15;:24;;;5636:222;;;;;;;;;;;;14543:25:169;;;-1:-1:-1;;;;;14604:55:169;;;;14599:2;14584:18;;14577:83;14691:2;14676:18;;14669:34;;;;14734:2;14719:18;;14712:34;14777:3;14762:19;;14755:35;14821:3;14806:19;;14799:35;14530:3;14515:19;;14256:584;5636:222:91;;;;;;;;;;;;;5619:245;;;;;;5612:252;;5478:391;;;:::o;5859:1907:90:-;2500:21:44;:19;:21::i;:::-;6282:30:90::1;::::0;;;;-1:-1:-1;;;;;1120:55:169;;;6282:30:90::1;::::0;::::1;1102:74:169::0;6282:13:90::1;:21;::::0;::::1;::::0;1075:18:169;;6282:30:90::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6277:54;;6321:10;;;;;;;;;;;;;;6277:54;6366:30:::0;;;::::1;6406:22:::0;;;;;:80:::1;;-1:-1:-1::0;6454:32:90;;;::::1;6432:54:::0;::::1;;6406:80;6402:254;;;6516:133;6537:18:::0;6557:30;;;::::1;6589:32:::0;;;::::1;6623:18;6516:11;:133::i;:::-;6496:153;;6402:254;6662:130;6683:10;6695:7;6704:17;6723:6;6731:13;;6746:6;6754:15;6771;6662:13;:130::i;:::-;-1:-1:-1::0;;;;;6799:15:90::1;:28;;6835:22;::::0;;;::::1;::::0;::::1;;:::i;:::-;6859:25;::::0;;;:20:::1;::::0;::::1;:25;:::i;:::-;6886:32;6799:143:::0;;::::1;::::0;;;;;;::::1;::::0;;;6886:32;;;::::1;::::0;6920:16;;6799:143:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;6949:357;6970:6;6984:7;6999:17;7024:18;7046:1;7024:23;:80;;;-1:-1:-1::0;7072:32:90;;;::::1;7051:53:::0;::::1;7024:80;:152;;7158:18;7024:152;;;7115:32:::0;;;::::1;7024:152;7184:6:::0;7198:13;;7219:42:::1;7269:31;::::0;;;::::1;::::0;::::1;;:::i;:::-;6949:13;:357::i;:::-;7336:12;;::::0;::::1;:6:::0;:12:::1;:::i;:::-;7318:443;;;;;;;:::i;:::-;;::::0;;;;::::1;::::0;;::::1;7356:13;::::0;;;::::1;::::0;::::1;;:::i;:::-;7377:22;::::0;;;::::1;::::0;::::1;;:::i;:::-;7407:25;::::0;;;:20:::1;::::0;::::1;:25;:::i;:::-;7440:26;::::0;;;:21:::1;::::0;::::1;:26;:::i;:::-;7474:23:::0;;;:80:::1;;-1:-1:-1::0;7522:32:90;;;::::1;7501:53:::0;::::1;7474:80;:147;;7603:18;7474:147;;;7565:27:::0;;;::::1;7474:147;7650:30:::0;;;::::1;7629:51:::0;::::1;:102;;7714:17;7629:102;;;7683:28:::0;;;::::1;7629:102;7739:6;:16;;;;;;;;;;:::i;:::-;7318:443;::::0;;-1:-1:-1;;;;;18257:15:169;;;18239:34;;18309:15;;;18304:2;18289:18;;18282:43;18361:15;;;18341:18;;;18334:43;;;;18413:15;;;18408:2;18393:18;;18386:43;18460:3;18445:19;;18438:35;18504:3;18489:19;;18482:35;18554:15;;;18548:3;18533:19;;18526:44;18165:3;18150:19;7318:443:90::1;;;;;;;6271:1495;2542:20:44::0;1857:1;3068:21;;2888:208;2542:20;5859:1907:90;;;;;;;;;:::o;14436:563:91:-;14546:9;14541:225;14561:19;:6;;:19;:::i;:::-;:26;;14557:1;:30;14541:225;;;14602:34;14639:19;:6;;:19;:::i;:::-;14659:1;14639:22;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;14602:59;-1:-1:-1;;;;;;14674:25:91;;;14700:11;;;;14602:59;14700:11;:::i;:::-;14674:38;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;14674:38:91;;;1102:74:169;1075:18;;14674:38:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14670:90;;;14731:20;;;;;;;;;;;;;;14670:90;-1:-1:-1;14589:3:91;;14541:225;;;;14777:9;14772:223;14792:18;;;;:6;:18;:::i;:::-;:25;;14788:1;:29;14772:223;;;14832:34;14869:18;;;;:6;:18;:::i;:::-;14888:1;14869:21;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;14832:58;-1:-1:-1;;;;;;14903:25:91;;;14929:11;;;;14832:58;14929:11;:::i;:::-;14903:38;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;14903:38:91;;;1102:74:169;1075:18;;14903:38:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14899:90;;;14960:20;;;;;;;;;;;;;;14899:90;-1:-1:-1;14819:3:91;;14772:223;;;;14436:563;;:::o;5092:382::-;5208:7;2182:67;5304:19;;;;:14;:19;:::i;4627:523:90:-;4876:62;4914:6;4922:15;4876:37;:62::i;:::-;4944:201;4971:7;4986:6;5000:15;5023:18;5049:41;5098;4944:19;:201::i;:::-;4627:523;;;;;:::o;4091:109:91:-;4155:40;4177:10;4189:5;4155:21;:40::i;:::-;4091:109;:::o;7272:1606::-;7498:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7498:27:91;7537:9;7532:1297;7548:24;;;7532:1297;;;7587:41;7631:13;;7645:1;7631:16;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;7587:60;-1:-1:-1;7655:23:91;;7681:20;;;;7587:60;7681:20;:::i;:::-;7655:46;;-1:-1:-1;7655:46:91;-1:-1:-1;;;;;;7714:25:91;;;7740:18;;;;:11;:18;:::i;:::-;7714:45;;;;;;;;;;-1:-1:-1;;;;;1120:55:169;;;7714:45:91;;;1102:74:169;1075:18;;7714:45:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7710:1113;;;7771:10;7796:14;7792:52;;;7819:25;;;;;;;;;;;;;;7792:52;7878:1;7859:20;;7855:119;;-1:-1:-1;7923:29:91;;7855:119;7988:33;;;;;7984:831;;8049:45;8068:8;;8078:7;8087:6;8049:18;:45::i;:::-;8035:1;:10;;:59;;;;;;;:::i;:::-;;;-1:-1:-1;7984:831:91;;;8115:33;;;;;8111:704;;8176:45;8195:8;;8205:7;8214:6;8176:18;:45::i;:::-;8162:1;:10;;:59;;;;;;;:::i;8111:704::-;8242:39;;;;;8238:577;;8340:50;8364:8;;8374:7;8383:6;8340:23;:50::i;:::-;8317:19;;;8295:95;8296:19;;;8295:95;;;8402:10;;;:33;;;;8295:95;;8402:33;:::i;:::-;;;-1:-1:-1;8461:19:91;;;;8447:10;;;:33;;;;8461:19;;8447:33;:::i;8238:577::-;8501:32;;;;;8497:318;;8560:44;8578:8;;8588:7;8597:6;8560:17;:44::i;:::-;8547:57;;:1;;:57;;;;;:::i;8497:318::-;8625:35;;;;;8621:194;;8690:47;8711:8;;8721:7;8730:6;8690:20;:47::i;:::-;8674:1;:12;;:63;;;;;;;:::i;8621:194::-;8773:31;;;;;;;;;;;;;;8621:194;7761:1062;7710:1113;7579:1250;;;7574:3;;;;;7532:1297;;;;8835:38;8863:6;8871:1;8835:27;:38::i;:::-;7492:1386;7272:1606;;;;;;:::o;15182:1005::-;15364:21;15336:24;;;;:10;:24;:::i;:::-;:49;;;;;;;;:::i;:::-;;15332:851;;-1:-1:-1;;;;;15399:72:91;;:50;15416:5;15423:25;;;;:10;:25;:::i;:::-;15399:16;:50::i;:::-;-1:-1:-1;;;;;15399:72:91;;15395:128;;15490:24;;;;;;;;;;;;;;15332:851;15567:22;15539:24;;;;:10;:24;:::i;:::-;:50;;;;;;;;:::i;:::-;;15535:648;;15655:20;15599:19;15645:31;;;15692:2;15685:17;;;15739:2;15726:16;;-1:-1:-1;;;;;15761:78:91;;:56;15726:16;15791:25;;;;:10;:25;:::i;15761:56::-;-1:-1:-1;;;;;15761:78:91;;15757:135;;15858:25;;;;;;;;;;;;;;15757:135;15591:307;14772:223;14436:563;;:::o;15535:648::-;15936:22;15908:24;;;;:10;:24;:::i;:::-;:50;;;;;;;;:::i;:::-;;15904:279;;15972:102;-1:-1:-1;;;;;15972:45:91;;;16018:5;16025:25;;;;:10;:25;:::i;:::-;15972:79;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:102;;;15968:159;;16093:25;;;;;;;;;;;;;;15904:279;16154:22;;;;;;;;;;;;;;6025:761;6124:7;6209:18;:16;:18::i;:::-;2011:107;6381:12;:6;;:12;:::i;:::-;6370:24;;;;;;;;;:::i;:::-;;;;;;;;;;;;;6360:35;;;;;;6397:6;:12;;;6411:6;:13;;;;;;;;;;:::i;:::-;6323:102;;;;;;22262:25:169;;;;22303:18;;22296:34;;;;22346:18;;;22339:34;-1:-1:-1;;;;;22409:55:169;22389:18;;;22382:83;22234:19;;6323:102:91;;;;;;;;;;;;;6465:22;;;;;;;;:::i;:::-;6503:16;;;;;;;;:::i;:::-;6535:17;;;;;;;;:::i;:::-;6568:22;;;;6606:23;;;;6645:20;;;;6681:18;;;;6715:16;;;;;;;;:::i;:::-;6439:306;;;-1:-1:-1;;;;;22898:15:169;;;6439:306:91;;;22880:34:169;22950:15;;;22930:18;;;22923:43;23002:15;;;22982:18;;;22975:43;23034:18;;;23027:34;;;;23077:19;;;23070:35;;;;23121:19;;;23114:35;23165:19;;;23158:35;23230:15;;;23209:19;;;23202:44;22791:19;;6439:306:91;;;;;;;;;;;;;;6258:499;;;6439:306;6258:499;;:::i;:::-;;;;;;;;;;;;;6237:530;;;;;;6163:612;;;;;;;;24120:66:169;24108:79;;24212:1;24203:11;;24196:27;;;;24248:2;24239:12;;24232:28;24285:2;24276:12;;23850:444;2894:1690:90;2500:21:44;:19;:21::i;:::-;2266:34:90::1;::::0;;;;2289:10:::1;2266:34;::::0;::::1;1102:74:169::0;2266:13:90::1;-1:-1:-1::0;;;;;2266:22:90::1;::::0;::::1;::::0;1075:18:169;;2266:34:90::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2261:59;;2309:11;;;;;;;;;;;;;;2261:59;3251:30:::2;::::0;;;;-1:-1:-1;;;;;1120:55:169;;;3251:30:90::2;::::0;::::2;1102:74:169::0;3251:13:90::2;:21;::::0;::::2;::::0;1075:18:169;;3251:30:90::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3246:54;;3290:10;;;;;;;;;;;;;;3246:54;3335:30:::0;;;::::2;3375:22:::0;;;;;:80:::2;;-1:-1:-1::0;3423:32:90;;;::::2;3401:54:::0;::::2;;3375:80;3371:254;;;3485:133;3506:18:::0;3526:30;;;::::2;3558:32:::0;;;::::2;3592:18;3485:11;:133::i;:::-;3465:153;;3371:254;3631:130;3652:10;3664:7;3673:17;3692:6;3700:13;;3715:6;3723:15;3740;3631:13;:130::i;:::-;3768:356;3789:6:::0;3803:7;3818:17;3843:23;;;:80:::2;;-1:-1:-1::0;3891:32:90;;;::::2;3870:53:::0;::::2;3843:80;:152;;3977:18;3843:152;;;3934:32:::0;;;::::2;3843:152;4003:6:::0;4017:13;;4038:41:::2;4087:31;::::0;;;::::2;::::0;::::2;;:::i;3768:356::-;4154:12;;::::0;::::2;:6:::0;:12:::2;:::i;:::-;4136:443;;;;;;;:::i;:::-;;::::0;;;;::::2;::::0;;::::2;4174:13;::::0;;;::::2;::::0;::::2;;:::i;:::-;4195:22;::::0;;;::::2;::::0;::::2;;:::i;:::-;4225:25;::::0;;;:20:::2;::::0;::::2;:25;:::i;:::-;4258:26;::::0;;;:21:::2;::::0;::::2;:26;:::i;:::-;4292:23:::0;;;:80:::2;;-1:-1:-1::0;4340:32:90;;;::::2;4319:53:::0;::::2;4292:80;:147;;4421:18;4292:147;;;4383:27:::0;;;::::2;4292:147;4468:30:::0;;;::::2;4447:51:::0;::::2;:102;;4532:17;4447:102;;;4501:28:::0;;;::::2;4447:102;4557:6;:16;;;;;;;;;;:::i;:::-;4136:443;::::0;;-1:-1:-1;;;;;18257:15:169;;;18239:34;;18309:15;;;18304:2;18289:18;;18282:43;18361:15;;;18341:18;;;18334:43;;;;18413:15;;;18408:2;18393:18;;18386:43;18460:3;18445:19;;18438:35;18504:3;18489:19;;18482:35;18554:15;;;18548:3;18533:19;;18526:44;18165:3;18150:19;4136:443:90::2;;;;;;;3240:1344;2542:20:44::0;1857:1;3068:21;;2888:208;2542:20;2894:1690:90;;;;;;;;:::o;5154:701::-;5472:62;5510:6;5518:15;5472:37;:62::i;:::-;-1:-1:-1;;;;;5540:15:90;:28;;5569:22;;;;;;;;:::i;:::-;5593:16;;;;;;;;:::i;:::-;5611:6;:22;;;5635:16;5540:112;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5658:192;5685:7;5700:6;5714:15;5737:18;5763:42;5813:15;:31;;;;;;;;;;:::i;:::-;5658:19;:192::i;:::-;5154:701;;;;;;:::o;4336:752:91:-;4428:7;4513:18;:16;:18::i;:::-;2439:220;4714:12;;;;:6;:12;:::i;:::-;4703:24;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;4693:35;;4703:24;4693:35;;;;4744:12;;;;4772:13;;;;;;;;:::i;:::-;4801:22;;;;;;;;:::i;:::-;4839:18;;;;4873:16;;;;;;;;:::i;:::-;4627:312;;;;;;24642:25:169;;;;24683:18;;24676:34;;;;24726:18;;;24719:34;;;;-1:-1:-1;;;;;24850:15:169;;;24830:18;;;24823:43;24903:15;;24882:19;;;24875:44;24935:19;;;24928:35;;;;25000:15;24979:19;;;24972:44;4905:20:91;;;;;25032:19:169;;;25025:35;24614:19;;4627:312:91;;;;;;;;;;;;4953:39;4971:6;:20;;4953:17;:39::i;:::-;5006:41;5025:6;:21;;5006:18;:41::i;:::-;4562:497;;;;;;;;;;:::i;13818:485::-;14034:29;;;;13968:63;14003:28;;;;13968:32;;;;:63;:::i;:::-;:95;;;;:::i;:::-;13929:27;;;;:134;13918:184;;14077:25;;;;;;;;;;;;;;13918:184;14228:30;;;;14160:65;14193:32;;;;14160:30;;;;:65;:::i;:::-;:98;;;;:::i;:::-;14120:28;;;;:138;14109:189;;14272:26;;;;;;;;;;;;;;16423:233;16514:7;16529:14;16546:32;16560:5;16567:10;;16546:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16546:13:91;;-1:-1:-1;;;16546:32:91:i;:::-;16529:49;-1:-1:-1;;;;;;16588:20:91;;16584:48;;16617:15;;;;;;;;;;;;;;16584:48;16645:6;16423:233;-1:-1:-1;;;;16423:233:91:o;2575:307:44:-;1899:1;2702:7;;:18;2698:86;;2743:30;;;;;;;;;;;;;;2698:86;1899:1;2858:7;:17;2575:307::o;9351:238:48:-;9452:7;9506:76;9522:26;9539:8;9522:16;:26::i;:::-;:59;;;;;9580:1;9565:11;9552:25;;;;;:::i;:::-;9562:1;9559;9552:25;:29;9522:59;34914:9:49;34907:17;;34795:145;9506:76:48;9478:25;9485:1;9488;9491:11;9478:6;:25::i;:::-;:104;;;;:::i;:::-;9471:111;9351:238;-1:-1:-1;;;;;9351:238:48:o;17073:1250:91:-;17445:17;17465;17475:6;17465:9;:17::i;:::-;17445:37;;17488:54;17506:7;17515:9;17526:15;17488:17;:54::i;:::-;17567:22;;;;;;;;:::i;:::-;-1:-1:-1;;;;;17553:36:91;:10;-1:-1:-1;;;;;17553:36:91;;17549:223;;17599:69;17617:22;;;;;;;;:::i;:::-;17641:9;17652:15;17599:17;:69::i;:::-;17549:223;;;17693:30;;;;:15;:30;:::i;:::-;:37;;17734:1;17693:42;17689:76;;17744:21;;;;;;;;;;;;;;17689:76;17777:59;17799:22;;;;;;;;:::i;:::-;17823:6;:12;;;17777:21;:59::i;:::-;17865:6;:18;;;17847:15;:36;17843:69;;;17892:20;;;;;;;;;;;;;;17843:69;17939:1;17922:14;:18;:61;;;;;17962:6;:20;;;17945:14;:37;17922:61;17918:93;;;17992:19;;;;;;;;;;;;;;17918:93;18018:28;18039:6;18018:20;:28::i;:::-;18053:34;18067:11;18080:6;18053:13;:34::i;:::-;18094:173;18122:11;18141:7;18173:1;18156:14;:18;:70;;;;-1:-1:-1;18196:30:91;;;;18178:48;;;18156:70;18234:6;18248:13;;18094:20;:173::i;:::-;18274:44;18296:7;18305:6;:12;;;18274:21;:44::i;:::-;17439:884;17073:1250;;;;;;;;;:::o;8812:1368:90:-;9164:40;9184:19;:6;;:19;:::i;:::-;9164;:40::i;:::-;9211:23;9237:60;9269:28;;;;9237:29;;;;:60;:::i;:::-;9211:86;;9304:15;-1:-1:-1;;;;;9304:30:90;;9342:150;;;;;;;;9380:6;:22;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9342:150:90;;;;;9412:4;-1:-1:-1;;;;;9342:150:90;;;;;9419:6;:20;;:25;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9342:150:90;;;;;9446:15;9342:150;;;;9463:21;9342:150;;;;;;;;:::i;:::-;;;;9304:194;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9505:15;-1:-1:-1;;;;;9505:30:90;;9543:155;;;;;;;;9581:6;:22;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9543:155:90;;;;;9605:6;:16;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9543:155:90;;;;;9623:6;:20;;:25;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9543:155:90;;;;;9650:17;9543:155;;;;9669:21;9543:155;;;;;;;;:::i;:::-;;;;9505:199;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9711:34;9731:13;;9711:19;:34::i;:::-;9752:15;-1:-1:-1;;;;;9752:30:90;;9790:138;;;;;;;;9828:7;-1:-1:-1;;;;;9790:138:90;;;;;9837:6;:13;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9790:138:90;;;;;9852:6;:21;;:26;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;9790:138:90;;;;;9880:17;9790:138;;;;9899:21;9790:138;;;;;;;;:::i;:::-;;;;9752:182;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9941:39:90;;-1:-1:-1;9961:18:90;;-1:-1:-1;;9961:18:90;;;:6;:18;:::i;9941:39::-;9987:15;10012:25;;;;:20;;;:25;:::i;:::-;10005:58;;;;;10057:4;10005:58;;;1102:74:169;-1:-1:-1;;;;;10005:43:90;;;;;;;1075:18:169;;10005:58:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9987:76;-1:-1:-1;10074:12:90;;10070:106;;10096:73;10143:16;;;;;;;;:::i;:::-;10161:7;10103:6;:20;;:25;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;10096:46:90;;:73;:46;:73::i;:::-;9158:1022;;8812:1368;;;;;;;;;:::o;18485:482:91:-;18673:22;;;;;;;;:::i;:::-;-1:-1:-1;;;;;18659:36:91;:10;-1:-1:-1;;;;;18659:36:91;;18655:237;;18705:83;18723:22;;;;;;;;:::i;:::-;18747:23;18763:6;18747:15;:23::i;:::-;18772:15;18705:17;:83::i;:::-;18655:237;;;18813:30;;;;:15;:30;:::i;:::-;:37;;18854:1;18813:42;18809:76;;18864:21;;;;;;;;;;;;;;18809:76;18897:65;18925:22;;;;;;;;:::i;:::-;18949:6;:12;;;18897:27;:65::i;:::-;18485:482;;:::o;10379:1484:90:-;10694:23;;;;10727;;;;;:70;;;10775:6;:22;;;10754:18;:43;10727:70;10723:216;;;10832:100;10844:18;10864:6;:23;;;10889:6;:22;;;10913:18;10832:11;:100::i;:::-;10807:125;;10723:216;10945:70;10966:7;10975:14;10991:6;10999:15;10945:20;:70::i;:::-;11022:15;-1:-1:-1;;;;;11022:30:90;;11060:297;;;;;;;;11098:6;:22;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11060:297:90;;;;;11130:16;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11060:297:90;;;;;11156:16;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11060:297:90;;;;;11182:23;;;:70;;;11230:6;:22;;;11209:18;:43;11182:70;:136;;11300:18;11182:136;;;11265:6;:22;;;11182:136;11060:297;;;;11328:21;11060:297;;;;;;;;:::i;:::-;;;;11022:341;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11370:15;-1:-1:-1;;;;;11370:30:90;;11408:110;;;;;;;;11437:7;-1:-1:-1;;;;;11408:110:90;;;;;11446:6;:13;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11408:110:90;;;;;11461:17;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11408:110:90;;;;;11480:14;11408:110;;;;11496:21;11408:110;;;;;;;;:::i;:::-;;;;11370:154;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11554:12:90;;-1:-1:-1;11554:6:90;;-1:-1:-1;11554:6:90;;-1:-1:-1;11554:12:90;:::i;:::-;11536:322;;;;;;;:::i;:::-;;;;;;;;;11574:6;:13;;;;;;;;;;:::i;:::-;11595:22;;;;;;;;:::i;:::-;11625:16;;;;;;;;:::i;:::-;11649:17;;;;;;;;:::i;:::-;11674:23;;;:70;;;11722:6;:22;;;11701:18;:43;11674:70;:132;;11788:18;11674:132;;;11755:6;:22;;;11674:132;11814:14;11836:6;:16;;;;;;;;;;:::i;:::-;11536:322;;;-1:-1:-1;;;;;18257:15:169;;;18239:34;;18309:15;;;18304:2;18289:18;;18282:43;18361:15;;;18341:18;;;18334:43;;;;18413:15;;;18408:2;18393:18;;18386:43;18460:3;18445:19;;18438:35;18504:3;18489:19;;18482:35;18554:15;;;18548:3;18533:19;;18526:44;18165:3;18150:19;11536:322:90;;;;;;;10663:1200;10379:1484;;;;;;:::o;20053:172:91:-;-1:-1:-1;;;;;20136:16:91;;:7;:16;;;;;;;;;;;:24;;;;;;;;;;;20132:51;;;20169:14;;;;;;;;;;;;;;20132:51;-1:-1:-1;;;;;20189:16:91;;;:7;:16;;;;;;;;;;;:24;;;;;;;:31;;;;20216:4;20189:31;;;20053:172::o;9090:497::-;9242:7;;;;9321:12;:8;9330:1;9321:8;;:12;:::i;:::-;9310:59;;;;;;;:::i;:::-;-1:-1:-1;9257:112:91;;-1:-1:-1;9257:112:91;-1:-1:-1;9257:112:91;-1:-1:-1;9388:25:91;;;;:20;;;:25;:::i;:::-;-1:-1:-1;;;;;9379:34:91;:5;-1:-1:-1;;;;;9379:34:91;;9375:61;;9422:14;;;;;;;;;;;;;;9375:61;9457:8;-1:-1:-1;;;;;9446:19:91;:7;-1:-1:-1;;;;;9446:19:91;;9442:47;;9474:15;;;;;;;;;;;;;;9442:47;9509:29;;;;9499:39;;9495:67;;9547:15;;;;;;;;;;;;;;9495:67;9576:6;9090:497;-1:-1:-1;;;;;;;9090:497:91:o;9799:589::-;9951:7;;;;;10053:12;:8;10062:1;10053:8;;:12;:::i;:::-;10042:62;;;;;;;:::i;:::-;9966:138;;-1:-1:-1;9966:138:91;;-1:-1:-1;9966:138:91;-1:-1:-1;9966:138:91;-1:-1:-1;10123:26:91;;;;:21;;;:26;:::i;:::-;-1:-1:-1;;;;;10114:35:91;:5;-1:-1:-1;;;;;10114:35:91;;10110:62;;10158:14;;;;;;;;;;;;;;10110:62;10193:8;-1:-1:-1;;;;;10182:19:91;:7;-1:-1:-1;;;;;10182:19:91;;10178:47;;10210:15;;;;;;;;;;;;;;10178:47;10247:13;;;;;;;;:::i;:::-;-1:-1:-1;;;;;10235:25:91;:8;-1:-1:-1;;;;;10235:25:91;;10231:58;;10269:20;;;;;;;;;;;;;;10231:58;10309:30;;;;10299:40;;10295:68;;10348:15;;;;;;;;;;;;;;10295:68;10377:6;9799:589;-1:-1:-1;;;;;;;;9799:589:91:o;10633:953::-;10790:7;10799;10822:13;10843:16;10867:14;10889:17;10914:14;10936:18;10962:19;11001:8;;11010:1;11001:12;;;;;;;;;:::i;:::-;10990:89;;;;;;;:::i;:::-;10814:265;;-1:-1:-1;10814:265:91;;-1:-1:-1;10814:265:91;;-1:-1:-1;10814:265:91;-1:-1:-1;10814:265:91;-1:-1:-1;10814:265:91;-1:-1:-1;10814:265:91;-1:-1:-1;11098:26:91;;;;:21;;;:26;:::i;:::-;-1:-1:-1;;;;;11089:35:91;:5;-1:-1:-1;;;;;11089:35:91;;11085:62;;11133:14;;;;;;;;;;;;;;11085:62;11168:8;-1:-1:-1;;;;;11157:19:91;:7;-1:-1:-1;;;;;11157:19:91;;11153:47;;11185:15;;;;;;;;;;;;;;11153:47;-1:-1:-1;;;;;11210:23:91;;11228:4;11210:23;11206:51;;11242:15;;;;;;;;;;;;;;11206:51;11280:13;;;;;;;;:::i;:::-;-1:-1:-1;;;;;11267:26:91;:9;-1:-1:-1;;;;;11267:26:91;;11263:59;;11302:20;;;;;;;;;;;;;;11263:59;11342:30;;;;11332:40;;11328:68;;11381:15;;;;;;;;;;;;;;11328:68;11420:25;;;;:20;;;:25;:::i;:::-;-1:-1:-1;;;;;11406:39:91;:10;-1:-1:-1;;;;;11406:39:91;;11402:66;;11454:14;;;;;;;;;;;;;;11402:66;11493:29;;;;11478:44;;11474:72;;11531:15;;;;;;;;;;;;;;11474:72;11561:6;;;;-1:-1:-1;10633:953:91;;-1:-1:-1;;;;;;;;;;10633:953:91:o;11796:488::-;11947:7;;;;12025:12;:8;12034:1;12025:8;;:12;:::i;:::-;12014:53;;;;;;;:::i;:::-;11962:105;;-1:-1:-1;11962:105:91;-1:-1:-1;11962:105:91;-1:-1:-1;12086:25:91;;;;:20;;;:25;:::i;:::-;-1:-1:-1;;;;;12077:34:91;:5;-1:-1:-1;;;;;12077:34:91;;12073:61;;12120:14;;;;;;;;;;;;;;12073:61;12155:8;-1:-1:-1;;;;;12144:19:91;:7;-1:-1:-1;;;;;12144:19:91;;12140:47;;12172:15;;;;;;;;;;;;;;12140:47;12207:28;;;;12197:38;;12193:66;;12244:15;;;;;;;;;;;;;;12500:602;12654:7;;;;;12758:12;:8;12767:1;12758:8;;:12;:::i;:::-;12747:68;;;;;;;:::i;:::-;-1:-1:-1;12669:146:91;;-1:-1:-1;12669:146:91;;-1:-1:-1;12669:146:91;-1:-1:-1;12669:146:91;-1:-1:-1;12834:26:91;;;;:21;;;:26;:::i;:::-;-1:-1:-1;;;;;12825:35:91;:5;-1:-1:-1;;;;;12825:35:91;;12821:62;;12869:14;;;;;;;;;;;;;;12821:62;12904:9;-1:-1:-1;;;;;12893:20:91;:7;-1:-1:-1;;;;;12893:20:91;;12889:48;;12922:15;;;;;;;;;;;;;;12889:48;12959:13;;;;;;;;:::i;:::-;-1:-1:-1;;;;;12947:25:91;:8;-1:-1:-1;;;;;12947:25:91;;12943:58;;12981:20;;;;;;;;;;;;;;12943:58;13021:32;;;;13011:42;;13007:70;;13062:15;;;;;;;;;;;;;;13259:466;13404:9;;13417:28;;;;13404:41;;;:88;;-1:-1:-1;13449:10:91;;;;13463:29;;;;13449:43;;13404:88;13400:153;;;13509:37;;;;;;;;;;;;;;13400:153;13563:12;;;;13579:32;;;;13563:48;;;:96;;-1:-1:-1;13615:10:91;;;;13629:30;;;;13615:44;;13563:96;13559:162;;;13676:38;;;;;;;;;;;;;;3714:255:45;3792:7;3812:17;3831:18;3851:16;3871:27;3882:4;3888:9;3871:10;:27::i;:::-;3811:87;;;;;;3908:28;3920:5;3927:8;3908:11;:28::i;:::-;-1:-1:-1;3953:9:45;;-1:-1:-1;;3714:255:45;;;;;:::o;29533:122:48:-;29601:4;29642:1;29630:8;29624:15;;;;;;;;:::i;:::-;:19;;;;:::i;:::-;:24;;29647:1;29624:24;29617:31;;29533:122;;;:::o;4996:4226::-;5078:14;5449:5;;;5078:14;5634:6;5453:1;5449;5621:20;5694:5;5690:2;5687:13;5679:5;5675:2;5671:14;5667:34;5658:43;;;5796:5;5805:1;5796:10;5792:368;;6134:11;6126:5;:19;;;;;:::i;:::-;;6119:26;;;;;;5792:368;6285:5;6270:11;:20;6266:143;;6310:84;3066:5;6330:16;;3065:36;940:4:43;3060:42:48;6310:11;:84::i;:::-;6664:17;6799:11;6796:1;6793;6786:25;7199:12;7229:15;;;7214:31;;7348:22;;;;;8094:1;8075;:15;;8074:21;;8327;;;8323:25;;8312:36;8397:21;;;8393:25;;8382:36;8469:21;;;8465:25;;8454:36;8540:21;;;8536:25;;8525:36;8613:21;;;8609:25;;8598:36;8687:21;;;8683:25;;;8672:36;7597:12;;;;7593:23;;;7618:1;7589:31;6913:20;;;6902:32;;;7709:12;;;;6960:21;;;;7446:16;;;;7700:21;;;;9163:15;;;;;-1:-1:-1;;4996:4226:48;;;;;:::o;8348:460:90:-;8452:9;8447:357;8463:24;;;8447:357;;;8502:41;8546:13;;8560:1;8546:16;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;8502:60;-1:-1:-1;;;;;;8605:15:90;8575:46;:18;;;;8502:60;8575:18;:::i;:::-;-1:-1:-1;;;;;8575:46:90;;8571:79;;8630:20;;;;;;;;;;;;;;8571:79;8658:36;8682:11;8658:23;:36::i;:::-;8720:18;;;;:11;:18;:::i;:::-;-1:-1:-1;;;;;8708:89:90;;8740:11;:17;;;8759:37;8784:11;8759:24;:37::i;:::-;8708:89;;;30953:25:169;;;31026:66;31014:79;;;31009:2;30994:18;;30987:107;30926:18;8708:89:90;;;;;;;-1:-1:-1;8489:3:90;;8447:357;;1219:160:39;1328:43;;;-1:-1:-1;;;;;31297:55:169;;1328:43:39;;;31279:74:169;31369:18;;;;31362:34;;;1328:43:39;;;;;;;;;;31252:18:169;;;;1328:43:39;;;;;;;;;;;;;;1301:71;;1321:5;;1301:19;:71::i;19109:500:91:-;19332:1;19315:14;:18;:61;;;;;19355:6;:20;;;19338:14;:37;19315:61;19311:93;;;19385:19;;;;;;;;;;;;;;19311:93;19410:68;19428:7;19437:23;19453:6;19437:15;:23::i;19410:68::-;19484:50;19512:7;19521:6;:12;;;19484:27;:50::i;:::-;19566:15;19544:6;:18;;;:37;19540:64;;19590:14;;;;;;;;;;;;;;2129:778:45;2232:17;2251:16;2269:14;2299:9;:16;2319:2;2299:22;2295:606;;2604:4;2589:20;;2583:27;2653:4;2638:20;;2632:27;2710:4;2695:20;;2689:27;2337:9;2681:36;2751:25;2762:4;2681:36;2583:27;2632;2751:10;:25::i;:::-;2744:32;;;;;;;;;;;2295:606;-1:-1:-1;;2872:16:45;;2823:1;;-1:-1:-1;2827:35:45;;2295:606;2129:778;;;;;:::o;7280:532::-;7375:20;7366:5;:29;;;;;;;;:::i;:::-;;7362:444;;7280:532;;:::o;7362:444::-;7471:29;7462:5;:38;;;;;;;;:::i;:::-;;7458:348;;7523:23;;;;;;;;;;;;;;7458:348;7576:35;7567:5;:44;;;;;;;;:::i;:::-;;7563:243;;7634:46;;;;;;;;1333:25:169;;;1306:18;;7634:46:45;;;;;;;;7563:243;7710:30;7701:5;:39;;;;;;;;:::i;:::-;;7697:109;;7763:32;;;;;;;;1333:25:169;;;1306:18;;7763:32:45;1187:177:169;1776:194:43;1881:10;1875:4;1868:24;1918:4;1912;1905:18;1949:4;1943;1936:18;582:989:72;649:14;666:18;;;;:11;:18;:::i;:::-;649:35;-1:-1:-1;706:17:72;;;;729:23;690:13;755:20;;;;706:11;755:20;:::i;:::-;729:46;;;;1305:4;1299:11;1366:15;1349;1330:17;1317:65;1465:1;1462;1445:15;1426:17;1419:5;1411:6;1404:5;1399:68;1389:172;;1500:16;1497:1;1494;1479:38;1536:16;1533:1;1526:27;1798:809;1874:13;1895:23;1874:13;1921:20;;;;:11;:20;:::i;:::-;1895:46;;-1:-1:-1;1895:46:72;-1:-1:-1;1970:1:72;1951:20;;1947:656;;2573:15;2560:29;2550:39;;1947:656;1889:718;;1798:809;;;:::o;8370:720:39:-;8450:18;8478:19;8616:4;8613:1;8606:4;8600:11;8593:4;8587;8583:15;8580:1;8573:5;8566;8561:60;8673:7;8663:176;;8717:4;8711:11;8762:16;8759:1;8754:3;8739:40;8808:16;8803:3;8796:29;8663:176;-1:-1:-1;;8916:1:39;8910:8;8866:16;;-1:-1:-1;8942:15:39;;:68;;8994:11;9009:1;8994:16;;8942:68;;;-1:-1:-1;;;;;8960:26:39;;;:31;8942:68;8938:146;;;9033:40;;;;;-1:-1:-1;;;;;1120:55:169;;9033:40:39;;;1102:74:169;1075:18;;9033:40:39;931:251:169;5203:1551:45;5329:17;;;6283:66;6270:79;;6266:164;;;-1:-1:-1;6381:1:45;;-1:-1:-1;6385:30:45;;-1:-1:-1;6417:1:45;6365:54;;6266:164;6541:24;;;6524:14;6541:24;;;;;;;;;31816:25:169;;;31889:4;31877:17;;31857:18;;;31850:45;;;;31911:18;;;31904:34;;;31954:18;;;31947:34;;;6541:24:45;;31788:19:169;;6541:24:45;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6541:24:45;;;;;;-1:-1:-1;;;;;;;6579:20:45;;6575:113;;-1:-1:-1;6631:1:45;;-1:-1:-1;6635:29:45;;-1:-1:-1;6631:1:45;;-1:-1:-1;6615:62:45;;6575:113;6706:6;-1:-1:-1;6714:20:45;;-1:-1:-1;6714:20:45;;-1:-1:-1;5203:1551:45;;;;;;;;;:::o;14:659:169:-;93:6;101;109;162:2;150:9;141:7;137:23;133:32;130:52;;;178:1;175;168:12;130:52;214:9;201:23;191:33;;275:2;264:9;260:18;247:32;298:18;339:2;331:6;328:14;325:34;;;355:1;352;345:12;325:34;393:6;382:9;378:22;368:32;;438:7;431:4;427:2;423:13;419:27;409:55;;460:1;457;450:12;409:55;500:2;487:16;526:2;518:6;515:14;512:34;;;542:1;539;532:12;512:34;587:7;582:2;573:6;569:2;565:15;561:24;558:37;555:57;;;608:1;605;598:12;555:57;639:2;635;631:11;621:21;;661:6;651:16;;;;;14:659;;;;;:::o;1369:163::-;1436:5;1481:3;1472:6;1467:3;1463:16;1459:26;1456:46;;;1498:1;1495;1488:12;1456:46;-1:-1:-1;1520:6:169;1369:163;-1:-1:-1;1369:163:169:o;1537:254::-;1631:6;1684:3;1672:9;1663:7;1659:23;1655:33;1652:53;;;1701:1;1698;1691:12;1652:53;1724:61;1777:7;1766:9;1724:61;:::i;1796:154::-;-1:-1:-1;;;;;1875:5:169;1871:54;1864:5;1861:65;1851:93;;1940:1;1937;1930:12;1955:134;2023:20;;2052:31;2023:20;2052:31;:::i;:::-;1955:134;;;:::o;2094:154::-;2152:5;2197:3;2188:6;2183:3;2179:16;2175:26;2172:46;;;2214:1;2211;2204:12;2253:380;2329:8;2339:6;2393:3;2386:4;2378:6;2374:17;2370:27;2360:55;;2411:1;2408;2401:12;2360:55;-1:-1:-1;2434:20:169;;2477:18;2466:30;;2463:50;;;2509:1;2506;2499:12;2463:50;2546:4;2538:6;2534:17;2522:29;;2606:3;2599:4;2589:6;2586:1;2582:14;2574:6;2570:27;2566:38;2563:47;2560:67;;;2623:1;2620;2613:12;2560:67;2253:380;;;;;:::o;2638:153::-;2696:5;2741:2;2732:6;2727:3;2723:16;2719:25;2716:45;;;2757:1;2754;2747:12;2796:162;2863:5;2908:2;2899:6;2894:3;2890:16;2886:25;2883:45;;;2924:1;2921;2914:12;2963:1853;3295:6;3303;3311;3319;3327;3335;3343;3351;3359;3412:3;3400:9;3391:7;3387:23;3383:33;3380:53;;;3429:1;3426;3419:12;3380:53;3452:29;3471:9;3452:29;:::i;:::-;3442:39;;3528:2;3517:9;3513:18;3500:32;3490:42;;3583:2;3572:9;3568:18;3555:32;3606:18;3647:2;3639:6;3636:14;3633:34;;;3663:1;3660;3653:12;3633:34;3686:65;3743:7;3734:6;3723:9;3719:22;3686:65;:::i;:::-;3676:75;;3804:2;3793:9;3789:18;3776:32;3760:48;;3833:2;3823:8;3820:16;3817:36;;;3849:1;3846;3839:12;3817:36;3888:85;3965:7;3954:8;3943:9;3939:24;3888:85;:::i;:::-;3992:8;;-1:-1:-1;3862:111:169;-1:-1:-1;4080:3:169;4065:19;;4052:33;;-1:-1:-1;4097:16:169;;;4094:36;;;4126:1;4123;4116:12;4094:36;4149:67;4208:7;4197:8;4186:9;4182:24;4149:67;:::i;:::-;4139:77;;4269:3;4258:9;4254:19;4241:33;4225:49;;4299:2;4289:8;4286:16;4283:36;;;4315:1;4312;4305:12;4283:36;4338:76;4406:7;4395:8;4384:9;4380:24;4338:76;:::i;:::-;4328:86;;4467:3;4456:9;4452:19;4439:33;4423:49;;4497:2;4487:8;4484:16;4481:36;;;4513:1;4510;4503:12;4481:36;4536:76;4604:7;4593:8;4582:9;4578:24;4536:76;:::i;:::-;4526:86;;4665:3;4654:9;4650:19;4637:33;4621:49;;4695:2;4685:8;4682:16;4679:36;;;4711:1;4708;4701:12;4679:36;;4734:76;4802:7;4791:8;4780:9;4776:24;4734:76;:::i;:::-;4724:86;;;2963:1853;;;;;;;;;;;:::o;4821:509::-;4936:6;4944;4997:2;4985:9;4976:7;4972:23;4968:32;4965:52;;;5013:1;5010;5003:12;4965:52;5052:9;5039:23;5071:31;5096:5;5071:31;:::i;:::-;5121:5;-1:-1:-1;5177:2:169;5162:18;;5149:32;5204:18;5193:30;;5190:50;;;5236:1;5233;5226:12;5190:50;5259:65;5316:7;5307:6;5296:9;5292:22;5259:65;:::i;:::-;5249:75;;;4821:509;;;;;:::o;5845:155::-;5904:5;5949:3;5940:6;5935:3;5931:16;5927:26;5924:46;;;5966:1;5963;5956:12;6005:1079;6197:6;6205;6213;6221;6229;6282:3;6270:9;6261:7;6257:23;6253:33;6250:53;;;6299:1;6296;6289:12;6250:53;6338:9;6325:23;6357:31;6382:5;6357:31;:::i;:::-;6407:5;-1:-1:-1;6463:2:169;6448:18;;6435:32;6486:18;6516:14;;;6513:34;;;6543:1;6540;6533:12;6513:34;6566:66;6624:7;6615:6;6604:9;6600:22;6566:66;:::i;:::-;6556:76;;6685:2;6674:9;6670:18;6657:32;6641:48;;6714:2;6704:8;6701:16;6698:36;;;6730:1;6727;6720:12;6698:36;6753:76;6821:7;6810:8;6799:9;6795:24;6753:76;:::i;:::-;6743:86;;6876:2;6865:9;6861:18;6848:32;6838:42;;6933:3;6922:9;6918:19;6905:33;6889:49;;6963:2;6953:8;6950:16;6947:36;;;6979:1;6976;6969:12;6947:36;;7002:76;7070:7;7059:8;7048:9;7044:24;7002:76;:::i;:::-;6992:86;;;6005:1079;;;;;;;;:::o;7089:180::-;7148:6;7201:2;7189:9;7180:7;7176:23;7172:32;7169:52;;;7217:1;7214;7207:12;7169:52;-1:-1:-1;7240:23:169;;7089:180;-1:-1:-1;7089:180:169:o;7274:118::-;7360:5;7353:13;7346:21;7339:5;7336:32;7326:60;;7382:1;7379;7372:12;7397:1161;7588:6;7596;7604;7612;7620;7628;7681:3;7669:9;7660:7;7656:23;7652:33;7649:53;;;7698:1;7695;7688:12;7649:53;7737:9;7724:23;7756:31;7781:5;7756:31;:::i;:::-;7806:5;-1:-1:-1;7863:2:169;7848:18;;7835:32;7876:33;7835:32;7876:33;:::i;:::-;7928:7;-1:-1:-1;7987:2:169;7972:18;;7959:32;8000:30;7959:32;8000:30;:::i;:::-;8049:7;-1:-1:-1;8107:2:169;8092:18;;8079:32;8130:18;8160:14;;;8157:34;;;8187:1;8184;8177:12;8157:34;8210:65;8267:7;8258:6;8247:9;8243:22;8210:65;:::i;:::-;8200:75;;8328:3;8317:9;8313:19;8300:33;8284:49;;8358:2;8348:8;8345:16;8342:36;;;8374:1;8371;8364:12;8342:36;;8413:85;8490:7;8479:8;8468:9;8464:24;8413:85;:::i;:::-;7397:1161;;;;-1:-1:-1;7397:1161:169;;-1:-1:-1;7397:1161:169;;8517:8;;7397:1161;-1:-1:-1;;;7397:1161:169:o;8563:574::-;8675:6;8683;8691;8744:2;8732:9;8723:7;8719:23;8715:32;8712:52;;;8760:1;8757;8750:12;8712:52;8799:9;8786:23;8818:31;8843:5;8818:31;:::i;:::-;8868:5;-1:-1:-1;8920:2:169;8905:18;;8892:32;;-1:-1:-1;8975:2:169;8960:18;;8947:32;9002:18;8991:30;;8988:50;;;9034:1;9031;9024:12;8988:50;9057:74;9123:7;9114:6;9103:9;9099:22;9057:74;:::i;:::-;9047:84;;;8563:574;;;;;:::o;9142:355::-;9228:6;9281:2;9269:9;9260:7;9256:23;9252:32;9249:52;;;9297:1;9294;9287:12;9249:52;9337:9;9324:23;9370:18;9362:6;9359:30;9356:50;;;9402:1;9399;9392:12;9356:50;9425:66;9483:7;9474:6;9463:9;9459:22;9425:66;:::i;9767:1602::-;10054:6;10062;10070;10078;10086;10094;10102;10110;10163:3;10151:9;10142:7;10138:23;10134:33;10131:53;;;10180:1;10177;10170:12;10131:53;10203:29;10222:9;10203:29;:::i;:::-;10193:39;;10279:2;10268:9;10264:18;10251:32;10241:42;;10334:2;10323:9;10319:18;10306:32;10357:18;10398:2;10390:6;10387:14;10384:34;;;10414:1;10411;10404:12;10384:34;10437:65;10494:7;10485:6;10474:9;10470:22;10437:65;:::i;:::-;10427:75;;10555:2;10544:9;10540:18;10527:32;10511:48;;10584:2;10574:8;10571:16;10568:36;;;10600:1;10597;10590:12;10568:36;10639:85;10716:7;10705:8;10694:9;10690:24;10639:85;:::i;:::-;10743:8;;-1:-1:-1;10613:111:169;-1:-1:-1;10831:3:169;10816:19;;10803:33;;-1:-1:-1;10848:16:169;;;10845:36;;;10877:1;10874;10867:12;10845:36;10900:67;10959:7;10948:8;10937:9;10933:24;10900:67;:::i;:::-;10890:77;;11020:3;11009:9;11005:19;10992:33;10976:49;;11050:2;11040:8;11037:16;11034:36;;;11066:1;11063;11056:12;11034:36;11089:76;11157:7;11146:8;11135:9;11131:24;11089:76;:::i;:::-;11079:86;;11218:3;11207:9;11203:19;11190:33;11174:49;;11248:2;11238:8;11235:16;11232:36;;;11264:1;11261;11254:12;11232:36;;11287:76;11355:7;11344:8;11333:9;11329:24;11287:76;:::i;:::-;11277:86;;;9767:1602;;;;;;;;;;;:::o;11374:1269::-;11611:6;11619;11627;11635;11643;11651;11704:3;11692:9;11683:7;11679:23;11675:33;11672:53;;;11721:1;11718;11711:12;11672:53;11744:29;11763:9;11744:29;:::i;:::-;11734:39;;11824:2;11813:9;11809:18;11796:32;11847:18;11888:2;11880:6;11877:14;11874:34;;;11904:1;11901;11894:12;11874:34;11927:66;11985:7;11976:6;11965:9;11961:22;11927:66;:::i;:::-;11917:76;;12046:2;12035:9;12031:18;12018:32;12002:48;;12075:2;12065:8;12062:16;12059:36;;;12091:1;12088;12081:12;12059:36;12114:76;12182:7;12171:8;12160:9;12156:24;12114:76;:::i;:::-;12104:86;;12237:2;12226:9;12222:18;12209:32;12199:42;;12294:3;12283:9;12279:19;12266:33;12250:49;;12324:2;12314:8;12311:16;12308:36;;;12340:1;12337;12330:12;12308:36;12363:76;12431:7;12420:8;12409:9;12405:24;12363:76;:::i;:::-;12353:86;;12492:3;12481:9;12477:19;12464:33;12448:49;;12522:2;12512:8;12509:16;12506:36;;;12538:1;12535;12528:12;12506:36;;12561:76;12629:7;12618:8;12607:9;12603:24;12561:76;:::i;:::-;12551:86;;;11374:1269;;;;;;;;:::o;12648:353::-;12733:6;12786:2;12774:9;12765:7;12761:23;12757:32;12754:52;;;12802:1;12799;12792:12;12754:52;12842:9;12829:23;12875:18;12867:6;12864:30;12861:50;;;12907:1;12904;12897:12;12861:50;12930:65;12987:7;12978:6;12967:9;12963:22;12930:65;:::i;13237:245::-;13304:6;13357:2;13345:9;13336:7;13332:23;13328:32;13325:52;;;13373:1;13370;13363:12;13325:52;13405:9;13399:16;13424:28;13446:5;13424:28;:::i;14004:247::-;14063:6;14116:2;14104:9;14095:7;14091:23;14087:32;14084:52;;;14132:1;14129;14122:12;14084:52;14171:9;14158:23;14190:31;14215:5;14190:31;:::i;14845:325::-;14933:6;14928:3;14921:19;14985:6;14978:5;14971:4;14966:3;14962:14;14949:43;;15037:1;15030:4;15021:6;15016:3;15012:16;15008:27;15001:38;14903:3;15159:4;15089:66;15084:2;15076:6;15072:15;15068:88;15063:3;15059:98;15055:109;15048:116;;14845:325;;;;:::o;15175:167::-;15242:20;;15302:14;15291:26;;15281:37;;15271:65;;15332:1;15329;15322:12;15347:1365;15593:4;-1:-1:-1;;;;;15703:2:169;15695:6;15691:15;15680:9;15673:34;15755:2;15747:6;15743:15;15738:2;15727:9;15723:18;15716:43;;15795:6;15790:2;15779:9;15775:18;15768:34;15838:3;15833:2;15822:9;15818:18;15811:31;15890:6;15877:20;15973:66;15964:6;15948:14;15944:27;15940:100;15920:18;15916:125;15906:153;;16055:1;16052;16045:12;15906:153;16081:31;;16189:2;16178:14;;;16135:19;16215:18;16204:30;;16201:50;;;16247:1;16244;16237:12;16201:50;16296:6;16280:14;16276:27;16267:7;16263:41;16260:61;;;16317:1;16314;16307:12;16260:61;16358:2;16352:3;16341:9;16337:19;16330:31;16384:63;16442:3;16431:9;16427:19;16419:6;16410:7;16384:63;:::i;:::-;16370:77;;;16476:34;16506:2;16498:6;16494:15;16476:34;:::i;:::-;16529:14;16598:2;16584:12;16580:21;16574:3;16563:9;16559:19;16552:50;16679:2;16643:34;16673:2;16665:6;16661:15;16643:34;:::i;:::-;16639:43;16633:3;16622:9;16618:19;16611:72;;;16700:6;16692:14;;;15347:1365;;;;;;;:::o;16717:277::-;16797:6;16850:2;16838:9;16829:7;16825:23;16821:32;16818:52;;;16866:1;16863;16856:12;16818:52;16905:9;16892:23;16944:1;16937:5;16934:12;16924:40;;16960:1;16957;16950:12;16999:581;17077:4;17083:6;17143:11;17130:25;17233:66;17222:8;17206:14;17202:29;17198:102;17178:18;17174:127;17164:155;;17315:1;17312;17305:12;17164:155;17342:33;;17394:20;;;-1:-1:-1;17437:18:169;17426:30;;17423:50;;;17469:1;17466;17459:12;17423:50;17502:4;17490:17;;-1:-1:-1;17533:14:169;17529:27;;;17519:38;;17516:58;;;17570:1;17567;17560:12;17585:273;17770:6;17762;17757:3;17744:33;17726:3;17796:16;;17821:13;;;17796:16;17585:273;-1:-1:-1;17585:273:169:o;18581:629::-;18699:4;18705:6;18765:11;18752:25;18855:66;18844:8;18828:14;18824:29;18820:102;18800:18;18796:127;18786:155;;18937:1;18934;18927:12;18786:155;18964:33;;19016:20;;;-1:-1:-1;19059:18:169;19048:30;;19045:50;;;19091:1;19088;19081:12;19045:50;19124:4;19112:17;;-1:-1:-1;19175:1:169;19171:14;;;19155;19151:35;19141:46;;19138:66;;;19200:1;19197;19190:12;19215:184;19267:77;19264:1;19257:88;19364:4;19361:1;19354:15;19388:4;19385:1;19378:15;19404:381;19495:4;19553:11;19540:25;19643:66;19632:8;19616:14;19612:29;19608:102;19588:18;19584:127;19574:155;;19725:1;19722;19715:12;19574:155;19746:33;;;;;19404:381;-1:-1:-1;;19404:381:169:o;20375:279::-;20440:9;;;20461:10;;;20458:190;;;20504:77;20501:1;20494:88;20605:4;20602:1;20595:15;20633:4;20630:1;20623:15;20659:184;20711:77;20708:1;20701:88;20808:4;20805:1;20798:15;20832:4;20829:1;20822:15;20848:266;20917:6;20970:2;20958:9;20949:7;20945:23;20941:32;20938:52;;;20986:1;20983;20976:12;20938:52;21025:9;21012:23;21064:1;21057:5;21054:12;21044:40;;21080:1;21077;21070:12;21119:315;21304:6;21293:9;21286:25;21347:2;21342;21331:9;21327:18;21320:30;21267:4;21367:61;21424:2;21413:9;21409:18;21401:6;21393;21367:61;:::i;21439:336::-;21508:6;21561:2;21549:9;21540:7;21536:23;21532:32;21529:52;;;21577:1;21574;21567:12;21529:52;21609:9;21603:16;21659:66;21652:5;21648:78;21641:5;21638:89;21628:117;;21741:1;21738;21731:12;21780:246;21939:2;21928:9;21921:21;21902:4;21959:61;22016:2;22005:9;22001:18;21993:6;21985;21959:61;:::i;23257:322::-;23298:3;23336:5;23330:12;23360:1;23370:128;23384:6;23381:1;23378:13;23370:128;;;23481:4;23466:13;;;23462:24;;23456:31;23443:11;;;23436:52;23399:12;23370:128;;;-1:-1:-1;23553:1:169;23517:16;;23542:13;;;-1:-1:-1;23517:16:169;;23257:322;-1:-1:-1;23257:322:169:o;23584:261::-;23759:3;23784:55;23809:29;23834:3;23826:6;23809:29;:::i;:::-;23801:6;23784:55;:::i;25071:350::-;25256:3;25287:29;25312:3;25304:6;25287:29;:::i;:::-;25325:21;;;-1:-1:-1;;25373:2:169;25362:14;;25355:30;25412:2;25401:14;;25071:350;-1:-1:-1;25071:350:169:o;25426:184::-;25478:77;25475:1;25468:88;25575:4;25572:1;25565:15;25599:4;25596:1;25589:15;25615:844;25769:4;25811:3;25800:9;25796:19;25788:27;;-1:-1:-1;;;;;25922:2:169;25913:6;25907:13;25903:22;25892:9;25885:41;25994:2;25986:4;25978:6;25974:17;25968:24;25964:33;25957:4;25946:9;25942:20;25935:63;26066:2;26058:4;26050:6;26046:17;26040:24;26036:33;26029:4;26018:9;26014:20;26007:63;;26126:4;26118:6;26114:17;26108:24;26101:4;26090:9;26086:20;26079:54;26180:4;26172:6;26168:17;26162:24;26222:1;26208:12;26205:19;26195:207;;26258:77;26255:1;26248:88;26359:4;26356:1;26349:15;26387:4;26384:1;26377:15;26195:207;26440:12;26433:4;26422:9;26418:20;26411:42;;25615:844;;;;:::o;26464:184::-;26534:6;26587:2;26575:9;26566:7;26562:23;26558:32;26555:52;;;26603:1;26600;26593:12;26555:52;-1:-1:-1;26626:16:169;;26464:184;-1:-1:-1;26464:184:169:o;26653:331::-;26758:9;26769;26811:8;26799:10;26796:24;26793:44;;;26833:1;26830;26823:12;26793:44;26862:6;26852:8;26849:20;26846:40;;;26882:1;26879;26872:12;26846:40;-1:-1:-1;;26908:23:169;;;26953:25;;;;;-1:-1:-1;26653:331:169:o;26989:608::-;27088:6;27096;27104;27112;27165:3;27153:9;27144:7;27140:23;27136:33;27133:53;;;27182:1;27179;27172:12;27133:53;27221:9;27208:23;27240:31;27265:5;27240:31;:::i;:::-;27290:5;-1:-1:-1;27347:2:169;27332:18;;27319:32;27360:33;27319:32;27360:33;:::i;:::-;27412:7;-1:-1:-1;27466:2:169;27451:18;;27438:32;;-1:-1:-1;27522:2:169;27507:18;;27494:32;27535:30;27494:32;27535:30;:::i;:::-;26989:608;;;;-1:-1:-1;26989:608:169;;-1:-1:-1;;26989:608:169:o;27602:622::-;27712:6;27720;27728;27736;27789:3;27777:9;27768:7;27764:23;27760:33;27757:53;;;27806:1;27803;27796:12;27757:53;27845:9;27832:23;27864:31;27889:5;27864:31;:::i;:::-;27914:5;-1:-1:-1;27971:2:169;27956:18;;27943:32;27984:33;27943:32;27984:33;:::i;:::-;28036:7;-1:-1:-1;28095:2:169;28080:18;;28067:32;28108:33;28067:32;28108:33;:::i;:::-;27602:622;;;;-1:-1:-1;28160:7:169;;28214:2;28199:18;28186:32;;-1:-1:-1;;27602:622:169:o;28229:991::-;28382:6;28390;28398;28406;28414;28422;28430;28483:3;28471:9;28462:7;28458:23;28454:33;28451:53;;;28500:1;28497;28490:12;28451:53;28539:9;28526:23;28558:31;28583:5;28558:31;:::i;:::-;28608:5;-1:-1:-1;28665:2:169;28650:18;;28637:32;28678:33;28637:32;28678:33;:::i;:::-;28730:7;-1:-1:-1;28789:2:169;28774:18;;28761:32;28802:33;28761:32;28802:33;:::i;:::-;28854:7;-1:-1:-1;28913:2:169;28898:18;;28885:32;28926:33;28885:32;28926:33;:::i;:::-;28978:7;-1:-1:-1;29032:3:169;29017:19;;29004:33;;-1:-1:-1;29089:3:169;29074:19;;29061:33;29103;29061;29103;:::i;:::-;29155:7;29145:17;;;29209:3;29198:9;29194:19;29181:33;29171:43;;28229:991;;;;;;;;;;:::o;29225:472::-;29318:6;29326;29334;29387:2;29375:9;29366:7;29362:23;29358:32;29355:52;;;29403:1;29400;29393:12;29355:52;29442:9;29429:23;29461:31;29486:5;29461:31;:::i;:::-;29511:5;-1:-1:-1;29568:2:169;29553:18;;29540:32;29581:33;29540:32;29581:33;:::i;:::-;29225:472;;29633:7;;-1:-1:-1;;;29687:2:169;29672:18;;;;29659:32;;29225:472::o;29702:758::-;29818:6;29826;29834;29842;29850;29903:3;29891:9;29882:7;29878:23;29874:33;29871:53;;;29920:1;29917;29910:12;29871:53;29959:9;29946:23;29978:31;30003:5;29978:31;:::i;:::-;30028:5;-1:-1:-1;30085:2:169;30070:18;;30057:32;30098:33;30057:32;30098:33;:::i;:::-;30150:7;-1:-1:-1;30209:2:169;30194:18;;30181:32;30222:33;30181:32;30222:33;:::i;:::-;30274:7;-1:-1:-1;30328:2:169;30313:18;;30300:32;;-1:-1:-1;30384:3:169;30369:19;;30356:33;30398:30;30356:33;30398:30;:::i;:::-;30447:7;30437:17;;;29702:758;;;;;;;;:::o;30465:311::-;30495:1;30529:4;30526:1;30522:12;30553:3;30543:191;;30590:77;30587:1;30580:88;30691:4;30688:1;30681:15;30719:4;30716:1;30709:15;30543:191;30766:3;30759:4;30756:1;30752:12;30748:22;30743:27;;;30465:311;;;;:::o", - "linkReferences": {}, - "immutableReferences": { - "65518": [ - { - "start": 824, - "length": 32 - }, - { - "start": 1042, - "length": 32 - }, - { - "start": 1703, - "length": 32 - }, - { - "start": 5408, - "length": 32 - }, - { - "start": 5631, - "length": 32 - } - ], - "65523": [ - { - "start": 407, - "length": 32 - }, - { - "start": 1978, - "length": 32 - }, - { - "start": 6284, - "length": 32 - }, - { - "start": 7724, - "length": 32 - }, - { - "start": 7966, - "length": 32 - }, - { - "start": 8236, - "length": 32 - }, - { - "start": 8971, - "length": 32 - }, - { - "start": 9255, - "length": 32 - }, - { - "start": 12348, - "length": 32 - } - ], - "65528": [ - { - "start": 599, - "length": 32 - }, - { - "start": 1924, - "length": 32 - }, - { - "start": 5852, - "length": 32 - } - ], - "66488": [ - { - "start": 1444, - "length": 32 - } - ], - "66490": [ - { - "start": 1242, - "length": 32 - } - ] - } - }, - "methodIdentifiers": { - "AUTHENTICATOR()": "c6186181", - "BALANCE_MANAGER()": "29bcdc95", - "DOMAIN_SEPARATOR()": "3644e515", - "REPOSITORY()": "6f35d2d2", - "cancelLimitOrder(uint256)": "a5cdc8fc", - "hashBaseTokenData((address,uint256,uint256,uint256,uint256))": "875530ff", - "hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": "e242924e", - "hashQuoteTokenData((address,uint256,uint256,uint256,uint256))": "4c9e03d3", - "hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))": "b11f1262", - "isValidSignature(bytes32,bytes)": "1626ba7e", - "settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))": "cba673a7", - "settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))": "9935c868", - "settleSingleWithPermitsSignatures(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes),(bytes,uint48,uint48))": "db587728", - "settleWithPermitsSignatures(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes),(bytes,uint48,uint48))": "51d46815", - "validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))": "5aa0e95d", - "validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])": "a7ab49bc", - "validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": "fa5cd56c", - "validateSignature(address,bytes32,(uint8,uint8,bytes))": "ae80c584" - }, - "rawMetadata": "{\"compiler\":{\"version\":\"0.8.23+commit.f704f362\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IAllowListAuthentication\",\"name\":\"authenticator_\",\"type\":\"address\"},{\"internalType\":\"contract IRepository\",\"name\":\"repository_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"permit2_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ECDSAInvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"ECDSAInvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"ECDSAInvalidSignatureS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAsset\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidBaseTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDestination\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidEIP1271Signature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidEIP712Signature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidETHSignSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFillAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidHooksTarget\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInteractionsBaseTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInteractionsQuoteTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidLendingPoolInteraction\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuoteTokenAmounts\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignatureType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSource\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonceInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotMaker\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSolver\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OrderExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PartialFillNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReceiverNotManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrancyGuardReentrantCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignatureIsExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignatureIsNotEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpdatedMakerAmountsTooLow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroMakerAmount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"selector\",\"type\":\"bytes4\"}],\"name\":\"Interaction\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"TradeOrder\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"AUTHENTICATOR\",\"outputs\":[{\"internalType\":\"contract IAllowListAuthentication\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BALANCE_MANAGER\",\"outputs\":[{\"internalType\":\"contract IBalanceManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REPOSITORY\",\"outputs\":[{\"internalType\":\"contract IRepository\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"cancelLimitOrder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"_baseTokenData\",\"type\":\"tuple\"}],\"name\":\"hashBaseTokenData\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"}],\"name\":\"hashOrder\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"_quoteTokenData\",\"type\":\"tuple\"}],\"name\":\"hashQuoteTokenData\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"internalType\":\"struct ILiquoriceSettlement.Single\",\"name\":\"_order\",\"type\":\"tuple\"}],\"name\":\"hashSingleOrder\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_hash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"isValidSignature\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"_interactions\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"beforeSettle\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"afterSettle\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GPv2Interaction.Hooks\",\"name\":\"_hooks\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"}],\"name\":\"settle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"internalType\":\"struct ILiquoriceSettlement.Single\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"}],\"name\":\"settleSingle\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"baseToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"quoteToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"baseTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"internalType\":\"struct ILiquoriceSettlement.Single\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint48\",\"name\":\"nonce\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"deadline\",\"type\":\"uint48\"}],\"internalType\":\"struct Signature.TakerPermitInfo\",\"name\":\"_takerPermitInfo\",\"type\":\"tuple\"}],\"name\":\"settleSingleWithPermitsSignatures\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_filledTakerAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"_interactions\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"beforeSettle\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"afterSettle\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GPv2Interaction.Hooks\",\"name\":\"_hooks\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_makerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_takerSignature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint48\",\"name\":\"nonce\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"deadline\",\"type\":\"uint48\"}],\"internalType\":\"struct Signature.TakerPermitInfo\",\"name\":\"_takerPermitInfo\",\"type\":\"tuple\"}],\"name\":\"settleWithPermitsSignatures\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IRepository\",\"name\":\"_repository\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"beforeSettle\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"afterSettle\",\"type\":\"tuple[]\"}],\"internalType\":\"struct GPv2Interaction.Hooks\",\"name\":\"_hooks\",\"type\":\"tuple\"}],\"name\":\"validateHooks\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IRepository\",\"name\":\"_repository\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_signer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_isPartialFill\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct GPv2Interaction.Data[]\",\"name\":\"_interactions\",\"type\":\"tuple[]\"}],\"name\":\"validateInteractions\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"rfqId\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"trader\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"effectiveTrader\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"quoteExpiry\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minFillAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRecipient\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toSupply\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.BaseTokenData\",\"name\":\"baseTokenData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toTrader\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toBorrow\",\"type\":\"uint256\"}],\"internalType\":\"struct ILiquoriceSettlement.QuoteTokenData\",\"name\":\"quoteTokenData\",\"type\":\"tuple\"}],\"internalType\":\"struct ILiquoriceSettlement.Order\",\"name\":\"_order\",\"type\":\"tuple\"}],\"name\":\"validateOrderAmounts\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_validationAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"_hash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"enum Signature.Type\",\"name\":\"signatureType\",\"type\":\"uint8\"},{\"internalType\":\"enum Signature.TransferCommand\",\"name\":\"transferCommand\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"signatureBytes\",\"type\":\"bytes\"}],\"internalType\":\"struct Signature.TypedSignature\",\"name\":\"_signature\",\"type\":\"tuple\"}],\"name\":\"validateSignature\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"errors\":{\"ECDSAInvalidSignature()\":[{\"details\":\"The signature derives the `address(0)`.\"}],\"ECDSAInvalidSignatureLength(uint256)\":[{\"details\":\"The signature has an invalid length.\"}],\"ECDSAInvalidSignatureS(bytes32)\":[{\"details\":\"The signature has an S value that is in the upper half order.\"}],\"ReentrancyGuardReentrantCall()\":[{\"details\":\"Unauthorized reentrant call.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC-20 token failed.\"}]},\"events\":{\"Interaction(address,uint256,bytes4)\":{\"params\":{\"selector\":\"Selector of the interaction function\",\"target\":\"Address of the interaction target\",\"value\":\"Value associated with the interaction\"}}},\"kind\":\"dev\",\"methods\":{\"cancelLimitOrder(uint256)\":{\"params\":{\"nonce\":\"Nonce of the order to be canceled\"}},\"hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"params\":{\"_order\":\"Order data to hash\"},\"returns\":{\"_0\":\"bytes32 Hash of the order\"}},\"hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))\":{\"params\":{\"_order\":\"Single order data to hash\"},\"returns\":{\"_0\":\"bytes32 Hash of the single order\"}},\"isValidSignature(bytes32,bytes)\":{\"params\":{\"_hash\":\"Hash of the data\",\"_signature\":\"Signature to validate\"},\"returns\":{\"_0\":\"Magic value if signature is valid, otherwise 0xffffffff\"}},\"settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))\":{\"params\":{\"_filledTakerAmount\":\"Amount filled by the taker\",\"_hooks\":\"Hooks to be called before and after settlement\",\"_interactions\":\"Array of interaction data to be executed during settlement\",\"_makerSignature\":\"Typed signature of the maker\",\"_order\":\"Order data\",\"_signer\":\"Address that signed the order\",\"_takerSignature\":\"Typed signature of the taker\"}},\"settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))\":{\"params\":{\"_filledTakerAmount\":\"Amount filled by the taker\",\"_makerSignature\":\"Signature of the maker\",\"_order\":\"Single order data\",\"_signer\":\"Address that signed the order\",\"_takerSignature\":\"Signature of the taker\"}},\"validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))\":{\"params\":{\"_hooks\":\"Hooks data\",\"_repository\":\"Repository interface\"}},\"validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])\":{\"params\":{\"_interactions\":\"Array of interaction data\",\"_order\":\"Order data\",\"_repository\":\"Repository interface\",\"_signer\":\"Signer address\"}},\"validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"params\":{\"_order\":\"Order data\"}},\"validateSignature(address,bytes32,(uint8,uint8,bytes))\":{\"params\":{\"_hash\":\"Hash of the data\",\"_signature\":\"Signature data\",\"_validationAddress\":\"Address to validate against\"}}},\"title\":\"Liquorice Settlement Contract\",\"version\":1},\"userdoc\":{\"events\":{\"Interaction(address,uint256,bytes4)\":{\"notice\":\"Emitted when an interaction is executed\"}},\"kind\":\"user\",\"methods\":{\"AUTHENTICATOR()\":{\"notice\":\"Authenticator for verifying solvers and makers\"},\"BALANCE_MANAGER()\":{\"notice\":\"Manager for handling balance transfers\"},\"REPOSITORY()\":{\"notice\":\"Repository that stores data for Lending Pools\"},\"cancelLimitOrder(uint256)\":{\"notice\":\"Cancels a limit order by invalidating its nonce\"},\"hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"notice\":\"Computes the hash of an order\"},\"hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))\":{\"notice\":\"Computes the hash of a single order\"},\"isValidSignature(bytes32,bytes)\":{\"notice\":\"Validates a signature\"},\"settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))\":{\"notice\":\"Settles a signed order with the given interactions and hooks\"},\"settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))\":{\"notice\":\"Settles a single order\"},\"validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))\":{\"notice\":\"Validates hooks for an order\"},\"validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])\":{\"notice\":\"Validates interactions for an order\"},\"validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))\":{\"notice\":\"Validates the amounts in an order\"},\"validateSignature(address,bytes32,(uint8,uint8,bytes))\":{\"notice\":\"Validates a signature\"}},\"notice\":\"Handles settlement of orders and interactions\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/settlement/LiquoriceSettlement.sol\":\"LiquoriceSettlement\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[\":@chainlink/=lib/chainlink/contracts/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/\",\":chainlink/=lib/chainlink/\",\":contracts/=src/contracts/\",\":ds-test/=node_modules/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/\",\":interfaces/=src/interfaces/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/\",\":openzeppelin-upgrades/=lib/openzeppelin-upgrades/\",\":solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/\"]},\"sources\":{\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol\":{\"keccak256\":\"0xc92e946b954f185c3ca5ee56f9721aa73d64464456a46459384cb0ccf3c3856e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ae178b4e7b259557d8b93f3dd4f6f909ac72f914a9e92676e59b8d737f0423e2\",\"dweb:/ipfs/QmXeqyUJYzn6w8wyivQAtSzmwwFQnHaFYPvGad66RW1sPf\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol\":{\"keccak256\":\"0x9b6b3e7803bc5f2f8cd7ad57db8ac1def61a9930a5a3107df4882e028a9605d7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://da62d6be1f5c6edf577f0cb45666a8aa9c2086a4bac87d95d65f02e2f4c36a4b\",\"dweb:/ipfs/QmNkpvBpoCMvX8JwAFNSc5XxJ2q5BXJpL5L1txb4QkqVFF\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol\":{\"keccak256\":\"0xde7e9fd9aee8d4f40772f96bb3b58836cbc6dfc0227014a061947f8821ea9724\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://11fea9f8bc98949ac6709f0c1699db7430d2948137aa94d5a9e95a91f61a710a\",\"dweb:/ipfs/QmQdfRXxQjwP6yn3DVo1GHPpriKNcFghSPi94Z1oKEFUNS\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol\":{\"keccak256\":\"0xce41876e78d1badc0512229b4d14e4daf83bc1003d7f83978d18e0e56f965b9c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a2608291cb038b388d80b79a06b6118a42f7894ff67b7da10ec0dbbf5b2973ba\",\"dweb:/ipfs/QmWohqcBLbcxmA4eGPhZDXe5RYMMEEpFq22nfkaUMvTfw1\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://df6f0c459663c9858b6cba2cda1d14a7d05a985bed6d2de72bd8e78c25ee79db\",\"dweb:/ipfs/QmeTTxZ7qVk9rjEv2R4CpCwdf8UMCcRqDNMvzNxHc3Fnn9\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol\":{\"keccak256\":\"0x6dd0cb67846da3fa1241c520faaa215d6bec8226e37beac6056c51e8af44d24e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://650e533e62b30dcc6edea2b6c91358d5659da3bde42e56adf7316c493b916a15\",\"dweb:/ipfs/QmYkmK2vPE6FjdAoQVpZSJxamTLGno9wzGS495TcMNFViV\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Panic.sol\":{\"keccak256\":\"0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a\",\"dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol\":{\"keccak256\":\"0x11a5a79827df29e915a12740caf62fe21ebe27c08c9ae3e09abe9ee3ba3866d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3cf0c69ab827e3251db9ee6a50647d62c90ba580a4d7bbff21f2bea39e7b2f4a\",\"dweb:/ipfs/QmZiKwtKU1SBX4RGfQtY7PZfiapbbu6SZ9vizGQD9UHjRA\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9\",\"dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x79796192ec90263f21b464d5bc90b777a525971d3de8232be80d9c4f9fb353b8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f6fda447a62815e8064f47eff0dd1cf58d9207ad69b5d32280f8d7ed1d1e4621\",\"dweb:/ipfs/QmfDRc7pxfaXB2Dh9np5Uf29Na3pQ7tafRS684wd3GLjVL\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0x6f61a65c733690afafb4cf528b5677e704828c8350b60b948dbc1d3bb6d7689c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://00265b985b303af62ee243e10db819fa8cf890d9f122f82f4f03f55b02f62654\",\"dweb:/ipfs/QmNneFqZn2uKK6dECxatH6aENk1EMCTETi58dGaz5NCWQe\"]},\"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol\":{\"keccak256\":\"0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8\",\"dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy\"]},\"src/contracts/lib/GPv2Interaction.sol\":{\"keccak256\":\"0x55968a83f6ae3d8d806b8faf02360abc676fb7476d05f33c0c9d324e6336fd0f\",\"license\":\"LGPL-3.0-or-later\",\"urls\":[\"bzz-raw://2d813e60c3fa006d02c8fd1aed73d2d47f9f153ac3c410d408384f3084e46de3\",\"dweb:/ipfs/QmdNyQMmyscMH6CVUkhQQfGdKdxgqhqDEe5K4iwrvcWDsk\"]},\"src/contracts/lib/Signature.sol\":{\"keccak256\":\"0xc084fe793244e2e7b0f4a51440df7dbf97d39b4ad6450a2b8a082cb6d86993b5\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://9bff9732e68149a83f2e044c7f1700432997750166cd15f4a54f73bd68a475aa\",\"dweb:/ipfs/QmZJMNppHQ3nUDcJhAkrMYa4QWhGLDr4Tzah6LndgrDCib\"]},\"src/contracts/settlement/BalanceManager.sol\":{\"keccak256\":\"0x82d5d0de5cf88ff8882f1f7a2d05b98ed32bb3f2a6b9eab728ce55ae943e67c3\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://ebcbe822ad5c68896a12ecd60e17ba6a2ed0ba8e0544c7ad54d88d1c25206b5c\",\"dweb:/ipfs/QmYEZeKUEz7Nw6MW9uZHnXvkeRTmmcS1WZhx77s9kUWSWw\"]},\"src/contracts/settlement/LiquoriceSettlement.sol\":{\"keccak256\":\"0xcac528919829fc8e021cec4325b38835866a7d0630b61349deae6ecfbe0ddaef\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://6d6dafbba3885b42cb97be6d190ac1f611548ceb2116e9b6ed7da9bf422c8b58\",\"dweb:/ipfs/QmZQk6WQNgYqsu9Z85tPF2VQGXgaYzvpEqc7VEmJ4zEEJU\"]},\"src/contracts/settlement/Signing.sol\":{\"keccak256\":\"0xad9e59ae740627e5b71fa1ebde019999084480664d06d18f0a01e4d31fa32ef6\",\"license\":\"BUSL-1.1\",\"urls\":[\"bzz-raw://ea0e0021cd0074292b04f9921f6ca3cc77a6799c86cacabb9dc6ff7dadbd7933\",\"dweb:/ipfs/QmPjY69PntfUGW5eNrNe98DCTemq6daRqUiLFkcYvVWuvh\"]},\"src/interfaces/IACLManager.sol\":{\"keccak256\":\"0xeee5cbedcfaff01733979b8f439a817aa67b09d9e330d21e11f180dceebed024\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://814431cd9df23d0d7cc0f9761927e2aa18fc7fa599f34422f332ee6352580d69\",\"dweb:/ipfs/QmXLdGsdMyeX5j64rAaByz35SwEMPMQ7usXwruWjEPo6Cz\"]},\"src/interfaces/IAllowListAuthentication.sol\":{\"keccak256\":\"0xbabb9eda80757d9355ab9863fccb3fdb1f15c1cbce458c3236d792d007077a9e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f6fa97e90b315ffc3cae3998adda6810c856ea96be015e797723e13b436d1a10\",\"dweb:/ipfs/Qme1dzXXcMDQpeqyqfuSbZDY6GKWjyrRBQrNDjitPeXQEF\"]},\"src/interfaces/IBalanceManager.sol\":{\"keccak256\":\"0xc4cff6f33170df6d91a866ee69263c9b90091e94027bea04038558c315e6e127\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://867164a381fb78da320c89db6b15978becd49be61e2349abc805362904bffb4e\",\"dweb:/ipfs/QmPY9UYCi9YVdCC8A1UxmTPcnV5BmMj93Gq1nqxBv4fMJ7\"]},\"src/interfaces/IInterestRateModel.sol\":{\"keccak256\":\"0xccd4c1dea98176c392de07cb8f5a2ac969405090d42d831310fa53464c0d9264\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a22b5b87be29e616142b6c4677e109e9246157c4b7e6378334fbc7ba403d82de\",\"dweb:/ipfs/QmXmSF34VsktTfqSCJU8Mz9sTaXGVk7xdYQwr9NcsR3k43\"]},\"src/interfaces/ILiquoriceSettlement.sol\":{\"keccak256\":\"0xa4a36d51f174d9994c39287f89e63bbea57ff5adcd2a9bc649c67bb5cae75272\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8562fe9fc033c3e3320c5d95ad10e49f5e23ea50a5e9eaf186cbf53d9f1ce7a6\",\"dweb:/ipfs/QmXKSjRi8oxmS5xd5V95HofYtFzYfehbL6s8t2MKoXR7y1\"]},\"src/interfaces/IPriceProvider.sol\":{\"keccak256\":\"0x75812be8d692287010f5ee9ce13556df1bd8299faa64b42c49cd08cf7cc53847\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://623d4faa57b078a33a2afe0d13fc426c4a750ae7f07f9d826000047dab54148e\",\"dweb:/ipfs/QmYmFpZnLug6FBG9C8s1mxPBjZHwiCk7cRBC7A9WXtyGKE\"]},\"src/interfaces/IRepository.sol\":{\"keccak256\":\"0xf08a5812ce10042564d518994db487c49d9f35d511da07a5103b9b886b6e2607\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b602c9f5a61c9796f711330ee56d4f0287adc656c686acf391d4e8c45453e6d0\",\"dweb:/ipfs/QmQ7XJ1qERgRxWurpkS3t1XDtuBUTpQEz14h4eXBc8vp9t\"]},\"src/interfaces/external/permit/IAllowanceTransfer.sol\":{\"keccak256\":\"0x23986b17f0c10296cb8afadb43014cd7901f56dac5ba85067d18ca7db7d3e37e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5f6ec55ce038e045b15a89a7f19fa45aa09d42a52517dd1846968d16777d3a9b\",\"dweb:/ipfs/QmZXthQLUtRFgqGv3bFbijmNk5Vviacrf7VnRDbXEQjdBQ\"]},\"src/interfaces/external/permit/IEIP712.sol\":{\"keccak256\":\"0x07e44e64248ed6316fe1db6f44c80468b950e6d1ab4bfdf21a65cbbd27718f77\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://58487548bc5289e7f5a4d4c278e5c7e9a7829d8a5be024a42938943f8c8fb63b\",\"dweb:/ipfs/QmYg63mq3SgXH6H4Wyvznb1E5fEjw6W7NeLASUcRjMuKYa\"]}},\"version\":1}", - "metadata": { - "compiler": { - "version": "0.8.23+commit.f704f362" - }, - "language": "Solidity", - "output": { - "abi": [ - { - "inputs": [ - { - "internalType": "contract IAllowListAuthentication", - "name": "authenticator_", - "type": "address" - }, - { - "internalType": "contract IRepository", - "name": "repository_", - "type": "address" - }, - { - "internalType": "address", - "name": "permit2_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "type": "error", - "name": "ECDSAInvalidSignature" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "type": "error", - "name": "ECDSAInvalidSignatureLength" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "type": "error", - "name": "ECDSAInvalidSignatureS" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidAmount" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidAsset" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidBaseTokenAmounts" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidDestination" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidEIP1271Signature" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidEIP712Signature" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidETHSignSignature" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidFillAmount" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidHooksTarget" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidInteractionsBaseTokenAmounts" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidInteractionsQuoteTokenAmounts" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidLendingPoolInteraction" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidQuoteTokenAmounts" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidSignatureType" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidSigner" - }, - { - "inputs": [], - "type": "error", - "name": "InvalidSource" - }, - { - "inputs": [], - "type": "error", - "name": "NonceInvalid" - }, - { - "inputs": [], - "type": "error", - "name": "NotMaker" - }, - { - "inputs": [], - "type": "error", - "name": "NotSolver" - }, - { - "inputs": [], - "type": "error", - "name": "OrderExpired" - }, - { - "inputs": [], - "type": "error", - "name": "PartialFillNotSupported" - }, - { - "inputs": [], - "type": "error", - "name": "ReceiverNotManager" - }, - { - "inputs": [], - "type": "error", - "name": "ReentrancyGuardReentrantCall" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "type": "error", - "name": "SafeERC20FailedOperation" - }, - { - "inputs": [], - "type": "error", - "name": "SignatureIsExpired" - }, - { - "inputs": [], - "type": "error", - "name": "SignatureIsNotEmpty" - }, - { - "inputs": [], - "type": "error", - "name": "UpdatedMakerAmountsTooLow" - }, - { - "inputs": [], - "type": "error", - "name": "ZeroMakerAmount" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address", - "indexed": true - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256", - "indexed": false - }, - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4", - "indexed": false - } - ], - "type": "event", - "name": "Interaction", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "string", - "name": "rfqId", - "type": "string", - "indexed": true - }, - { - "internalType": "address", - "name": "trader", - "type": "address", - "indexed": false - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address", - "indexed": false - }, - { - "internalType": "address", - "name": "baseToken", - "type": "address", - "indexed": false - }, - { - "internalType": "address", - "name": "quoteToken", - "type": "address", - "indexed": false - }, - { - "internalType": "uint256", - "name": "baseTokenAmount", - "type": "uint256", - "indexed": false - }, - { - "internalType": "uint256", - "name": "quoteTokenAmount", - "type": "uint256", - "indexed": false - }, - { - "internalType": "address", - "name": "recipient", - "type": "address", - "indexed": false - } - ], - "type": "event", - "name": "TradeOrder", - "anonymous": false - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "AUTHENTICATOR", - "outputs": [ - { - "internalType": "contract IAllowListAuthentication", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "BALANCE_MANAGER", - "outputs": [ - { - "internalType": "contract IBalanceManager", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "REPOSITORY", - "outputs": [ - { - "internalType": "contract IRepository", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "cancelLimitOrder" - }, - { - "inputs": [ - { - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "name": "_baseTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRecipient", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRepay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toSupply", - "type": "uint256" - } - ] - } - ], - "stateMutability": "pure", - "type": "function", - "name": "hashBaseTokenData", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ] - }, - { - "inputs": [ - { - "internalType": "struct ILiquoriceSettlement.Order", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "market", - "type": "address" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "name": "baseTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRecipient", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRepay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toSupply", - "type": "uint256" - } - ] - }, - { - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "name": "quoteTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toTrader", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toWithdraw", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toBorrow", - "type": "uint256" - } - ] - } - ] - } - ], - "stateMutability": "view", - "type": "function", - "name": "hashOrder", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ] - }, - { - "inputs": [ - { - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "name": "_quoteTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toTrader", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toWithdraw", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toBorrow", - "type": "uint256" - } - ] - } - ], - "stateMutability": "pure", - "type": "function", - "name": "hashQuoteTokenData", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ] - }, - { - "inputs": [ - { - "internalType": "struct ILiquoriceSettlement.Single", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "address", - "name": "baseToken", - "type": "address" - }, - { - "internalType": "address", - "name": "quoteToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "baseTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "quoteTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ] - } - ], - "stateMutability": "view", - "type": "function", - "name": "hashSingleOrder", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ] - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_hash", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "_signature", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function", - "name": "isValidSignature", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ] - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_filledTakerAmount", - "type": "uint256" - }, - { - "internalType": "struct ILiquoriceSettlement.Order", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "market", - "type": "address" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "name": "baseTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRecipient", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRepay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toSupply", - "type": "uint256" - } - ] - }, - { - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "name": "quoteTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toTrader", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toWithdraw", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toBorrow", - "type": "uint256" - } - ] - } - ] - }, - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "_interactions", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - }, - { - "internalType": "struct GPv2Interaction.Hooks", - "name": "_hooks", - "type": "tuple", - "components": [ - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "beforeSettle", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - }, - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "afterSettle", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - } - ] - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_makerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_takerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "settle" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_signer", - "type": "address" - }, - { - "internalType": "struct ILiquoriceSettlement.Single", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "address", - "name": "baseToken", - "type": "address" - }, - { - "internalType": "address", - "name": "quoteToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "baseTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "quoteTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ] - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_makerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - }, - { - "internalType": "uint256", - "name": "_filledTakerAmount", - "type": "uint256" - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_takerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - } - ], - "stateMutability": "payable", - "type": "function", - "name": "settleSingle" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_signer", - "type": "address" - }, - { - "internalType": "struct ILiquoriceSettlement.Single", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "address", - "name": "baseToken", - "type": "address" - }, - { - "internalType": "address", - "name": "quoteToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "baseTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "quoteTokenAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ] - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_makerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - }, - { - "internalType": "uint256", - "name": "_filledTakerAmount", - "type": "uint256" - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_takerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - }, - { - "internalType": "struct Signature.TakerPermitInfo", - "name": "_takerPermitInfo", - "type": "tuple", - "components": [ - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "uint48", - "name": "nonce", - "type": "uint48" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - } - ] - } - ], - "stateMutability": "payable", - "type": "function", - "name": "settleSingleWithPermitsSignatures" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_signer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_filledTakerAmount", - "type": "uint256" - }, - { - "internalType": "struct ILiquoriceSettlement.Order", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "market", - "type": "address" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "name": "baseTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRecipient", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRepay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toSupply", - "type": "uint256" - } - ] - }, - { - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "name": "quoteTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toTrader", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toWithdraw", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toBorrow", - "type": "uint256" - } - ] - } - ] - }, - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "_interactions", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - }, - { - "internalType": "struct GPv2Interaction.Hooks", - "name": "_hooks", - "type": "tuple", - "components": [ - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "beforeSettle", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - }, - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "afterSettle", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - } - ] - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_makerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_takerSignature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - }, - { - "internalType": "struct Signature.TakerPermitInfo", - "name": "_takerPermitInfo", - "type": "tuple", - "components": [ - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "internalType": "uint48", - "name": "nonce", - "type": "uint48" - }, - { - "internalType": "uint48", - "name": "deadline", - "type": "uint48" - } - ] - } - ], - "stateMutability": "payable", - "type": "function", - "name": "settleWithPermitsSignatures" - }, - { - "inputs": [ - { - "internalType": "contract IRepository", - "name": "_repository", - "type": "address" - }, - { - "internalType": "struct GPv2Interaction.Hooks", - "name": "_hooks", - "type": "tuple", - "components": [ - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "beforeSettle", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - }, - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "afterSettle", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - } - ] - } - ], - "stateMutability": "view", - "type": "function", - "name": "validateHooks" - }, - { - "inputs": [ - { - "internalType": "contract IRepository", - "name": "_repository", - "type": "address" - }, - { - "internalType": "address", - "name": "_signer", - "type": "address" - }, - { - "internalType": "bool", - "name": "_isPartialFill", - "type": "bool" - }, - { - "internalType": "struct ILiquoriceSettlement.Order", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "market", - "type": "address" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "name": "baseTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRecipient", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRepay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toSupply", - "type": "uint256" - } - ] - }, - { - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "name": "quoteTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toTrader", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toWithdraw", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toBorrow", - "type": "uint256" - } - ] - } - ] - }, - { - "internalType": "struct GPv2Interaction.Data[]", - "name": "_interactions", - "type": "tuple[]", - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ] - } - ], - "stateMutability": "view", - "type": "function", - "name": "validateInteractions" - }, - { - "inputs": [ - { - "internalType": "struct ILiquoriceSettlement.Order", - "name": "_order", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "market", - "type": "address" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "rfqId", - "type": "string" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "trader", - "type": "address" - }, - { - "internalType": "address", - "name": "effectiveTrader", - "type": "address" - }, - { - "internalType": "uint256", - "name": "quoteExpiry", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minFillAmount", - "type": "uint256" - }, - { - "internalType": "struct ILiquoriceSettlement.BaseTokenData", - "name": "baseTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRecipient", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toRepay", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toSupply", - "type": "uint256" - } - ] - }, - { - "internalType": "struct ILiquoriceSettlement.QuoteTokenData", - "name": "quoteTokenData", - "type": "tuple", - "components": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toTrader", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toWithdraw", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "toBorrow", - "type": "uint256" - } - ] - } - ] - } - ], - "stateMutability": "pure", - "type": "function", - "name": "validateOrderAmounts" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_validationAddress", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "_hash", - "type": "bytes32" - }, - { - "internalType": "struct Signature.TypedSignature", - "name": "_signature", - "type": "tuple", - "components": [ - { - "internalType": "enum Signature.Type", - "name": "signatureType", - "type": "uint8" - }, - { - "internalType": "enum Signature.TransferCommand", - "name": "transferCommand", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "signatureBytes", - "type": "bytes" - } - ] - } - ], - "stateMutability": "view", - "type": "function", - "name": "validateSignature" - }, - { - "inputs": [], - "stateMutability": "payable", - "type": "receive" - } - ], - "devdoc": { - "kind": "dev", - "methods": { - "cancelLimitOrder(uint256)": { - "params": { - "nonce": "Nonce of the order to be canceled" - } - }, - "hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { - "params": { - "_order": "Order data to hash" - }, - "returns": { - "_0": "bytes32 Hash of the order" - } - }, - "hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))": { - "params": { - "_order": "Single order data to hash" - }, - "returns": { - "_0": "bytes32 Hash of the single order" - } - }, - "isValidSignature(bytes32,bytes)": { - "params": { - "_hash": "Hash of the data", - "_signature": "Signature to validate" - }, - "returns": { - "_0": "Magic value if signature is valid, otherwise 0xffffffff" - } - }, - "settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))": { - "params": { - "_filledTakerAmount": "Amount filled by the taker", - "_hooks": "Hooks to be called before and after settlement", - "_interactions": "Array of interaction data to be executed during settlement", - "_makerSignature": "Typed signature of the maker", - "_order": "Order data", - "_signer": "Address that signed the order", - "_takerSignature": "Typed signature of the taker" - } - }, - "settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))": { - "params": { - "_filledTakerAmount": "Amount filled by the taker", - "_makerSignature": "Signature of the maker", - "_order": "Single order data", - "_signer": "Address that signed the order", - "_takerSignature": "Signature of the taker" - } - }, - "validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))": { - "params": { - "_hooks": "Hooks data", - "_repository": "Repository interface" - } - }, - "validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])": { - "params": { - "_interactions": "Array of interaction data", - "_order": "Order data", - "_repository": "Repository interface", - "_signer": "Signer address" - } - }, - "validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { - "params": { - "_order": "Order data" - } - }, - "validateSignature(address,bytes32,(uint8,uint8,bytes))": { - "params": { - "_hash": "Hash of the data", - "_signature": "Signature data", - "_validationAddress": "Address to validate against" - } - } - }, - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": { - "AUTHENTICATOR()": { - "notice": "Authenticator for verifying solvers and makers" - }, - "BALANCE_MANAGER()": { - "notice": "Manager for handling balance transfers" - }, - "REPOSITORY()": { - "notice": "Repository that stores data for Lending Pools" - }, - "cancelLimitOrder(uint256)": { - "notice": "Cancels a limit order by invalidating its nonce" - }, - "hashOrder((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { - "notice": "Computes the hash of an order" - }, - "hashSingleOrder((string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address))": { - "notice": "Computes the hash of a single order" - }, - "isValidSignature(bytes32,bytes)": { - "notice": "Validates a signature" - }, - "settle(address,uint256,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[],((address,uint256,bytes)[],(address,uint256,bytes)[]),(uint8,uint8,bytes),(uint8,uint8,bytes))": { - "notice": "Settles a signed order with the given interactions and hooks" - }, - "settleSingle(address,(string,uint256,address,address,address,address,uint256,uint256,uint256,uint256,address),(uint8,uint8,bytes),uint256,(uint8,uint8,bytes))": { - "notice": "Settles a single order" - }, - "validateHooks(address,((address,uint256,bytes)[],(address,uint256,bytes)[]))": { - "notice": "Validates hooks for an order" - }, - "validateInteractions(address,address,bool,(address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)),(address,uint256,bytes)[])": { - "notice": "Validates interactions for an order" - }, - "validateOrderAmounts((address,uint256,string,uint256,address,address,uint256,address,uint256,(address,uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256,uint256)))": { - "notice": "Validates the amounts in an order" - }, - "validateSignature(address,bytes32,(uint8,uint8,bytes))": { - "notice": "Validates a signature" - } - }, - "version": 1 - } - }, - "settings": { - "remappings": [ - "@chainlink/=lib/chainlink/contracts/", - "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", - "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/", - "chainlink/=lib/chainlink/", - "contracts/=src/contracts/", - "ds-test/=node_modules/ds-test/src/", - "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", - "forge-std/=lib/forge-std/src/", - "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/", - "interfaces/=src/interfaces/", - "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", - "openzeppelin-contracts/=lib/openzeppelin-contracts/", - "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", - "openzeppelin-upgrades/=lib/openzeppelin-upgrades/", - "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/" - ], - "optimizer": { - "enabled": true, - "runs": 10000 - }, - "metadata": { - "bytecodeHash": "ipfs" - }, - "compilationTarget": { - "src/contracts/settlement/LiquoriceSettlement.sol": "LiquoriceSettlement" - }, - "evmVersion": "shanghai", - "libraries": {} - }, - "sources": { - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol": { - "keccak256": "0xc92e946b954f185c3ca5ee56f9721aa73d64464456a46459384cb0ccf3c3856e", - "urls": [ - "bzz-raw://ae178b4e7b259557d8b93f3dd4f6f909ac72f914a9e92676e59b8d737f0423e2", - "dweb:/ipfs/QmXeqyUJYzn6w8wyivQAtSzmwwFQnHaFYPvGad66RW1sPf" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol": { - "keccak256": "0x9b6b3e7803bc5f2f8cd7ad57db8ac1def61a9930a5a3107df4882e028a9605d7", - "urls": [ - "bzz-raw://da62d6be1f5c6edf577f0cb45666a8aa9c2086a4bac87d95d65f02e2f4c36a4b", - "dweb:/ipfs/QmNkpvBpoCMvX8JwAFNSc5XxJ2q5BXJpL5L1txb4QkqVFF" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol": { - "keccak256": "0xde7e9fd9aee8d4f40772f96bb3b58836cbc6dfc0227014a061947f8821ea9724", - "urls": [ - "bzz-raw://11fea9f8bc98949ac6709f0c1699db7430d2948137aa94d5a9e95a91f61a710a", - "dweb:/ipfs/QmQdfRXxQjwP6yn3DVo1GHPpriKNcFghSPi94Z1oKEFUNS" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol": { - "keccak256": "0xce41876e78d1badc0512229b4d14e4daf83bc1003d7f83978d18e0e56f965b9c", - "urls": [ - "bzz-raw://a2608291cb038b388d80b79a06b6118a42f7894ff67b7da10ec0dbbf5b2973ba", - "dweb:/ipfs/QmWohqcBLbcxmA4eGPhZDXe5RYMMEEpFq22nfkaUMvTfw1" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": { - "keccak256": "0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7", - "urls": [ - "bzz-raw://df6f0c459663c9858b6cba2cda1d14a7d05a985bed6d2de72bd8e78c25ee79db", - "dweb:/ipfs/QmeTTxZ7qVk9rjEv2R4CpCwdf8UMCcRqDNMvzNxHc3Fnn9" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": { - "keccak256": "0x6dd0cb67846da3fa1241c520faaa215d6bec8226e37beac6056c51e8af44d24e", - "urls": [ - "bzz-raw://650e533e62b30dcc6edea2b6c91358d5659da3bde42e56adf7316c493b916a15", - "dweb:/ipfs/QmYkmK2vPE6FjdAoQVpZSJxamTLGno9wzGS495TcMNFViV" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Panic.sol": { - "keccak256": "0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a", - "urls": [ - "bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a", - "dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol": { - "keccak256": "0x11a5a79827df29e915a12740caf62fe21ebe27c08c9ae3e09abe9ee3ba3866d3", - "urls": [ - "bzz-raw://3cf0c69ab827e3251db9ee6a50647d62c90ba580a4d7bbff21f2bea39e7b2f4a", - "dweb:/ipfs/QmZiKwtKU1SBX4RGfQtY7PZfiapbbu6SZ9vizGQD9UHjRA" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": { - "keccak256": "0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84", - "urls": [ - "bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9", - "dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": { - "keccak256": "0x79796192ec90263f21b464d5bc90b777a525971d3de8232be80d9c4f9fb353b8", - "urls": [ - "bzz-raw://f6fda447a62815e8064f47eff0dd1cf58d9207ad69b5d32280f8d7ed1d1e4621", - "dweb:/ipfs/QmfDRc7pxfaXB2Dh9np5Uf29Na3pQ7tafRS684wd3GLjVL" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/Math.sol": { - "keccak256": "0x6f61a65c733690afafb4cf528b5677e704828c8350b60b948dbc1d3bb6d7689c", - "urls": [ - "bzz-raw://00265b985b303af62ee243e10db819fa8cf890d9f122f82f4f03f55b02f62654", - "dweb:/ipfs/QmNneFqZn2uKK6dECxatH6aENk1EMCTETi58dGaz5NCWQe" - ], - "license": "MIT" - }, - "lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol": { - "keccak256": "0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54", - "urls": [ - "bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8", - "dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy" - ], - "license": "MIT" - }, - "src/contracts/lib/GPv2Interaction.sol": { - "keccak256": "0x55968a83f6ae3d8d806b8faf02360abc676fb7476d05f33c0c9d324e6336fd0f", - "urls": [ - "bzz-raw://2d813e60c3fa006d02c8fd1aed73d2d47f9f153ac3c410d408384f3084e46de3", - "dweb:/ipfs/QmdNyQMmyscMH6CVUkhQQfGdKdxgqhqDEe5K4iwrvcWDsk" - ], - "license": "LGPL-3.0-or-later" - }, - "src/contracts/lib/Signature.sol": { - "keccak256": "0xc084fe793244e2e7b0f4a51440df7dbf97d39b4ad6450a2b8a082cb6d86993b5", - "urls": [ - "bzz-raw://9bff9732e68149a83f2e044c7f1700432997750166cd15f4a54f73bd68a475aa", - "dweb:/ipfs/QmZJMNppHQ3nUDcJhAkrMYa4QWhGLDr4Tzah6LndgrDCib" - ], - "license": "BUSL-1.1" - }, - "src/contracts/settlement/BalanceManager.sol": { - "keccak256": "0x82d5d0de5cf88ff8882f1f7a2d05b98ed32bb3f2a6b9eab728ce55ae943e67c3", - "urls": [ - "bzz-raw://ebcbe822ad5c68896a12ecd60e17ba6a2ed0ba8e0544c7ad54d88d1c25206b5c", - "dweb:/ipfs/QmYEZeKUEz7Nw6MW9uZHnXvkeRTmmcS1WZhx77s9kUWSWw" - ], - "license": "BUSL-1.1" - }, - "src/contracts/settlement/LiquoriceSettlement.sol": { - "keccak256": "0xcac528919829fc8e021cec4325b38835866a7d0630b61349deae6ecfbe0ddaef", - "urls": [ - "bzz-raw://6d6dafbba3885b42cb97be6d190ac1f611548ceb2116e9b6ed7da9bf422c8b58", - "dweb:/ipfs/QmZQk6WQNgYqsu9Z85tPF2VQGXgaYzvpEqc7VEmJ4zEEJU" - ], - "license": "BUSL-1.1" - }, - "src/contracts/settlement/Signing.sol": { - "keccak256": "0xad9e59ae740627e5b71fa1ebde019999084480664d06d18f0a01e4d31fa32ef6", - "urls": [ - "bzz-raw://ea0e0021cd0074292b04f9921f6ca3cc77a6799c86cacabb9dc6ff7dadbd7933", - "dweb:/ipfs/QmPjY69PntfUGW5eNrNe98DCTemq6daRqUiLFkcYvVWuvh" - ], - "license": "BUSL-1.1" - }, - "src/interfaces/IACLManager.sol": { - "keccak256": "0xeee5cbedcfaff01733979b8f439a817aa67b09d9e330d21e11f180dceebed024", - "urls": [ - "bzz-raw://814431cd9df23d0d7cc0f9761927e2aa18fc7fa599f34422f332ee6352580d69", - "dweb:/ipfs/QmXLdGsdMyeX5j64rAaByz35SwEMPMQ7usXwruWjEPo6Cz" - ], - "license": "MIT" - }, - "src/interfaces/IAllowListAuthentication.sol": { - "keccak256": "0xbabb9eda80757d9355ab9863fccb3fdb1f15c1cbce458c3236d792d007077a9e", - "urls": [ - "bzz-raw://f6fa97e90b315ffc3cae3998adda6810c856ea96be015e797723e13b436d1a10", - "dweb:/ipfs/Qme1dzXXcMDQpeqyqfuSbZDY6GKWjyrRBQrNDjitPeXQEF" - ], - "license": "MIT" - }, - "src/interfaces/IBalanceManager.sol": { - "keccak256": "0xc4cff6f33170df6d91a866ee69263c9b90091e94027bea04038558c315e6e127", - "urls": [ - "bzz-raw://867164a381fb78da320c89db6b15978becd49be61e2349abc805362904bffb4e", - "dweb:/ipfs/QmPY9UYCi9YVdCC8A1UxmTPcnV5BmMj93Gq1nqxBv4fMJ7" - ], - "license": "MIT" - }, - "src/interfaces/IInterestRateModel.sol": { - "keccak256": "0xccd4c1dea98176c392de07cb8f5a2ac969405090d42d831310fa53464c0d9264", - "urls": [ - "bzz-raw://a22b5b87be29e616142b6c4677e109e9246157c4b7e6378334fbc7ba403d82de", - "dweb:/ipfs/QmXmSF34VsktTfqSCJU8Mz9sTaXGVk7xdYQwr9NcsR3k43" - ], - "license": "MIT" - }, - "src/interfaces/ILiquoriceSettlement.sol": { - "keccak256": "0xa4a36d51f174d9994c39287f89e63bbea57ff5adcd2a9bc649c67bb5cae75272", - "urls": [ - "bzz-raw://8562fe9fc033c3e3320c5d95ad10e49f5e23ea50a5e9eaf186cbf53d9f1ce7a6", - "dweb:/ipfs/QmXKSjRi8oxmS5xd5V95HofYtFzYfehbL6s8t2MKoXR7y1" - ], - "license": "MIT" - }, - "src/interfaces/IPriceProvider.sol": { - "keccak256": "0x75812be8d692287010f5ee9ce13556df1bd8299faa64b42c49cd08cf7cc53847", - "urls": [ - "bzz-raw://623d4faa57b078a33a2afe0d13fc426c4a750ae7f07f9d826000047dab54148e", - "dweb:/ipfs/QmYmFpZnLug6FBG9C8s1mxPBjZHwiCk7cRBC7A9WXtyGKE" - ], - "license": "MIT" - }, - "src/interfaces/IRepository.sol": { - "keccak256": "0xf08a5812ce10042564d518994db487c49d9f35d511da07a5103b9b886b6e2607", - "urls": [ - "bzz-raw://b602c9f5a61c9796f711330ee56d4f0287adc656c686acf391d4e8c45453e6d0", - "dweb:/ipfs/QmQ7XJ1qERgRxWurpkS3t1XDtuBUTpQEz14h4eXBc8vp9t" - ], - "license": "MIT" - }, - "src/interfaces/external/permit/IAllowanceTransfer.sol": { - "keccak256": "0x23986b17f0c10296cb8afadb43014cd7901f56dac5ba85067d18ca7db7d3e37e", - "urls": [ - "bzz-raw://5f6ec55ce038e045b15a89a7f19fa45aa09d42a52517dd1846968d16777d3a9b", - "dweb:/ipfs/QmZXthQLUtRFgqGv3bFbijmNk5Vviacrf7VnRDbXEQjdBQ" - ], - "license": "MIT" - }, - "src/interfaces/external/permit/IEIP712.sol": { - "keccak256": "0x07e44e64248ed6316fe1db6f44c80468b950e6d1ab4bfdf21a65cbbd27718f77", - "urls": [ - "bzz-raw://58487548bc5289e7f5a4d4c278e5c7e9a7829d8a5be024a42938943f8c8fb63b", - "dweb:/ipfs/QmYg63mq3SgXH6H4Wyvznb1E5fEjw6W7NeLASUcRjMuKYa" - ], - "license": "MIT" - } - }, - "version": 1 - }, - "id": 90 -} \ No newline at end of file diff --git a/crates/contracts/artifacts/PancakeRouter.json b/crates/contracts/artifacts/PancakeRouter.json deleted file mode 120000 index e485e1a596..0000000000 --- a/crates/contracts/artifacts/PancakeRouter.json +++ /dev/null @@ -1 +0,0 @@ -IUniswapLikeRouter.json \ No newline at end of file diff --git a/crates/contracts/artifacts/Signatures.json b/crates/contracts/artifacts/Signatures.json deleted file mode 100644 index 8b36e8b168..0000000000 --- a/crates/contracts/artifacts/Signatures.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISettlement", - "name": "settlement", - "type": "address" - }, - { - "internalType": "contract IVaultRelayer", - "name": "vaultRelayer", - "type": "address" - } - ], - "internalType": "struct Signatures.Contracts", - "name": "contracts", - "type": "tuple" - }, - { - "internalType": "contract IERC1271", - "name": "signer", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "order", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ], - "internalType": "struct Interaction[]", - "name": "interactions", - "type": "tuple[]" - } - ], - "name": "validate", - "outputs": [ - { - "internalType": "uint256", - "name": "gasUsed", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x6080604052348015600e575f5ffd5b50610ae88061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b46054151461002d575b5f5ffd5b61004760048036038101906100429190610602565b61005d565b60405161005491906106d1565b60405180910390f35b5f61006988848461018c565b5a90505f8773ffffffffffffffffffffffffffffffffffffffff16631626ba7e8888886040518463ffffffff1660e01b81526004016100aa93929190610743565b602060405180830381865afa1580156100c5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e991906107c8565b90505a826100f79190610820565b9150631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610180576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610177906108ad565b60405180910390fd5b50979650505050505050565b825f015173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16146101fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f490610915565b60405180910390fd5b5f5b82829050811015610348575f83838381811061021e5761021d610933565b5b9050602002810190610230919061096c565b5f01602081019061024191906109bd565b90505f84848481811061025757610256610933565b5b9050602002810190610269919061096c565b602001359050365f86868681811061028457610283610933565b5b9050602002810190610296919061096c565b80604001906102a591906109e8565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361031b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031290610a94565b60405180910390fd5b604051818382375f5f838387895af1610336573d5f5f3e3d5ffd5b505050505080806001019150506101ff565b50505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103a982610363565b810181811067ffffffffffffffff821117156103c8576103c7610373565b5b80604052505050565b5f6103da61034e565b90506103e682826103a0565b919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610414826103eb565b9050919050565b5f6104258261040a565b9050919050565b6104358161041b565b811461043f575f5ffd5b50565b5f813590506104508161042c565b92915050565b5f6104608261040a565b9050919050565b61047081610456565b811461047a575f5ffd5b50565b5f8135905061048b81610467565b92915050565b5f604082840312156104a6576104a561035f565b5b6104b060406103d1565b90505f6104bf84828501610442565b5f8301525060206104d28482850161047d565b60208301525092915050565b5f6104e88261040a565b9050919050565b6104f8816104de565b8114610502575f5ffd5b50565b5f81359050610513816104ef565b92915050565b5f819050919050565b61052b81610519565b8114610535575f5ffd5b50565b5f8135905061054681610522565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261056d5761056c61054c565b5b8235905067ffffffffffffffff81111561058a57610589610550565b5b6020830191508360018202830111156105a6576105a5610554565b5b9250929050565b5f5f83601f8401126105c2576105c161054c565b5b8235905067ffffffffffffffff8111156105df576105de610550565b5b6020830191508360208202830111156105fb576105fa610554565b5b9250929050565b5f5f5f5f5f5f5f60c0888a03121561061d5761061c610357565b5b5f61062a8a828b01610491565b975050604061063b8a828b01610505565b965050606061064c8a828b01610538565b955050608088013567ffffffffffffffff81111561066d5761066c61035b565b5b6106798a828b01610558565b945094505060a088013567ffffffffffffffff81111561069c5761069b61035b565b5b6106a88a828b016105ad565b925092505092959891949750929550565b5f819050919050565b6106cb816106b9565b82525050565b5f6020820190506106e45f8301846106c2565b92915050565b6106f381610519565b82525050565b5f82825260208201905092915050565b828183375f83830152505050565b5f61072283856106f9565b935061072f838584610709565b61073883610363565b840190509392505050565b5f6040820190506107565f8301866106ea565b8181036020830152610769818486610717565b9050949350505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6107a781610773565b81146107b1575f5ffd5b50565b5f815190506107c28161079e565b92915050565b5f602082840312156107dd576107dc610357565b5b5f6107ea848285016107b4565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61082a826106b9565b9150610835836106b9565b925082820390508181111561084d5761084c6107f3565b5b92915050565b5f82825260208201905092915050565b7f6469646e27742073617920746865206d6167696320776f7264000000000000005f82015250565b5f610897601983610853565b91506108a282610863565b602082019050919050565b5f6020820190508181035f8301526108c48161088b565b9050919050565b7f696e636f72726563742063616c6c696e6720636f6e74657874000000000000005f82015250565b5f6108ff601983610853565b915061090a826108cb565b602082019050919050565b5f6020820190508181035f83015261092c816108f3565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f8235600160600383360303811261098757610986610960565b5b80830191505092915050565b61099c8161040a565b81146109a6575f5ffd5b50565b5f813590506109b781610993565b92915050565b5f602082840312156109d2576109d1610357565b5b5f6109df848285016109a9565b91505092915050565b5f5f83356001602003843603038112610a0457610a03610960565b5b80840192508235915067ffffffffffffffff821115610a2657610a25610964565b5b602083019250600182023603831315610a4257610a41610968565b5b509250929050565b7f475076323a20666f7262696464656e20696e746572616374696f6e00000000005f82015250565b5f610a7e601b83610853565b9150610a8982610a4a565b602082019050919050565b5f6020820190508181035f830152610aab81610a72565b905091905056fea2646970667358221220660d187da1e475ceefbf157d27c034019c73dc808ef7cc51fe1a5e58fce0379464736f6c634300081e0033", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b46054151461002d575b5f5ffd5b61004760048036038101906100429190610602565b61005d565b60405161005491906106d1565b60405180910390f35b5f61006988848461018c565b5a90505f8773ffffffffffffffffffffffffffffffffffffffff16631626ba7e8888886040518463ffffffff1660e01b81526004016100aa93929190610743565b602060405180830381865afa1580156100c5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e991906107c8565b90505a826100f79190610820565b9150631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610180576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610177906108ad565b60405180910390fd5b50979650505050505050565b825f015173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16146101fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f490610915565b60405180910390fd5b5f5b82829050811015610348575f83838381811061021e5761021d610933565b5b9050602002810190610230919061096c565b5f01602081019061024191906109bd565b90505f84848481811061025757610256610933565b5b9050602002810190610269919061096c565b602001359050365f86868681811061028457610283610933565b5b9050602002810190610296919061096c565b80604001906102a591906109e8565b91509150876020015173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361031b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031290610a94565b60405180910390fd5b604051818382375f5f838387895af1610336573d5f5f3e3d5ffd5b505050505080806001019150506101ff565b50505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103a982610363565b810181811067ffffffffffffffff821117156103c8576103c7610373565b5b80604052505050565b5f6103da61034e565b90506103e682826103a0565b919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610414826103eb565b9050919050565b5f6104258261040a565b9050919050565b6104358161041b565b811461043f575f5ffd5b50565b5f813590506104508161042c565b92915050565b5f6104608261040a565b9050919050565b61047081610456565b811461047a575f5ffd5b50565b5f8135905061048b81610467565b92915050565b5f604082840312156104a6576104a561035f565b5b6104b060406103d1565b90505f6104bf84828501610442565b5f8301525060206104d28482850161047d565b60208301525092915050565b5f6104e88261040a565b9050919050565b6104f8816104de565b8114610502575f5ffd5b50565b5f81359050610513816104ef565b92915050565b5f819050919050565b61052b81610519565b8114610535575f5ffd5b50565b5f8135905061054681610522565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261056d5761056c61054c565b5b8235905067ffffffffffffffff81111561058a57610589610550565b5b6020830191508360018202830111156105a6576105a5610554565b5b9250929050565b5f5f83601f8401126105c2576105c161054c565b5b8235905067ffffffffffffffff8111156105df576105de610550565b5b6020830191508360208202830111156105fb576105fa610554565b5b9250929050565b5f5f5f5f5f5f5f60c0888a03121561061d5761061c610357565b5b5f61062a8a828b01610491565b975050604061063b8a828b01610505565b965050606061064c8a828b01610538565b955050608088013567ffffffffffffffff81111561066d5761066c61035b565b5b6106798a828b01610558565b945094505060a088013567ffffffffffffffff81111561069c5761069b61035b565b5b6106a88a828b016105ad565b925092505092959891949750929550565b5f819050919050565b6106cb816106b9565b82525050565b5f6020820190506106e45f8301846106c2565b92915050565b6106f381610519565b82525050565b5f82825260208201905092915050565b828183375f83830152505050565b5f61072283856106f9565b935061072f838584610709565b61073883610363565b840190509392505050565b5f6040820190506107565f8301866106ea565b8181036020830152610769818486610717565b9050949350505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6107a781610773565b81146107b1575f5ffd5b50565b5f815190506107c28161079e565b92915050565b5f602082840312156107dd576107dc610357565b5b5f6107ea848285016107b4565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61082a826106b9565b9150610835836106b9565b925082820390508181111561084d5761084c6107f3565b5b92915050565b5f82825260208201905092915050565b7f6469646e27742073617920746865206d6167696320776f7264000000000000005f82015250565b5f610897601983610853565b91506108a282610863565b602082019050919050565b5f6020820190508181035f8301526108c48161088b565b9050919050565b7f696e636f72726563742063616c6c696e6720636f6e74657874000000000000005f82015250565b5f6108ff601983610853565b915061090a826108cb565b602082019050919050565b5f6020820190508181035f83015261092c816108f3565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f8235600160600383360303811261098757610986610960565b5b80830191505092915050565b61099c8161040a565b81146109a6575f5ffd5b50565b5f813590506109b781610993565b92915050565b5f602082840312156109d2576109d1610357565b5b5f6109df848285016109a9565b91505092915050565b5f5f83356001602003843603038112610a0457610a03610960565b5b80840192508235915067ffffffffffffffff821115610a2657610a25610964565b5b602083019250600182023603831315610a4257610a41610968565b5b509250929050565b7f475076323a20666f7262696464656e20696e746572616374696f6e00000000005f82015250565b5f610a7e601b83610853565b9150610a8982610a4a565b602082019050919050565b5f6020820190508181035f830152610aab81610a72565b905091905056fea2646970667358221220660d187da1e475ceefbf157d27c034019c73dc808ef7cc51fe1a5e58fce0379464736f6c634300081e0033", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/artifacts/Solver.json b/crates/contracts/artifacts/Solver.json deleted file mode 100644 index 94ba3bd7da..0000000000 --- a/crates/contracts/artifacts/Solver.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "contract Trader", - "name": "trader", - "type": "address" - }, - { - "internalType": "contract ISettlement", - "name": "settlementContract", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "nativeToken", - "type": "address" - }, - { - "internalType": "address", - "name": "spardose", - "type": "address" - } - ], - "name": "ensureTradePreconditions", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "bool", - "name": "countGas", - "type": "bool" - } - ], - "name": "storeBalance", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract ISettlement", - "name": "settlementContract", - "type": "address" - }, - { - "internalType": "address[]", - "name": "tokens", - "type": "address[]" - }, - { - "internalType": "address payable", - "name": "receiver", - "type": "address" - }, - { - "internalType": "bytes", - "name": "settlementCall", - "type": "bytes" - } - ], - "name": "swap", - "outputs": [ - { - "internalType": "uint256", - "name": "gasUsed", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "queriedBalances", - "type": "uint256[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x6080604052348015600e575f5ffd5b506109c58061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80631d47e7f4146100435780632582edb41461006d5780633bbb2e1d14610082575b5f5ffd5b610056610051366004610702565b610095565b6040516100649291906107c6565b60405180910390f35b61008061007b366004610813565b610229565b005b610080610090366004610888565b61031e565b5f606033301461012b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f6f6e6c792073696d756c6174696f6e206c6f67696320697320616c6c6f77656460448201527f20746f2063616c6c202773776170272066756e6374696f6e0000000000000000606482015260840160405180910390fd5b5f8573ffffffffffffffffffffffffffffffffffffffff165f6040515f6040518083038185875af1925050503d805f8114610181576040519150601f19603f3d011682016040523d82523d5f602084013e610186565b606091505b505090505061019687878a61048d565b6101a1888585610557565b91506101ae87878a61048d565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c80548060200260200160405190810160405280929190818152602001828054801561021757602002820191905f5260205f20905b815481526020019060010190808311610203575b50505050509050965096945050505050565b5f5a6040517f542eb77d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152878116602483015260448201879052858116606483015284811660848301529192509088169063542eb77d9060a4015f604051808303815f87803b1580156102b4575f5ffd5b505af11580156102c6573d5f5f3e3d5ffd5b505050505a6102d59082610901565b6102e19061116c61091a565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f828254610310919061091a565b909155505050505050505050565b5f5a90507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff861614610407576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528616906370a0823190602401602060405180830381865afa1580156103de573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610402919061092d565b610420565b8373ffffffffffffffffffffffffffffffffffffffff16315b81546001810183555f9283526020909220909101558115610487575a6104469082610901565b6104529061116c61091a565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f828254610481919061091a565b90915550505b50505050565b5f5b828110156104875730633bbb2e1d8585848181106104af576104af610944565b90506020020160208101906104c49190610971565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff918216600482015290851660248201525f60448201526064015f604051808303815f87803b158015610535575f5ffd5b505af1158015610547573d5f5f3e3d5ffd5b50506001909201915061048f9050565b5f5f5a90506105b284848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505073ffffffffffffffffffffffffffffffffffffffff8916929150506105f3565b507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b545a6105e09083610901565b6105ea9190610901565b95945050505050565b6060610600835f84610607565b9392505050565b60605f8473ffffffffffffffffffffffffffffffffffffffff168484604051610630919061098c565b5f6040518083038185875af1925050503d805f811461066a576040519150601f19603f3d011682016040523d82523d5f602084013e61066f565b606091505b50925090508061068157815160208301fd5b509392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106aa575f5ffd5b50565b80356106b881610689565b919050565b5f5f83601f8401126106cd575f5ffd5b50813567ffffffffffffffff8111156106e4575f5ffd5b6020830191508360208285010111156106fb575f5ffd5b9250929050565b5f5f5f5f5f5f60808789031215610717575f5ffd5b863561072281610689565b9550602087013567ffffffffffffffff81111561073d575f5ffd5b8701601f8101891361074d575f5ffd5b803567ffffffffffffffff811115610763575f5ffd5b8960208260051b8401011115610777575f5ffd5b6020919091019550935061078d604088016106ad565b9250606087013567ffffffffffffffff8111156107a8575f5ffd5b6107b489828a016106bd565b979a9699509497509295939492505050565b5f60408201848352604060208401528084518083526060850191506020860192505f5b818110156108075783518352602093840193909201916001016107e9565b50909695505050505050565b5f5f5f5f5f5f60c08789031215610828575f5ffd5b863561083381610689565b9550602087013561084381610689565b9450604087013561085381610689565b935060608701359250608087013561086a81610689565b915060a087013561087a81610689565b809150509295509295509295565b5f5f5f6060848603121561089a575f5ffd5b83356108a581610689565b925060208401356108b581610689565b9150604084013580151581146108c9575f5ffd5b809150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610914576109146108d4565b92915050565b80820180821115610914576109146108d4565b5f6020828403121561093d575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215610981575f5ffd5b813561060081610689565b5f82515f5b818110156109ab5760208186018101518583015201610991565b505f92019182525091905056fea164736f6c634300081e000a", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80631d47e7f4146100435780632582edb41461006d5780633bbb2e1d14610082575b5f5ffd5b610056610051366004610702565b610095565b6040516100649291906107c6565b60405180910390f35b61008061007b366004610813565b610229565b005b610080610090366004610888565b61031e565b5f606033301461012b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f6f6e6c792073696d756c6174696f6e206c6f67696320697320616c6c6f77656460448201527f20746f2063616c6c202773776170272066756e6374696f6e0000000000000000606482015260840160405180910390fd5b5f8573ffffffffffffffffffffffffffffffffffffffff165f6040515f6040518083038185875af1925050503d805f8114610181576040519150601f19603f3d011682016040523d82523d5f602084013e610186565b606091505b505090505061019687878a61048d565b6101a1888585610557565b91506101ae87878a61048d565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c80548060200260200160405190810160405280929190818152602001828054801561021757602002820191905f5260205f20905b815481526020019060010190808311610203575b50505050509050965096945050505050565b5f5a6040517f542eb77d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152878116602483015260448201879052858116606483015284811660848301529192509088169063542eb77d9060a4015f604051808303815f87803b1580156102b4575f5ffd5b505af11580156102c6573d5f5f3e3d5ffd5b505050505a6102d59082610901565b6102e19061116c61091a565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f828254610310919061091a565b909155505050505050505050565b5f5a90507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff861614610407576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528616906370a0823190602401602060405180830381865afa1580156103de573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610402919061092d565b610420565b8373ffffffffffffffffffffffffffffffffffffffff16315b81546001810183555f9283526020909220909101558115610487575a6104469082610901565b6104529061116c61091a565b7f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b5f828254610481919061091a565b90915550505b50505050565b5f5b828110156104875730633bbb2e1d8585848181106104af576104af610944565b90506020020160208101906104c49190610971565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff918216600482015290851660248201525f60448201526064015f604051808303815f87803b158015610535575f5ffd5b505af1158015610547573d5f5f3e3d5ffd5b50506001909201915061048f9050565b5f5f5a90506105b284848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505073ffffffffffffffffffffffffffffffffffffffff8916929150506105f3565b507f14f5b2c185fc03c75c787d1f0e10ea137cc6d235a0047448eff18c9a173a722b545a6105e09083610901565b6105ea9190610901565b95945050505050565b6060610600835f84610607565b9392505050565b60605f8473ffffffffffffffffffffffffffffffffffffffff168484604051610630919061098c565b5f6040518083038185875af1925050503d805f811461066a576040519150601f19603f3d011682016040523d82523d5f602084013e61066f565b606091505b50925090508061068157815160208301fd5b509392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106aa575f5ffd5b50565b80356106b881610689565b919050565b5f5f83601f8401126106cd575f5ffd5b50813567ffffffffffffffff8111156106e4575f5ffd5b6020830191508360208285010111156106fb575f5ffd5b9250929050565b5f5f5f5f5f5f60808789031215610717575f5ffd5b863561072281610689565b9550602087013567ffffffffffffffff81111561073d575f5ffd5b8701601f8101891361074d575f5ffd5b803567ffffffffffffffff811115610763575f5ffd5b8960208260051b8401011115610777575f5ffd5b6020919091019550935061078d604088016106ad565b9250606087013567ffffffffffffffff8111156107a8575f5ffd5b6107b489828a016106bd565b979a9699509497509295939492505050565b5f60408201848352604060208401528084518083526060850191506020860192505f5b818110156108075783518352602093840193909201916001016107e9565b50909695505050505050565b5f5f5f5f5f5f60c08789031215610828575f5ffd5b863561083381610689565b9550602087013561084381610689565b9450604087013561085381610689565b935060608701359250608087013561086a81610689565b915060a087013561087a81610689565b809150509295509295509295565b5f5f5f6060848603121561089a575f5ffd5b83356108a581610689565b925060208401356108b581610689565b9150604084013580151581146108c9575f5ffd5b809150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610914576109146108d4565b92915050565b80820180821115610914576109146108d4565b5f6020828403121561093d575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215610981575f5ffd5b813561060081610689565b5f82515f5b818110156109ab5760208186018101518583015201610991565b505f92019182525091905056fea164736f6c634300081e000a", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/artifacts/Spardose.json b/crates/contracts/artifacts/Spardose.json deleted file mode 100644 index 16ba804c7f..0000000000 --- a/crates/contracts/artifacts/Spardose.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "requestFunds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x6080604052348015600e575f5ffd5b506102ca8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063494666b61461002d575b5f5ffd5b61004061003b366004610230565b610042565b005b61006373ffffffffffffffffffffffffffffffffffffffff83163383610067565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052905f906100f990861683610175565b905061010481610189565b61016e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a207472616e73666572206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b6060610182835f846101ae565b9392505050565b5f81515f14806101a85750818060200190518101906101a89190610272565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516101d79190610291565b5f6040518083038185875af1925050503d805f8114610211576040519150601f19603f3d011682016040523d82523d5f602084013e610216565b606091505b50925090508061022857815160208301fd5b509392505050565b5f5f60408385031215610241575f5ffd5b823573ffffffffffffffffffffffffffffffffffffffff81168114610264575f5ffd5b946020939093013593505050565b5f60208284031215610282575f5ffd5b81518015158114610182575f5ffd5b5f82515f5b818110156102b05760208186018101518583015201610296565b505f92019182525091905056fea164736f6c634300081e000a", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063494666b61461002d575b5f5ffd5b61004061003b366004610230565b610042565b005b61006373ffffffffffffffffffffffffffffffffffffffff83163383610067565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052905f906100f990861683610175565b905061010481610189565b61016e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a207472616e73666572206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b6060610182835f846101ae565b9392505050565b5f81515f14806101a85750818060200190518101906101a89190610272565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff1684846040516101d79190610291565b5f6040518083038185875af1925050503d805f8114610211576040519150601f19603f3d011682016040523d82523d5f602084013e610216565b606091505b50925090508061022857815160208301fd5b509392505050565b5f5f60408385031215610241575f5ffd5b823573ffffffffffffffffffffffffffffffffffffffff81168114610264575f5ffd5b946020939093013593505050565b5f60208284031215610282575f5ffd5b81518015158114610182575f5ffd5b5f82515f5b818110156102b05760208186018101518583015201610296565b505f92019182525091905056fea164736f6c634300081e000a", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/artifacts/SushiSwapRouter.json b/crates/contracts/artifacts/SushiSwapRouter.json deleted file mode 120000 index e485e1a596..0000000000 --- a/crates/contracts/artifacts/SushiSwapRouter.json +++ /dev/null @@ -1 +0,0 @@ -IUniswapLikeRouter.json \ No newline at end of file diff --git a/crates/contracts/artifacts/Swapper.json b/crates/contracts/artifacts/Swapper.json deleted file mode 100644 index eb7e177447..0000000000 --- a/crates/contracts/artifacts/Swapper.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "isValidSignature", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract ISettlement", - "name": "settlement", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "internalType": "struct Asset", - "name": "sell", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "internalType": "struct Asset", - "name": "buy", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "internalType": "struct Allowance", - "name": "allowance", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - } - ], - "internalType": "struct Interaction[]", - "name": "calls", - "type": "tuple[]" - } - ], - "name": "swap", - "outputs": [ - { - "internalType": "uint256", - "name": "gasUsed", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b506111df806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80631626ba7e1461003b578063e8333e0d146100a7575b600080fd5b610071610049366004610a9b565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b6100ba6100b5366004610b54565b6100c8565b60405190815260200161009e565b6000602086018035906100db9088610c11565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa158015610147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061016b9190610c2e565b101561017957506000610858565b6102178773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101eb9190610c47565b60006101fa60208a018a610c11565b73ffffffffffffffffffffffffffffffffffffffff169190610862565b61029a8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610265573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102899190610c47565b602088018035906101fa908a610c11565b6040805160028082526060820183526000926020830190803683370190505090506102c86020880188610c11565b816000815181106102db576102db610c93565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015261030b90870187610c11565b8160018151811061031e5761031e610c93565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516002808252606082018352600093919290918301908036833701905050905086602001358160008151811061037e5761037e610c93565b6020026020010181815250508760200135816001815181106103a2576103a2610c93565b6020908102919091010152604080516001808252818301909252600091816020015b6104406040518061016001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600063ffffffff16815260200160008019168152602001600081526020016000815260200160008152602001606081525090565b8152602001906001900390816103c45790505090506040518061016001604052806000815260200160018152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020018a6020013581526020018960200135815260200163ffffffff801681526020016000801b815260200160008152602001604081526020016000815260200130604051602001610506919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b6040516020818303038152906040528152508160008151811061052b5761052b610c93565b602002602001018190525061053e610a74565b60208089013590610551908c018c610c11565b73ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8d61057a60208d018d610c11565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa1580156105ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060e9190610c2e565b101561078c5760408051600180825281830190925290816020015b60408051606080820183526000808352602083015291810191909152815260200190600190039081610629575050815261066660208b018b610c11565b8151805160009061067957610679610c93565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff9092169091526106ac908b018b610c11565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b36106d460208b018b610c11565b60405173ffffffffffffffffffffffffffffffffffffffff909116602482015260208b01356044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b929092179091529050816000602002015160008151811061077c5761077c610c93565b6020026020010151604001819052505b6107968688610d3a565b60208201526040516108519073ffffffffffffffffffffffffffffffffffffffff8d16906313d79a0b906107d49088908890889088906024016110a1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b9290921790915273ffffffffffffffffffffffffffffffffffffffff8e169150610971565b9450505050505b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052906000906108f590861683610986565b905061090081610994565b61096a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b600061097f836000846109bb565b9392505050565b606061097f836000846109ee565b60008151600014806109b55750818060200190518101906109b5919061115a565b92915050565b60005a905060008083516020850186885af16109db573d6000803e3d6000fd5b5a6109e6908261117c565b949350505050565b606060008473ffffffffffffffffffffffffffffffffffffffff168484604051610a1891906111b6565b60006040518083038185875af1925050503d8060008114610a55576040519150601f19603f3d011682016040523d82523d6000602084013e610a5a565b606091505b509250905080610a6c57815160208301fd5b509392505050565b60405180606001604052806003905b6060815260200190600190039081610a835790505090565b600080600060408486031215610ab057600080fd5b83359250602084013567ffffffffffffffff80821115610acf57600080fd5b818601915086601f830112610ae357600080fd5b813581811115610af257600080fd5b876020828501011115610b0457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff81168114610b3957600080fd5b50565b600060408284031215610b4e57600080fd5b50919050565b6000806000806000806101008789031215610b6e57600080fd5b8635610b7981610b17565b9550610b888860208901610b3c565b9450610b978860608901610b3c565b9350610ba68860a08901610b3c565b925060e087013567ffffffffffffffff80821115610bc357600080fd5b818901915089601f830112610bd757600080fd5b813581811115610be657600080fd5b8a60208260051b8501011115610bfb57600080fd5b6020830194508093505050509295509295509295565b600060208284031215610c2357600080fd5b813561097f81610b17565b600060208284031215610c4057600080fd5b5051919050565b600060208284031215610c5957600080fd5b815161097f81610b17565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6040516060810167ffffffffffffffff81118282101715610ce557610ce5610c64565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d3257610d32610c64565b604052919050565b600067ffffffffffffffff80841115610d5557610d55610c64565b8360051b6020610d66818301610ceb565b868152918501918181019036841115610d7e57600080fd5b865b84811015610e6d57803586811115610d985760008081fd5b88016060368290031215610dac5760008081fd5b610db4610cc2565b8135610dbf81610b17565b8152818601358682015260408083013589811115610ddd5760008081fd5b9290920191601f3681850112610df35760008081fd5b83358a811115610e0557610e05610c64565b610e34897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08484011601610ceb565b91508082523689828701011115610e4b5760008081fd5b808986018a840137600090820189015290820152845250918301918301610d80565b50979650505050505050565b60005b83811015610e94578181015183820152602001610e7c565b50506000910152565b60008151808452610eb5816020860160208601610e79565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015610fc75782840389528151610160815186528682015187870152604080830151610f4a8289018273ffffffffffffffffffffffffffffffffffffffff169052565b5050606082810151908701526080808301519087015260a08083015163ffffffff169087015260c0808301519087015260e080830151908701526101008083015190870152610120808301519087015261014091820151918601819052610fb381870183610e9d565b9a87019a9550505090840190600101610f05565b5091979650505050505050565b6000826060808201846000805b6003811015610fc7578584038952825180518086526020918201918087019190600582901b88018101865b8381101561108a578982037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00185528551805173ffffffffffffffffffffffffffffffffffffffff16835283810151848401526040908101519083018c90526110778c840182610e9d565b968401969584019592505060010161100c565b509c81019c97509590950194505050600101610fe1565b6080808252855190820181905260009060209060a0840190828901845b828110156110f057815173ffffffffffffffffffffffffffffffffffffffff16845292840192908401906001016110be565b5050508381038285015286518082528783019183019060005b8181101561112557835183529284019291840191600101611109565b505084810360408601526111398188610ee7565b92505050828103606084015261114f8185610fd4565b979650505050505050565b60006020828403121561116c57600080fd5b8151801515811461097f57600080fd5b818103818111156109b5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082516111c8818460208701610e79565b919091019291505056fea164736f6c6343000811000a", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80631626ba7e1461003b578063e8333e0d146100a7575b600080fd5b610071610049366004610a9b565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b6100ba6100b5366004610b54565b6100c8565b60405190815260200161009e565b6000602086018035906100db9088610c11565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa158015610147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061016b9190610c2e565b101561017957506000610858565b6102178773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101eb9190610c47565b60006101fa60208a018a610c11565b73ffffffffffffffffffffffffffffffffffffffff169190610862565b61029a8773ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610265573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102899190610c47565b602088018035906101fa908a610c11565b6040805160028082526060820183526000926020830190803683370190505090506102c86020880188610c11565b816000815181106102db576102db610c93565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015261030b90870187610c11565b8160018151811061031e5761031e610c93565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516002808252606082018352600093919290918301908036833701905050905086602001358160008151811061037e5761037e610c93565b6020026020010181815250508760200135816001815181106103a2576103a2610c93565b6020908102919091010152604080516001808252818301909252600091816020015b6104406040518061016001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600063ffffffff16815260200160008019168152602001600081526020016000815260200160008152602001606081525090565b8152602001906001900390816103c45790505090506040518061016001604052806000815260200160018152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020018a6020013581526020018960200135815260200163ffffffff801681526020016000801b815260200160008152602001604081526020016000815260200130604051602001610506919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b6040516020818303038152906040528152508160008151811061052b5761052b610c93565b602002602001018190525061053e610a74565b60208089013590610551908c018c610c11565b73ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8d61057a60208d018d610c11565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa1580156105ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060e9190610c2e565b101561078c5760408051600180825281830190925290816020015b60408051606080820183526000808352602083015291810191909152815260200190600190039081610629575050815261066660208b018b610c11565b8151805160009061067957610679610c93565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff9092169091526106ac908b018b610c11565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b36106d460208b018b610c11565b60405173ffffffffffffffffffffffffffffffffffffffff909116602482015260208b01356044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b929092179091529050816000602002015160008151811061077c5761077c610c93565b6020026020010151604001819052505b6107968688610d3a565b60208201526040516108519073ffffffffffffffffffffffffffffffffffffffff8d16906313d79a0b906107d49088908890889088906024016110a1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b9290921790915273ffffffffffffffffffffffffffffffffffffffff8e169150610971565b9450505050505b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052906000906108f590861683610986565b905061090081610994565b61096a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640160405180910390fd5b5050505050565b600061097f836000846109bb565b9392505050565b606061097f836000846109ee565b60008151600014806109b55750818060200190518101906109b5919061115a565b92915050565b60005a905060008083516020850186885af16109db573d6000803e3d6000fd5b5a6109e6908261117c565b949350505050565b606060008473ffffffffffffffffffffffffffffffffffffffff168484604051610a1891906111b6565b60006040518083038185875af1925050503d8060008114610a55576040519150601f19603f3d011682016040523d82523d6000602084013e610a5a565b606091505b509250905080610a6c57815160208301fd5b509392505050565b60405180606001604052806003905b6060815260200190600190039081610a835790505090565b600080600060408486031215610ab057600080fd5b83359250602084013567ffffffffffffffff80821115610acf57600080fd5b818601915086601f830112610ae357600080fd5b813581811115610af257600080fd5b876020828501011115610b0457600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff81168114610b3957600080fd5b50565b600060408284031215610b4e57600080fd5b50919050565b6000806000806000806101008789031215610b6e57600080fd5b8635610b7981610b17565b9550610b888860208901610b3c565b9450610b978860608901610b3c565b9350610ba68860a08901610b3c565b925060e087013567ffffffffffffffff80821115610bc357600080fd5b818901915089601f830112610bd757600080fd5b813581811115610be657600080fd5b8a60208260051b8501011115610bfb57600080fd5b6020830194508093505050509295509295509295565b600060208284031215610c2357600080fd5b813561097f81610b17565b600060208284031215610c4057600080fd5b5051919050565b600060208284031215610c5957600080fd5b815161097f81610b17565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6040516060810167ffffffffffffffff81118282101715610ce557610ce5610c64565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d3257610d32610c64565b604052919050565b600067ffffffffffffffff80841115610d5557610d55610c64565b8360051b6020610d66818301610ceb565b868152918501918181019036841115610d7e57600080fd5b865b84811015610e6d57803586811115610d985760008081fd5b88016060368290031215610dac5760008081fd5b610db4610cc2565b8135610dbf81610b17565b8152818601358682015260408083013589811115610ddd5760008081fd5b9290920191601f3681850112610df35760008081fd5b83358a811115610e0557610e05610c64565b610e34897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08484011601610ceb565b91508082523689828701011115610e4b5760008081fd5b808986018a840137600090820189015290820152845250918301918301610d80565b50979650505050505050565b60005b83811015610e94578181015183820152602001610e7c565b50506000910152565b60008151808452610eb5816020860160208601610e79565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015610fc75782840389528151610160815186528682015187870152604080830151610f4a8289018273ffffffffffffffffffffffffffffffffffffffff169052565b5050606082810151908701526080808301519087015260a08083015163ffffffff169087015260c0808301519087015260e080830151908701526101008083015190870152610120808301519087015261014091820151918601819052610fb381870183610e9d565b9a87019a9550505090840190600101610f05565b5091979650505050505050565b6000826060808201846000805b6003811015610fc7578584038952825180518086526020918201918087019190600582901b88018101865b8381101561108a578982037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00185528551805173ffffffffffffffffffffffffffffffffffffffff16835283810151848401526040908101519083018c90526110778c840182610e9d565b968401969584019592505060010161100c565b509c81019c97509590950194505050600101610fe1565b6080808252855190820181905260009060209060a0840190828901845b828110156110f057815173ffffffffffffffffffffffffffffffffffffffff16845292840192908401906001016110be565b5050508381038285015286518082528783019183019060005b8181101561112557835183529284019291840191600101611109565b505084810360408601526111398188610ee7565b92505050828103606084015261114f8185610fd4565b979650505050505050565b60006020828403121561116c57600080fd5b8151801515811461097f57600080fd5b818103818111156109b5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082516111c8818460208701610e79565b919091019291505056fea164736f6c6343000811000a", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/artifacts/SwaprRouter.json b/crates/contracts/artifacts/SwaprRouter.json deleted file mode 120000 index e485e1a596..0000000000 --- a/crates/contracts/artifacts/SwaprRouter.json +++ /dev/null @@ -1 +0,0 @@ -IUniswapLikeRouter.json \ No newline at end of file diff --git a/crates/contracts/artifacts/TestnetUniswapV2Router02.json b/crates/contracts/artifacts/TestnetUniswapV2Router02.json deleted file mode 120000 index e485e1a596..0000000000 --- a/crates/contracts/artifacts/TestnetUniswapV2Router02.json +++ /dev/null @@ -1 +0,0 @@ -IUniswapLikeRouter.json \ No newline at end of file diff --git a/crates/contracts/artifacts/Trader.json b/crates/contracts/artifacts/Trader.json deleted file mode 100644 index 2bb2245e43..0000000000 --- a/crates/contracts/artifacts/Trader.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "abi": [ - { - "stateMutability": "payable", - "type": "fallback" - }, - { - "inputs": [ - { - "internalType": "contract ISettlement", - "name": "settlementContract", - "type": "address" - }, - { - "internalType": "address", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "nativeToken", - "type": "address" - }, - { - "internalType": "address", - "name": "spardose", - "type": "address" - } - ], - "name": "ensureTradePreconditions", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "isValidSignature", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "address", - "name": "vaultRelayer", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "safeApprove", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x6080604052348015600e575f5ffd5b50610d008061001c5f395ff3fe608060405260043610610037575f3560e01c80631626ba7e1461008d578063542eb77d14610104578063eb5625d9146101255761003e565b3661003e57005b5f6100835f368080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525062010000939250506101449050565b9050805160208201f35b348015610098575f5ffd5b506100cf6100a7366004610b01565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b34801561010f575f5ffd5b5061012361011e366004610b9c565b6101c2565b005b348015610130575f5ffd5b5061012361013f366004610c00565b610916565b60605f8373ffffffffffffffffffffffffffffffffffffffff168360405161016c9190610c3e565b5f60405180830381855af49150503d805f81146101a4576040519150601f19603f3d011682016040523d82523d5f602084013e6101a9565b606091505b5092509050806101bb57815160208301fd5b5092915050565b7f02565dba7d68dcbed629110024b7b5e785bfc1a484602045eea513de8a2dcf99805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082161790915560ff16156102a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f70726570617265537761702063616e206f6e6c792062652063616c6c6564206f60448201527f6e6365000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036103e4576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8616906370a0823190602401602060405180830381865afa158015610340573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103649190610c6a565b9050838110156103e2575f6103798286610c81565b90508047106103e0578373ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156103c8575f5ffd5b505af11580156103da573d5f5f3e3d5ffd5b50505050505b505b505b5f8573ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561042e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104529190610cb9565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff80831660248301529192505f9187169063dd62ed3e90604401602060405180830381865afa1580156104c7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104eb9190610c6a565b905084811015610748576040517feb5625d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8088166004830152831660248201525f6044820152309063eb5625d9906064015f604051808303815f87803b158015610567575f5ffd5b505af1925050508015610578575060015b506040517feb5625d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8088166004830152831660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6044820152309063eb5625d9906064015f604051808303815f87803b15801561060b575f5ffd5b505af192505050801561061c575060015b506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301525f919088169063dd62ed3e90604401602060405180830381865afa158015610690573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b49190610c6a565b905085811015610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f74726164657220646964206e6f7420676976652074686520726571756972656460448201527f20617070726f76616c7300000000000000000000000000000000000000000000606482015260840161029a565b505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8816906370a0823190602401602060405180830381865afa1580156107b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d69190610c6a565b90508581101561090c5773ffffffffffffffffffffffffffffffffffffffff841663494666b688610807848a610c81565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044015f604051808303815f87803b15801561086f575f5ffd5b505af1925050508015610880575060015b61090c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f74726164657220646f6573206e6f74206861766520656e6f7567682073656c6c60448201527f20746f6b656e0000000000000000000000000000000000000000000000000000606482015260840161029a565b5050505050505050565b61093773ffffffffffffffffffffffffffffffffffffffff8416838361093c565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052905f906109ce90861683610a46565b90506109d981610a5a565b610a3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640161029a565b5050505050565b6060610a53835f84610a7f565b9392505050565b5f81515f1480610a79575081806020019051810190610a799190610cd4565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff168484604051610aa89190610c3e565b5f6040518083038185875af1925050503d805f8114610ae2576040519150601f19603f3d011682016040523d82523d5f602084013e610ae7565b606091505b509250905080610af957815160208301fd5b509392505050565b5f5f5f60408486031215610b13575f5ffd5b83359250602084013567ffffffffffffffff811115610b30575f5ffd5b8401601f81018613610b40575f5ffd5b803567ffffffffffffffff811115610b56575f5ffd5b866020828401011115610b67575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610b99575f5ffd5b50565b5f5f5f5f5f60a08688031215610bb0575f5ffd5b8535610bbb81610b78565b94506020860135610bcb81610b78565b9350604086013592506060860135610be281610b78565b91506080860135610bf281610b78565b809150509295509295909350565b5f5f5f60608486031215610c12575f5ffd5b8335610c1d81610b78565b92506020840135610c2d81610b78565b929592945050506040919091013590565b5f82515f5b81811015610c5d5760208186018101518583015201610c43565b505f920191825250919050565b5f60208284031215610c7a575f5ffd5b5051919050565b81810381811115610a79577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60208284031215610cc9575f5ffd5b8151610a5381610b78565b5f60208284031215610ce4575f5ffd5b81518015158114610a53575f5ffdfea164736f6c634300081e000a", - "deployedBytecode": "0x608060405260043610610037575f3560e01c80631626ba7e1461008d578063542eb77d14610104578063eb5625d9146101255761003e565b3661003e57005b5f6100835f368080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525062010000939250506101449050565b9050805160208201f35b348015610098575f5ffd5b506100cf6100a7366004610b01565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b34801561010f575f5ffd5b5061012361011e366004610b9c565b6101c2565b005b348015610130575f5ffd5b5061012361013f366004610c00565b610916565b60605f8373ffffffffffffffffffffffffffffffffffffffff168360405161016c9190610c3e565b5f60405180830381855af49150503d805f81146101a4576040519150601f19603f3d011682016040523d82523d5f602084013e6101a9565b606091505b5092509050806101bb57815160208301fd5b5092915050565b7f02565dba7d68dcbed629110024b7b5e785bfc1a484602045eea513de8a2dcf99805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082161790915560ff16156102a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f70726570617265537761702063616e206f6e6c792062652063616c6c6564206f60448201527f6e6365000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036103e4576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8616906370a0823190602401602060405180830381865afa158015610340573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103649190610c6a565b9050838110156103e2575f6103798286610c81565b90508047106103e0578373ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156103c8575f5ffd5b505af11580156103da573d5f5f3e3d5ffd5b50505050505b505b505b5f8573ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561042e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104529190610cb9565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff80831660248301529192505f9187169063dd62ed3e90604401602060405180830381865afa1580156104c7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104eb9190610c6a565b905084811015610748576040517feb5625d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8088166004830152831660248201525f6044820152309063eb5625d9906064015f604051808303815f87803b158015610567575f5ffd5b505af1925050508015610578575060015b506040517feb5625d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8088166004830152831660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6044820152309063eb5625d9906064015f604051808303815f87803b15801561060b575f5ffd5b505af192505050801561061c575060015b506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301525f919088169063dd62ed3e90604401602060405180830381865afa158015610690573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b49190610c6a565b905085811015610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f74726164657220646964206e6f7420676976652074686520726571756972656460448201527f20617070726f76616c7300000000000000000000000000000000000000000000606482015260840161029a565b505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8816906370a0823190602401602060405180830381865afa1580156107b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d69190610c6a565b90508581101561090c5773ffffffffffffffffffffffffffffffffffffffff841663494666b688610807848a610c81565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044015f604051808303815f87803b15801561086f575f5ffd5b505af1925050508015610880575060015b61090c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f74726164657220646f6573206e6f74206861766520656e6f7567682073656c6c60448201527f20746f6b656e0000000000000000000000000000000000000000000000000000606482015260840161029a565b5050505050505050565b61093773ffffffffffffffffffffffffffffffffffffffff8416838361093c565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052905f906109ce90861683610a46565b90506109d981610a5a565b610a3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640161029a565b5050505050565b6060610a53835f84610a7f565b9392505050565b5f81515f1480610a79575081806020019051810190610a799190610cd4565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff168484604051610aa89190610c3e565b5f6040518083038185875af1925050503d805f8114610ae2576040519150601f19603f3d011682016040523d82523d5f602084013e610ae7565b606091505b509250905080610af957815160208301fd5b509392505050565b5f5f5f60408486031215610b13575f5ffd5b83359250602084013567ffffffffffffffff811115610b30575f5ffd5b8401601f81018613610b40575f5ffd5b803567ffffffffffffffff811115610b56575f5ffd5b866020828401011115610b67575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610b99575f5ffd5b50565b5f5f5f5f5f60a08688031215610bb0575f5ffd5b8535610bbb81610b78565b94506020860135610bcb81610b78565b9350604086013592506060860135610be281610b78565b91506080860135610bf281610b78565b809150509295509295909350565b5f5f5f60608486031215610c12575f5ffd5b8335610c1d81610b78565b92506020840135610c2d81610b78565b929592945050506040919091013590565b5f82515f5b81811015610c5d5760208186018101518583015201610c43565b505f920191825250919050565b5f60208284031215610c7a575f5ffd5b5051919050565b81810381811115610a79577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60208284031215610cc9575f5ffd5b8151610a5381610b78565b5f60208284031215610ce4575f5ffd5b81518015158114610a53575f5ffdfea164736f6c634300081e000a", - "devdoc": { - "methods": {} - }, - "userdoc": { - "methods": {} - } -} diff --git a/crates/contracts/rustfmt.toml b/crates/contracts/rustfmt.toml deleted file mode 100644 index 0cf3970aa7..0000000000 --- a/crates/contracts/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -# Applying our custom formatting to the generated code is broken. -# That's why we specifically unset those rules for this directory. diff --git a/crates/contracts/solidity/Trader.sol b/crates/contracts/solidity/Trader.sol deleted file mode 100644 index f73e805ec9..0000000000 --- a/crates/contracts/solidity/Trader.sol +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import { IERC20, INativeERC20 } from "./interfaces/IERC20.sol"; -import { Interaction, Trade, ISettlement } from "./interfaces/ISettlement.sol"; -import { Caller } from "./libraries/Caller.sol"; -import { Math } from "./libraries/Math.sol"; -import { SafeERC20 } from "./libraries/SafeERC20.sol"; -import { Spardose } from "./Spardose.sol"; - -/// @title A contract for impersonating a trader. -/// Because this contract code gets put at the address of a trader account it uses -/// a custom storage layout to avoid storage slot conflicts with trader accounts -/// that are smart contracts using the default layout. -/// layout at uint256(keccak256("cowprotocol/services trader impersonator")) -contract Trader layout at 0x02565dba7d68dcbed629110024b7b5e785bfc1a484602045eea513de8a2dcf99 { - using Caller for *; - using Math for *; - using SafeERC20 for *; - - bool private _initializationTriggered; - - /// @dev Address where the original code for the trader implementation is - /// expected to be. Use 0x10000 as its the first "valid" address, since - /// addresses up to 0xffff are reserved for pre-compiles. - /// This is used to proxy calls to the original implementation in case - /// the trader is actually a smart contract. - address constant private TRADER_IMPL = address(0x10000); - - /// @dev Returns whether the trader initialization already happened and - /// sets the flag to true. - function triggerInitialization() private returns (bool value) { - value = _initializationTriggered; - _initializationTriggered = true; - } - - // The `Trader` contract gets deployed on the `from` address of the quote. - // Since the `from` address might be a safe or other smart contract we still - // need to make the `Trader` behave as the original `from` would have in - // case some custom interactions rely on that behavior. - // To do that we simply implement fallback handlers that do delegate calls - // to the original implementation. - fallback() external payable { - bytes memory rdata = TRADER_IMPL.doDelegatecall(msg.data); - assembly { return(add(rdata, 32), mload(rdata)) } - } - // Proxying to the original trader implementation doesn't make sense since - // smart contracts that do something on `receive()` are not supported by the - // settlement contract anyway. - receive() external payable {} - - /// @dev Executes needed actions on behalf of the trader to make the trade possible. - /// (e.g. wrapping ETH, setting approvals, and funding the account) - /// @param settlementContract - pass in settlement contract because it does not have - /// a stable address in tests. - /// @param sellToken - token being sold by the trade - /// @param sellAmount - expected amount to be sold according to the quote - /// @param nativeToken - ERC20 version of the chain's native token - /// @param spardose - piggy bank for requesting additional funds - function ensureTradePreconditions( - ISettlement settlementContract, - address sellToken, - uint256 sellAmount, - address nativeToken, - address spardose - ) external { - require(!triggerInitialization(), "prepareSwap can only be called once"); - - if (sellToken == nativeToken) { - uint256 availableNativeToken = IERC20(sellToken).balanceOf(address(this)); - if (availableNativeToken < sellAmount) { - uint256 amountToWrap = sellAmount - availableNativeToken; - // If the user has sufficient balance, simulate the wrapping the missing - // `ETH` so the user doesn't have to spend gas on that just to get a quote. - // If they are happy with the quote and want to create an order they will - // actually have to do the wrapping, though. Note that we don't attempt to - // wrap if the user doesn't have sufficient `ETH` balance, since that would - // revert. Instead, we fall-through so that we handle insufficient sell - // token balances uniformly for all tokens. - if (address(this).balance >= amountToWrap) { - INativeERC20(nativeToken).deposit{value: amountToWrap}(); - } - } - } - - address vaultRelayer = settlementContract.vaultRelayer(); - uint256 currentAllowance = IERC20(sellToken).allowance(address(this), vaultRelayer); - if (currentAllowance < sellAmount) { - // Simulate an approval to the vault relayer so the user doesn't have to - // spend gas on that just to get a quote. If they are happy with the quote and - // want to create an order they will actually have to do the approvals, though. - // - // We first reset the allowance to 0 since some ERC20 tokens (e.g. USDT) - // require that due to this attack: - // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - // - // In order to handle tokens which are not ERC20 compliant (like USDT) we have - // to use `safeApprove()` instead of the regular `approve()` here. - // - // Some tokens revert when you try to set an approval to 0. To support these - // tokens and USDT at the same time we catch any revert from the 2 approve calls. - try this.safeApprove(sellToken, vaultRelayer, 0) {} catch {} - try this.safeApprove(sellToken, vaultRelayer, type(uint256).max) {} catch {} - uint256 allowance = IERC20(sellToken).allowance(address(this), vaultRelayer); - require(allowance >= sellAmount, "trader did not give the required approvals"); - } - - // Ensure that the user has sufficient sell token balance. If not, request some - // funds from the Spardose (piggy bank) which will be available if balance - // overrides are enabled. - uint256 sellBalance = IERC20(sellToken).balanceOf(address(this)); - if (sellBalance < sellAmount) { - try Spardose(spardose).requestFunds(sellToken, sellAmount - sellBalance) {} - catch { - // The trader does not have sufficient sell token balance, and the - // piggy bank pre-fund failed, as balance overrides are not available. - // Revert with a helpful message. - revert("trader does not have enough sell token"); - } - } - } - - /// @dev Wrap the `safeApprove` function in another function in order to mark it - /// as `external`. That allows us to call it in a try-catch. - function safeApprove(address token, address vaultRelayer, uint amount) external { - IERC20(token).safeApprove(vaultRelayer, amount); - } - - /// @dev Validate all signature requests. This makes "signing" CoW protocol - /// orders trivial. - function isValidSignature(bytes32, bytes calldata) external pure returns (bytes4) { - return 0x1626ba7e; - } -} diff --git a/crates/contracts/src/alloy.rs b/crates/contracts/src/alloy.rs deleted file mode 100644 index b575da1112..0000000000 --- a/crates/contracts/src/alloy.rs +++ /dev/null @@ -1,989 +0,0 @@ -pub mod networks { - pub const MAINNET: u64 = 1; - pub const GNOSIS: u64 = 100; - pub const SEPOLIA: u64 = 11155111; - pub const ARBITRUM_ONE: u64 = 42161; - pub const BASE: u64 = 8453; - pub const POLYGON: u64 = 137; - pub const AVALANCHE: u64 = 43114; - pub const BNB: u64 = 56; - pub const OPTIMISM: u64 = 10; - pub const LENS: u64 = 232; - pub const LINEA: u64 = 59144; - pub const PLASMA: u64 = 9745; -} - -crate::bindings!( - ChainalysisOracle, - crate::deployments! { - MAINNET => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - ARBITRUM_ONE => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - BASE => address!("0x3A91A31cB3dC49b4db9Ce721F50a9D076c8D739B"), - AVALANCHE => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - BNB => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - OPTIMISM => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - POLYGON => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - } -); - -crate::bindings!( - IZeroex, - crate::deployments! { - MAINNET => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - SEPOLIA => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - ARBITRUM_ONE => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - BASE => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - AVALANCHE => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - BNB => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - OPTIMISM => address!("0xdef1abe32c034e558cdd535791643c58a13acc10"), - POLYGON => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - // Not available on Lens - } -); - -crate::bindings!(ERC20Mintable); - -crate::bindings!(GnosisSafe); -crate::bindings!(GnosisSafeCompatibilityFallbackHandler); -crate::bindings!(GnosisSafeProxy); -crate::bindings!(GnosisSafeProxyFactory); - -crate::bindings!(BalancerV2Authorizer); -crate::bindings!(BalancerV2BasePool); -crate::bindings!(BalancerV2BasePoolFactory); -crate::bindings!(BalancerV2WeightedPool); -crate::bindings!(BalancerV2StablePool); -crate::bindings!(BalancerV2ComposableStablePool); -crate::bindings!(BalancerV2LiquidityBootstrappingPool); -crate::bindings!( - BalancerV2WeightedPoolFactory, - // - crate::deployments! { - // - MAINNET => (address!("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9"), 12272147) - // Not available on Sepolia (only version ≥ 4) - // - // Not available on Lens - } -); -crate::bindings!( - BalancerV2WeightedPoolFactoryV3, - // - crate::deployments! { - // - MAINNET => (address!("0x5Dd94Da3644DDD055fcf6B3E1aa310Bb7801EB8b"), 16520627), - // - GNOSIS => (address!("0xC128a9954e6c874eA3d62ce62B468bA073093F25"), 26226256), - // - AVALANCHE => (address!("0x94f68b54191F62f781Fe8298A8A5Fa3ed772d227"), 26389236), - // - OPTIMISM => (address!("0xA0DAbEBAAd1b243BBb243f933013d560819eB66f"), 72832703), - // - POLYGON => (address!("0x82e4cFaef85b1B6299935340c964C942280327f4"), 39036828), - // - BNB => (address!("0x6e4cF292C5349c79cCd66349c3Ed56357dD11B46"), 25474982), - // Not available on Sepolia (only version ≥ 4) - // - // Not available on Lens - } -); -crate::bindings!( - BalancerV2WeightedPoolFactoryV4, - crate::deployments! { - // - MAINNET => (address!("0x897888115Ada5773E02aA29F775430BFB5F34c51"), 16878323), - // - GNOSIS => (address!("0x6CaD2ea22BFA7F4C14Aae92E47F510Cd5C509bc7"), 27055829), - // - // - SEPOLIA => (address!("0x7920BFa1b2041911b354747CA7A6cDD2dfC50Cfd"), 3424893), - // - ARBITRUM_ONE => (address!("0xc7E5ED1054A24Ef31D827E6F86caA58B3Bc168d7"), 72222060), - // - BASE => (address!("0x4C32a8a8fDa4E24139B51b456B42290f51d6A1c4"), 1204869), - // - AVALANCHE => (address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), 27739006), - // - OPTIMISM => (address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), 82737545), - // - POLYGON => (address!("0xFc8a407Bba312ac761D8BFe04CE1201904842B76"), 40611103), - // - BNB => (address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), 26665331), - // Not available on Base and Lens - // - } -); -crate::bindings!( - BalancerV2WeightedPool2TokensFactory, - // - crate::deployments! { - // - MAINNET => (address!("0xa5bf2ddf098bb0ef6d120c98217dd6b141c74ee0"), 12349891), - ARBITRUM_ONE => (address!("0xCF0a32Bbef8F064969F21f7e02328FB577382018"), 222864), - // - OPTIMISM => (address!("0xdAE7e32ADc5d490a43cCba1f0c736033F2b4eFca"), 7005512), - // - POLYGON => (address!("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9"), 15832998), - // Not available on Sepolia, Base, Avalanche, BNB and Lens - // - // - } -); -crate::bindings!( - BalancerV2StablePoolFactoryV2, - // - crate::deployments! { - // - MAINNET => (address!("0x8df6efec5547e31b0eb7d1291b511ff8a2bf987c"), 14934936), - // - GNOSIS => (address!("0xf23b4DB826DbA14c0e857029dfF076b1c0264843"), 25415344), - ARBITRUM_ONE => (address!("0xEF44D6786b2b4d544b7850Fe67CE6381626Bf2D6"), 14244664), - // - OPTIMISM => (address!("0xeb151668006CD04DAdD098AFd0a82e78F77076c3"), 11088891), - // - POLYGON => (address!("0xcA96C4f198d343E251b1a01F3EBA061ef3DA73C1"), 29371951), - // Not available on Sepolia, Base, Avalanche, BNB and Lens - // - // - } -); -crate::bindings!( - BalancerV2LiquidityBootstrappingPoolFactory, - // - crate::deployments! { - // - MAINNET => (address!("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE"), 12871780), - ARBITRUM_ONE => (address!("0x142B9666a0a3A30477b052962ddA81547E7029ab"), 222870), - // - POLYGON => (address!("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE"), 17116402), - // Not available on Sepolia, Base, Avalanche, BNB, Optimism and Lens - // - // - } -); -crate::bindings!( - BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory, - // - crate::deployments! { - // - MAINNET => (address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), 13730248), - // - // - GNOSIS => (address!("0x85a80afee867aDf27B50BdB7b76DA70f1E853062"), 25415236), - // - // - SEPOLIA => (address!("0x45fFd460cC6642B8D8Fb12373DFd77Ceb0f4932B"), 25415236), - ARBITRUM_ONE => (address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), 4859669), - // - BASE => (address!("0x0c6052254551EAe3ECac77B01DFcf1025418828f"), 1206531), - // - AVALANCHE => (address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), 26386552), - // - BNB => (address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), 22691243), - // - OPTIMISM => (address!("0xf302f9F50958c5593770FDf4d4812309fF77414f"), 7005915), - // - POLYGON => (address!("0x41B953164995c11C81DA73D212ED8Af25741b7Ac"), 22067480), - // Not available on Lens - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactory, - crate::deployments! { - // - MAINNET => (address!("0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F"), 15485885), - ARBITRUM_ONE => (address!("0xaEb406b0E430BF5Ea2Dc0B9Fe62E4E53f74B3a33"), 23227044), - // - BNB => (address!("0xf302f9F50958c5593770FDf4d4812309fF77414f"), 22691193), - // - OPTIMISM => (address!("0xf145caFB67081895EE80eB7c04A30Cf87f07b745"), 22182522), - // - POLYGON => (address!("0x136FD06Fa01eCF624C7F2B3CB15742c1339dC2c4"), 32774224), - // Not available on Sepolia, Gnosis Chain, Base, Avalanche and Lens - // - // - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV3, - crate::deployments! { - // - MAINNET => (address!("0xdba127fBc23fb20F5929C546af220A991b5C6e01"), 16580899), - // - GNOSIS => (address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), 26365805), - ARBITRUM_ONE => (address!("0x1c99324EDC771c82A0DCCB780CC7DDA0045E50e7"), 58948370), - // - BNB => (address!("0xacAaC3e6D6Df918Bf3c809DFC7d42de0e4a72d4C"), 25475700), - // - OPTIMISM => (address!("0xe2E901AB09f37884BA31622dF3Ca7FC19AA443Be"), 72832821), - // - POLYGON => (address!("0x7bc6C0E73EDAa66eF3F6E2f27b0EE8661834c6C9"), 39037615), - // Not available on Sepolia (only version ≥ 4) and on Base (only version ≥ 5) - // - // - // Not available on Lens - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV4, - crate::deployments! { - // - MAINNET => (address!("0xfADa0f4547AB2de89D1304A668C39B3E09Aa7c76"), 16878679), - // - GNOSIS => (address!("0xD87F44Df0159DC78029AB9CA7D7e57E7249F5ACD"), 27056416), - // - // - SEPOLIA => (address!("0xA3fd20E29358c056B727657E83DFd139abBC9924"), 3425277), - ARBITRUM_ONE => (address!("0x2498A2B0d6462d2260EAC50aE1C3e03F4829BA95"), 72235860), - // - AVALANCHE => (address!("0x3B1eb8EB7b43882b385aB30533D9A2BeF9052a98"), 29221425), - // - BNB => (address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), 26666380), - // - OPTIMISM => (address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), 82748180), - // - POLYGON => (address!("0x6Ab5549bBd766A43aFb687776ad8466F8b42f777"), 40613553), - // Not available on Base and Lens - // - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV5, - crate::deployments! { - // - MAINNET => (address!("0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A"), 17672478), - // - GNOSIS => (address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), 28900564), - // - // - SEPOLIA => (address!("0xa523f47A933D5020b23629dDf689695AA94612Dc"), 3872211), - ARBITRUM_ONE => (address!("0xA8920455934Da4D853faac1f94Fe7bEf72943eF1"), 110212282), - // - BASE => (address!("0x8df317a729fcaA260306d7de28888932cb579b88"), 1204710), - // - AVALANCHE => (address!("0xE42FFA682A26EF8F25891db4882932711D42e467"), 32478827), - // - BNB => (address!("0x4fb47126Fa83A8734991E41B942Ac29A3266C968"), 29877945), - // - OPTIMISM => (address!("0x043A2daD730d585C44FB79D2614F295D2d625412"), 106752707), - // - POLYGON => (address!("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b"), 44961548), - // Not available on Lens - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV6, - crate::deployments! { - // - MAINNET => (address!("0x5B42eC6D40f7B7965BE5308c70e2603c0281C1E9"), 19314764), - // - GNOSIS => (address!("0x47B489bf5836f83ABD928C316F8e39bC0587B020"), 32650879), - // - SEPOLIA => (address!("0x05503B3aDE04aCA81c8D6F88eCB73Ba156982D2B"), 5369821), - // - ARBITRUM_ONE => (address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), 184805448), - // - BASE => (address!("0x956CCab09898C0AF2aCa5e6C229c3aD4E93d9288"), 11099703), - // - AVALANCHE => (address!("0xb9F8AB3ED3F3aCBa64Bc6cd2DcA74B7F38fD7B88"), 42186350), - // - BNB => (address!("0x6B5dA774890Db7B7b96C6f44e6a4b0F657399E2e"), 36485719), - // - OPTIMISM => (address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), 116694338), - // - POLYGON => (address!("0xEAedc32a51c510d35ebC11088fD5fF2b47aACF2E"), 53996258), - // Not available on Lens - } -); -crate::bindings!( - // Balancer addresses can be obtained from: - // - BalancerV2Vault, - crate::deployments! { - // - MAINNET => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 12272146), - // - GNOSIS => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 24821598), - // - SEPOLIA => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 3418831), - // - ARBITRUM_ONE => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 222832), - // - BASE => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 1196036), - // - AVALANCHE => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 26386141), - // - BNB => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 22691002), - // - OPTIMISM => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 7003431), - // - POLYGON => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 15832990), - // Not available on Lens - } -); -crate::bindings!( - BalancerV3BatchRouter, - crate::deployments! { - // - MAINNET => (address!("0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1"), 21339510), - // - GNOSIS => (address!("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b"), 37377506), - // - SEPOLIA => (address!("0xC85b652685567C1B074e8c0D4389f83a2E458b1C"), 7219301), - // - ARBITRUM_ONE => (address!("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E"), 297828544), - // - BASE => (address!("0x85a80afee867aDf27B50BdB7b76DA70f1E853062"), 25347205), - // - AVALANCHE => (address!("0xc9b36096f5201ea332Db35d6D195774ea0D5988f"), 59965747), - // - OPTIMISM => (address!("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E"), 133969588), - // Not available on Lens, Polygon, BNB - } -); - -// UniV2 -crate::bindings!( - BaoswapRouter, - crate::deployments! { - // https://gnosisscan.io/tx/0xdcbfa037f2c6c7456022df0632ec8d6a75d0f9a195238eec679d5d26895eb7b1 - GNOSIS => (address!("0x6093AeBAC87d62b1A5a4cEec91204e35020E38bE")) - } -); -crate::bindings!( - HoneyswapRouter, - crate::deployments! { - GNOSIS => (address!("0x1C232F01118CB8B424793ae03F870aa7D0ac7f77")) - } -); -crate::bindings!( - PancakeRouter, - crate::deployments! { - // - MAINNET => (address!("0xEfF92A263d31888d860bD50809A8D171709b7b1c")), - // - ARBITRUM_ONE => (address!("0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb")), - // - BASE => (address!("0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb")), - // - BNB => (address!("0x10ED43C718714eb63d5aA57B78B54704E256024E")) - } -); -crate::bindings!( - SushiSwapRouter, - // - crate::deployments! { - // - MAINNET => (address!("0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f")), - // - GNOSIS => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - ARBITRUM_ONE => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - BASE => (address!("0x6bded42c6da8fbf0d2ba55b2fa120c5e0c8d7891")), - // - AVALANCHE => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - BNB => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - OPTIMISM => (address!("0x2abf469074dc0b54d793850807e6eb5faf2625b1")), - // - POLYGON => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // Not available on Lens - } -); -crate::bindings!( - SwaprRouter, - // - crate::deployments! { - // - MAINNET => address!("0xb9960d9bca016e9748be75dd52f02188b9d0829f"), - // - GNOSIS => address!("0xE43e60736b1cb4a75ad25240E2f9a62Bff65c0C0"), - // - ARBITRUM_ONE => address!("0x530476d5583724A89c8841eB6Da76E7Af4C0F17E"), - // Not available on Base and Lens - } -); -crate::bindings!(ISwaprPair); -crate::bindings!( - TestnetUniswapV2Router02, - crate::deployments! { - // - SEPOLIA => address!("0x86dcd3293C53Cf8EFd7303B57beb2a3F671dDE98"), - } -); -crate::bindings!( - UniswapV2Factory, - // - crate::deployments! { - // - MAINNET => address!("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), - // - GNOSIS => address!("0xA818b4F111Ccac7AA31D0BCc0806d64F2E0737D7"), - // - ARBITRUM_ONE => address!("0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9"), - // - BASE => address!("0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"), - // - SEPOLIA => address!("0xF62c03E08ada871A0bEb309762E260a7a6a880E6"), - // - AVALANCHE => address!("0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C"), - // - BNB => address!("0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"), - // - OPTIMISM => address!("0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf"), - // - POLYGON => address!("0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C"), - // Not available on Lens - } -); -crate::bindings!( - UniswapV2Router02, - // - crate::deployments! { - // - MAINNET => address!("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"), - // - GNOSIS => address!("0x1C232F01118CB8B424793ae03F870aa7D0ac7f77"), - // - ARBITRUM_ONE => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - BASE => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - SEPOLIA => address!("0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3"), - // - AVALANCHE => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - BNB => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - OPTIMISM => address!("0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2"), - // - POLYGON => address!("0xedf6066a2b290C185783862C7F4776A2C8077AD1"), - // Not available on Lens - } -); -crate::bindings!(IUniswapLikeRouter); -crate::bindings!(IUniswapLikePair); -crate::bindings!(UniswapV3Pool); -crate::bindings!( - UniswapV3QuoterV2, - crate::deployments! { - // - MAINNET => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - ARBITRUM_ONE => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - BASE => address!("0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a"), - AVALANCHE => address!("0xbe0F5544EC67e9B3b2D979aaA43f18Fd87E6257F"), - BNB => address!("0x78D78E420Da98ad378D7799bE8f4AF69033EB077"), - OPTIMISM => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - POLYGON => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - LENS => address!("0x1eEA2B790Dc527c5a4cd3d4f3ae8A2DDB65B2af1"), - LINEA => address!("0x42bE4D6527829FeFA1493e1fb9F3676d2425C3C1"), - // Not listed on Gnosis and Sepolia chains - } -); -crate::bindings!( - UniswapV3SwapRouterV2, - crate::deployments! { - // - ARBITRUM_ONE => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - MAINNET => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - POLYGON => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - OPTIMISM => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - BASE => address!("0x2626664c2603336E57B271c5C0b26F421741e481"), - AVALANCHE => address!("0xbb00FF08d01D300023C629E8fFfFcb65A5a578cE"), - BNB => address!("0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2"), - LENS => address!("0x6ddD32cd941041D8b61df213B9f515A7D288Dc13"), - LINEA => address!("0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a"), - // Not available on Gnosis Chain - } -); -crate::bindings!( - IUniswapV3Factory, - crate::deployments! { - // - MAINNET => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - SEPOLIA => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - ARBITRUM_ONE => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - BASE => address!( "0x33128a8fC17869897dcE68Ed026d694621f6FDfD"), - AVALANCHE => address!( "0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD"), - BNB => address!( "0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7"), - OPTIMISM => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - POLYGON => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - // not official - LENS => address!( "0xc3A5b857Ba82a2586A45a8B59ECc3AA50Bc3D0e3"), - LINEA => address!("0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9"), - // Not available on Gnosis Chain - } -); - -crate::bindings!( - HooksTrampoline, - // - crate::deployments! { - MAINNET => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - // Gnosis is using the old instance of the hook trampoline since it's hardcoded in gnosis pay rebalance integration. - GNOSIS => address!("0x01DcB88678aedD0C4cC9552B20F4718550250574"), - SEPOLIA => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - ARBITRUM_ONE => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - BASE => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - AVALANCHE => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - BNB => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - OPTIMISM => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - POLYGON => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - LENS => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - // compiled with an older, linea-compatible evm version - LINEA => address!("0xeFcf0d30DB41Ae0b136c5E3B4340dFeE2D099Ada"), - PLASMA => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - } -); - -crate::bindings!( - CoWSwapEthFlow, - crate::deployments! { - // - MAINNET => (address!("0x40a50cf069e992aa4536211b23f286ef88752187"), 16169866), - // - GNOSIS => (address!("0x40a50cf069e992aa4536211b23f286ef88752187"), 25414331), - // - // - SEPOLIA => (address!("0x0b7795E18767259CC253a2dF471db34c72B49516"), 4718739), - // - ARBITRUM_ONE => (address!("0x6DFE75B5ddce1ADE279D4fa6BD6AeF3cBb6f49dB"), 204747458), - // - BASE => (address!("0x3C3eA1829891BC9bEC3d06A81d5d169e52a415e3"), 21490258), - // - AVALANCHE => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 60496408), - // - BNB => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 48411237), - // - OPTIMISM => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 134607215), - // - POLYGON => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 71296258), - // - LENS => (address!("0xFb337f8a725A142f65fb9ff4902d41cc901de222"), 3007173), - // - LINEA => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 24522097), - // - PLASMA => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 3521855), - } -); -crate::bindings!(CoWSwapOnchainOrders); -crate::bindings!(ERC1271SignatureValidator); - -// Used in the gnosis/solvers repo for the balancer solver -crate::bindings!( - BalancerQueries, - crate::deployments! { - // - MAINNET => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 15188261), - // - ARBITRUM_ONE => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 18238624), - // - OPTIMISM => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 15288107), - // - BASE => (address!("0x300Ab2038EAc391f26D9F895dc61F8F66a548833"), 1205869), - // - GNOSIS => (address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), 24821845), - // - POLYGON => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 30988035), - // - AVALANCHE => (address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), 26387068), - // Not available on Lens - } -); - -crate::bindings!( - LiquoriceSettlement, - crate::deployments! { - // - MAINNET => address!("0x0448633eb8B0A42EfED924C42069E0DcF08fb552"), - ARBITRUM_ONE => address!("0x0448633eb8B0A42EfED924C42069E0DcF08fb552"), - } -); - -crate::bindings!( - FlashLoanRouter, - crate::deployments! { - MAINNET => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - GNOSIS => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - SEPOLIA => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - ARBITRUM_ONE => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - BASE => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - POLYGON => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - AVALANCHE => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - } -); - -crate::bindings!(ICowWrapper); - -// Only used in -crate::bindings!( - Permit2, - crate::deployments! { - // - MAINNET => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 15986406), - // - GNOSIS => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 27338672), - // - SEPOLIA => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 2356287), - // - ARBITRUM_ONE => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 38692735), - // - BASE => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 1425180), - // - AVALANCHE => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 28844415), - // - BNB => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 25343783), - // - OPTIMISM => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 38854427), - // - POLYGON => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 35701901), - } -); - -crate::bindings!( - GPv2AllowListAuthentication, - crate::deployments! { - // - MAINNET => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 12593263), - // - GNOSIS => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 16465099), - // - SEPOLIA => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 4717469), - // - ARBITRUM_ONE => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 204702129), - // - BASE => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 21407137), - // - AVALANCHE => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 59891351), - // - BNB => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 48173639), - // - OPTIMISM => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 134254466), - // - POLYGON => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 45854728), - // - LENS => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 2612937), - // - LINEA => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 24333100), - // - PLASMA => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 3439709), - } -); - -crate::bindings!( - GPv2Settlement, - crate::deployments! { - // - MAINNET => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 12593265), - // - GNOSIS => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 16465100), - // - SEPOLIA => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 4717488), - // - ARBITRUM_ONE => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 204704802), - // - BASE => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 21407238), - // - AVALANCHE => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 59891356), - // - BNB => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 48173641), - // - OPTIMISM => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 134254624), - // - POLYGON => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 45859743), - // - LENS => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 2621745), - // - LINEA => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 24333100), - // - PLASMA => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 3439711), - } -); - -crate::bindings!( - WETH9, - crate::deployments! { - // Note: the WETH address must be consistent with the one used by the ETH-flow - // contract - MAINNET => address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), - GNOSIS => address!("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"), - SEPOLIA => address!("0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"), - ARBITRUM_ONE => address!("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), - BASE => address!("0x4200000000000000000000000000000000000006"), - AVALANCHE => address!("0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"), - BNB => address!("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), - OPTIMISM => address!("0x4200000000000000000000000000000000000006"), - POLYGON => address!("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"), - LENS => address!("0x6bDc36E20D267Ff0dd6097799f82e78907105e2F"), - LINEA => address!("0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f"), - PLASMA => address!("0x6100E367285b01F48D07953803A2d8dCA5D19873"), - } -); - -crate::bindings!(ERC20); - -pub mod cow_amm { - crate::bindings!(CowAmm); - crate::bindings!( - CowAmmConstantProductFactory, - crate::deployments! { - // - MAINNET => (address!("0x40664207e3375FB4b733d4743CE9b159331fd034"), 19861952), - // - GNOSIS => (address!("0xdb1cba3a87f2db53b6e1e6af48e28ed877592ec0"), 33874317), - // - SEPOLIA => (address!("0xb808e8183e3a72d196457d127c7fd4befa0d7fd3"), 5874562), - } - ); - crate::bindings!( - CowAmmLegacyHelper, - crate::deployments! { - // - MAINNET => (address!("0x3705ceee5eaa561e3157cf92641ce28c45a3999c"), 20332745), - // - GNOSIS => (address!("0xd9ec06b001957498ab1bc716145515d1d0e30ffb"), 35026999), - } - ); - crate::bindings!(CowAmmUniswapV2PriceOracle); - crate::bindings!(CowAmmFactoryGetter); -} - -pub mod support { - // Support contracts used for trade and token simulations. - crate::bindings!(AnyoneAuthenticator); - crate::bindings!(Solver); - crate::bindings!(Spardose); - crate::bindings!(Trader); - // Support contract used for solver fee simulations in the gnosis/solvers repo. - crate::bindings!(Swapper); - crate::bindings!( - Signatures, - crate::deployments! { - MAINNET => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - ARBITRUM_ONE => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - BASE => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - AVALANCHE => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - BNB => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - OPTIMISM => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - POLYGON => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - LENS => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - GNOSIS => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - SEPOLIA => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - // built with evm=London, because deployment reverts on Linea otherwise - LINEA => address!("0xf6E57e72F7dB3D9A51a8B4c149C00475b94A37e4"), - PLASMA => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - } - ); - // Support contracts used for various order simulations. - crate::bindings!( - Balances, - crate::deployments! { - MAINNET => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - ARBITRUM_ONE => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - BASE => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - AVALANCHE => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - BNB => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - OPTIMISM => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - POLYGON => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - LENS => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - GNOSIS => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - SEPOLIA => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - PLASMA => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - // built with evm=London, because deployment reverts on Linea otherwise - LINEA => address!("0x361350f708f7c0c63c8a505226592c3e5d1faa29"), - } - ); -} - -pub mod test { - // Test Contract for using up a specified amount of gas. - crate::bindings!(GasHog); - // Test Contract for incrementing arbitrary counters. - crate::bindings!(Counter); - // Token with support for `permit` (for pre-interaction tests) - crate::bindings!( - CowProtocolToken, - crate::deployments! { - MAINNET => address!("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), - GNOSIS => address!("0x177127622c4A00F3d409B75571e12cB3c8973d3c"), - SEPOLIA => address!("0x0625aFB445C3B6B7B929342a04A22599fd5dBB59"), - ARBITRUM_ONE => address!("0xcb8b5CD20BdCaea9a010aC1F8d835824F5C87A04"), - BASE => address!("0xc694a91e6b071bF030A18BD3053A7fE09B6DaE69"), - } - ); -} - -pub use alloy::providers::DynProvider as Provider; - -/// Extension trait to attach some useful functions to the contract instance. -pub trait InstanceExt: Sized { - /// Crates a contract instance at the expected address for the current - /// network. - fn deployed( - provider: &Provider, - ) -> impl std::future::Future> + Send; -} - -/// Build a `HashMap)>` from entries like: -/// `CHAIN_ID => address!("0x…")` // block = None -/// `CHAIN_ID => (address!("0x…"), 12_345_678)` // block = Some(…) -#[macro_export] -macro_rules! deployments { - (@acc $m:ident; ) => {}; - - // Tuple form with trailing comma: CHAIN => (addr, block), - (@acc $m:ident; $chain:expr => ( $addr:expr, $block:expr ), $($rest:tt)* ) => { - $m.insert($chain, ($addr, Some($block))); - $crate::deployments!(@acc $m; $($rest)*); - }; - - // Address-only form with trailing comma: CHAIN => addr, - (@acc $m:ident; $chain:expr => $addr:expr, $($rest:tt)* ) => { - $m.insert($chain, ($addr, None::)); - $crate::deployments!(@acc $m; $($rest)*); - }; - - // Tuple form without trailing comma (last entry). - (@acc $m:ident; $chain:expr => ( $addr:expr, $block:expr ) ) => { - $m.insert($chain, ($addr, Some($block))); - }; - - // Address-only form without trailing comma (last entry). - (@acc $m:ident; $chain:expr => $addr:expr ) => { - $m.insert($chain, ($addr, None::)); - }; - - ( $($rest:tt)* ) => {{ - let mut m = ::std::collections::HashMap::new(); - $crate::deployments!(@acc m; $($rest)*); - m - }}; -} - -#[macro_export] -macro_rules! bindings { - ($contract:ident $(, $deployment_info:expr)?) => { - paste::paste! { - // Generate the main bindings in a private module. That allows - // us to re-export all items in our own module while also adding - // some items ourselves. - #[expect(non_snake_case)] - mod [<$contract Private>] { - alloy::sol!( - #[allow(missing_docs, clippy::too_many_arguments)] - #[sol(rpc, all_derives)] - $contract, - concat!("./artifacts/", stringify!($contract), ".json"), - ); - } - - #[expect(non_snake_case)] - pub mod $contract { - use alloy::providers::DynProvider; - - pub use super::[<$contract Private>]::*; - pub type Instance = $contract::[<$contract Instance>]; - - $( - use { - std::sync::LazyLock, - anyhow::Result, - std::collections::HashMap, - alloy::{ - providers::Provider, - primitives::{address, Address}, - }, - anyhow::Context, - $crate::alloy::networks::*, - }; - - static DEPLOYMENT_INFO: LazyLock)>> = LazyLock::new(|| { - $deployment_info - }); - - /// Returns the contract's deployment block (if one exists) for the given chain. - pub fn deployment_block(chain_id: &u64) -> Option { - DEPLOYMENT_INFO.get(chain_id).map(|(_, block)| *block).flatten() - } - - /// Returns the contract's deployment address (if one exists) for the given chain. - pub fn deployment_address(chain_id: &u64) -> Option { - DEPLOYMENT_INFO.get(chain_id).map(|(addr, _)| *addr) - } - - impl $crate::alloy::InstanceExt for Instance { - fn deployed(provider: &DynProvider) -> impl Future> + Send { - async move { - let chain_id = provider - .get_chain_id() - .await - .context("could not fetch current chain id")?; - - let (address, _deployed_block) = *DEPLOYMENT_INFO - .get(&chain_id) - .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; - - Ok(Instance::new( - address, - provider.clone(), - )) - } - } - } - )* - } - } - }; -} - -#[cfg(test)] -mod tests { - use super::networks::*; - use super::*; - - #[test] - fn test_has_address() { - assert!(BaoswapRouter::deployment_address(&GNOSIS).is_some()); - assert!(HoneyswapRouter::deployment_address(&GNOSIS).is_some()); - - for chain_id in &[MAINNET, ARBITRUM_ONE, BASE, BNB] { - assert!(PancakeRouter::deployment_address(chain_id).is_some()); - } - - for chain_id in &[ - MAINNET, - GNOSIS, - ARBITRUM_ONE, - BASE, - AVALANCHE, - BNB, - OPTIMISM, - POLYGON, - ] { - assert!(SushiSwapRouter::deployment_address(chain_id).is_some()); - } - - for chain_id in &[MAINNET, GNOSIS, ARBITRUM_ONE] { - assert!(SwaprRouter::deployment_address(chain_id).is_some()); - } - - assert!(TestnetUniswapV2Router02::deployment_address(&SEPOLIA).is_some()); - - for chain_id in &[ - MAINNET, - GNOSIS, - ARBITRUM_ONE, - BASE, - SEPOLIA, - AVALANCHE, - BNB, - OPTIMISM, - POLYGON, - ] { - assert!(UniswapV2Factory::deployment_address(chain_id).is_some()); - assert!(UniswapV2Router02::deployment_address(chain_id).is_some()); - } - } -} diff --git a/crates/contracts/src/errors.rs b/crates/contracts/src/errors.rs deleted file mode 100644 index 6eb7c907e6..0000000000 --- a/crates/contracts/src/errors.rs +++ /dev/null @@ -1,79 +0,0 @@ -use ethcontract::errors::{ExecutionError, MethodError}; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum EthcontractErrorType { - // The error stems from communicating with the node. - Node, - // Communication was successful but the contract on chain errored. - Contract, -} - -impl EthcontractErrorType { - pub fn classify(err: &impl AsExecutionError) -> Self { - match err.as_execution_error() { - ExecutionError::Web3(_) => Self::Node, - _ => Self::Contract, - } - } - - /// Returns true if the specified error is a contract error. - /// - /// This is short hand for calling `classify` and checking it returns a - /// `Contract` variant. - pub fn is_contract_err(err: &MethodError) -> bool { - matches!(Self::classify(err), Self::Contract) - } -} - -pub trait AsExecutionError { - fn as_execution_error(&self) -> &ExecutionError; -} - -impl AsExecutionError for MethodError { - fn as_execution_error(&self) -> &ExecutionError { - &self.inner - } -} - -impl AsExecutionError for ExecutionError { - fn as_execution_error(&self) -> &ExecutionError { - self - } -} - -// Create an arbitrary error. Useful for testing. -pub fn testing_node_error() -> MethodError { - MethodError { - signature: String::new(), - inner: ExecutionError::Web3(ethcontract::web3::Error::Internal), - } -} - -// Create an arbitrary error. Useful for testing. -pub fn testing_contract_error() -> MethodError { - MethodError { - signature: String::new(), - inner: ExecutionError::InvalidOpcode, - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn node_error() { - assert_eq!( - EthcontractErrorType::classify(&testing_node_error()), - EthcontractErrorType::Node - ); - } - - #[test] - fn contract_error() { - assert_eq!( - EthcontractErrorType::classify(&testing_contract_error()), - EthcontractErrorType::Contract - ); - } -} diff --git a/crates/contracts/src/lib.rs b/crates/contracts/src/lib.rs deleted file mode 100644 index b39baad16f..0000000000 --- a/crates/contracts/src/lib.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![allow(clippy::let_unit_value)] - -pub use ethcontract; -pub mod alloy; -pub mod errors; -use { - anyhow::{Result, anyhow, bail}, - ethcontract::{ - Contract, - common::{DeploymentInformation, contract::Network}, - }, -}; - -pub fn deployment(contract: &Contract, chain_id: u64) -> Result<&Network> { - contract - .networks - .get(&chain_id.to_string()) - // Note that we are conflating network IDs with chain IDs. In general - // they cannot be considered the same, but for the networks that we - // support (xDAI, Görli and Mainnet) they are. - .ok_or_else(|| anyhow!("missing {} deployment for {}", contract.name, chain_id)) -} - -pub fn deployment_block(contract: &Contract, chain_id: u64) -> Result { - let deployment_info = deployment(contract, chain_id)? - .deployment_information - .ok_or_else(|| anyhow!("missing deployment information for {}", contract.name))?; - - match deployment_info { - DeploymentInformation::BlockNumber(block) => Ok(block), - DeploymentInformation::TransactionHash(tx) => { - bail!("missing deployment block number for {}", tx) - } - } -} - -#[macro_use] -mod macros; - -#[cfg(feature = "bin")] -pub mod paths; -pub mod vault; -pub mod web3; - -#[cfg(test)] -mod tests { - use { - super::*, - crate::alloy::networks::{ARBITRUM_ONE, GNOSIS, MAINNET, SEPOLIA}, - }; - - #[test] - fn deployment_addresses() { - for network in &[MAINNET, GNOSIS, SEPOLIA, ARBITRUM_ONE] { - assert!( - alloy::BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory::deployment_address(network).is_some() - ) - } - for network in &[MAINNET, ARBITRUM_ONE] { - assert!( - alloy::BalancerV2WeightedPool2TokensFactory::deployment_address(network).is_some() - ); - assert!( - alloy::BalancerV2LiquidityBootstrappingPoolFactory::deployment_address(network) - .is_some() - ); - } - - assert!(alloy::BalancerV2WeightedPoolFactory::deployment_address(&MAINNET).is_some()); - - for network in &[MAINNET, GNOSIS, ARBITRUM_ONE] { - assert!(alloy::BalancerV2StablePoolFactoryV2::deployment_address(network).is_some()); - } - } - - #[test] - fn deployment_information() { - assert!(alloy::BalancerV2WeightedPoolFactory::deployment_address(&MAINNET).is_some()); - for network in &[MAINNET, ARBITRUM_ONE] { - assert!( - alloy::BalancerV2WeightedPool2TokensFactory::deployment_address(network).is_some() - ); - } - for network in &[MAINNET, GNOSIS, ARBITRUM_ONE] { - assert!(alloy::BalancerV2StablePoolFactoryV2::deployment_address(network).is_some()); - } - } -} diff --git a/crates/contracts/src/macros.rs b/crates/contracts/src/macros.rs deleted file mode 100644 index 1fcf2ec4cf..0000000000 --- a/crates/contracts/src/macros.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[macro_export] -macro_rules! dummy_contract { - ($contract:ty, $addr:expr_2021) => { - <$contract>::at(&$crate::web3::dummy(), $addr.into()) - }; -} diff --git a/crates/contracts/src/paths.rs b/crates/contracts/src/paths.rs deleted file mode 100644 index 5550643df1..0000000000 --- a/crates/contracts/src/paths.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Module for common paths used for generated contract bindings. - -use std::path::{Path, PathBuf}; - -/// Path to the directory containing the vendored contract artifacts. -pub fn contract_artifacts_dir() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")).join("artifacts") -} diff --git a/crates/contracts/src/vault.rs b/crates/contracts/src/vault.rs deleted file mode 100644 index af5c3d8f52..0000000000 --- a/crates/contracts/src/vault.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Module containing utilities for interfacing with the Balancer V2 Vault -//! contract. - -use { - crate::alloy::BalancerV2Authorizer, - alloy::{primitives::Address, sol_types::SolCall}, -}; - -fn role_id(vault: Address) -> alloy::primitives::B256 { - let mut data = [0u8; 36]; - data[12..32].copy_from_slice(vault.as_slice()); - data[32..36].copy_from_slice(&Call::SELECTOR); - alloy::primitives::keccak256(data) -} - -pub async fn grant_required_roles( - authorizer: &BalancerV2Authorizer::Instance, - vault: Address, - vault_relayer: Address, -) -> Result<(), alloy::contract::Error> { - use crate::alloy::BalancerV2Vault::BalancerV2Vault::batchSwapCall; - use crate::alloy::BalancerV2Vault::BalancerV2Vault::manageUserBalanceCall; - - authorizer - .grantRoles( - vec![ - role_id::(vault).0.into(), - role_id::(vault).0.into(), - ], - vault_relayer, - ) - .send() - .await? - .watch() - .await?; - Ok(()) -} - -#[cfg(test)] -mod tests { - use alloy::primitives::b256; - - use super::*; - use crate::alloy::BalancerV2Vault; - use crate::alloy::BalancerV2Vault::BalancerV2Vault::batchSwapCall; - use crate::alloy::BalancerV2Vault::BalancerV2Vault::manageUserBalanceCall; - - #[test] - fn role_ids() { - // These roles were generated by simulating `manageUserBalance` and - // `batchSwap` transactions in Tenderly and then inspecting the `role` - // value that was passed to the authenticator contract. - - let vault = BalancerV2Vault::deployment_address(&1).unwrap(); - assert_eq!( - role_id::(vault), - b256!("0xeba777d811cd36c06d540d7ff2ed18ed042fd67bbf7c9afcf88c818c7ee6b498") - ); - assert_eq!( - role_id::(vault), - b256!("0x1282ab709b2b70070f829c46bc36f76b32ad4989fecb2fcb09a1b3ce00bbfc30") - ); - } -} diff --git a/crates/contracts/src/web3.rs b/crates/contracts/src/web3.rs deleted file mode 100644 index e73ab5ed69..0000000000 --- a/crates/contracts/src/web3.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! This module provides a "dummy" implementation of a [`web3::Transport`]. The -//! reason is that [`ethcontract`] generated bindings require a `web3` instance -//! in order to construct contract instances. This is annoying when trying to -//! use the generated bindings for just encoding contract function calls, where -//! connection to a node is not needed at all. - -use ethcontract::{ - futures, - json::Value, - jsonrpc::Call as RpcCall, - web3::{self, BatchTransport, RequestId, Transport, Web3}, -}; - -/// A dummy [`web3::Transport`] implementation that always panics. -#[derive(Clone, Debug)] -pub struct DummyTransport; - -impl Transport for DummyTransport { - type Out = futures::future::Pending>; - - fn prepare(&self, _method: &str, _params: Vec) -> (web3::RequestId, RpcCall) { - unimplemented!() - } - - fn send(&self, _id: web3::RequestId, _request: RpcCall) -> Self::Out { - unimplemented!() - } -} - -impl BatchTransport for DummyTransport { - type Batch = futures::future::Pending>>>; - - fn send_batch(&self, _requests: T) -> Self::Batch - where - T: IntoIterator, - { - unimplemented!() - } -} - -/// Creates a [`web3::Web3`] instance with a [`DummyTransport`]. -pub fn dummy() -> Web3 { - Web3::new(DummyTransport) -} diff --git a/crates/cow-amm/Cargo.toml b/crates/cow-amm/Cargo.toml index d7eee9464e..77992a730c 100644 --- a/crates/cow-amm/Cargo.toml +++ b/crates/cow-amm/Cargo.toml @@ -4,24 +4,28 @@ version = "0.1.0" edition = "2024" [dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-sol-types = { workspace = true } anyhow = { workspace = true } -alloy = { workspace = true } app-data = { workspace = true } async-trait = { workspace = true } +const-hex = { workspace = true } contracts = { workspace = true } database = { workspace = true } ethrpc = { workspace = true } +event-indexing = { workspace = true } futures = { workspace = true } model = { workspace = true } observe = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } -shared = { workspace = true } +signature-validator = { workspace = true } sqlx = { workspace = true } tokio = { workspace = true, features = [] } tracing = { workspace = true } -const-hex = { workspace = true } -hex-literal = { workspace = true } [lints] workspace = true diff --git a/crates/cow-amm/src/amm.rs b/crates/cow-amm/src/amm.rs index c1a9286a86..4e39f36867 100644 --- a/crates/cow-amm/src/amm.rs +++ b/crates/cow-amm/src/amm.rs @@ -1,20 +1,16 @@ use { - alloy::primitives::{Address, TxHash, U256}, + alloy_primitives::{Address, TxHash, U256}, anyhow::{Context, Result}, app_data::AppDataHash, - contracts::alloy::cow_amm::{ - CowAmmLegacyHelper, - CowAmmLegacyHelper::CowAmmLegacyHelper::orderReturn, - }, + contracts::cow_amm::{CowAmmLegacyHelper, CowAmmLegacyHelper::CowAmmLegacyHelper::orderReturn}, database::byte_array::ByteArray, - ethrpc::alloy::conversions::IntoLegacy, model::{ DomainSeparator, interaction::InteractionData, order::{BuyTokenDestination, OrderData, OrderKind, SellTokenSource}, signature::{Signature, hashed_eip712_message}, }, - shared::signature_validator::{SignatureCheck, SignatureValidating}, + signature_validator::{SignatureCheck, SignatureValidating}, }; #[derive(Clone, Debug)] @@ -28,7 +24,7 @@ impl Amm { pub async fn new( address: Address, helper: &CowAmmLegacyHelper::Instance, - ) -> alloy::contract::Result { + ) -> alloy_contract::Result { let tradeable_tokens = helper.tokens(address).call().await?; Ok(Self { @@ -71,13 +67,13 @@ impl Amm { // To avoid issues caused by that we check the validity of the signature. let hash = hashed_eip712_message(domain_separator, &template.order.hash_struct()); validator - .validate_signature_and_get_additional_gas(SignatureCheck { - signer: self.address.into_legacy(), - hash, - signature: template.signature.to_bytes(), - interactions: template.pre_interactions.clone(), - balance_override: None, - }) + .validate_signature_and_get_additional_gas(SignatureCheck::new( + self.address, + hash.0, + template.signature.to_bytes(), + template.pre_interactions.clone(), + None, + )) .await .context("invalid signature")?; diff --git a/crates/cow-amm/src/cache.rs b/crates/cow-amm/src/cache.rs index 02c1ebe709..87d111be09 100644 --- a/crates/cow-amm/src/cache.rs +++ b/crates/cow-amm/src/cache.rs @@ -1,14 +1,14 @@ use { crate::{Amm, Metrics}, - alloy::{primitives::Address, rpc::types::Log}, + alloy_primitives::Address, + alloy_rpc_types::Log, anyhow::Context, - contracts::alloy::cow_amm::{ + contracts::cow_amm::{ CowAmmLegacyHelper, CowAmmLegacyHelper::CowAmmLegacyHelper::CowAmmLegacyHelperEvents as CowAmmEvent, }, database::byte_array::ByteArray, - ethrpc::block_stream::RangeInclusive, - shared::event_handling::EventStoring, + event_indexing::{block_retriever::RangeInclusive, event_handler::EventStoring}, sqlx::PgPool, std::{collections::HashMap, sync::Arc}, tokio::sync::RwLock, @@ -61,7 +61,7 @@ impl Storage { } let amm_process_tasks = db_amms.into_iter().map(|db_amm| async move { - let amm_address = alloy::primitives::Address::from_slice(&db_amm.address.0); + let amm_address = Address::from_slice(&db_amm.address.0); let amm = Amm::new(amm_address, &self.0.helper).await?; let block_number = u64::try_from(db_amm.block_number).context(format!( "db stored cow amm {:?} block number is not u64", @@ -98,7 +98,7 @@ impl Storage { .collect() } - pub(crate) async fn remove_amms(&self, amm_addresses: &[alloy::primitives::Address]) { + pub(crate) async fn remove_amms(&self, amm_addresses: &[Address]) { let mut lock = self.0.cache.write().await; for (_, amms) in lock.iter_mut() { amms.retain(|amm| !amm_addresses.contains(amm.address())) @@ -169,7 +169,7 @@ impl EventStoring<(CowAmmEvent, Log)> for Storage { let cow_amm = cow_amm.amm; match Amm::new(cow_amm, &self.0.helper).await { Ok(amm) => processed_events.push((block_number, tx_hash, Arc::new(amm))), - Err(err) if matches!(&err, alloy::contract::Error::TransportError(_)) => { + Err(err) if matches!(&err, alloy_contract::Error::TransportError(_)) => { // Abort completely to later try the entire block range again. // That keeps the cache in a consistent state and avoids indexing // the same event multiple times which would result in duplicate amms. diff --git a/crates/cow-amm/src/factory.rs b/crates/cow-amm/src/factory.rs index 54f6d7984b..ee506217b4 100644 --- a/crates/cow-amm/src/factory.rs +++ b/crates/cow-amm/src/factory.rs @@ -1,20 +1,18 @@ use { - alloy::{ - primitives::Address, - providers::DynProvider, - rpc::types::{Filter, FilterSet}, - sol_types::SolEvent, + alloy_primitives::Address, + alloy_provider::DynProvider, + alloy_rpc_types::{Filter, FilterSet}, + alloy_sol_types::SolEvent, + contracts::cow_amm::CowAmmLegacyHelper::CowAmmLegacyHelper::{ + self, + CowAmmLegacyHelperEvents as CowAmmEvent, }, - contracts::alloy::cow_amm::CowAmmLegacyHelper::{ - CowAmmLegacyHelper, - CowAmmLegacyHelper::CowAmmLegacyHelperEvents as CowAmmEvent, - }, - ethrpc::Web3, - shared::event_handling::AlloyEventRetrieving, + ethrpc::AlloyProvider, + event_indexing::event_handler::AlloyEventRetrieving, }; pub(crate) struct Factory { - pub(crate) web3: Web3, + pub(crate) provider: AlloyProvider, pub(crate) address: Address, } @@ -30,6 +28,6 @@ impl AlloyEventRetrieving for Factory { } fn provider(&self) -> &DynProvider { - &self.web3.alloy + &self.provider } } diff --git a/crates/cow-amm/src/lib.rs b/crates/cow-amm/src/lib.rs index f494451017..9aa1cd3c4d 100644 --- a/crates/cow-amm/src/lib.rs +++ b/crates/cow-amm/src/lib.rs @@ -6,7 +6,7 @@ mod registry; pub use { amm::Amm, - contracts::alloy::cow_amm::CowAmmLegacyHelper::Instance as Helper, + contracts::cow_amm::CowAmmLegacyHelper::Instance as Helper, registry::Registry, }; @@ -32,11 +32,9 @@ impl Metrics { /// See: pub mod gpv2_order { use { - alloy::{ - primitives::{B256, FixedBytes, Keccak256}, - sol_types::{SolStruct, SolValue}, - }, - contracts::alloy::cow_amm::CowAmm, + alloy_primitives::{Address, B256, Keccak256}, + alloy_sol_types::{SolStruct, SolValue}, + contracts::cow_amm::CowAmm, model::{DomainSeparator, interaction::InteractionData, signature::hashed_eip712_message}, }; @@ -51,7 +49,7 @@ pub mod gpv2_order { /// Note the use of `string` for kind, sellTokenBalance, and buyTokenBalance /// instead of `bytes32`. const TYPE_HASH: [u8; 32] = - alloy::hex!("d5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489"); + alloy_primitives::hex!("d5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489"); /// Computes the correct EIP-712 hash for a GPv2Order. fn eip712_hash_struct(order: &CowAmm::GPv2Order::Data) -> B256 { @@ -73,7 +71,7 @@ pub mod gpv2_order { pub fn generate_eip1271_signature( order: &CowAmm::GPv2Order::Data, trading_params: &CowAmm::ConstantProduct::TradingParams, - amm_address: alloy::primitives::Address, + amm_address: Address, ) -> Vec { // Encode the order and trading params let signature_data = (order.clone(), trading_params.clone()).abi_encode_sequence(); @@ -98,7 +96,7 @@ pub mod gpv2_order { ) -> InteractionData { let order_hash = eip712_hash_struct(order); let order_hash = hashed_eip712_message(domain_separator, &order_hash); - let calldata = amm.commit(FixedBytes(order_hash)).calldata().clone(); + let calldata = amm.commit(order_hash).calldata().clone(); InteractionData { target: *amm.address(), diff --git a/crates/cow-amm/src/maintainers.rs b/crates/cow-amm/src/maintainers.rs index b5cd5b6a23..12431db15f 100644 --- a/crates/cow-amm/src/maintainers.rs +++ b/crates/cow-amm/src/maintainers.rs @@ -1,21 +1,24 @@ use { crate::{Amm, cache::Storage}, - contracts::alloy::ERC20, - ethrpc::Web3, - futures::future::{join_all, select_ok}, - shared::maintenance::Maintaining, + contracts::ERC20, + ethrpc::AlloyProvider, + event_indexing::maintenance::Maintaining, + futures::{ + future::{join_all, select_ok}, + stream::{FuturesUnordered, StreamExt}, + }, std::sync::Arc, tokio::sync::RwLock, }; pub struct EmptyPoolRemoval { storage: Arc>>, - web3: Web3, + provider: AlloyProvider, } impl EmptyPoolRemoval { - pub fn new(storage: Arc>>, web3: Web3) -> Self { - Self { storage, web3 } + pub fn new(storage: Arc>>, provider: AlloyProvider) -> Self { + Self { storage, provider } } /// Checks if the given AMM has a zero token balance. @@ -25,7 +28,7 @@ impl EmptyPoolRemoval { .traded_tokens() .iter() .map(move |token| async move { - ERC20::Instance::new(*token, self.web3.alloy.clone()) + ERC20::Instance::new(*token, self.provider.clone()) .balanceOf(*amm_address) .call() .await @@ -55,13 +58,20 @@ impl Maintaining for EmptyPoolRemoval { amms_to_check.extend(storage.cow_amms().await); } } - let futures = amms_to_check.iter().map(|amm| async { - self.has_zero_balance(amm.clone()) - .await - .then_some(*amm.address()) - }); - let empty_amms: Vec<_> = join_all(futures).await.into_iter().flatten().collect(); + let empty_amms: Vec<_> = amms_to_check + .iter() + .map(|amm| { + let amm = amm.clone(); + async move { + let address = *amm.address(); + self.has_zero_balance(amm).await.then_some(address) + } + }) + .collect::>() + .filter_map(std::future::ready) + .collect() + .await; if !empty_amms.is_empty() { tracing::debug!(amms = ?empty_amms, "removing AMMs with zero token balance"); let lock = self.storage.read().await; diff --git a/crates/cow-amm/src/registry.rs b/crates/cow-amm/src/registry.rs index 068347eb94..853df2f771 100644 --- a/crates/cow-amm/src/registry.rs +++ b/crates/cow-amm/src/registry.rs @@ -1,11 +1,12 @@ use { crate::{Amm, cache::Storage, factory::Factory, maintainers::EmptyPoolRemoval}, - alloy::primitives::Address, - contracts::alloy::cow_amm::CowAmmLegacyHelper, - ethrpc::{Web3, block_stream::CurrentBlockWatcher}, - shared::{ - event_handling::{AlloyEventRetriever, EventHandler}, - maintenance::{Maintaining, ServiceMaintenance}, + alloy_primitives::Address, + contracts::cow_amm::CowAmmLegacyHelper, + ethrpc::AlloyProvider, + event_indexing::{ + block_retriever::BlockRetriever, + event_handler::EventHandler, + maintenance::Maintaining, }, sqlx::PgPool, std::sync::Arc, @@ -16,20 +17,24 @@ use { /// CoW AMM indexer which stores events in-memory. #[derive(Clone)] pub struct Registry { - web3: Web3, + block_retriever: Arc, storage: Arc>>, maintenance_tasks: Vec>, } impl Registry { - pub fn new(web3: Web3) -> Self { + pub fn new(block_retriever: Arc) -> Self { Self { storage: Default::default(), - web3, + block_retriever, maintenance_tasks: vec![], } } + fn provider(&self) -> &AlloyProvider { + &self.block_retriever.provider + } + /// Registers a new listener to detect CoW AMMs deployed by `factory`. /// Interfacing with the CoW AMM happens via the /// [`contracts::CowAmmLegacyHelper`] deployed at `helper_contract`. @@ -44,7 +49,7 @@ impl Registry { ) { let storage = Storage::new( deployment_block, - CowAmmLegacyHelper::Instance::new(helper_contract, self.web3.alloy.clone()), + CowAmmLegacyHelper::Instance::new(helper_contract, self.provider().clone()), factory, db, ) @@ -53,17 +58,12 @@ impl Registry { self.storage.write().await.push(storage.clone()); let indexer = Factory { - web3: self.web3.clone(), + provider: self.provider().clone(), address: factory, }; - let event_handler = EventHandler::new( - Arc::new(self.web3.alloy.clone()), - AlloyEventRetriever(indexer), - storage, - None, - ); + let event_handler = EventHandler::new(self.block_retriever.clone(), indexer, storage, None); let token_balance_maintainer = - EmptyPoolRemoval::new(self.storage.clone(), self.web3.clone()); + EmptyPoolRemoval::new(self.storage.clone(), self.provider().clone()); self.maintenance_tasks .push(Arc::new(Mutex::new(event_handler))); @@ -72,6 +72,7 @@ impl Registry { } /// Returns all the deployed CoW AMMs + #[instrument(skip_all)] pub async fn amms(&self) -> Vec> { let mut result = vec![]; let lock = self.storage.read().await; @@ -81,11 +82,6 @@ impl Registry { result } - pub fn spawn_maintenance_task(&self, block_stream: CurrentBlockWatcher) { - let maintenance = ServiceMaintenance::new(self.maintenance_tasks.clone()); - tokio::task::spawn(maintenance.run_maintenance_on_new_block(block_stream)); - } - pub fn maintenance_tasks(&self) -> &Vec> { &self.maintenance_tasks } @@ -94,7 +90,7 @@ impl Registry { impl std::fmt::Debug for Registry { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("Registry") - .field("web3", &self.web3) + .field("block_retriever", &self.block_retriever) .field("storage", &self.storage) .finish() } diff --git a/crates/database/Cargo.toml b/crates/database/Cargo.toml index 13ee6bc92f..6c81a9b390 100644 --- a/crates/database/Cargo.toml +++ b/crates/database/Cargo.toml @@ -9,11 +9,11 @@ license = "MIT OR Apache-2.0" bigdecimal = { workspace = true } chrono = { workspace = true, features = ["clock"] } const_format = { workspace = true } -futures = { workspace = true } const-hex = { workspace = true } +futures = { workspace = true } +serde_json = { workspace = true } sqlx = { workspace = true } strum = { workspace = true } -serde_json = { workspace = true } tracing = { workspace = true } [dev-dependencies] diff --git a/crates/database/src/auction.rs b/crates/database/src/auction.rs index 4b0b809f2b..b682e76c15 100644 --- a/crates/database/src/auction.rs +++ b/crates/database/src/auction.rs @@ -18,21 +18,39 @@ LIMIT 1 sqlx::query_as(QUERY).fetch_optional(ex).await } -pub async fn replace_auction( +pub async fn last_used_auction_id(ex: &mut PgConnection) -> Result, sqlx::Error> { + const QUERY: &str = r#" +SELECT id +FROM auctions +ORDER BY id DESC +LIMIT 1 + ;"#; + sqlx::query_scalar(QUERY).fetch_optional(ex).await +} + +pub async fn get_next_auction_id(ex: &mut PgConnection) -> Result { + const QUERY: &str = + r#"SELECT nextval(pg_get_serial_sequence('auctions', 'id'))::bigint as next_id;"#; + + let (id,) = sqlx::query_as(QUERY).fetch_one(ex).await?; + Ok(id) +} + +pub async fn insert_auction_with_id( ex: &mut PgConnection, - data: &JsonValue, -) -> Result { + id: AuctionId, + json: &str, +) -> Result<(), sqlx::Error> { const QUERY: &str = r#" WITH deleted AS ( DELETE FROM auctions ) -INSERT INTO auctions (json) -VALUES ($1) -RETURNING id; +INSERT INTO auctions (id, json) +VALUES ($1, $2::jsonb); "#; - let (id,) = sqlx::query_as(QUERY).bind(data).fetch_one(ex).await?; - Ok(id) + sqlx::query(QUERY).bind(id).bind(json).execute(ex).await?; + Ok(()) } #[derive(Debug, Clone, PartialEq, sqlx::FromRow)] @@ -72,6 +90,14 @@ pub async fn fetch(ex: &mut PgConnection, id: AuctionId) -> Result Result, sqlx::Error> { + const QUERY: &str = r#"SELECT * FROM competition_auctions WHERE id = ANY($1) ORDER BY id"#; + sqlx::query_as(QUERY).bind(ids).fetch_all(ex).await +} + pub async fn get_order_uids( ex: &mut PgConnection, auction_id: AuctionId, @@ -84,6 +110,34 @@ pub async fn get_order_uids( Ok(record.map(|(order_uids,)| order_uids)) } +pub async fn save_auction_orders( + ex: &mut PgConnection, + auction_id: AuctionId, + order_uids: &[OrderUid], +) -> Result<(), sqlx::Error> { + const QUERY: &str = r#" +INSERT INTO auction_orders (auction_id, order_uid) +SELECT $1, unnest($2::bytea[]) +ON CONFLICT DO NOTHING + "#; + sqlx::query(QUERY) + .bind(auction_id) + .bind(order_uids) + .execute(ex) + .await?; + Ok(()) +} + +pub async fn fetch_auction_ids_by_order_uid( + ex: &mut PgConnection, + order_uid: &OrderUid, +) -> Result, sqlx::Error> { + const QUERY: &str = + "SELECT auction_id FROM auction_orders WHERE order_uid = $1 ORDER BY auction_id"; + let rows: Vec<(AuctionId,)> = sqlx::query_as(QUERY).bind(order_uid).fetch_all(ex).await?; + Ok(rows.into_iter().map(|(id,)| id).collect()) +} + #[cfg(test)] mod tests { use {super::*, crate::byte_array::ByteArray, sqlx::Connection}; @@ -96,14 +150,22 @@ mod tests { crate::clear_DANGER_(&mut db).await.unwrap(); let value = JsonValue::Number(1.into()); - let id = replace_auction(&mut db, &value).await.unwrap(); + let id = get_next_auction_id(&mut db).await.unwrap(); + let value_str = serde_json::to_string(&value).unwrap(); + insert_auction_with_id(&mut db, id, &value_str) + .await + .unwrap(); let (id_, value_) = load_most_recent(&mut db).await.unwrap().unwrap(); assert_eq!(id, id_); assert_eq!(value, value_); let value = JsonValue::Number(2.into()); - let id_ = replace_auction(&mut db, &value).await.unwrap(); + let id_ = get_next_auction_id(&mut db).await.unwrap(); assert_eq!(id + 1, id_); + let value_str = serde_json::to_string(&value).unwrap(); + insert_auction_with_id(&mut db, id_, &value_str) + .await + .unwrap(); let (id, value_) = load_most_recent(&mut db).await.unwrap().unwrap(); assert_eq!(value, value_); assert_eq!(id_, id); diff --git a/crates/database/src/auction_prices.rs b/crates/database/src/auction_prices.rs index 1db843d7e8..de8b1f57c6 100644 --- a/crates/database/src/auction_prices.rs +++ b/crates/database/src/auction_prices.rs @@ -142,6 +142,6 @@ mod tests { .await .unwrap() .unwrap(); - assert_eq!(output, 3.into()); + assert_eq!(output, BigDecimal::from(3)); } } diff --git a/crates/database/src/byte_array.rs b/crates/database/src/byte_array.rs index e4886bbe40..a4af65b8e4 100644 --- a/crates/database/src/byte_array.rs +++ b/crates/database/src/byte_array.rs @@ -8,7 +8,7 @@ use { error::BoxDynError, postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef}, }, - std::fmt::{self, Debug, Formatter}, + std::fmt::{self, Debug, Display, Formatter}, }; /// Wrapper type for fixed size byte arrays compatible with sqlx's Postgres @@ -22,6 +22,12 @@ impl Debug for ByteArray { } } +impl Display for ByteArray { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", const_hex::encode_prefixed(self.0)) + } +} + impl Default for ByteArray { fn default() -> Self { Self([0; N]) @@ -62,8 +68,8 @@ impl Decode<'_, Postgres> for ByteArray { } impl Encode<'_, Postgres> for ByteArray { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { - self.0.encode(buf) + fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { + self.0.encode_by_ref(buf) } } diff --git a/crates/database/src/ethflow_orders.rs b/crates/database/src/ethflow_orders.rs index de8cb52a45..2c40d6858d 100644 --- a/crates/database/src/ethflow_orders.rs +++ b/crates/database/src/ethflow_orders.rs @@ -1,6 +1,7 @@ use { crate::{OrderUid, PgTransaction, TransactionHash}, sqlx::{Executor, PgConnection}, + std::time::Duration, tracing::instrument, }; @@ -23,17 +24,33 @@ pub async fn insert_or_overwrite_orders( #[instrument(skip_all)] pub async fn insert_or_overwrite_ethflow_order( - ex: &mut PgConnection, + ex: &mut PgTransaction<'_>, event: &EthOrderPlacement, ) -> Result<(), sqlx::Error> { - const QUERY: &str = "\ + const INSERT_ETHFLOW_ORDER_QUERY: &str = "\ INSERT INTO ethflow_orders (uid, valid_to) VALUES ($1, $2) ON CONFLICT (uid) DO UPDATE SET \ - valid_to = $2;"; - sqlx::query(QUERY) - .bind(event.uid) - .bind(event.valid_to) - .execute(ex) - .await?; + valid_to = $2;"; + ex.execute( + sqlx::query(INSERT_ETHFLOW_ORDER_QUERY) + .bind(event.uid) + .bind(event.valid_to), + ) + .await?; + + // Update true_valid_to field if order already in the database + // as the Ethflow orders get inserted with validity of u32::MAX + // and the true validity is contained in the EthOrderPlacement + const UPDATE_TRUE_VALID_TO_QUERY: &str = r#" + UPDATE orders + SET true_valid_to = $1 + WHERE uid = $2 + "#; + ex.execute( + sqlx::query(UPDATE_TRUE_VALID_TO_QUERY) + .bind(event.valid_to) + .bind(event.uid), + ) + .await?; Ok(()) } @@ -95,7 +112,7 @@ pub async fn insert_refund_tx_hash( refund: &Refund, ) -> Result<(), sqlx::Error> { const QUERY: &str = r#" - INSERT INTO ethflow_refunds (order_uid, block_number, tx_hash) VALUES($1, $2, $3) + INSERT INTO ethflow_refunds (order_uid, block_number, tx_hash) VALUES($1, $2, $3) ON CONFLICT (order_uid) DO UPDATE SET block_number = $2, tx_hash = $3 "#; @@ -115,6 +132,7 @@ pub async fn refundable_orders( since_valid_to: i64, min_validity_duration: i64, min_price_deviation: f64, + max_lookback_time: Option, ) -> Result, sqlx::Error> { // condition (1.0 - o.buy_amount / GREATEST(oq.buy_amount,1)) >= $3 is added to // skip refunding orders that have unrealistic slippage set. Those orders are @@ -125,24 +143,32 @@ pub async fn refundable_orders( // GREATEST(oq.buy_amount,1) added to avoid division by zero since // table order_quotes contains entries with buy_amount = 0 (see // https://github.com/cowprotocol/services/pull/1767#issuecomment-1680825756) - const QUERY: &str = r#" -SELECT eo.uid, eo.valid_to from orders o -INNER JOIN ethflow_orders eo on eo.uid = o.uid -INNER JOIN order_quotes oq on o.uid = oq.order_uid -LEFT JOIN trades t on o.uid = t.order_uid -LEFT JOIN onchain_order_invalidations o_inv on o.uid = o_inv.uid -LEFT JOIN ethflow_refunds o_ref on o.uid = o_ref.order_uid -WHERE -o_ref.tx_hash is null -AND o_inv.uid is null -AND o.partially_fillable = false -AND t.order_uid is null -AND eo.valid_to < $1 -AND o.sell_amount = oq.sell_amount -AND (1.0 - o.buy_amount / GREATEST(oq.buy_amount,1)) >= $3 -AND eo.valid_to - extract(epoch from o.creation_timestamp)::int > $2 - "#; - sqlx::query_as(QUERY) + + let creation_filter = max_lookback_time + .map(|window| { + let created_after = (chrono::Utc::now() - window).format("%Y-%m-%d %H:%M:%S"); + format!("AND o.creation_timestamp >= '{created_after}'") + }) + .unwrap_or_default(); + + let query = format!( + r#" +SELECT eo.uid, eo.valid_to +FROM ethflow_orders eo +JOIN orders o ON o.uid = eo.uid + AND o.partially_fillable = false + {creation_filter} +JOIN order_quotes oq ON oq.order_uid = eo.uid + AND o.sell_amount = oq.sell_amount + AND (1.0 - o.buy_amount / GREATEST(oq.buy_amount,1)) >= $3 +WHERE eo.valid_to < $1 + AND eo.valid_to - extract(epoch FROM o.creation_timestamp)::int > $2 + AND NOT EXISTS (SELECT 1 FROM trades t WHERE t.order_uid = eo.uid) + AND NOT EXISTS (SELECT 1 FROM ethflow_refunds o_ref WHERE o_ref.order_uid = eo.uid) + AND NOT EXISTS (SELECT 1 FROM onchain_order_invalidations o_inv WHERE o_inv.uid = eo.uid) + "# + ); + sqlx::query_as(&query) .bind(since_valid_to) .bind(min_validity_duration) .bind(min_price_deviation) @@ -310,9 +336,12 @@ mod tests { } async fn insert_order_parts_in_db(db: &mut PgConnection, order_parts: &EthflowOrderParts) { insert_order(db, &order_parts.order).await.unwrap(); - insert_or_overwrite_ethflow_order(db, &order_parts.eth_order) + let mut ex = db.begin().await.unwrap(); + insert_or_overwrite_ethflow_order(&mut ex, &order_parts.eth_order) .await .unwrap(); + ex.commit().await.unwrap(); + insert_quote(db, &order_parts.quote).await.unwrap(); if let Some(refund) = &order_parts.refund { let mut ex = db.begin().await.unwrap(); @@ -324,16 +353,16 @@ mod tests { let order_parts = create_standard_ethflow_order_parts(order_uid_1); insert_order_parts_in_db(&mut db, &order_parts).await; // all criteria are fulfilled - let orders = refundable_orders(&mut db, 5, 1, 0.01).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.01, None).await.unwrap(); assert_eq!(orders, vec![order_parts.eth_order.clone()]); // slippage is not fulfilled - let orders = refundable_orders(&mut db, 5, 1, 0.53).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.53, None).await.unwrap(); assert_eq!(orders, Vec::new()); // min_validity is not fulfilled - let orders = refundable_orders(&mut db, 1, 1, 0.01).await.unwrap(); + let orders = refundable_orders(&mut db, 1, 1, 0.01, None).await.unwrap(); assert_eq!(orders, Vec::new()); // min_duration is not fulfilled - let orders = refundable_orders(&mut db, 5, 3, 0.01).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 3, 0.01, None).await.unwrap(); assert_eq!(orders, Vec::new()); // order already settled let trade = Trade { @@ -343,7 +372,7 @@ mod tests { insert_trade(&mut db, &EventIndex::default(), &trade) .await .unwrap(); - let orders = refundable_orders(&mut db, 5, 1, 0.01).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.01, None).await.unwrap(); assert_eq!(orders, Vec::new()); let order_uid_2 = ByteArray([2u8; 56]); let mut order_parts = create_standard_ethflow_order_parts(order_uid_2); @@ -353,7 +382,7 @@ mod tests { }); insert_order_parts_in_db(&mut db, &order_parts).await; // order was refunded - let orders = refundable_orders(&mut db, 5, 1, 0.01).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.01, None).await.unwrap(); assert_eq!(orders, Vec::new()); let order_uid_3 = ByteArray([3u8; 56]); @@ -361,7 +390,7 @@ mod tests { order_parts.order.sell_amount = BigDecimal::from(99u32); insert_order_parts_in_db(&mut db, &order_parts).await; // sell_amount is not fulfilled - let orders = refundable_orders(&mut db, 5, 1, 0.01).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.01, None).await.unwrap(); assert_eq!(orders, Vec::new()); let order_uid_4 = ByteArray([4u8; 56]); @@ -369,14 +398,14 @@ mod tests { order_parts.order.partially_fillable = true; insert_order_parts_in_db(&mut db, &order_parts).await; // no refundable orders as order is partially fillable - let orders = refundable_orders(&mut db, 5, 1, 0.001).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.001, None).await.unwrap(); assert_eq!(orders, Vec::new()); let order_uid_5 = ByteArray([5u8; 56]); let order_parts = create_standard_ethflow_order_parts(order_uid_5); insert_order_parts_in_db(&mut db, &order_parts).await; // the newly created order should be found - let orders = refundable_orders(&mut db, 5, 1, 0.001).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.001, None).await.unwrap(); assert_eq!(orders, vec![order_parts.eth_order]); insert_onchain_invalidation( &mut db, @@ -388,7 +417,7 @@ mod tests { ) .await .unwrap(); - let orders = refundable_orders(&mut db, 5, 1, 0.001).await.unwrap(); + let orders = refundable_orders(&mut db, 5, 1, 0.001, None).await.unwrap(); // but after invaldiation event, it should not longer be found assert_eq!(orders, Vec::new()); } @@ -458,9 +487,93 @@ mod tests { } let now = std::time::Instant::now(); - refundable_orders(&mut db, 1, 1, 1.0).await.unwrap(); + refundable_orders(&mut db, 1, 1, 1.0, None).await.unwrap(); let elapsed = now.elapsed(); println!("{elapsed:?}"); assert!(elapsed < std::time::Duration::from_secs(1)); } + + #[tokio::test] + #[ignore] + async fn postgres_refundable_orders_creation_filter() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut db = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut db).await.unwrap(); + + let now = Utc::now(); + let lookback_time = Duration::from_mins(10); + + let new_order_uid = ByteArray([1; 56]); + let order_new = Order { + uid: new_order_uid, + buy_amount: BigDecimal::from(1), + sell_amount: BigDecimal::from(100u32), + creation_timestamp: now, + ..Default::default() + }; + insert_order(&mut db, &order_new).await.unwrap(); + + let quote = Quote { + order_uid: new_order_uid, + buy_amount: BigDecimal::from(2), + sell_amount: BigDecimal::from(100u32), + ..Default::default() + }; + insert_quote(&mut db, "e).await.unwrap(); + + let order_new = EthOrderPlacement { + valid_to: order_new.creation_timestamp.timestamp() + 600, + uid: new_order_uid, + }; + insert_or_overwrite_orders(&mut db, &[order_new]) + .await + .unwrap(); + + let old_order_uid = ByteArray([2; 56]); + let order_old = Order { + uid: old_order_uid, + buy_amount: BigDecimal::from(1), + sell_amount: BigDecimal::from(100u32), + creation_timestamp: now - lookback_time - Duration::from_secs(1), + ..Default::default() + }; + insert_order(&mut db, &order_old).await.unwrap(); + + let quote = Quote { + order_uid: old_order_uid, + buy_amount: BigDecimal::from(2), + sell_amount: BigDecimal::from(100u32), + ..Default::default() + }; + insert_quote(&mut db, "e).await.unwrap(); + + let order_old = EthOrderPlacement { + valid_to: order_old.creation_timestamp.timestamp() + 600, + uid: old_order_uid, + }; + insert_or_overwrite_orders(&mut db, &[order_old]) + .await + .unwrap(); + + let all_orders = refundable_orders(&mut db, i64::MAX, 1, 0., None) + .await + .unwrap(); + assert_eq!(all_orders.len(), 2); + assert!( + all_orders + .iter() + .all(|order| [new_order_uid, old_order_uid].contains(&order.uid)) + ); + + let within_lookback_period = + refundable_orders(&mut db, i64::MAX, 1, 0., Some(lookback_time)) + .await + .unwrap(); + assert_eq!(within_lookback_period.len(), 1); + assert!( + within_lookback_period + .iter() + .all(|order| [new_order_uid].contains(&order.uid)) + ); + } } diff --git a/crates/database/src/fee_policies.rs b/crates/database/src/fee_policies.rs index 2dbfb378a2..4fe72c7eee 100644 --- a/crates/database/src/fee_policies.rs +++ b/crates/database/src/fee_policies.rs @@ -94,6 +94,15 @@ pub async fn fetch_all( Ok(result) } +pub async fn fetch_by_order_uid( + ex: &mut PgConnection, + order_uid: &OrderUid, +) -> Result, sqlx::Error> { + const QUERY: &str = + "SELECT * FROM fee_policies WHERE order_uid = $1 ORDER BY auction_id, application_order"; + sqlx::query_as(QUERY).bind(order_uid).fetch_all(ex).await +} + #[cfg(test)] mod tests { use {super::*, crate::byte_array::ByteArray, sqlx::Connection}; diff --git a/crates/database/src/jit_orders.rs b/crates/database/src/jit_orders.rs index 69a48a8a76..b9d1fde168 100644 --- a/crates/database/src/jit_orders.rs +++ b/crates/database/src/jit_orders.rs @@ -54,6 +54,16 @@ SELECT, sqlx::query_as(QUERY).bind(uid).fetch_optional(ex).await } +#[instrument(skip_all)] +pub async fn get_many_by_uid<'a>( + ex: &'a mut PgConnection, + order_uids: &'a [OrderUid], +) -> Result, sqlx::Error> { + const QUERY: &str = + const_format::concatcp!("SELECT ", SELECT, " FROM ", FROM, " WHERE o.uid = ANY($1)"); + sqlx::query_as(QUERY).bind(order_uids).fetch_all(ex).await +} + #[instrument(skip_all)] pub async fn get_by_tx( ex: &mut PgConnection, @@ -70,7 +80,7 @@ pub async fn get_by_tx( t.block_number = (SELECT block_number FROM settlement) AND -- BETWEEN is inclusive t.log_index BETWEEN (SELECT * from previous_settlement) AND (SELECT log_index FROM \ - settlement) + settlement) AND NOT EXISTS ( SELECT 1 FROM orders ord WHERE ord.uid = o.uid) @@ -131,7 +141,7 @@ pub async fn insert(ex: &mut PgConnection, jit_orders: &[JitOrder]) -> Result<() signing_scheme, sell_token_balance, buy_token_balance - ) + ) "#, ); diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs index 6cdfb9c9a0..16257f6849 100644 --- a/crates/database/src/lib.rs +++ b/crates/database/src/lib.rs @@ -62,6 +62,7 @@ pub const TABLES: &[&str] = &[ "last_indexed_blocks", "onchain_order_invalidations", "onchain_placed_orders", + "pool_indexer_checkpoints", "presignature_events", "proposed_jit_orders", "quotes", @@ -71,10 +72,13 @@ pub const TABLES: &[&str] = &[ "solver_competitions", "surplus_capturing_jit_order_owners", "trades", + "uniswap_v3_pool_states", + "uniswap_v3_pools", ]; /// The names of potentially big volume tables we use in the db. pub const LARGE_TABLES: &[&str] = &[ + "auction_orders", "auction_prices", "competition_auctions", "fee_policies", @@ -84,6 +88,7 @@ pub const LARGE_TABLES: &[&str] = &[ "order_quotes", "proposed_solutions", "proposed_trade_executions", + "uniswap_v3_ticks", ]; pub fn all_tables() -> impl Iterator { @@ -91,11 +96,15 @@ pub fn all_tables() -> impl Iterator { } /// Delete all data in the database. Only used by tests. +/// +/// Truncates all tables in a single statement so Postgres accepts foreign-key +/// cycles between listed tables (e.g. `uniswap_v3_pool_states` → +/// `uniswap_v3_pools`). Individual per-table `TRUNCATE`s error out when any +/// other listed table references the one being truncated. #[expect(non_snake_case)] pub async fn clear_DANGER_(ex: &mut PgTransaction<'_>) -> sqlx::Result<()> { - for table in all_tables() { - ex.execute(format!("TRUNCATE {table};").as_str()).await?; - } + let tables = all_tables().collect::>().join(", "); + ex.execute(format!("TRUNCATE {tables};").as_str()).await?; Ok(()) } diff --git a/crates/database/src/onchain_invalidations.rs b/crates/database/src/onchain_invalidations.rs index 548d24d648..dd0b3a34bf 100644 --- a/crates/database/src/onchain_invalidations.rs +++ b/crates/database/src/onchain_invalidations.rs @@ -32,6 +32,7 @@ pub async fn insert_onchain_invalidations( // this is more involved, and now() should be good enough. timestamp: Utc::now(), order_uid: *event, + reason: None, }, ) .await?; diff --git a/crates/database/src/order_events.rs b/crates/database/src/order_events.rs index e4656ebb1c..930c18ebb0 100644 --- a/crates/database/src/order_events.rs +++ b/crates/database/src/order_events.rs @@ -5,6 +5,7 @@ use { crate::{OrderUid, byte_array::ByteArray}, chrono::Utc, sqlx::{PgConnection, PgPool, types::chrono::DateTime}, + std::fmt::Display, tracing::instrument, }; @@ -33,9 +34,43 @@ pub enum OrderEventLabel { Cancelled, } +/// Why an order was filtered or marked invalid. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, sqlx::Type)] +#[sqlx(type_name = "OrderFilterReason")] +#[sqlx(rename_all = "snake_case")] +pub enum OrderFilterReason { + InFlight, + BannedUser, + InvalidSignature, + UnsupportedToken, + InsufficientBalance, + DustOrder, + MissingNativePrice, +} + +impl OrderFilterReason { + pub fn as_str(self) -> &'static str { + match self { + Self::InFlight => "in_flight", + Self::BannedUser => "banned_user", + Self::InvalidSignature => "invalid_signature", + Self::UnsupportedToken => "unsupported_token", + Self::InsufficientBalance => "insufficient_balance", + Self::DustOrder => "dust_order", + Self::MissingNativePrice => "missing_native_price", + } + } +} + +impl Display for OrderFilterReason { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + /// Contains a single event of the life cycle of an order and when it was /// registered. -#[derive(Clone, Copy, Debug, Eq, PartialEq, sqlx::Type, sqlx::FromRow)] +#[derive(Clone, Debug, Eq, PartialEq, sqlx::Type, sqlx::FromRow)] pub struct OrderEvent { /// Which order this event belongs to pub order_uid: OrderUid, @@ -44,37 +79,61 @@ pub struct OrderEvent { pub timestamp: DateTime, /// What kind of event happened pub label: OrderEventLabel, + /// Why the order was filtered/invalidated (only set for Filtered/Invalid + /// labels) + pub reason: Option, } /// Inserts a row into the `order_events` table only if the latest event for the -/// corresponding order UID has a different label than the provided event.. +/// corresponding order UID has a different label than the provided event. pub async fn insert_order_event( ex: &mut PgConnection, event: &OrderEvent, +) -> Result<(), sqlx::Error> { + insert_order_events( + ex, + &[event.order_uid], + event.timestamp, + event.label, + event.reason, + ) + .await +} + +pub async fn insert_order_events( + ex: &mut PgConnection, + orders: &[OrderUid], + timestamp: DateTime, + label: OrderEventLabel, + reason: Option, ) -> Result<(), sqlx::Error> { const QUERY: &str = r#" - WITH cte AS ( - SELECT label - FROM order_events - WHERE order_uid = $1 - ORDER BY timestamp DESC - LIMIT 1 - ) - INSERT INTO order_events (order_uid, timestamp, label) - SELECT $1, $2, $3 - WHERE NOT EXISTS ( - SELECT 1 - FROM cte - WHERE label = $3 - ) + WITH latest_events AS ( + SELECT DISTINCT ON (order_uid) order_uid, label, reason + FROM order_events + WHERE order_uid = ANY($1) + ORDER BY order_uid, timestamp DESC + ), + incoming AS ( + SELECT t.order_uid, $2 AS timestamp, $3 AS label, $4 AS reason + FROM unnest($1) AS t(order_uid) + ) + INSERT INTO order_events (order_uid, timestamp, label, reason) + SELECT DISTINCT i.order_uid, i.timestamp, i.label, i.reason + FROM incoming i + LEFT JOIN latest_events le ON le.order_uid = i.order_uid + WHERE le.label IS DISTINCT FROM i.label + OR le.reason IS DISTINCT FROM i.reason "#; + sqlx::query(QUERY) - .bind(event.order_uid) - .bind(event.timestamp) - .bind(event.label) + .bind(orders) + .bind(timestamp) + .bind(label) + .bind(reason) .execute(ex) - .await - .map(|_| ()) + .await?; + Ok(()) } /// Deletes rows before the provided timestamp from the `order_events` table. @@ -107,6 +166,18 @@ pub async fn get_latest( .await } +#[instrument(skip_all)] +pub async fn get_all( + ex: &mut PgConnection, + order: &OrderUid, +) -> Result, sqlx::Error> { + const QUERY: &str = r#"SELECT * FROM order_events WHERE order_uid = $1 ORDER BY timestamp ASC"#; + sqlx::query_as(QUERY) + .bind(ByteArray(order.0)) + .fetch_all(ex) + .await +} + #[cfg(test)] mod tests { use { @@ -115,6 +186,7 @@ mod tests { byte_array::ByteArray, order_events::{OrderEvent, OrderEventLabel}, }, + chrono::TimeZone, sqlx::Connection, }; @@ -132,24 +204,28 @@ mod tests { order_uid: uid_a, timestamp: now - chrono::Duration::milliseconds(300), label: OrderEventLabel::Created, + reason: None, }; insert_order_event(&mut ex, &event_a).await.unwrap(); let event_b = OrderEvent { order_uid: uid_a, timestamp: now - chrono::Duration::milliseconds(200), label: OrderEventLabel::Invalid, + reason: None, }; insert_order_event(&mut ex, &event_b).await.unwrap(); let event_c = OrderEvent { order_uid: uid_b, timestamp: now - chrono::Duration::milliseconds(100), label: OrderEventLabel::Invalid, + reason: None, }; insert_order_event(&mut ex, &event_c).await.unwrap(); let event_d = OrderEvent { order_uid: uid_a, timestamp: now, label: OrderEventLabel::Invalid, + reason: None, }; insert_order_event(&mut ex, &event_d).await.unwrap(); @@ -186,4 +262,87 @@ mod tests { .await .unwrap() } + + #[tokio::test] + #[ignore] + async fn postgres_multi_insert() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut ex = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut ex).await.unwrap(); + + let early = Utc.with_ymd_and_hms(2026, 2, 19, 0, 0, 0).unwrap(); + let uid_a = ByteArray([1; 56]); + let uid_b = ByteArray([2; 56]); + let event_a = OrderEvent { + order_uid: uid_a, + timestamp: early, + label: OrderEventLabel::Created, + reason: None, + }; + insert_order_event(&mut ex, &event_a).await.unwrap(); + let event_b = OrderEvent { + order_uid: uid_b, + timestamp: early, + label: OrderEventLabel::Invalid, + reason: None, + }; + insert_order_event(&mut ex, &event_b).await.unwrap(); + + let later = Utc.with_ymd_and_hms(2027, 2, 19, 0, 0, 0).unwrap(); + insert_order_events( + &mut ex, + &[uid_a, uid_b], + later, + OrderEventLabel::Invalid, + None, + ) + .await + .unwrap(); + + let a = get_latest(&mut ex, &uid_a).await.unwrap(); + assert_eq!( + a, + Some(OrderEvent { + order_uid: uid_a, + // new latest event was added + timestamp: later, + label: OrderEventLabel::Invalid, + reason: None, + }) + ); + + let b = get_latest(&mut ex, &uid_b).await.unwrap(); + assert_eq!( + b, + Some(OrderEvent { + order_uid: uid_b, + // since the latest event was already `Invalid` + // no new entry was created + timestamp: early, + label: OrderEventLabel::Invalid, + reason: None, + }) + ); + } + + #[tokio::test] + #[ignore] + async fn postgres_avoid_duplicate_uids() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut ex = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut ex).await.unwrap(); + let uid = ByteArray([1; 56]); + insert_order_events( + &mut ex, + &[uid, uid], + Utc::now(), + OrderEventLabel::Invalid, + None, + ) + .await + .unwrap(); + let events = all_order_events(&mut ex).await; + // query didn't insert 2 identical events for the same uid + assert_eq!(events.len(), 1); + } } diff --git a/crates/database/src/order_execution.rs b/crates/database/src/order_execution.rs index e9d38bd8cb..3e0de10c96 100644 --- a/crates/database/src/order_execution.rs +++ b/crates/database/src/order_execution.rs @@ -8,6 +8,18 @@ use { type Execution = (AuctionId, OrderUid); +#[derive(Clone, Debug, PartialEq, sqlx::FromRow)] +pub struct OrderExecution { + pub order_uid: OrderUid, + pub auction_id: AuctionId, + pub reward: f64, + pub executed_fee: BigDecimal, + pub executed_fee_token: Address, + pub block_number: i64, + pub protocol_fee_tokens: Vec
, + pub protocol_fee_amounts: Vec, +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct Asset { pub amount: BigDecimal, @@ -48,6 +60,21 @@ DO UPDATE SET reward = $3, executed_fee = $4, executed_fee_token = $5, block_num Ok(()) } +#[instrument(skip_all)] +pub async fn read_by_order_uid( + ex: &mut PgConnection, + order_uid: &OrderUid, +) -> Result, sqlx::Error> { + const QUERY: &str = r#" +SELECT order_uid, auction_id, reward, executed_fee, executed_fee_token, + block_number, protocol_fee_tokens, protocol_fee_amounts +FROM order_execution +WHERE order_uid = $1 +ORDER BY auction_id + "#; + sqlx::query_as(QUERY).bind(order_uid).fetch_all(ex).await +} + /// Fetch protocol fees for all keys in the filter #[instrument(skip_all)] pub async fn executed_protocol_fees( diff --git a/crates/database/src/order_history.rs b/crates/database/src/order_history.rs index f556124bdf..24ad9d0ebe 100644 --- a/crates/database/src/order_history.rs +++ b/crates/database/src/order_history.rs @@ -22,25 +22,69 @@ pub fn user_orders<'a>( // see that these queries are taking too long in practice. #[rustfmt::skip] const QUERY: &str = const_format::concatcp!( -"(SELECT ", orders::SELECT, -" FROM ", orders::FROM, -" LEFT OUTER JOIN onchain_placed_orders onchain_o on onchain_o.uid = o.uid", -" WHERE o.owner = $1", -" ORDER BY creation_timestamp DESC LIMIT $2 + $3 ) ", -" UNION ", -" (SELECT ", orders::SELECT, -" FROM ", orders::FROM, -" LEFT OUTER JOIN onchain_placed_orders onchain_o on onchain_o.uid = o.uid", -" WHERE onchain_o.sender = $1 ", -" ORDER BY creation_timestamp DESC LIMIT $2 + $3 ) ", -" UNION ", -" (SELECT ", jit_orders::SELECT, -" FROM ", jit_orders::FROM, -" WHERE o.owner = $1 AND NOT EXISTS (SELECT 1 FROM orders ord WHERE o.uid = ord.uid)", -" ORDER BY creation_timestamp DESC LIMIT $2 + $3 ) ", -" ORDER BY creation_timestamp DESC ", -" LIMIT $2 ", -" OFFSET $3 ", + // Phase 1: find the page of UIDs using cheap index scans. + // Because we `UNION` the sub-query results before determining the + // window requested by the user we need to fetch LIMIT + OFFSET results + // in each sub-query. + "WITH page_uids AS (", + " SELECT uid, min(creation_timestamp) as creation_timestamp FROM (", + // regular orders with that owner (relies on the + // `user_order_creation_timestamp` index) + " (", + " SELECT o.uid, o.creation_timestamp", + " FROM orders o", + " WHERE o.owner = $1", + " ORDER BY creation_timestamp DESC", + " LIMIT $2 + $3", + " )", + " UNION ALL", + // onchain placed orders from that sender - gets a dedicated + // subquery to avoid having to needlessly LEFT JOIN potentially + // thousands of onchain_placed_orders on orders because those + // are relatively rare + // + // relies on the `order_sender` index + " (", + " SELECT o.uid, o.creation_timestamp", + " FROM onchain_placed_orders opo", + " JOIN orders o ON opo.uid = o.uid", + " WHERE opo.sender = $1 AND o.owner != $1", + " ORDER BY creation_timestamp DESC", + " LIMIT $2 + $3", + " )", + " UNION ALL", + // JIT orders with that owner (relies on the + // `jit_order_creation_timestamp` index) + " (", + " SELECT jit_o.uid, jit_o.creation_timestamp", + " FROM jit_orders jit_o", + " WHERE jit_o.owner = $1", + " ORDER BY creation_timestamp DESC", + " LIMIT $2 + $3", + " )", + " ) combined", + " GROUP BY uid", + " ORDER BY creation_timestamp DESC", + " LIMIT $2 OFFSET $3", + ") ", + // Phase 2: fetch full rows for the relevant UIDs only + " (", + " SELECT ", orders::SELECT, + " FROM ", orders::FROM, + " WHERE o.uid IN (SELECT uid FROM page_uids)", + " )", + " UNION ALL", + " (", + " SELECT ", jit_orders::SELECT, + " FROM ", jit_orders::FROM, + " WHERE o.uid IN (SELECT uid FROM page_uids)", + // despite already handling duplicates in phase 1 we need to handle + // them here again. Because JIT orders are very rare we check that + // the order does not exist in the regular orders table instead of the + // other way around. + " AND NOT EXISTS (SELECT 1 FROM orders ord WHERE o.uid = ord.uid)", + " )", + " ORDER BY creation_timestamp DESC", ); sqlx::query_as(QUERY) .bind(owner) @@ -58,7 +102,7 @@ mod tests { events::EventIndex, onchain_broadcasted_orders::{OnchainOrderPlacement, insert_onchain_order}, }, - chrono::{DateTime, Utc}, + chrono::{DateTime, Duration, Utc}, futures::StreamExt, sqlx::Connection, }; @@ -176,4 +220,144 @@ mod tests { ); assert!(elapsed / number_of_query_executions < std::time::Duration::from_secs(1)); } + + #[tokio::test] + #[ignore] + async fn postgres_user_orders_correctness() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut db = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut db).await.unwrap(); + + let owner = ByteArray([1u8; 20]); + let other_owner = ByteArray([2u8; 20]); + let now = Utc::now(); + let t = |secs: i64| now - Duration::seconds(secs); + + // Ordered newest→oldest: uid_a, uid_b, uid_c, uid_d, uid_e + let uid_a = ByteArray([0xaau8; 56]); // orders only + let uid_b = ByteArray([0xbbu8; 56]); // both orders AND jit_orders — must appear once + let uid_c = ByteArray([0xccu8; 56]); // jit_orders only + let uid_d = ByteArray([0xddu8; 56]); // orders only + let uid_e = ByteArray([0xeeu8; 56]); // orders, owned by other_owner, sender = owner + let uid_x = ByteArray([0xffu8; 56]); // other_owner — must never appear + + orders::insert_order( + &mut db, + &orders::Order { + uid: uid_a, + owner, + creation_timestamp: t(1), + ..Default::default() + }, + ) + .await + .unwrap(); + + orders::insert_order( + &mut db, + &orders::Order { + uid: uid_b, + owner, + creation_timestamp: t(2), + ..Default::default() + }, + ) + .await + .unwrap(); + // jit_orders primary key is (block_number, log_index) — use distinct values. + jit_orders::insert( + &mut db, + &[ + jit_orders::JitOrder { + uid: uid_b, + owner, + creation_timestamp: t(2), + block_number: 1, + ..Default::default() + }, + jit_orders::JitOrder { + uid: uid_c, + owner, + creation_timestamp: t(3), + block_number: 2, + ..Default::default() + }, + ], + ) + .await + .unwrap(); + + orders::insert_order( + &mut db, + &orders::Order { + uid: uid_d, + owner, + creation_timestamp: t(4), + ..Default::default() + }, + ) + .await + .unwrap(); + + orders::insert_order( + &mut db, + &orders::Order { + uid: uid_e, + owner: other_owner, + creation_timestamp: t(5), + ..Default::default() + }, + ) + .await + .unwrap(); + insert_onchain_order( + &mut db, + &EventIndex::default(), + &OnchainOrderPlacement { + order_uid: uid_e, + sender: owner, + placement_error: None, + }, + ) + .await + .unwrap(); + + orders::insert_order( + &mut db, + &orders::Order { + uid: uid_x, + owner: other_owner, + creation_timestamp: t(0), + ..Default::default() + }, + ) + .await + .unwrap(); + + let uids_of = |v: Vec| v.into_iter().map(|(uid, _, _)| uid).collect::>(); + + // All results in order. + let all = uids_of(user_orders(&mut db, &owner, 0, Some(100)).await); + assert_eq!(all, vec![uid_a.0, uid_b.0, uid_c.0, uid_d.0, uid_e.0]); + + // uid_b is in both tables but must appear exactly once. + assert_eq!(all.iter().filter(|&&u| u == uid_b.0).count(), 1); + + // First page: both rows come from orders. + let page1 = uids_of(user_orders(&mut db, &owner, 0, Some(2)).await); + assert_eq!(page1, vec![uid_a.0, uid_b.0]); + + // Second page: crosses the table boundary — uid_c from jit_orders, uid_d from + // orders. + let page2 = uids_of(user_orders(&mut db, &owner, 2, Some(2)).await); + assert_eq!(page2, vec![uid_c.0, uid_d.0]); + + // Last page: onchain-sender order. + let page3 = uids_of(user_orders(&mut db, &owner, 4, Some(10)).await); + assert_eq!(page3, vec![uid_e.0]); + + // Unrelated address returns nothing. + let none = user_orders(&mut db, &ByteArray([0xabu8; 20]), 0, Some(100)).await; + assert!(none.is_empty()); + } } diff --git a/crates/database/src/orders.rs b/crates/database/src/orders.rs index 8e9658236a..23d12ae1db 100644 --- a/crates/database/src/orders.rs +++ b/crates/database/src/orders.rs @@ -116,6 +116,7 @@ pub async fn insert_orders_and_ignore_conflicts( label: OrderEventLabel::Created, timestamp: order.creation_timestamp, order_uid: order.uid, + reason: None, }, ) .await?; @@ -145,9 +146,21 @@ INSERT INTO orders ( sell_token_balance, buy_token_balance, cancellation_timestamp, - class + class, + true_valid_to +) +VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, + -- Ethflow orders are inserted with valid_to set to u32::MAX. Their true validity is stored in + -- the ethflow_orders table. + -- If there already exists an Ethflow order with the same uid, take smaller of the two valid_to values + CASE + WHEN $21 = 4294967295 THEN -- u32::MAX + COALESCE((SELECT valid_to FROM ethflow_orders WHERE uid = $1), $21) + ELSE + $21 + END ) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20) "#; #[instrument(skip_all)] @@ -189,6 +202,8 @@ async fn insert_order_execute_sqlx( .bind(order.buy_token_balance) .bind(order.cancellation_timestamp) .bind(order.class) + // true_valid_to takes the same value as valid_to when inserting an order + .bind(order.valid_to) .execute(ex) .await .map(|result| result.rows_affected() > 0) @@ -630,6 +645,21 @@ COALESCE((SELECT executed_fee_token FROM order_execution oe WHERE oe.order_uid = "#; pub const FROM: &str = "orders o"; +const FULL_ORDER_WITH_QUOTE: &str = const_format::concatcp!( + "SELECT ", + SELECT, + ", o_quotes.sell_amount as quote_sell_amount", + ", o_quotes.buy_amount as quote_buy_amount", + ", o_quotes.gas_amount as quote_gas_amount", + ", o_quotes.gas_price as quote_gas_price", + ", o_quotes.sell_token_price as quote_sell_token_price", + ", o_quotes.verified as quote_verified", + ", o_quotes.metadata as quote_metadata", + ", o_quotes.solver as solver", + " FROM ", + FROM, + " LEFT JOIN order_quotes o_quotes ON o.uid = o_quotes.order_uid", +); #[instrument(skip_all)] pub async fn single_full_order_with_quote( @@ -638,22 +668,21 @@ pub async fn single_full_order_with_quote( ) -> Result, sqlx::Error> { #[rustfmt::skip] const QUERY: &str = const_format::concatcp!( - "SELECT ", SELECT, - ", o_quotes.sell_amount as quote_sell_amount", - ", o_quotes.buy_amount as quote_buy_amount", - ", o_quotes.gas_amount as quote_gas_amount", - ", o_quotes.gas_price as quote_gas_price", - ", o_quotes.sell_token_price as quote_sell_token_price", - ", o_quotes.verified as quote_verified", - ", o_quotes.metadata as quote_metadata", - ", o_quotes.solver as solver", - " FROM ", FROM, - " LEFT JOIN order_quotes o_quotes ON o.uid = o_quotes.order_uid", - " WHERE o.uid = $1", - ); + FULL_ORDER_WITH_QUOTE, + " WHERE o.uid = $1" + ); sqlx::query_as(QUERY).bind(uid).fetch_optional(ex).await } +#[instrument(skip_all)] +pub async fn many_full_orders_with_quotes<'a>( + ex: &'a mut PgConnection, + order_ids: &'a [OrderUid], +) -> Result, sqlx::Error> { + const QUERY: &str = const_format::concatcp!(FULL_ORDER_WITH_QUOTE, " WHERE o.uid = ANY($1)"); + sqlx::query_as(QUERY).bind(order_ids).fetch_all(ex).await +} + // Partial query for getting the log indices of events of a single settlement. // // This will fail if we ever have multiple settlements in the same transaction @@ -718,26 +747,24 @@ pub fn solvable_orders( /// - pending pre-signature /// - ethflow specific invalidation conditions const OPEN_ORDERS: &str = r#" - WITH live_orders AS ( + WITH live_orders AS MATERIALIZED ( SELECT o.* FROM orders o - LEFT JOIN ethflow_orders e ON e.uid = o.uid WHERE o.cancellation_timestamp IS NULL - AND o.valid_to >= $1 - AND (e.valid_to IS NULL OR e.valid_to >= $1) - AND NOT EXISTS (SELECT 1 FROM invalidations i WHERE i.order_uid = o.uid) - AND NOT EXISTS (SELECT 1 FROM onchain_order_invalidations oi WHERE oi.uid = o.uid) - AND NOT EXISTS (SELECT 1 FROM onchain_placed_orders op WHERE op.uid = o.uid - AND op.placement_error IS NOT NULL) + AND o.true_valid_to >= $1 + AND NOT EXISTS (SELECT 1 FROM invalidations i WHERE i.order_uid = o.uid) + AND NOT EXISTS (SELECT 1 FROM onchain_order_invalidations oi WHERE oi.uid = o.uid) + AND NOT EXISTS (SELECT 1 FROM onchain_placed_orders op WHERE op.uid = o.uid AND op.placement_error IS NOT NULL) + AND NOT EXISTS (SELECT 1 FROM ethflow_refunds r WHERE r.order_uid = o.uid) ), trades_agg AS ( - SELECT t.order_uid, - SUM(t.buy_amount) AS sum_buy, - SUM(t.sell_amount) AS sum_sell, - SUM(t.fee_amount) AS sum_fee - FROM trades t - JOIN live_orders lo ON lo.uid = t.order_uid - GROUP BY t.order_uid + SELECT t.order_uid, + SUM(t.buy_amount) AS sum_buy, + SUM(t.sell_amount) AS sum_sell, + SUM(t.fee_amount) AS sum_fee + FROM trades t + JOIN live_orders lo ON lo.uid = t.order_uid + GROUP BY t.order_uid ) SELECT lo.uid, @@ -759,6 +786,7 @@ pub fn solvable_orders( lo.sell_token_balance, lo.buy_token_balance, lo.class, + lo.true_valid_to, COALESCE(ta.sum_buy, 0) AS sum_buy, COALESCE(ta.sum_sell, 0) AS sum_sell, @@ -825,15 +853,104 @@ pub fn open_orders_by_time_or_uids<'a>( uids: &'a [OrderUid], after_timestamp: DateTime, ) -> BoxStream<'a, Result> { + // Optimized version using the OPEN_ORDERS pattern with CTEs and LATERAL joins #[rustfmt::skip] - const OPEN_ORDERS_AFTER: &str = const_format::concatcp!( - "SELECT ", SELECT, - " FROM ", FROM, - " LEFT OUTER JOIN ethflow_orders eth_o on eth_o.uid = o.uid ", - " WHERE (o.creation_timestamp > $1 OR o.cancellation_timestamp > $1 OR o.uid = ANY($2))", - ); + const QUERY: &str = r#" +WITH selected_orders AS ( + SELECT o.* + FROM orders o + WHERE (o.creation_timestamp > $1 OR o.cancellation_timestamp > $1 OR o.uid = ANY($2)) +), +trades_agg AS ( + SELECT t.order_uid, + SUM(t.buy_amount) AS sum_buy, + SUM(t.sell_amount) AS sum_sell, + SUM(t.fee_amount) AS sum_fee + FROM trades t + JOIN selected_orders so ON so.uid = t.order_uid + GROUP BY t.order_uid +) +SELECT + so.uid, + so.owner, + so.creation_timestamp, + so.sell_token, + so.buy_token, + so.sell_amount, + so.buy_amount, + so.valid_to, + so.app_data, + so.fee_amount, + so.kind, + so.partially_fillable, + so.signature, + so.receiver, + so.signing_scheme, + so.settlement_contract, + so.sell_token_balance, + so.buy_token_balance, + so.class, + so.true_valid_to, + + COALESCE(ta.sum_buy, 0) AS sum_buy, + COALESCE(ta.sum_sell, 0) AS sum_sell, + COALESCE(ta.sum_fee, 0) AS sum_fee, + (so.cancellation_timestamp IS NOT NULL OR + EXISTS (SELECT 1 FROM invalidations WHERE order_uid = so.uid) OR + EXISTS (SELECT 1 FROM onchain_order_invalidations WHERE uid = so.uid) + ) AS invalidated, + (so.signing_scheme = 'presign' AND COALESCE(pe.unsigned, TRUE)) AS presignature_pending, + ARRAY( + SELECT (p.target, p.value, p.data) + FROM interactions p + WHERE p.order_uid = so.uid AND p.execution = 'pre' + ORDER BY p.index + ) AS pre_interactions, + ARRAY( + SELECT (p.target, p.value, p.data) + FROM interactions p + WHERE p.order_uid = so.uid AND p.execution = 'post' + ORDER BY p.index + ) AS post_interactions, + ed.ethflow_data, + opo.onchain_user, + opo.onchain_placement_error, + COALESCE(fee_agg.executed_fee,0) AS executed_fee, + COALESCE(fee_agg.executed_fee_token, so.sell_token) AS executed_fee_token, + ad.full_app_data +FROM selected_orders so +LEFT JOIN LATERAL ( + SELECT NOT signed AS unsigned + FROM presignature_events + WHERE order_uid = so.uid + ORDER BY block_number DESC, log_index DESC + LIMIT 1 + ) pe ON TRUE +LEFT JOIN LATERAL ( + SELECT sender AS onchain_user, + placement_error AS onchain_placement_error + FROM onchain_placed_orders + WHERE uid = so.uid + ORDER BY block_number DESC + LIMIT 1 + ) opo ON TRUE +LEFT JOIN LATERAL ( + SELECT ROW(tx_hash, eo.valid_to) AS ethflow_data + FROM ethflow_orders eo + LEFT JOIN ethflow_refunds r ON r.order_uid = eo.uid + WHERE eo.uid = so.uid + ) ed ON TRUE +LEFT JOIN LATERAL ( + SELECT SUM(executed_fee) AS executed_fee, + (ARRAY_AGG(executed_fee_token))[1] AS executed_fee_token + FROM order_execution + WHERE order_uid = so.uid +) fee_agg ON TRUE +LEFT JOIN app_data ad ON ad.contract_app_data = so.app_data +LEFT JOIN trades_agg ta ON ta.order_uid = so.uid +"#; - sqlx::query_as(OPEN_ORDERS_AFTER) + sqlx::query_as(QUERY) .bind(after_timestamp) .bind(uids) .fetch(ex) @@ -866,41 +983,40 @@ pub async fn user_orders_with_quote( min_valid_to: i64, owner: &Address, ) -> Result, sqlx::Error> { - // Same functionality as OPEN_ORDERS but not optimized to fetch all live orders - // at once. Performs better when used with filtering by user. - #[rustfmt::skip] - const OPEN_ORDERS_EMBEDDABLE: &str = const_format::concatcp!( - "SELECT * FROM ( ", - "SELECT ", SELECT, - " FROM ", FROM, - " LEFT OUTER JOIN ethflow_orders eth_o on eth_o.uid = o.uid ", - " WHERE o.valid_to >= $1", - " AND CASE WHEN eth_o.valid_to IS NULL THEN true ELSE eth_o.valid_to >= $1 END", - r#") AS unfiltered - WHERE - CASE kind - WHEN 'sell' THEN sum_sell < sell_amount - WHEN 'buy' THEN sum_buy < buy_amount - END AND - (NOT invalidated) AND - (onchain_placement_error IS NULL) - "#); - - #[rustfmt::skip] - const QUERY: &str = const_format::concatcp!( - "SELECT o_quotes.sell_amount as quote_sell_amount, o.sell_amount as order_sell_amount,", - " o_quotes.buy_amount as quote_buy_amount, o.buy_amount as order_buy_amount,", - " o.kind as order_kind, o_quotes.gas_amount as quote_gas_amount,", - " o_quotes.gas_price as quote_gas_price, o_quotes.sell_token_price as quote_sell_token_price", - " FROM (", - " SELECT *", - " FROM (", OPEN_ORDERS_EMBEDDABLE, - " AND owner = $2", - " AND class = 'limit'", - " ) AS subquery", - " ) AS o", - " INNER JOIN order_quotes o_quotes ON o.uid = o_quotes.order_uid" + // Optimized version following the same pattern as OPEN_ORDERS + const QUERY: &str = r#" + WITH live_orders AS ( + SELECT o.* + FROM orders o + WHERE o.cancellation_timestamp IS NULL + AND o.true_valid_to >= $1 + AND NOT EXISTS (SELECT 1 FROM ethflow_refunds r WHERE r.order_uid = o.uid) + AND NOT EXISTS (SELECT 1 FROM invalidations i WHERE i.order_uid = o.uid) + AND NOT EXISTS (SELECT 1 FROM onchain_order_invalidations oi WHERE oi.uid = o.uid) + AND NOT EXISTS (SELECT 1 FROM onchain_placed_orders op WHERE op.uid = o.uid AND op.placement_error IS NOT NULL) + AND NOT EXISTS (SELECT 1 FROM ethflow_refunds r WHERE r.order_uid = o.uid) + AND o.owner = $2 + AND o.class = 'limit' + ) + SELECT + o_quotes.sell_amount AS quote_sell_amount, + lo.sell_amount AS order_sell_amount, + o_quotes.buy_amount AS quote_buy_amount, + lo.buy_amount AS order_buy_amount, + lo.kind AS order_kind, + o_quotes.gas_amount AS quote_gas_amount, + o_quotes.gas_price AS quote_gas_price, + o_quotes.sell_token_price AS quote_sell_token_price + FROM live_orders lo + INNER JOIN order_quotes o_quotes ON lo.uid = o_quotes.order_uid + WHERE ( + lo.kind = 'sell' + AND COALESCE((SELECT SUM(sell_amount) FROM trades WHERE order_uid = lo.uid), 0) < lo.sell_amount + ) OR ( + lo.kind = 'buy' + AND COALESCE((SELECT SUM(buy_amount) FROM trades WHERE order_uid = lo.uid), 0) < lo.buy_amount ); + "#; sqlx::query_as::<_, OrderWithQuote>(QUERY) .bind(min_valid_to) .bind(owner) diff --git a/crates/database/src/settlement_executions.rs b/crates/database/src/settlement_executions.rs index a709688539..78e6b465db 100644 --- a/crates/database/src/settlement_executions.rs +++ b/crates/database/src/settlement_executions.rs @@ -5,6 +5,19 @@ use { tracing::instrument, }; +#[derive(Clone, Debug, Eq, PartialEq, sqlx::FromRow)] +pub struct SettlementExecution { + pub auction_id: AuctionId, + pub solver: Address, + pub solution_uid: i64, + pub start_timestamp: DateTime, + pub end_timestamp: Option>, + pub start_block: i64, + pub end_block: Option, + pub deadline_block: i64, + pub outcome: Option, +} + #[instrument(skip_all)] pub async fn insert( ex: &mut PgConnection, @@ -62,6 +75,21 @@ WHERE auction_id = $1 AND solver = $2 AND solution_uid = $3 Ok(()) } +#[instrument(skip_all)] +pub async fn read_by_auction_ids( + ex: &mut PgConnection, + auction_ids: &[AuctionId], +) -> Result, sqlx::Error> { + const QUERY: &str = r#" +SELECT auction_id, solver, solution_uid, start_timestamp, end_timestamp, + start_block, end_block, deadline_block, outcome +FROM settlement_executions +WHERE auction_id = ANY($1) +ORDER BY auction_id, start_timestamp + "#; + sqlx::query_as(QUERY).bind(auction_ids).fetch_all(ex).await +} + #[cfg(test)] mod tests { use { @@ -122,7 +150,7 @@ mod tests { let output = fetch(&mut db, auction_id).await.unwrap(); assert_eq!(output.len(), 3); - let expected_a = ExecutionRow { + let expected_a = SettlementExecution { auction_id, solver: solver_a, solution_uid: 1, @@ -133,7 +161,7 @@ mod tests { deadline_block, outcome: None, }; - let expected_b = ExecutionRow { + let expected_b = SettlementExecution { auction_id, solver: solver_a, solution_uid: 2, @@ -144,7 +172,7 @@ mod tests { deadline_block, outcome: None, }; - let expected_c = ExecutionRow { + let expected_c = SettlementExecution { auction_id, solver: solver_b, solution_uid: 1, @@ -202,7 +230,7 @@ mod tests { let output = fetch(&mut db, auction_id).await.unwrap(); assert_eq!(output.len(), 3); - let expected_a = ExecutionRow { + let expected_a = SettlementExecution { auction_id, solver: solver_a, solution_uid: 1, @@ -213,7 +241,7 @@ mod tests { deadline_block, outcome: Some(success_outcome.clone()), }; - let expected_b = ExecutionRow { + let expected_b = SettlementExecution { auction_id, solver: solver_a, solution_uid: 2, @@ -224,7 +252,7 @@ mod tests { deadline_block, outcome: Some(failure_outcome), }; - let expected_c = ExecutionRow { + let expected_c = SettlementExecution { auction_id, solver: solver_b, solution_uid: 1, @@ -240,23 +268,10 @@ mod tests { assert!(output.contains(&expected_c)); } - #[derive(Debug, Clone, Eq, PartialEq, sqlx::FromRow)] - struct ExecutionRow { - pub auction_id: AuctionId, - pub solver: Address, - pub solution_uid: i64, - pub start_timestamp: DateTime, - pub end_timestamp: Option>, - pub start_block: i64, - pub end_block: Option, - pub deadline_block: i64, - pub outcome: Option, - } - async fn fetch( ex: &mut PgConnection, auction_id: AuctionId, - ) -> Result, sqlx::Error> { + ) -> Result, sqlx::Error> { const QUERY: &str = r#"SELECT * FROM settlement_executions WHERE auction_id = $1;"#; sqlx::query_as(QUERY).bind(auction_id).fetch_all(ex).await diff --git a/crates/database/src/settlements.rs b/crates/database/src/settlements.rs index a0215d279a..c47b378e81 100644 --- a/crates/database/src/settlements.rs +++ b/crates/database/src/settlements.rs @@ -9,16 +9,18 @@ pub async fn find_settlement_transaction( ex: &mut PgConnection, auction_id: i64, solver: Address, + solution_uid: i64, ) -> Result, sqlx::Error> { const QUERY: &str = r#" SELECT tx_hash FROM settlements WHERE - auction_id = $1 AND solver = $2 + auction_id = $1 AND solver = $2 AND solution_uid = $3 "#; sqlx::query_as(QUERY) .bind(auction_id) .bind(solver) + .bind(solution_uid) .fetch_optional(ex) .await } @@ -31,17 +33,16 @@ pub struct SettlementEvent { } #[instrument(skip_all)] -pub async fn get_settlement_without_auction( +pub async fn get_settlements_without_auction( ex: &mut PgConnection, -) -> Result, sqlx::Error> { +) -> Result, sqlx::Error> { const QUERY: &str = r#" SELECT block_number, log_index, tx_hash FROM settlements WHERE auction_id IS NULL ORDER BY block_number ASC -LIMIT 1 "#; - sqlx::query_as(QUERY).fetch_optional(ex).await + sqlx::query_as(QUERY).fetch_all(ex).await } #[instrument(skip_all)] @@ -195,10 +196,8 @@ mod tests { .await .unwrap(); - let settlement = get_settlement_without_auction(&mut db) - .await - .unwrap() - .unwrap(); + let settlements = get_settlements_without_auction(&mut db).await.unwrap(); + let settlement = &settlements[0]; assert_eq!(settlement.block_number, event.block_number); assert_eq!(settlement.log_index, event.log_index); @@ -207,8 +206,8 @@ mod tests { .await .unwrap(); - let settlement = get_settlement_without_auction(&mut db).await.unwrap(); + let settlement = get_settlements_without_auction(&mut db).await.unwrap(); - assert!(settlement.is_none()); + assert!(settlement.is_empty()); } } diff --git a/crates/database/src/solver_competition.rs b/crates/database/src/solver_competition.rs index 5f73c7b7e2..a51b94b458 100644 --- a/crates/database/src/solver_competition.rs +++ b/crates/database/src/solver_competition.rs @@ -50,51 +50,61 @@ pub async fn auction_start_block( pub async fn load_by_id( ex: &mut PgConnection, id: AuctionId, + after_block: Option, ) -> Result, sqlx::Error> { const QUERY: &str = r#" SELECT sc.json, sc.id, COALESCE(ARRAY_AGG(s.tx_hash) FILTER (WHERE s.solution_uid IS NOT NULL), '{}') AS tx_hashes FROM solver_competitions sc -- outer joins because the data might not have been indexed yet LEFT OUTER JOIN settlements s ON sc.id = s.auction_id --- exclude settlements from another environment for which observation is guaranteed to not exist -WHERE sc.id = $1 +LEFT JOIN competition_auctions ca ON sc.id = ca.id +WHERE sc.id = $1 AND ($2::bigint IS NULL OR ca.deadline <= $2) GROUP BY sc.id ;"#; - sqlx::query_as(QUERY).bind(id).fetch_optional(ex).await + sqlx::query_as(QUERY) + .bind(id) + .bind(after_block) + .fetch_optional(ex) + .await } #[instrument(skip_all)] pub async fn load_latest_competitions( ex: &mut PgConnection, latest_competitions_count: u32, + after_block: Option, ) -> Result, sqlx::Error> { const QUERY: &str = r#" SELECT sc.json, sc.id, COALESCE(ARRAY_AGG(s.tx_hash) FILTER (WHERE s.solution_uid IS NOT NULL), '{}') AS tx_hashes FROM solver_competitions sc -- outer joins because the data might not have been indexed yet LEFT OUTER JOIN settlements s ON sc.id = s.auction_id +LEFT JOIN competition_auctions ca ON sc.id = ca.id +WHERE ($2::bigint IS NULL OR ca.deadline <= $2) GROUP BY sc.id ORDER BY sc.id DESC LIMIT $1 ;"#; sqlx::query_as(QUERY) .bind(i64::from(latest_competitions_count)) + .bind(after_block) .fetch_all(ex) .await } pub async fn load_latest_competition( ex: &mut PgConnection, + after_block: Option, ) -> Result, sqlx::Error> { - let competitions = load_latest_competitions(ex, 1).await?; - let latest = competitions.into_iter().next(); - Ok(latest) + let competitions = load_latest_competitions(ex, 1, after_block).await?; + Ok(competitions.into_iter().next()) } #[instrument(skip_all)] pub async fn load_by_tx_hash( ex: &mut PgConnection, tx_hash: &TransactionHash, + after_block: Option, ) -> Result, sqlx::Error> { const QUERY: &str = r#" WITH competition AS ( @@ -106,10 +116,16 @@ WITH competition AS ( SELECT sc.json, sc.id, COALESCE(ARRAY_AGG(s.tx_hash) FILTER (WHERE s.solution_uid IS NOT NULL), '{}') AS tx_hashes FROM solver_competitions sc JOIN settlements s ON sc.id = s.auction_id +LEFT JOIN competition_auctions ca ON sc.id = ca.id WHERE sc.id = (SELECT id FROM competition) AND s.solution_uid IS NOT NULL + AND ($2::bigint IS NULL OR ca.deadline <= $2) GROUP BY sc.id ;"#; - sqlx::query_as(QUERY).bind(tx_hash).fetch_optional(ex).await + sqlx::query_as(QUERY) + .bind(tx_hash) + .bind(after_block) + .fetch_optional(ex) + .await } #[cfg(test)] @@ -142,24 +158,27 @@ mod tests { assert_eq!(value_, "1234"); // load by id works - let value_ = load_by_id(&mut db, 0).await.unwrap().unwrap(); + let value_ = load_by_id(&mut db, 0, None).await.unwrap().unwrap(); assert_eq!(value, value_.json); assert!(value_.tx_hashes.is_empty()); // load as latest works - let value_ = load_latest_competition(&mut db).await.unwrap().unwrap(); + let value_ = load_latest_competition(&mut db, None) + .await + .unwrap() + .unwrap(); assert_eq!(value, value_.json); assert!(value_.tx_hashes.is_empty()); // load by tx doesn't work, as there is no settlement yet assert!( - load_by_tx_hash(&mut db, &ByteArray([0u8; 32])) + load_by_tx_hash(&mut db, &ByteArray([0u8; 32]), None) .await .unwrap() .is_none() ); // non-existent auction returns none - assert!(load_by_id(&mut db, 1).await.unwrap().is_none()); + assert!(load_by_id(&mut db, 1, None).await.unwrap().is_none()); // insert three settlement events for the same auction id, with one of them not // having solution UID (in practice, usually meaning it's from a different @@ -221,26 +240,29 @@ mod tests { .unwrap(); // load by id works, and finds two hashes - let value_ = load_by_id(&mut db, 0).await.unwrap().unwrap(); + let value_ = load_by_id(&mut db, 0, None).await.unwrap().unwrap(); assert!(value_.tx_hashes.len() == 2); // load as latest works, and finds two hashes - let value_ = load_latest_competition(&mut db).await.unwrap().unwrap(); + let value_ = load_latest_competition(&mut db, None) + .await + .unwrap() + .unwrap(); assert!(value_.tx_hashes.len() == 2); // load by tx works, and finds two hashes, no matter which tx hash is used - let value_ = load_by_tx_hash(&mut db, &ByteArray([0u8; 32])) + let value_ = load_by_tx_hash(&mut db, &ByteArray([0u8; 32]), None) .await .unwrap() .unwrap(); assert!(value_.tx_hashes.len() == 2); - let value_ = load_by_tx_hash(&mut db, &ByteArray([1u8; 32])) + let value_ = load_by_tx_hash(&mut db, &ByteArray([1u8; 32]), None) .await .unwrap() .unwrap(); assert!(value_.tx_hashes.len() == 2); // this one should not find any hashes since it's from another environment - let value_ = load_by_tx_hash(&mut db, &ByteArray([2u8; 32])) + let value_ = load_by_tx_hash(&mut db, &ByteArray([2u8; 32]), None) .await .unwrap(); assert!(value_.is_none()); diff --git a/crates/database/src/solver_competition_v2.rs b/crates/database/src/solver_competition_v2.rs index 34be8500a4..5768b328e4 100644 --- a/crates/database/src/solver_competition_v2.rs +++ b/crates/database/src/solver_competition_v2.rs @@ -32,6 +32,7 @@ pub struct Auction { pub price_values: Vec, pub block: i64, pub id: i64, + pub deadline: i64, } #[derive(sqlx::FromRow)] @@ -74,6 +75,7 @@ pub struct SolverCompetition { pub async fn load_by_tx_hash( mut ex: &mut PgConnection, tx_hash: TransactionHash, + after_block: Option, ) -> Result, sqlx::Error> { const FETCH_AUCTION_ID: &str = r#" SELECT s.auction_id @@ -87,40 +89,45 @@ pub async fn load_by_tx_hash( let Some(auction_id) = auction_id else { return Ok(None); }; - load_by_id(ex.deref_mut(), auction_id).await + load_by_id(ex.deref_mut(), auction_id, after_block).await } #[instrument(skip_all)] pub async fn load_latest( mut ex: &mut PgConnection, + after_block: Option, ) -> Result, sqlx::Error> { const FETCH_AUCTION_ID: &str = r#" SELECT id FROM competition_auctions + WHERE ($1::bigint IS NULL OR deadline <= $1) ORDER BY id DESC LIMIT 1; "#; let auction_id: Option = sqlx::query_scalar(FETCH_AUCTION_ID) + .bind(after_block) .fetch_optional(ex.deref_mut()) .await?; let Some(auction_id) = auction_id else { return Ok(None); }; - load_by_id(ex.deref_mut(), auction_id).await + load_by_id(ex.deref_mut(), auction_id, after_block).await } #[instrument(skip_all)] pub async fn load_by_id( mut ex: &mut PgConnection, id: AuctionId, + after_block: Option, ) -> Result, sqlx::Error> { const FETCH_AUCTION: &str = r#" - SELECT id, order_uids, price_tokens, price_values, block + SELECT id, order_uids, price_tokens, price_values, block, deadline FROM competition_auctions - WHERE id = $1; + WHERE id = $1 AND ($2::bigint IS NULL OR deadline <= $2); "#; let auction: Option = sqlx::query_as(FETCH_AUCTION) .bind(id) + .bind(after_block) .fetch_optional(ex.deref_mut()) .await?; let Some(auction) = auction else { @@ -150,7 +157,7 @@ pub async fn load_by_id( .await?; const FETCH_TRADES: &str = r#" - SELECT pte.solution_uid, pte.order_uid, executed_sell, executed_buy, + SELECT pte.solution_uid, pte.order_uid, executed_sell, executed_buy, COALESCE(o.sell_token, pjo.sell_token) AS sell_token, COALESCE(o.buy_token, pjo.buy_token) AS buy_token FROM proposed_trade_executions AS pte @@ -208,115 +215,6 @@ pub async fn fetch_auction_participants( sqlx::query_as(QUERY).bind(auction_id).fetch_all(ex).await } -/// Identifies solvers that have consistently failed to settle solutions in -/// recent N auctions. -/// -/// 1. Retrieves `last_auctions_count` most recent auctions already ended -/// auctions by filtering them by their deadlines. -/// 2. Identifies solvers who won these auctions but did not submit a successful -/// settlement. -/// 3. Counts how often each solver appears in these unsuccessful cases. -/// 4. Determines the total number of auctions considered. -/// 5. Flags solvers who failed to settle in all of these auctions. -/// 6. Returns a list of solvers that have consistently failed to settle -/// solutions. -#[instrument(skip_all)] -pub async fn find_non_settling_solvers( - ex: &mut PgConnection, - last_auctions_count: u32, - current_block: u64, -) -> Result, sqlx::Error> { - const QUERY: &str = r#" -WITH - last_auctions AS ( - SELECT ps.auction_id, ps.solver - FROM ( - SELECT DISTINCT ca.id AS auction_id - FROM competition_auctions ca - WHERE ca.deadline <= $1 - ORDER BY ca.id DESC - LIMIT $2 - ) latest_auctions - JOIN proposed_solutions ps ON ps.auction_id = latest_auctions.auction_id - WHERE ps.is_winner = true - ), - unsuccessful_solvers AS ( - SELECT la.auction_id, la.solver - FROM last_auctions la - LEFT JOIN settlements s - ON la.auction_id = s.auction_id AND la.solver = s.solver - WHERE s.auction_id IS NULL - ), - solver_appearance_count AS ( - SELECT solver, COUNT(DISTINCT auction_id) AS appearance_count - FROM unsuccessful_solvers - GROUP BY solver - ), - auction_count AS ( - SELECT COUNT(DISTINCT auction_id) AS total_auctions - FROM last_auctions - ), - consistent_solvers AS ( - SELECT sa.solver - FROM solver_appearance_count sa, auction_count ac - WHERE sa.appearance_count = ac.total_auctions - ) -SELECT DISTINCT solver -FROM consistent_solvers; - "#; - - sqlx::query_scalar(QUERY) - .bind(sqlx::types::BigDecimal::from(current_block)) - .bind(i64::from(last_auctions_count)) - .fetch_all(ex) - .await -} - -#[instrument(skip_all)] -pub async fn find_low_settling_solvers( - ex: &mut PgConnection, - last_auctions_count: u32, - current_block: u64, - max_failure_rate: f64, - min_wins_threshold: u32, -) -> Result, sqlx::Error> { - const QUERY: &str = r#" -WITH - last_auctions AS ( - SELECT ps.auction_id, ps.solver - FROM ( - SELECT DISTINCT ca.id AS auction_id - FROM competition_auctions ca - WHERE ca.deadline <= $1 - ORDER BY ca.id DESC - LIMIT $2 - ) latest_auctions - JOIN proposed_solutions ps ON ps.auction_id = latest_auctions.auction_id - WHERE ps.is_winner = true - ), - solver_settlement_counts AS ( - SELECT la.solver, - COUNT(DISTINCT la.auction_id) AS total_wins, - COUNT(DISTINCT s.auction_id) AS total_settlements - FROM last_auctions la - LEFT JOIN settlements s - ON la.auction_id = s.auction_id AND la.solver = s.solver - GROUP BY la.solver - ) -SELECT solver -FROM solver_settlement_counts -WHERE total_wins >= $3 AND (1 - (total_settlements::decimal / NULLIF(total_wins, 0))) > $4; - "#; - - sqlx::query_scalar(QUERY) - .bind(sqlx::types::BigDecimal::from(current_block)) - .bind(i64::from(last_auctions_count)) - .bind(i64::from(min_wins_threshold)) - .bind(max_failure_rate) - .fetch_all(ex) - .await -} - #[derive(Clone, Debug, PartialEq, Default)] pub struct Solution { // Unique Id generated by the autopilot to uniquely identify the solution within Auction @@ -370,7 +268,7 @@ async fn save_solutions( solutions: &[Solution], ) -> Result<(), sqlx::Error> { let mut builder = QueryBuilder::new( - r#"INSERT INTO proposed_solutions + r#"INSERT INTO proposed_solutions (auction_id, uid, id, solver, is_winner, filtered_out, score, price_tokens, price_values)"#, ); @@ -398,7 +296,7 @@ async fn save_trade_executions( solutions: &[Solution], ) -> Result<(), sqlx::Error> { let mut builder = QueryBuilder::new( - r#"INSERT INTO proposed_trade_executions + r#"INSERT INTO proposed_trade_executions (auction_id, solution_uid, order_uid, executed_sell, executed_buy)"#, ); @@ -434,7 +332,7 @@ async fn save_jit_orders( // Order data is saved to `proposed_jit_orders` table only if the order is not // already in the `orders` table. const QUERY_JIT: &str = r#" - INSERT INTO proposed_jit_orders + INSERT INTO proposed_jit_orders (auction_id, solution_uid, order_uid, sell_token, buy_token, limit_sell, limit_buy, side) SELECT $1, $2, $3, $4, $5, $6, $7, $8 WHERE NOT EXISTS (SELECT 1 FROM orders WHERE uid = $3) @@ -562,6 +460,65 @@ fn map_rows_to_solutions(rows: Vec) -> Result, sqlx:: Ok(solutions) } +/// Fetches all orders for which we must assume that there are +/// still onchain transactions being mined or submitted. +/// +/// Those are all orders (JIT or regular) that belong to winning +/// solutions with a deadline greater than the current block +/// where the execution actually has not been observed onchain yet. +pub async fn fetch_in_flight_orders( + ex: &mut PgConnection, + current_block: i64, +) -> Result, sqlx::Error> { + const QUERY: &str = r#" + SELECT DISTINCT order_uid + FROM competition_auctions ca + JOIN proposed_solutions ps ON ps.auction_id = ca.id + JOIN proposed_trade_executions pte ON pte.auction_id = ca.id AND pte.solution_uid = ps.uid + WHERE ca.deadline > $1 + AND ps.is_winner = true + AND NOT EXISTS ( + SELECT 1 FROM settlements s + WHERE s.auction_id = ca.id AND s.solution_uid = ps.uid + ); + "#; + + sqlx::query_as(QUERY) + .bind(current_block) + .fetch_all(ex) + .await +} + +#[derive(Clone, Debug, sqlx::FromRow)] +pub struct OrderProposedSolution { + pub auction_id: AuctionId, + pub solution_uid: i64, + pub solver: Address, + pub is_winner: bool, + pub filtered_out: bool, + pub score: BigDecimal, + pub executed_sell: BigDecimal, + pub executed_buy: BigDecimal, +} + +#[instrument(skip_all)] +pub async fn find_solutions_for_order( + ex: &mut PgConnection, + order_uid: &OrderUid, +) -> Result, sqlx::Error> { + const QUERY: &str = r#" +SELECT ps.auction_id, ps.uid AS solution_uid, + ps.solver, ps.is_winner, ps.filtered_out, ps.score, + pte.executed_sell, pte.executed_buy +FROM proposed_trade_executions pte +JOIN proposed_solutions ps + ON ps.auction_id = pte.auction_id AND ps.uid = pte.solution_uid +WHERE pte.order_uid = $1 +ORDER BY ps.auction_id DESC, ps.uid + "#; + sqlx::query_as(QUERY).bind(order_uid).fetch_all(ex).await +} + #[cfg(test)] mod tests { use { @@ -672,351 +629,6 @@ mod tests { assert!(fetched_solutions[2].orders.len() == 3); } - #[tokio::test] - #[ignore] - async fn postgres_non_settling_solvers_roundtrip() { - let mut db = PgConnection::connect("postgresql://").await.unwrap(); - let mut db = db.begin().await.unwrap(); - crate::clear_DANGER_(&mut db).await.unwrap(); - - let non_settling_solver = ByteArray([1u8; 20]); - - let mut solution_uid = 0; - let deadline_block = 100u64; - let last_auctions_count = 3i64; - // competition_auctions - // Insert auctions within the deadline - for auction_id in 1..=4 { - let auction = auction::Auction { - id: auction_id, - block: auction_id, - deadline: i64::try_from(deadline_block).unwrap(), - order_uids: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - surplus_capturing_jit_order_owners: Default::default(), - }; - auction::save(&mut db, auction).await.unwrap(); - } - - // Insert auctions outside the deadline - for auction_id in 5..=6 { - let auction = auction::Auction { - id: auction_id, - block: auction_id, - deadline: i64::try_from(deadline_block).unwrap() + auction_id, - order_uids: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - surplus_capturing_jit_order_owners: Default::default(), - }; - auction::save(&mut db, auction).await.unwrap(); - } - - // proposed_solutions - // Non-settling solver wins `last_auctions_count` auctions within the deadline - for auction_id in 2..=4 { - solution_uid += 1; - let solutions = vec![Solution { - uid: auction_id, - id: solution_uid.into(), - solver: non_settling_solver, - is_winner: true, - filtered_out: false, - score: Default::default(), - orders: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - }]; - save_solutions(&mut db, auction_id, &solutions) - .await - .unwrap(); - } - - // Another non-settling solver wins not all the auctions within the deadline - for auction_id in 2..=4 { - solution_uid += 1; - let solutions = vec![Solution { - uid: auction_id, - id: solution_uid.into(), - solver: ByteArray([2u8; 20]), - is_winner: auction_id != 2, - filtered_out: false, - score: Default::default(), - orders: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - }]; - save_solutions(&mut db, auction_id, &solutions) - .await - .unwrap(); - } - - // One more non-settling solver has `last_auctions_count` winning auctions but - // not consecutive - for auction_id in 1..=4 { - // Break the sequence - if auction_id == 2 { - continue; - } - solution_uid += 1; - let solutions = vec![Solution { - uid: auction_id, - id: solution_uid.into(), - solver: ByteArray([3u8; 20]), - is_winner: true, - filtered_out: false, - score: Default::default(), - orders: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - }]; - save_solutions(&mut db, auction_id, &solutions) - .await - .unwrap(); - } - - // One more non-settling solver has `last_auctions_count` winning auctions but - // some of them are outside the deadline - for auction_id in 3..=5 { - solution_uid += 1; - let solutions = vec![Solution { - uid: auction_id, - id: solution_uid.into(), - solver: ByteArray([4u8; 20]), - is_winner: true, - filtered_out: false, - score: Default::default(), - orders: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - }]; - save_solutions(&mut db, auction_id, &solutions) - .await - .unwrap(); - } - - // Verify only the non-settling solver is returned - let result = find_non_settling_solvers( - &mut db, - u32::try_from(last_auctions_count).unwrap(), - deadline_block, - ) - .await - .unwrap(); - assert_eq!(result, vec![non_settling_solver]); - - // Non-settling solver settles one of the auctions - let event = EventIndex { - block_number: 4, - log_index: 0, - }; - let settlement = Settlement { - solver: non_settling_solver, - transaction_hash: ByteArray([0u8; 32]), - }; - events::insert_settlement(&mut db, &event, &settlement) - .await - .unwrap(); - - // The same result until the auction_id is updated in the settlements table - let result = find_non_settling_solvers( - &mut db, - u32::try_from(last_auctions_count).unwrap(), - deadline_block, - ) - .await - .unwrap(); - assert_eq!(result, vec![non_settling_solver]); - - settlements::update_settlement_auction(&mut db, 4, 0, 4) - .await - .unwrap(); - - let result = find_non_settling_solvers( - &mut db, - u32::try_from(last_auctions_count).unwrap(), - deadline_block, - ) - .await - .unwrap(); - assert!(result.is_empty()); - } - - #[tokio::test] - #[ignore] - async fn postgres_low_settling_solvers_roundtrip() { - let mut db = PgConnection::connect("postgresql://").await.unwrap(); - let mut db = db.begin().await.unwrap(); - crate::clear_DANGER_(&mut db).await.unwrap(); - - let deadline_block = 2u64; - let last_auctions_count = 100i64; - let max_failure_ratio = 0.6; - let min_wins_threshold = 2; - let mut solution_uid = 0; - - for auction_id in 1..=10 { - let auction = auction::Auction { - id: auction_id, - block: auction_id, - deadline: i64::try_from(deadline_block).unwrap(), - order_uids: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - surplus_capturing_jit_order_owners: Default::default(), - }; - auction::save(&mut db, auction).await.unwrap(); - } - - // Settles only 20% of won auctions - let low_settling_solver = ByteArray([1u8; 20]); - for auction_id in 1..=5 { - solution_uid += 1; - let solutions = vec![Solution { - uid: solution_uid, - id: auction_id.into(), - solver: low_settling_solver, - is_winner: true, - filtered_out: false, - score: Default::default(), - orders: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - }]; - save_solutions(&mut db, auction_id, &solutions) - .await - .unwrap(); - } - let event = EventIndex { - block_number: 1, - log_index: 0, - }; - let settlement = Settlement { - solver: low_settling_solver, - transaction_hash: ByteArray([0u8; 32]), - }; - events::insert_settlement(&mut db, &event, &settlement) - .await - .unwrap(); - settlements::update_settlement_auction(&mut db, 1, 0, 1) - .await - .unwrap(); - - // Settles 0% of won auctions - let non_settling_solver = ByteArray([2u8; 20]); - for auction_id in 1..=5 { - solution_uid += 1; - let solutions = vec![Solution { - uid: solution_uid, - id: auction_id.into(), - solver: non_settling_solver, - is_winner: true, - filtered_out: false, - score: Default::default(), - orders: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - }]; - save_solutions(&mut db, auction_id, &solutions) - .await - .unwrap(); - } - - // Settled 40% of won auctions - let settling_solver = ByteArray([3u8; 20]); - for auction_id in 1..=5 { - solution_uid += 1; - let solutions = vec![Solution { - uid: solution_uid, - id: auction_id.into(), - solver: settling_solver, - is_winner: true, - filtered_out: false, - score: Default::default(), - orders: Default::default(), - price_tokens: Default::default(), - price_values: Default::default(), - }]; - save_solutions(&mut db, auction_id, &solutions) - .await - .unwrap(); - } - for auction_id in 2..=3 { - let event = EventIndex { - block_number: auction_id, - log_index: 0, - }; - let settlement = Settlement { - solver: settling_solver, - transaction_hash: ByteArray([u8::try_from(auction_id).unwrap(); 32]), - }; - events::insert_settlement(&mut db, &event, &settlement) - .await - .unwrap(); - settlements::update_settlement_auction(&mut db, auction_id, 0, auction_id) - .await - .unwrap(); - } - - let result = find_low_settling_solvers( - &mut db, - u32::try_from(last_auctions_count).unwrap(), - deadline_block, - max_failure_ratio, - min_wins_threshold, - ) - .await - .unwrap(); - - assert_eq!(result.len(), 2); - assert!(result.contains(&low_settling_solver)); - assert!(result.contains(&non_settling_solver)); - - // Both won only 5 auctions. With threshold 6, no solver should be returned. - assert!( - find_low_settling_solvers( - &mut db, - u32::try_from(last_auctions_count).unwrap(), - deadline_block, - max_failure_ratio, - 6, - ) - .await - .unwrap() - .is_empty() - ); - - // Low settling solver settles another auction - let event = EventIndex { - block_number: 2, - log_index: 1, - }; - let settlement = Settlement { - solver: low_settling_solver, - transaction_hash: ByteArray([2u8; 32]), - }; - events::insert_settlement(&mut db, &event, &settlement) - .await - .unwrap(); - settlements::update_settlement_auction(&mut db, 2, 1, 2) - .await - .unwrap(); - - let result = find_low_settling_solvers( - &mut db, - u32::try_from(last_auctions_count).unwrap(), - deadline_block, - max_failure_ratio, - min_wins_threshold, - ) - .await - .unwrap(); - - // Now, it is not a low-settling solver anymore - assert_eq!(result, vec![non_settling_solver]); - } - #[tokio::test] #[ignore] async fn postgres_load_by_tx_hash() { @@ -1037,10 +649,10 @@ mod tests { .await .unwrap(); - let solver_competition = load_by_tx_hash(&mut db, tx_hash).await.unwrap(); + let solver_competition = load_by_tx_hash(&mut db, tx_hash, None).await.unwrap(); assert!(solver_competition.is_none()); - let solver_competition = load_by_tx_hash(&mut db, tx_hash).await.unwrap(); + let solver_competition = load_by_tx_hash(&mut db, tx_hash, None).await.unwrap(); assert!(solver_competition.is_none()); // update settlements @@ -1063,7 +675,7 @@ mod tests { }; auction::save(&mut db, auction).await.unwrap(); - let solver_competition = load_by_tx_hash(&mut db, tx_hash).await.unwrap(); + let solver_competition = load_by_tx_hash(&mut db, tx_hash, None).await.unwrap(); assert!(solver_competition.is_some()); let solver_competition = solver_competition.unwrap(); assert_eq!(solver_competition.settlements.len(), 1); @@ -1084,7 +696,7 @@ mod tests { let log_index = 0; let auction_id = 1; - let solver_competition = load_by_id(&mut db, auction_id).await.unwrap(); + let solver_competition = load_by_id(&mut db, auction_id, None).await.unwrap(); assert!(solver_competition.is_none()); // example order @@ -1109,7 +721,7 @@ mod tests { }; auction::save(&mut db, auction).await.unwrap(); - let solver_competition = load_by_id(&mut db, auction_id).await.unwrap(); + let solver_competition = load_by_id(&mut db, auction_id, None).await.unwrap(); assert!(solver_competition.is_some()); // settlements @@ -1127,14 +739,14 @@ mod tests { .unwrap(); // Check before the joined table is populated - let solver_competition = load_by_id(&mut db, auction_id).await.unwrap(); + let solver_competition = load_by_id(&mut db, auction_id, None).await.unwrap(); assert!(solver_competition.is_some()); let solver_competition = solver_competition.unwrap(); assert!(solver_competition.settlements.is_empty()); assert_eq!(solver_competition.auction.id, 1); // Check after the joined table is populated - let solver_competition = load_by_id(&mut db, auction_id).await.unwrap(); + let solver_competition = load_by_id(&mut db, auction_id, None).await.unwrap(); assert!(solver_competition.is_some()); let solver_competition = solver_competition.unwrap(); assert!(solver_competition.settlements.is_empty()); @@ -1155,7 +767,7 @@ mod tests { .unwrap(); // Check after both tables are linked - let solver_competition = load_by_id(&mut db, auction_id).await.unwrap(); + let solver_competition = load_by_id(&mut db, auction_id, None).await.unwrap(); assert!(solver_competition.is_some()); let solver_competition = solver_competition.unwrap(); assert_eq!(solver_competition.settlements.len(), 1); @@ -1219,7 +831,7 @@ mod tests { .await .unwrap(); - let solver_competition = load_by_id(&mut db, auction_id).await.unwrap(); + let solver_competition = load_by_id(&mut db, auction_id, None).await.unwrap(); assert!(solver_competition.is_some()); let solver_competition = solver_competition.unwrap(); assert_eq!(solver_competition.settlements.len(), 1); @@ -1228,6 +840,7 @@ mod tests { tx_hash ); assert_eq!(solver_competition.auction.id, 1); + assert_eq!(solver_competition.auction.deadline, 2); assert_eq!(solver_competition.trades.len(), 1); assert_eq!(solver_competition.trades.first().unwrap().solution_uid, 0); assert_eq!(solver_competition.reference_scores.len(), 1); @@ -1240,4 +853,123 @@ mod tests { assert_eq!(auction_participants.len(), 1); assert_eq!(auction_participants[0].participant, solutions[0].solver); } + + #[tokio::test] + #[ignore] + async fn postgres_fetch_inflight_orders() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut db = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut db).await.unwrap(); + + let order_uid = |i| ByteArray([i; 56]); + let order = |i| Order { + uid: order_uid(i), + ..Default::default() + }; + let solutions = vec![ + Solution { + uid: 0, + id: 0.into(), + orders: vec![order(0)], + is_winner: true, + ..Default::default() + }, + Solution { + uid: 1, + id: 0.into(), + orders: vec![order(1)], + is_winner: true, + ..Default::default() + }, + ]; + crate::auction::save( + &mut db, + crate::auction::Auction { + id: 0, + block: 0, + deadline: 5, + order_uids: Default::default(), + price_tokens: Default::default(), + price_values: Default::default(), + surplus_capturing_jit_order_owners: Default::default(), + }, + ) + .await + .unwrap(); + save(&mut db, 0, &solutions).await.unwrap(); + + let solutions = vec![ + Solution { + uid: 2, + id: 1.into(), + orders: vec![order(2)], + is_winner: true, + ..Default::default() + }, + Solution { + uid: 3, + id: 1.into(), + orders: vec![order(3)], + is_winner: true, + ..Default::default() + }, + ]; + crate::auction::save( + &mut db, + crate::auction::Auction { + id: 1, + block: 5, + deadline: 10, + order_uids: Default::default(), + price_tokens: Default::default(), + price_values: Default::default(), + surplus_capturing_jit_order_owners: Default::default(), + }, + ) + .await + .unwrap(); + save(&mut db, 1, &solutions).await.unwrap(); + + // all orders in flight at block 4 + let early_block = fetch_in_flight_orders(&mut db, 4).await.unwrap(); + assert_eq!(early_block.len(), 4); + assert!( + [0, 1, 2, 3] + .into_iter() + .all(|id| early_block.contains(&order_uid(id))) + ); + + // only orders from the later auction in flight at block 5 + let later_block = fetch_in_flight_orders(&mut db, 5).await.unwrap(); + assert_eq!(later_block.len(), 2); + assert!( + [2, 3] + .into_iter() + .all(|id| later_block.contains(&order_uid(id))) + ); + + // observe settlement event + crate::events::insert_settlement( + &mut db, + &EventIndex { + block_number: 5, + log_index: 0, + }, + &Default::default(), + ) + .await + .unwrap(); + // associate with auction 1 + settlements::update_settlement_auction(&mut db, 5, 0, 1) + .await + .unwrap(); + // associate with solution 3 + settlements::update_settlement_solver(&mut db, 5, 0, Default::default(), 3) + .await + .unwrap(); + + // when an order gets marked as settled we dont consider it inflight anymore + let later_block_with_settlement = fetch_in_flight_orders(&mut db, 5).await.unwrap(); + assert_eq!(later_block_with_settlement, vec![order_uid(2)]); + } } diff --git a/crates/database/src/trades.rs b/crates/database/src/trades.rs index 047b07d9c9..09d6072ae5 100644 --- a/crates/database/src/trades.rs +++ b/crates/database/src/trades.rs @@ -1,7 +1,6 @@ use { crate::{Address, OrderUid, TransactionHash, auction::AuctionId, events::EventIndex}, bigdecimal::BigDecimal, - futures::stream::BoxStream, sqlx::PgConnection, tracing::{Instrument, info_span, instrument}, }; @@ -25,8 +24,10 @@ pub fn trades<'a>( ex: &'a mut PgConnection, owner_filter: Option<&'a Address>, order_uid_filter: Option<&'a OrderUid>, -) -> instrument::Instrumented>> { - const COMMON_QUERY: &str = r#" + offset: i64, + limit: i64, +) -> instrument::Instrumented, sqlx::Error>>> { + const SELECT: &str = r#" SELECT t.block_number, t.log_index, @@ -38,8 +39,9 @@ SELECT o.buy_token, o.sell_token, settlement.tx_hash, - settlement.auction_id -FROM trades t + settlement.auction_id"#; + + const SETTLEMENT_JOIN: &str = r#" LEFT OUTER JOIN LATERAL ( SELECT tx_hash, auction_id FROM settlements s WHERE s.block_number = t.block_number @@ -49,28 +51,71 @@ LEFT OUTER JOIN LATERAL ( ) AS settlement ON true"#; const QUERY: &str = const_format::concatcp!( - COMMON_QUERY, + "(", + SELECT, + " FROM trades t", + SETTLEMENT_JOIN, " JOIN orders o ON o.uid = t.order_uid", - " WHERE ($1 IS NULL OR o.owner = $1)", - " AND ($2 IS NULL OR o.uid = $2)", + // the uid already contains the owner address and we have + // an index on this expression so this is very efficient + " WHERE ($1 IS NULL OR substring(t.order_uid, 33, 20) = $1)", + " AND ($2 IS NULL OR t.order_uid = $2)", + " ORDER BY t.block_number DESC, t.log_index DESC", + " LIMIT $3 + $4", + ")", " UNION ", - COMMON_QUERY, + "(", + SELECT, + " FROM trades t", + SETTLEMENT_JOIN, " JOIN orders o ON o.uid = t.order_uid", - " LEFT OUTER JOIN onchain_placed_orders onchain_o", + " JOIN onchain_placed_orders onchain_o", " ON onchain_o.uid = t.order_uid", - " WHERE onchain_o.sender = $1", - " AND ($2 IS NULL OR o.uid = $2)", + " WHERE ($1 IS NULL OR onchain_o.sender = $1)", + " AND ($2 IS NULL OR t.order_uid = $2)", + " ORDER BY t.block_number DESC, t.log_index DESC", + " LIMIT $3 + $4", + ")", " UNION ", - COMMON_QUERY, - " JOIN jit_orders o ON o.uid = t.order_uid", - " WHERE ($1 IS NULL OR o.owner = $1)", - " AND ($2 IS NULL OR o.uid = $2)", + // Note that we apply 2 tricks here: + // 1. we invert the join order (join `trades` onto `jit_orders` instead + // of `jit_orders` onto `trades`). For cases where 1 account has MANY + // trades joining `jit_orders` onto the trades means fetching data for + // MANY `jit_orders`. But given that `jit_orders` are rare inverting the + // join order means we only fetch few or no `jit_orders` at all when + // looking them up by `owner`. + // 2. we explicitly use a MATERIALIZED CTE to force the query planner + // to follow this lookup order. Without using `MATERIALIZED` the query + // planner can "inline" this sub-query and which can lead to incorrect + // optimization decisions. + // Specifically NOT using `MATERIALIZED` can lead to the query + // planner doing full scans on the `trades` table instead of searching + // via the `owner` index on the `jit_orders` table. + "(", + " WITH jit AS MATERIALIZED (", + " SELECT uid, owner, buy_token, sell_token", + " FROM jit_orders", + " WHERE ($1 IS NULL OR owner = $1)", + " AND ($2 IS NULL OR uid = $2)", + ")", + SELECT, + " FROM jit o", + " JOIN trades t ON o.uid = t.order_uid", + SETTLEMENT_JOIN, + " ORDER BY t.block_number DESC, t.log_index DESC", + " LIMIT $3 + $4", + ")", + " ORDER BY block_number DESC, log_index DESC", + " LIMIT $3", + " OFFSET $4", ); sqlx::query_as(QUERY) .bind(owner_filter) .bind(order_uid_filter) - .fetch(ex) + .bind(limit) + .bind(offset) + .fetch_all(ex) .instrument(info_span!("trades")) } @@ -146,17 +191,31 @@ mod tests { onchain_broadcasted_orders::{OnchainOrderPlacement, insert_onchain_order}, orders::Order, }, - futures::TryStreamExt, sqlx::Connection, }; + /// Generates 1 unique user and the provided number of unique orders + /// for that user. async fn generate_owners_and_order_ids( - num_owners: usize, - num_orders: usize, - ) -> (Vec
, Vec) { - let owners: Vec
= (0..num_owners).map(|t| ByteArray([t as u8; 20])).collect(); - let order_ids: Vec = (0..num_orders).map(|i| ByteArray([i as u8; 56])).collect(); - (owners, order_ids) + orders_for_user: &[usize], + ) -> Vec<(Address, Vec)> { + orders_for_user + .iter() + .enumerate() + .map(|(index, num_orders)| { + let user = ByteArray([index as u8; 20]); + let orders = (0usize..*num_orders) + .map(|index| { + let mut uid_bytes = [index as u8; 56]; + // make sure to write the owner bytes correctly into + // the order uid since those are used in some queries + uid_bytes[32..52].copy_from_slice(&user.0); + ByteArray(uid_bytes) + }) + .collect(); + (user, orders) + }) + .collect() } async fn add_trade( @@ -213,9 +272,9 @@ mod tests { order_uid_filter: Option<&OrderUid>, expected: &[TradesQueryRow], ) { - let mut filtered = trades(db, owner_filter, order_uid_filter) + // Use large limit to get all trades + let mut filtered = trades(db, owner_filter, order_uid_filter, 0, 1000) .into_inner() - .try_collect::>() .await .unwrap(); filtered.sort_by_key(|t| (t.block_number, t.log_index)); @@ -230,22 +289,37 @@ mod tests { let mut db = db.begin().await.unwrap(); crate::clear_DANGER_(&mut db).await.unwrap(); - let (owners, order_ids) = generate_owners_and_order_ids(2, 2).await; + // 1 user with 2 orders + let users_and_orders = generate_owners_and_order_ids(&[2]).await; assert_trades(&mut db, None, None, &[]).await; let event_index_a = EventIndex { block_number: 0, log_index: 0, }; - let trade_a = - add_order_and_trade(&mut db, owners[0], order_ids[0], event_index_a, None, None).await; + let trade_a = add_order_and_trade( + &mut db, + users_and_orders[0].0, + users_and_orders[0].1[0], + event_index_a, + None, + None, + ) + .await; assert_trades(&mut db, None, None, std::slice::from_ref(&trade_a)).await; let event_index_b = EventIndex { block_number: 1, log_index: 0, }; - let trade_b = - add_order_and_trade(&mut db, owners[0], order_ids[1], event_index_b, None, None).await; + let trade_b = add_order_and_trade( + &mut db, + users_and_orders[0].0, + users_and_orders[0].1[1], + event_index_b, + None, + None, + ) + .await; assert_trades(&mut db, None, None, &[trade_a, trade_b]).await; } @@ -287,9 +361,8 @@ mod tests { } let now = std::time::Instant::now(); - trades(&mut db, Some(&ByteArray([2u8; 20])), None) + trades(&mut db, Some(&ByteArray([2u8; 20])), None, 0, 100) .into_inner() - .try_collect::>() .await .unwrap(); let elapsed = now.elapsed(); @@ -304,65 +377,80 @@ mod tests { let mut db = db.begin().await.unwrap(); crate::clear_DANGER_(&mut db).await.unwrap(); - let (owners, order_ids) = generate_owners_and_order_ids(4, 4).await; + let users_and_orders = generate_owners_and_order_ids(&[1, 1, 1, 1, 1]).await; let event_index_0 = EventIndex { block_number: 0, log_index: 0, }; - let trade_0 = - add_order_and_trade(&mut db, owners[0], order_ids[0], event_index_0, None, None).await; + let trade_0 = add_order_and_trade( + &mut db, + users_and_orders[0].0, + users_and_orders[0].1[0], + event_index_0, + None, + None, + ) + .await; let event_index_1 = EventIndex { block_number: 0, log_index: 1, }; - let trade_1 = - add_order_and_trade(&mut db, owners[1], order_ids[1], event_index_1, None, None).await; + let trade_1 = add_order_and_trade( + &mut db, + users_and_orders[1].0, + users_and_orders[1].1[0], + event_index_1, + None, + None, + ) + .await; assert_trades( &mut db, - Some(&owners[0]), + Some(&users_and_orders[0].0), None, std::slice::from_ref(&trade_0), ) .await; assert_trades( &mut db, - Some(&owners[1]), + Some(&users_and_orders[1].0), None, std::slice::from_ref(&trade_1), ) .await; - assert_trades(&mut db, Some(&owners[2]), None, &[]).await; + assert_trades(&mut db, Some(&users_and_orders[2].0), None, &[]).await; let onchain_order = OnchainOrderPlacement { - order_uid: ByteArray(order_ids[0].0), - sender: owners[3], + order_uid: users_and_orders[3].1[0], + sender: users_and_orders[4].0, placement_error: None, }; - let event_index = EventIndex::default(); - insert_onchain_order(&mut db, &event_index, &onchain_order) + let event_index_2 = EventIndex { + block_number: 0, + log_index: 2, + }; + let trade_2 = add_order_and_trade( + &mut db, + users_and_orders[3].0, + users_and_orders[3].1[0], + event_index_2, + None, + None, + ) + .await; + insert_onchain_order(&mut db, &event_index_2, &onchain_order) .await .unwrap(); assert_trades( &mut db, - Some(&owners[3]), + Some(&users_and_orders[4].0), None, - std::slice::from_ref(&trade_0), + std::slice::from_ref(&trade_2), ) .await; - - add_order_and_trade(&mut db, owners[3], order_ids[3], event_index_1, None, None).await; - let onchain_order = OnchainOrderPlacement { - order_uid: ByteArray(order_ids[3].0), - sender: owners[3], - placement_error: None, - }; - insert_onchain_order(&mut db, &event_index_1, &onchain_order) - .await - .unwrap(); - assert_trades(&mut db, Some(&owners[3]), None, &[trade_0]).await; } #[tokio::test] @@ -372,25 +460,40 @@ mod tests { let mut db = db.begin().await.unwrap(); crate::clear_DANGER_(&mut db).await.unwrap(); - let (owners, order_ids) = generate_owners_and_order_ids(2, 3).await; + // 3 users with 1 order each + let users_and_orders = generate_owners_and_order_ids(&[1, 1, 1]).await; let event_index_0 = EventIndex { block_number: 0, log_index: 0, }; - let trade_0 = - add_order_and_trade(&mut db, owners[0], order_ids[0], event_index_0, None, None).await; + let trade_0 = add_order_and_trade( + &mut db, + users_and_orders[0].0, + users_and_orders[0].1[0], + event_index_0, + None, + None, + ) + .await; let event_index_1 = EventIndex { block_number: 0, log_index: 1, }; - let trade_1 = - add_order_and_trade(&mut db, owners[1], order_ids[1], event_index_1, None, None).await; + let trade_1 = add_order_and_trade( + &mut db, + users_and_orders[1].0, + users_and_orders[1].1[0], + event_index_1, + None, + None, + ) + .await; - assert_trades(&mut db, None, Some(&order_ids[0]), &[trade_0]).await; - assert_trades(&mut db, None, Some(&order_ids[1]), &[trade_1]).await; - assert_trades(&mut db, None, Some(&order_ids[2]), &[]).await; + assert_trades(&mut db, None, Some(&users_and_orders[0].1[0]), &[trade_0]).await; + assert_trades(&mut db, None, Some(&users_and_orders[1].1[0]), &[trade_1]).await; + assert_trades(&mut db, None, Some(&users_and_orders[2].1[0]), &[]).await; } #[tokio::test] @@ -400,16 +503,25 @@ mod tests { let mut db = db.begin().await.unwrap(); crate::clear_DANGER_(&mut db).await.unwrap(); - let (owners, order_ids) = generate_owners_and_order_ids(1, 1).await; + // 1 user with 1 order + let users_and_trades = generate_owners_and_order_ids(&[1]).await; let event_index = EventIndex { block_number: 0, log_index: 0, }; - add_trade(&mut db, owners[0], order_ids[0], event_index, None, None).await; + add_trade( + &mut db, + users_and_trades[0].0, + users_and_trades[0].1[0], + event_index, + None, + None, + ) + .await; // Trade exists in DB but no matching order - assert_trades(&mut db, None, Some(&order_ids[0]), &[]).await; - assert_trades(&mut db, Some(&owners[0]), None, &[]).await; + assert_trades(&mut db, None, Some(&users_and_trades[0].1[0]), &[]).await; + assert_trades(&mut db, Some(&users_and_trades[0].0), None, &[]).await; } // Testing Trades with settlements @@ -445,7 +557,8 @@ mod tests { let mut db = db.begin().await.unwrap(); crate::clear_DANGER_(&mut db).await.unwrap(); - let (owners, order_ids) = generate_owners_and_order_ids(2, 2).await; + // 1 user with 2 orders + let users_and_orders = generate_owners_and_order_ids(&[2]).await; assert_trades(&mut db, None, None, &[]).await; let settlement = add_settlement( @@ -462,8 +575,8 @@ mod tests { let trade_a = add_order_and_trade( &mut db, - owners[0], - order_ids[0], + users_and_orders[0].0, + users_and_orders[0].1[0], EventIndex { block_number: 0, log_index: 0, @@ -476,8 +589,8 @@ mod tests { let trade_b = add_order_and_trade( &mut db, - owners[0], - order_ids[1], + users_and_orders[0].0, + users_and_orders[0].1[1], EventIndex { block_number: 0, log_index: 1, @@ -496,7 +609,8 @@ mod tests { let mut db = db.begin().await.unwrap(); crate::clear_DANGER_(&mut db).await.unwrap(); - let (owners, order_ids) = generate_owners_and_order_ids(2, 2).await; + // 1 user with 2 orders + let users_and_trades = generate_owners_and_order_ids(&[2]).await; assert_trades(&mut db, None, None, &[]).await; let settlement = add_settlement( @@ -513,8 +627,8 @@ mod tests { add_trade( &mut db, - owners[0], - order_ids[0], + users_and_trades[0].0, + users_and_trades[0].1[0], EventIndex { block_number: 0, log_index: 0, @@ -526,8 +640,8 @@ mod tests { add_trade( &mut db, - owners[0], - order_ids[1], + users_and_trades[0].0, + users_and_trades[0].1[1], EventIndex { block_number: 0, log_index: 1, @@ -547,7 +661,8 @@ mod tests { let mut db = db.begin().await.unwrap(); crate::clear_DANGER_(&mut db).await.unwrap(); - let (owners, order_ids) = generate_owners_and_order_ids(2, 2).await; + // 1 user with 2 orders + let users_and_orders = generate_owners_and_order_ids(&[2]).await; assert_trades(&mut db, None, None, &[]).await; let settlement_a_event = EventIndex { @@ -578,8 +693,8 @@ mod tests { let trade_a = add_order_and_trade( &mut db, - owners[0], - order_ids[0], + users_and_orders[0].0, + users_and_orders[0].1[0], EventIndex { block_number: 0, log_index: 0, @@ -592,8 +707,8 @@ mod tests { let trade_b = add_order_and_trade( &mut db, - owners[0], - order_ids[1], + users_and_orders[0].0, + users_and_orders[0].1[1], EventIndex { block_number: 0, log_index: 2, @@ -639,7 +754,8 @@ mod tests { let token = Default::default(); assert_eq!(token_first_trade_block(&mut db, token).await.unwrap(), None); - let (owners, order_ids) = generate_owners_and_order_ids(2, 2).await; + // 2 users with 1 order each + let users_and_orders = generate_owners_and_order_ids(&[1, 1]).await; let event_index_a = EventIndex { block_number: 123, log_index: 0, @@ -648,11 +764,92 @@ mod tests { block_number: 124, log_index: 0, }; - add_order_and_trade(&mut db, owners[0], order_ids[0], event_index_a, None, None).await; - add_order_and_trade(&mut db, owners[1], order_ids[1], event_index_b, None, None).await; + add_order_and_trade( + &mut db, + users_and_orders[0].0, + users_and_orders[0].1[0], + event_index_a, + None, + None, + ) + .await; + add_order_and_trade( + &mut db, + users_and_orders[1].0, + users_and_orders[1].1[0], + event_index_b, + None, + None, + ) + .await; assert_eq!( token_first_trade_block(&mut db, token).await.unwrap(), Some(123) ); } + + #[tokio::test] + #[ignore] + async fn postgres_trades_pagination() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut db = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut db).await.unwrap(); + + // Create 5 trades with the same owner + let users_and_orders = generate_owners_and_order_ids(&[5]).await; + let owner = users_and_orders[0].0; + + let mut expected_trades = Vec::new(); + for (i, order_id) in users_and_orders[0].1.iter().enumerate() { + let trade = add_order_and_trade( + &mut db, + owner, + *order_id, + EventIndex { + block_number: i.try_into().unwrap(), + log_index: 0, + }, + None, + None, + ) + .await; + expected_trades.push(trade); + } + + // Sort expected trades by block_number DESC (matching query ORDER BY) + expected_trades.sort_by_key(|trade| std::cmp::Reverse(trade.block_number)); + + // Test limit: get first 2 trades (blocks 4 and 3 in DESC order) + let result = trades(&mut db, Some(&owner), None, 0, 2) + .into_inner() + .await + .unwrap(); + assert_eq!(result.len(), 2); + assert_eq!(result[0], expected_trades[0]); // block 4 + assert_eq!(result[1], expected_trades[1]); // block 3 + + // Test offset: skip first 2, get next 2 (blocks 2 and 1 in DESC order) + let result = trades(&mut db, Some(&owner), None, 2, 2) + .into_inner() + .await + .unwrap(); + assert_eq!(result.len(), 2); + assert_eq!(result[0], expected_trades[2]); // block 2 + assert_eq!(result[1], expected_trades[3]); // block 1 + + // Test offset beyond available trades + let result = trades(&mut db, Some(&owner), None, 10, 2) + .into_inner() + .await + .unwrap(); + assert_eq!(result.len(), 0); + + // Test large limit returns all available trades in DESC order + let result = trades(&mut db, Some(&owner), None, 0, 100) + .into_inner() + .await + .unwrap(); + assert_eq!(result.len(), 5); + assert_eq!(result, expected_trades); + } } diff --git a/crates/driver/Cargo.toml b/crates/driver/Cargo.toml index 0f4b880741..a79476d896 100644 --- a/crates/driver/Cargo.toml +++ b/crates/driver/Cargo.toml @@ -6,86 +6,103 @@ edition = "2024" license = "GPL-3.0-or-later" [lib] +doctest = false name = "driver" path = "src/lib.rs" -doctest = false [[bin]] name = "driver" path = "src/main.rs" [dependencies] -alloy = { workspace = true, features = ["sol-types"] } +account-balances = { workspace = true } +alloy = { + workspace = true, + features = ["json-rpc", "provider-anvil-api", "provider-txpool-api", "rand", "rpc-types", "signer-aws", "sol-types"] +} app-data = { workspace = true } async-trait = { workspace = true } axum = { workspace = true } +bad-tokens = { workspace = true } +balance-overrides = { workspace = true } bigdecimal = { workspace = true } -bytes-hex = { workspace = true } # may get marked as unused but it's used with serde +bytes = { workspace = true } +bytes-hex = { workspace = true } # may get marked as unused but it's used with serde chain = { workspace = true } -chrono = { workspace = true, features = ["clock"], default-features = false } +chrono = { workspace = true, default-features = false, features = ["clock"] } +configs = { workspace = true } +const-hex = { workspace = true } cow-amm = { workspace = true } dashmap = { workspace = true } derive_more = { workspace = true } -ethereum-types = { workspace = true } +eth-domain-types = { workspace = true } ethrpc = { workspace = true } +event-indexing = { workspace = true } futures = { workspace = true } -const-hex = { workspace = true } +gas-price-estimation = { workspace = true } hex-literal = { workspace = true } +http-client = { workspace = true } humantime = { workspace = true } humantime-serde = { workspace = true } -hyper = { workspace = true } itertools = { workspace = true } -mimalloc = { workspace = true } +liquidity-sources = { workspace = true } +mimalloc = { workspace = true, optional = true } moka = { workspace = true, features = ["future"] } num = { workspace = true } number = { workspace = true } +price-estimation = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } rand = { workspace = true } -reqwest = { workspace = true } +request-sharing = { workspace = true } +reqwest = { workspace = true, features = ["query"] } s3 = { workspace = true } -serde = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-ext = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } +simulator = { workspace = true } solvers-dto = { path = "../solvers-dto" } thiserror = { workspace = true } +tikv-jemallocator = { workspace = true } +token-info = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "time"] } toml = { workspace = true } tower = { workspace = true } -tower-http = { workspace = true, features = ["limit", "trace"] } +tower-http = { workspace = true, features = ["decompression-br", "limit", "trace"] } url = { workspace = true, features = ["serde"] } -web3 = { workspace = true, features = ["http"] } # These still use { workspace = true } because they're used at # the boundary between driver and shared. -primitive-types = { workspace = true } -secp256k1 = { workspace = true } # TODO These either need to be removed or changed to be direct # dependencies rather than workspace dependencies anyhow = { workspace = true } clap = { workspace = true } contracts = { workspace = true } -ethcontract = { workspace = true } -gas-estimation = { workspace = true } model = { workspace = true } -observe = { workspace = true, features = ["axum-tracing"] } +observe = { workspace = true } shared = { workspace = true } +signature-validator = { workspace = true } solver = { workspace = true } tracing = { workspace = true } [dev-dependencies] +alloy = { workspace = true, features = ["signer-mnemonic"] } app-data = { workspace = true, features = ["test_helpers"] } +contracts = { workspace = true } +ethrpc = { workspace = true, features = ["test-util"] } maplit = { workspace = true } -tokio = { workspace = true, features = ["test-util", "process"] } tempfile = { workspace = true } -ethrpc = { workspace = true, features = ["test-util"] } -contracts = { workspace = true } -alloy = { workspace = true, features = ["signer-mnemonic"] } +tokio = { workspace = true, features = ["process", "test-util"] } [build-dependencies] anyhow = { workspace = true } vergen = { workspace = true, features = ["git", "gitcl"] } +[features] +mimalloc-allocator = ["dep:mimalloc"] +tokio-console = ["observe/tokio-console"] + [lints] workspace = true diff --git a/crates/driver/example.toml b/crates/driver/example.toml index bdc1e5a4b7..7925978367 100644 --- a/crates/driver/example.toml +++ b/crates/driver/example.toml @@ -1,15 +1,16 @@ tx-gas-limit = "45000000" + [[solver]] -name = "mysolver" # Arbitrary name given to this solver, must be unique +name = "mysolver" # Arbitrary name given to this solver, must be unique endpoint = "http://0.0.0.0:7872" -absolute-slippage = "40000000000000000" # Denominated in wei, optional -relative-slippage = "0.1" # Percentage in the [0, 1] range -account = "0x0000000000000000000000000000000000000000000000000000000000000001" # The private key of the solver -merge-solutions = true # Multiple solutions proposed by the solver may be combined into one by the driver +absolute-slippage = "40000000000000000" # Denominated in wei, optional +relative-slippage = "0.1" # Percentage in the [0, 1] range +account = "0x0000000000000000000000000000000000000000000000000000000000000001" # The private key of the solver +merge-solutions = true # Multiple solutions proposed by the solver may be combined into one by the driver response-size-limit-max-bytes = 30000000 [solver.request-headers] -fake-header-one = "FAKE-HEADER-VALUE" # For instance an authorization token which must be provided on each request +fake-header-one = "FAKE-HEADER-VALUE" # For instance an authorization token which must be provided on each request # [[solver]] # And so on, specify as many solvers as needed # name = "othersolver" @@ -21,18 +22,14 @@ fake-header-one = "FAKE-HEADER-VALUE" # For instance an authorization token whic gas-price-cap = "1000000000000" [[submission.mempool]] -mempool = "public" -max-additional-tip = "5000000000" -additional-tip-percentage = 0.05 - -[[submission.mempool]] -mempool = "mev-blocker" url = "https://your.custom.rpc.endpoint" +# optional args +name = "custom_name" max-additional-tip = "5000000000" additional-tip-percentage = 0.05 -use-soft-cancellations = true +mines-reverting-txs = true -[contracts] # Optionally override the contract addresses, necessary on less popular blockchains +[contracts] # Optionally override the contract addresses, necessary on less popular blockchains gp-v2-settlement = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" balances = "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b" @@ -47,8 +44,8 @@ helper = "0x86f3df416979136cb4fdea2c0886301b911c163b" [liquidity] base-tokens = [ - "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB", - "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB", + "0x6B175474E89094C44Da98b954EedeAC495271d0F", ] [[order-priority]] @@ -94,22 +91,23 @@ max-order-age = "1m" # liquidity-bootstrapping = [] # liquidity bootstrapping pool factory addresses # pool-deny-list = [] # which pools to ignore -# [[liquidity.uniswap-v3]] # Uniswap V3 configuration +# [[liquidity.uniswap-v3]] # Uniswap V3 configuration (subgraph as data source) # preset = "uniswap-v3" -# graph-url = "http://localhost:1234" # which subgraph url to fetch the data from +# indexer-config = { subgraph = { url = "http://localhost:1234" } } # max_pools_to_initialize = 100 # how many of the deepest pools to initialise on startup +# [[liquidity.uniswap-v3]] # Uniswap V3 configuration (pool-indexer as data source) +# preset = "uniswap-v3" +# indexer-config = { pool-indexer = { url = "http://pool-indexer/", wait-until-timeout = "5m" } } +# max_pools_to_initialize = 100 + # [[liquidity.uniswap-v3]] # Custom Uniswap V3 configuration # router = "0xE592427A0AEce92De3Edee1F18E0157C05861564" +# indexer-config = { subgraph = { url = "http://localhost:1234" } } # max_pools_to_initialize = 100 # how many of the deepest pools to initialise on startup -# [enso] -# url = "http://localhost:8454" -# network-block-interval = "12s" - # [liquidity-sources-notifier] # Sends settlement notifications to third party liquidity sources used by solvers # [liquidity-sources-notifier.liquorice] # base-url = "https://api.liquorice.tech/" # api-key = "..." # http_timeout = "10s" - diff --git a/crates/driver/openapi.yml b/crates/driver/openapi.yml index 50ab2176c6..a10c4e073e 100644 --- a/crates/driver/openapi.yml +++ b/crates/driver/openapi.yml @@ -537,11 +537,17 @@ components: type: string description: The effective amount the user received after all fees. clearingPrices: + deprecated: true description: > - Mapping of hex token address to price. + Deprecated. The autopilot no longer consumes uniform clearing + prices from the `/solve` response and ignores this field if + present. It is still emitted by drivers for backward + compatibility with autopilots running the previous code, and + will be removed in a follow-up release. - The prices of tokens for settled user orders as passed to the - settlement contract. + + Mapping of hex token address to price. The prices of tokens + for settled user orders as passed to the settlement contract. type: object additionalProperties: $ref: "#/components/schemas/BigUint" diff --git a/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs b/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs index 820ad58e51..350a687555 100644 --- a/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs +++ b/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs @@ -2,13 +2,13 @@ use { crate::{ boundary, domain::{ - eth, + self, liquidity::{self, balancer}, }, infra::{self, blockchain::Ethereum}, }, anyhow::{Context, Result}, - contracts::alloy::{ + contracts::{ BalancerV2ComposableStablePoolFactory, BalancerV2LiquidityBootstrappingPoolFactory, BalancerV2StablePoolFactoryV2, @@ -16,24 +16,20 @@ use { BalancerV2WeightedPoolFactory, BalancerV2WeightedPoolFactoryV3, }, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::{BlockRetrieving, CurrentBlockWatcher}, - }, - shared::{ - http_solver::model::TokenAmount, - sources::balancer_v2::{ - BalancerPoolFetcher, - pool_fetching::{BalancerContracts, BalancerFactoryInstance}, - }, - token_info::{CachedTokenInfoFetcher, TokenInfoFetcher}, + eth_domain_types as eth, + ethrpc::block_stream::CurrentBlockWatcher, + event_indexing::block_retriever::BlockRetrieving, + liquidity_sources::balancer_v2::{ + BalancerPoolFetcher, + pool_fetching::{BalancerContracts, BalancerFactoryInstance}, }, + shared::http_solver::model::TokenAmount, solver::{ - interactions::allowances::Allowances, - liquidity::{balancer_v2, balancer_v2::BalancerV2Liquidity}, + liquidity::balancer_v2::{self, BalancerV2Liquidity}, liquidity_collector::{BackgroundInitLiquiditySource, LiquidityCollecting}, }, std::sync::Arc, + token_info::{CachedTokenInfoFetcher, TokenInfoFetcher}, }; pub mod stable; @@ -49,27 +45,26 @@ fn to_interaction( input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, -) -> eth::Interaction { +) -> domain::Interaction { let handler = balancer_v2::SettlementHandler::new( - pool.id.into(), + pool.id.0, // Note that this code assumes `receiver == sender`. This assumption is // also baked into the Balancer V2 logic in the `shared` crate, so to // change this assumption, we would need to change it there as well. - receiver.0.into_alloy(), - pool.vault.0.into_alloy(), - Allowances::empty(receiver.0), + *receiver, + *pool.vault, ); let interaction = handler.swap( - TokenAmount::new(input.0.token.into(), input.0.amount), - TokenAmount::new(output.0.token.into(), output.0.amount), + TokenAmount::new(*input.0.token, input.0.amount.0), + TokenAmount::new(*output.0.token, output.0.amount.0), ); let (target, value, call_data) = interaction.encode_swap(); - eth::Interaction { - target: target.into_legacy().into(), - value: value.into_legacy().into(), + domain::Interaction { + target, + value: value.into(), call_data: call_data.0.to_vec().into(), } } @@ -107,7 +102,7 @@ async fn init_liquidity( ) -> Result> { let web3 = eth.web3().clone(); let contracts = BalancerContracts { - vault: BalancerV2Vault::Instance::new(config.vault.0.into_alloy(), web3.alloy.clone()), + vault: BalancerV2Vault::Instance::new(*config.vault, web3.provider.clone()), factories: [ config .weighted @@ -115,7 +110,7 @@ async fn init_liquidity( .map(|&factory| { BalancerFactoryInstance::Weighted(BalancerV2WeightedPoolFactory::Instance::new( factory, - web3.alloy.clone(), + web3.provider.clone(), )) }) .collect::>(), @@ -124,7 +119,10 @@ async fn init_liquidity( .iter() .map(|&factory| { BalancerFactoryInstance::WeightedV3( - BalancerV2WeightedPoolFactoryV3::Instance::new(factory, web3.alloy.clone()), + BalancerV2WeightedPoolFactoryV3::Instance::new( + factory, + web3.provider.clone(), + ), ) }) .collect::>(), @@ -134,7 +132,7 @@ async fn init_liquidity( .map(|&factory| { BalancerFactoryInstance::StableV2(BalancerV2StablePoolFactoryV2::Instance::new( factory, - web3.alloy.clone(), + web3.provider.clone(), )) }) .collect::>(), @@ -145,7 +143,7 @@ async fn init_liquidity( BalancerFactoryInstance::LiquidityBootstrapping( BalancerV2LiquidityBootstrappingPoolFactory::Instance::new( factory, - web3.alloy.clone(), + web3.provider.clone(), ), ) }) @@ -157,7 +155,7 @@ async fn init_liquidity( BalancerFactoryInstance::ComposableStable( BalancerV2ComposableStablePoolFactory::Instance::new( factory, - web3.alloy.clone(), + web3.provider.clone(), ), ) }) @@ -181,14 +179,13 @@ async fn init_liquidity( boundary::liquidity::http_client(), web3.clone(), &contracts, - config.pool_deny_list.clone(), + config.pool_deny_list.to_vec(), ) .await .context("failed to create balancer pool fetcher")?, ); Ok(BalancerV2Liquidity::new( - web3, balancer_pool_fetcher, *eth.contracts().settlement().address(), *contracts.vault.address(), diff --git a/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs b/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs index dc252d7312..c74039e887 100644 --- a/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs +++ b/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs @@ -2,11 +2,11 @@ use { crate::{ boundary::Result, domain::{ - eth, + self, liquidity::{self, balancer}, }, }, - ethrpc::alloy::conversions::IntoLegacy, + eth_domain_types as eth, solver::liquidity::{StablePoolOrder, balancer_v2}, }; @@ -47,13 +47,13 @@ pub fn to_domain(id: liquidity::Id, pool: StablePoolOrder) -> Result eth::ContractAddress { - pool.settlement_handling + (*pool + .settlement_handling .as_any() .downcast_ref::() .expect("downcast balancer settlement handler") - .vault() - .into_legacy() - .into() + .vault()) + .into() } fn pool_id(pool: &StablePoolOrder) -> balancer::v2::Id { @@ -70,7 +70,7 @@ pub fn to_interaction( input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, -) -> eth::Interaction { +) -> domain::Interaction { super::to_interaction( &super::Pool { vault: pool.vault, diff --git a/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs b/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs index 1b7af883f8..caa03290db 100644 --- a/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs +++ b/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs @@ -2,12 +2,12 @@ use { crate::{ boundary::Result, domain::{ - eth, + self, liquidity::{self, balancer}, }, }, - ethrpc::alloy::conversions::IntoLegacy, - shared::sources::balancer_v2::pool_fetching::WeightedPoolVersion, + eth_domain_types as eth, + liquidity_sources::balancer_v2::pool_fetching::WeightedPoolVersion, solver::liquidity::{WeightedProductOrder, balancer_v2}, }; @@ -51,13 +51,13 @@ pub fn to_domain(id: liquidity::Id, pool: WeightedProductOrder) -> Result eth::ContractAddress { - pool.settlement_handling + (*pool + .settlement_handling .as_any() .downcast_ref::() .expect("downcast balancer settlement handler") - .vault() - .into_legacy() - .into() + .vault()) + .into() } fn pool_id(pool: &WeightedProductOrder) -> balancer::v2::Id { @@ -74,7 +74,7 @@ pub fn to_interaction( input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, -) -> eth::Interaction { +) -> domain::Interaction { super::to_interaction( &super::Pool { vault: pool.vault, diff --git a/crates/driver/src/boundary/liquidity/mod.rs b/crates/driver/src/boundary/liquidity/mod.rs index 90735260c1..ceb8ec56b7 100644 --- a/crates/driver/src/boundary/liquidity/mod.rs +++ b/crates/driver/src/boundary/liquidity/mod.rs @@ -1,20 +1,18 @@ use { crate::{ - domain::{eth, liquidity}, + domain::liquidity, infra::{self, blockchain::Ethereum}, }, anyhow::Result, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, + eth_domain_types as eth, + ethrpc::block_stream::CurrentBlockWatcher, futures::future, - model::TokenPair, - shared::{ - baseline_solver::BaseTokens, - http_client::HttpClientFactory, + http_client::HttpClientFactory, + liquidity_sources::{ + base_tokens::BaseTokens, recent_block_cache::{self, CacheConfig}, }, + model::TokenPair, solver::{ liquidity::Liquidity, liquidity_collector::{LiquidityCollecting, LiquidityCollector}, @@ -59,7 +57,7 @@ impl Fetcher { /// Creates a new fetcher for the specified configuration. pub async fn try_new(eth: &Ethereum, config: &infra::liquidity::Config) -> Result { let block_stream = eth.current_block(); - let block_retriever = Arc::new(eth.web3().alloy.clone()); + let block_retriever = Arc::new(eth.web3().provider.clone()); let uni_v2: Vec<_> = future::try_join_all( config @@ -103,12 +101,12 @@ impl Fetcher { .await?; let base_tokens = BaseTokens::new( - eth.contracts().weth().address().into_legacy(), + *eth.contracts().weth().address(), &config .base_tokens .iter() - .copied() - .map(eth::H160::from) + .cloned() + .map(Into::into) .collect::>(), ); @@ -131,11 +129,15 @@ impl Fetcher { pairs: &HashSet, block: infra::liquidity::AtBlock, ) -> Result> { + if pairs.is_empty() { + return Ok(vec![]); + } + let pairs = pairs .iter() .map(|pair| { let (a, b) = pair.get(); - TokenPair::new(a.0.0.into_alloy(), b.0.0.into_alloy()).expect("a != b") + TokenPair::new(*a, *b).expect("a != b") }) .collect(); diff --git a/crates/driver/src/boundary/liquidity/swapr.rs b/crates/driver/src/boundary/liquidity/swapr.rs index 843404d032..779ec79748 100644 --- a/crates/driver/src/boundary/liquidity/swapr.rs +++ b/crates/driver/src/boundary/liquidity/swapr.rs @@ -5,7 +5,7 @@ use { infra::{self, blockchain::Ethereum}, }, ethrpc::block_stream::CurrentBlockWatcher, - shared::sources::{swapr::SwaprPoolReader, uniswap_v2::pool_fetching::DefaultPoolReader}, + liquidity_sources::{swapr::SwaprPoolReader, uniswap_v2::pool_fetching::DefaultPoolReader}, solver::{liquidity::ConstantProductOrder, liquidity_collector::LiquidityCollecting}, }; diff --git a/crates/driver/src/boundary/liquidity/uniswap/v2.rs b/crates/driver/src/boundary/liquidity/uniswap/v2.rs index 12da65e9eb..70deaf9bcf 100644 --- a/crates/driver/src/boundary/liquidity/uniswap/v2.rs +++ b/crates/driver/src/boundary/liquidity/uniswap/v2.rs @@ -2,38 +2,28 @@ use { crate::{ boundary::{self, Result}, domain::{ - eth, + self, liquidity::{self, uniswap}, }, infra::{self, blockchain::Ethereum}, }, - async_trait::async_trait, - contracts::alloy::IUniswapLikeRouter, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, - shared::{ - http_solver::model::TokenAmount, - sources::uniswap_v2::{ - pair_provider::PairProvider, - pool_cache::PoolCache, - pool_fetching::{DefaultPoolReader, PoolFetcher, PoolReading}, - }, + contracts::IUniswapLikeRouter, + eth_domain_types as eth, + ethrpc::{Web3, block_stream::CurrentBlockWatcher}, + liquidity_sources::uniswap_v2::{ + pair_provider::PairProvider, + pool_cache::PoolCache, + pool_fetching::{DefaultPoolReader, PoolFetcher, PoolReading}, }, + shared::http_solver::model::TokenAmount, solver::{ - interactions::allowances::{AllowanceManaging, Allowances, Approval, ApprovalRequest}, liquidity::{ ConstantProductOrder, uniswap_v2::{self, UniswapLikeLiquidity}, }, liquidity_collector::LiquidityCollecting, }, - std::{ - collections::HashSet, - sync::{Arc, Mutex}, - }, + std::sync::Arc, }; /// Median gas used per UniswapInteraction (v2). @@ -60,7 +50,7 @@ pub fn router(pool: &ConstantProductOrder) -> eth::ContractAddress { .downcast_ref::() .expect("downcast uniswap settlement handler") .router(); - eth::ContractAddress::from(address.into_legacy()) + eth::ContractAddress::from(address) } pub(in crate::boundary::liquidity) fn to_domain_pool( @@ -75,15 +65,15 @@ pub(in crate::boundary::liquidity) fn to_domain_pool( ); Ok(liquidity::uniswap::v2::Pool { - address: pool.address.into(), + address: pool.address, router: router(&pool), reserves: liquidity::uniswap::v2::Reserves::try_new( eth::Asset { - token: pool.tokens.get().0.into_legacy().into(), + token: pool.tokens.get().0.into(), amount: pool.reserves.0.into(), }, eth::Asset { - token: pool.tokens.get().1.into_legacy().into(), + token: pool.tokens.get().1.into(), amount: pool.reserves.1.into(), }, ) @@ -96,23 +86,19 @@ pub fn to_interaction( input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, -) -> eth::Interaction { - let handler = uniswap_v2::Inner::new( - pool.router.0.into_alloy(), - receiver.0.into_alloy(), - Mutex::new(Allowances::empty(receiver.0)), - ); +) -> domain::Interaction { + let handler = uniswap_v2::Inner::new(*pool.router, *receiver); - let (_, interaction) = handler.settle( - TokenAmount::new(input.0.token.into(), input.0.amount), - TokenAmount::new(output.0.token.into(), output.0.amount), + let interaction = handler.settle( + TokenAmount::new(*input.0.token, input.0.amount), + TokenAmount::new(*output.0.token, output.0.amount), ); let (target, value, call_data) = interaction.encode_swap(); - eth::Interaction { - target: target.into_legacy().into(), - value: value.into_legacy().into(), + domain::Interaction { + target, + value: value.into(), call_data: call_data.0.to_vec().into(), } } @@ -136,13 +122,12 @@ where R: PoolReading + Send + Sync + 'static, F: FnOnce(Web3, PairProvider) -> R, { - let router = - IUniswapLikeRouter::Instance::new(config.router.0.into_alloy(), eth.web3().alloy.clone()); + let router = IUniswapLikeRouter::Instance::new(*config.router, eth.web3().provider.clone()); let settlement = eth.contracts().settlement().clone(); let pool_fetcher = { let factory = router.factory().call().await?; let pair_provider = PairProvider { - factory: factory.into_legacy(), + factory, init_code_digest: config.pool_code.into(), }; @@ -159,34 +144,9 @@ where )?) }; - Ok(Box::new(UniswapLikeLiquidity::with_allowances( + Ok(Box::new(UniswapLikeLiquidity::new( *router.address(), *settlement.address(), - Box::new(NoAllowanceManaging), pool_fetcher, ))) } - -/// An allowance manager that always reports no allowances. -struct NoAllowanceManaging; - -#[async_trait] -impl AllowanceManaging for NoAllowanceManaging { - async fn get_allowances( - &self, - _: HashSet, - spender: eth::H160, - ) -> Result { - Ok(Allowances::empty(spender)) - } - - async fn get_approvals(&self, requests: &[ApprovalRequest]) -> Result> { - Ok(requests - .iter() - .map(|request| Approval { - spender: request.spender, - token: request.token, - }) - .collect()) - } -} diff --git a/crates/driver/src/boundary/liquidity/uniswap/v3.rs b/crates/driver/src/boundary/liquidity/uniswap/v3.rs index 6c4b368e99..e0da5d4180 100644 --- a/crates/driver/src/boundary/liquidity/uniswap/v3.rs +++ b/crates/driver/src/boundary/liquidity/uniswap/v3.rs @@ -2,37 +2,35 @@ use { crate::{ boundary::{self, Result}, domain::{ - eth, + self, liquidity::{ self, uniswap::v3::{Fee, Liquidity, LiquidityNet, Pool, SqrtPrice, Tick}, }, }, - infra::{self, blockchain::Ethereum}, + infra::{self, blockchain::Ethereum, liquidity::config::UniswapV3PoolSource}, }, anyhow::Context, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::BlockRetrieving, + eth_domain_types as eth, + event_indexing::{ + block_retriever::BlockRetrieving, + maintenance::{Maintaining, ServiceMaintenance}, }, - shared::{ - http_solver::model::TokenAmount, - interaction::Interaction, - maintenance::ServiceMaintenance, - sources::uniswap_v3::pool_fetching::UniswapV3PoolFetcher, + liquidity_sources::uniswap_v3::{ + V3PoolDataSource, + graph_api::UniV3SubgraphClient, + pool_fetching::UniswapV3PoolFetcher, + pool_indexer::PoolIndexerClient, }, + shared::{http_solver::model::TokenAmount, interaction::Interaction}, solver::{ - interactions::allowances::Allowances, liquidity::{ ConcentratedLiquidity, uniswap_v3::{self, UniswapV3Liquidity, UniswapV3SettlementHandler}, }, liquidity_collector::{BackgroundInitLiquiditySource, LiquidityCollecting}, }, - std::{ - collections::BTreeMap, - sync::{Arc, Mutex}, - }, + std::{collections::BTreeMap, sync::Arc}, }; pub fn to_domain(id: liquidity::Id, pool: ConcentratedLiquidity) -> Result { @@ -51,15 +49,15 @@ pub fn to_domain(id: liquidity::Id, pool: ConcentratedLiquidity) -> Result eth::Interaction { - let handler = UniswapV3SettlementHandler::new( - pool.router.0.into_alloy(), - receiver.0.into_alloy(), - Mutex::new(Allowances::empty(receiver.0)), - pool.fee.0, - ); +) -> domain::Interaction { + let handler = UniswapV3SettlementHandler::new(*pool.router, *receiver, pool.fee.0); - let (_, interaction) = handler.settle( + let interaction = handler.settle( TokenAmount::new(input.0.token.into(), input.0.amount), TokenAmount::new(output.0.token.into(), output.0.amount), ); let encoded = interaction.encode(); - eth::Interaction { - target: eth::Address(encoded.0.into_legacy()), - value: eth::Ether(encoded.1.into_legacy()), - call_data: crate::util::Bytes(encoded.2.0.to_vec()), + domain::Interaction { + target: encoded.0, + value: encoded.1.into(), + call_data: encoded.2, } } @@ -129,28 +122,64 @@ async fn init_liquidity( config: &infra::liquidity::config::UniswapV3, ) -> anyhow::Result> { let web3 = eth.web3().clone(); + let source = build_pool_data_source(eth, config).await?; let pool_fetcher = Arc::new( UniswapV3PoolFetcher::new( - &config.graph_url, + source, web3.clone(), - boundary::liquidity::http_client(), block_retriever, config.max_pools_to_initialize, - config.max_pools_per_tick_query, ) .await .context("failed to initialise UniswapV3 liquidity")?, ); - let update_task = ServiceMaintenance::new(vec![pool_fetcher.clone()]) + // only run maintenance as long as someone is using the original pool_fetcher + let maintenance = Arc::downgrade(&(pool_fetcher.clone() as Arc)); + let update_task = ServiceMaintenance::new(vec![maintenance]) .run_maintenance_on_new_block(eth.current_block().clone()); tokio::task::spawn(update_task); Ok(UniswapV3Liquidity::new( - config.router.0.into_alloy(), + *config.router, *eth.contracts().settlement().address(), - web3, pool_fetcher, )) } + +/// Picks the V3 pool data source based on the configured pool source variant. +async fn build_pool_data_source( + eth: &Ethereum, + config: &infra::liquidity::config::UniswapV3, +) -> anyhow::Result> { + let http = boundary::liquidity::http_client(); + + match &config.pool_source { + UniswapV3PoolSource::PoolIndexer(indexer) => { + tracing::info!( + url = %indexer.url, + wait_until_timeout = ?indexer.wait_until_timeout, + "uniswap v3: using pool-indexer as data source", + ); + Ok(Arc::new(PoolIndexerClient::new( + indexer.url.clone(), + eth.chain(), + http, + indexer.wait_until_timeout, + ))) + } + UniswapV3PoolSource::Subgraph(subgraph) => { + tracing::info!(url = %subgraph.url, "uniswap v3: using subgraph as data source"); + Ok(Arc::new( + UniV3SubgraphClient::from_subgraph_url( + &subgraph.url, + http, + subgraph.max_pools_per_tick_query, + ) + .await + .context("failed to construct UniV3 subgraph client")?, + )) + } + } +} diff --git a/crates/driver/src/boundary/liquidity/zeroex.rs b/crates/driver/src/boundary/liquidity/zeroex.rs index fdd128885d..257ccaf2af 100644 --- a/crates/driver/src/boundary/liquidity/zeroex.rs +++ b/crates/driver/src/boundary/liquidity/zeroex.rs @@ -7,13 +7,10 @@ use { infra::{self, Ethereum}, }, anyhow::anyhow, - contracts::alloy::InstanceExt, ethrpc::block_stream::CurrentBlockWatcher, - shared::{ - http_client::HttpClientFactory, - price_estimation::gas::GAS_PER_ZEROEX_ORDER, - zeroex_api::DefaultZeroExApi, - }, + http_client::HttpClientFactory, + liquidity_sources::zeroex::DefaultZeroExApi, + price_estimation::gas::GAS_PER_ZEROEX_ORDER, solver::{ liquidity::{LimitOrder, zeroex::ZeroExLiquidity}, liquidity_collector::LiquidityCollecting, @@ -65,8 +62,10 @@ pub fn to_domain( let domain = zeroex::LimitOrder { order, fillable: Amounts { - maker: limit_order.sell_amount.as_u128(), - taker: limit_order.buy_amount.as_u128(), + maker: u128::try_from(limit_order.sell_amount) + .expect("value should be lower than u128::MAX"), + taker: u128::try_from(limit_order.buy_amount) + .expect("value should be lower than u128::MAX"), }, zeroex: handler.zeroex.clone(), }; @@ -86,9 +85,9 @@ pub async fn collector( let eth = eth.with_metric_label("zeroex".into()); let settlement = *eth.contracts().settlement().address(); let web3 = eth.web3().clone(); - let contract = contracts::alloy::IZeroex::Instance::deployed(&web3.alloy).await?; - let http_client_factory = &HttpClientFactory::new(&shared::http_client::Arguments { - http_timeout: config.http_timeout, + let contract = contracts::IZeroex::Instance::deployed(&web3.provider).await?; + let http_client_factory = &HttpClientFactory::new(&configs::http_client::HttpClient { + timeout: config.http_timeout, }); let api = Arc::new(DefaultZeroExApi::new( http_client_factory.builder(), @@ -97,6 +96,6 @@ pub async fn collector( blocks.clone(), )?); Ok(Box::new( - ZeroExLiquidity::new(web3, api, contract, settlement, blocks).await, + ZeroExLiquidity::new(api, contract, settlement, blocks).await, )) } diff --git a/crates/driver/src/boundary/mod.rs b/crates/driver/src/boundary/mod.rs index 0e220a985d..8ab03cafe3 100644 --- a/crates/driver/src/boundary/mod.rs +++ b/crates/driver/src/boundary/mod.rs @@ -32,33 +32,18 @@ pub use { anyhow::{Error, Result}, contracts, model::order::OrderData, - shared::ethrpc::Web3, + shared::web3::Web3, }; -/// Builds a web3 client that buffers requests and sends them in a -/// batch call. -pub fn buffered_web3_client( - ethrpc: &Url, - max_batch_size: usize, - max_concurrent_requests: usize, -) -> Web3 { - web3_client(ethrpc, max_batch_size, max_concurrent_requests) -} - /// Builds a web3 client that sends requests one by one. -pub fn unbuffered_web3_client(ethrpc: &Url) -> Web3 { - web3_client(ethrpc, 0, 0) -} - -fn web3_client(ethrpc: &Url, max_batch_size: usize, max_concurrent_requests: usize) -> Web3 { - let ethrpc_args = shared::ethrpc::Arguments { - ethrpc_max_batch_size: max_batch_size, - ethrpc_max_concurrent_requests: max_concurrent_requests, - ethrpc_batch_delay: Default::default(), - }; - let http_factory = - shared::http_client::HttpClientFactory::new(&shared::http_client::Arguments { - http_timeout: std::time::Duration::from_secs(10), - }); - shared::ethrpc::web3(ðrpc_args, &http_factory, ethrpc, "base") +pub fn unbuffered_web3(ethrpc: &Url) -> Web3 { + shared::web3::web3( + &shared::web3::Arguments { + ethrpc_max_batch_size: 0, + ethrpc_max_concurrent_requests: 0, + ethrpc_batch_delay: Default::default(), + }, + ethrpc, + "base", + ) } diff --git a/crates/driver/src/domain/blockchain.rs b/crates/driver/src/domain/blockchain.rs new file mode 100644 index 0000000000..36c33839e9 --- /dev/null +++ b/crates/driver/src/domain/blockchain.rs @@ -0,0 +1,83 @@ +use { + alloy::{ + primitives::{B256, Bytes}, + rpc::types::TransactionRequest, + }, + derive_more::derive::{From, Into}, + eth_domain_types::{AccessList, Address, BlockNo, Ether}, +}; + +/// A transaction ID, AKA transaction hash. +#[derive(Clone, Debug, From, Into)] +pub struct TxId(pub B256); + +pub enum TxStatus { + /// The transaction has been included and executed successfully. + Executed { block_number: BlockNo }, + /// The transaction has been included but execution failed. + Reverted { block_number: BlockNo }, + /// The transaction has not been included yet. + Pending, +} + +/// An onchain transaction. +#[derive(derive_more::Debug, Clone)] +pub struct Tx { + pub from: Address, + pub to: Address, + pub value: Ether, + pub input: Bytes, + #[debug(ignore)] + pub access_list: AccessList, +} + +impl From for TransactionRequest { + fn from(value: Tx) -> Self { + TransactionRequest::default() + .from(value.from) + .to(value.to) + .value(value.value.0) + .input(value.input.into()) + .access_list(value.access_list.into()) + } +} + +impl Tx { + pub fn set_access_list(self, access_list: AccessList) -> Self { + Self { + access_list, + ..self + } + } +} + +/// The Keccak-256 hash of a contract's initialization code. +/// +/// This value is meaningful in the context of the EVM `CREATE2` opcode in that +/// it influences the deterministic address that the contract ends up on. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct CodeDigest(pub B256); + +impl From for CodeDigest { + fn from(value: B256) -> Self { + Self(value) + } +} + +impl From for B256 { + fn from(value: CodeDigest) -> Self { + value.0 + } +} + +impl From<[u8; 32]> for CodeDigest { + fn from(value: [u8; 32]) -> Self { + Self(B256::from(value)) + } +} + +impl From for [u8; 32] { + fn from(value: CodeDigest) -> Self { + value.0.into() + } +} diff --git a/crates/driver/src/domain/competition/auction.rs b/crates/driver/src/domain/competition/auction.rs index f29fcbe4ad..57545181b2 100644 --- a/crates/driver/src/domain/competition/auction.rs +++ b/crates/driver/src/domain/competition/auction.rs @@ -2,13 +2,17 @@ use { crate::{ domain::{ competition::{self}, - eth, liquidity, time, }, infra::{Ethereum, blockchain, solver::Timeouts}, }, - std::collections::{HashMap, HashSet}, + alloy::primitives::U256, + eth_domain_types::{self as eth, GasPrice}, + std::{ + collections::{HashMap, HashSet}, + sync::Arc, + }, thiserror::Error, }; @@ -22,10 +26,10 @@ pub struct Auction { /// See the [`Self::orders`] method. pub(crate) orders: Vec, /// The tokens that are used in the orders of this auction. - pub(crate) tokens: Tokens, + pub(crate) tokens: Arc, pub(crate) gas_price: eth::GasPrice, pub(crate) deadline: chrono::DateTime, - pub(crate) surplus_capturing_jit_order_owners: HashSet, + pub(crate) surplus_capturing_jit_order_owners: Arc>, } impl Auction { @@ -56,13 +60,21 @@ impl Auction { true }); + let gas_est = eth.gas_price().await?; + let base_fee = eth.current_block().borrow().base_fee; + let gas_price = GasPrice::new( + U256::from(gas_est.max_fee_per_gas).into(), + U256::from(gas_est.max_priority_fee_per_gas).into(), + base_fee, + ); + Ok(Self { id, orders, - tokens, - gas_price: eth.gas_price(None).await?, + tokens: Arc::new(tokens), + gas_price, deadline, - surplus_capturing_jit_order_owners, + surplus_capturing_jit_order_owners: Arc::new(surplus_capturing_jit_order_owners), }) } @@ -111,7 +123,7 @@ impl Auction { .filter_map(|(address, token)| token.price.map(|price| (*address, price))) .chain(std::iter::once(( eth::ETH_TOKEN, - eth::U256::exp10(18).into(), + eth::U256::from(10).pow(eth::U256::from(18)).into(), ))) .collect() } @@ -171,16 +183,22 @@ impl Price { /// Converting 1 ETH expressed in `eth::TokenAmount` into `eth::Ether` /// /// ``` - /// use driver::domain::{competition::auction::Price, eth}; + /// use {driver::domain::competition::auction::Price, eth_domain_types as eth}; /// - /// let amount = eth::TokenAmount::from(eth::U256::exp10(18)); - /// let price = Price::try_new(eth::Ether::from(eth::U256::exp10(15))).unwrap(); // 0.001 ETH + /// let amount = eth::TokenAmount::from(eth::U256::from(10).pow(eth::U256::from(18))); + /// let price = Price::try_new(eth::Ether::from( + /// eth::U256::from(10).pow(eth::U256::from(15)), + /// )) + /// .unwrap(); // 0.001 ETH /// /// let eth = price.in_eth(amount); - /// assert_eq!(eth, eth::Ether::from(eth::U256::exp10(15))); + /// assert_eq!( + /// eth, + /// eth::Ether::from(eth::U256::from(10).pow(eth::U256::from(15))) + /// ); /// ``` pub fn in_eth(self, amount: eth::TokenAmount) -> eth::Ether { - (amount.0 * self.0.0 / Self::BASE).into() + (amount.0 * self.0.0 / eth::U256::from(Self::BASE)).into() } /// Convert an amount of ETH into a token amount using this price. @@ -189,11 +207,17 @@ impl Price { /// /// # Examples /// ``` - /// use driver::domain::{competition::auction::Price, eth}; + /// use {driver::domain::competition::auction::Price, eth_domain_types as eth}; /// - /// let amount = eth::Ether::from(eth::U256::exp10(18)); - /// let price = Price::try_new(eth::Ether::from(eth::U256::exp10(17))).unwrap(); // 0.1ETH - /// assert_eq!(price.from_eth(amount), eth::U256::exp10(19).into()); + /// let amount = eth::Ether::from(eth::U256::from(10).pow(eth::U256::from(18))); + /// let price = Price::try_new(eth::Ether::from( + /// eth::U256::from(10).pow(eth::U256::from(17)), + /// )) + /// .unwrap(); // 0.1ETH + /// assert_eq!( + /// price.from_eth(amount), + /// eth::U256::from(10).pow(eth::U256::from(19)).into() + /// ); /// ``` pub fn from_eth(self, amount: eth::Ether) -> eth::TokenAmount { (amount.0 * eth::U256::from(Self::BASE) / self.0.0).into() diff --git a/crates/driver/src/domain/competition/bad_tokens/metrics.rs b/crates/driver/src/domain/competition/bad_tokens/metrics.rs deleted file mode 100644 index a0444169b9..0000000000 --- a/crates/driver/src/domain/competition/bad_tokens/metrics.rs +++ /dev/null @@ -1,175 +0,0 @@ -use { - super::Quality, - crate::{ - domain::eth, - infra::{observe::metrics, solver}, - }, - dashmap::DashMap, - std::{ - sync::Arc, - time::{Duration, Instant}, - }, -}; - -#[derive(Default, Debug)] -struct TokenStatistics { - attempts: u32, - fails: u32, - flagged_unsupported_at: Option, -} - -/// Monitors tokens to determine whether they are considered "unsupported" based -/// on the ratio of failing to total settlement encoding attempts. A token must -/// have participated in at least `REQUIRED_MEASUREMENTS` attempts to be -/// evaluated. If, at that point, the ratio of failures is greater than or equal -/// to `FAILURE_RATIO`, the token is considered unsupported. -#[derive(Clone)] -pub struct Detector { - failure_ratio: f64, - required_measurements: u32, - counter: Arc>, - log_only: bool, - token_freeze_time: Duration, - solver: solver::Name, -} - -impl Detector { - pub fn new( - failure_ratio: f64, - required_measurements: u32, - log_only: bool, - token_freeze_time: Duration, - solver: solver::Name, - ) -> Self { - Self { - failure_ratio, - required_measurements, - counter: Default::default(), - log_only, - token_freeze_time, - solver, - } - } - - pub fn get_quality(&self, token: ð::TokenAddress, now: Instant) -> Quality { - let Some(stats) = self.counter.get(token) else { - return Quality::Unknown; - }; - - if stats - .flagged_unsupported_at - .is_some_and(|t| now.duration_since(t) > self.token_freeze_time) - { - // Sometimes tokens only cause issues temporarily. If the token's freeze - // period expired we pretend we don't have enough information to give it - // another chance. If it still behaves badly it will get frozen immediately. - return Quality::Unknown; - } - - match self.log_only { - true => Quality::Supported, - false => self.quality_based_on_stats(&stats), - } - } - - fn quality_based_on_stats(&self, stats: &TokenStatistics) -> Quality { - if stats.attempts < self.required_measurements { - return Quality::Unknown; - } - let token_failure_ratio = f64::from(stats.fails) / f64::from(stats.attempts); - match token_failure_ratio >= self.failure_ratio { - true => Quality::Unsupported, - false => Quality::Supported, - } - } - - /// Updates the tokens that participated in settlements by - /// incrementing their attempt count. - /// `failure` indicates whether the settlement was successful or not. - pub fn update_tokens( - &self, - token_pairs: &[(eth::TokenAddress, eth::TokenAddress)], - failure: bool, - ) { - let now = Instant::now(); - let mut new_unsupported_tokens = vec![]; - token_pairs - .iter() - .flat_map(|(token_a, token_b)| [token_a, token_b]) - .for_each(|token| { - let mut stats = self - .counter - .entry(*token) - .and_modify(|counter| { - counter.attempts += 1; - counter.fails += u32::from(failure); - }) - .or_insert_with(|| TokenStatistics { - attempts: 1, - fails: u32::from(failure), - flagged_unsupported_at: None, - }); - - // token needs to be frozen as unsupported for a while - if self.quality_based_on_stats(&stats) == Quality::Unsupported - && stats - .flagged_unsupported_at - .is_none_or(|t| now.duration_since(t) > self.token_freeze_time) - { - new_unsupported_tokens.push(token); - stats.flagged_unsupported_at = Some(now); - } - }); - - if !new_unsupported_tokens.is_empty() { - tracing::debug!( - tokens = ?new_unsupported_tokens, - "mark tokens as unsupported" - ); - metrics::get() - .bad_tokens_detected - .with_label_values(&[&self.solver.0, "metrics"]) - .inc_by(new_unsupported_tokens.len() as u64); - } - } -} - -#[cfg(test)] -mod tests { - use {super::*, ethcontract::H160}; - - /// Tests that a token only gets marked temporarily as unsupported. - /// After the freeze period it will be allowed again. - #[tokio::test] - async fn unfreeze_bad_tokens() { - const FREEZE_DURATION: Duration = Duration::from_millis(50); - let detector = Detector::new( - 0.5, - 2, - false, - FREEZE_DURATION, - solver::Name("mysolver".to_string()), - ); - - let token_a = eth::TokenAddress(eth::ContractAddress(H160([1; 20]))); - let token_b = eth::TokenAddress(eth::ContractAddress(H160([2; 20]))); - let token_quality = || detector.get_quality(&token_a, Instant::now()); - - // token is reported as unknown while we don't have enough measurements - assert_eq!(token_quality(), Quality::Unknown); - detector.update_tokens(&[(token_a, token_b)], true); - assert_eq!(token_quality(), Quality::Unknown); - detector.update_tokens(&[(token_a, token_b)], true); - - // after we got enough measurements the token gets marked as bad - assert_eq!(token_quality(), Quality::Unsupported); - - // after the freeze period is over the token gets reported as unknown again - tokio::time::sleep(FREEZE_DURATION).await; - assert_eq!(token_quality(), Quality::Unknown); - - // after an unfreeze another bad measurement is enough to freeze it again - detector.update_tokens(&[(token_a, token_b)], true); - assert_eq!(token_quality(), Quality::Unsupported); - } -} diff --git a/crates/driver/src/domain/competition/mod.rs b/crates/driver/src/domain/competition/mod.rs index d9cf51cbc9..34b45b4805 100644 --- a/crates/driver/src/domain/competition/mod.rs +++ b/crates/driver/src/domain/competition/mod.rs @@ -2,61 +2,262 @@ use { self::solution::settlement, super::{ Mempools, + mempools::SubmissionMode, time::{self, Remaining}, }, crate::{ domain::{ - competition::{solution::Settlement, sorting::SortingStrategy}, - eth, + competition::{ + pre_processing::DataFetchingTasks, + solution::Settlement, + sorting::SortingStrategy, + }, time::DeadlineExceeded, }, infra::{ self, - Simulator, blockchain::Ethereum, notify, observe::{self, metrics}, - simulator::{RevertError, SimulatorError}, - solver::{self, SolutionMerging, Solver}, + solver::{self, Account, SolutionMerging, Solver}, }, - util::{Bytes, math}, + util::math, }, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - futures::{StreamExt, future::Either, stream::FuturesUnordered}, + alloy::{network::TxSigner as _, primitives::Bytes}, + anyhow::Context as _, + axum::{body::Body, http::Request}, + eth_domain_types as eth, + futures::{FutureExt, StreamExt}, itertools::Itertools, - num::Zero, + simulator::{RevertError, Simulator, SimulatorError}, std::{ cmp::Reverse, collections::{HashMap, HashSet, VecDeque}, sync::{Arc, Mutex}, - time::{Duration, Instant}, - }, - tokio::{ - sync::{mpsc, oneshot}, - task, + time::Instant, }, + tokio::{sync::mpsc, task}, tracing::{Instrument, instrument}, }; pub mod auction; -pub mod bad_tokens; pub mod order; mod pre_processing; +pub mod risk_detector; pub mod solution; pub mod sorting; +use { + crate::infra::notify::liquidity_sources::LiquiditySourceNotifying, + eth_domain_types::BlockNo, + ethrpc::block_stream::BlockInfo, +}; pub use {auction::Auction, order::Order, pre_processing::DataAggregator, solution::Solution}; -use crate::{domain::BlockNo, infra::notify::liquidity_sources::LiquiditySourceNotifying}; - type BalanceGroup = (order::Trader, eth::TokenAddress, order::SellTokenBalance); type Balances = HashMap; +/// How many concurrent auction generations we size the settlement cache for. +/// Each auction can propose up to `max_solutions_to_propose` settlements; +/// keeping this many generations around lets a stale /settle for a previous +/// auction still find its settlement. +const MAX_CONCURRENT_AUCTIONS: usize = 5; + /// An ongoing competition. There is one competition going on per solver at any /// time. The competition stores settlements to solutions generated by the /// driver, and allows them to be executed onchain when requested later. The /// solutions expire after a certain amount of time, at which point trying to /// use them will return an `[Error::InvalidSolutionId]`. +/// Unified pool of submission slots. Contains one "direct" slot (solver EOA, +/// no forwarding overhead) and zero or more "delegated" slots (EIP-7702 +/// submission accounts). The direct slot is preferred; delegated slots are +/// used only when the solver EOA is already busy with an in-flight settlement. +#[derive(Debug)] +struct SubmitterPool { + /// 1-permit semaphore for the solver EOA (direct submission). + direct_slot: Arc, + /// EIP-7702 submission accounts. `None` in legacy single-EOA mode. + delegated: Option, + /// Limits total in-flight settle requests (including those waiting for a + /// pool slot). This replaces the old settle-queue-based admission check + /// and allows buffering requests beyond the number of physical slots. + admission: Arc, + solver_address: eth::Address, +} + +#[derive(Debug)] +struct DelegatedSlots { + release: mpsc::Sender, + acquire: tokio::sync::Mutex>, +} + +impl SubmitterPool { + fn new( + solver_address: eth::Address, + submission_accounts: Vec, + settle_queue_size: usize, + ) -> Self { + let num_delegated = submission_accounts.len(); + let delegated = if submission_accounts.is_empty() { + None + } else { + let (tx, rx) = mpsc::channel(submission_accounts.len()); + for account in submission_accounts { + tx.try_send(account) + .expect("channel has sufficient capacity"); + } + Some(DelegatedSlots { + release: tx, + acquire: tokio::sync::Mutex::new(rx), + }) + }; + let total_slots = 1 + num_delegated; + let admission_capacity = total_slots + settle_queue_size; + Self { + direct_slot: Arc::new(tokio::sync::Semaphore::new(1)), + delegated, + admission: Arc::new(tokio::sync::Semaphore::new(admission_capacity)), + solver_address, + } + } + + /// Acquire a submission slot. Prefers the direct solver EOA slot + /// (cheaper, no forwarding). Falls back to a delegated EIP-7702 account + /// when the direct slot is busy. Blocks if all slots are in use. + async fn acquire(&self) -> Option { + // Try the direct slot first (non-blocking). + if let Ok(permit) = Arc::clone(&self.direct_slot).try_acquire_owned() { + tracing::debug!("submitting directly from solver EOA"); + return Some(SubmitterGuard { + inner: GuardInner::Direct(permit), + solver_address: self.solver_address, + }); + } + + // Direct slot busy — race it against delegated accounts. select_ok + // ensures that if one future errors the other is still awaited. + let fetch_direct_slot = async { + let permit = Arc::clone(&self.direct_slot) + .acquire_owned() + .await + .context("semaphore closed")?; + tracing::debug!("submitting directly from solver EOA"); + Ok(GuardInner::Direct(permit)) + } + .boxed(); + + let fetch_eip7702_slot = async { + let Some(ref delegated) = self.delegated else { + return Err(anyhow::anyhow!("no EIP-7702 accounts configured")); + }; + let mut channel = delegated.acquire.lock().await; + let account = channel.recv().await.context("channel closed")?; + tracing::debug!(submitter = ?account.address(), "using EIP-7702 submission account"); + Ok(GuardInner::Delegated { + account, + release: delegated.release.clone(), + }) + } + .boxed(); + + let (inner, _remaining) = + futures::future::select_ok([fetch_direct_slot, fetch_eip7702_slot]) + .await + .inspect_err(|err| tracing::error!(?err, "could not acquire submission account")) + .ok()?; + + Some(SubmitterGuard { + inner, + solver_address: self.solver_address, + }) + } + + /// Try to reserve an admission permit without blocking. Returns `None` if + /// the maximum number of in-flight settle requests has been reached. + fn try_admit(&self) -> Option { + Arc::clone(&self.admission).try_acquire_owned().ok() + } +} + +/// RAII guard for a submission slot. Dropping returns the slot to the pool. +struct SubmitterGuard { + inner: GuardInner, + solver_address: eth::Address, +} + +enum GuardInner { + /// Solver EOA submits directly. Permit released on drop. + Direct(#[expect(dead_code)] tokio::sync::OwnedSemaphorePermit), + /// Delegated EIP-7702 submission. Account returned to channel on drop. + Delegated { + account: Account, + release: mpsc::Sender, + }, + /// Sentinel used during `Drop` to move data out of `self`. + Dropped, +} + +impl SubmitterGuard { + fn submission_mode(&self) -> SubmissionMode { + match &self.inner { + GuardInner::Direct(_) => SubmissionMode::Direct(self.solver_address), + GuardInner::Delegated { account, .. } => SubmissionMode::Delegated { + submitter_eoa: account.address(), + solver_eoa: self.solver_address, + }, + GuardInner::Dropped => unreachable!(), + } + } +} + +impl Drop for SubmitterGuard { + fn drop(&mut self) { + let inner = std::mem::replace(&mut self.inner, GuardInner::Dropped); + if let GuardInner::Delegated { account, release } = inner { + tokio::spawn(async move { + if release.send(account).await.is_err() { + tracing::error!("failed to return submission account to pool: channel closed"); + } + }); + } + // Direct: OwnedSemaphorePermit drops here, releasing the permit. + } +} + +/// Wrapper around a spawned settlement task's [`JoinHandle`]. When dropped +/// (e.g. because the HTTP handler was cancelled by the autopilot), the task is +/// aborted after a short grace period to allow cleanup (e.g. cancelling a +/// pending mempool tx). +struct SettleTaskHandle(task::JoinHandle>); + +impl std::future::Future for SettleTaskHandle { + type Output = Result; + + fn poll( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + std::pin::Pin::new(&mut self.0).poll(cx).map(|join_result| { + join_result.map_err(|err| { + tracing::error!(?err, "settle task panicked"); + Error::SubmissionError + })? + }) + } +} + +impl Drop for SettleTaskHandle { + fn drop(&mut self) { + if !self.0.is_finished() { + let handle = self.0.abort_handle(); + tokio::spawn(async move { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + handle.abort(); + }); + } + } +} + #[derive(Debug)] pub struct Competition { pub solver: Solver, @@ -67,10 +268,11 @@ pub struct Competition { pub mempools: Mempools, /// Cached solutions with the most recent solutions at the front. pub settlements: Mutex>, - pub bad_tokens: Arc, + /// bad token and orders detector + pub risk_detector: Arc, fetcher: Arc, - settle_queue: mpsc::Sender, order_sorting_strategies: Vec>, + submitter_pool: SubmitterPool, } impl Competition { @@ -82,13 +284,22 @@ impl Competition { liquidity_sources_notifier: infra::notify::liquidity_sources::Notifier, simulator: Simulator, mempools: Mempools, - bad_tokens: Arc, + risk_detector: Arc, fetcher: Arc, order_sorting_strategies: Vec>, ) -> Arc { - let (settle_sender, settle_receiver) = mpsc::channel(solver.settle_queue_size()); + let submission_accounts = solver.submission_accounts().to_vec(); + if !submission_accounts.is_empty() { + tracing::info!( + count = submission_accounts.len(), + "EIP-7702 parallel submission enabled" + ); + } + let settle_queue_size = solver.settle_queue_size(); + let submitter_pool = + SubmitterPool::new(solver.address(), submission_accounts, settle_queue_size); - let competition = Arc::new(Self { + Arc::new(Self { solver, eth, liquidity, @@ -96,87 +307,38 @@ impl Competition { simulator, mempools, settlements: Default::default(), - settle_queue: settle_sender, - bad_tokens, + risk_detector, fetcher, order_sorting_strategies, - }); - - let competition_clone = Arc::clone(&competition); - tokio::spawn(async move { - competition_clone - .process_settle_requests(settle_receiver) - .await; - }); - - competition + submitter_pool, + }) } /// Solve an auction as part of this competition. - pub async fn solve(&self, auction: Arc) -> Result, Error> { + pub async fn solve(&self, request: Request) -> Result, Error> { let start = Instant::now(); let timer = ::observe::metrics::metrics() .on_auction_overhead_start("driver", "pre_processing_total"); let tasks = self .fetcher - .start_or_get_tasks_for_auction(auction) + .start_or_get_tasks_for_auction(request) .await .map_err(|err| { tracing::error!(?err, "pre-processing auction failed"); Error::MalformedRequest })?; - let mut auction = Arc::unwrap_or_clone(tasks.auction.await); - - let settlement_contract = self.eth.contracts().settlement().address(); - let solver_address = self.solver.account().address(); - let order_sorting_strategies = self.order_sorting_strategies.clone(); - // Add the CoW AMM orders to the auction - let cow_amm_orders = tasks.cow_amm_orders.await; - auction.orders.extend(cow_amm_orders.iter().cloned()); + let auction = self.assemble_auction(&tasks).await; - let settlement = settlement_contract.into_legacy(); - let sort_orders_future = Self::run_blocking_with_timer("sort_orders", move || { - // Use spawn_blocking() because a lot of CPU bound computations are happening - // and we don't want to block the runtime for too long. - Self::sort_orders( - auction, - solver_address, - order_sorting_strategies, - settlement, - ) - }); - - // We can sort the orders and fetch auction data in parallel - let (auction, balances, app_data) = - tokio::join!(sort_orders_future, tasks.balances, tasks.app_data); - - let auction = Self::run_blocking_with_timer("update_orders", move || { - // Same as before with sort_orders, we use spawn_blocking() because a lot of CPU - // bound computations are happening and we want to avoid blocking - // the runtime. - Self::update_orders( - auction, - balances, - app_data, - cow_amm_orders, - ð::Address(settlement), - ) - }) + let liquidity = async { + match self.solver.liquidity() { + solver::Liquidity::Fetch => tasks.liquidity.await, + solver::Liquidity::Skip => Arc::new(Vec::new()), + } + } .await; - // We can run bad token filtering and liquidity fetching in parallel - let (liquidity, auction) = tokio::join!( - async { - match self.solver.liquidity() { - solver::Liquidity::Fetch => tasks.liquidity.await, - solver::Liquidity::Skip => Arc::new(Vec::new()), - } - }, - self.without_unsupported_orders(auction) - ); - let elapsed = start.elapsed(); metrics::get() .auction_preprocessing @@ -185,6 +347,11 @@ impl Competition { drop(timer); tracing::debug!(?elapsed, "auction task execution time"); + if auction.orders.is_empty() { + tracing::info!("no orders left after pre-processing; skipping solving"); + return Ok(vec![]); + } + let auction = &auction; // Fetch the solutions from the solver. @@ -231,14 +398,11 @@ impl Competition { SolutionMerging::Forbidden => solutions.collect(), }; - // Encode solutions into settlements (streamed). - let encoded = all_solutions - .into_iter() + let encoded = futures::stream::iter(all_solutions) .map(|solution| async move { - let id = solution.id().clone(); - let token_pairs = solution.token_pairs(); - observe::encoding(&id); + observe::encoding(solution.id()); let settlement = solution + .clone() .encode( auction, &self.eth, @@ -246,21 +410,36 @@ impl Competition { self.solver.solver_native_token(), ) .await; - (id, token_pairs, settlement) + (solution, settlement) }) - .collect::>() - .filter_map(|(id, token_pairs, result)| async move { + .buffer_unordered(self.solver.config().post_processing_concurrency_limit.get()) + .filter_map(|(solution, result)| async move { + let id = solution.id().clone(); + let orders: Vec<_> = solution + .user_trades() + .map(|trade| trade.order().uid) + .collect(); + let has_haircut = solution.has_haircut(); match result { - Ok(solution) => { - self.bad_tokens.encoding_succeeded(&token_pairs); - Some(solution) + Ok(encoded) => { + self.risk_detector.encoding_succeeded(&orders); + Some(encoded) } // don't report on errors coming from solution merging Err(_err) if id.solutions().len() > 1 => None, Err(err) => { - self.bad_tokens.encoding_failed(&token_pairs); - observe::encoding_failed(self.solver.name(), &id, &err); - notify::encoding_failed(&self.solver, auction.id(), &id, &err); + self.risk_detector.encoding_failed(&orders); + observe::encoding_failed( + self.solver.name(), + &id, + &err, + has_haircut, + &orders, + ); + // don't notify on errors for solutions with haircut + if !has_haircut { + notify::encoding_failed(&self.solver, auction.id(), &id, &err); + } None } } @@ -284,119 +463,192 @@ impl Competition { } // Score the settlements. - let scores = settlements + let scored: Vec<(Solved, Settlement)> = settlements .into_iter() - .map(|settlement| { + .filter_map(|settlement| { observe::scoring(&settlement); - ( - settlement.score( - &auction.native_prices(), - auction.surplus_capturing_jit_order_owners(), - ), - settlement, - ) - }) - .collect_vec(); - - // Filter out settlements which failed scoring. - let scores = scores - .into_iter() - .filter_map(|(result, settlement)| { - result - .inspect_err(|err| { - observe::scoring_failed(self.solver.name(), err); + let score = settlement.score( + &auction.native_prices(), + auction.surplus_capturing_jit_order_owners(), + ); + match score { + Ok(score) => { + observe::score(&settlement, &score); + Some((score, settlement)) + } + Err(err) => { + observe::scoring_failed(self.solver.name(), &err); notify::scoring_failed( &self.solver, auction.id(), settlement.solution(), - err, + &err, ); - }) - .ok() - .map(|score| (score, settlement)) + None + } + } }) - .collect_vec(); - - // Observe the scores. - for (score, settlement) in scores.iter() { - observe::score(settlement, score); - } - - // Pick the best-scoring settlement. - let (mut score, settlement) = scores - .into_iter() - .max_by_key(|(score, _)| score.to_owned()) + .sorted_by_key(|(score, _)| Reverse(*score)) .map(|(score, settlement)| { - ( - Solved { - id: settlement.solution().clone(), - score, - trades: settlement.orders(), - prices: settlement.prices(), - gas: Some(settlement.gas.estimate), - }, - settlement, - ) + let solved = Solved { + id: settlement.solution().clone(), + score, + trades: settlement.orders(), + prices: settlement.prices(), + gas: Some(settlement.gas.estimate), + }; + (solved, settlement) }) - .unzip(); + .collect(); - let Some(settlement) = settlement else { - // Don't wait for the deadline because we can't produce a solution anyway. - return Ok(score); - }; - let solution_id = settlement.solution().get(); + if scored.is_empty() { + return Ok(vec![]); + } + + let max_to_propose = self.solver.max_solutions_to_propose(); + let mut scored: Vec<(Solved, Settlement)> = + scored.into_iter().take(max_to_propose).collect(); + // Cache all settlements so they can be revealed/settled later. Keep + // solutions from previous overlapping auctions around long enough + // for their /settle to complete. { let mut lock = self.settlements.lock().unwrap(); - lock.push_front(settlement.clone()); - - /// Number of solutions that may be cached at most. - const MAX_SOLUTION_STORAGE: usize = 5; - lock.truncate(MAX_SOLUTION_STORAGE); + for (_, settlement) in &scored { + lock.push_front(settlement.clone()); + } + lock.truncate(max_to_propose * MAX_CONCURRENT_AUCTIONS); } - // Re-simulate the solution on every new block until the deadline ends to make - // sure we actually submit a working solution close to when the winner - // gets picked by the procotol. if let Ok(remaining) = deadline.remaining() { - let score_ref = &mut score; - let simulate_on_new_blocks = async move { - let mut stream = - ethrpc::block_stream::into_stream(self.eth.current_block().clone()); - while let Some(block) = stream.next().await { - if let Err(infra::simulator::Error::Revert(err)) = - self.simulate_settlement(&settlement).await - { - observe::winner_voided(block, &err); - *score_ref = None; - self.settlements - .lock() - .unwrap() - .retain(|s| s.solution().get() != solution_id); - notify::simulation_failed( - &self.solver, - auction.id(), - settlement.solution(), - &infra::simulator::Error::Revert(err), - true, - ); - return; - } - } - }; - let _ = tokio::time::timeout(remaining, simulate_on_new_blocks).await; + let _ = tokio::time::timeout( + remaining, + self.resimulate_until_revert(&mut scored, auction), + ) + .await; } - Ok(score) + Ok(scored.into_iter().map(|(solved, _)| solved).collect()) + } + + /// Re-simulate all proposed solutions on every new block and drop any + /// that start reverting. Returns once every solution has reverted; + /// otherwise runs forever and the caller must impose a deadline. + /// Mutates `scored` and the cached settlements in place. + async fn resimulate_until_revert( + &self, + scored: &mut Vec<(Solved, Settlement)>, + auction: &Auction, + ) -> anyhow::Result<()> { + let mut stream = ethrpc::block_stream::into_stream(self.eth.current_block().clone()); + while let Some(block) = stream.next().await { + let voided_ids: HashSet = + futures::future::join_all(scored.iter().map(|(solved, settlement)| { + self.reverts_on_block(block, solved, settlement, auction) + })) + .await + .into_iter() + .flatten() + .collect(); + + if voided_ids.is_empty() { + continue; + } + + scored.retain(|(solved, _)| !voided_ids.contains(&solved.id.get())); + let mut lock = self + .settlements + .lock() + .map_err(|_| anyhow::anyhow!("settlements mutex poisoned"))?; + lock.retain(|s| !voided_ids.contains(&s.solution().get())); + + if scored.is_empty() { + return Ok(()); + } + } + Ok(()) + } + + /// Re-simulate a single solution and return its id if it started + /// reverting on this block. Reports metrics and solver notifications as + /// a side effect. + async fn reverts_on_block( + &self, + block: BlockInfo, + solved: &Solved, + settlement: &Settlement, + auction: &Auction, + ) -> Option { + let err = match self.simulate_settlement(settlement).await { + Err(simulator::Error::Revert(err)) => err, + _ => return None, + }; + let has_haircut = settlement.has_haircut(); + observe::winner_voided(self.solver.name(), block, &err, has_haircut); + if !has_haircut { + notify::simulation_failed( + &self.solver, + auction.id(), + settlement.solution(), + &simulator::Error::Revert(err), + true, + ); + } + Some(solved.id.get()) + } + + async fn assemble_auction(&self, tasks: &DataFetchingTasks) -> Auction { + let (base_auction, cow_amm_orders) = + tokio::join!(tasks.auction.clone(), tasks.cow_amm_orders.clone()); + + let auction = Auction { + id: base_auction.id, + orders: base_auction + .orders + .iter() + .cloned() + .chain(cow_amm_orders.iter().cloned()) + .collect(), + tokens: base_auction.tokens.clone(), + gas_price: base_auction.gas_price, + deadline: base_auction.deadline, + surplus_capturing_jit_order_owners: base_auction + .surplus_capturing_jit_order_owners + .clone(), + }; + + let solver_address = self.solver.address(); + let order_sorting_strategies = self.order_sorting_strategies.clone(); + + let sort_orders_future = Self::run_blocking_with_timer("sort_orders", move || { + // Use spawn_blocking() because a lot of CPU bound computations are happening + // and we don't want to block the runtime for too long. + Self::sort_orders(auction, solver_address, order_sorting_strategies) + }); + + // We can sort the orders and fetch auction data in parallel + let (auction, balances, app_data) = tokio::join!( + sort_orders_future, + tasks.balances.clone(), + tasks.app_data.clone() + ); + + let auction = Self::run_blocking_with_timer("update_orders", move || { + // Same as before with sort_orders, we use spawn_blocking() because a lot of CPU + // bound computations are happening and we want to avoid blocking + // the runtime. + Self::update_orders(auction, balances, app_data, cow_amm_orders) + }) + .await; + self.without_unsupported_orders(auction).await } // Oders already need to be sorted from most relevant to least relevant so that // we allocate balances for the most relevants first. fn sort_orders( mut auction: Auction, - solver: eth::H160, + solver: eth::Address, order_sorting_strategies: Vec>, - _settlement_contract: eth::H160, ) -> Auction { sorting::sort_orders( &mut auction.orders, @@ -416,7 +668,6 @@ impl Competition { balances: Arc, app_data: Arc>>, cow_amm_orders: Arc>, - settlement_contract: ð::Address, ) -> Auction { // Clone balances since we only aggregate data once but each solver needs // to use and modify the data individually. @@ -444,13 +695,17 @@ impl Competition { // Update order app data if it was fetched. if let Some(fetched_app_data) = app_data.get(&order.app_data.hash()) { order.app_data = fetched_app_data.clone().into(); - if order.app_data.flashloan().is_some() { - // If an order requires a flashloan we assume all the necessary - // sell tokens will come from there. But the receiver must be the - // settlement contract because that is how the driver expects - // the flashloan to be repaid for now. - return order.receiver.as_ref() == Some(settlement_contract); - } + } + + // Flashloan orders get their sell tokens from the flashloan at + // settlement time, so skip the balance check. + if order.app_data.flashloan().is_some() { + return true; + } + + // wrappers can produce the required funds at settlement time + if !order.app_data.wrappers().is_empty() { + return true; } let remaining_balance = match balances.get_mut(&( @@ -495,13 +750,8 @@ impl Competition { // following: `available + (fee * available / sell) <= allocated_balance` if let order::Partial::Yes { available } = &mut order.partial { *available = order::TargetAmount( - math::mul_ratio( - available.0.into_alloy(), - allocated_balance.0.into_alloy(), - max_sell.0.into_alloy(), - ) - .unwrap_or_default() - .into_legacy(), + math::mul_ratio(available.0, allocated_balance.0, max_sell.0) + .unwrap_or_default(), ); } if order.available().is_zero() { @@ -567,102 +817,55 @@ impl Competition { /// Execute the solution generated as part of this competition. Use /// [`Competition::solve`] to generate the solution. pub async fn settle( - &self, + self: &Arc, auction_id: auction::Id, solution_id: u64, submission_deadline: BlockNo, ) -> Result { - let (response_sender, response_receiver) = oneshot::channel(); - - let request = SettleRequest { - auction_id, - solution_id, - submission_deadline, - response_sender, - tracing_span: tracing::Span::current(), - }; - - self.settle_queue.try_send(request).map_err(|err| { - tracing::warn!(?err, "Failed to enqueue /settle request"); + let admission_permit = self.submitter_pool.try_admit().ok_or_else(|| { + tracing::warn!("too many pending settlements; settle request rejected"); Error::TooManyPendingSettlements })?; - response_receiver.await.map_err(|err| { - tracing::error!(?err, "Failed to dequeue /settle response"); - Error::SubmissionError - })? + if self.eth.current_block().borrow().number >= submission_deadline.0 { + return Err(DeadlineExceeded.into()); + } + + let this = Arc::clone(self); + let tracing_span = tracing::Span::current(); + // Spawn as a separate task to enable concurrent EIP-7702 submissions. + // SettleTaskHandle aborts the task (with a grace period) if the caller + // disconnects. + let handle = tokio::spawn( + async move { + let result = this + .process_settle_request(auction_id, solution_id, submission_deadline) + .await; + observe::settled(this.solver.name(), &result); + drop(admission_permit); + result + } + .instrument(tracing_span), + ); + SettleTaskHandle(handle).await } pub fn ensure_settle_queue_capacity(&self) -> Result<(), Error> { - if self.settle_queue.capacity() == 0 { - tracing::warn!("settlement queue is full; auction is rejected"); + if self.submitter_pool.admission.available_permits() == 0 { + tracing::warn!("no idle submission slots; auction is rejected"); Err(Error::TooManyPendingSettlements) } else { Ok(()) } } - async fn process_settle_requests( - self: Arc, - mut settle_receiver: mpsc::Receiver, - ) { - while let Some(request) = settle_receiver.recv().await { - let SettleRequest { - auction_id, - solution_id, - submission_deadline, - mut response_sender, - tracing_span, - } = request; - async { - if self.eth.current_block().borrow().number >= submission_deadline { - if let Err(err) = response_sender.send(Err(DeadlineExceeded.into())) { - tracing::error!( - ?err, - "settle deadline exceeded. unable to return a response" - ); - } - return; - } - - observe::settling(); - let settle_fut = Box::pin(self.process_settle_request( - auction_id, - solution_id, - submission_deadline, - )); - let closed_fut = Box::pin(response_sender.closed()); - let result = match futures::future::select(closed_fut, settle_fut).await { - // Cancel the settlement task if the sender is closed (client likely - // disconnected). This is a fallback to recover from issues - // like a stuck driver (e.g., stalled block stream). - Either::Left((_closed, settle_fut)) => { - // Add a grace period to give driver the last chance to fetch the settlement - // tx. - tokio::time::timeout(Duration::from_secs(1), settle_fut) - .await - .unwrap_or_else(|_| Err(DeadlineExceeded.into())) - } - Either::Right((res, _)) => res, - }; - observe::settled(self.solver.name(), &result); - - if let Err(err) = response_sender.send(result) { - tracing::error!(?err, "Failed to send /settle response"); - } - } - .instrument(tracing_span) - .await - } - } - async fn process_settle_request( &self, auction_id: auction::Id, solution_id: u64, submission_deadline: BlockNo, ) -> Result { - let mut settlement = { + let settlement = { let mut lock = self.settlements.lock().unwrap(); let index = lock .iter() @@ -690,23 +893,23 @@ impl Competition { }); } - // When settling, the gas price must be carefully chosen to ensure the - // transaction is included in a block before the deadline. - let time_limit = submission_time_limit(&self.eth, submission_deadline); - // refresh gas price to be up-to-date - if let Ok(gas_price) = self.eth.gas_price(time_limit).await { - tracing::debug!( - ?time_limit, - ?gas_price, - "time limit used for refreshed gas price" - ); - settlement.gas.price = gas_price; - } + notify::settlement_started(&self.solver, settlement.auction_id, settlement.solution()); + + // Acquire a submission slot. The pool prefers the direct solver EOA + // (no forwarding overhead); falls back to a delegated EIP-7702 + // submission account when the solver EOA is busy. + let guard = self + .submitter_pool + .acquire() + .await + .ok_or(Error::SubmissionError)?; + let mode = guard.submission_mode(); let executed = self .mempools - .execute(&self.solver, &settlement, submission_deadline) + .execute(&settlement, submission_deadline, &mode) .await; + notify::executed( &self.solver, settlement.auction_id, @@ -741,14 +944,11 @@ impl Competition { } /// Returns whether the settlement can be executed or would revert. - async fn simulate_settlement( - &self, - settlement: &Settlement, - ) -> Result<(), infra::simulator::Error> { + async fn simulate_settlement(&self, settlement: &Settlement) -> Result<(), simulator::Error> { let tx = settlement.transaction(settlement::Internalization::Enable); - let gas_needed_for_tx = self.simulator.gas(tx).await?; + let gas_needed_for_tx = self.simulator.gas(tx.clone()).await?; if gas_needed_for_tx > settlement.gas.limit { - return Err(infra::simulator::Error::Revert(RevertError { + return Err(simulator::Error::Revert(RevertError { err: SimulatorError::GasExceeded(gas_needed_for_tx, settlement.gas.limit), tx: tx.clone(), block: self.eth.current_block().borrow().number.into(), @@ -762,7 +962,7 @@ impl Competition { if !self.solver.config().flashloans_enabled { auction.orders.retain(|o| o.app_data.flashloan().is_none()); } - self.bad_tokens + self.risk_detector .filter_unsupported_orders_in_auction(auction) .await } @@ -783,14 +983,9 @@ fn merge( for solution in solutions.take(MAX_SOLUTIONS_TO_MERGE) { let mut extension = vec![]; for already_merged in merged.iter() { - match solution.merge(already_merged, max_orders_per_merged_solution) { - Ok(merged) => { - observe::merged(&solution, already_merged, &merged); - extension.push(merged); - } - Err(err) => { - observe::not_merged(&solution, already_merged, err); - } + if let Ok(merged) = solution.merge(already_merged, max_orders_per_merged_solution) { + observe::merged(&solution, already_merged, &merged); + extension.push(merged); } } @@ -814,33 +1009,6 @@ fn merge( merged } -/// Returns the aimed time limit for bringing the solution onchain, based on the -/// submission deadline. -fn submission_time_limit(eth: &Ethereum, submission_deadline: BlockNo) -> Option { - let current_block = eth.current_block().borrow().number; - let blocks_until_deadline: u32 = (submission_deadline.checked_sub(current_block))? - .try_into() - .ok()?; - if blocks_until_deadline.is_zero() { - return None; - } - let time_limit = eth - .chain() - .block_time_in_ms() - .checked_mul(blocks_until_deadline)?; - // Using the above time limit, solutions are expected to be settled before the - // deadline. For safety, let's aim to settle the solution earlier (half that - // time): - time_limit.checked_div(2) -} -struct SettleRequest { - auction_id: auction::Id, - solution_id: u64, - submission_deadline: BlockNo, - response_sender: oneshot::Sender>, - tracing_span: tracing::Span, -} - /// Solution information sent to the protocol by the driver before the solution /// ranking happens. #[derive(Debug)] @@ -848,6 +1016,11 @@ pub struct Solved { pub id: solution::Id, pub score: eth::Ether, pub trades: HashMap, + /// Deprecated: uniform clearing prices are no longer consumed by the + /// autopilot. Still emitted on the `/solve` response so that autopilots + /// running the previous code can deserialise it during a rolling deploy. + /// Remove together with the response field once the new autopilot is + /// fully rolled out. pub prices: HashMap, pub gas: Option, } @@ -877,22 +1050,22 @@ pub struct PriceLimits { #[derive(Debug)] pub struct Revealed { /// The internalized calldata is the final calldata that appears onchain. - pub internalized_calldata: Bytes>, + pub internalized_calldata: Bytes, /// The uninternalized calldata must be known so that the CoW solver team /// can manually enforce certain rules which can not be enforced /// automatically. - pub uninternalized_calldata: Bytes>, + pub uninternalized_calldata: Bytes, } #[derive(Debug)] pub struct Settled { /// The transaction hash in which the solution was submitted. pub tx_hash: eth::TxId, - pub internalized_calldata: Bytes>, + pub internalized_calldata: Bytes, /// The uninternalized calldata must be known so that the CoW solver team /// can manually enforce certain rules which can not be enforced /// automatically. - pub uninternalized_calldata: Bytes>, + pub uninternalized_calldata: Bytes, } #[derive(Debug, thiserror::Error)] diff --git a/crates/driver/src/domain/competition/order/app_data.rs b/crates/driver/src/domain/competition/order/app_data.rs index 937eda7bf9..513bef8d8e 100644 --- a/crates/driver/src/domain/competition/order/app_data.rs +++ b/crates/driver/src/domain/competition/order/app_data.rs @@ -1,11 +1,11 @@ use { - crate::util::Bytes, + alloy::primitives::FixedBytes, anyhow::Context, app_data::AppDataDocument, derive_more::From, moka::future::Cache, reqwest::StatusCode, - std::{collections::HashMap, sync::Arc}, + std::{collections::HashMap, sync::Arc, time::Duration}, thiserror::Error, url::Url, }; @@ -34,7 +34,10 @@ struct Inner { impl AppDataRetriever { pub fn new(orderbook_url: Url, cache_size: u64) -> Self { Self(Arc::new(Inner { - client: reqwest::Client::new(), + client: reqwest::Client::builder() + .tcp_keepalive(Duration::from_secs(60)) + .build() + .expect("reqwest client built correctly"), base_url: orderbook_url, cache: Cache::new(cache_size), })) @@ -78,7 +81,8 @@ impl AppDataRetriever { true => None, // empty app data false => Some(Arc::new(app_data::ValidatedAppData { hash: app_data::AppDataHash(app_data.0.0), - protocol: app_data::parse(appdata.full_app_data.as_bytes())?, + protocol: app_data::parse(appdata.full_app_data.as_bytes()) + .context("invalid app data json")?, document: appdata.full_app_data, })), } @@ -154,7 +158,7 @@ pub const APP_DATA_LEN: usize = 32; /// While this type holds the hash, the data itself is uploaded to IPFS. This /// hash is signed along with the order. #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)] -pub struct AppDataHash(pub Bytes<[u8; APP_DATA_LEN]>); +pub struct AppDataHash(pub FixedBytes); impl From<[u8; APP_DATA_LEN]> for AppDataHash { fn from(inner: [u8; APP_DATA_LEN]) -> Self { diff --git a/crates/driver/src/domain/competition/order/mod.rs b/crates/driver/src/domain/competition/order/mod.rs index 8a53dff4ad..55eec87ff6 100644 --- a/crates/driver/src/domain/competition/order/mod.rs +++ b/crates/driver/src/domain/competition/order/mod.rs @@ -1,12 +1,14 @@ use { crate::{ - domain::eth, + domain, infra::{Ethereum, blockchain}, - util::{self, Bytes}, + util, }, + alloy::primitives::FixedBytes, derive_more::{From, Into}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + eth_domain_types as eth, model::order::{BuyTokenDestination, SellTokenSource}, + std::sync::Arc, }; pub use {fees::FeePolicy, signature::Signature}; @@ -14,9 +16,10 @@ pub mod app_data; pub mod fees; pub mod signature; -/// An order in the auction. -#[derive(Debug, Clone)] -pub struct Order { +/// The immutable, auction-independent data of an order. Wrapped in [`Arc`] so +/// that per-solver copies of [`Order`] share a single allocation. +#[derive(Debug)] +pub struct OrderData { pub uid: Uid, /// The user specified a custom address to receive the output of this order. pub receiver: Option, @@ -28,16 +31,14 @@ pub struct Order { pub sell: eth::Asset, pub side: Side, pub kind: Kind, - pub app_data: app_data::AppData, - pub partial: Partial, /// The onchain calls to run before sending user funds to the settlement /// contract. /// These are set by the user and included in the settlement transaction. - pub pre_interactions: Vec, + pub pre_interactions: Vec, /// The onchain calls to run after sending tokens from the settlement /// contract to the user. /// These are set by the user and included in the settlement transaction. - pub post_interactions: Vec, + pub post_interactions: Vec, pub sell_token_balance: SellTokenBalance, pub buy_token_balance: BuyTokenBalance, pub signature: Signature, @@ -49,6 +50,32 @@ pub struct Order { pub quote: Option, } +/// An order in the auction. +/// +/// Designed to be cheap to clone. Most of the data is immutable and is +/// reference counted. Solvers only get individual copies of data they +/// have need to update during the pre-processing phase. +#[derive(Debug, Clone)] +pub struct Order { + /// Immutable order data shared across all per-solver copies. + pub data: Arc, + /// Per-solver mutable as the data may only become available after + /// assembling the orders. + pub app_data: app_data::AppData, + /// Per-solver mutable as the driver may allocated different amounts of + /// the user's available balance based on the solver's order prioritization + /// logic. + pub partial: Partial, +} + +impl std::ops::Deref for Order { + type Target = OrderData; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + /// An amount denominated in the sell token of an [`Order`]. #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, From, Into)] pub struct SellAmount(pub eth::U256); @@ -150,23 +177,14 @@ impl Order { }; let target = self.target(); - amounts.sell.amount = util::math::mul_ratio( - amounts.sell.amount.0.into_alloy(), - available.0.into_alloy(), - target.0.into_alloy(), - ) - .unwrap_or_default() - .into_legacy() - .into(); - - amounts.buy.amount = util::math::mul_ratio_ceil( - amounts.buy.amount.0.into_alloy(), - available.0.into_alloy(), - target.0.into_alloy(), - ) - .unwrap_or_default() - .into_legacy() - .into(); + amounts.sell.amount = util::math::mul_ratio(amounts.sell.amount.0, available.0, target.0) + .unwrap_or_default() + .into(); + + amounts.buy.amount = + util::math::mul_ratio_ceil(amounts.buy.amount.0, available.0, target.0) + .unwrap_or_default() + .into(); amounts } @@ -209,7 +227,7 @@ pub const UID_LEN: usize = 56; /// UID of an order. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Uid(pub Bytes<[u8; UID_LEN]>); +pub struct Uid(pub FixedBytes); impl From<&solvers_dto::solution::OrderUid> for Uid { fn from(value: &solvers_dto::solution::OrderUid) -> Self { @@ -218,16 +236,32 @@ impl From<&solvers_dto::solution::OrderUid> for Uid { } impl Uid { + pub fn from_parts(order_hash: eth::B256, owner: eth::Address, valid_to: u32) -> Self { + let mut bytes = [0; UID_LEN]; + bytes[0..32].copy_from_slice(order_hash.as_slice()); + bytes[32..52].copy_from_slice(owner.as_slice()); + bytes[52..56].copy_from_slice(&valid_to.to_be_bytes()); + Self(FixedBytes(bytes)) + } + + /// Address that authorized the order. Sell tokens will be taken + /// from that address. pub fn owner(&self) -> eth::Address { - self.parts().1.into() + self.parts().1 + } + + /// Returns a UNIX timestamp after which the settlement + /// contract will not allow the order to be settled anymore. + pub fn valid_to(&self) -> u32 { + self.parts().2 } /// Splits an order UID into its parts. - fn parts(&self) -> (eth::H256, eth::H160, u32) { + fn parts(&self) -> (eth::B256, eth::Address, u32) { ( - eth::H256::from_slice(&self.0.0[0..32]), - eth::H160::from_slice(&self.0.0[32..52]), - u32::from_le_bytes(self.0.0[52..].try_into().unwrap()), + eth::B256::from_slice(&self.0.0[0..32]), + eth::Address::from_slice(&self.0.0[32..52]), + u32::from_be_bytes(self.0.0[52..].try_into().unwrap()), ) } } @@ -323,13 +357,13 @@ impl From for SellTokenBalance { impl SellTokenBalance { /// Returns the hash value for the specified source. - pub fn hash(&self) -> eth::H256 { + pub fn hash(&self) -> eth::B256 { let name = match self { Self::Erc20 => "erc20", Self::Internal => "internal", Self::External => "external", }; - eth::H256(web3::signing::keccak256(name.as_bytes())) + alloy::primitives::keccak256(name.as_bytes()) } } @@ -417,45 +451,51 @@ mod tests { #[test] fn order_scaling() { let sell = |amount: u64| eth::Asset { - token: eth::H160::from_low_u64_be(0x5e11).into(), + token: eth::Address::left_padding_from(0x5e11_u64.to_be_bytes().as_slice()).into(), amount: eth::U256::from(amount).into(), }; let buy = |amount: u64| eth::Asset { - token: eth::H160::from_low_u64_be(0xbbbb).into(), + token: eth::Address::left_padding_from(0xbbbb_u64.to_be_bytes().as_slice()).into(), amount: eth::U256::from(amount).into(), }; - let order = |sell_amount: u64, buy_amount: u64, available: Option| Order { - uid: Default::default(), - receiver: Default::default(), - created: util::Timestamp(100), - valid_to: util::Timestamp(u32::MAX), - buy: buy(buy_amount), - sell: sell(sell_amount), - side: match available { + let order = |sell_amount: u64, buy_amount: u64, available: Option| { + let side = match available { None => Side::Sell, Some(executed) if executed.token == sell(0).token => Side::Sell, Some(executed) if executed.token == buy(0).token => Side::Buy, _ => panic!(), - }, - kind: Kind::Limit, - app_data: Default::default(), - partial: available + }; + let partial = available .map(|available| Partial::Yes { available: available.amount.into(), }) - .unwrap_or(Partial::No), - pre_interactions: Default::default(), - post_interactions: Default::default(), - sell_token_balance: SellTokenBalance::Erc20, - buy_token_balance: BuyTokenBalance::Erc20, - signature: Signature { - scheme: signature::Scheme::PreSign, - data: Default::default(), - signer: Default::default(), - }, - protocol_fees: Default::default(), - quote: Default::default(), + .unwrap_or(Partial::No); + Order { + data: Arc::new(OrderData { + uid: Default::default(), + receiver: Default::default(), + created: util::Timestamp(100), + valid_to: util::Timestamp(u32::MAX), + buy: buy(buy_amount), + sell: sell(sell_amount), + side, + kind: Kind::Limit, + pre_interactions: Default::default(), + post_interactions: Default::default(), + sell_token_balance: SellTokenBalance::Erc20, + buy_token_balance: BuyTokenBalance::Erc20, + signature: Signature { + scheme: signature::Scheme::PreSign, + data: Default::default(), + signer: Default::default(), + }, + protocol_fees: Default::default(), + quote: Default::default(), + }), + app_data: Default::default(), + partial, + } }; assert_eq!( diff --git a/crates/driver/src/domain/competition/order/signature.rs b/crates/driver/src/domain/competition/order/signature.rs index 2964fdc8e3..cb50a19098 100644 --- a/crates/driver/src/domain/competition/order/signature.rs +++ b/crates/driver/src/domain/competition/order/signature.rs @@ -1,33 +1,35 @@ -use { - crate::{domain::eth, util::Bytes}, - model::signature::EcdsaSignature, -}; +use {alloy::primitives::Bytes, eth_domain_types as eth, model::signature::EcdsaSignature}; /// Signature over the order data. #[derive(Debug, Clone)] pub struct Signature { pub scheme: Scheme, - pub data: Bytes>, + pub data: Bytes, /// The address used to sign and place this order. pub signer: eth::Address, } impl Signature { - pub fn to_boundary_signature(&self) -> model::signature::Signature { + pub fn to_boundary_signature(&self) -> anyhow::Result { // TODO Different signing schemes imply different sizes of signature data, which // indicates that I'm missing an invariant in my types and I need to fix // that PreSign, for example, carries no data. Everything should be // reflected in the types! - match self.scheme { + Ok(match self.scheme { Scheme::Eip712 => model::signature::Signature::Eip712(EcdsaSignature::from_bytes( - self.data.0.as_slice().try_into().unwrap(), - )), + self.data + .as_array() + .ok_or_else(|| anyhow::anyhow!("ECDSA signature must be 65 bytes"))?, + )?), Scheme::EthSign => model::signature::Signature::EthSign(EcdsaSignature::from_bytes( - self.data.0.as_slice().try_into().unwrap(), - )), + self.data + .0 + .as_array() + .ok_or_else(|| anyhow::anyhow!("ECDSA signature must be 65 bytes"))?, + )?), Scheme::Eip1271 => model::signature::Signature::Eip1271(self.data.clone().into()), Scheme::PreSign => model::signature::Signature::PreSign, - } + }) } } diff --git a/crates/driver/src/domain/competition/pre_processing.rs b/crates/driver/src/domain/competition/pre_processing.rs index a49c5adfe9..c9bddca00c 100644 --- a/crates/driver/src/domain/competition/pre_processing.rs +++ b/crates/driver/src/domain/competition/pre_processing.rs @@ -4,15 +4,20 @@ use { domain::{ competition::order::{SellTokenBalance, app_data::AppData}, cow_amm, - eth, liquidity, }, infra::{self, api::routes::solve::dto::SolveRequest, observe::metrics, tokens}, - util::Bytes, }, + account_balances::{BalanceFetching, Query}, + alloy::primitives::{Bytes, FixedBytes}, anyhow::{Context, Result}, + axum::{ + body::{self, Body}, + http::Request, + }, + balance_overrides::BalanceOverrideRequest, chrono::Utc, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + eth_domain_types::{self as eth, Address, TokenAddress}, futures::{FutureExt, StreamExt, future::BoxFuture, stream::FuturesUnordered}, itertools::Itertools, model::{ @@ -20,14 +25,16 @@ use { order::{OrderKind, SellTokenSource}, signature::Signature, }, - shared::{ - account_balances::{BalanceFetching, Query}, - price_estimation::trade_verifier::balance_overrides::BalanceOverrideRequest, - signature_validator::SignatureValidating, + observe::tracing::lazy::Lazy, + signature_validator::SignatureValidating, + std::{ + collections::HashMap, + future::Future, + sync::Arc, + time::{Duration, Instant}, }, - std::{collections::HashMap, future::Future, sync::Arc, time::Duration}, tokio::sync::Mutex, - tracing::Instrument, + tracing::{Instrument, instrument}, }; type Shared = futures::future::Shared>; @@ -60,7 +67,7 @@ pub struct Utilities { liquidity_fetcher: infra::liquidity::Fetcher, tokens: tokens::Fetcher, balance_fetcher: Arc, - cow_amm_cache: cow_amm::Cache, + cow_amm_cache: Option, } impl std::fmt::Debug for Utilities { @@ -74,7 +81,7 @@ impl std::fmt::Debug for Utilities { #[derive(Debug)] struct ControlBlock { /// Auction for which the data aggregation task was spawned. - solve_request: Arc, + auction_id: i64, /// Data aggregation task. tasks: DataFetchingTasks, } @@ -91,26 +98,34 @@ impl DataAggregator { /// only once for all connected solvers to share. pub async fn start_or_get_tasks_for_auction( &self, - request: Arc, + request: Request, ) -> Result { let mut lock = self.control.lock().await; - let current_auction = &lock.solve_request; - - // The autopilot ensures that all drivers receive identical - // requests per auction. That means we can use the significantly - // cheaper string comparison instead of parsing the JSON to compare - // the auction ids. - if &request == current_auction { - let id = lock.tasks.auction.clone().await.id; - init_auction_id_in_span(id.map(|i| i.0)); + let current_auction = &lock.auction_id; + + // Figure out for which auction this `/solve` request was issued + // by looking at the `X-Auction-Id` header. + let request_auction_id: i64 = request + .headers() + .get("X-Auction-Id") + .context("request has no X-Auction-Id header")? + .to_str() + .context("X-Auction-Id header is not ASCII")? + .parse() + .context("could not parse X-Auction-Id header as i64")?; + + // Some other driver is already doing the pre-processing for this + // auction. Stop processing here and just await the existing task. + if request_auction_id == *current_auction { + init_auction_id_in_span(Some(request_auction_id)); tracing::debug!("await running data aggregation task"); return Ok(lock.tasks.clone()); } - let tasks = self.assemble_tasks(request.clone()).await?; + let tasks = self.assemble_tasks(request).await?; tracing::debug!("started new data aggregation task"); - lock.solve_request = request; + lock.auction_id = request_auction_id; lock.tasks = tasks.clone(); Ok(tasks) @@ -123,24 +138,24 @@ impl DataAggregator { tokens: tokens::Fetcher, balance_fetcher: Arc, ) -> Self { - let signature_validator = shared::signature_validator::validator( + let signature_validator = signature_validator::validator( eth.web3(), - shared::signature_validator::Contracts { + signature_validator::Contracts { settlement: eth.contracts().settlement().clone(), - vault_relayer: eth.contracts().vault_relayer().0, + vault_relayer: *eth.contracts().vault_relayer(), signatures: eth.contracts().signatures().clone(), }, - eth.balance_overrider(), + eth.state_overrider(), ); let cow_amm_helper_by_factory = eth .contracts() .cow_amm_helper_by_factory() .iter() - .map(|(factory, helper)| (factory.0.into_alloy(), helper.0.into_alloy())) + .map(|(factory, helper)| (Address::from(*factory), Address::from(*helper))) .collect(); let cow_amm_cache = - cow_amm::Cache::new(eth.web3().alloy.clone(), cow_amm_helper_by_factory); + cow_amm::Cache::new(eth.web3().provider.clone(), cow_amm_helper_by_factory); Self { utilities: Arc::new(Utilities { @@ -153,7 +168,7 @@ impl DataAggregator { cow_amm_cache, }), control: Mutex::new(ControlBlock { - solve_request: Default::default(), + auction_id: Default::default(), tasks: DataFetchingTasks { auction: futures::future::pending().boxed().shared(), balances: futures::future::pending().boxed().shared(), @@ -165,7 +180,7 @@ impl DataAggregator { } } - async fn assemble_tasks(&self, request: Arc) -> Result { + async fn assemble_tasks(&self, request: Request) -> Result { let auction = self.utilities.parse_request(request).await?; let balances = @@ -212,14 +227,20 @@ impl Utilities { /// Parses the JSON body of the `/solve` request during the unified /// auction pre-processing since eagerly deserializing these requests /// is surprisingly costly because their are so big. - async fn parse_request(&self, solve_request: Arc) -> Result> { + async fn parse_request(&self, solve_request: Request) -> Result> { + let solve_request = collect_request_body(solve_request).await?; + let auction_dto: SolveRequest = { let _timer = metrics::get().processing_stage_timer("parse_dto"); let _timer2 = observe::metrics::metrics().on_auction_overhead_start("driver", "parse_dto"); // deserialization takes tens of milliseconds so run it on a blocking task tokio::task::spawn_blocking(move || { - serde_json::from_str(&solve_request).context("could not parse solve request") + serde_json::from_slice(&solve_request) + .inspect_err(|err| { + tracing::warn!(?err, "failed to parse /solve request body"); + }) + .context("could not parse solve request") }) .await .context("failed to await blocking task")?? @@ -273,8 +294,8 @@ impl Utilities { && order.app_data.flashloan() == first.app_data.flashloan() }); Query { - owner: trader.0.0, - token: token.0.0, + owner: trader.0, + token: *token, source: match source { SellTokenBalance::Erc20 => SellTokenSource::Erc20, SellTokenBalance::Internal => SellTokenSource::Internal, @@ -285,9 +306,9 @@ impl Utilities { .pre_interactions .iter() .map(|i| InteractionData { - target: i.target.0.into_alloy(), - value: i.value.0.into_alloy(), - call_data: i.call_data.0.clone(), + target: i.target, + value: i.value.0, + call_data: i.call_data.0.to_vec(), }) .collect() } else { @@ -298,9 +319,9 @@ impl Utilities { .app_data .flashloan() .map(|loan| BalanceOverrideRequest { - token: loan.token.into_legacy(), - amount: loan.amount.into_legacy(), - holder: loan.receiver.into_legacy(), + token: loan.token, + amount: loan.amount, + holder: loan.receiver, }) } else { None @@ -318,7 +339,7 @@ impl Utilities { let balance = balance.ok()?; Some(( ( - order::Trader(query.owner.into()), + order::Trader(query.owner), query.token.into(), match query.source { SellTokenSource::Erc20 => SellTokenBalance::Erc20, @@ -390,12 +411,16 @@ impl Utilities { } async fn cow_amm_orders(self: Arc, auction: Arc) -> Arc> { + let Some(ref cow_amm_cache) = self.cow_amm_cache else { + // CoW AMMs are not configured, return empty vec + return Default::default(); + }; + let _timer = metrics::get().processing_stage_timer("cow_amm_orders"); let _timer2 = observe::metrics::metrics().on_auction_overhead_start("driver", "cow_amm_orders"); - let cow_amms = self - .cow_amm_cache + let cow_amms = cow_amm_cache .get_or_create_amms(&auction.surplus_capturing_jit_order_owners) .await; @@ -416,9 +441,9 @@ impl Utilities { .iter() .map(|t| { auction.tokens - .get(ð::TokenAddress(eth::ContractAddress(t.into_legacy()))) + .get(&TokenAddress::from(*t)) .and_then(|token| token.price) - .map(|price| price.0.0.into_alloy()) + .map(|price| price.0.0) }) .collect::>>()?; Some((amm, prices)) @@ -439,61 +464,21 @@ impl Utilities { let orders: Vec<_> = results .into_iter() .filter_map(|(amm, result)| match result { - Ok(template) => Some(Order { - uid: template - .order - .uid(&domain_separator, &amm.into_legacy()) - .0 - .into(), - receiver: template - .order - .receiver - .map(|addr| addr.into_legacy().into()), - created: u32::try_from(Utc::now().timestamp()) - .unwrap_or(u32::MIN) - .into(), - valid_to: template.order.valid_to.into(), - buy: eth::Asset { - amount: template.order.buy_amount.into_legacy().into(), - token: template.order.buy_token.into_legacy().into(), - }, - sell: eth::Asset { - amount: template.order.sell_amount.into_legacy().into(), - token: template.order.sell_token.into_legacy().into(), - }, - kind: order::Kind::Limit, - side: template.order.kind.into(), - app_data: order::app_data::AppDataHash(Bytes(template.order.app_data.0)).into(), - buy_token_balance: template.order.buy_token_balance.into(), - sell_token_balance: template.order.sell_token_balance.into(), - partial: match template.order.partially_fillable { + Ok(template) => { + let partial = match template.order.partially_fillable { true => order::Partial::Yes { available: match template.order.kind { - OrderKind::Sell => { - order::TargetAmount(template.order.sell_amount.into_legacy()) - } - OrderKind::Buy => { - order::TargetAmount(template.order.buy_amount.into_legacy()) - } + OrderKind::Sell => order::TargetAmount(template.order.sell_amount), + OrderKind::Buy => order::TargetAmount(template.order.buy_amount), }, }, false => order::Partial::No, - }, - pre_interactions: template - .pre_interactions - .into_iter() - .map(Into::into) - .collect(), - post_interactions: template - .post_interactions - .into_iter() - .map(Into::into) - .collect(), - signature: match template.signature { + }; + let signature = match template.signature { Signature::Eip1271(bytes) => order::Signature { scheme: order::signature::Scheme::Eip1271, - data: Bytes(bytes), - signer: amm.into_legacy().into(), + data: Bytes::from(bytes), + signer: amm, }, _ => { tracing::warn!( @@ -503,10 +488,48 @@ impl Utilities { ); return None; } - }, - protocol_fees: vec![], - quote: None, - }), + }; + Some(Order { + data: Arc::new(order::OrderData { + uid: template.order.uid(&domain_separator, amm).0.into(), + receiver: template.order.receiver, + created: u32::try_from(Utc::now().timestamp()) + .unwrap_or(u32::MIN) + .into(), + valid_to: template.order.valid_to.into(), + buy: eth::Asset { + amount: template.order.buy_amount.into(), + token: template.order.buy_token.into(), + }, + sell: eth::Asset { + amount: template.order.sell_amount.into(), + token: template.order.sell_token.into(), + }, + kind: order::Kind::Limit, + side: template.order.kind.into(), + buy_token_balance: template.order.buy_token_balance.into(), + sell_token_balance: template.order.sell_token_balance.into(), + pre_interactions: template + .pre_interactions + .into_iter() + .map(Into::into) + .collect(), + post_interactions: template + .post_interactions + .into_iter() + .map(Into::into) + .collect(), + signature, + protocol_fees: vec![], + quote: None, + }), + app_data: order::app_data::AppDataHash(FixedBytes( + template.order.app_data.0, + )) + .into(), + partial, + }) + } Err(err) => { tracing::warn!(?err, ?amm, "failed to generate template order for cow amm"); None @@ -515,6 +538,8 @@ impl Utilities { .collect(); if !orders.is_empty() { + tracing::trace!(?orders, "generated cow amm template orders (details)"); + let orders = Lazy(|| orders.iter().map(|o| o.uid).collect_vec()); tracing::debug!(?orders, "generated cow amm template orders"); } @@ -545,3 +570,19 @@ fn init_auction_id_in_span(id: Option) { debug_assert!(current_span.has_field("auction_id")); current_span.record("auction_id", id); } + +#[instrument(skip_all)] +async fn collect_request_body(request: Request) -> Result { + tracing::trace!("start streaming request body"); + let _timer = + observe::metrics::metrics().on_auction_overhead_start("driver", "stream_http_body"); + let start = Instant::now(); + + let body_bytes = axum::body::to_bytes(request.into_body(), usize::MAX) + .await + .context("failed to stream request body")?; + + let duration = start.elapsed(); + tracing::debug!(?duration, "finished streaming request body"); + Ok(body_bytes) +} diff --git a/crates/driver/src/domain/competition/risk_detector/bad_orders/metrics.rs b/crates/driver/src/domain/competition/risk_detector/bad_orders/metrics.rs new file mode 100644 index 0000000000..c85164383d --- /dev/null +++ b/crates/driver/src/domain/competition/risk_detector/bad_orders/metrics.rs @@ -0,0 +1,268 @@ +use { + crate::{ + domain::competition::{order::Uid, risk_detector::Quality}, + infra::{observe::metrics, solver}, + }, + dashmap::DashMap, + model::time::now_in_epoch_seconds, + std::{ + sync::{Arc, Weak}, + time::{Duration, Instant}, + }, +}; + +#[derive(Debug)] +struct OrderStatistics { + attempts: u32, + fails: u32, + flagged_unsupported_at: Option, + /// When an order was last seen in a solution. This + /// timestamp is used to determine whether the order's + /// metrics can be evicted from the cache to avoid bloat. + last_seen_at: Instant, +} + +/// Monitors orders to determine whether they are considered "unsupported" based +/// on the ratio of failing to total settlement encoding attempts. An order must +/// have participated in at least `REQUIRED_MEASUREMENTS` attempts to be +/// evaluated. If, at that point, the ratio of failures is greater than or equal +/// to `FAILURE_RATIO`, the order is considered unsupported. +#[derive(Clone)] +pub struct Detector { + failure_ratio: f64, + required_measurements: u32, + counter: Arc>, + log_only: bool, + order_freeze_time: Duration, + solver: solver::Name, +} + +impl Detector { + pub fn new( + failure_ratio: f64, + required_measurements: u32, + log_only: bool, + order_freeze_time: Duration, + gc_interval: Duration, + gc_max_age: Duration, + solver: solver::Name, + ) -> Self { + let counter = Arc::new(DashMap::default()); + + Self::spawn_gc_task(Arc::downgrade(&counter), gc_interval, gc_max_age); + + Self { + failure_ratio, + required_measurements, + counter: counter.clone(), + log_only, + order_freeze_time, + solver, + } + } + + pub fn get_quality(&self, order: &Uid, now: Instant) -> Quality { + let Some(stats) = self.counter.get(order) else { + return Quality::Unknown; + }; + + if stats + .flagged_unsupported_at + .is_some_and(|t| now.duration_since(t) > self.order_freeze_time) + { + // Sometimes tokens only cause issues temporarily. If the token's freeze + // period expired we pretend we don't have enough information to give it + // another chance. If it still behaves badly it will get frozen immediately. + return Quality::Unknown; + } + + match self.log_only { + true => Quality::Supported, + false => self.quality_based_on_stats(&stats), + } + } + + fn quality_based_on_stats(&self, stats: &OrderStatistics) -> Quality { + if stats.attempts < self.required_measurements { + return Quality::Unknown; + } + let token_failure_ratio = f64::from(stats.fails) / f64::from(stats.attempts); + match token_failure_ratio >= self.failure_ratio { + true => Quality::Unsupported, + false => Quality::Supported, + } + } + + /// Updates the orders that participated in settlements by + /// incrementing their attempt count. + /// `failure` indicates whether the settlement was successful or not. + pub fn update_orders(&self, orders: &[Uid], failure: bool) { + let now = Instant::now(); + let mut new_unsupported_orders = vec![]; + orders.iter().for_each(|order| { + let mut stats = self + .counter + .entry(*order) + .and_modify(|counter| { + counter.attempts += 1; + counter.fails += u32::from(failure); + counter.last_seen_at = now; + }) + .or_insert_with(|| OrderStatistics { + attempts: 1, + fails: u32::from(failure), + flagged_unsupported_at: None, + last_seen_at: now, + }); + + // order needs to be frozen as unsupported for a while + if self.quality_based_on_stats(&stats) == Quality::Unsupported + && stats + .flagged_unsupported_at + .is_none_or(|t| now.duration_since(t) > self.order_freeze_time) + { + new_unsupported_orders.push(order); + stats.flagged_unsupported_at = Some(now); + } + }); + + if !new_unsupported_orders.is_empty() { + tracing::debug!( + orders = ?new_unsupported_orders, + "mark order as unsupported" + ); + metrics::get() + .bad_orders_detected + .with_label_values(&[&self.solver.0]) + .inc_by(new_unsupported_orders.len() as u64); + } + } + + /// Spawns a background tasks that periodically evicts items from the cache + /// that are no longer relevant to avoid bloat. + fn spawn_gc_task( + cache: Weak>, + interval: Duration, + max_age: Duration, + ) { + tokio::task::spawn(async move { + let mut interval = tokio::time::interval(interval); + while let Some(cache) = cache.upgrade() { + let now = Instant::now(); + let now_as_unix = now_in_epoch_seconds(); + + cache.retain(|uid, stats| { + uid.valid_to() > now_as_unix && now.duration_since(stats.last_seen_at) < max_age + }); + interval.tick().await; + } + tracing::debug!("terminating gc task because cache was dropped"); + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Tests that an order only gets marked temporarily as unsupported. + /// After the freeze period it will be allowed again. + #[tokio::test] + async fn unfreeze_bad_orders() { + const FREEZE_DURATION: Duration = Duration::from_millis(50); + let detector = Detector::new( + 0.5, + 2, + false, + FREEZE_DURATION, + Duration::from_hours(1), + Duration::from_hours(1), + solver::Name("mysolver".to_string()), + ); + + let order = Uid::from_parts(Default::default(), Default::default(), u32::MAX); + let order_quality = || detector.get_quality(&order, Instant::now()); + + // order is reported as unknown while we don't have enough measurements + assert_eq!(order_quality(), Quality::Unknown); + detector.update_orders(&[order], true); + assert_eq!(order_quality(), Quality::Unknown); + detector.update_orders(&[order], true); + + // after we got enough measurements the order gets marked as bad + assert_eq!(order_quality(), Quality::Unsupported); + + // after the freeze period is over the token gets reported as unknown again + tokio::time::sleep(FREEZE_DURATION).await; + assert_eq!(order_quality(), Quality::Unknown); + + // after an unfreeze another bad measurement is enough to freeze it again + detector.update_orders(&[order], true); + assert_eq!(order_quality(), Quality::Unsupported); + } + + /// Tests that the GC task correctly evicts orders that are expired + /// or have not been seen for the configured amount of time. + #[tokio::test] + async fn evict_outdated_entries() { + const FREEZE_DURATION: Duration = Duration::from_millis(50); + const GC_INTERVAL: Duration = Duration::from_millis(10); + const GC_CYCLES_UNTIL_EVICTION: u32 = 5; + let gc_max_age = GC_INTERVAL * GC_CYCLES_UNTIL_EVICTION; + + // this spawns a gc task that evicts entries from the cache + let detector = Detector::new( + 0.5, + 2, + false, + FREEZE_DURATION, + GC_INTERVAL, + gc_max_age, + solver::Name("mysolver".to_string()), + ); + + let long_valid_to = now_in_epoch_seconds() + 1000; + let short_valid_to = 0; // already expired -> evict on first GC run + + let long_order = Uid::from_parts(Default::default(), Default::default(), long_valid_to); + let short_order = Uid::from_parts(Default::default(), Default::default(), short_valid_to); + + assert_eq!(detector.counter.len(), 0); + detector.update_orders(&[long_order, short_order], true); + assert_eq!(detector.counter.len(), 2); + assert!(detector.counter.get(&long_order).is_some()); + assert!(detector.counter.get(&short_order).is_some()); + + // The gc task and this test operate on an interval. In order to avoid + // issues due to variance we wait half a GC interval to make sure + // our assertions always happen in the middle between 2 GC runs. + tokio::time::sleep(GC_INTERVAL / 2).await; + let mut interval = tokio::time::interval(GC_INTERVAL); + + // after 1 GC cycle the expired order was evicted + assert_eq!(detector.counter.len(), 1); + assert!(detector.counter.get(&long_order).is_some()); + + for _ in 0..(GC_CYCLES_UNTIL_EVICTION - 1) { + interval.tick().await; + } + + // order was still not evicted because the max age has not been reached yet + assert_eq!(detector.counter.len(), 1); + assert!(detector.counter.get(&long_order).is_some()); + + // add another measurement to extend lifetime in cache + detector.update_orders(&[long_order], true); + + // metrics are still in the cache after almost max_age * 2 + for _ in 0..=(GC_CYCLES_UNTIL_EVICTION - 1) { + interval.tick().await; + } + assert_eq!(detector.counter.len(), 1); + assert!(detector.counter.get(&long_order).is_some()); + + // after one more GC cycle the order finally gets evicted + interval.tick().await; + assert_eq!(detector.counter.len(), 0); + } +} diff --git a/crates/driver/src/domain/competition/risk_detector/bad_orders/mod.rs b/crates/driver/src/domain/competition/risk_detector/bad_orders/mod.rs new file mode 100644 index 0000000000..88e26ca262 --- /dev/null +++ b/crates/driver/src/domain/competition/risk_detector/bad_orders/mod.rs @@ -0,0 +1,2 @@ +pub mod metrics; +pub use metrics::Detector; diff --git a/crates/driver/src/domain/competition/bad_tokens/cache.rs b/crates/driver/src/domain/competition/risk_detector/bad_tokens/cache.rs similarity index 96% rename from crates/driver/src/domain/competition/bad_tokens/cache.rs rename to crates/driver/src/domain/competition/risk_detector/bad_tokens/cache.rs index 7e8693154c..9bd9dd6418 100644 --- a/crates/driver/src/domain/competition/bad_tokens/cache.rs +++ b/crates/driver/src/domain/competition/risk_detector/bad_tokens/cache.rs @@ -1,6 +1,7 @@ use { - crate::domain::{competition::bad_tokens::Quality, eth}, + crate::domain::competition::risk_detector::Quality, dashmap::DashMap, + eth_domain_types as eth, std::{ sync::Arc, time::{Duration, Instant}, diff --git a/crates/driver/src/domain/competition/risk_detector/bad_tokens/mod.rs b/crates/driver/src/domain/competition/risk_detector/bad_tokens/mod.rs new file mode 100644 index 0000000000..664646340b --- /dev/null +++ b/crates/driver/src/domain/competition/risk_detector/bad_tokens/mod.rs @@ -0,0 +1,3 @@ +pub mod cache; +pub mod simulation; +pub use simulation::Detector; diff --git a/crates/driver/src/domain/competition/bad_tokens/simulation.rs b/crates/driver/src/domain/competition/risk_detector/bad_tokens/simulation.rs similarity index 79% rename from crates/driver/src/domain/competition/bad_tokens/simulation.rs rename to crates/driver/src/domain/competition/risk_detector/bad_tokens/simulation.rs index 174a37c409..a6018e6035 100644 --- a/crates/driver/src/domain/competition/bad_tokens/simulation.rs +++ b/crates/driver/src/domain/competition/risk_detector/bad_tokens/simulation.rs @@ -1,22 +1,13 @@ use { + super::cache::Cache, crate::{ - domain::{ - competition::{ - Order, - bad_tokens::{Quality, cache::Cache}, - order, - }, - eth, - }, + domain::competition::{Order, order, risk_detector::Quality}, infra::{self, observe::metrics}, }, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + bad_tokens::{TokenQuality, trace_call::TraceCallDetectorRaw}, futures::FutureExt, model::interaction::InteractionData, - shared::{ - bad_token::{TokenQuality, trace_call::TraceCallDetectorRaw}, - request_sharing::BoxRequestSharing, - }, + request_sharing::BoxRequestSharing, std::{ sync::Arc, time::{Duration, Instant}, @@ -38,10 +29,8 @@ struct Inner { impl Detector { pub fn new(max_age: Duration, eth: &infra::Ethereum) -> Self { - let detector = TraceCallDetectorRaw::new( - eth.web3().clone(), - eth.contracts().settlement().address().into_legacy(), - ); + let detector = + TraceCallDetectorRaw::new(eth.web3().clone(), *eth.contracts().settlement().address()); Self(Arc::new(Inner { cache: Cache::new(max_age), detector, @@ -74,12 +63,12 @@ impl Detector { .pre_interactions .iter() .map(|i| InteractionData { - target: i.target.0.into_alloy(), - value: i.value.0.into_alloy(), - call_data: i.call_data.0.clone(), + target: i.target, + value: i.value.0, + call_data: i.call_data.to_vec(), }) .collect(); - let trader = eth::Address::from(order.trader()).0; + let trader = order.trader().0; let sell_amount = match order.partial { order::Partial::Yes { available } => available.0, order::Partial::No => order.sell.amount.0, @@ -88,7 +77,7 @@ impl Detector { async move { let result = inner .detector - .test_transfer(trader, sell_token.0 .0, sell_amount, &pre_interactions) + .test_transfer(trader, *sell_token, sell_amount, &pre_interactions) .await; match result { Err(err) => { @@ -104,7 +93,7 @@ impl Detector { Ok(TokenQuality::Bad { reason }) => { tracing::debug!(reason, token=?sell_token.0, "cache token as unsupported"); // All solvers share the same cache for the simulation detector, so there is no need to specify the solver name here. - metrics::get().bad_tokens_detected.with_label_values(&["any", "simulation"]).inc(); + metrics::get().bad_tokens_detected.inc(); inner .cache .update_quality(sell_token, false, now); diff --git a/crates/driver/src/domain/competition/bad_tokens/mod.rs b/crates/driver/src/domain/competition/risk_detector/mod.rs similarity index 71% rename from crates/driver/src/domain/competition/bad_tokens/mod.rs rename to crates/driver/src/domain/competition/risk_detector/mod.rs index 947b41f2f7..357f0b6e04 100644 --- a/crates/driver/src/domain/competition/bad_tokens/mod.rs +++ b/crates/driver/src/domain/competition/risk_detector/mod.rs @@ -1,12 +1,29 @@ +//! This module implements logic to detect risky orders that +//! a solver is not able to support. The module supports +//! flagging individual tokens that are not supported outright. +//! A bad token could for example be one that forbids trading +//! with AMMs, only allows 1 transfer per transaction/block, or +//! was simply built with a buggy compiler which makes it incompatible +//! with the settlement contract (see ). +//! +//! Additionally there are some heuristics to detect when an +//! order itself is somehow broken or causes issues and slipped through +//! other detection mechanisms. One big error case is orders adjusting +//! debt postions in lending protocols. While pre-checks might correctly +//! detect that the EIP 1271 signature is valid the transfer of the token +//! would fail because the user's debt position is not collateralized enough. +//! In other words the bad order detection is a last fail safe in case +//! we were not able to predict issues with orders and pre-emptively +//! filter them out of the auction. use { - crate::domain::{competition::Auction, eth}, + crate::domain::competition::{Auction, order::Uid}, + eth_domain_types as eth, futures::{StreamExt, stream::FuturesUnordered}, std::{collections::HashMap, fmt, time::Instant}, }; -pub mod cache; -pub mod metrics; -pub mod simulation; +pub mod bad_orders; +pub mod bad_tokens; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Quality { @@ -33,8 +50,8 @@ pub struct Detector { /// tokens that get detected incorrectly by the automatic detectors get /// listed here and therefore have a higher precedence. hardcoded: HashMap, - simulation_detector: Option, - metrics: Option, + simulation_detector: Option, + metrics: Option, } impl Detector { @@ -49,13 +66,16 @@ impl Detector { /// Enables detection of unsupported tokens via simulation based detection /// methods. - pub fn with_simulation_detector(&mut self, detector: simulation::Detector) -> &mut Self { + pub fn with_simulation_detector( + &mut self, + detector: bad_tokens::simulation::Detector, + ) -> &mut Self { self.simulation_detector = Some(detector); self } /// Enables detection of unsupported tokens based on heuristics. - pub fn with_metrics_detector(&mut self, detector: metrics::Detector) -> &mut Self { + pub fn with_metrics_detector(&mut self, detector: bad_orders::metrics::Detector) -> &mut Self { self.metrics = Some(detector); self } @@ -71,6 +91,12 @@ impl Detector { let mut supported_orders: Vec<_> = supported_orders .into_iter() + .filter(|order| { + self.metrics + .as_ref() + .map(|metrics| metrics.get_quality(&order.uid, now)) + .is_none_or(|q| q != Quality::Unsupported) + }) .filter_map(|order| { let sell = self.get_token_quality(order.sell.token, now); let buy = self.get_token_quality(order.buy.token, now); @@ -123,16 +149,16 @@ impl Detector { } /// Updates the tokens quality metric for successful operation. - pub fn encoding_succeeded(&self, token_pairs: &[(eth::TokenAddress, eth::TokenAddress)]) { + pub fn encoding_succeeded(&self, orders: &[Uid]) { if let Some(metrics) = &self.metrics { - metrics.update_tokens(token_pairs, false); + metrics.update_orders(orders, false); } } /// Updates the tokens quality metric for failures. - pub fn encoding_failed(&self, token_pairs: &[(eth::TokenAddress, eth::TokenAddress)]) { + pub fn encoding_failed(&self, orders: &[Uid]) { if let Some(metrics) = &self.metrics { - metrics.update_tokens(token_pairs, true); + metrics.update_orders(orders, true); } } @@ -142,21 +168,10 @@ impl Detector { Some(quality) => return *quality, } - if let Some(Quality::Unsupported) = self - .simulation_detector + self.simulation_detector .as_ref() .map(|d| d.get_quality(&token, now)) - { - return Quality::Unsupported; - } - - if let Some(Quality::Unsupported) = - self.metrics.as_ref().map(|m| m.get_quality(&token, now)) - { - return Quality::Unsupported; - } - - Quality::Unknown + .unwrap_or(Quality::Unknown) } } diff --git a/crates/driver/src/domain/competition/solution/encoding.rs b/crates/driver/src/domain/competition/solution/encoding.rs index fb4357d02a..ea55b103af 100644 --- a/crates/driver/src/domain/competition/solution/encoding.rs +++ b/crates/driver/src/domain/competition/solution/encoding.rs @@ -2,22 +2,21 @@ use { super::{error::Math, interaction::Liquidity, settlement, slippage, trade::ClearingPrices}, crate::{ domain::{ + self, competition::{ self, order::{self, Partial}, }, - eth::{self, Ether, allowance}, liquidity, }, infra::{self, solver::ManageNativeToken}, - util::Bytes, }, allowance::Allowance, - alloy::sol_types::SolCall, - contracts::alloy::{FlashLoanRouter::LoanRequest, WETH9}, - ethcontract::H160, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + alloy::primitives::{Address, Bytes, FixedBytes, U256}, + contracts::{FlashLoanRouter::LoanRequest, WETH9}, + eth_domain_types::{self as eth, Ether, allowance}, itertools::Itertools, + num::Zero, }; #[derive(Debug, thiserror::Error)] @@ -53,7 +52,7 @@ pub fn tx( let mut interactions = Vec::with_capacity(approvals.size_hint().0 + solution.interactions().len()); let mut post_interactions = solution.post_interactions.clone(); - let mut native_unwrap = eth::TokenAmount(eth::U256::zero()); + let mut native_unwrap = eth::TokenAmount(eth::U256::ZERO); // Encode uniform clearing price vector for (token, amount) in solution @@ -61,8 +60,8 @@ pub fn tx( .into_iter() .sorted_by_cached_key(|(token, _amount)| *token) { - tokens.push(token.0.0.into_alloy()); - clearing_prices.push(amount.into_alloy()); + tokens.push(token.into()); + clearing_prices.push(amount); } // Encode trades with custom clearing prices @@ -98,12 +97,12 @@ pub fn tx( // indices are set below sell_token_index: Default::default(), buy_token_index: Default::default(), - receiver: trade.order().receiver.unwrap_or_default().into(), + receiver: trade.order().receiver.unwrap_or_default(), sell_amount: trade.order().sell.amount.into(), buy_amount: trade.order().buy.amount.into(), valid_to: trade.order().valid_to.into(), app_data: trade.order().app_data.hash().0.0.into(), - fee_amount: eth::U256::zero(), + fee_amount: eth::U256::ZERO, flags: Flags { side: trade.order().side, partially_fillable: matches!( @@ -136,12 +135,12 @@ pub fn tx( // indices are set below sell_token_index: Default::default(), buy_token_index: Default::default(), - receiver: trade.order().receiver.into(), + receiver: trade.order().receiver, sell_amount: trade.order().sell.amount.into(), buy_amount: trade.order().buy.amount.into(), valid_to: trade.order().valid_to.into(), app_data: trade.order().app_data.0.0.into(), - fee_amount: eth::U256::zero(), + fee_amount: eth::U256::ZERO, flags: Flags { side: trade.order().side, partially_fillable: matches!( @@ -158,13 +157,13 @@ pub fn tx( ) } }; - tokens.push(price.sell_token.into_alloy()); - tokens.push(price.buy_token.into_alloy()); - clearing_prices.push(price.sell_price.into_alloy()); - clearing_prices.push(price.buy_price.into_alloy()); + tokens.push(price.sell_token); + tokens.push(price.buy_token); + clearing_prices.push(price.sell_price); + clearing_prices.push(price.buy_price); - trade.sell_token_index = (tokens.len() - 2).into(); - trade.buy_token_index = (tokens.len() - 1).into(); + trade.sell_token_index = U256::from(tokens.len() - 2); + trade.buy_token_index = U256::from(tokens.len() - 1); trades.push(trade); } @@ -191,16 +190,14 @@ pub fn tx( } interactions.push(match interaction { - competition::solution::Interaction::Custom(interaction) => eth::Interaction { + competition::solution::Interaction::Custom(interaction) => domain::Interaction { value: interaction.value, target: interaction.target.into(), call_data: interaction.call_data.clone(), }, - competition::solution::Interaction::Liquidity(liquidity) => liquidity_interaction( - liquidity, - &slippage, - contracts.settlement().address().into_legacy(), - )?, + competition::solution::Interaction::Liquidity(liquidity) => { + liquidity_interaction(liquidity, &slippage, contracts.settlement().address())? + } }) } @@ -209,9 +206,6 @@ pub fn tx( interactions.push(unwrap(native_unwrap, contracts.weth())); } - let has_flashloans = !solution.flashloans.is_empty(); - let has_wrappers = !solution.wrappers.is_empty(); - // Encode the base settlement calldata let mut settle_calldata = contracts .settlement() @@ -230,25 +224,25 @@ pub fn tx( // Append auction ID to settlement calldata settle_calldata.extend(auction.id().ok_or(Error::MissingAuctionId)?.to_be_bytes()); + let has_flashloans = !solution.flashloans.is_empty(); + let has_wrappers = !solution.wrappers.is_empty(); let (to, calldata) = if has_flashloans && has_wrappers { return Err(Error::FlashloanWrappersIncompatible); } else if has_flashloans { encode_flashloan_settlement(solution, contracts, settle_calldata)? } else if has_wrappers { - encode_wrapper_settlement(solution, settle_calldata) + simulator::encoding::encode_wrapper_settlement(&solution.wrappers, settle_calldata.into()) + .expect("wrappers is not empty") } else { - ( - contracts.settlement().address().into_legacy().into(), - settle_calldata, - ) + (*contracts.settlement().address(), settle_calldata.into()) }; Ok(eth::Tx { from: solution.solver().address(), to, - input: calldata.into(), - value: Ether(0.into()), + input: calldata, + value: Ether::zero(), access_list: Default::default(), }) } @@ -263,7 +257,7 @@ fn encode_flashloan_settlement( solution: &super::Solution, contracts: &infra::blockchain::Contracts, settle_calldata: Vec, -) -> Result<(eth::Address, Vec), Error> { +) -> Result<(eth::Address, Bytes), Error> { // Get flashloan router contract let router = contracts .flashloan_router() @@ -274,10 +268,10 @@ fn encode_flashloan_settlement( .flashloans .values() .map(|flashloan| LoanRequest::Data { - amount: flashloan.amount.0.into_alloy(), - borrower: flashloan.protocol_adapter.0.into_alloy(), - lender: flashloan.liquidity_provider.0.into_alloy(), - token: flashloan.token.0.0.into_alloy(), + amount: flashloan.amount, + borrower: flashloan.protocol_adapter, + lender: flashloan.liquidity_provider, + token: flashloan.token, }) .collect(); @@ -287,87 +281,29 @@ fn encode_flashloan_settlement( .calldata() .to_vec(); - Ok((router.address().into_legacy().into(), calldata)) -} - -/// Encodes a settlement transaction that uses wrapper contracts. -/// -/// Takes the base settlement calldata and wraps it in a wrappedSettleCall -/// with encoded wrapper metadata. Since wrappers are a chain, the wrapper -/// address to call is also processed by this function. -/// -/// Returns (first_wrapper_address, wrapped_calldata) -fn encode_wrapper_settlement( - solution: &super::Solution, - settle_calldata: Vec, -) -> (eth::Address, Vec) { - // Encode wrapper metadata - let wrapper_data = encode_wrapper_data(&solution.wrappers); - - // Create wrappedSettleCall - let calldata = contracts::alloy::ICowWrapper::ICowWrapper::wrappedSettleCall { - settleData: settle_calldata.into(), - wrapperData: wrapper_data.into(), - } - .abi_encode(); - - (solution.wrappers[0].address, calldata) -} - -/// Encodes wrapper metadata for wrapper settlement calls. -/// -/// The format is: -/// - For wrappers after the first: 20 bytes (address) -/// - For each wrapper: 2 bytes (data length as u16 in native endian) + data -/// -/// More information about wrapper encoding: -/// https://www.notion.so/cownation/Generalized-Wrapper-2798da5f04ca8095a2d4c56b9d17134e?source=copy_link#2858da5f04ca807980bbf7f845354120 -/// -/// Note: The first wrapper address is omitted from the encoded data since it's -/// already used as the transaction target. -fn encode_wrapper_data(wrappers: &[super::WrapperCall]) -> Vec { - let mut wrapper_data = Vec::new(); - - for (index, w) in wrappers.iter().enumerate() { - // Skip first wrapper's address (it's the transaction target) - if index != 0 { - wrapper_data.extend(w.address.0.as_bytes()); - } - - // Encode data length as u16 in native endian, then the data itself - wrapper_data.extend((w.data.len() as u16).to_be_bytes().to_vec()); - wrapper_data.extend(w.data.clone()); - } - - wrapper_data + Ok((*router.address(), calldata.into())) } pub fn liquidity_interaction( liquidity: &Liquidity, slippage: &slippage::Parameters, - settlement_contract: H160, -) -> Result { + settlement_contract: &Address, +) -> Result { let (input, output) = slippage.apply_to(&slippage::Interaction { input: liquidity.input, output: liquidity.output, })?; match liquidity.liquidity.kind.clone() { - liquidity::Kind::UniswapV2(pool) => { - pool.swap(&input, &output, &settlement_contract.into()).ok() - } - liquidity::Kind::UniswapV3(pool) => { - pool.swap(&input, &output, &settlement_contract.into()).ok() - } + liquidity::Kind::UniswapV2(pool) => pool.swap(&input, &output, settlement_contract).ok(), + liquidity::Kind::UniswapV3(pool) => pool.swap(&input, &output, settlement_contract).ok(), liquidity::Kind::BalancerV2Stable(pool) => { - pool.swap(&input, &output, &settlement_contract.into()).ok() + pool.swap(&input, &output, settlement_contract).ok() } liquidity::Kind::BalancerV2Weighted(pool) => { - pool.swap(&input, &output, &settlement_contract.into()).ok() - } - liquidity::Kind::Swapr(pool) => { - pool.swap(&input, &output, &settlement_contract.into()).ok() + pool.swap(&input, &output, settlement_contract).ok() } + liquidity::Kind::Swapr(pool) => pool.swap(&input, &output, settlement_contract).ok(), liquidity::Kind::ZeroEx(limit_order) => limit_order.to_interaction(&input).ok(), } .ok_or(Error::InvalidInteractionExecution(Box::new( @@ -375,17 +311,17 @@ pub fn liquidity_interaction( ))) } -pub fn approve(allowance: &Allowance) -> eth::Interaction { +pub fn approve(allowance: &Allowance) -> domain::Interaction { let selector = hex_literal::hex!("095ea7b3"); let amount: [_; 32] = allowance.amount.to_be_bytes(); - eth::Interaction { + domain::Interaction { target: allowance.token.0.into(), - value: eth::U256::zero().into(), + value: Ether::zero(), // selector (4 bytes) + spender (20 byte address padded to 32 bytes) + amount (32 bytes) call_data: [ selector.as_slice(), [0; 12].as_slice(), - allowance.spender.0.as_bytes(), + allowance.spender.as_slice(), &amount, ] .concat() @@ -393,32 +329,32 @@ pub fn approve(allowance: &Allowance) -> eth::Interaction { } } -fn unwrap(amount: eth::TokenAmount, weth: &WETH9::Instance) -> eth::Interaction { - eth::Interaction { - target: weth.address().into_legacy().into(), - value: Ether(0.into()), - call_data: Bytes(weth.withdraw(amount.0.into_alloy()).calldata().to_vec()), +fn unwrap(amount: eth::TokenAmount, weth: &WETH9::Instance) -> domain::Interaction { + domain::Interaction { + target: *weth.address(), + value: Ether::zero(), + call_data: weth.withdraw(amount.0).calldata().to_vec().into(), } } struct Trade { sell_token_index: eth::U256, buy_token_index: eth::U256, - receiver: eth::H160, + receiver: eth::Address, sell_amount: eth::U256, buy_amount: eth::U256, valid_to: u32, - app_data: Bytes<[u8; 32]>, + app_data: FixedBytes<32>, fee_amount: eth::U256, flags: Flags, executed_amount: eth::U256, - signature: Bytes>, + signature: Bytes, } struct Price { - sell_token: eth::H160, + sell_token: eth::Address, sell_price: eth::U256, - buy_token: eth::H160, + buy_token: eth::Address, buy_price: eth::U256, } @@ -432,23 +368,24 @@ struct Flags { pub mod codec { use { - crate::domain::{competition::order, eth}, - contracts::alloy::GPv2Settlement, - ethrpc::alloy::conversions::IntoAlloy, + crate::domain::{self, competition::order}, + alloy::primitives::{Bytes, U256}, + contracts::GPv2Settlement, + eth_domain_types as eth, }; pub(super) fn trade(trade: &super::Trade) -> GPv2Settlement::GPv2Trade::Data { GPv2Settlement::GPv2Trade::Data { - sellTokenIndex: trade.sell_token_index.into_alloy(), - buyTokenIndex: trade.buy_token_index.into_alloy(), - receiver: trade.receiver.into_alloy(), - sellAmount: trade.sell_amount.into_alloy(), - buyAmount: trade.buy_amount.into_alloy(), + sellTokenIndex: trade.sell_token_index, + buyTokenIndex: trade.buy_token_index, + receiver: trade.receiver, + sellAmount: trade.sell_amount, + buyAmount: trade.buy_amount, validTo: trade.valid_to, appData: trade.app_data.0.into(), - feeAmount: trade.fee_amount.into_alloy(), - flags: flags(&trade.flags).into_alloy(), - executedAmount: trade.executed_amount.into_alloy(), + feeAmount: trade.fee_amount, + flags: flags(&trade.flags), + executedAmount: trade.executed_amount, signature: trade.signature.0.clone().into(), } } @@ -481,53 +418,50 @@ pub mod codec { order::signature::Scheme::Eip1271 => 0b10, order::signature::Scheme::PreSign => 0b11, } << 5; - result.into() + U256::from(result) } pub(super) fn interaction( - interaction: ð::Interaction, + interaction: &domain::Interaction, ) -> GPv2Settlement::GPv2Interaction::Data { GPv2Settlement::GPv2Interaction::Data { - target: interaction.target.0.into_alloy(), - value: interaction.value.0.into_alloy(), + target: interaction.target, + value: interaction.value.0, callData: interaction.call_data.0.clone().into(), } } - pub fn signature(signature: &order::Signature) -> super::Bytes> { + pub fn signature(signature: &order::Signature) -> Bytes { match signature.scheme { order::signature::Scheme::Eip712 | order::signature::Scheme::EthSign => { signature.data.clone() } - order::signature::Scheme::Eip1271 => { - super::Bytes([signature.signer.0.as_bytes(), signature.data.0.as_slice()].concat()) - } - order::signature::Scheme::PreSign => { - super::Bytes(signature.signer.0.as_bytes().to_vec()) - } + order::signature::Scheme::Eip1271 => [signature.signer.as_slice(), &signature.data] + .concat() + .into(), + order::signature::Scheme::PreSign => signature.signer.to_vec().into(), } } } #[cfg(test)] mod test { - use {super::*, hex_literal::hex}; + use {super::*, alloy::primitives::address, hex_literal::hex}; #[test] fn test_approve() { let allowance = Allowance { - token: eth::H160::from_slice(&hex!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")).into(), - spender: eth::H160::from_slice(&hex!("000000000022D473030F116dDEE9F6B43aC78BA3")) - .into(), + token: address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").into(), + spender: address!("000000000022D473030F116dDEE9F6B43aC78BA3"), amount: alloy::primitives::U256::MAX, }; let interaction = approve(&allowance); assert_eq!( interaction.target, - eth::H160::from_slice(&hex!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")).into(), + address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), ); assert_eq!( - interaction.call_data.0.as_slice(), + interaction.call_data.as_ref(), hex!( "095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ) diff --git a/crates/driver/src/domain/competition/solution/fee.rs b/crates/driver/src/domain/competition/solution/fee.rs index a6b4d0cdc2..b2cda84535 100644 --- a/crates/driver/src/domain/competition/solution/fee.rs +++ b/crates/driver/src/domain/competition/solution/fee.rs @@ -27,15 +27,13 @@ use { error::Math, trade::{ClearingPrices, Fee, Fulfillment}, }, - crate::domain::{ - competition::{ - PriceLimits, - order::{self, FeePolicy, Side}, - solution::error::Trade, - }, - eth::{self}, + crate::domain::competition::{ + PriceLimits, + order::{self, FeePolicy, Side}, + solution::error::Trade, }, bigdecimal::Zero, + eth_domain_types as eth, }; impl Fulfillment { @@ -84,7 +82,7 @@ impl Fulfillment { ), }; - Fulfillment::new(order, executed, fee).map_err(Into::into) + Fulfillment::new(order, executed, fee, self.haircut_fee()).map_err(Into::into) } /// Computed protocol fee in surplus token. @@ -312,19 +310,19 @@ pub enum Error { // todo: should be removed once integration tests are implemented #[cfg(test)] mod tests { - use super::*; + use {super::*, number::units::EthUnit}; #[test] fn test_adjust_quote_to_out_market_sell_order_limits() { let order = Order { - sell_amount: to_wei(20), - buy_amount: to_wei(19), + sell_amount: 20u64.eth(), + buy_amount: 19u64.eth(), side: Side::Sell, }; let quote = Quote { - sell_amount: to_wei(21), - buy_amount: to_wei(18), - fee_amount: to_wei(1), + sell_amount: 21u64.eth(), + buy_amount: 18u64.eth(), + fee_amount: 1u64.eth(), }; let limit = adjust_quote_to_order_limits(order.clone(), quote).unwrap(); @@ -334,7 +332,7 @@ mod tests { ); assert_eq!( limit.buy.0, - to_wei(19), + 19u64.eth(), "Buy amount should be equal to order buy amount for out of market orders" ); } @@ -342,14 +340,14 @@ mod tests { #[test] fn test_adjust_quote_to_out_market_buy_order_limits() { let order = Order { - sell_amount: to_wei(20), - buy_amount: to_wei(19), + sell_amount: 20u64.eth(), + buy_amount: 19u64.eth(), side: Side::Buy, }; let quote = Quote { - sell_amount: to_wei(21), - buy_amount: to_wei(18), - fee_amount: to_wei(1), + sell_amount: 21u64.eth(), + buy_amount: 18u64.eth(), + fee_amount: 1u64.eth(), }; let limit = adjust_quote_to_order_limits(order.clone(), quote).unwrap(); @@ -360,7 +358,7 @@ mod tests { ); assert_eq!( limit.sell.0, - to_wei(20), + 20u64.eth(), "Sell amount should be equal to order sell amount for out of market orders." ); } @@ -368,14 +366,14 @@ mod tests { #[test] fn test_adjust_quote_to_in_market_sell_order_limits() { let order = Order { - sell_amount: to_wei(10), - buy_amount: to_wei(10), + sell_amount: 10u64.eth(), + buy_amount: 10u64.eth(), side: Side::Sell, }; let quote = Quote { - sell_amount: to_wei(10), - buy_amount: to_wei(25), - fee_amount: to_wei(2), + sell_amount: 10u64.eth(), + buy_amount: 25u64.eth(), + fee_amount: 2u64.eth(), }; let limit = adjust_quote_to_order_limits(order.clone(), quote.clone()).unwrap(); @@ -386,7 +384,7 @@ mod tests { ); assert_eq!( limit.buy.0, - to_wei(20), + 20u64.eth(), "Buy amount should be equal to quoted buy amount but reduced by fee." ); } @@ -394,21 +392,21 @@ mod tests { #[test] fn test_adjust_quote_to_in_market_buy_order_limits() { let order = Order { - sell_amount: to_wei(20), - buy_amount: to_wei(10), + sell_amount: 20u64.eth(), + buy_amount: 10u64.eth(), side: Side::Buy, }; let quote = Quote { - sell_amount: to_wei(17), - buy_amount: to_wei(10), - fee_amount: to_wei(1), + sell_amount: 17u64.eth(), + buy_amount: 10u64.eth(), + fee_amount: 1u64.eth(), }; let limit = adjust_quote_to_order_limits(order.clone(), quote.clone()).unwrap(); assert_eq!( limit.sell.0, - to_wei(18), + 18u64.eth(), "Sell amount should match quoted buy amount increased by fee" ); assert_eq!( @@ -416,8 +414,4 @@ mod tests { "Buy amount should be taken from the order for buy orders in market price." ); } - - pub fn to_wei(base: u32) -> eth::U256 { - eth::U256::from(base) * eth::U256::exp10(18) - } } diff --git a/crates/driver/src/domain/competition/solution/interaction.rs b/crates/driver/src/domain/competition/solution/interaction.rs index b2b285f9af..50d48e4719 100644 --- a/crates/driver/src/domain/competition/solution/interaction.rs +++ b/crates/driver/src/domain/competition/solution/interaction.rs @@ -1,9 +1,7 @@ use { - crate::{ - domain::{self, eth, liquidity}, - util::Bytes, - }, - ethrpc::alloy::conversions::IntoLegacy, + crate::domain::{self, liquidity}, + alloy::primitives::Bytes, + eth_domain_types as eth, }; /// Interaction with a smart contract which is needed to execute this solution @@ -40,12 +38,12 @@ impl Interaction { Interaction::Custom(interaction) => interaction.allowances.clone(), Interaction::Liquidity(interaction) => { let address = match &interaction.liquidity.kind { - liquidity::Kind::UniswapV2(pool) => pool.router.into(), - liquidity::Kind::UniswapV3(pool) => pool.router.into(), - liquidity::Kind::BalancerV2Stable(pool) => pool.vault.into(), - liquidity::Kind::BalancerV2Weighted(pool) => pool.vault.into(), - liquidity::Kind::Swapr(pool) => pool.base.router.into(), - liquidity::Kind::ZeroEx(pool) => pool.zeroex.address().into_legacy(), + liquidity::Kind::UniswapV2(pool) => pool.router, + liquidity::Kind::UniswapV3(pool) => pool.router, + liquidity::Kind::BalancerV2Stable(pool) => pool.vault, + liquidity::Kind::BalancerV2Weighted(pool) => pool.vault, + liquidity::Kind::Swapr(pool) => pool.base.router, + liquidity::Kind::ZeroEx(pool) => (*pool.zeroex.address()).into(), }; // As a gas optimization, we always approve the max amount possible. This // minimizes the number of approvals necessary, and therefore @@ -70,7 +68,7 @@ impl Interaction { pub struct Custom { pub target: eth::ContractAddress, pub value: eth::Ether, - pub call_data: Bytes>, + pub call_data: Bytes, pub allowances: Vec, /// See the [`Interaction::inputs`] method. pub inputs: Vec, diff --git a/crates/driver/src/domain/competition/solution/mod.rs b/crates/driver/src/domain/competition/solution/mod.rs index 327dfcc808..f4e5ca731d 100644 --- a/crates/driver/src/domain/competition/solution/mod.rs +++ b/crates/driver/src/domain/competition/solution/mod.rs @@ -4,22 +4,25 @@ use { crate::{ boundary, domain::{ + self, competition::{self, order}, - eth::{self, Flashloan, TokenAddress}, }, infra::{ - Simulator, blockchain::{self, Ethereum}, config::file::FeeHandler, - simulator, solver::{ManageNativeToken, Solver}, }, }, + alloy::network::TxSigner, chrono::Utc, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + contracts::ERC20::ERC20, + eth_domain_types::{self as eth, TokenAddress}, futures::future::try_join_all, itertools::Itertools, num::{BigRational, One}, + number::conversions::{big_rational_to_u256, u256_to_big_int, u256_to_big_rational}, + simulator::{self, Simulator, encoding::WrapperCall}, + solvers_dto::solution::Flashloan, std::{ collections::{BTreeSet, HashMap, HashSet, hash_map::Entry}, sync::atomic::{AtomicU64, Ordering}, @@ -39,44 +42,58 @@ pub use {error::Error, interaction::Interaction, settlement::Settlement, trade:: type Prices = HashMap; -#[derive(Clone)] -pub struct WrapperCall { - pub address: eth::Address, - pub data: Vec, -} - // TODO Add a constructor and ensure that the clearing prices are included for // each trade /// A solution represents a set of orders which the solver has found an optimal /// way to settle. A [`Solution`] is generated by a solver as a response to a /// [`competition::Auction`]. See also [`settlement::Settlement`]. -#[derive(Clone)] +#[derive(derive_more::Debug, Clone)] pub struct Solution { id: Id, trades: Vec, prices: Prices, - pre_interactions: Vec, + #[debug(ignore)] + pre_interactions: Vec, + #[debug(ignore)] interactions: Vec, - post_interactions: Vec, + #[debug(ignore)] + post_interactions: Vec, + #[debug("{}", solver.name())] solver: Solver, - weth: eth::WethAddress, + #[debug(ignore)] + weth: eth::WrappedNativeToken, gas: Option, + gas_fee_override: Option, flashloans: HashMap, + #[debug(ignore)] wrappers: Vec, } +/// Gas fee overrides provided by the solver, used instead of the driver's +/// own gas price estimation during settlement submission. +/// +/// Note: the driver may raise these values above what the solver specified +/// if a pending replacement transaction requires a higher gas price (a node +/// requirement for transaction replacement). +#[derive(Clone, Copy, Debug)] +pub struct GasFeeOverride { + pub max_fee_per_gas: u128, + pub max_priority_fee_per_gas: u128, +} + impl Solution { #[expect(clippy::too_many_arguments)] pub fn new( id: Id, mut trades: Vec, prices: Prices, - pre_interactions: Vec, + pre_interactions: Vec, interactions: Vec, - post_interactions: Vec, + post_interactions: Vec, solver: Solver, - weth: eth::WethAddress, + weth: eth::WrappedNativeToken, gas: Option, + gas_fee_override: Option, fee_handler: FeeHandler, surplus_capturing_jit_order_owners: &HashSet, flashloans: HashMap, @@ -95,28 +112,33 @@ impl Solution { *trade = Trade::Fulfillment( Fulfillment::new( competition::Order { - uid: jit.order().uid, - kind: order::Kind::Limit, - side: jit.order().side, - sell: jit.order().sell, - buy: jit.order().buy, - signature: jit.order().signature.clone(), - receiver: Some(jit.order().receiver), - created: u32::try_from(Utc::now().timestamp()) - .unwrap_or(u32::MIN) - .into(), - valid_to: jit.order().valid_to, + data: std::sync::Arc::new(order::OrderData { + uid: jit.order().uid, + kind: order::Kind::Limit, + side: jit.order().side, + sell: jit.order().sell, + buy: jit.order().buy, + signature: jit.order().signature.clone(), + receiver: Some(jit.order().receiver), + created: u32::try_from(Utc::now().timestamp()) + .unwrap_or(u32::MIN) + .into(), + valid_to: jit.order().valid_to, + pre_interactions: vec![], + post_interactions: vec![], + sell_token_balance: jit.order().sell_token_balance, + buy_token_balance: jit.order().buy_token_balance, + protocol_fees: vec![], + quote: None, + }), app_data: jit.order().app_data.into(), partial: jit.order().partially_fillable(), - pre_interactions: vec![], - post_interactions: vec![], - sell_token_balance: jit.order().sell_token_balance, - buy_token_balance: jit.order().buy_token_balance, - protocol_fees: vec![], - quote: None, }, jit.executed(), Fee::Dynamic(jit.fee()), + // JIT orders don't get haircut because they supply private + // liquidity which should not prone to negative slippage. + eth::U256::ZERO, ) .map_err(error::Solution::InvalidJitTrade)?, ); @@ -136,6 +158,7 @@ impl Solution { solver, weth, gas, + gas_fee_override, flashloans, wrappers, }; @@ -204,11 +227,11 @@ impl Solution { &self.interactions } - pub fn pre_interactions(&self) -> &[eth::Interaction] { + pub fn pre_interactions(&self) -> &[domain::Interaction] { &self.pre_interactions } - pub fn post_interactions(&self) -> &[eth::Interaction] { + pub fn post_interactions(&self) -> &[domain::Interaction] { &self.post_interactions } @@ -221,6 +244,10 @@ impl Solution { self.gas } + pub fn gas_fee_override(&self) -> Option { + self.gas_fee_override + } + fn trade_count_for_scorable( &self, trade: &Trade, @@ -274,27 +301,52 @@ impl Solution { } /// Approval interactions necessary for encoding the settlement. + /// To support tokens like USDT which first need to have their allowance + /// set to 0 before it can be set to the desired value we simulate each + /// `approve()` call and inject additional `approve(0)` interactions when + /// we encounter a revert. + /// Whenever the needed allowance is less the current allowance no + /// `approve()` interactions get encoded to save on gas. + /// See pub async fn approvals( &self, eth: &Ethereum, internalization: settlement::Internalization, ) -> Result + use<>, Error> { - let settlement_contract = ð.contracts().settlement(); + let settlement_contract = *eth.contracts().settlement().address(); let allowances = try_join_all(self.allowances(internalization).map(|required| async move { - eth.erc20(required.0.token) - .allowance( - settlement_contract.address().into_legacy().into(), - required.0.spender, - ) + let erc20_token = ERC20::new(required.0.token.into(), ð.web3().provider); + + let current_allowance = erc20_token + .allowance(settlement_contract, required.0.spender) + .call() + .await?; + + // if the current allowance is sufficient we can skip that interaction + if current_allowance >= required.0.amount { + return Ok::<_, blockchain::Error>(vec![]); + } + + let regular_approval_succeeds = erc20_token + .approve(required.0.spender, required.0.amount) + .from(settlement_contract) + .call() .await - .map(|existing| (required, existing)) + .is_ok(); + + let approval = eth::allowance::Approval(required.0); + if regular_approval_succeeds { + Ok(vec![approval]) + } else { + // setting the desired approval reverts so we assume we are + // dealing with a USDT-like token that needs to have the + // approval reset to 0 first + Ok(vec![approval.revoke(), approval]) + } })) .await?; - let approvals = allowances - .into_iter() - .filter_map(|(required, existing)| required.approval(&existing)); - Ok(approvals) + Ok(allowances.into_iter().flatten()) } /// An empty solution has no trades which is allowed to capture surplus and @@ -342,10 +394,8 @@ impl Solution { // Scale prices let mut prices = self.prices.clone(); for (token, price) in other.prices.iter() { - let scaled = number::conversions::big_rational_to_u256( - &(number::conversions::u256_to_big_rational(price) * &factor), - ) - .map_err(error::Merge::Math)?; + let scaled = big_rational_to_u256(&(u256_to_big_rational(price) * &factor)) + .map_err(error::Merge::Math)?; match prices.entry(*token) { Entry::Occupied(entry) => { // This shouldn't fail unless there are rounding errors given that the scaling @@ -391,6 +441,8 @@ impl Solution { (None, Some(gas)) => Some(gas), (None, None) => None, }, + // Gas fee overrides are per-solution; no meaningful way to merge them. + gas_fee_override: None, flashloans, wrappers: self.wrappers.clone(), }) @@ -398,7 +450,7 @@ impl Solution { /// Return the trades which fulfill non-liquidity auction orders. These are /// the orders placed by end users. - fn user_trades(&self) -> impl Iterator { + pub fn user_trades(&self) -> impl Iterator { self.trades.iter().filter_map(|trade| match trade { Trade::Fulfillment(fulfillment) => Some(fulfillment), Trade::Jit(_) => None, @@ -425,8 +477,8 @@ impl Solution { for allowance in allowances { let amount = normalized .entry((allowance.0.token, allowance.0.spender)) - .or_insert(eth::U256::zero()); - *amount = amount.saturating_add(allowance.0.amount.into_legacy()); + .or_insert(eth::U256::ZERO); + *amount = amount.saturating_add(allowance.0.amount); } normalized .into_iter() @@ -434,7 +486,7 @@ impl Solution { eth::Allowance { token, spender, - amount: amount.into_alloy(), + amount, } .into() }) @@ -474,18 +526,18 @@ impl Solution { // price is needed. Remove the unneeded WETH price, which slightly reduces // gas used by the settlement. let mut prices: Prices = if self.user_trades().all(|trade| { - trade.order().sell.token != self.weth.0 && trade.order().buy.token != self.weth.0 + trade.order().sell.token != *self.weth && trade.order().buy.token != *self.weth }) { prices .into_iter() - .filter(|(token, _price)| *token != self.weth.0) + .filter(|(token, _price)| *token != *self.weth) .collect() } else { prices }; // Add a clearing price for ETH equal to WETH. - prices.insert(eth::ETH_TOKEN, self.prices[&self.weth.into()].to_owned()); + prices.insert(eth::ETH_TOKEN, self.prices[&self.weth].to_owned()); return prices; } @@ -514,21 +566,15 @@ impl Solution { ) }) } -} -impl std::fmt::Debug for Solution { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("Solution") - .field("id", &self.id) - .field("trades", &self.trades) - .field("prices", &self.prices) - .field("pre_interactions", &self.pre_interactions) - .field("interactions", &self.interactions) - .field("post_interactions", &self.post_interactions) - .field("solver", &self.solver.name()) - .field("gas", &self.gas) - .field("flashloans", &self.flashloans) - .finish() + /// Returns true if any trade in this solution has a non-zero haircut fee. + /// Used to determine if simulation failures should suppress solver + /// notifications. + pub fn has_haircut(&self) -> bool { + self.trades.iter().any(|trade| match trade { + Trade::Fulfillment(fulfillment) => !fulfillment.haircut_fee().is_zero(), + Trade::Jit(_) => false, // JIT orders don't have haircut + }) } } @@ -547,8 +593,8 @@ fn scaling_factor(first: &Prices, second: &Prices) -> Option { let first_price = first[token]; let second_price = second[token]; BigRational::new( - number::conversions::u256_to_big_int(&first_price), - number::conversions::u256_to_big_int(&second_price), + u256_to_big_int(&first_price), + u256_to_big_int(&second_price), ) }) .collect(); diff --git a/crates/driver/src/domain/competition/solution/scoring.rs b/crates/driver/src/domain/competition/solution/scoring.rs index 8191411624..5980a734c5 100644 --- a/crates/driver/src/domain/competition/solution/scoring.rs +++ b/crates/driver/src/domain/competition/solution/scoring.rs @@ -12,21 +12,18 @@ use { order::{self, Side}, trade::CustomClearingPrices, }, - crate::{ - domain::{ - competition::{ - PriceLimits, - auction, - order::FeePolicy, - solution::{ - error, - fee::{self, adjust_quote_to_order_limits}, - }, - }, - eth, + crate::domain::competition::{ + PriceLimits, + auction, + order::FeePolicy, + solution::{ + error, + fee::{self, adjust_quote_to_order_limits}, }, - util::conv::u256::U256Ext, }, + alloy::primitives::ruint::UintTryFrom, + eth_domain_types as eth, + number::u256_ext::U256Ext, }; pub fn compute_score( @@ -108,11 +105,11 @@ impl Trade { // to avoid loss of precision because we work with integers we first multiply // and then divide: // buy_amount = surplus * buy_price / sell_price - let surplus_in_buy_tokens: eth::U256 = surplus_in_surplus_token - .full_mul(self.signed_buy.amount.0) - .checked_div(self.signed_sell.amount.0.into()) - .ok_or(Error::Math(Math::DivisionByZero))? - .try_into() + let surplus_in_buy_tokens = surplus_in_surplus_token + .widening_mul(self.signed_buy.amount.0) + .checked_div(alloy::primitives::U512::from(self.signed_sell.amount.0)) + .ok_or(Error::Math(Math::DivisionByZero))?; + let surplus_in_buy_tokens = eth::U256::uint_try_from(surplus_in_buy_tokens) .map_err(|_| Error::Math(Math::Overflow))?; // Afterwards we convert the buy token surplus to the native token. @@ -296,7 +293,7 @@ impl Trade { // negative surplus is not error in this case, as solutions often have no // improvement over quote which results in negative surplus if let Err(Math::Negative) = surplus { - return Ok(eth::SurplusTokenAmount(0.into())); + return Ok(eth::SurplusTokenAmount(eth::U256::ZERO)); } Ok(surplus?) } @@ -400,48 +397,53 @@ pub enum Error { #[cfg(test)] mod tests { - use {super::*, auction::Price, shared::addr, std::collections::HashMap}; + use { + super::*, + alloy::primitives::{Address, U256, address}, + auction::Price, + std::collections::HashMap, + }; /// Tests that the new score computation limits the score of certain /// buy orders to a reasonable amount. - /// Data is based on this + /// NOTE(historical): Data is based on this /// [auction](https://api.cow.fi/base/api/v1/solver_competition/by_tx_hash/0xe3ef02493255f17c0abd2ff88c34682d35f0de4f4875a4653104e3453473d8d9). #[test] fn score_problematic_buy_order() { - let weth = addr!("4200000000000000000000000000000000000006"); - let bnkr = addr!("22af33fe49fd1fa80c7149773dde5890d3c76f3b"); + const WETH: Address = address!("4200000000000000000000000000000000000006"); + const BNKR: Address = address!("22af33fe49fd1fa80c7149773dde5890d3c76f3b"); // Buy order which results in an unreasonably high score // using the original scoring mechanism. let trade = Trade { signed_sell: eth::Asset { - token: weth.into(), + token: WETH.into(), amount: 9865986634773384514560000000000000u128.into(), }, signed_buy: eth::Asset { - token: bnkr.into(), + token: BNKR.into(), amount: 4025333872768468868566822740u128.into(), }, side: Side::Buy, - executed: order::TargetAmount(8050667745u128.into()), + executed: order::TargetAmount(U256::from(8050667745u128)), custom_price: CustomClearingPrices { - sell: 874045870u128.into(), - buy: 8050667745u128.into(), + sell: U256::from(874045870u128), + buy: U256::from(8050667745u128), }, policies: vec![], }; let native_prices: HashMap<_, _> = [ ( - weth.into(), - Price(eth::Ether(1000000000000000000u128.into())), + WETH.into(), + Price(eth::Ether(U256::from(1000000000000000000u128))), ), - (bnkr.into(), Price(eth::Ether(113181296327u128.into()))), + (BNKR.into(), Price(eth::Ether(U256::from(113181296327u128)))), ] .into_iter() .collect(); let score = trade.score(&native_prices).unwrap(); - assert_eq!(score.0, 911.into()); + assert_eq!(score.0, U256::from(911)); } } diff --git a/crates/driver/src/domain/competition/solution/settlement.rs b/crates/driver/src/domain/competition/solution/settlement.rs index 9c8358b5ff..047221e799 100644 --- a/crates/driver/src/domain/competition/solution/settlement.rs +++ b/crates/driver/src/domain/competition/solution/settlement.rs @@ -1,18 +1,26 @@ use { - super::{Error, Solution, encoding, trade::ClearingPrices}, + super::{ + Error, + Solution, + encoding, + trade::{self, ClearingPrices}, + }, crate::{ domain::{ + self, competition::{ self, auction, order::{self}, solution::{self, Interaction, Trade, error}, }, - eth, }, - infra::{Simulator, blockchain::Ethereum, observe, solver::ManageNativeToken}, + infra::{blockchain::Ethereum, solver::ManageNativeToken}, }, - futures::future::try_join_all, + alloy::primitives::U256, + eth_domain_types as eth, + futures::{FutureExt, future::try_join_all}, + simulator::{self, Simulator}, std::collections::{BTreeSet, HashMap, HashSet}, tracing::instrument, }; @@ -37,20 +45,22 @@ use { /// for the solver (earning reduced rewards). Enforcing these rules ensures that /// the settlement can be broadcast safely with high confidence that it will not /// be reverted and that it will not result in slashing for the solver. -#[derive(Debug, Clone)] +#[derive(derive_more::Debug, Clone)] pub struct Settlement { pub auction_id: auction::Id, /// The prepared on-chain transaction for this settlement transaction: SettlementTx, /// The gas parameters used by the settlement. pub gas: Gas, + #[debug(ignore)] solution: Solution, } -#[derive(Debug, Clone)] +#[derive(derive_more::Debug, Clone)] struct SettlementTx { /// Transaction with all internalizable interactions omitted internalized: eth::Tx, + #[debug(ignore)] /// Full Transaction without internalizing any interactions uninternalized: eth::Tx, /// Whether this settlement has interactions that could make it revert @@ -58,12 +68,9 @@ struct SettlementTx { } impl SettlementTx { - fn with_access_list(self, access_list: eth::AccessList) -> Self { - Self { - internalized: self.internalized.set_access_list(access_list.clone()), - uninternalized: self.uninternalized.set_access_list(access_list), - ..self - } + fn set_access_list(&mut self, access_list: RequiredAccessList) { + self.internalized.set_access_list(access_list.0.clone()); + self.uninternalized.set_access_list(access_list.0); } } @@ -100,13 +107,18 @@ impl Settlement { return Err(Error::NonBufferableTokensUsed(untrusted_tokens)); } + let (internalized, uninternalized) = futures::try_join!( + solution.approvals(eth, Internalization::Enable), + solution.approvals(eth, Internalization::Disable), + )?; + // Encode the solution into a settlement. let tx = SettlementTx { internalized: encoding::tx( auction, &solution, eth.contracts(), - solution.approvals(eth, Internalization::Enable).await?, + internalized, Internalization::Enable, solver_native_token, )?, @@ -114,7 +126,7 @@ impl Settlement { auction, &solution, eth.contracts(), - solution.approvals(eth, Internalization::Disable).await?, + uninternalized, Internalization::Disable, solver_native_token, )?, @@ -128,111 +140,86 @@ impl Settlement { async fn new( auction_id: auction::Id, solution: Solution, - transaction: SettlementTx, + mut transaction: SettlementTx, eth: &Ethereum, simulator: &Simulator, ) -> Result { - // The settlement contract will fail if the receiver is a smart contract. - // Because of this, if the receiver is a smart contract and we try to - // estimate the access list, the access list estimation will also fail. + //
.transfer(ETH) is allowed to use at most 2300 gas units ( + // see ). + // This is not enough when the receiver is a smart contract wallet which does + // non-trivial work in the `fallback` handler. + // To support sending native ETH to SC wallets we use access lists which + // effectively move the cost of accessing storage out of the critical section + // and into the tx's initial gas cost. + // While correctly built access lists provide a very minor net cost + // reduction an access list with unused storage slots increases the cost + // significantly. Since the risk is high and the reward is very low we only + // compute access list items which are absolutely necessary for the tx to work. // - // This failure happens because the Ethereum protocol sets a hard gas limit - // on transferring ETH into a smart contract, which some contracts exceed unless - // the access list is already specified. - - // The solution is to do access list estimation in two steps: first, simulate - // moving 1 wei into every smart contract to get a partial access list, and then - // use that partial access list to calculate the final access list. - let partial_access_lists = try_join_all(solution.user_trades().map(|trade| async { - if !trade.order().buys_eth() || !trade.order().pays_to_contract(eth).await? { - return Ok(Default::default()); - } - let tx = eth::Tx { - from: solution.solver().address(), - to: trade.order().receiver(), - value: 1.into(), - input: Default::default(), - access_list: Default::default(), - }; - Result::<_, Error>::Ok(simulator.access_list(&tx).await?) - })) - .await?; - let partial_access_list = partial_access_lists - .into_iter() - .fold(eth::AccessList::default(), |acc, list| acc.merge(list)); - - // Simulate the settlement and get the access list and gas. - let (access_list, gas) = Self::simulate( - transaction.internalized.clone(), - &partial_access_list, - eth, - simulator, + // We compute those access lists by using `eth_createAccessList` for a call + // sending 1 wei to each SC wallet that is supposed to get ETH during the + // settlement. Those lists get merged and added to the settlement transaction. + // + // `Some(..)` means at least one trade strictly requires an access list; + // `None` means it is purely a gas optimization for this settlement, so a + // non-revert fetch failure below can be tolerated. + let partial_access_list: Option = try_join_all( + solution + .user_trades() + .map(|trade| partial_access_list_for(trade, &solution, eth, simulator)), ) - .await?; - let price = eth.gas_price(None).await?; - let gas = Gas::new(gas, eth.block_gas_limit(), price)?; + .await? + .into_iter() + .flatten() + .map(|required| required.0) + .reduce(|acc, list| acc.merge(list)) + .map(RequiredAccessList); - // Ensure that the solver has sufficient balance for the settlement to be mined. - if eth.balance(solution.solver().address()).await? < gas.required_balance() { - return Err(Error::SolverAccountInsufficientBalance( - gas.required_balance(), - )); + if let Some(access_list) = partial_access_list { + transaction.set_access_list(access_list.clone()); } - // Is at least one interaction internalized? - if solution - .interactions() - .iter() - .any(|interaction| interaction.internalize()) - { - // Some rules which are enforced by the settlement contract for non-internalized - // interactions are not enforced for internalized interactions (in order to save - // gas). However, publishing a settlement with interactions that violate - // these rules constitutes a punishable offense for the solver, even if - // the interactions are internalized. To ensure that this doesn't happen, check - // that the settlement simulates even when internalizations are disabled. - Self::simulate( - transaction.uninternalized.clone(), - &partial_access_list, - eth, - simulator, - ) - .await?; + let gas_used_fut = simulator + .gas(transaction.internalized.clone()) + .inspect(|res| { + tracing::debug!( + block = eth.current_block().borrow().number, + transaction = ?transaction.internalized, + ?res, + "simulated settlement" + ) + }); + + // run everything concurrently to minimize latency added through RPC roundtrips + let (gas_used, gas_price, solver_eth) = tokio::join!( + gas_used_fut, + eth.gas_price(), + eth.balance(solution.solver().address()), + ); + + // Ensure the solver can cover the gas the node reserves to admit the settlement + // tx, which is `gas_limit * max_fee_per_gas` at whichever price we submit with. + let gas = Gas::new(gas_used?, eth.block_gas_limit(), eth.tx_gas_limit())?; + let required_eth_balance = gas.required_balance(submission_max_fee_per_gas( + gas_price?.max_fee_per_gas, + solution + .gas_fee_override() + .map(|gas_override| gas_override.max_fee_per_gas), + )); + if solver_eth? < required_eth_balance { + return Err(Error::SolverAccountInsufficientBalance( + required_eth_balance, + )); } Ok(Self { auction_id, solution, - transaction: transaction.with_access_list(access_list), + transaction, gas, }) } - /// Simulate executing this settlement on the blockchain. This process - /// ensures that the settlement does not revert, and calculates the - /// access list and gas needed to settle the solution. - #[instrument(name = "simulate_settlement", skip_all)] - async fn simulate( - tx: eth::Tx, - partial_access_list: ð::AccessList, - eth: &Ethereum, - simulator: &Simulator, - ) -> Result<(eth::AccessList, eth::Gas), Error> { - // Add the partial access list to the settlement tx. - let tx = tx.set_access_list(partial_access_list.to_owned()); - - // Simulate the full access list, passing the partial access - // list into the simulation. - let access_list = simulator.access_list(&tx).await?; - let tx = tx.set_access_list(access_list.clone()); - - // Simulate the settlement using the full access list and get the gas used. - let gas = simulator.gas(&tx).await; - - observe::simulated(eth, &tx, &gas); - Ok((access_list, gas?)) - } - /// The calldata for this settlement. pub fn transaction(&self, internalization: Internalization) -> ð::Tx { match internalization { @@ -262,8 +249,13 @@ impl Settlement { self.solution.id() } + /// Optional gas fee overrides provided by the solver. + pub fn gas_fee_override(&self) -> Option { + self.solution.gas_fee_override() + } + /// Solution's pre interactions - pub fn pre_interactions(&self) -> &[eth::Interaction] { + pub fn pre_interactions(&self) -> &[domain::Interaction] { self.solution.pre_interactions() } @@ -273,7 +265,7 @@ impl Settlement { } /// Solution's post interactions - pub fn post_interactions(&self) -> &[eth::Interaction] { + pub fn post_interactions(&self) -> &[domain::Interaction] { self.solution.post_interactions() } @@ -324,7 +316,10 @@ impl Settlement { acc } - /// The uniform price vector this settlement proposes + /// The uniform price vector this settlement proposes. + /// + /// Deprecated: only emitted on the `/solve` response so that autopilots + /// running the previous code can deserialise it during a rolling deploy. pub fn prices(&self) -> HashMap { self.solution .clearing_prices() @@ -332,6 +327,37 @@ impl Settlement { .map(|(token, amount)| (token, amount.into())) .collect() } + + /// Returns true if this settlement's solution has any trades with haircut. + pub fn has_haircut(&self) -> bool { + self.solution.has_haircut() + } +} + +/// Access lists that are required when the order buys native ETH and the +/// receiver is a smart-contract. +#[derive(Debug, Clone)] +struct RequiredAccessList(eth::AccessList); + +/// Returns the partial access list for a single trade, or `None` if the +/// trade does not buy native ETH or its receiver has no on-chain code. +async fn partial_access_list_for( + trade: &trade::Fulfillment, + solution: &Solution, + eth: &Ethereum, + simulator: &Simulator, +) -> Result, Error> { + if !trade.order().buys_eth() || !trade.order().pays_to_contract(eth).await? { + return Ok(None); + } + let tx = eth::Tx { + from: solution.solver().address(), + to: trade.order().receiver(), + value: 1.into(), + input: Default::default(), + access_list: Default::default(), + }; + Ok(Some(RequiredAccessList(simulator.access_list(&tx).await?))) } /// Should the interactions be internalized? @@ -358,8 +384,6 @@ pub struct Gas { /// computed by adding a buffer to the gas estimate to allow for small /// variations in the actual gas that gets used. pub limit: eth::Gas, - /// The gas price (EIP1559) for a settlement transaction. - pub price: eth::GasPrice, } impl Gas { @@ -368,7 +392,7 @@ impl Gas { pub fn new( estimate: eth::Gas, block_limit: eth::Gas, - price: eth::GasPrice, + tx_gas_limit: eth::Gas, ) -> Result { // We don't allow for solutions to take up more than half of the block's gas // limit. This is to ensure that block producers attempt to include the @@ -380,7 +404,11 @@ impl Gas { // will not exceed the remaining space in the block next and ignore transactions // whose gas limit exceed the remaining space (without simulating the actual // gas required). - let max_gas = eth::Gas(block_limit.0 / 2); + // Additionally cap by the configured per-tx gas limit. Operators set + // this per chain (e.g. to EIP-7825's 16,777,215 cap on Mainnet Fusaka) + // so the mempool can't reject the settlement for exceeding the per-tx + // ceiling. + let max_gas = std::cmp::min(eth::Gas(block_limit.0 / eth::U256::from(2)), tx_gas_limit); if estimate > max_gas { return Err(solution::Error::GasLimitExceeded(estimate, max_gas)); } @@ -392,20 +420,112 @@ impl Gas { // the end of execution, so we want to increase gas limit enough so // those solutions don't revert with out of gas error. const GAS_LIMIT_FACTOR: f64 = 2.0; - let estimate_with_buffer = - eth::U256::from_f64_lossy(eth::U256::to_f64_lossy(estimate.into()) * GAS_LIMIT_FACTOR) - .into(); + let estimate_with_buffer = eth::U256::from(f64::from(estimate.0) * GAS_LIMIT_FACTOR).into(); Ok(Self { estimate, limit: std::cmp::min(max_gas, estimate_with_buffer), - price, }) } /// The balance required to ensure settlement execution with the given gas /// parameters. - pub fn required_balance(&self) -> eth::Ether { - self.limit * self.price.max() + pub fn required_balance(&self, max_fee_per_gas: U256) -> eth::Ether { + self.limit * max_fee_per_gas.into() + } +} + +/// The `max_fee_per_gas` the settlement will be submitted with, used to size +/// the solver's required balance. Mirrors `apply_gas_fee_override`: with an +/// override we submit at that value, otherwise at the driver estimate doubled +/// to absorb the gas price climbing during submission. The override is the +/// solver's own choice, so we take it as is. +fn submission_max_fee_per_gas( + driver_max_fee_per_gas: u128, + override_max_fee_per_gas: Option, +) -> U256 { + override_max_fee_per_gas + .map(U256::from) + .unwrap_or_else(|| U256::from(driver_max_fee_per_gas).saturating_mul(U256::from(2))) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn gas(value: u64) -> eth::Gas { + eth::Gas(eth::U256::from(value)) + } + + /// EIP-7825 per-transaction gas cap (2^24 - 1) introduced in Mainnet's + /// Fusaka hardfork. Used in tests as a representative value for the + /// configurable `tx_gas_limit` knob on Mainnet. + const EIP_7825_MAINNET_TX_GAS_CAP: u64 = (1 << 24) - 1; + + #[test] + fn rejects_solution_above_tx_gas_limit() { + // Block limit (120M) is high enough that half the block (60M) exceeds + // the configured per-tx limit (EIP-7825 cap, 16,777,215). The per-tx + // limit must win. + let block_limit = gas(120_000_000); + let tx_gas_limit = gas(EIP_7825_MAINNET_TX_GAS_CAP); + let estimate = gas(20_000_000); + let err = Gas::new(estimate, block_limit, tx_gas_limit).unwrap_err(); + match err { + solution::Error::GasLimitExceeded(used, limit) => { + assert_eq!(used, estimate); + assert_eq!(limit, tx_gas_limit); + } + other => panic!("unexpected error: {other:?}"), + } + } + + #[test] + fn accepts_solution_at_tx_gas_limit() { + let block_limit = gas(120_000_000); + let tx_gas_limit = gas(EIP_7825_MAINNET_TX_GAS_CAP); + let result = Gas::new(tx_gas_limit, block_limit, tx_gas_limit).unwrap(); + assert_eq!(result.estimate, tx_gas_limit); + // The 2x buffer would otherwise push limit to 2 * tx_gas_limit; the + // min(max_gas, ...) clamp must keep it at the configured cap. + assert_eq!(result.limit, tx_gas_limit); + } + + #[test] + fn small_block_limit_still_caps_at_half() { + // On chains with a low block gas limit, the half-block cap is tighter + // than the configured per-tx limit and must keep applying. + let block_limit = gas(10_000_000); + let tx_gas_limit = gas(EIP_7825_MAINNET_TX_GAS_CAP); + let estimate = gas(6_000_000); + let err = Gas::new(estimate, block_limit, tx_gas_limit).unwrap_err(); + match err { + solution::Error::GasLimitExceeded(_, limit) => assert_eq!(limit, gas(5_000_000)), + other => panic!("unexpected error: {other:?}"), + } + } + + #[test] + fn high_tx_gas_limit_lets_half_block_bind() { + // Non-Fusaka chain: tx_gas_limit configured well above half the block, + // so the half-block cap is the binding limit. + let block_limit = gas(120_000_000); + let tx_gas_limit = gas(100_000_000); + let estimate = gas(70_000_000); + let err = Gas::new(estimate, block_limit, tx_gas_limit).unwrap_err(); + match err { + solution::Error::GasLimitExceeded(_, limit) => assert_eq!(limit, gas(60_000_000)), + other => panic!("unexpected error: {other:?}"), + } + } + + #[test] + fn submission_fee_prefers_override_over_driver_estimate() { + // No override: driver estimate, doubled. + assert_eq!(submission_max_fee_per_gas(100, None), U256::from(200)); + // Override above the doubled estimate: use the override. + assert_eq!(submission_max_fee_per_gas(100, Some(500)), U256::from(500)); + // Override below the doubled estimate: still the override, not driver * 2. + assert_eq!(submission_max_fee_per_gas(100, Some(50)), U256::from(50)); } } diff --git a/crates/driver/src/domain/competition/solution/slippage.rs b/crates/driver/src/domain/competition/solution/slippage.rs index cf12a7c22b..7d5a2f6a0d 100644 --- a/crates/driver/src/domain/competition/solution/slippage.rs +++ b/crates/driver/src/domain/competition/solution/slippage.rs @@ -1,13 +1,11 @@ use { crate::domain::{ competition::auction::Prices, - eth, liquidity::{ExactOutput, MaxInput}, }, - ethcontract::U256, + eth_domain_types as eth, num::{BigRational, CheckedDiv, CheckedMul}, - number::conversions::big_rational_to_u256, - shared::conversions::U256Ext, + number::{conversions::big_rational_to_u256, u256_ext::U256Ext}, }; #[derive(Clone)] @@ -48,10 +46,9 @@ impl Parameters { big_rational_to_u256(&relative).map_err(|_| super::error::Math::DivisionByZero)?; // Final slippage considers min/max caps - let slippage = num::clamp( - relative, + let slippage = relative.clamp( self.min.unwrap_or_default(), - self.max.unwrap_or(U256::max_value()), + self.max.unwrap_or(eth::U256::MAX), ); tracing::debug!( @@ -70,10 +67,9 @@ impl Parameters { big_rational_to_u256(&relative).map_err(|_| super::error::Math::DivisionByZero)?; // Final slippage considers min/max caps - let slippage = num::clamp( - relative, + let slippage = relative.clamp( self.min.unwrap_or_default(), - self.max.unwrap_or(U256::max_value()), + self.max.unwrap_or(alloy::primitives::U256::MAX), ); tracing::debug!( @@ -91,7 +87,7 @@ impl Parameters { .checked_div(&interaction.output.amount) .ok_or(super::error::Math::DivisionByZero)? } else { - tracing::warn!( + tracing::trace!( input_token = ?interaction.input.token, output_token = ?interaction.output.token, "unable to compute capped slippage; falling back to relative slippage", @@ -102,7 +98,7 @@ impl Parameters { .into() }; - tracing::debug!(?interaction, ?slippage, "applying slippage to liquidity",); + tracing::trace!(?interaction, ?slippage, "applying slippage to liquidity",); Ok(( MaxInput(eth::Asset { amount: interaction.input.amount + slippage, @@ -115,15 +111,10 @@ impl Parameters { #[cfg(test)] mod tests { - use {super::*, crate::domain::eth::Asset, num::rational::Ratio}; + use {super::*, alloy::primitives::address, eth_domain_types::Asset, num::rational::Ratio}; - const GNO: eth::H160 = eth::H160(hex_literal::hex!( - "6810e776880c02933d47db1b9fc05908e5386b96" - )); - - const USDC: eth::H160 = eth::H160(hex_literal::hex!( - "A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" - )); + const GNO: eth::Address = address!("6810e776880c02933d47db1b9fc05908e5386b96"); + const USDC: eth::Address = address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); #[test] fn test_input_price() { @@ -131,17 +122,17 @@ mod tests { input: Asset { token: GNO.into(), // 1GNO - amount: eth::U256::exp10(18).into(), + amount: eth::U256::from(10).pow(eth::U256::from(18)).into(), }, output: Asset { token: USDC.into(), // 200 USDC - amount: (U256::from(200) * eth::U256::exp10(6)).into(), + amount: (eth::U256::from(200) * eth::U256::from(10).pow(eth::U256::from(6))).into(), }, }; let prices = maplit::hashmap! { // 0.1 ETH - GNO.into() => eth::U256::exp10(17).into(), + GNO.into() => eth::U256::from(10).pow(eth::U256::from(17)).into(), }; // no cap @@ -154,33 +145,39 @@ mod tests { let (max_input, exact_output) = slippage.apply_to(&interaction).unwrap(); assert_eq!( max_input.0.amount, - (eth::U256::exp10(18) + eth::U256::exp10(17)).into() + (eth::U256::from(10).pow(eth::U256::from(18)) + + eth::U256::from(10).pow(eth::U256::from(17))) + .into() ); assert_eq!(exact_output.0.amount, interaction.output.amount); // min cap let min_cap = Parameters { // 0.1 ETH (1 GNO) - min: Some(eth::U256::exp10(17)), + min: Some(eth::U256::from(10).pow(eth::U256::from(17))), ..slippage.clone() }; let (max_input, _) = min_cap.apply_to(&interaction).unwrap(); assert_eq!( max_input.0.amount, - (eth::U256::exp10(18) + eth::U256::exp10(18)).into() + (eth::U256::from(10).pow(eth::U256::from(18)) + + eth::U256::from(10).pow(eth::U256::from(18))) + .into() ); assert_eq!(exact_output.0.amount, interaction.output.amount); // max cap let max_cap = Parameters { // 0.001 ETH (0.01 GNO) - max: Some(eth::U256::exp10(15)), + max: Some(eth::U256::from(10).pow(eth::U256::from(15))), ..slippage }; let (max_input, _) = max_cap.apply_to(&interaction).unwrap(); assert_eq!( max_input.0.amount, - (eth::U256::exp10(18) + eth::U256::exp10(16)).into() + (eth::U256::from(10).pow(eth::U256::from(18)) + + eth::U256::from(10).pow(eth::U256::from(16))) + .into() ); assert_eq!(exact_output.0.amount, interaction.output.amount); } @@ -191,17 +188,17 @@ mod tests { input: Asset { token: GNO.into(), // 1GNO - amount: eth::U256::exp10(18).into(), + amount: eth::U256::from(10).pow(eth::U256::from(18)).into(), }, output: Asset { token: USDC.into(), // 200 USDC - amount: (U256::from(200) * eth::U256::exp10(6)).into(), + amount: (eth::U256::from(200) * eth::U256::from(10).pow(eth::U256::from(6))).into(), }, }; let prices = maplit::hashmap! { // $4000 per ETH (1 USD = 0.0005 ETH), 6 decimals - USDC.into() => (U256::from(5) * eth::U256::exp10(26)).into(), + USDC.into() => (eth::U256::from(5) * eth::U256::from(10).pow(eth::U256::from(26))).into(), }; // no cap @@ -214,33 +211,39 @@ mod tests { let (max_input, exact_output) = slippage.apply_to(&interaction).unwrap(); assert_eq!( max_input.0.amount, - (eth::U256::exp10(18) + eth::U256::exp10(17)).into() + (eth::U256::from(10).pow(eth::U256::from(18)) + + eth::U256::from(10).pow(eth::U256::from(17))) + .into() ); assert_eq!(exact_output.0.amount, interaction.output.amount); // min cap let min_cap = Parameters { // 0.1 ETH (1 GNO) - min: Some(eth::U256::exp10(17)), + min: Some(eth::U256::from(10).pow(eth::U256::from(17))), ..slippage.clone() }; let (max_input, _) = min_cap.apply_to(&interaction).unwrap(); assert_eq!( max_input.0.amount, - (eth::U256::exp10(18) + eth::U256::exp10(18)).into() + (eth::U256::from(10).pow(eth::U256::from(18)) + + eth::U256::from(10).pow(eth::U256::from(18))) + .into() ); assert_eq!(exact_output.0.amount, interaction.output.amount); // max cap let max_cap = Parameters { // 0.001 ETH (0.01 GNO) - max: Some(eth::U256::exp10(15)), + max: Some(eth::U256::from(10).pow(eth::U256::from(15))), ..slippage }; let (max_input, _) = max_cap.apply_to(&interaction).unwrap(); assert_eq!( max_input.0.amount, - (eth::U256::exp10(18) + eth::U256::exp10(16)).into() + (eth::U256::from(10).pow(eth::U256::from(18)) + + eth::U256::from(10).pow(eth::U256::from(16))) + .into() ); assert_eq!(exact_output.0.amount, interaction.output.amount); } @@ -249,20 +252,20 @@ mod tests { fn test_no_price() { let slippage = Parameters { relative: Ratio::from_float(1.).unwrap(), - max: Some(eth::U256::exp10(16)), - min: Some(eth::U256::exp10(18)), + max: Some(eth::U256::from(10).pow(eth::U256::from(16))), + min: Some(eth::U256::from(10).pow(eth::U256::from(18))), prices: Default::default(), }; let interaction = Interaction { input: Asset { token: GNO.into(), // 1GNO - amount: eth::U256::exp10(18).into(), + amount: eth::U256::from(10).pow(eth::U256::from(18)).into(), }, output: Asset { token: USDC.into(), // 200 USDC - amount: (U256::from(200) * eth::U256::exp10(6)).into(), + amount: (eth::U256::from(200) * eth::U256::from(10).pow(eth::U256::from(6))).into(), }, }; @@ -270,7 +273,9 @@ mod tests { let (max_input, exact_output) = slippage.apply_to(&interaction).unwrap(); assert_eq!( max_input.0.amount, - (eth::U256::exp10(18) + eth::U256::exp10(18)).into() + (eth::U256::from(10).pow(eth::U256::from(18)) + + eth::U256::from(10).pow(eth::U256::from(18))) + .into() ); assert_eq!(exact_output.0.amount, interaction.output.amount); } diff --git a/crates/driver/src/domain/competition/solution/trade.rs b/crates/driver/src/domain/competition/solution/trade.rs index 3aefc566e4..b85981e671 100644 --- a/crates/driver/src/domain/competition/solution/trade.rs +++ b/crates/driver/src/domain/competition/solution/trade.rs @@ -1,18 +1,15 @@ -use crate::{ - domain::{ - competition::{ - self, - order::{self, FeePolicy, SellAmount, Side, TargetAmount, Uid}, - solution::error::{self, Math}, - }, - eth::{self, Asset}, +use { + crate::domain::competition::{ + self, + order::{self, FeePolicy, SellAmount, Side, TargetAmount, Uid}, + solution::error::{self, Math}, }, - util::conv::u256::U256Ext, + eth_domain_types::{self as eth, Asset}, + number::u256_ext::U256Ext, }; /// A trade which executes an order as part of this solution. #[derive(Debug, Clone)] -#[expect(clippy::large_enum_variant)] pub enum Trade { Fulfillment(Fulfillment), Jit(Jit), @@ -73,19 +70,10 @@ impl Trade { &self, prices: &ClearingPrices, ) -> Result { - let before_fee = match self.side() { - order::Side::Sell => self.executed().0, - order::Side::Buy => self - .executed() - .0 - .checked_mul(prices.buy) - .ok_or(Math::Overflow)? - .checked_div(prices.sell) - .ok_or(Math::DivisionByZero)?, - }; - Ok(eth::TokenAmount( - before_fee.checked_add(self.fee().0).ok_or(Math::Overflow)?, - )) + match self { + Trade::Fulfillment(fulfillment) => fulfillment.sell_amount(prices), + Trade::Jit(jit) => jit.sell_amount(prices), + } } /// The effective amount the user received after all fees. @@ -95,27 +83,20 @@ impl Trade { &self, prices: &ClearingPrices, ) -> Result { - let amount = match self.side() { - order::Side::Buy => self.executed().0, - order::Side::Sell => self - .executed() - .0 - .checked_mul(prices.sell) - .ok_or(Math::Overflow)? - .checked_ceil_div(&prices.buy) - .ok_or(Math::DivisionByZero)?, - }; - Ok(eth::TokenAmount(amount)) + match self { + Trade::Fulfillment(fulfillment) => fulfillment.buy_amount(prices), + Trade::Jit(jit) => jit.buy_amount(prices), + } } pub fn custom_prices( &self, prices: &ClearingPrices, ) -> Result { - Ok(CustomClearingPrices { - sell: self.buy_amount(prices)?.into(), - buy: self.sell_amount(prices)?.into(), - }) + match self { + Trade::Fulfillment(fulfillment) => fulfillment.custom_prices(prices), + Trade::Jit(jit) => jit.custom_prices(prices), + } } pub fn receiver(&self) -> eth::Address { @@ -135,6 +116,11 @@ pub struct Fulfillment { /// order. executed: order::TargetAmount, fee: Fee, + /// Additional fee for conservative bidding (haircut). Applied on top of + /// the regular fee to reduce reported surplus without affecting executed + /// amounts. Expressed in the order's target token (sell token for sell + /// orders, buy token for buy orders). + haircut_fee: eth::U256, } impl Fulfillment { @@ -142,6 +128,7 @@ impl Fulfillment { order: competition::Order, executed: order::TargetAmount, fee: Fee, + haircut_fee: eth::U256, ) -> Result { // If the order is partial, the total executed amount can be smaller than // the target amount. Otherwise, the executed amount must be equal to the target @@ -179,6 +166,7 @@ impl Fulfillment { order, executed, fee, + haircut_fee, }) } else { Err(error::Trade::InvalidExecutedAmount) @@ -201,7 +189,7 @@ impl Fulfillment { // Orders with static fees are no longer used, except for quoting purposes, when // the static fee is set to 0. This is expected to be resolved with https://github.com/cowprotocol/services/issues/2543 // Once resolved, this code will be simplified as part of https://github.com/cowprotocol/services/issues/2507 - order::SellAmount(0.into()) + order::SellAmount(eth::U256::ZERO) } Fee::Dynamic(fee) => fee, } @@ -215,7 +203,15 @@ impl Fulfillment { } } + /// Returns the haircut fee for conservative bidding. + pub fn haircut_fee(&self) -> eth::U256 { + self.haircut_fee + } + /// The effective amount that left the user's wallet including all fees. + /// + /// For buy orders, this includes the haircut effect (haircut increases the + /// effective sell amount the user pays). pub fn sell_amount(&self, prices: &ClearingPrices) -> Result { let before_fee = match self.order.side { order::Side::Sell => self.executed.0, @@ -227,28 +223,69 @@ impl Fulfillment { .checked_div(prices.sell) .ok_or(Math::DivisionByZero)?, }; + + let with_fee = before_fee.checked_add(self.fee().0).ok_or(Math::Overflow)?; + // Add haircut for buy orders (haircut is in buy token, convert to sell token) + let haircut = match self.order.side { + order::Side::Sell => eth::U256::ZERO, // Haircut applied to buy_amount for sell orders + order::Side::Buy => self.haircut_in_sell_token(prices)?, + }; + Ok(eth::TokenAmount( - before_fee.checked_add(self.fee().0).ok_or(Math::Overflow)?, + with_fee.checked_add(haircut).ok_or(Math::Overflow)?, )) } /// The effective amount the user received after all fees. /// /// Settlement contract uses `ceil` division for buy amount calculation. + /// + /// For sell orders, this includes the haircut effect (haircut reduces the + /// effective buy amount the user receives). pub fn buy_amount(&self, prices: &ClearingPrices) -> Result { let amount = match self.order.side { order::Side::Buy => self.executed.0, - order::Side::Sell => self - .executed - .0 - .checked_mul(prices.sell) - .ok_or(Math::Overflow)? - .checked_ceil_div(&prices.buy) - .ok_or(Math::DivisionByZero)?, + order::Side::Sell => { + // Base buy amount from executed sell + let base = self + .executed + .0 + .checked_mul(prices.sell) + .ok_or(Math::Overflow)? + .checked_ceil_div(&prices.buy) + .ok_or(Math::DivisionByZero)?; + // Reduce by haircut (haircut is in sell token, convert to buy token) + let haircut_in_buy = self + .haircut_fee + .checked_mul(prices.sell) + .ok_or(Math::Overflow)? + .checked_div(prices.buy) + .ok_or(Math::DivisionByZero)?; + base.checked_sub(haircut_in_buy).ok_or(Math::Negative)? + } }; Ok(eth::TokenAmount(amount)) } + /// Computes the haircut amount in sell token. + /// Used for buy orders to add haircut to the sell amount. + fn haircut_in_sell_token(&self, prices: &ClearingPrices) -> Result { + match self.order.side { + order::Side::Sell => Ok(self.haircut_fee), + order::Side::Buy => self + .haircut_fee + .checked_mul(prices.buy) + .ok_or(Math::Overflow)? + .checked_div(prices.sell) + .ok_or(Math::DivisionByZero), + } + } + + /// Computes custom clearing prices for this trade. + /// + /// Note: This function relies on `sell_amount()` and `buy_amount()` to + /// correctly incorporate all adjustments (fees, haircuts). No additional + /// modifications are applied here. pub fn custom_prices( &self, prices: &ClearingPrices, @@ -303,7 +340,7 @@ impl Fulfillment { // be caught by simulation limit_sell_amount .checked_sub(executed_sell_amount_with_fee) - .unwrap_or(eth::U256::zero()) + .unwrap_or(eth::U256::ZERO) } Side::Sell => { // Scale to support partially fillable orders @@ -328,7 +365,7 @@ impl Fulfillment { // be caught by simulation executed_buy_amount .checked_sub(limit_buy_amount) - .unwrap_or(eth::U256::zero()) + .unwrap_or(eth::U256::ZERO) } }; Ok(surplus.into()) @@ -463,6 +500,50 @@ impl Jit { pub fn fee(&self) -> order::SellAmount { self.fee } + + /// The effective amount that left the user's wallet including all fees. + pub fn sell_amount(&self, prices: &ClearingPrices) -> Result { + let before_fee = match self.order.side { + Side::Sell => self.executed.0, + Side::Buy => self + .executed + .0 + .checked_mul(prices.buy) + .ok_or(Math::Overflow)? + .checked_div(prices.sell) + .ok_or(Math::DivisionByZero)?, + }; + Ok(eth::TokenAmount( + before_fee.checked_add(self.fee.0).ok_or(Math::Overflow)?, + )) + } + + /// The effective amount the user received after all fees. + pub fn buy_amount(&self, prices: &ClearingPrices) -> Result { + let amount = match self.order.side { + Side::Buy => self.executed.0, + Side::Sell => self + .executed + .0 + .checked_mul(prices.sell) + .ok_or(Math::Overflow)? + .checked_ceil_div(&prices.buy) + .ok_or(Math::DivisionByZero)?, + }; + Ok(eth::TokenAmount(amount)) + } + + pub fn custom_prices( + &self, + prices: &ClearingPrices, + ) -> Result { + // JIT orders don't have haircut, so custom prices are simply derived + // from sell_amount and buy_amount. + Ok(CustomClearingPrices { + sell: self.buy_amount(prices)?.into(), + buy: self.sell_amount(prices)?.into(), + }) + } } /// The amounts executed by a trade. diff --git a/crates/driver/src/domain/competition/sorting.rs b/crates/driver/src/domain/competition/sorting.rs index 83d0a667af..40182dcbc9 100644 --- a/crates/driver/src/domain/competition/sorting.rs +++ b/crates/driver/src/domain/competition/sorting.rs @@ -1,12 +1,10 @@ use { crate::{ - domain::{ - competition::{auction::Tokens, order}, - eth, - }, + domain::competition::{auction::Tokens, order}, util, }, chrono::Duration, + eth_domain_types as eth, std::{fmt::Debug, sync::Arc}, }; @@ -22,7 +20,7 @@ pub trait SortingStrategy: Send + Sync + Debug { &self, order: &order::Order, tokens: &Tokens, - solver: ð::H160, + solver: ð::Address, now: chrono::DateTime, ) -> SortingKey; } @@ -37,7 +35,7 @@ impl SortingStrategy for ExternalPrice { &self, order: &order::Order, tokens: &Tokens, - _solver: ð::H160, + _solver: ð::Address, _now: chrono::DateTime, ) -> SortingKey { // The likelihood that this order will be fulfilled, based on token prices. @@ -48,8 +46,8 @@ impl SortingStrategy for ExternalPrice { tokens.get(&order.sell.token).and_then(|token| token.price), ) { (Some(buy_price), Some(sell_price)) => { - let buy = buy_price.in_eth(order.buy.amount).0.to_f64_lossy(); - let sell = sell_price.in_eth(order.sell.amount).0.to_f64_lossy(); + let buy = f64::from(buy_price.in_eth(order.buy.amount).0); + let sell = f64::from(sell_price.in_eth(order.sell.amount).0); if buy.is_subnormal() { 0. } else { sell / buy } } _ => 0., @@ -91,7 +89,7 @@ impl SortingStrategy for CreationTimestamp { &self, order: &order::Order, _tokens: &Tokens, - _solver: ð::H160, + _solver: ð::Address, now: chrono::DateTime, ) -> SortingKey { SortingKey::Timestamp(match self.max_order_age { @@ -116,7 +114,7 @@ impl SortingStrategy for OwnQuotes { &self, order: &order::Order, _tokens: &Tokens, - solver: ð::H160, + solver: ð::Address, now: chrono::DateTime, ) -> SortingKey { let is_order_outdated = self.max_order_age.is_some_and(|max_order_age| { @@ -124,7 +122,7 @@ impl SortingStrategy for OwnQuotes { u32::try_from((now - max_order_age).timestamp()).unwrap_or(u32::MAX); order.created.0 < earliest_allowed_creation }); - let is_own_quote = order.quote.as_ref().is_some_and(|q| &q.solver.0 == solver); + let is_own_quote = order.quote.as_ref().is_some_and(|q| &q.solver == solver); SortingKey::Bool(!is_order_outdated && is_own_quote) } @@ -135,7 +133,7 @@ impl SortingStrategy for OwnQuotes { pub fn sort_orders( orders: &mut [order::Order], tokens: &Tokens, - solver: ð::H160, + solver: ð::Address, order_comparators: &[Arc], ) { let now = chrono::Utc::now(); diff --git a/crates/driver/src/domain/cow_amm.rs b/crates/driver/src/domain/cow_amm.rs index c60dcaaa72..9b9cd8688c 100644 --- a/crates/driver/src/domain/cow_amm.rs +++ b/crates/driver/src/domain/cow_amm.rs @@ -1,9 +1,8 @@ use { - crate::domain::eth, alloy::{primitives::Address, providers::DynProvider}, - contracts::alloy::cow_amm::CowAmmLegacyHelper, + contracts::cow_amm::CowAmmLegacyHelper, cow_amm::Amm, - ethrpc::alloy::conversions::IntoAlloy, + eth_domain_types as eth, itertools::{ Either::{Left, Right}, Itertools, @@ -24,7 +23,11 @@ pub struct Cache { } impl Cache { - pub fn new(web3: DynProvider, factory_mapping: HashMap) -> Self { + pub fn new(web3: DynProvider, factory_mapping: HashMap) -> Option { + if factory_mapping.is_empty() { + return None; + } + let helper_by_factory = factory_mapping .into_iter() .map(|(factory, helper)| { @@ -34,11 +37,11 @@ impl Cache { ) }) .collect(); - Self { + Some(Self { inner: RwLock::new(HashMap::new()), web3: web3.clone(), helper_by_factory, - } + }) } /// Gets or creates AMM instances for the given surplus capturing JIT order @@ -51,12 +54,9 @@ impl Cache { let cache = self.inner.read().await; surplus_capturing_jit_order_owners .iter() - .partition_map(|&address| { - let address = address.0.into_alloy(); - match cache.get(&address) { - Some(amm) => Left(amm.clone()), - None => Right(address), - } + .partition_map(|&address| match cache.get(&address) { + Some(amm) => Left(amm.clone()), + None => Right(address), }) }; @@ -124,11 +124,10 @@ impl Cache { /// Fetches the factory address for the given AMM by calling the /// `FACTORY` function. async fn fetch_amm_factory_address(&self, amm_address: Address) -> anyhow::Result
{ - let factory_getter = - contracts::alloy::cow_amm::CowAmmFactoryGetter::CowAmmFactoryGetter::new( - amm_address, - self.web3.clone(), - ); + let factory_getter = contracts::cow_amm::CowAmmFactoryGetter::CowAmmFactoryGetter::new( + amm_address, + self.web3.clone(), + ); Ok(factory_getter.FACTORY().call().await?) } } diff --git a/crates/driver/src/domain/eth/mod.rs b/crates/driver/src/domain/eth/mod.rs deleted file mode 100644 index 6c02781fbc..0000000000 --- a/crates/driver/src/domain/eth/mod.rs +++ /dev/null @@ -1,459 +0,0 @@ -use { - crate::util::{Bytes, conv::u256::U256Ext}, - derive_more::{From, Into}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - itertools::Itertools, - solvers_dto::auction::FlashloanHint, - std::{ - collections::{HashMap, HashSet}, - ops::{Div, Mul, Sub}, - }, - web3::types::CallRequest, -}; - -pub mod allowance; -mod eip712; -mod gas; - -pub use { - allowance::Allowance, - eip712::DomainSeparator, - gas::{EffectiveGasPrice, FeePerGas, Gas, GasPrice}, - number::nonzero::U256 as NonZeroU256, - primitive_types::{H160, H256, U256, U512}, -}; - -// TODO This module is getting a little hectic with all kinds of different -// types, I wonder if there could be meaningful submodules? - -/// ERC20 token address for ETH. In reality, ETH is not an ERC20 token because -/// it does not implement the ERC20 interface, but this address is used by -/// convention across the Ethereum ecosystem whenever ETH is treated like an -/// ERC20 token. -pub const ETH_TOKEN: TokenAddress = TokenAddress(ContractAddress(H160([0xee; 20]))); - -/// An EIP-2930 access list. This type ensures that the addresses and storage -/// keys are not repeated, and that the ordering is deterministic. -/// -/// https://eips.ethereum.org/EIPS/eip-2930 -#[derive(Debug, Clone, Default)] -pub struct AccessList(HashMap>); - -impl AccessList { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl AccessList { - /// Merge two access lists together. - pub fn merge(mut self, other: Self) -> Self { - for (address, storage_keys) in other.0.into_iter() { - self.0.entry(address).or_default().extend(storage_keys); - } - self - } -} - -impl From for AccessList { - fn from(value: web3::types::AccessList) -> Self { - Self( - value - .into_iter() - .map(|item| { - ( - item.address.into(), - item.storage_keys - .into_iter() - .map(|key| key.into()) - .collect(), - ) - }) - .collect(), - ) - } -} - -impl From for web3::types::AccessList { - fn from(value: AccessList) -> Self { - value - .0 - .into_iter() - .sorted_by_key(|&(address, _)| address) - .map(|(address, storage_keys)| web3::types::AccessListItem { - address: address.into(), - storage_keys: storage_keys.into_iter().sorted().map(|key| key.0).collect(), - }) - .collect() - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Into, From)] -struct StorageKey(pub H256); - -/// An address. Can be an EOA or a smart contract address. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] -pub struct Address(pub H160); - -// TODO This type should probably use Ethereum::is_contract to verify during -// construction that it does indeed point to a contract -/// A smart contract address. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Into, From)] -pub struct ContractAddress(pub H160); - -impl From for Address { - fn from(value: ContractAddress) -> Self { - value.0.into() - } -} - -/// An ERC20 token address. -/// -/// https://eips.ethereum.org/EIPS/eip-20 -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct TokenAddress(pub ContractAddress); - -impl TokenAddress { - /// If the token is ETH, return WETH, thereby converting it to erc20. - pub fn as_erc20(self, weth: WethAddress) -> Self { - if self == ETH_TOKEN { weth.into() } else { self } - } -} - -/// An ERC20 token amount. -/// -/// https://eips.ethereum.org/EIPS/eip-20 -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] -pub struct TokenAmount(pub U256); - -impl TokenAmount { - /// Applies a factor to the token amount. - pub fn apply_factor(&self, factor: f64) -> Option { - Some(self.0.checked_mul_f64(factor)?.into()) - } -} - -/// A value denominated in an order's surplus token (buy token for -/// sell orders and sell token for buy orders). -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] -pub struct SurplusTokenAmount(pub U256); - -impl Sub for TokenAmount { - type Output = TokenAmount; - - fn sub(self, rhs: Self) -> Self::Output { - self.0.sub(rhs.0).into() - } -} - -impl num::CheckedSub for TokenAmount { - fn checked_sub(&self, other: &Self) -> Option { - self.0.checked_sub(other.0).map(Into::into) - } -} - -impl Mul for TokenAmount { - type Output = TokenAmount; - - fn mul(self, rhs: Self) -> Self::Output { - self.0.mul(rhs.0).into() - } -} - -impl num::CheckedMul for TokenAmount { - fn checked_mul(&self, other: &Self) -> Option { - self.0.checked_mul(other.0).map(Into::into) - } -} - -impl num::CheckedAdd for TokenAmount { - fn checked_add(&self, other: &Self) -> Option { - self.0.checked_add(other.0).map(Into::into) - } -} - -impl Div for TokenAmount { - type Output = TokenAmount; - - fn div(self, rhs: Self) -> Self::Output { - self.0.div(rhs.0).into() - } -} - -impl num::CheckedDiv for TokenAmount { - fn checked_div(&self, other: &Self) -> Option { - self.0.checked_div(other.0).map(Into::into) - } -} - -impl From for TokenAmount { - fn from(value: u128) -> Self { - Self(value.into()) - } -} - -impl std::ops::Add for TokenAmount { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl std::ops::AddAssign for TokenAmount { - fn add_assign(&mut self, rhs: Self) { - self.0 += rhs.0; - } -} - -impl num::Zero for TokenAmount { - fn zero() -> Self { - Self(U256::zero()) - } - - fn is_zero(&self) -> bool { - self.0.is_zero() - } -} - -impl std::fmt::Display for TokenAmount { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} - -/// The address of the WETH contract. -#[derive(Debug, Clone, Copy, From, Into)] -pub struct WethAddress(pub TokenAddress); - -impl From for WethAddress { - fn from(value: H160) -> Self { - WethAddress(value.into()) - } -} - -impl From for TokenAddress { - fn from(value: H160) -> Self { - Self(value.into()) - } -} - -impl From for H160 { - fn from(value: TokenAddress) -> Self { - value.0.into() - } -} - -impl From for ContractAddress { - fn from(value: TokenAddress) -> Self { - value.0 - } -} - -/// An asset on the Ethereum blockchain. Represents a particular amount of a -/// particular token. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct Asset { - pub amount: TokenAmount, - pub token: TokenAddress, -} - -/// An amount of native Ether tokens denominated in wei. -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, From, Into)] -pub struct Ether(pub U256); - -impl From for num::BigInt { - fn from(value: Ether) -> Self { - let mut bytes = [0; 32]; - value.0.to_big_endian(&mut bytes); - num::BigUint::from_bytes_be(&bytes).into() - } -} - -impl From for Ether { - fn from(value: i32) -> Self { - Self(value.into()) - } -} - -impl std::ops::Add for Ether { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl num::Zero for Ether { - fn zero() -> Self { - Self(U256::zero()) - } - - fn is_zero(&self) -> bool { - self.0.is_zero() - } -} - -impl std::iter::Sum for Ether { - fn sum>(iter: I) -> Self { - iter.fold(num::Zero::zero(), std::ops::Add::add) - } -} - -/// Block number. -#[derive(Debug, Clone, Copy, From, Into)] -pub struct BlockNo(pub u64); - -/// An onchain transaction which interacts with a smart contract. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Interaction { - pub target: Address, - pub value: Ether, - pub call_data: Bytes>, -} - -impl From for model::interaction::InteractionData { - fn from(interaction: Interaction) -> Self { - Self { - target: interaction.target.0.into_alloy(), - value: interaction.value.0.into_alloy(), - call_data: interaction.call_data.0, - } - } -} - -impl From for Interaction { - fn from(interaction: model::interaction::InteractionData) -> Self { - Self { - target: interaction.target.into_legacy().into(), - value: interaction.value.into_legacy().into(), - call_data: interaction.call_data.into(), - } - } -} - -/// A transaction ID, AKA transaction hash. -#[derive(Clone, Debug, From, Into)] -pub struct TxId(pub H256); - -pub enum TxStatus { - /// The transaction has been included and executed successfully. - Executed { block_number: BlockNo }, - /// The transaction has been included but execution failed. - Reverted { block_number: BlockNo }, - /// The transaction has not been included yet. - Pending, -} - -/// An onchain transaction. -#[derive(Clone)] -pub struct Tx { - pub from: Address, - pub to: Address, - pub value: Ether, - pub input: Bytes>, - pub access_list: AccessList, -} - -impl From for CallRequest { - fn from(value: Tx) -> Self { - Self { - from: Some(value.from.into()), - to: Some(value.to.into()), - gas: None, - gas_price: None, - value: Some(value.value.into()), - data: Some(value.input.into()), - transaction_type: None, - access_list: Some(value.access_list.into()), - max_fee_per_gas: None, - max_priority_fee_per_gas: None, - } - } -} - -impl std::fmt::Debug for Tx { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Tx") - .field("from", &self.from) - .field("to", &self.to) - .field("value", &self.value) - .field("input", &self.input) - .field("access_list", &self.access_list) - .finish() - } -} - -impl Tx { - pub fn set_access_list(self, access_list: AccessList) -> Self { - Self { - access_list, - ..self - } - } -} - -/// The Keccak-256 hash of a contract's initialization code. -/// -/// This value is meaningful in the context of the EVM `CREATE2` opcode in that -/// it influences the deterministic address that the contract ends up on. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct CodeDigest(pub H256); - -impl From for CodeDigest { - fn from(value: H256) -> Self { - Self(value) - } -} - -impl From for H256 { - fn from(value: CodeDigest) -> Self { - value.0 - } -} - -impl From<[u8; 32]> for CodeDigest { - fn from(value: [u8; 32]) -> Self { - Self(H256(value)) - } -} - -impl From for [u8; 32] { - fn from(value: CodeDigest) -> Self { - value.0.0 - } -} - -#[derive(Debug, Clone)] -pub struct Flashloan { - pub liquidity_provider: ContractAddress, - pub protocol_adapter: ContractAddress, - pub receiver: Address, - pub token: TokenAddress, - pub amount: TokenAmount, -} - -impl From<&solvers_dto::solution::Flashloan> for Flashloan { - fn from(value: &solvers_dto::solution::Flashloan) -> Self { - Self { - liquidity_provider: value.liquidity_provider.into(), - protocol_adapter: value.protocol_adapter.into(), - receiver: value.receiver.into(), - token: value.token.into(), - amount: value.amount.into(), - } - } -} - -#[expect(clippy::from_over_into)] -impl Into for &Flashloan { - fn into(self) -> FlashloanHint { - FlashloanHint { - liquidity_provider: self.liquidity_provider.into(), - protocol_adapter: self.protocol_adapter.into(), - receiver: self.receiver.into(), - token: self.token.into(), - amount: self.amount.into(), - } - } -} diff --git a/crates/driver/src/domain/flashloan.rs b/crates/driver/src/domain/flashloan.rs new file mode 100644 index 0000000000..8329d29599 --- /dev/null +++ b/crates/driver/src/domain/flashloan.rs @@ -0,0 +1,51 @@ +use { + eth_domain_types::{Address, ContractAddress, TokenAddress, TokenAmount}, + solvers_dto::auction::FlashloanHint, +}; + +#[derive(Debug, Clone)] +pub struct Flashloan { + pub liquidity_provider: ContractAddress, + pub protocol_adapter: ContractAddress, + pub receiver: Address, + pub token: TokenAddress, + pub amount: TokenAmount, +} + +impl From<&solvers_dto::solution::Flashloan> for Flashloan { + fn from(value: &solvers_dto::solution::Flashloan) -> Self { + Self { + liquidity_provider: value.liquidity_provider.into(), + protocol_adapter: value.protocol_adapter.into(), + receiver: value.receiver, + token: value.token.into(), + amount: value.amount.into(), + } + } +} + +#[expect(clippy::from_over_into)] +impl Into for &Flashloan { + fn into(self) -> solvers_dto::solution::Flashloan { + solvers_dto::solution::Flashloan { + liquidity_provider: self.liquidity_provider.into(), + protocol_adapter: self.protocol_adapter.into(), + receiver: self.receiver, + token: self.token.0.into(), + amount: self.amount.into(), + } + } +} + +#[expect(clippy::from_over_into)] +impl Into for &Flashloan { + fn into(self) -> FlashloanHint { + FlashloanHint { + liquidity_provider: self.liquidity_provider.into(), + protocol_adapter: self.protocol_adapter.into(), + receiver: self.receiver, + token: self.token.0.into(), + amount: self.amount.into(), + } + } +} diff --git a/crates/driver/src/domain/interaction.rs b/crates/driver/src/domain/interaction.rs new file mode 100644 index 0000000000..a1d24c9dcf --- /dev/null +++ b/crates/driver/src/domain/interaction.rs @@ -0,0 +1,32 @@ +use { + alloy::primitives::Bytes, + eth_domain_types::{Address, Ether}, +}; + +/// An onchain transaction which interacts with a smart contract. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Interaction { + pub target: Address, + pub value: Ether, + pub call_data: Bytes, +} + +impl From for model::interaction::InteractionData { + fn from(interaction: Interaction) -> Self { + Self { + target: interaction.target, + value: interaction.value.0, + call_data: interaction.call_data.to_vec(), + } + } +} + +impl From for Interaction { + fn from(interaction: model::interaction::InteractionData) -> Self { + Self { + target: interaction.target, + value: interaction.value.into(), + call_data: interaction.call_data.into(), + } + } +} diff --git a/crates/driver/src/domain/liquidity/balancer/v2/mod.rs b/crates/driver/src/domain/liquidity/balancer/v2/mod.rs index 302fbea332..fc82db96a2 100644 --- a/crates/driver/src/domain/liquidity/balancer/v2/mod.rs +++ b/crates/driver/src/domain/liquidity/balancer/v2/mod.rs @@ -1,6 +1,6 @@ use { - crate::domain::eth, derive_more::{From, Into}, + eth_domain_types as eth, }; pub mod stable; @@ -13,12 +13,12 @@ pub mod weighted; /// * 20..22: the pool specialization /// * 22..32: the pool nonce #[derive(Clone, Copy, Debug, Eq, PartialEq, From, Into)] -pub struct Id(pub eth::H256); +pub struct Id(pub eth::B256); impl Id { /// Extracts the pool address configured in the ID. pub fn address(&self) -> eth::ContractAddress { - eth::H160::from_slice(&self.0[..20]).into() + eth::Address::from_slice(&self.0[..20]).into() } } diff --git a/crates/driver/src/domain/liquidity/balancer/v2/stable.rs b/crates/driver/src/domain/liquidity/balancer/v2/stable.rs index fbcdbbdb6d..c2013c2274 100644 --- a/crates/driver/src/domain/liquidity/balancer/v2/stable.rs +++ b/crates/driver/src/domain/liquidity/balancer/v2/stable.rs @@ -2,8 +2,9 @@ use { super::{Fee, Id, ScalingFactor}, crate::{ boundary, - domain::{eth, liquidity}, + domain::{self, liquidity}, }, + eth_domain_types as eth, itertools::Itertools, }; @@ -32,7 +33,7 @@ impl Pool { input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, - ) -> Result { + ) -> Result { if !self.reserves.has_tokens(&input.0.token, &output.0.token) { return Err(liquidity::InvalidSwap); } diff --git a/crates/driver/src/domain/liquidity/balancer/v2/weighted.rs b/crates/driver/src/domain/liquidity/balancer/v2/weighted.rs index 53da2a6ac8..df0a5debc8 100644 --- a/crates/driver/src/domain/liquidity/balancer/v2/weighted.rs +++ b/crates/driver/src/domain/liquidity/balancer/v2/weighted.rs @@ -2,8 +2,9 @@ use { super::{Fee, Id, ScalingFactor}, crate::{ boundary, - domain::{eth, liquidity}, + domain::{self, liquidity}, }, + eth_domain_types as eth, itertools::Itertools, }; @@ -37,7 +38,7 @@ impl Pool { input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, - ) -> Result { + ) -> Result { if !self.reserves.has_tokens(&input.0.token, &output.0.token) { return Err(liquidity::InvalidSwap); } @@ -123,7 +124,7 @@ impl Weight { } fn base() -> eth::U256 { - eth::U256::exp10(18) + eth::U256::from(10).pow(eth::U256::from(18)) } } diff --git a/crates/driver/src/domain/liquidity/mod.rs b/crates/driver/src/domain/liquidity/mod.rs index 2544958ec0..f72e51e8bc 100644 --- a/crates/driver/src/domain/liquidity/mod.rs +++ b/crates/driver/src/domain/liquidity/mod.rs @@ -2,8 +2,8 @@ #![allow(dead_code)] use { - crate::domain::eth, derive_more::{From, Into}, + eth_domain_types as eth, std::cmp::Ordering, }; diff --git a/crates/driver/src/domain/liquidity/swapr.rs b/crates/driver/src/domain/liquidity/swapr.rs index fd96d584af..41e5210449 100644 --- a/crates/driver/src/domain/liquidity/swapr.rs +++ b/crates/driver/src/domain/liquidity/swapr.rs @@ -1,6 +1,9 @@ -use crate::domain::{ - eth, - liquidity::{self, uniswap}, +use { + crate::domain::{ + self, + liquidity::{self, uniswap}, + }, + eth_domain_types as eth, }; /// The famous Uniswap V2 constant product pool with a twist of lemon, @@ -26,7 +29,7 @@ impl Pool { input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, - ) -> Result { + ) -> Result { // Note that swap interactions are identical in Swapr and Uniswap V2 // pools. The only difference is the input/output computation uses // different fees. diff --git a/crates/driver/src/domain/liquidity/uniswap/v2.rs b/crates/driver/src/domain/liquidity/uniswap/v2.rs index 07ee2e2667..d5f6a8d136 100644 --- a/crates/driver/src/domain/liquidity/uniswap/v2.rs +++ b/crates/driver/src/domain/liquidity/uniswap/v2.rs @@ -1,8 +1,9 @@ use { crate::{ boundary, - domain::{eth, liquidity}, + domain::{self, liquidity}, }, + eth_domain_types as eth, std::cmp::Ordering, }; @@ -31,7 +32,7 @@ impl Pool { input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, - ) -> Result { + ) -> Result { if !self.reserves.has_tokens(&input.0.token, &output.0.token) { return Err(liquidity::InvalidSwap); } diff --git a/crates/driver/src/domain/liquidity/uniswap/v3.rs b/crates/driver/src/domain/liquidity/uniswap/v3.rs index 8325db95a5..bd1de68744 100644 --- a/crates/driver/src/domain/liquidity/uniswap/v3.rs +++ b/crates/driver/src/domain/liquidity/uniswap/v3.rs @@ -2,11 +2,12 @@ use { crate::{ boundary, domain::{ - eth, + self, liquidity::{self, InvalidSwap}, }, }, derive_more::Debug, + eth_domain_types as eth, std::collections::BTreeMap, }; @@ -66,7 +67,7 @@ impl Pool { input: &liquidity::MaxInput, output: &liquidity::ExactOutput, receiver: ð::Address, - ) -> Result { + ) -> Result { let tokens_match = (input.0.token == self.tokens.0 && output.0.token == self.tokens.1) || (input.0.token == self.tokens.1 && output.0.token == self.tokens.0); diff --git a/crates/driver/src/domain/liquidity/zeroex.rs b/crates/driver/src/domain/liquidity/zeroex.rs index 93d8ac31ca..cae4192b49 100644 --- a/crates/driver/src/domain/liquidity/zeroex.rs +++ b/crates/driver/src/domain/liquidity/zeroex.rs @@ -1,9 +1,8 @@ use { - crate::domain::{eth, liquidity}, + crate::domain::{self, liquidity}, + alloy::primitives::{Address, B256, U256}, anyhow::anyhow, - contracts::alloy::IZeroex, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - primitive_types::{H160, H256, U256}, + contracts::IZeroex, std::sync::Arc, }; @@ -25,15 +24,15 @@ pub struct LimitOrder { #[derive(Clone, Debug)] pub struct Order { - pub maker: H160, - pub taker: H160, - pub sender: H160, - pub maker_token: H160, - pub taker_token: H160, + pub maker: Address, + pub taker: Address, + pub sender: Address, + pub maker_token: Address, + pub taker_token: Address, pub amounts: Amounts, pub taker_token_fee_amount: u128, - pub fee_recipient: H160, - pub pool: H256, + pub fee_recipient: Address, + pub pool: B256, pub expiry: u64, pub salt: U256, pub signature: ZeroExSignature, @@ -41,34 +40,37 @@ pub struct Order { #[derive(Clone, Debug)] pub struct ZeroExSignature { - pub r: H256, - pub s: H256, + pub r: B256, + pub s: B256, pub v: u8, pub signature_type: u8, } impl LimitOrder { - pub fn to_interaction(&self, input: &liquidity::MaxInput) -> anyhow::Result { + pub fn to_interaction( + &self, + input: &liquidity::MaxInput, + ) -> anyhow::Result { let method = self.zeroex.fillOrKillLimitOrder( IZeroex::LibNativeOrder::LimitOrder { - makerToken: self.order.maker_token.into_alloy(), - takerToken: self.order.taker_token.into_alloy(), + makerToken: self.order.maker_token, + takerToken: self.order.taker_token, makerAmount: self.order.amounts.maker, takerAmount: self.order.amounts.taker, takerTokenFeeAmount: self.order.taker_token_fee_amount, - maker: self.order.maker.into_alloy(), - taker: self.order.taker.into_alloy(), - sender: self.order.sender.into_alloy(), - feeRecipient: self.order.fee_recipient.into_alloy(), - pool: self.order.pool.into_alloy(), + maker: self.order.maker, + taker: self.order.taker, + sender: self.order.sender, + feeRecipient: self.order.fee_recipient, + pool: self.order.pool, expiry: self.order.expiry, - salt: self.order.salt.into_alloy(), + salt: self.order.salt, }, IZeroex::LibSignature::Signature { signatureType: self.order.signature.signature_type, v: self.order.signature.v, - r: self.order.signature.r.into_alloy(), - s: self.order.signature.s.into_alloy(), + r: self.order.signature.r, + s: self.order.signature.s, }, input .0 @@ -79,8 +81,8 @@ impl LimitOrder { ); let calldata = method.calldata(); - Ok(eth::Interaction { - target: self.zeroex.address().into_legacy().into(), + Ok(domain::Interaction { + target: *self.zeroex.address(), value: 0.into(), call_data: calldata.to_vec().into(), }) diff --git a/crates/driver/src/domain/mempools.rs b/crates/driver/src/domain/mempools.rs index 672c892535..95e2feb325 100644 --- a/crates/driver/src/domain/mempools.rs +++ b/crates/driver/src/domain/mempools.rs @@ -1,31 +1,46 @@ use { - super::{ - competition::{self, solution::settlement}, - eth, - }, + super::competition::solution::{GasFeeOverride, settlement}, crate::{ - domain::{ - BlockNo, - competition::solution::Settlement, - eth::{TxId, TxStatus}, - }, - infra::{self, Ethereum, observe, solver::Solver}, + domain::{blockchain::TxStatus, competition::solution::Settlement}, + infra::{self, Ethereum, observe}, }, - anyhow::Context, + alloy::{consensus::Transaction, eips::eip1559::Eip1559Estimation, primitives::Bytes}, + anyhow::{Context, anyhow}, + eth_domain_types::{self as eth, BlockNo, TxId}, ethrpc::block_stream::into_stream, futures::{FutureExt, StreamExt, future::select_ok}, - std::ops::Sub, + itertools::Itertools, + num::Saturating, thiserror::Error, tracing::Instrument, }; /// Factor by how much a transaction fee needs to be increased to override a -/// pending transaction at the same nonce. -const GAS_PRICE_BUMP: f64 = 1.125; +/// pending transaction at the same nonce. The correct factor is actually +/// 12.5% but to avoid rounding issues on chains with very low gas prices +/// we increase slightly more. +const GAS_PRICE_BUMP_PCT: u64 = 13; /// The gas amount required to cancel a transaction. const CANCELLATION_GAS_AMOUNT: u64 = 21000; +/// How the settlement transaction should be submitted on-chain. +#[derive(Debug, Clone)] +pub enum SubmissionMode { + /// Solver EOA signs and submits directly to the settlement contract. + Direct(eth::Address), + /// A dedicated submission EOA signs and pays for the tx while routing it + /// through the solver's EIP-7702 delegate. + Delegated { + /// The address that signs the transaction and whose nonce is used. + submitter_eoa: eth::Address, + /// The solver EOA address. In EIP-7702 mode tx.to is set to this + /// address (which delegates to Solver7702Delegate), instead of the + /// settlement contract. + solver_eoa: eth::Address, + }, +} + /// The mempools used to execute settlements. #[derive(Debug, Clone)] pub struct Mempools { @@ -42,65 +57,82 @@ impl Mempools { } } - /// Publish a settlement to the mempools. + /// Race the enabled mempools concurrently; first success wins. Pending + /// submission futures are dropped at that point and every other mempool is + /// recorded as `Superseded`. If every mempool fails, return one of the + /// failure errors. pub async fn execute( &self, - solver: &Solver, settlement: &Settlement, submission_deadline: BlockNo, + mode: &SubmissionMode, ) -> Result { - let (submission, _remaining_futures) = - select_ok(self.mempools.iter().cloned().map(|mempool| { + let mut stats = vec![Outcome::Superseded; self.mempools.len()]; + + let res = select_ok(self.mempools.iter().zip(stats.iter_mut()).map( + |(mempool, stat)| { async move { let result = self - .submit(&mempool, solver, settlement, submission_deadline) - .instrument(tracing::info_span!("mempool", kind = mempool.to_string())) + .submit(mempool, settlement, submission_deadline, mode) + .instrument(tracing::info_span!("mempool", kind = %mempool)) .await; - observe::mempool_executed(&mempool, settlement, &result); + // Log inline so errors from mempools that later get superseded still surface; + // metrics are emitted from `update_metrics` once the race outcome is known. + observe::mempool_log(mempool, settlement, &result); + *stat = Outcome::from(&result); result } .boxed() - })) - .await?; + }, + )) + .await + // Drop the remaining futures (and the mutable borrow on `stats` they + // carry) so `update_metrics` can read `stats` below. + .map(|(success, _remaining)| success); + + self.update_metrics(&stats); - Ok(submission.tx_hash) + Ok(res?.tx_hash) + } + + /// A mempool is disabled if all of the following are true: + /// * the settlement may revert (see [`Settlement::may_revert`]) + /// * the pool has revert protection enabled (see + /// [`Self::revert_protection`]) + /// * reverts can get mined (see [`infra::Mempool::reverts_can_get_mined`]) + fn is_disabled(&self, mempool: &infra::Mempool, settlement: &Settlement) -> bool { + settlement.may_revert() + && matches!(self.revert_protection(), RevertProtection::Enabled) + && mempool.reverts_can_get_mined() } /// Defines if the mempools are configured in a way that guarantees that /// settled solution will not revert. pub fn revert_protection(&self) -> RevertProtection { - if self.mempools.iter().any(|mempool| { - matches!( - mempool.config().kind, - infra::mempool::Kind::Public { - revert_protection: infra::mempool::RevertProtection::Disabled, - .. - } - ) - }) { - RevertProtection::Disabled - } else { - RevertProtection::Enabled + match self + .mempools + .iter() + .all(|mempool| mempool.reverts_can_get_mined()) + { + true => RevertProtection::Disabled, + false => RevertProtection::Enabled, } } async fn submit( &self, mempool: &infra::mempool::Mempool, - solver: &Solver, settlement: &Settlement, submission_deadline: BlockNo, + mode: &SubmissionMode, ) -> Result { - // Don't submit risky transactions if revert protection is - // enabled and the settlement may revert in this mempool. - if settlement.may_revert() - && matches!(self.revert_protection(), RevertProtection::Enabled) - && mempool.may_revert() - { + if self.is_disabled(mempool, settlement) { return Err(Error::Disabled); } let tx = settlement.transaction(settlement::Internalization::Enable); + let tx = prepare_submission(tx, mode); + let signer = tx.from; // Instantiate block stream and skip the current block before we submit the // settlement. This way we only run iterations in blocks that can potentially @@ -108,43 +140,84 @@ impl Mempools { let mut block_stream = into_stream(self.ethereum.current_block().clone()); block_stream.next().await; + let current_block = self.ethereum.current_block().borrow().number; // The tx is simulated before submitting the solution to the competition, but a // delay between that and the actual execution can cause the simulation to be // invalid which doesn't make sense to submit to the mempool anymore. - if let Err(err) = self.ethereum.estimate_gas(tx).await { - if err.is_revert() { - tracing::info!( - ?err, - "settlement tx simulation reverted before submitting to the mempool" - ); - let block = self.ethereum.current_block().borrow().number; - return Err(Error::SimulationRevert { - submitted_at_block: block, - reverted_at_block: block, - }); - } else { - tracing::warn!( - ?err, - "couldn't simulate tx before submitting to the mempool" - ); + if mempool.reverts_can_get_mined() { + if let Err(err) = self.ethereum.estimate_gas(tx.clone()).await { + if err.is_revert() { + tracing::info!( + ?err, + "settlement tx simulation reverted before submitting to the mempool" + ); + return Err(Error::SimulationRevert { + submitted_at_block: current_block.into(), + reverted_at_block: current_block.into(), + }); + } else { + tracing::warn!( + ?err, + "couldn't simulate tx before submitting to the mempool" + ); + } } + } else { + tracing::trace!("skipping tx simulation because mempool does not mine reverting txs"); } - // Fetch the pending nonce to avoid race conditions between concurrent - // transactions (e.g., settlement tx and cancellation tx) from the same - // solver address. - let nonce = mempool.get_pending_nonce(solver.address()).await?; - let hash = mempool - .submit(tx.clone(), settlement.gas, solver, nonce) - .await?; - let submitted_at_block = self.ethereum.current_block().borrow().number; + // Fetch the nonce for the signing account (not the solver in 7702 mode). + let nonce = mempool.get_nonce(signer).await?; + + // estimate the gas price such that the tx should still be included + // even if the gas price increases the maximum amount until the submission + // deadline + let current_gas_price = self + .ethereum + .gas_price() + .await + .context("failed to compute current gas price")?; + let submission_block = self.ethereum.current_block().borrow().number.into(); + let blocks_until_deadline = submission_deadline.saturating_sub(submission_block); + + // if there is still a tx pending we also have to make sure we outbid that one + // enough to make the node replace it in the mempool + let replacement_gas_price = self + .minimum_replacement_gas_price(mempool, signer, nonce) + .await; + let final_gas_price = match &replacement_gas_price { + Some(replacement_gas_price) + if replacement_gas_price.max_fee_per_gas > current_gas_price.max_fee_per_gas => + { + *replacement_gas_price + } + _ => current_gas_price, + }; + + let final_gas_price = apply_gas_fee_override( + final_gas_price, + settlement.gas_fee_override(), + replacement_gas_price.as_ref(), + ); + tracing::debug!( - ?hash, - current_block = ?submitted_at_block, - max_fee_per_gas = ?settlement.gas.price.max(), - priority_fee_per_gas = ?settlement.gas.price.tip(), - "submitted tx to the mempool" + ?submission_block, + ?blocks_until_deadline, + ?replacement_gas_price, + ?current_gas_price, + ?final_gas_price, + ?signer, + "submitting settlement tx" ); + let hash = mempool + .submit( + tx.clone(), + final_gas_price, + settlement.gas.limit, + signer, + nonce, + ) + .await?; // Wait for the transaction to be mined, expired or failing. let result = async { @@ -160,72 +233,105 @@ impl Mempools { }); match receipt { TxStatus::Executed { block_number } => return Ok(SubmissionSuccess { - tx_hash: hash.clone(), - submitted_at_block: submitted_at_block.into(), + tx_hash: hash, + submitted_at_block: submission_block, included_in_block: block_number, }), TxStatus::Reverted { block_number } => { return Err(Error::Revert { - tx_id: hash.clone(), - submitted_at_block, - reverted_at_block: block_number.into(), + tx_id: hash, + submitted_at_block: submission_block, + reverted_at_block: block_number, }) } TxStatus::Pending => { - let blocks_elapsed = block.number.sub(submitted_at_block); - // Check if the current block reached the submission deadline block number - if block.number >= submission_deadline { - let cancellation_tx_hash = self - .cancel(mempool, settlement.gas.price, solver, blocks_elapsed, nonce) - .await - .context("cancellation tx due to deadline failed")?; - tracing::info!( - settle_tx_hash = ?hash, - deadline = submission_deadline, + if BlockNo(block.number) >= submission_deadline { + tracing::debug!( + submission_deadline = submission_deadline.0, current_block = block.number, - ?cancellation_tx_hash, - "tx not confirmed in time, cancelling", + settle_tx_hash = ?hash, + "exceeded submission deadline, cancelling" ); + let _ = self + .cancel(mempool, final_gas_price, signer, nonce) + .await; return Err(Error::Expired { - tx_id: hash.clone(), - submitted_at_block, + tx_id: hash, + submitted_at_block: submission_block, submission_deadline, }); } - // Check if transaction still simulates - if let Err(err) = self.ethereum.estimate_gas(tx).await { - if err.is_revert() { - let cancellation_tx_hash = self - .cancel(mempool, settlement.gas.price, solver, blocks_elapsed, nonce) - .await - .context("cancellation tx due to revert failed")?; - tracing::info!( - settle_tx_hash = ?hash, - ?cancellation_tx_hash, - ?err, - "tx started failing in mempool, cancelling" - ); - return Err(Error::SimulationRevert { - submitted_at_block, - reverted_at_block: block.number, - }); - } else { - tracing::warn!(?hash, ?err, "couldn't re-simulate tx"); - } + // A node can report a new block before its receipt index catches up, + // so re-simulating reverts on our own already-applied tx. Tell that + // apart from a real revert with two signals: our `Settlement` event in + // any block since submission (which `eth_getLogs` sees even while the + // receipt lags), and the signer's pending nonce (which still covers our + // tx while it sits in the mempool). + let (gas, mined, pending_nonce) = futures::join!( + self.ethereum.estimate_gas(tx.clone()), + self.ethereum + .successful_settlement_block(hash, submission_block.0), + self.ethereum.pending_transaction_count(signer), + ); + + if let Ok(Some(included_in_block)) = mined { + // Found on-chain in [submission_block, head]. The receipt-by-hash + // lookup is just lagging, and scanning the whole range catches it + // even if the block stream coalesced past the block it mined in. + // Report success now rather than wait on the receipt and risk the + // deadline. + tracing::info!( + ?hash, + ?included_in_block, + "settlement found on-chain via getLogs, treating as success" + ); + return Ok(SubmissionSuccess { + tx_hash: hash, + submitted_at_block: submission_block, + included_in_block, + }); + } + + let resimulation_reverted = matches!(&gas, Err(err) if err.is_revert()); + if requires_cancellation(resimulation_reverted, &pending_nonce, nonce) { + tracing::info!( + settle_tx_hash = ?hash, + err = ?gas.as_ref().err(), + "tx started failing in mempool, cancelling" + ); + let _ = self.cancel(mempool, final_gas_price, signer, nonce).await; + return Err(Error::SimulationRevert { + submitted_at_block: submission_block, + reverted_at_block: block.number.into(), + }); + } else if let Err(err) = &pending_nonce { + tracing::warn!( + ?hash, + ?err, + "couldn't fetch the pending nonce, not cancelling" + ); + } else if resimulation_reverted { + tracing::debug!( + ?hash, + "detected false positive revert (already pending tx conflicted \ + with our simulation), waiting for next block" + ); + } else if let Err(err) = &gas { + tracing::warn!(?hash, ?err, "couldn't re-simulate tx"); } } } } - Err(Error::Other(anyhow::anyhow!( + Err(Error::Other(anyhow!( "Block stream finished unexpectedly" ))) } .await; if result.is_err() { - // Do one last attempt to see if the transaction was confirmed (in case of race - // conditions or misclassified errors like `OrderFilled` simulation failures). + // One last check in case the tx landed after the loop exited, e.g. the + // receipt finally caught up to a block we had already processed. if let Ok(TxStatus::Executed { block_number }) = self.ethereum.transaction_status(&hash).await { @@ -237,7 +343,7 @@ impl Mempools { return Ok(SubmissionSuccess { tx_hash: hash, included_in_block: block_number, - submitted_at_block: submitted_at_block.into(), + submitted_at_block: submission_block, }); } } @@ -249,45 +355,241 @@ impl Mempools { async fn cancel( &self, mempool: &infra::mempool::Mempool, - pending: eth::GasPrice, - solver: &Solver, - blocks_elapsed: u64, - nonce: eth::U256, + original_tx_gas_price: Eip1559Estimation, + signer: eth::Address, + nonce: u64, ) -> Result { + let fallback_gas_price = original_tx_gas_price.scaled_by_pct(GAS_PRICE_BUMP_PCT); + let replacement_gas_price = self + .minimum_replacement_gas_price(mempool, signer, nonce) + .await; + + // the node is the ultimate source of truth to compute the minimum + // replacement gas price, but if that fails for whatever reason + // we use our best estimate based on the originally submitted tx + let final_gas_price = match &replacement_gas_price { + Some(replacement) => *replacement, + _ => fallback_gas_price, + }; + let cancellation = eth::Tx { - from: solver.address(), - to: solver.address(), + from: signer, + to: signer, value: 0.into(), input: Default::default(), access_list: Default::default(), }; - let gas_price_bump_factor = GAS_PRICE_BUMP.powi(blocks_elapsed.max(1) as i32); - let new_gas_price = pending * gas_price_bump_factor; - let gas = competition::solution::settlement::Gas { - estimate: CANCELLATION_GAS_AMOUNT.into(), - limit: CANCELLATION_GAS_AMOUNT.into(), - price: new_gas_price, - }; + tracing::debug!( - ?blocks_elapsed, - original_gas_price = ?pending, - ?new_gas_price, - bump_factor = ?gas_price_bump_factor, - "Cancelling transaction with adjusted gas price" + ?replacement_gas_price, + ?fallback_gas_price, + ?final_gas_price, + "submitting cancellation tx" ); - mempool.submit(cancellation, gas, solver, nonce).await + mempool + .submit( + cancellation, + final_gas_price, + CANCELLATION_GAS_AMOUNT.into(), + signer, + nonce, + ) + .await + } + + /// Computes minimum price to replace the last tx that was submitted + /// with the given nonce. Returns `None` if no tx was submitted with + /// that nonce yet. + #[tracing::instrument(skip_all)] + async fn minimum_replacement_gas_price( + &self, + mempool: &infra::Mempool, + signer: eth::Address, + next_nonce: u64, + ) -> Option { + if let Some(last_submission) = mempool.last_submission(signer) { + if last_submission.nonce == next_nonce { + Some(last_submission.gas_price.scaled_by_pct(GAS_PRICE_BUMP_PCT)) + } else { + None + } + } else { + // If we don't have the last submission in-memory (i.e. first submission + // attempt after a restart) we try to inspect the nodes transaction mempool. + // This is only done as a backup since it can incur significant latency and + // is generally not very widely supported. + let pending_tx = mempool + .find_pending_tx_in_mempool(signer, next_nonce) + .await + .inspect_err(|err| tracing::debug!(?err, "could not inspect tx mempool")) + .ok()??; + + let pending_tx_gas_price = Eip1559Estimation { + max_fee_per_gas: pending_tx.max_fee_per_gas(), + max_priority_fee_per_gas: pending_tx.max_priority_fee_per_gas().or_else(|| { + tracing::error!(tx = ?pending_tx.inner.tx_hash(), "pending tx is not EIP 1559"); + None + })?, + }; + + Some(pending_tx_gas_price.scaled_by_pct(GAS_PRICE_BUMP_PCT)) + } + } + + /// Update per-mempool metrics based on submission outcomes. + /// + /// When a winner exists, `Failed` outcomes are reclassified as `Superseded` + /// since errors are typically race-condition false-positives. + fn update_metrics(&self, stats: &[Outcome]) { + let winner_exists = stats.iter().any(|s| matches!(s, Outcome::Success { .. })); + // Using `zip_eq` to catch regressions in tests (sizes always match in + // practice). + for (mempool, &outcome) in self.mempools.iter().zip_eq(stats.iter()) { + let label = match outcome { + Outcome::Failed { .. } if winner_exists => Outcome::Superseded.metric_label(), + other => other.metric_label(), + }; + observe::mempool_submission_result(mempool, label, outcome.blocks_passed()); + } + } +} + +#[derive(Clone, Copy)] +enum Outcome { + /// Submission future was dropped because another mempool won the race. + Superseded, + Success { + blocks_passed: u64, + }, + Failed { + reason: &'static str, + blocks_passed: Option, + }, + Disabled, +} + +impl Outcome { + fn metric_label(self) -> &'static str { + match self { + Outcome::Superseded => "Superseded", + Outcome::Success { .. } => "Success", + Outcome::Failed { reason, .. } => reason, + Outcome::Disabled => "Disabled", + } + } + + fn blocks_passed(self) -> Option { + match self { + Outcome::Superseded | Outcome::Disabled => None, + Outcome::Success { blocks_passed } => Some(blocks_passed), + Outcome::Failed { blocks_passed, .. } => blocks_passed, + } } } +impl From<&Result> for Outcome { + fn from(result: &Result) -> Self { + match result { + Ok(s) => Outcome::Success { + blocks_passed: s.blocks_passed(), + }, + Err(Error::Disabled) => Outcome::Disabled, + Err(err @ (Error::Revert { .. } | Error::SimulationRevert { .. })) => Outcome::Failed { + reason: "Revert", + blocks_passed: err.blocks_passed(), + }, + Err(err @ Error::Expired { .. }) => Outcome::Failed { + reason: "Expired", + blocks_passed: err.blocks_passed(), + }, + Err(Error::Other(_)) => Outcome::Failed { + reason: "Other", + blocks_passed: None, + }, + } + } +} + +/// Applies the solver's gas fee override if present. When a replacement +/// transaction is pending, the solver's values are raised to at least the +/// replacement minimum (a node requirement). +fn apply_gas_fee_override( + driver_estimate: Eip1559Estimation, + solver_override: Option, + replacement_price: Option<&Eip1559Estimation>, +) -> Eip1559Estimation { + let Some(gas_override) = solver_override else { + return driver_estimate; + }; + let solver_price = Eip1559Estimation { + max_fee_per_gas: gas_override.max_fee_per_gas, + max_priority_fee_per_gas: gas_override.max_priority_fee_per_gas, + }; + match replacement_price { + Some(replacement) => Eip1559Estimation { + max_fee_per_gas: std::cmp::max( + solver_price.max_fee_per_gas, + replacement.max_fee_per_gas, + ), + max_priority_fee_per_gas: std::cmp::max( + solver_price.max_priority_fee_per_gas, + replacement.max_priority_fee_per_gas, + ), + }, + None => solver_price, + } +} + +/// In EIP-7702 mode, reroute the tx through the solver EOA's delegate. Its +/// fallback expects the 20-byte target address followed by target calldata. +/// `from` is the submitter EOA so simulations see the correct `msg.sender` +/// for the delegate's caller whitelist. The solver EOA is in `tx.to` and +/// becomes `address(this)` when the delegate runs. +fn prepare_submission(tx: ð::Tx, mode: &SubmissionMode) -> eth::Tx { + let mut tx = tx.clone(); + match mode { + SubmissionMode::Direct(solver_eoa) => { + tx.from = *solver_eoa; + tx + } + SubmissionMode::Delegated { + submitter_eoa, + solver_eoa, + } => { + let original_target = tx.to; + tx.from = *submitter_eoa; + tx.to = *solver_eoa; + tx.input = delegated_calldata(original_target, &tx.input); + tx + } + } +} + +fn delegated_calldata(target: eth::Address, calldata: &Bytes) -> Bytes { + let mut input = Vec::with_capacity(target.len() + calldata.len()); + input.extend_from_slice(target.as_slice()); + input.extend_from_slice(calldata); + input.into() +} + pub struct SubmissionSuccess { pub tx_hash: eth::TxId, - /// At which block we started to submit the transaction. - pub included_in_block: eth::BlockNo, /// In which block the transaction actually appeared onchain. + pub included_in_block: eth::BlockNo, + /// At which block we started to submit the transaction. pub submitted_at_block: eth::BlockNo, } +impl SubmissionSuccess { + /// Number of blocks between submission start and on-chain inclusion. + pub fn blocks_passed(&self) -> u64 { + self.included_in_block + .saturating_sub(self.submitted_at_block) + .0 + } +} + #[derive(Debug, Error)] #[error("no mempools configured, cannot execute settlements")] pub struct NoMempools; @@ -302,13 +604,19 @@ pub enum RevertProtection { #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("Mined reverted transaction: {tx_id:?}, block number: {reverted_at_block}")] + #[error( + "Mined reverted transaction: {tx_id:?}, block number: {reverted_at_block}, submitted at \ + block: {submitted_at_block}" + )] Revert { tx_id: eth::TxId, submitted_at_block: BlockNo, reverted_at_block: BlockNo, }, - #[error("Simulation started reverting during submission, block number: {reverted_at_block}")] + #[error( + "Simulation started reverting during submission, block number: {reverted_at_block}, \ + submitted at block: {submitted_at_block}" + )] SimulationRevert { submitted_at_block: BlockNo, reverted_at_block: BlockNo, @@ -327,3 +635,114 @@ pub enum Error { #[error("Failed to submit: {0:?}")] Other(#[from] anyhow::Error), } + +impl Error { + /// Number of blocks between the first submission and when the error was + /// returned, if the error carries that timing. + pub fn blocks_passed(&self) -> Option { + let (start, end) = match self { + Self::Revert { + submitted_at_block, + reverted_at_block, + .. + } + | Self::SimulationRevert { + submitted_at_block, + reverted_at_block, + } => (*submitted_at_block, *reverted_at_block), + Self::Expired { + submitted_at_block, + submission_deadline, + .. + } => (*submitted_at_block, *submission_deadline), + Self::Disabled | Self::Other(_) => return None, + }; + Some(end.saturating_sub(start).0) + } +} + +/// Whether a submitted settlement whose receipt is missing should be cancelled. +/// We cancel only when the re-simulation reverts and the signer's pending nonce +/// shows our tx is gone from the mempool (`pending_nonce <= submission_nonce`, +/// so it was neither mined nor is it still queued). While the tx is still +/// queued the revert is just our own pending tx re-applied, a false positive, +/// so we keep waiting. A failed nonce lookup counts as "unknown" and never +/// cancels. +fn requires_cancellation( + resimulation_reverted: bool, + pending_nonce: &Result, + submission_nonce: u64, +) -> bool { + resimulation_reverted && matches!(pending_nonce, Ok(n) if *n <= submission_nonce) +} + +#[cfg(test)] +mod tests { + use { + super::*, + alloy::primitives::{Bytes, address}, + }; + + const ORIGINAL_FROM: eth::Address = address!("0000000000000000000000000000000000000001"); + const SETTLEMENT: eth::Address = address!("0000000000000000000000000000000000000002"); + const SOLVER: eth::Address = address!("0000000000000000000000000000000000000003"); + const SUBMITTER: eth::Address = address!("0000000000000000000000000000000000000004"); + + fn tx(input: Bytes) -> eth::Tx { + eth::Tx { + from: ORIGINAL_FROM, + to: SETTLEMENT, + value: 0.into(), + input, + access_list: Default::default(), + } + } + + #[test] + fn delegated_submission_rewrites_transaction() { + let prepared = prepare_submission( + &tx(Bytes::from_static(&[0xaa, 0xbb])), + &SubmissionMode::Delegated { + submitter_eoa: SUBMITTER, + solver_eoa: SOLVER, + }, + ); + let mut expected = SETTLEMENT.as_slice().to_vec(); + expected.extend_from_slice(&[0xaa, 0xbb]); + + assert_eq!(prepared.from, SUBMITTER); + assert_eq!(prepared.to, SOLVER); + assert_eq!(prepared.input, Bytes::from(expected)); + } + + const SUBMISSION_NONCE: u64 = 7; + const STILL_QUEUED: Result = Ok(8); // pending advanced past our nonce + const DROPPED: Result = Ok(7); // pending still at our nonce, tx is gone + const NONCE_LOOKUP_FAILED: Result = Err(()); + + #[test] + fn cancels_only_when_reverted_and_tx_left_the_mempool() { + // Reverted and the tx is no longer queued: a real revert, cancel. + assert!(requires_cancellation(true, &DROPPED, SUBMISSION_NONCE)); + // Reverted but still queued: the revert is our own pending tx, so wait. + assert!(!requires_cancellation( + true, + &STILL_QUEUED, + SUBMISSION_NONCE + )); + // Re-simulation still succeeds: wait regardless of the nonce. + assert!(!requires_cancellation(false, &DROPPED, SUBMISSION_NONCE)); + } + + #[test] + fn failed_nonce_lookup_never_cancels() { + // An unknown pending nonce must never trigger a cancel, even on a revert. + // Otherwise a flaky nonce lookup reverts to the original bug: cancelling a + // tx that may have mined or is still queued. + assert!(!requires_cancellation( + true, + &NONCE_LOOKUP_FAILED, + SUBMISSION_NONCE + )); + } +} diff --git a/crates/driver/src/domain/mod.rs b/crates/driver/src/domain/mod.rs index cc7bb1bc7d..29590c611a 100644 --- a/crates/driver/src/domain/mod.rs +++ b/crates/driver/src/domain/mod.rs @@ -1,6 +1,8 @@ +pub mod blockchain; pub mod competition; pub mod cow_amm; -pub mod eth; +pub mod flashloan; +pub mod interaction; pub mod liquidity; pub mod mempools; pub mod quote; @@ -8,8 +10,8 @@ pub mod time; pub use { competition::Competition, + flashloan::Flashloan, + interaction::Interaction, liquidity::Liquidity, mempools::{Mempools, RevertProtection}, }; - -pub type BlockNo = u64; diff --git a/crates/driver/src/domain/quote.rs b/crates/driver/src/domain/quote.rs index 0fd50b101a..efba437c20 100644 --- a/crates/driver/src/domain/quote.rs +++ b/crates/driver/src/domain/quote.rs @@ -1,10 +1,10 @@ use { - super::competition::{auction, solution}, + super::competition::{auction, risk_detector, solution}, crate::{ boundary, domain::{ + self, competition::{self, order}, - eth, liquidity, time, }, @@ -16,41 +16,38 @@ use { util, }, chrono::Utc, - ethrpc::alloy::conversions::IntoLegacy, - std::{ - collections::{HashMap, HashSet}, - iter, - }, + eth_domain_types as eth, + std::collections::{HashMap, HashSet}, }; /// A quote describing the expected outcome of an order. -#[derive(Debug)] +#[derive(derive_more::Debug)] pub struct Quote { - pub clearing_prices: HashMap, - pub pre_interactions: Vec, - pub interactions: Vec, + pub clearing_prices: HashMap, + #[debug(ignore)] + pub pre_interactions: Vec, + #[debug(ignore)] + pub interactions: Vec, pub solver: eth::Address, pub gas: Option, /// Which `tx.origin` is required to make the quote simulation pass. + #[debug(ignore)] pub tx_origin: Option, + #[debug(ignore)] pub jit_orders: Vec, } impl Quote { fn try_new(eth: &Ethereum, solution: competition::Solution) -> Result { + let clearing_prices = Self::compute_clearing_prices(&solution)?; + Ok(Self { - clearing_prices: solution - .clearing_prices() - .into_iter() - .map(|(token, amount)| (token.into(), amount)) - .collect(), + clearing_prices, pre_interactions: solution.pre_interactions().to_vec(), interactions: solution .interactions() .iter() - .map(|i| { - encode::interaction(i, eth.contracts().settlement().address().into_legacy()) - }) + .map(|i| encode::interaction(i, eth.contracts().settlement().address())) .collect::, _>>()? .into_iter() .flatten() @@ -68,6 +65,50 @@ impl Quote { .collect(), }) } + + /// Compute clearing prices for the quote. + /// + /// Uses uniform clearing prices from the solution, adjusted for haircut + /// when enabled. Uses `custom_prices()` which includes haircut effects + /// to make quotes conservative for users. + fn compute_clearing_prices( + solution: &competition::Solution, + ) -> Result, Error> { + // Start with uniform clearing prices + let mut prices: HashMap = solution + .clearing_prices() + .into_iter() + .map(|(token, amount)| (token.into(), amount)) + .collect(); + + // Quote competitions contain only a single order (see `fake_auction()`), + // so there's at most one fulfillment in the solution. + // Apply haircut adjustment to prices if there's a fulfillment with non-zero + // haircut. + if let Some(trade) = solution.trades().iter().find(|trade| match trade { + solution::Trade::Fulfillment(f) => f.haircut_fee() > eth::U256::ZERO, + _ => false, + }) { + let sell_token: eth::Address = trade.sell().token.into(); + let buy_token: eth::Address = trade.buy().token.into(); + let uniform_clearing = solution::trade::ClearingPrices { + sell: *prices + .get(&sell_token) + .ok_or(QuotingFailed::ClearingSellMissing)?, + buy: *prices + .get(&buy_token) + .ok_or(QuotingFailed::ClearingBuyMissing)?, + }; + let custom_prices = trade + .custom_prices(&uniform_clearing) + .map_err(|_| QuotingFailed::Math)?; + + prices.insert(sell_token, custom_prices.sell); + prices.insert(buy_token, custom_prices.buy); + } + + Ok(prices) + } } /// An order which needs to be quoted. @@ -90,11 +131,12 @@ impl Order { solver: &Solver, liquidity: &infra::liquidity::Fetcher, tokens: &infra::tokens::Fetcher, + risk_detector: &risk_detector::Detector, ) -> Result { let liquidity = match solver.liquidity() { solver::Liquidity::Fetch => { liquidity - .fetch(&self.liquidity_pairs(), infra::liquidity::AtBlock::Recent) + .fetch(&self.token_liquidity(), infra::liquidity::AtBlock::Recent) .await } solver::Liquidity::Skip => Default::default(), @@ -103,6 +145,12 @@ impl Order { let auction = self .fake_auction(eth, tokens, solver.quote_using_limit_orders()) .await?; + let auction = risk_detector + .filter_unsupported_orders_in_auction(auction) + .await; + if auction.orders.is_empty() { + return Err(QuotingFailed::UnsupportedToken.into()); + } let solutions = solver.solve(&auction, &liquidity).await?; Quote::try_new( eth, @@ -129,33 +177,35 @@ impl Order { competition::Auction::new( None, vec![competition::Order { - uid: Default::default(), - receiver: None, - created: u32::try_from(Utc::now().timestamp()) - .unwrap_or(u32::MIN) - .into(), - valid_to: util::Timestamp::MAX, - buy: self.buy(), - sell: self.sell(), - side: self.side, - kind: if quote_using_limit_orders { - competition::order::Kind::Limit - } else { - competition::order::Kind::Market - }, + data: std::sync::Arc::new(competition::order::OrderData { + uid: Default::default(), + receiver: None, + created: u32::try_from(Utc::now().timestamp()) + .unwrap_or(u32::MIN) + .into(), + valid_to: util::Timestamp::MAX, + buy: self.buy(), + sell: self.sell(), + side: self.side, + kind: if quote_using_limit_orders { + competition::order::Kind::Limit + } else { + competition::order::Kind::Market + }, + pre_interactions: Default::default(), + post_interactions: Default::default(), + sell_token_balance: competition::order::SellTokenBalance::Erc20, + buy_token_balance: competition::order::BuyTokenBalance::Erc20, + signature: competition::order::Signature { + scheme: competition::order::signature::Scheme::Eip1271, + data: Default::default(), + signer: Default::default(), + }, + protocol_fees: Default::default(), + quote: Default::default(), + }), app_data: Default::default(), partial: competition::order::Partial::No, - pre_interactions: Default::default(), - post_interactions: Default::default(), - sell_token_balance: competition::order::SellTokenBalance::Erc20, - buy_token_balance: competition::order::BuyTokenBalance::Erc20, - signature: competition::order::Signature { - scheme: competition::order::signature::Scheme::Eip1271, - data: Default::default(), - signer: Default::default(), - }, - protocol_fees: Default::default(), - quote: Default::default(), }], [ auction::Token { @@ -191,7 +241,7 @@ impl Order { fn buy(&self) -> eth::Asset { match self.side { order::Side::Sell => eth::Asset { - amount: eth::U256::one().into(), + amount: eth::U256::ONE.into(), token: self.tokens.buy, }, order::Side::Buy => eth::Asset { @@ -219,22 +269,23 @@ impl Order { // contract level. Requiring to trade more than `type(uint112).max` // is unlikely and would not work with Uniswap V2 anyway. order::Side::Buy => eth::Asset { - amount: (eth::U256::one() << 144).into(), + // NOTE: the saturating strategy here is slightly irrelevant since we know that 1 << + // 144 fits within U256 + amount: (eth::U256::ONE.saturating_shl(144)).into(), token: self.tokens.sell, }, } } /// Returns the token pairs to fetch liquidity for. - fn liquidity_pairs(&self) -> HashSet { - let pair = liquidity::TokenPair::try_new(self.tokens.sell(), self.tokens.buy()) - .expect("sell != buy by construction"); - iter::once(pair).collect() + fn token_liquidity(&self) -> HashSet { + liquidity::TokenPair::try_new(self.tokens.sell(), self.tokens.buy()) + .ok() + .into_iter() + .collect() } } -/// The sell and buy tokens to quote for. This type maintains the invariant that -/// the sell and buy tokens are distinct. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct Tokens { sell: eth::TokenAddress, @@ -242,13 +293,8 @@ pub struct Tokens { } impl Tokens { - /// Creates a new instance of [`Tokens`], verifying that the input buy and - /// sell tokens are distinct. - pub fn try_new(sell: eth::TokenAddress, buy: eth::TokenAddress) -> Result { - if sell == buy { - return Err(SameTokens); - } - Ok(Self { sell, buy }) + pub fn new(sell: eth::TokenAddress, buy: eth::TokenAddress) -> Self { + Self { sell, buy } } pub fn sell(&self) -> eth::TokenAddress { @@ -262,14 +308,9 @@ impl Tokens { mod encode { use { - crate::domain::{ - competition::solution, - eth::{ - self, - allowance::{Approval, Required}, - }, - }, - ethcontract::H160, + crate::domain::{self, competition::solution}, + alloy::primitives::Address, + eth_domain_types::allowance::{Approval, Required}, num::rational::Ratio, }; @@ -277,8 +318,8 @@ mod encode { pub(super) fn interaction( interaction: &solution::Interaction, - settlement: H160, - ) -> Result, solution::encoding::Error> { + settlement: &Address, + ) -> Result, solution::encoding::Error> { let slippage = solution::slippage::Parameters { relative: Ratio::new_raw(DEFAULT_QUOTE_SLIPPAGE_BPS.into(), 10_000.into()), max: None, @@ -287,9 +328,9 @@ mod encode { }; let encoded = match interaction { - solution::Interaction::Custom(interaction) => eth::Interaction { + solution::Interaction::Custom(interaction) => domain::Interaction { value: interaction.value, - target: interaction.target.0.into(), + target: *interaction.target, call_data: interaction.call_data.clone(), }, solution::Interaction::Liquidity(liquidity) => { @@ -348,6 +389,10 @@ pub enum QuotingFailed { ClearingBuyMissing, #[error("solver returned no solutions")] NoSolutions, + #[error("math error computing custom prices")] + Math, + #[error("token is unsupported by this solver")] + UnsupportedToken, } #[derive(Debug, thiserror::Error)] diff --git a/crates/driver/src/infra/api/error.rs b/crates/driver/src/infra/api/error.rs index 52629bdf3f..0b6529fa88 100644 --- a/crates/driver/src/infra/api/error.rs +++ b/crates/driver/src/infra/api/error.rs @@ -4,9 +4,11 @@ use { infra::{api, blockchain}, }, serde::Serialize, + solvers_dto, + std::borrow::Cow, }; -#[derive(Debug, Clone, Copy, Serialize)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize)] #[serde(rename_all = "PascalCase")] enum Kind { QuotingFailed, @@ -23,16 +25,20 @@ enum Kind { FailedToSubmit, NoValidOrders, MalformedRequest, + TradingOutsideAllowedWindow, + TokenTemporarilySuspended, + InsufficientLiquidity, + CustomSolverError, } #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Error { kind: Kind, - description: &'static str, + description: Cow<'static, str>, } -impl From for (hyper::StatusCode, axum::Json) { +impl From for (axum::http::StatusCode, axum::Json) { fn from(value: Kind) -> Self { let description = match value { Kind::QuotingFailed => "No valid quote found", @@ -57,19 +63,67 @@ impl From for (hyper::StatusCode, axum::Json) { Kind::TooManyPendingSettlements => "Settlement queue is full", Kind::NoValidOrders => "No valid orders found in the auction", Kind::MalformedRequest => "Could not parse the request", + Kind::TradingOutsideAllowedWindow => { + "Token can only be traded during specific time windows" + } + Kind::TokenTemporarilySuspended => "Token is temporarily suspended from trading", + Kind::InsufficientLiquidity => "Insufficient liquidity for the requested trade size", + Kind::CustomSolverError => "Solver returned a custom error", }; ( - hyper::StatusCode::BAD_REQUEST, + axum::http::StatusCode::BAD_REQUEST, axum::Json(Error { kind: value, - description, + description: description.into(), }), ) } } -impl From for (hyper::StatusCode, axum::Json) { +fn map_custom_solver_error(custom_err: &solvers_dto::solution::SolverError) -> (Kind, String) { + let (kind, default_message) = match custom_err.code { + solvers_dto::solution::SolverErrorCode::TradingOutsideAllowedWindow => ( + Kind::TradingOutsideAllowedWindow, + "Token can only be traded during specific time windows", + ), + solvers_dto::solution::SolverErrorCode::TokenTemporarilySuspended => ( + Kind::TokenTemporarilySuspended, + "Token is temporarily suspended from trading", + ), + solvers_dto::solution::SolverErrorCode::InsufficientLiquidity => ( + Kind::InsufficientLiquidity, + "Insufficient liquidity for the requested trade size", + ), + solvers_dto::solution::SolverErrorCode::Other => { + (Kind::CustomSolverError, "Solver returned a custom error") + } + }; + + let message = custom_err + .message + .clone() + .unwrap_or_else(|| default_message.to_string()); + + (kind, message) +} + +impl From for (axum::http::StatusCode, axum::Json) { fn from(value: quote::Error) -> Self { + // Check if this is a custom solver error + if let quote::Error::Solver(ref solver_err) = value + && let Some(custom_err) = solver_err.custom_error() + { + tracing::warn!(err=?custom_err, "received custom solver error, mapping to internal errors"); + let (kind, description) = map_custom_solver_error(custom_err); + return ( + axum::http::StatusCode::BAD_REQUEST, + axum::Json(Error { + kind, + description: description.into(), + }), + ); + } + let error = match value { quote::Error::QuotingFailed(_) => Kind::QuotingFailed, quote::Error::DeadlineExceeded(_) => Kind::DeadlineExceeded, @@ -82,7 +136,7 @@ impl From for (hyper::StatusCode, axum::Json) { } } -impl From for (hyper::StatusCode, axum::Json) { +impl From for (axum::http::StatusCode, axum::Json) { fn from(value: competition::Error) -> Self { let error = match value { competition::Error::SolutionNotAvailable => Kind::SolutionNotAvailable, @@ -97,13 +151,13 @@ impl From for (hyper::StatusCode, axum::Json) { } } -impl From for (hyper::StatusCode, axum::Json) { +impl From for (axum::http::StatusCode, axum::Json) { fn from(_: blockchain::Error) -> Self { Kind::Unknown.into() } } -impl From for (hyper::StatusCode, axum::Json) { +impl From for (axum::http::StatusCode, axum::Json) { fn from(value: api::routes::AuctionError) -> Self { let error = match value { api::routes::AuctionError::InvalidAuctionId => Kind::InvalidAuctionId, @@ -116,7 +170,7 @@ impl From for (hyper::StatusCode, axum::Json) } } -impl From for (hyper::StatusCode, axum::Json) { +impl From for (axum::http::StatusCode, axum::Json) { fn from(value: api::routes::OrderError) -> Self { let error = match value { api::routes::OrderError::SameTokens => Kind::QuoteSameTokens, @@ -124,3 +178,57 @@ impl From for (hyper::StatusCode, axum::Json) { error.into() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn maps_custom_solver_error_codes_to_kinds_and_default_messages() { + let cases = [ + ( + solvers_dto::solution::SolverErrorCode::TradingOutsideAllowedWindow, + Kind::TradingOutsideAllowedWindow, + "Token can only be traded during specific time windows", + ), + ( + solvers_dto::solution::SolverErrorCode::TokenTemporarilySuspended, + Kind::TokenTemporarilySuspended, + "Token is temporarily suspended from trading", + ), + ( + solvers_dto::solution::SolverErrorCode::InsufficientLiquidity, + Kind::InsufficientLiquidity, + "Insufficient liquidity for the requested trade size", + ), + ( + solvers_dto::solution::SolverErrorCode::Other, + Kind::CustomSolverError, + "Solver returned a custom error", + ), + ]; + + for (code, expected_kind, expected_message) in cases { + let custom_err = solvers_dto::solution::SolverError { + code, + message: None, + }; + + let (kind, message) = map_custom_solver_error(&custom_err); + assert_eq!(kind, expected_kind); + assert_eq!(message, expected_message); + } + } + + #[test] + fn preserves_custom_solver_error_message_when_provided() { + let custom_err = solvers_dto::solution::SolverError { + code: solvers_dto::solution::SolverErrorCode::Other, + message: Some("downstream solver reason".to_string()), + }; + + let (kind, message) = map_custom_solver_error(&custom_err); + assert!(matches!(kind, Kind::CustomSolverError)); + assert_eq!(message, "downstream solver reason"); + } +} diff --git a/crates/driver/src/infra/api/extract.rs b/crates/driver/src/infra/api/extract.rs new file mode 100644 index 0000000000..74663d8921 --- /dev/null +++ b/crates/driver/src/infra/api/extract.rs @@ -0,0 +1,69 @@ +//! Axum extractors that emit a `warn` log when request deserialization +//! fails, then delegate to the stock extractor's rejection so the HTTP +//! response shape is unchanged. + +use { + axum::{ + extract::{ + FromRequest, + FromRequestParts, + Request, + rejection::{JsonRejection, QueryRejection}, + }, + http::request::Parts, + }, + serde::de::DeserializeOwned, +}; + +/// JSON extractor that wraps Axum's native one and logs deserialization +/// errors. +pub struct LoggingJson(pub T); + +impl FromRequest for LoggingJson +where + S: Send + Sync, + T: DeserializeOwned, +{ + type Rejection = JsonRejection; + + async fn from_request(req: Request, state: &S) -> Result { + match axum::Json::::from_request(req, state).await { + Ok(axum::Json(value)) => Ok(Self(value)), + Err(rejection) => { + tracing::warn!( + err = %rejection, + target = std::any::type_name::(), + "failed to deserialize JSON request body", + ); + Err(rejection) + } + } + } +} + +/// Query extractor that wraps Axum's native one and logs deserialization +/// errors. +pub struct LoggingQuery(pub T); + +impl FromRequestParts for LoggingQuery +where + S: Send + Sync, + T: DeserializeOwned, +{ + type Rejection = QueryRejection; + + async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { + match axum::extract::Query::::from_request_parts(parts, state).await { + Ok(axum::extract::Query(value)) => Ok(Self(value)), + Err(rejection) => { + tracing::warn!( + err = %rejection, + target = std::any::type_name::(), + query = parts.uri.query().unwrap_or_default(), + "failed to deserialize query string", + ); + Err(rejection) + } + } + } +} diff --git a/crates/driver/src/infra/api/mod.rs b/crates/driver/src/infra/api/mod.rs index fbfa63ade5..0ba4ad0441 100644 --- a/crates/driver/src/infra/api/mod.rs +++ b/crates/driver/src/infra/api/mod.rs @@ -3,12 +3,15 @@ use { domain::{ self, Mempools, - competition::{bad_tokens, order::app_data::AppDataRetriever, sorting}, + competition::{ + order::app_data::AppDataRetriever, + risk_detector::{self, bad_orders}, + sorting, + }, }, infra::{ self, Ethereum, - Simulator, config::file::OrderPriorityStrategy, liquidity, notify, @@ -18,17 +21,16 @@ use { }, error::Error, futures::Future, - observe::distributed_tracing::tracing_axum::{make_span, record_trace_id}, - shared::account_balances, + observe::tracing::distributed::axum::{make_span, record_trace_id}, + simulator::Simulator, std::{net::SocketAddr, sync::Arc}, tokio::sync::oneshot, }; mod error; +mod extract; pub mod routes; -const REQUEST_BODY_LIMIT: usize = 10 * 1024 * 1024; - pub struct Api { pub solvers: Vec, pub liquidity: liquidity::Fetcher, @@ -37,7 +39,7 @@ pub struct Api { pub eth: Ethereum, pub mempools: Mempools, pub addr: SocketAddr, - pub bad_token_detector: bad_tokens::simulation::Detector, + pub bad_token_detector: risk_detector::bad_tokens::Detector, /// If this channel is specified, the bound address will be sent to it. This /// allows the driver to bind to 0.0.0.0:0 during testing. pub addr_sender: Option>, @@ -49,11 +51,9 @@ impl Api { shutdown: impl Future + Send + 'static, order_priority_strategies: Vec, app_data_retriever: Option, - ) -> Result<(), hyper::Error> { + ) -> Result<(), std::io::Error> { // Add middleware. - let mut app = axum::Router::new().layer(tower::ServiceBuilder::new().layer( - tower_http::limit::RequestBodyLimitLayer::new(REQUEST_BODY_LIMIT), - )); + let mut app = axum::Router::new(); let balance_fetcher = account_balances::cached( self.eth.web3(), @@ -92,21 +92,22 @@ impl Api { let router = routes::solve(router); let router = routes::reveal(router); let router = routes::settle(router); - let router = routes::notify(router); - let bad_token_config = solver.bad_token_detection(); + let bad_order_config = solver.bad_order_detection(); let mut bad_tokens = - bad_tokens::Detector::new(bad_token_config.tokens_supported.clone()); - if bad_token_config.enable_simulation_strategy { + risk_detector::Detector::new(bad_order_config.tokens_supported.clone()); + if bad_order_config.enable_simulation_strategy { bad_tokens.with_simulation_detector(self.bad_token_detector.clone()); } - if bad_token_config.enable_metrics_strategy { - bad_tokens.with_metrics_detector(bad_tokens::metrics::Detector::new( - bad_token_config.metrics_strategy_failure_ratio, - bad_token_config.metrics_strategy_required_measurements, - bad_token_config.metrics_strategy_log_only, - bad_token_config.metrics_strategy_token_freeze_time, + if bad_order_config.enable_metrics_strategy { + bad_tokens.with_metrics_detector(bad_orders::metrics::Detector::new( + bad_order_config.metrics_strategy_failure_ratio, + bad_order_config.metrics_strategy_required_measurements, + bad_order_config.metrics_strategy_log_only, + bad_order_config.metrics_strategy_order_freeze_time, + bad_order_config.metrics_strategy_cache_gc_interval, + bad_order_config.metrics_strategy_cache_max_age, name.clone(), )); } @@ -134,8 +135,10 @@ impl Api { } app = app - // axum's default body limit needs to be disabled to not have the default limit on top of our custom limit + // axum's default body limit is 2MB too low for solvers, 20MB is still too low + // so instead of constantly guessing and updating, we disable the limit altogether .layer(axum::extract::DefaultBodyLimit::disable()) + .layer(tower_http::decompression::RequestDecompressionLayer::new()) .layer( tower::ServiceBuilder::new() .layer(tower_http::trace::TraceLayer::new_for_http().make_span_with(make_span)) @@ -143,12 +146,15 @@ impl Api { ); // Start the server. - let server = axum::Server::bind(&self.addr).serve(app.into_make_service()); - tracing::info!(port = server.local_addr().port(), "serving driver"); + let listener = tokio::net::TcpListener::bind(self.addr).await?; + let local_addr = listener.local_addr()?; + tracing::info!(port = local_addr.port(), "serving driver"); if let Some(addr_sender) = self.addr_sender { - addr_sender.send(server.local_addr()).unwrap(); + addr_sender.send(local_addr).unwrap(); } - server.with_graceful_shutdown(shutdown).await + axum::serve(listener, app) + .with_graceful_shutdown(shutdown) + .await } fn build_order_sorting_strategies( @@ -190,7 +196,7 @@ impl State { &self.0.solver } - fn competition(&self) -> &domain::Competition { + fn competition(&self) -> &Arc { &self.0.competition } diff --git a/crates/driver/src/infra/api/routes/gasprice.rs b/crates/driver/src/infra/api/routes/gasprice.rs index a89097be3a..f495e3ec66 100644 --- a/crates/driver/src/infra/api/routes/gasprice.rs +++ b/crates/driver/src/infra/api/routes/gasprice.rs @@ -1,12 +1,7 @@ use { - crate::{ - domain::eth, - infra::{Ethereum, api::error::Error}, - util::serialize, - }, + crate::infra::{Ethereum, api::error::Error}, + alloy::eips::eip1559::Eip1559Estimation, axum::Json, - serde::{Deserialize, Serialize}, - serde_with::serde_as, tracing::instrument, }; @@ -14,29 +9,15 @@ pub(in crate::infra::api) fn gasprice(app: axum::Router) -> axum::Rout app.route("/gasprice", axum::routing::get(route)) } -/// Gas price components in EIP-1559 format. -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GasPriceResponse { - #[serde_as(as = "serialize::U256")] - pub max_fee_per_gas: eth::U256, - #[serde_as(as = "serialize::U256")] - pub max_priority_fee_per_gas: eth::U256, - #[serde_as(as = "serialize::U256")] - pub base_fee_per_gas: eth::U256, -} - #[instrument(skip(eth))] async fn route( eth: axum::extract::State, -) -> Result, (hyper::StatusCode, axum::Json)> { +) -> Result, (axum::http::StatusCode, axum::Json)> { // For simplicity we use the default time limit (None) - let gas_price = eth.gas_price(None).await?; + let gas_price = eth.gas_price().await?; - Ok(Json(GasPriceResponse { - max_fee_per_gas: gas_price.max().0.0, - max_priority_fee_per_gas: gas_price.tip().0.0, - base_fee_per_gas: gas_price.base().0.0, + Ok(Json(Eip1559Estimation { + max_fee_per_gas: gas_price.max_fee_per_gas, + max_priority_fee_per_gas: gas_price.max_priority_fee_per_gas, })) } diff --git a/crates/driver/src/infra/api/routes/healthz.rs b/crates/driver/src/infra/api/routes/healthz.rs index 157f557a93..62fc74b469 100644 --- a/crates/driver/src/infra/api/routes/healthz.rs +++ b/crates/driver/src/infra/api/routes/healthz.rs @@ -1,9 +1,13 @@ -use axum::{http::StatusCode, response::IntoResponse, routing::get}; +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, + routing::get, +}; pub(in crate::infra::api) fn healthz(app: axum::Router<()>) -> axum::Router<()> { app.route("/healthz", get(route)) } -async fn route() -> impl IntoResponse { - StatusCode::OK +async fn route() -> Response { + StatusCode::OK.into_response() } diff --git a/crates/driver/src/infra/api/routes/mod.rs b/crates/driver/src/infra/api/routes/mod.rs index dcd4afffc8..9ea3bdf93f 100644 --- a/crates/driver/src/infra/api/routes/mod.rs +++ b/crates/driver/src/infra/api/routes/mod.rs @@ -2,7 +2,6 @@ mod gasprice; mod healthz; mod info; mod metrics; -mod notify; mod quote; mod reveal; mod settle; @@ -13,7 +12,6 @@ pub(super) use { healthz::healthz, info::info, metrics::metrics, - notify::notify, quote::{OrderError, quote}, reveal::reveal, settle::settle, diff --git a/crates/driver/src/infra/api/routes/notify/dto/mod.rs b/crates/driver/src/infra/api/routes/notify/dto/mod.rs deleted file mode 100644 index 9a24eedbc1..0000000000 --- a/crates/driver/src/infra/api/routes/notify/dto/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod notify_request; - -pub use notify_request::NotifyRequest; diff --git a/crates/driver/src/infra/api/routes/notify/dto/notify_request.rs b/crates/driver/src/infra/api/routes/notify/dto/notify_request.rs deleted file mode 100644 index c812453e32..0000000000 --- a/crates/driver/src/infra/api/routes/notify/dto/notify_request.rs +++ /dev/null @@ -1,42 +0,0 @@ -use { - crate::infra::notify, - chrono::{DateTime, Utc}, - serde::Deserialize, - serde_with::serde_as, -}; - -#[serde_as] -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum NotifyRequest { - Banned { - reason: BanReason, - until: DateTime, - }, -} - -#[serde_as] -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum BanReason { - /// The driver won multiple consecutive auctions but never settled them. - UnsettledConsecutiveAuctions, - /// Driver's settle failure rate is above the threshold. - HighSettleFailureRate, -} - -impl From for notify::Kind { - fn from(value: NotifyRequest) -> Self { - match value { - NotifyRequest::Banned { reason, until } => notify::Kind::Banned { - reason: match reason { - BanReason::UnsettledConsecutiveAuctions => { - notify::BanReason::UnsettledConsecutiveAuctions - } - BanReason::HighSettleFailureRate => notify::BanReason::HighSettleFailureRate, - }, - until, - }, - } - } -} diff --git a/crates/driver/src/infra/api/routes/notify/mod.rs b/crates/driver/src/infra/api/routes/notify/mod.rs deleted file mode 100644 index 3e952a6c6c..0000000000 --- a/crates/driver/src/infra/api/routes/notify/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod dto; - -use crate::infra::api::{Error, State}; - -pub(in crate::infra::api) fn notify(router: axum::Router) -> axum::Router { - router.route("/notify", axum::routing::post(route)) -} - -async fn route( - state: axum::extract::State, - req: axum::Json, -) -> Result)> { - let solver = &state.solver().name().0; - tracing::debug!(?req, ?solver, "received a notification"); - state.solver().notify(None, None, req.0.into()); - Ok(hyper::StatusCode::OK) -} diff --git a/crates/driver/src/infra/api/routes/quote/dto/order.rs b/crates/driver/src/infra/api/routes/quote/dto/order.rs index 9d7e4a4f95..64449b6a4b 100644 --- a/crates/driver/src/infra/api/routes/quote/dto/order.rs +++ b/crates/driver/src/infra/api/routes/quote/dto/order.rs @@ -1,24 +1,21 @@ use { - crate::{ - domain::{competition, eth, quote}, - util::serialize, - }, + crate::domain::{competition, quote}, + eth_domain_types as eth, serde::Deserialize, serde_with::serde_as, }; impl Order { - pub fn into_domain(self) -> Result { - Ok(quote::Order { - tokens: quote::Tokens::try_new(self.sell_token.into(), self.buy_token.into()) - .map_err(|quote::SameTokens| Error::SameTokens)?, + pub fn into_domain(self) -> quote::Order { + quote::Order { + tokens: quote::Tokens::new(self.sell_token.into(), self.buy_token.into()), amount: self.amount.into(), side: match self.kind { Kind::Sell => competition::order::Side::Sell, Kind::Buy => competition::order::Side::Buy, }, deadline: self.deadline, - }) + } } } @@ -26,9 +23,9 @@ impl Order { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Order { - sell_token: eth::H160, - buy_token: eth::H160, - #[serde_as(as = "serialize::U256")] + sell_token: eth::Address, + buy_token: eth::Address, + #[serde_as(as = "serde_ext::U256")] amount: eth::U256, kind: Kind, deadline: chrono::DateTime, diff --git a/crates/driver/src/infra/api/routes/quote/dto/quote.rs b/crates/driver/src/infra/api/routes/quote/dto/quote.rs index 6cc519855e..ceabcf48d4 100644 --- a/crates/driver/src/infra/api/routes/quote/dto/quote.rs +++ b/crates/driver/src/infra/api/routes/quote/dto/quote.rs @@ -1,8 +1,6 @@ use { - crate::{ - domain::{self, competition::solution::encoding::codec, eth, quote}, - util::serialize, - }, + crate::domain::{self, competition::solution::encoding::codec, quote}, + eth_domain_types as eth, model::{ order::{BuyTokenDestination, SellTokenSource}, signature::SigningScheme, @@ -18,9 +16,13 @@ impl Quote { clearing_prices: quote.clearing_prices, pre_interactions: quote.pre_interactions.into_iter().map(Into::into).collect(), interactions: quote.interactions.into_iter().map(Into::into).collect(), - solver: quote.solver.0, - gas: quote.gas.map(|gas| gas.0.as_u64()), - tx_origin: quote.tx_origin.map(|addr| addr.0), + solver: quote.solver, + gas: quote.gas.map(|gas| { + gas.0 + .try_into() + .expect("value should be lower than u64::MAX") + }), + tx_origin: quote.tx_origin, jit_orders: quote.jit_orders.into_iter().map(Into::into).collect(), } } @@ -30,15 +32,15 @@ impl Quote { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Quote { - #[serde_as(as = "HashMap<_, serialize::U256>")] - clearing_prices: HashMap, + #[serde_as(as = "HashMap<_, serde_ext::U256>")] + clearing_prices: HashMap, pre_interactions: Vec, interactions: Vec, - solver: eth::H160, + solver: eth::Address, #[serde(skip_serializing_if = "Option::is_none")] gas: Option, #[serde(skip_serializing_if = "Option::is_none")] - tx_origin: Option, + tx_origin: Option, jit_orders: Vec, } @@ -46,17 +48,17 @@ pub struct Quote { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct Interaction { - target: eth::H160, - #[serde_as(as = "serialize::U256")] + target: eth::Address, + #[serde_as(as = "serde_ext::U256")] value: eth::U256, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] call_data: Vec, } -impl From for Interaction { - fn from(interaction: eth::Interaction) -> Self { +impl From for Interaction { + fn from(interaction: domain::Interaction) -> Self { Self { - target: interaction.target.into(), + target: interaction.target, value: interaction.value.into(), call_data: interaction.call_data.into(), } @@ -67,23 +69,23 @@ impl From for Interaction { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct JitOrder { - buy_token: eth::H160, - sell_token: eth::H160, - #[serde_as(as = "serialize::U256")] + buy_token: eth::Address, + sell_token: eth::Address, + #[serde_as(as = "serde_ext::U256")] sell_amount: eth::U256, - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] buy_amount: eth::U256, - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] executed_amount: eth::U256, - receiver: eth::H160, + receiver: eth::Address, partially_fillable: bool, valid_to: u32, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] app_data: [u8; 32], side: Side, sell_token_source: SellTokenSource, buy_token_destination: BuyTokenDestination, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] signature: Vec, signing_scheme: SigningScheme, } @@ -96,7 +98,7 @@ impl From for JitOrder { sell_amount: jit.order().sell.amount.into(), buy_amount: jit.order().buy.amount.into(), executed_amount: jit.executed().into(), - receiver: jit.order().receiver.into(), + receiver: jit.order().receiver, partially_fillable: jit.order().partially_fillable, valid_to: jit.order().valid_to.into(), app_data: jit.order().app_data.into(), diff --git a/crates/driver/src/infra/api/routes/quote/mod.rs b/crates/driver/src/infra/api/routes/quote/mod.rs index 77de817213..5fb791b2ac 100644 --- a/crates/driver/src/infra/api/routes/quote/mod.rs +++ b/crates/driver/src/infra/api/routes/quote/mod.rs @@ -1,6 +1,6 @@ use { crate::infra::{ - api::{Error, State}, + api::{Error, State, extract::LoggingQuery}, observe, }, tracing::Instrument, @@ -16,12 +16,10 @@ pub(in crate::infra::api) fn quote(router: axum::Router) -> axum::Router< async fn route( state: axum::extract::State, - order: axum::extract::Query, -) -> Result, (hyper::StatusCode, axum::Json)> { + LoggingQuery(order): LoggingQuery, +) -> Result, (axum::http::StatusCode, axum::Json)> { let handle_request = async { - let order = order.0.into_domain().inspect_err(|err| { - observe::invalid_dto(err, "order"); - })?; + let order = order.into_domain(); observe::quoting(&order); let quote = order .quote( @@ -29,6 +27,7 @@ async fn route( state.solver(), state.liquidity(), state.tokens(), + &state.competition().risk_detector, ) .await; observe::quoted(state.solver().name(), &order, "e); diff --git a/crates/driver/src/infra/api/routes/reveal/dto/reveal_response.rs b/crates/driver/src/infra/api/routes/reveal/dto/reveal_response.rs index 0f1d495042..bc5053a4d5 100644 --- a/crates/driver/src/infra/api/routes/reveal/dto/reveal_response.rs +++ b/crates/driver/src/infra/api/routes/reveal/dto/reveal_response.rs @@ -1,8 +1,4 @@ -use { - crate::{domain::competition, util::serialize}, - serde::Serialize, - serde_with::serde_as, -}; +use {crate::domain::competition, serde::Serialize, serde_with::serde_as}; impl RevealResponse { pub fn new(reveal: competition::Revealed) -> Self { @@ -26,8 +22,8 @@ pub struct RevealResponse { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct Calldata { - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] internalized: Vec, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] uninternalized: Vec, } diff --git a/crates/driver/src/infra/api/routes/reveal/mod.rs b/crates/driver/src/infra/api/routes/reveal/mod.rs index 7a2d6081e5..0475649f20 100644 --- a/crates/driver/src/infra/api/routes/reveal/mod.rs +++ b/crates/driver/src/infra/api/routes/reveal/mod.rs @@ -4,7 +4,7 @@ use { crate::{ domain::competition::auction, infra::{ - api::{self, Error, State}, + api::{self, Error, State, extract::LoggingJson}, observe, }, }, @@ -17,8 +17,8 @@ pub(in crate::infra::api) fn reveal(router: axum::Router) -> axum::Router async fn route( state: axum::extract::State, - req: axum::Json, -) -> Result, (hyper::StatusCode, axum::Json)> { + LoggingJson(req): LoggingJson, +) -> Result, (axum::http::StatusCode, axum::Json)> { let auction_id = auction::Id::try_from(req.auction_id).map_err(api::routes::AuctionError::from)?; let handle_request = async { diff --git a/crates/driver/src/infra/api/routes/settle/mod.rs b/crates/driver/src/infra/api/routes/settle/mod.rs index 022d0e521f..3c7bec8a54 100644 --- a/crates/driver/src/infra/api/routes/settle/mod.rs +++ b/crates/driver/src/infra/api/routes/settle/mod.rs @@ -4,7 +4,7 @@ use { crate::{ domain::competition::auction, infra::{ - api::{self, Error, State}, + api::{self, Error, State, extract::LoggingJson}, observe, }, }, @@ -17,8 +17,8 @@ pub(in crate::infra::api) fn settle(router: axum::Router) -> axum::Router async fn route( state: axum::extract::State, - req: axum::Json, -) -> Result<(), (hyper::StatusCode, axum::Json)> { + LoggingJson(req): LoggingJson, +) -> Result<(), (axum::http::StatusCode, axum::Json)> { let auction_id = auction::Id::try_from(req.auction_id).map_err(api::routes::AuctionError::from)?; let solver = state.solver().name().to_string(); @@ -30,10 +30,9 @@ async fn route( .settle( auction_id, req.solution_id, - req.submission_deadline_latest_block, + req.submission_deadline_latest_block.into(), ) .await; - observe::settled(state.solver().name(), &result); result.map(|_| ()).map_err(Into::into) } .instrument(tracing::info_span!("/settle", solver, %auction_id)) diff --git a/crates/driver/src/infra/api/routes/solve/dto/solve_request.rs b/crates/driver/src/infra/api/routes/solve/dto/solve_request.rs index 509b9fb4d5..4b3db0a06b 100644 --- a/crates/driver/src/infra/api/routes/solve/dto/solve_request.rs +++ b/crates/driver/src/infra/api/routes/solve/dto/solve_request.rs @@ -1,6 +1,7 @@ use { crate::{ domain::{ + self, competition::{ self, auction, @@ -9,11 +10,10 @@ use { app_data::{AppData, AppDataHash}, }, }, - eth, }, infra::{Ethereum, tokens}, - util::serialize, }, + eth_domain_types as eth, serde::Deserialize, serde_with::serde_as, std::{ @@ -42,32 +42,12 @@ impl SolveRequest { Some(self.id.try_into()?), self.orders .into_iter() - .map(|order| competition::Order { - uid: order.uid.into(), - receiver: order.receiver.map(Into::into), - created: order.created.into(), - valid_to: order.valid_to.into(), - buy: eth::Asset { - amount: order.buy_amount.into(), - token: order.buy_token.into(), - }, - sell: eth::Asset { - amount: order.sell_amount.into(), - token: order.sell_token.into(), - }, - side: match order.kind { - Kind::Sell => competition::order::Side::Sell, - Kind::Buy => competition::order::Side::Buy, - }, - kind: match order.class { - Class::Market => competition::order::Kind::Market, - Class::Limit => competition::order::Kind::Limit, - }, - app_data: match app_data.get(&AppDataHash::from(order.app_data)) { + .map(|order| { + let app_data = match app_data.get(&AppDataHash::from(order.app_data)) { Some(data) => AppData::Full(data.clone()), None => AppData::Hash(AppDataHash::from(order.app_data)), - }, - partial: if order.partially_fillable { + }; + let partial = if order.partially_fillable { competition::order::Partial::Yes { available: match order.kind { Kind::Sell => { @@ -78,82 +58,116 @@ impl SolveRequest { } } else { competition::order::Partial::No - }, - pre_interactions: order - .pre_interactions - .into_iter() - .map(|interaction| eth::Interaction { - target: interaction.target.into(), - value: interaction.value.into(), - call_data: interaction.call_data.into(), - }) - .collect(), - post_interactions: order - .post_interactions - .into_iter() - .map(|interaction| eth::Interaction { - target: interaction.target.into(), - value: interaction.value.into(), - call_data: interaction.call_data.into(), - }) - .collect(), - sell_token_balance: match order.sell_token_balance { - SellTokenBalance::Erc20 => competition::order::SellTokenBalance::Erc20, - SellTokenBalance::Internal => { - competition::order::SellTokenBalance::Internal - } - SellTokenBalance::External => { - competition::order::SellTokenBalance::External - } - }, - buy_token_balance: match order.buy_token_balance { - BuyTokenBalance::Erc20 => competition::order::BuyTokenBalance::Erc20, - BuyTokenBalance::Internal => competition::order::BuyTokenBalance::Internal, - }, - signature: competition::order::Signature { - scheme: match order.signing_scheme { - SigningScheme::Eip712 => competition::order::signature::Scheme::Eip712, - SigningScheme::EthSign => { - competition::order::signature::Scheme::EthSign - } - SigningScheme::PreSign => { - competition::order::signature::Scheme::PreSign - } - SigningScheme::Eip1271 => { - competition::order::signature::Scheme::Eip1271 - } - }, - data: order.signature.into(), - signer: order.owner.into(), - }, - protocol_fees: order - .protocol_fees - .into_iter() - .map(|policy| match policy { - FeePolicy::Surplus { - factor, - max_volume_factor, - } => competition::order::FeePolicy::Surplus { - factor, - max_volume_factor, + }; + competition::Order { + data: Arc::new(competition::order::OrderData { + uid: order.uid.into(), + receiver: order.receiver, + created: order.created.into(), + valid_to: order.valid_to.into(), + buy: eth::Asset { + amount: order.buy_amount.into(), + token: order.buy_token.into(), + }, + sell: eth::Asset { + amount: order.sell_amount.into(), + token: order.sell_token.into(), + }, + side: match order.kind { + Kind::Sell => competition::order::Side::Sell, + Kind::Buy => competition::order::Side::Buy, + }, + kind: match order.class { + Class::Market => competition::order::Kind::Market, + Class::Limit => competition::order::Kind::Limit, + }, + pre_interactions: order + .pre_interactions + .into_iter() + .map(|interaction| domain::Interaction { + target: interaction.target, + value: interaction.value.into(), + call_data: interaction.call_data.into(), + }) + .collect(), + post_interactions: order + .post_interactions + .into_iter() + .map(|interaction| domain::Interaction { + target: interaction.target, + value: interaction.value.into(), + call_data: interaction.call_data.into(), + }) + .collect(), + sell_token_balance: match order.sell_token_balance { + SellTokenBalance::Erc20 => { + competition::order::SellTokenBalance::Erc20 + } + SellTokenBalance::Internal => { + competition::order::SellTokenBalance::Internal + } + SellTokenBalance::External => { + competition::order::SellTokenBalance::External + } }, - FeePolicy::PriceImprovement { - factor, - max_volume_factor, - quote, - } => competition::order::FeePolicy::PriceImprovement { - factor, - max_volume_factor, - quote: quote.into_domain(order.sell_token, order.buy_token), + buy_token_balance: match order.buy_token_balance { + BuyTokenBalance::Erc20 => { + competition::order::BuyTokenBalance::Erc20 + } + BuyTokenBalance::Internal => { + competition::order::BuyTokenBalance::Internal + } + }, + signature: competition::order::Signature { + scheme: match order.signing_scheme { + SigningScheme::Eip712 => { + competition::order::signature::Scheme::Eip712 + } + SigningScheme::EthSign => { + competition::order::signature::Scheme::EthSign + } + SigningScheme::PreSign => { + competition::order::signature::Scheme::PreSign + } + SigningScheme::Eip1271 => { + competition::order::signature::Scheme::Eip1271 + } + }, + data: order.signature.into(), + signer: order.owner, }, - FeePolicy::Volume { factor } => { - competition::order::FeePolicy::Volume { factor } - } - }) - .collect(), - quote: order - .quote - .map(|q| q.into_domain(order.sell_token, order.buy_token)), + protocol_fees: order + .protocol_fees + .into_iter() + .map(|policy| match policy { + FeePolicy::Surplus { + factor, + max_volume_factor, + } => competition::order::FeePolicy::Surplus { + factor, + max_volume_factor, + }, + FeePolicy::PriceImprovement { + factor, + max_volume_factor, + quote, + } => competition::order::FeePolicy::PriceImprovement { + factor, + max_volume_factor, + quote: quote.into_domain(order.sell_token, order.buy_token), + }, + FeePolicy::Volume { factor } => { + competition::order::FeePolicy::Volume { factor } + } + }) + .collect(), + quote: order + .quote + .map(|q| q.into_domain(order.sell_token, order.buy_token)), + }), + app_data, + partial, + } }) .collect(), self.tokens.into_iter().map(|token| { @@ -171,7 +185,6 @@ impl SolveRequest { eth, self.surplus_capturing_jit_order_owners .into_iter() - .map(Into::into) .collect::>(), ) .await @@ -217,7 +230,7 @@ pub struct SolveRequest { orders: Vec, deadline: chrono::DateTime, #[serde(default)] - surplus_capturing_jit_order_owners: Vec, + surplus_capturing_jit_order_owners: Vec, } impl SolveRequest { @@ -230,8 +243,8 @@ impl SolveRequest { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct Token { - pub address: eth::H160, - #[serde_as(as = "Option")] + pub address: eth::Address, + #[serde_as(as = "Option")] pub price: Option, pub trusted: bool, } @@ -240,23 +253,23 @@ struct Token { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct Order { - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] uid: [u8; order::UID_LEN], - sell_token: eth::H160, - buy_token: eth::H160, - #[serde_as(as = "serialize::U256")] + sell_token: eth::Address, + buy_token: eth::Address, + #[serde_as(as = "serde_ext::U256")] sell_amount: eth::U256, - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] buy_amount: eth::U256, protocol_fees: Vec, created: u32, valid_to: u32, kind: Kind, - receiver: Option, - owner: eth::H160, + receiver: Option, + owner: eth::Address, partially_fillable: bool, /// Always zero if the order is not partially fillable. - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] executed: eth::U256, pre_interactions: Vec, post_interactions: Vec, @@ -265,10 +278,10 @@ struct Order { #[serde(default)] buy_token_balance: BuyTokenBalance, class: Class, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] app_data: [u8; order::app_data::APP_DATA_LEN], signing_scheme: SigningScheme, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] signature: Vec, quote: Option, } @@ -284,10 +297,10 @@ enum Kind { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct Interaction { - target: eth::H160, - #[serde_as(as = "serialize::U256")] + target: eth::Address, + #[serde_as(as = "serde_ext::U256")] value: eth::U256, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] call_data: Vec, } @@ -343,17 +356,21 @@ enum FeePolicy { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Quote { - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] pub sell_amount: eth::U256, - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] pub buy_amount: eth::U256, - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] pub fee: eth::U256, - pub solver: eth::H160, + pub solver: eth::Address, } impl Quote { - fn into_domain(self, sell_token: eth::H160, buy_token: eth::H160) -> competition::order::Quote { + fn into_domain( + self, + sell_token: eth::Address, + buy_token: eth::Address, + ) -> competition::order::Quote { competition::order::Quote { sell: eth::Asset { amount: self.sell_amount.into(), @@ -367,7 +384,7 @@ impl Quote { amount: self.fee.into(), token: sell_token.into(), }, - solver: self.solver.into(), + solver: self.solver, } } } diff --git a/crates/driver/src/infra/api/routes/solve/dto/solve_response.rs b/crates/driver/src/infra/api/routes/solve/dto/solve_response.rs index 892810f5f1..0a98073152 100644 --- a/crates/driver/src/infra/api/routes/solve/dto/solve_response.rs +++ b/crates/driver/src/infra/api/routes/solve/dto/solve_response.rs @@ -1,16 +1,16 @@ use { crate::{ - domain::{competition, competition::order, eth}, + domain::{competition, competition::order}, infra::Solver, - util::serialize, }, + eth_domain_types as eth, serde::Serialize, serde_with::serde_as, std::collections::HashMap, }; impl SolveResponse { - pub fn new(solved: Option, solver: &Solver) -> Self { + pub fn new(solved: Vec, solver: &Solver) -> Self { let solutions = solved .into_iter() .map(|solved| Solution::new(solved.id.get(), solved, solver)) @@ -31,7 +31,7 @@ impl Solution { Self { solution_id, score: solved.score.0, - submission_address: solver.address().into(), + submission_address: solver.address(), orders: solved .trades .into_iter() @@ -71,13 +71,16 @@ pub struct Solution { /// Unique ID of the solution (per driver competition), used to identify it /// in subsequent requests (reveal, settle). solution_id: u64, - #[serde_as(as = "serialize::U256")] + submission_address: eth::Address, + #[serde_as(as = "serde_ext::U256")] score: eth::U256, - submission_address: eth::H160, - #[serde_as(as = "HashMap")] + #[serde_as(as = "HashMap")] orders: HashMap, - #[serde_as(as = "HashMap<_, serialize::U256>")] - clearing_prices: HashMap, + /// Deprecated: kept only for backward compatibility with autopilots + /// running the previous code during a rolling deploy. Will be removed in + /// a follow-up once the new autopilot is fully rolled out. + #[serde_as(as = "HashMap<_, serde_ext::U256>")] + clearing_prices: HashMap, } #[serde_as] @@ -85,19 +88,19 @@ pub struct Solution { #[serde(rename_all = "camelCase")] pub struct TradedOrder { pub side: Side, - pub sell_token: eth::H160, - pub buy_token: eth::H160, - #[serde_as(as = "serialize::U256")] + pub sell_token: eth::Address, + pub buy_token: eth::Address, + #[serde_as(as = "serde_ext::U256")] /// Sell limit order amount. pub limit_sell: eth::U256, - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] /// Buy limit order amount. pub limit_buy: eth::U256, /// The effective amount that left the user's wallet including all fees. - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] pub executed_sell: eth::U256, /// The effective amount the user received after all fees. - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] pub executed_buy: eth::U256, } diff --git a/crates/driver/src/infra/api/routes/solve/mod.rs b/crates/driver/src/infra/api/routes/solve/mod.rs index 3750b7ef1f..baa78c6b4d 100644 --- a/crates/driver/src/infra/api/routes/solve/mod.rs +++ b/crates/driver/src/infra/api/routes/solve/mod.rs @@ -6,7 +6,7 @@ use { api::{Error, State}, observe, }, - std::sync::Arc, + axum::{body::Body, http::Request}, tracing::Instrument, }; @@ -16,17 +16,20 @@ pub(in crate::infra::api) fn solve(router: axum::Router) -> axum::Router< async fn route( state: axum::extract::State, - // take the request body as a raw string to delay parsing as much - // as possible because many requests don't have to be parsed at all - req: String, -) -> Result, (hyper::StatusCode, axum::Json)> { + // Take the request as raw request to extract the body as a stream. + // This delays interpreting the data as much as possible and allows + // logging how long the raw data transfer takes. + request: Request, +) -> Result, (axum::http::StatusCode, axum::Json)> { + let solver = state.solver().name().as_str(); + let handle_request = async { let competition = state.competition(); - let result = competition.solve(Arc::new(req)).await; + let result = competition.solve(request).await; // Solving takes some time, so there is a chance for the settlement queue to // have capacity again. competition.ensure_settle_queue_capacity()?; - observe::solved(state.solver().name(), &result); + observe::solved(solver, &result); Ok(axum::Json(dto::SolveResponse::new( result?, &competition.solver, @@ -34,6 +37,10 @@ async fn route( }; handle_request - .instrument(tracing::info_span!("/solve", solver = %state.solver().name(), auction_id = tracing::field::Empty)) + .instrument(tracing::info_span!( + "/solve", + solver, + auction_id = tracing::field::Empty + )) .await } diff --git a/crates/driver/src/infra/blockchain/contracts.rs b/crates/driver/src/infra/blockchain/contracts.rs index d89a39b294..c2f937f818 100644 --- a/crates/driver/src/infra/blockchain/contracts.rs +++ b/crates/driver/src/infra/blockchain/contracts.rs @@ -1,19 +1,9 @@ use { - crate::domain::eth, chain::Chain, - contracts::alloy::{ - BalancerV2Vault, - FlashLoanRouter, - GPv2Settlement, - WETH9, - support::Balances, - }, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - }, + contracts::{BalancerV2Vault, FlashLoanRouter, GPv2Settlement, WETH9, support::Balances}, + eth_domain_types as eth, + ethrpc::Web3, std::collections::HashMap, - thiserror::Error, }; #[derive(Debug, Clone)] @@ -21,7 +11,7 @@ pub struct Contracts { settlement: GPv2Settlement::Instance, vault_relayer: eth::ContractAddress, vault: BalancerV2Vault::Instance, - signatures: contracts::alloy::support::Signatures::Instance, + signatures: contracts::support::Signatures::Instance, weth: WETH9::Instance, /// The domain separator for settlement contract used for signing orders. @@ -54,42 +44,42 @@ impl Contracts { web3: &Web3, chain: Chain, addresses: Addresses, - ) -> Result { + ) -> Result { let settlement = GPv2Settlement::Instance::new( addresses .settlement - .map(|addr| addr.0.into_alloy()) + .map(Into::into) .or_else(|| GPv2Settlement::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); let vault_relayer = settlement.vaultRelayer().call().await?; let vault = - BalancerV2Vault::Instance::new(settlement.vault().call().await?, web3.alloy.clone()); + BalancerV2Vault::Instance::new(settlement.vault().call().await?, web3.provider.clone()); let balance_helper = Balances::Instance::new( addresses .balances - .map(|addr| addr.0.into_alloy()) + .map(Into::into) .or_else(|| Balances::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); - let signatures = contracts::alloy::support::Signatures::Instance::new( + let signatures = contracts::support::Signatures::Instance::new( addresses .signatures - .map(|addr| addr.0.into_alloy()) - .or_else(|| contracts::alloy::support::Signatures::deployment_address(&chain.id())) + .map(Into::into) + .or_else(|| contracts::support::Signatures::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); let weth = WETH9::Instance::new( addresses .weth - .map(|addr| addr.0.into_alloy()) + .map(Into::into) .or_else(|| WETH9::deployment_address(&chain.id())) .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); let settlement_domain_separator = eth::DomainSeparator( @@ -105,17 +95,13 @@ impl Contracts { let flashloan_router = addresses .flashloan_router .or_else(|| { - FlashLoanRouter::deployment_address(&chain.id()).map(|deployment_address| { - eth::ContractAddress(deployment_address.into_legacy()) - }) + FlashLoanRouter::deployment_address(&chain.id()).map(eth::ContractAddress::from) }) - .map(|address| { - FlashLoanRouter::Instance::new(address.0.into_alloy(), web3.alloy.clone()) - }); + .map(|address| FlashLoanRouter::Instance::new(*address, web3.provider.clone())); Ok(Self { settlement, - vault_relayer: vault_relayer.into_legacy().into(), + vault_relayer: vault_relayer.into(), vault, signatures, weth, @@ -131,7 +117,7 @@ impl Contracts { &self.settlement } - pub fn signatures(&self) -> &contracts::alloy::support::Signatures::Instance { + pub fn signatures(&self) -> &contracts::support::Signatures::Instance { &self.signatures } @@ -147,8 +133,8 @@ impl Contracts { &self.weth } - pub fn weth_address(&self) -> eth::WethAddress { - self.weth.address().into_legacy().into() + pub fn weth_address(&self) -> eth::WrappedNativeToken { + (*self.weth.address()).into() } pub fn settlement_domain_separator(&self) -> ð::DomainSeparator { @@ -173,26 +159,3 @@ impl Contracts { &self.cow_amm_helper_by_factory } } - -/// Returns the address of a contract for the specified network, or `None` if -/// there is no known deployment for the contract on that network. -pub fn deployment_address( - contract: ðcontract::Contract, - chain: Chain, -) -> Option { - Some( - contract - .networks - .get(&chain.id().to_string())? - .address - .into(), - ) -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("method error: {0:?}")] - Method(#[from] ethcontract::errors::MethodError), - #[error("method error: {0:?}")] - Rpc(#[from] alloy::contract::Error), -} diff --git a/crates/driver/src/infra/blockchain/gas.rs b/crates/driver/src/infra/blockchain/gas.rs index 76ed302dac..2f02d4c1f8 100644 --- a/crates/driver/src/infra/blockchain/gas.rs +++ b/crates/driver/src/infra/blockchain/gas.rs @@ -4,19 +4,17 @@ /// private submission networks are used. use { super::Error, - crate::{ - domain::eth, - infra::{config::file::GasEstimatorType, mempool}, - }, + crate::infra::{config::file::GasEstimatorType, mempool}, + alloy::eips::eip1559::Eip1559Estimation, + anyhow::anyhow, + eth_domain_types as eth, ethrpc::Web3, - gas_estimation::{ - DEFAULT_GAS_LIMIT, - DEFAULT_TIME_LIMIT, + gas_price_estimation::{ GasPriceEstimating, - nativegasestimator::{NativeGasEstimator, Params}, + configurable_alloy::ConfigurableGasPriceEstimator, + eth_node::NodeGasPriceEstimator, }, - shared::gas_price_estimation::alloy::AlloyGasPriceEstimator, - std::{sync::Arc, time::Duration}, + std::sync::Arc, }; type MaxAdditionalTip = eth::U256; @@ -24,7 +22,7 @@ type AdditionalTipPercentage = f64; type AdditionalTip = (MaxAdditionalTip, AdditionalTipPercentage); pub struct GasPriceEstimator { - gas: Arc, + pub(super) gas: Arc, additional_tip: AdditionalTip, max_fee_per_gas: eth::U256, min_priority_fee: eth::U256, @@ -37,42 +35,30 @@ impl GasPriceEstimator { mempools: &[mempool::Config], ) -> Result { let gas: Arc = match gas_estimator_type { - GasEstimatorType::Native { - max_reward_percentile, - max_block_percentile, - min_block_percentile, - } => Arc::new( - NativeGasEstimator::new( - web3.transport().clone(), - Some(Params { - max_reward_percentile: *max_reward_percentile, - max_block_percentile: *max_block_percentile, - min_block_percentile: *min_block_percentile, - ..Default::default() - }), - ) - .await - .map_err(Error::GasPrice)?, - ), - GasEstimatorType::Web3 => Arc::new(web3.legacy.clone()), - GasEstimatorType::Alloy => Arc::new(AlloyGasPriceEstimator::new(web3.alloy.clone())), + GasEstimatorType::Web3 => Arc::new(NodeGasPriceEstimator::new(web3.provider.clone())), + GasEstimatorType::Alloy { + past_blocks, + reward_percentile, + } => Arc::new(ConfigurableGasPriceEstimator::new( + web3.provider.clone(), + configs::gas_price_estimation::EstimatorConfig { + past_blocks: *past_blocks, + reward_percentile: *reward_percentile, + }, + )), }; + // TODO: simplify logic by moving gas price adjustments out of the individual + // mempool configs let additional_tip = mempools .iter() - .map(|mempool| match mempool.kind { - mempool::Kind::MEVBlocker { - max_additional_tip, - additional_tip_percentage, - .. - } => (max_additional_tip, additional_tip_percentage), - mempool::Kind::Public { - max_additional_tip, - additional_tip_percentage, - .. - } => (max_additional_tip, additional_tip_percentage), + .map(|mempool| { + ( + mempool.max_additional_tip, + mempool.additional_tip_percentage, + ) }) .next() - .unwrap_or((eth::U256::zero(), 0.)); + .unwrap_or((eth::U256::ZERO, 0.)); // Use the lowest max_fee_per_gas of all mempools as the max_fee_per_gas let max_fee_per_gas = mempools .iter() @@ -98,27 +84,65 @@ impl GasPriceEstimator { /// If additional tip is configured, it will be added to the gas price. This /// is to increase the chance of a transaction being included in a block, in /// case private submission networks are used. - pub async fn estimate(&self, time_limit: Option) -> Result { - self.gas - .estimate_with_limits(DEFAULT_GAS_LIMIT, time_limit.unwrap_or(DEFAULT_TIME_LIMIT)) - .await - .map(|estimate| { - let (max, percentage) = self.additional_tip; - let additional_tip = max - .to_f64_lossy() - .min(estimate.max_fee_per_gas * percentage); + pub async fn estimate(&self) -> Result { + let estimate = self.gas.estimate().await.map_err(Error::GasPrice)?; - let tip = std::cmp::max( - self.min_priority_fee + eth::U256::from_f64_lossy(additional_tip), - eth::U256::from_f64_lossy(estimate.max_priority_fee_per_gas + additional_tip), - ); + let max_priority_fee_per_gas = { + // the driver supports tweaking the tx gas price tip in case the gas + // price estimator is systematically too low => compute configured tip bump + let (max_additional_tip, tip_percentage_increase) = self.additional_tip; - eth::GasPrice::new( - self.max_fee_per_gas.into(), - tip.into(), - eth::U256::from_f64_lossy(estimate.base_fee_per_gas).into(), - ) - }) - .map_err(Error::GasPrice) + // Calculate additional tip in integer space to avoid precision loss + // Convert percentage to basis points (multiply by 10000) to maintain precision + // e.g., tip_percentage_increase = 0.125 (12.5%) becomes 1250 + let overflow_err = || { + Error::GasPrice(anyhow!( + "overflow on multiplication (max_priority_fee_per_gas * tip_percentage_as_bps)" + )) + }; + let tip_percentage_as_bps = tip_percentage_increase * 10000.0; + let calculated_tip = eth::U256::from(estimate.max_priority_fee_per_gas) + .checked_mul(eth::U256::from(tip_percentage_as_bps)) + .ok_or_else(overflow_err)? + / eth::U256::from(10000u128); + + let additional_tip = max_additional_tip.min(calculated_tip); + + // make sure we tip at least some configurable minimum amount + std::cmp::max( + self.min_priority_fee, + eth::U256::from(estimate.max_priority_fee_per_gas) + additional_tip, + ) + }; + + // make sure the used max fee per gas is at least big enough to cover the tip - + // otherwise the tx will be rejected by the node immediately + let suggested_max_fee_per_gas = eth::U256::from(estimate.max_fee_per_gas); + let suggested_max_fee_per_gas = + std::cmp::max(suggested_max_fee_per_gas, max_priority_fee_per_gas); + if suggested_max_fee_per_gas > self.max_fee_per_gas { + return Err(Error::GasPrice(anyhow::anyhow!( + "suggested gas price is higher than maximum allowed gas price (network is too \ + congested)" + ))); + } + + Ok(Eip1559Estimation { + max_fee_per_gas: u128::try_from(suggested_max_fee_per_gas) + .map_err(|err| Error::GasPrice(err.into()))?, + max_priority_fee_per_gas: u128::try_from(max_priority_fee_per_gas) + .map_err(|err| Error::GasPrice(err.into()))?, + }) + } +} + +#[async_trait::async_trait] +impl GasPriceEstimating for GasPriceEstimator { + async fn estimate(&self) -> ::anyhow::Result { + GasPriceEstimator::estimate(self).await.map_err(Into::into) + } + + async fn base_fee(&self) -> ::anyhow::Result> { + self.gas.base_fee().await } } diff --git a/crates/driver/src/infra/blockchain/mod.rs b/crates/driver/src/infra/blockchain/mod.rs index ec2d5e448d..ba3c086d7d 100644 --- a/crates/driver/src/infra/blockchain/mod.rs +++ b/crates/driver/src/infra/blockchain/mod.rs @@ -1,21 +1,23 @@ use { - crate::{boundary, domain::eth}, - alloy::providers::Provider, - chain::Chain, - ethcontract::{U256, errors::ExecutionError}, - ethrpc::{Web3, alloy::conversions::IntoLegacy, block_stream::CurrentBlockWatcher}, - shared::{ - account_balances::{BalanceSimulator, SimulationError}, - price_estimation::trade_verifier::balance_overrides::{ - BalanceOverrides, - BalanceOverriding, - }, + crate::{boundary, domain::blockchain::TxStatus}, + account_balances::{BalanceSimulator, SimulationError}, + alloy::{ + eips::eip1559::Eip1559Estimation, + network::TransactionBuilder, + providers::Provider, + rpc::types::{TransactionReceipt, TransactionRequest}, + transports::TransportErrorKind, }, - std::{fmt, sync::Arc, time::Duration}, + balance_overrides::{StateOverrides, StateOverriding}, + chain::Chain, + eth_domain_types as eth, + ethrpc::{Web3, alloy::ProviderLabelingExt, block_stream::CurrentBlockWatcher}, + gas_price_estimation::{Eip1559EstimationExt, GasPriceEstimating}, + shared::web3, + std::{fmt, sync::Arc}, thiserror::Error, tracing::{Level, instrument}, url::Url, - web3::{Transport, types::CallRequest}, }; pub mod contracts; @@ -24,12 +26,14 @@ pub mod token; pub use self::{contracts::Contracts, gas::GasPriceEstimator}; /// An Ethereum RPC connection. +#[derive(Clone)] pub struct Rpc { web3: Web3, chain: Chain, args: RpcArgs, } +#[derive(Clone)] pub struct RpcArgs { pub url: Url, pub max_batch_size: usize, @@ -40,12 +44,16 @@ impl Rpc { /// Instantiate an RPC client to an Ethereum (or Ethereum-compatible) node /// at the specifed URL. pub async fn try_new(args: RpcArgs) -> Result { - let web3 = boundary::buffered_web3_client( + let web3 = web3::web3( + &web3::Arguments { + ethrpc_max_batch_size: args.max_batch_size, + ethrpc_max_concurrent_requests: args.max_concurrent_requests, + ethrpc_batch_delay: Default::default(), + }, &args.url, - args.max_batch_size, - args.max_concurrent_requests, + "base", ); - let chain = Chain::try_from(web3.alloy.get_chain_id().await?)?; + let chain = Chain::try_from(web3.provider.get_chain_id().await?)?; Ok(Self { web3, chain, args }) } @@ -63,8 +71,6 @@ impl Rpc { #[derive(Debug, Error)] pub enum RpcError { - #[error("web3 error: {0:?}")] - Web3(#[from] web3::error::Error), #[error("alloy transport error: {0:?}")] Alloy(#[from] alloy::transports::TransportError), #[error("unsupported chain")] @@ -84,8 +90,8 @@ struct Inner { gas: Arc, current_block: CurrentBlockWatcher, balance_simulator: BalanceSimulator, - balance_overrider: Arc, - tx_gas_limit: U256, + state_overrider: Arc, + tx_gas_limit: eth::Gas, } impl Ethereum { @@ -99,26 +105,25 @@ impl Ethereum { rpc: Rpc, addresses: contracts::Addresses, gas: Arc, - tx_gas_limit: U256, current_block_args: &shared::current_block::Arguments, + tx_gas_limit: eth::Gas, ) -> Self { let Rpc { web3, chain, args } = rpc; - let current_block_stream = current_block_args - .stream(args.url.clone(), web3.alloy.clone()) + .stream(args.url.clone(), web3.provider.clone()) .await .expect("couldn't initialize current block stream"); let contracts = Contracts::new(&web3, chain, addresses) .await .expect("could not initialize important smart contracts"); - let balance_overrider = Arc::new(BalanceOverrides::new(web3.clone())); + let state_overrider = Arc::new(StateOverrides::new(web3.clone())); let balance_simulator = BalanceSimulator::new( contracts.settlement().clone(), contracts.balance_helper().clone(), - contracts.vault_relayer().0, - Some(contracts.vault().address().into_legacy()), - balance_overrider.clone(), + *contracts.vault_relayer(), + Some(*contracts.vault().address()), + state_overrider.clone(), ); Self { @@ -128,7 +133,7 @@ impl Ethereum { contracts, gas, balance_simulator, - balance_overrider, + state_overrider, tx_gas_limit, }), web3, @@ -143,15 +148,15 @@ impl Ethereum { &self.inner.balance_simulator } - pub fn balance_overrider(&self) -> Arc { - Arc::clone(&self.inner.balance_overrider) + pub fn state_overrider(&self) -> Arc { + Arc::clone(&self.inner.state_overrider) } /// Clones self and returns an instance that captures metrics extended with /// the provided label. pub fn with_metric_label(&self, label: String) -> Self { Self { - web3: ethrpc::instrumented::instrument_with_label(&self.web3, label), + web3: self.web3.labeled(label), ..self.clone() } } @@ -163,8 +168,8 @@ impl Ethereum { /// Check if a smart contract is deployed to the given address. pub async fn is_contract(&self, address: eth::Address) -> Result { - let code = self.web3.eth().code(address.into(), None).await?; - Ok(!code.0.is_empty()) + let code = self.web3.provider.get_code_at(address).await?; + Ok(!code.is_empty()) } /// Returns a type that monitors the block chain to inform about the current @@ -173,69 +178,32 @@ impl Ethereum { &self.inner.current_block } - /// Create access list used by a transaction. - #[instrument(skip_all)] - pub async fn create_access_list(&self, tx: T) -> Result - where - CallRequest: From, - { - let mut tx: CallRequest = tx.into(); - tx.gas = Some(self.inner.tx_gas_limit); - tx.gas_price = self.simulation_gas_price().await; - - let json = self - .web3 - .transport() - .execute( - "eth_createAccessList", - vec![serde_json::to_value(&tx).unwrap()], - ) - .await?; - if let Some(err) = json.get("error") { - return Err(Error::AccessList(err.to_owned())); - } - let access_list: web3::types::AccessList = - serde_json::from_value(json.get("accessList").unwrap().to_owned()).unwrap(); - Ok(access_list.into()) - } - - /// Estimate gas used by a transaction. - pub async fn estimate_gas(&self, tx: ð::Tx) -> Result { - self.web3 - .eth() - .estimate_gas( - web3::types::CallRequest { - from: Some(tx.from.into()), - to: Some(tx.to.into()), - value: Some(tx.value.into()), - data: Some(tx.input.clone().into()), - access_list: Some(tx.access_list.clone().into()), - gas_price: self.simulation_gas_price().await, - ..Default::default() - }, - None, - ) - .await - .map(Into::into) - .map_err(Into::into) - } - /// The gas price is determined based on the deadline by which the /// transaction must be included on-chain. A shorter deadline requires a /// higher gas price to increase the likelihood of timely inclusion. - pub async fn gas_price(&self, time_limit: Option) -> Result { - self.inner.gas.estimate(time_limit).await + pub async fn gas_price(&self) -> Result { + self.inner.gas.estimate().await + } + + pub fn gas_estimator(&self) -> Arc { + Arc::clone(&self.inner.gas) as _ } pub fn block_gas_limit(&self) -> eth::Gas { self.inner.current_block.borrow().gas_limit.into() } + /// Per-transaction gas limit configured for this driver. Operators set + /// this per chain (e.g. EIP-7825's 16,777,215 cap on Fusaka chains). + pub fn tx_gas_limit(&self) -> eth::Gas { + self.inner.tx_gas_limit + } + /// Returns the current [`eth::Ether`] balance of the specified account. pub async fn balance(&self, address: eth::Address) -> Result { self.web3 - .eth() - .balance(address.into(), None) + .provider + .get_balance(address) .await .map(Into::into) .map_err(Into::into) @@ -246,35 +214,109 @@ impl Ethereum { token::Erc20::new(self, address) } + /// Estimate gas used by a transaction. + pub async fn estimate_gas(&self, tx: eth::Tx) -> Result { + let tx = TransactionRequest::default() + .from(tx.from) + .to(tx.to) + .value(tx.value.0) + .input(tx.input.into()) + .access_list(tx.access_list.into()); + + let tx = match self.simulation_gas_price().await { + Some(gas_price) => tx.with_gas_price(gas_price), + _ => tx, + }; + + let estimated_gas = self + .web3 + .provider + .estimate_gas(tx) + .pending() + .await + .map_err(Error::Rpc)? + .into(); + + Ok(estimated_gas) + } + /// Returns the transaction's on-chain inclusion status. - pub async fn transaction_status(&self, tx_hash: ð::TxId) -> Result { + pub async fn transaction_status(&self, tx_hash: ð::TxId) -> Result { self.web3 - .eth() - .transaction_receipt(tx_hash.0) + .provider + .get_transaction_receipt(tx_hash.0) .await - .map(|result| match result { - Some(web3::types::TransactionReceipt { - status: Some(status), - block_number: Some(block), - .. - }) => { - if status.is_zero() { - eth::TxStatus::Reverted { - block_number: eth::BlockNo(block.as_u64()), - } - } else { - eth::TxStatus::Executed { - block_number: eth::BlockNo(block.as_u64()), - } + .map(|result| { + let Some( + receipt @ TransactionReceipt { + block_number: Some(block_number), + .. + }, + ) = result + else { + return TxStatus::Pending; + }; + + if receipt.status() { + TxStatus::Executed { + block_number: eth::BlockNo(block_number), + } + } else { + TxStatus::Reverted { + block_number: eth::BlockNo(block_number), } } - _ => eth::TxStatus::Pending, }) .map_err(Into::into) } + /// The block our successful `Settlement` event for `tx_hash` landed in, + /// searching `[from_block, to_block]` inclusive, or `None` if it is not in + /// that range. Only a successful settle emits the event, and `eth_getLogs` + /// reads block logs even while the receipt-by-hash lookup still lags, so + /// this sees a freshly mined settlement that `eth_getTransactionReceipt` + /// would still miss. Scanning a range rather than a single block means a + /// block the (coalescing) block stream skipped on a fast chain is still + /// covered. + pub async fn successful_settlement_block( + &self, + tx_hash: eth::TxId, + from_block: u64, + ) -> Result, Error> { + let logs = self + .contracts() + .settlement() + .event_filter::<::contracts::GPv2Settlement::GPv2Settlement::Settlement>() + .from_block(alloy::eips::BlockNumberOrTag::Number(from_block)) + // `Latest` rather than the stream's head: the node may already be a block + // or two ahead, and querying up to its real tip narrows the race window. + .to_block(alloy::eips::BlockNumberOrTag::Latest) + .query() + .await?; + Ok(logs + .into_iter() + .find(|(_, log)| log.transaction_hash == Some(tx_hash.0)) + .and_then(|(_, log)| log.block_number) + .map(eth::BlockNo)) + } + + /// The signer's transaction count including the mempool (the `pending` + /// tag). A count above the nonce we submitted with means our tx is + /// still queued in the mempool or has already mined (the count stays at + /// `nonce + 1` once it mines). A count equal to that nonce means the tx + /// left the mempool without mining. + pub async fn pending_transaction_count(&self, address: eth::Address) -> Result { + self.web3 + .provider + .get_transaction_count(address) + .pending() + .await + .map_err(Into::into) + } + #[instrument(skip(self), ret(level = Level::DEBUG))] - pub(super) async fn simulation_gas_price(&self) -> Option { + pub(super) async fn simulation_gas_price(&self) -> Option { + let base_fee = self.current_block().borrow().base_fee; // Some nodes don't pick a reasonable default value when you don't specify a gas // price and default to 0. Additionally some sneaky tokens have special code // paths that detect that case to try to behave differently during simulations @@ -282,12 +324,7 @@ impl Ethereum { // default value we estimate the current gas price upfront. But because it's // extremely rare that tokens behave that way we are fine with falling back to // the node specific fallback value instead of failing the whole call. - self.inner - .gas - .estimate(None) - .await - .ok() - .map(|gas| gas.effective().0.0) + Some(self.inner.gas.estimate().await.ok()?.effective(base_fee)) } pub fn web3(&self) -> &Web3 { @@ -309,15 +346,13 @@ impl fmt::Debug for Ethereum { #[derive(Debug, Error)] pub enum Error { #[error("method error: {0:?}")] - Rpc(#[from] alloy::contract::Error), - #[error("method error: {0:?}")] - Method(#[from] ethcontract::errors::MethodError), - #[error("web3 error: {0:?}")] - Web3(#[from] web3::error::Error), + ContractRpc(#[from] alloy::contract::Error), + #[error("alloy rpc error: {0:?}")] + Rpc(#[from] alloy::transports::RpcError), #[error("gas price estimation error: {0}")] GasPrice(boundary::Error), #[error("access list estimation error: {0:?}")] - AccessList(serde_json::Value), + AccessList(String), } impl Error { @@ -326,23 +361,14 @@ impl Error { pub fn is_revert(&self) -> bool { // This behavior is node dependent match self { - Error::Method(error) => matches!(error.inner, ExecutionError::Revert(_)), - Error::Web3(inner) => { - let error = ExecutionError::from(inner.clone()); - matches!(error, ExecutionError::Revert(_)) - } Error::GasPrice(_) => false, Error::AccessList(_) => true, - Error::Rpc(_) => true, - } - } -} - -impl From for Error { - fn from(err: contracts::Error) -> Self { - match err { - contracts::Error::Method(err) => Self::Method(err), - contracts::Error::Rpc(err) => Self::Rpc(err), + Error::ContractRpc(_) => true, + Error::Rpc(err) => { + let is_revert = err.is_error_resp(); + tracing::trace!(is_revert, ?err, "classified error"); + is_revert + } } } } @@ -350,8 +376,7 @@ impl From for Error { impl From for Error { fn from(err: SimulationError) -> Self { match err { - SimulationError::Method(err) => Self::Rpc(err), - SimulationError::Web3(err) => Self::Web3(err), + SimulationError::Method(err) => Self::ContractRpc(err), } } } diff --git a/crates/driver/src/infra/blockchain/token.rs b/crates/driver/src/infra/blockchain/token.rs index 70744f035b..2aeb7dbcdd 100644 --- a/crates/driver/src/infra/blockchain/token.rs +++ b/crates/driver/src/infra/blockchain/token.rs @@ -1,32 +1,26 @@ use { super::{Error, Ethereum}, - crate::domain::eth, - ethrpc::alloy::{ - conversions::{IntoAlloy, IntoLegacy}, - errors::ContractErrorExt, - }, + eth_domain_types as eth, + ethrpc::alloy::errors::ContractErrorExt, }; /// An ERC-20 token. /// /// https://eips.ethereum.org/EIPS/eip-20 pub struct Erc20 { - token: contracts::alloy::ERC20::Instance, + token: contracts::ERC20::Instance, } impl Erc20 { pub(super) fn new(eth: &Ethereum, address: eth::TokenAddress) -> Self { Self { - token: contracts::alloy::ERC20::Instance::new( - address.0.0.into_alloy(), - eth.web3.alloy.clone(), - ), + token: contracts::ERC20::Instance::new(*address, eth.web3.provider.clone()), } } /// Returns the [`eth::TokenAddress`] of the ERC20. pub fn address(&self) -> eth::TokenAddress { - self.token.address().into_legacy().into() + (*self.token.address()).into() } /// Fetch the ERC20 allowance for the spender. See the allowance method in @@ -38,13 +32,9 @@ impl Erc20 { owner: eth::Address, spender: eth::Address, ) -> Result { - let amount = self - .token - .allowance(owner.0.into_alloy(), spender.0.into_alloy()) - .call() - .await?; + let amount = self.token.allowance(owner, spender).call().await?; Ok(eth::Allowance { - token: self.token.address().into_legacy().into(), + token: (*self.token.address()).into(), spender, amount, } @@ -81,10 +71,9 @@ impl Erc20 { /// https://eips.ethereum.org/EIPS/eip-20#balanceof pub async fn balance(&self, holder: eth::Address) -> Result { self.token - .balanceOf(holder.0.into_alloy()) + .balanceOf(holder) .call() .await - .map(IntoLegacy::into_legacy) .map(Into::into) .map_err(Into::into) } diff --git a/crates/driver/src/infra/config/file/load.rs b/crates/driver/src/infra/config/file/load.rs index a4a32a4e53..68f54c3507 100644 --- a/crates/driver/src/infra/config/file/load.rs +++ b/crates/driver/src/infra/config/file/load.rs @@ -1,6 +1,6 @@ use { crate::{ - domain::{competition::bad_tokens, eth}, + domain::competition::risk_detector, infra::{ self, blockchain, @@ -8,11 +8,12 @@ use { liquidity, mempool, notify, - simulator, - solver::{self, BadTokenDetection, SolutionMerging}, + solver::{self, Account, BadOrderDetection, SolutionMerging}, }, }, + alloy::signers::{aws::AwsSigner, local::PrivateKeySigner}, chain::Chain, + eth_domain_types as eth, futures::future::join_all, number::conversions::big_decimal_to_big_rational, std::path::Path, @@ -51,21 +52,7 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config { ); infra::Config { solvers: join_all(config.solvers.into_iter().map(|solver_config| async move { - let account = match solver_config.account { - file::Account::PrivateKey(private_key) => ethcontract::Account::Offline( - ethcontract::PrivateKey::from_raw(private_key.0).unwrap(), - None, - ), - file::Account::Kms(key_id) => { - let config = ethcontract::aws_config::load_from_env().await; - let account = - ethcontract::transaction::kms::Account::new((&config).into(), &key_id.0) - .await - .unwrap_or_else(|_| panic!("Unable to load KMS account {key_id:?}")); - ethcontract::Account::Kms(account, None) - } - file::Account::Address(address) => ethcontract::Account::Local(address, None), - }; + let account = load_account(solver_config.account, config.chain_id).await; solver::Config { endpoint: solver_config.endpoint, name: solver_config.name.into(), @@ -100,41 +87,47 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config { }, s3: solver_config.s3.map(Into::into), solver_native_token: solver_config.manage_native_token.to_domain(), - quote_tx_origin: solver_config.quote_tx_origin.map(eth::Address), + quote_tx_origin: solver_config.quote_tx_origin, response_size_limit_max_bytes: solver_config.response_size_limit_max_bytes, - bad_token_detection: BadTokenDetection { + bad_order_detection: BadOrderDetection { tokens_supported: solver_config - .bad_token_detection + .bad_order_detection .token_supported .iter() .map(|(token, supported)| { ( - eth::TokenAddress(eth::ContractAddress(*token)), + eth::TokenAddress::from(*token), match supported { - true => bad_tokens::Quality::Supported, - false => bad_tokens::Quality::Unsupported, + true => risk_detector::Quality::Supported, + false => risk_detector::Quality::Unsupported, }, ) }) .collect(), enable_simulation_strategy: solver_config - .bad_token_detection + .bad_order_detection .enable_simulation_strategy, enable_metrics_strategy: solver_config - .bad_token_detection + .bad_order_detection .enable_metrics_strategy, metrics_strategy_failure_ratio: solver_config - .bad_token_detection + .bad_order_detection .metrics_strategy_failure_ratio, metrics_strategy_required_measurements: solver_config - .bad_token_detection + .bad_order_detection .metrics_strategy_required_measurements, metrics_strategy_log_only: solver_config - .bad_token_detection + .bad_order_detection .metrics_strategy_log_only, - metrics_strategy_token_freeze_time: solver_config - .bad_token_detection - .metrics_strategy_token_freeze_time, + metrics_strategy_order_freeze_time: solver_config + .bad_order_detection + .metrics_strategy_freeze_time, + metrics_strategy_cache_gc_interval: solver_config + .bad_order_detection + .metrics_strategy_gc_interval, + metrics_strategy_cache_max_age: solver_config + .bad_order_detection + .metrics_strategy_gc_max_age, }, settle_queue_size: solver_config.settle_queue_size, flashloans_enabled: config.flashloans_enabled, @@ -142,6 +135,17 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config { file::AtBlock::Latest => liquidity::AtBlock::Latest, file::AtBlock::Finalized => liquidity::AtBlock::Finalized, }, + haircut_bps: solver_config.haircut_bps, + submission_accounts: join_all( + solver_config + .submission_accounts + .into_inner() + .into_iter() + .map(|acc| load_account(acc, config.chain_id)), + ) + .await, + max_solutions_to_propose: solver_config.max_solutions_to_propose, + post_processing_concurrency_limit: solver_config.post_processing_concurrency_limit, } })) .await, @@ -221,35 +225,32 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config { file::UniswapV3Config::Preset { preset, max_pools_to_initialize, - graph_url, - reinit_interval, - max_pools_per_tick_query, - } => liquidity::config::UniswapV3 { - max_pools_to_initialize, + indexer_config, reinit_interval, - ..match preset { + } => { + let pool_source = uniswap_v3_pool_source(indexer_config); + let preset_defaults = match preset { file::UniswapV3Preset::UniswapV3 => { - liquidity::config::UniswapV3::uniswap_v3( - &graph_url, - chain, - max_pools_per_tick_query, - ) + liquidity::config::UniswapV3::uniswap_v3(pool_source, chain) } } - .expect("no Uniswap V3 preset for current network") - }, + .expect("no Uniswap V3 preset for current network"); + liquidity::config::UniswapV3 { + max_pools_to_initialize, + reinit_interval, + ..preset_defaults + } + } file::UniswapV3Config::Manual { router, max_pools_to_initialize, - graph_url, + indexer_config, reinit_interval, - max_pools_per_tick_query, } => liquidity::config::UniswapV3 { router: router.into(), max_pools_to_initialize, - graph_url, + pool_source: uniswap_v3_pool_source(indexer_config), reinit_interval, - max_pools_per_tick_query, }, }) .collect(), @@ -321,68 +322,27 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config { .submission .mempools .iter() - .map(|mempool| mempool::Config { + .enumerate() + .map(|(index, mempool)| mempool::Config { min_priority_fee: config.submission.min_priority_fee, gas_price_cap: config.submission.gas_price_cap, target_confirm_time: config.submission.target_confirm_time, retry_interval: config.submission.retry_interval, - kind: match mempool { - file::Mempool::Public { - max_additional_tip, - additional_tip_percentage, - } => { - // If there is no private mempool, revert protection is - // disabled, otherwise driver would not even try to settle revertable - // settlements - let revert_protection = if config - .submission - .mempools - .iter() - .any(|pool| matches!(pool, file::Mempool::MevBlocker { .. })) - { - mempool::RevertProtection::Enabled - } else { - mempool::RevertProtection::Disabled - }; - - mempool::Kind::Public { - max_additional_tip: *max_additional_tip, - additional_tip_percentage: *additional_tip_percentage, - revert_protection, - } - } - file::Mempool::MevBlocker { - url, - max_additional_tip, - additional_tip_percentage, - use_soft_cancellations, - } => mempool::Kind::MEVBlocker { - url: url.to_owned(), - max_additional_tip: *max_additional_tip, - additional_tip_percentage: *additional_tip_percentage, - use_soft_cancellations: *use_soft_cancellations, - }, + nonce_block_number: config.submission.nonce_block_number.map(Into::into), + name: mempool + .name + .clone() + .unwrap_or_else(|| format!("mempool_{index}")), + url: mempool.url.clone(), + revert_protection: match mempool.mines_reverting_txs { + true => mempool::RevertProtection::Disabled, + false => mempool::RevertProtection::Enabled, }, + max_additional_tip: mempool.max_additional_tip, + additional_tip_percentage: mempool.additional_tip_percentage, }) .collect(), - simulator: match (config.tenderly, config.enso) { - (Some(config), None) => { - Some(simulator::Config::Tenderly(simulator::tenderly::Config { - url: config.url, - api_key: config.api_key, - user: config.user, - project: config.project, - save: config.save, - save_if_fails: config.save_if_fails, - })) - } - (None, Some(config)) => Some(simulator::Config::Enso(simulator::enso::Config { - url: config.url, - network_block_interval: config.network_block_interval, - })), - (None, None) => None, - (Some(_), Some(_)) => panic!("Cannot configure both Tenderly and Enso"), - }, + simulator: config.simulator, contracts: blockchain::contracts::Addresses { settlement: config.contracts.gp_v2_settlement.map(Into::into), weth: config.contracts.weth.map(Into::into), @@ -403,5 +363,48 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config { simulation_bad_token_max_age: config.simulation_bad_token_max_age, app_data_fetching: config.app_data_fetching, tx_gas_limit: config.tx_gas_limit, + http: config.http, + } +} + +fn uniswap_v3_pool_source( + indexer_config: file::IndexerConfig, +) -> liquidity::config::UniswapV3PoolSource { + match indexer_config { + file::IndexerConfig::Subgraph { + url, + max_pools_per_tick_query, + } => { + liquidity::config::UniswapV3PoolSource::Subgraph(liquidity::config::UniswapV3Subgraph { + url, + max_pools_per_tick_query, + }) + } + file::IndexerConfig::PoolIndexer { + url, + wait_until_timeout, + } => liquidity::config::UniswapV3PoolSource::PoolIndexer( + liquidity::config::UniswapV3PoolIndexer { + url, + wait_until_timeout, + }, + ), + } +} + +async fn load_account(account: file::Account, chain_id: Option) -> Account { + match account { + file::Account::PrivateKey(pk) => PrivateKeySigner::from_bytes(&pk) + .expect("invalid private key") + .into(), + file::Account::Kms(arn) => { + let sdk_config = alloy::signers::aws::aws_config::load_from_env().await; + let client = alloy::signers::aws::aws_sdk_kms::Client::new(&sdk_config); + AwsSigner::new(client, arn.0, chain_id) + .await + .expect("unable to load kms account") + .into() + } + file::Account::Address(address) => Account::Address(address), } } diff --git a/crates/driver/src/infra/config/file/mod.rs b/crates/driver/src/infra/config/file/mod.rs index d27579a3e1..69db5aa29b 100644 --- a/crates/driver/src/infra/config/file/mod.rs +++ b/crates/driver/src/infra/config/file/mod.rs @@ -1,13 +1,15 @@ pub use load::load; use { - crate::{domain::eth, infra, util::serialize}, - alloy::primitives::Address, + crate::infra, + alloy::{eips::BlockNumberOrTag, primitives::Address}, + configs::gas_price_estimation::{default_past_blocks, default_reward_percentile}, + eth_domain_types as eth, number::serialization::HexOrDecimalU256, reqwest::Url, serde::{Deserialize, Deserializer, Serialize}, serde_with::serde_as, solver::solver::Arn, - std::{collections::HashMap, time::Duration}, + std::{collections::HashMap, num::NonZeroUsize, time::Duration}, }; mod load; @@ -30,7 +32,7 @@ struct Config { /// Disable gas simulation and always use this fixed gas value instead. This /// can be useful for testing, but shouldn't be used in production since it /// will cause the driver to return invalid scores. - #[serde_as(as = "Option")] + #[serde_as(as = "Option")] disable_gas_simulation: Option, /// Defines the gas estimator to use. @@ -45,12 +47,6 @@ struct Config { #[serde(default)] contracts: ContractsConfig, - /// Use Tenderly for transaction simulation. - tenderly: Option, - - /// Use Enso for transaction simulation. - enso: Option, - /// Liquidity sources notifier configuration. liquidity_sources_notifier: Option, @@ -86,6 +82,13 @@ struct Config { #[serde_as(as = "HexOrDecimalU256")] tx_gas_limit: eth::U256, + + #[serde(default)] + simulator: configs::simulator::Config, + + /// Http client factory config + #[serde(default)] + http: configs::http_client::HttpClient, } #[serde_as] @@ -95,13 +98,13 @@ struct SubmissionConfig { /// The minimum priority fee in Gwei the solver is ensuring to pay in a /// settlement. #[serde(default)] - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] min_priority_fee: eth::U256, /// The maximum gas price in Gwei the solver is willing to pay in a /// settlement. #[serde(default = "default_gas_price_cap")] - #[serde_as(as = "serialize::U256")] + #[serde_as(as = "serde_ext::U256")] gas_price_cap: eth::U256, /// The target confirmation time for settlement transactions used @@ -114,52 +117,60 @@ struct SubmissionConfig { #[serde(with = "humantime_serde", default = "default_retry_interval")] retry_interval: Duration, + /// Block number to use when fetching nonces. Options: "pending", + /// "latest", "earliest". If not specified, uses the web3 lib's default + /// behavior. + #[serde(default)] + nonce_block_number: Option, + /// The mempools to submit settlement transactions to. Can be the public /// mempool of a node or the private MEVBlocker mempool. #[serde(rename = "mempool", default)] mempools: Vec, } +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "lowercase")] +enum BlockNumber { + Pending, + Latest, + Earliest, +} + +impl From for BlockNumberOrTag { + fn from(value: BlockNumber) -> Self { + match value { + BlockNumber::Pending => Self::Pending, + BlockNumber::Latest => Self::Latest, + BlockNumber::Earliest => Self::Earliest, + } + } +} + #[serde_as] #[derive(Debug, Deserialize)] -#[serde(tag = "mempool")] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] -enum Mempool { - #[serde(rename_all = "kebab-case")] - Public { - /// Maximum additional tip in Gwei that we are willing to pay - /// above regular gas price estimation. - #[serde(default = "default_max_additional_tip")] - #[serde_as(as = "serialize::U256")] - max_additional_tip: eth::U256, - /// Additional tip in percentage of max_fee_per_gas we are willing to - /// pay above regular gas price estimation. Expects a - /// floating point value between 0 and 1. - #[serde(default = "default_additional_tip_percentage")] - additional_tip_percentage: f64, - }, - #[serde(rename_all = "kebab-case")] - MevBlocker { - /// The MEVBlocker URL to use. - url: Url, - /// Maximum additional tip in Gwei that we are willing to give to - /// MEVBlocker above regular gas price estimation. - #[serde(default = "default_max_additional_tip")] - #[serde_as(as = "serialize::U256")] - max_additional_tip: eth::U256, - /// Additional tip in percentage of max_fee_per_gas we are giving to - /// MEVBlocker above regular gas price estimation. Expects a - /// floating point value between 0 and 1. - #[serde(default = "default_additional_tip_percentage")] - additional_tip_percentage: f64, - /// Configures whether the submission logic is allowed to assume the - /// submission nodes implement soft cancellations. With soft - /// cancellations a cancellation transaction doesn't have to get mined - /// to have an effect. On arrival in the node all pending transactions - /// with the same sender and nonce will get discarded immediately. - #[serde(default = "default_soft_cancellations_flag")] - use_soft_cancellations: bool, - }, +#[serde(rename_all = "kebab-case")] +struct Mempool { + /// Name for better logging and metrics. + name: Option, + /// The RPC URL to use. + url: Url, + /// Maximum additional tip in Gwei that we are willing to give to + /// the validator above regular gas price estimation. + #[serde(default = "default_max_additional_tip")] + #[serde_as(as = "serde_ext::U256")] + max_additional_tip: eth::U256, + /// Additional tip in percentage of max_fee_per_gas we are giving to + /// validator above regular gas price estimation. Expects a + /// floating point value between 0 and 1. + #[serde(default = "default_additional_tip_percentage")] + additional_tip_percentage: f64, + /// Informs the submission logic whether a reverting transaction will + /// actually be mined or just ignored. This is an advanced feature + /// for private mempools so for most configured mempools you have to + /// assume reverting transactions will get mined eventually. + #[serde(default = "default_mines_reverting_txs")] + mines_reverting_txs: bool, } #[derive(Debug, Deserialize)] @@ -195,7 +206,7 @@ fn default_additional_tip_percentage() -> f64 { /// 1000 gwei fn default_gas_price_cap() -> eth::U256 { - eth::U256::from(1000) * eth::U256::exp10(9) + eth::U256::from(1000) * eth::U256::from(10).pow(eth::U256::from(9)) } fn default_target_confirm_time() -> Duration { @@ -208,11 +219,11 @@ fn default_retry_interval() -> Duration { /// 3 gwei fn default_max_additional_tip() -> eth::U256 { - eth::U256::from(3) * eth::U256::exp10(9) + eth::U256::from(3) * eth::U256::from(10).pow(eth::U256::from(9)) } -fn default_soft_cancellations_flag() -> bool { - false +fn default_mines_reverting_txs() -> bool { + true } pub fn default_http_time_buffer() -> Duration { @@ -223,6 +234,14 @@ pub fn default_solving_share_of_deadline() -> f64 { 0.8 } +fn default_max_solutions_to_propose() -> NonZeroUsize { + NonZeroUsize::new(1).unwrap() +} + +fn default_post_processing_concurrency_limit() -> NonZeroUsize { + NonZeroUsize::MAX +} + #[serde_as] #[derive(Debug, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] @@ -280,20 +299,47 @@ struct SolverConfig { /// Which `tx.origin` is required to make a quote simulation pass. #[serde(default)] - quote_tx_origin: Option, + quote_tx_origin: Option, /// Maximum HTTP response size the driver will accept in bytes. #[serde(default = "default_response_size_limit_max_bytes")] response_size_limit_max_bytes: usize, - /// Configuration for bad token detection. + /// Configuration for bad order detection. #[serde(default, flatten)] - bad_token_detection: BadTokenDetectionConfig, + bad_order_detection: BadOrderDetectionConfig, /// The maximum number of `/settle` requests that can be queued up /// before the driver starts dropping new `/solve` requests. #[serde(default = "default_settle_queue_size")] settle_queue_size: usize, + + /// Haircut in basis points (0-10000). Applied to solver-reported + /// economics to make bids more conservative by adjusting clearing prices + /// to report lower surplus. Useful for solvers prone to negative slippage. + /// Default: 0 (no haircut). + #[serde(default)] + haircut_bps: u32, + + /// Additional EOAs that submit settlement txs on behalf of the solver + /// via EIP-7702 delegation. When non-empty, enables parallel submission + /// with one lane per account. + #[serde(default)] + submission_accounts: SubmissionAccounts, + + /// Maximum number of solutions the driver proposes to the autopilot per + /// auction. Defaults to 1 (only the best-scoring solution). Values > 1 + /// require `submission-accounts` to be configured; the driver will refuse + /// to start otherwise. + #[serde(default = "default_max_solutions_to_propose")] + max_solutions_to_propose: NonZeroUsize, + + /// How many solutions the driver may post-process (i.e. validate) + /// concurrently. When the RPC node is experiencing very high latency + /// this number can be lowered if the usual throughput can not be + /// sustained anymore. + #[serde(default = "default_post_processing_concurrency_limit")] + post_processing_concurrency_limit: NonZeroUsize, } #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize)] @@ -321,13 +367,60 @@ pub struct S3 { enum Account { /// A private key is used to sign transactions. Expects a 32-byte hex /// encoded string. - PrivateKey(eth::H256), + PrivateKey(eth::B256), /// AWS KMS is used to sign transactions. Expects the key identifier. Kms(#[serde_as(as = "serde_with::DisplayFromStr")] Arn), - /// An address is used to identify the account for signing, relying on the - /// connected node's account management features. This can also be used to - /// start the driver in a dry-run mode. - Address(eth::H160), + /// Used to start the driver in the dry-run mode. This account type is + /// *unable* to sign transactions as alloy does not support *implicit* + /// node-side signing. + Address(eth::Address), +} + +/// Accounts used for parallel EIP-7702 settlement submission. Every account is +/// guaranteed to be a signer (never [`Account::Address`]), because address-only +/// accounts cannot sign the delegated settlement transactions. +#[derive(Debug, Default)] +struct SubmissionAccounts(Vec); + +impl SubmissionAccounts { + /// Constructs a new [`SubmissionAccounts`], rejecting any address-only + /// account ([`Account::Address`]) since such accounts cannot sign EIP-7702 + /// delegated settlement transactions. + fn new(accounts: Vec) -> Result { + if accounts + .iter() + .any(|account| matches!(account, Account::Address(_))) + { + return Err(InvalidSubmissionAccounts); + } + Ok(Self(accounts)) + } + + fn into_inner(self) -> Vec { + self.0 + } +} + +#[derive(Debug)] +struct InvalidSubmissionAccounts; + +impl std::fmt::Display for InvalidSubmissionAccounts { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str( + "EIP-7702 submission accounts must be signers; address-only accounts cannot sign \ + delegated settlement transactions", + ) + } +} + +impl<'de> Deserialize<'de> for SubmissionAccounts { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let accounts = Vec::::deserialize(deserializer)?; + Self::new(accounts).map_err(serde::de::Error::custom) + } } #[serde_as] @@ -358,7 +451,7 @@ struct Slippage { /// The absolute slippage allowed by the solver. #[serde(rename = "absolute-slippage")] - #[serde_as(as = "Option")] + #[serde_as(as = "Option")] absolute: Option, } @@ -366,16 +459,16 @@ struct Slippage { #[serde(rename_all = "kebab-case", deny_unknown_fields)] struct ContractsConfig { /// Override the default address of the GPv2Settlement contract. - gp_v2_settlement: Option, + gp_v2_settlement: Option, /// Override the default address of the WETH contract. - weth: Option, + weth: Option, /// Override the default address of the Balances contract. - balances: Option, + balances: Option, /// Override the default address of the Signatures contract. - signatures: Option, + signatures: Option, /// List of all cow amm factories with the corresponding helper contract. #[serde(default)] @@ -383,50 +476,16 @@ struct ContractsConfig { /// Flashloan router to support taking out multiple flashloans /// in the same settlement. - flashloan_router: Option, + flashloan_router: Option, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct CowAmmConfig { /// CoW AMM factory address. - pub factory: eth::H160, + pub factory: eth::Address, /// Which helper contract to use for interfacing with CoW AMMs. - pub helper: eth::H160, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] -struct TenderlyConfig { - /// Optionally override the Tenderly API URL. - url: Option, - - /// Authentication key for the Tenderly API. - api_key: String, - - /// The Tenderly user associated with the API key. - user: String, - - /// The Tenderly project associated with the API key. - project: String, - - /// Save the transaction on Tenderly for later inspection, e.g. via the - /// dashboard. - save: bool, - - /// Save the transaction even in the case of failure. - save_if_fails: bool, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] -struct EnsoConfig { - /// URL at which the trade simulator is hosted - url: Url, - /// How often the network produces a new block. If this is not set the - /// system assumes an unpredictable network like proof-of-work. - #[serde(default, with = "humantime_serde")] - network_block_interval: Option, + pub helper: eth::Address, } #[derive(Clone, Debug, Default, Deserialize)] @@ -435,7 +494,7 @@ struct LiquidityConfig { /// Additional tokens for which liquidity is always fetched, regardless of /// whether or not the token appears in the auction. #[serde(default)] - base_tokens: Vec, + base_tokens: Vec, /// Liquidity provided by a Uniswap V2 compatible contract. #[serde(default)] @@ -472,10 +531,10 @@ enum UniswapV2Config { #[serde(rename_all = "kebab-case")] Manual { /// The address of the Uniswap V2 compatible router contract. - router: eth::H160, + router: eth::Address, /// The digest of the pool initialization code. - pool_code: eth::H256, + pool_code: eth::B256, /// How long liquidity should not be fetched for a token pair that /// didn't return useful liquidity before allowing to fetch it @@ -505,10 +564,10 @@ enum SwaprConfig { #[serde(rename_all = "kebab-case")] Manual { /// The address of the Swapr compatible router contract. - router: eth::H160, + router: eth::Address, /// The digest of the pool initialization code. - pool_code: eth::H256, + pool_code: eth::B256, /// How long liquidity should not be fetched for a token pair that /// didn't return useful liquidity before allowing to fetch it @@ -535,13 +594,8 @@ enum UniswapV3Config { #[serde(default = "uniswap_v3::default_max_pools_to_initialize")] max_pools_to_initialize: usize, - graph_url: Url, - - /// How many pool IDs can be present in a where clause of a Tick query - /// at once. Some subgraphs are overloaded and throw errors when - /// there are too many. - #[serde(default = "uniswap_v3::default_max_pools_per_tick_query")] - max_pools_per_tick_query: usize, + /// Source of pool definitions and tick data. + indexer_config: IndexerConfig, /// How often the liquidity source should be reinitialized to get /// access to new pools. @@ -552,20 +606,14 @@ enum UniswapV3Config { #[serde(rename_all = "kebab-case")] Manual { /// Addresses of Uniswap V3 compatible router contracts. - router: eth::H160, + router: eth::Address, /// How many pools to initialize during start up. #[serde(default = "uniswap_v3::default_max_pools_to_initialize")] max_pools_to_initialize: usize, - /// How many pool IDs can be present in a where clause of a Tick query - /// at once. Some subgraphs are overloaded and throw errors when - /// there are too many. - #[serde(default = "uniswap_v3::default_max_pools_per_tick_query")] - max_pools_per_tick_query: usize, - - /// The URL used to connect to uniswap v3 subgraph client. - graph_url: Url, + /// Source of pool definitions and tick data. + indexer_config: IndexerConfig, /// How often the liquidity source should be reinitialized to get /// access to new pools. @@ -574,6 +622,33 @@ enum UniswapV3Config { }, } +/// Where Uniswap V3 pool definitions and tick data are fetched from. Exactly +/// one variant is active per `[[liquidity.uniswap-v3]]` entry. +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +enum IndexerConfig { + #[serde(rename_all = "kebab-case")] + Subgraph { + url: Url, + /// How many pool IDs can be present in a where clause of a Tick query + /// at once. Some subgraphs are overloaded and throw errors when + /// there are too many. + #[serde(default = "uniswap_v3::default_max_pools_per_tick_query")] + max_pools_per_tick_query: usize, + }, + #[serde(rename_all = "kebab-case")] + PoolIndexer { + url: Url, + /// Upper bound on a single `wait_until` call. Size per-network to + /// comfortably exceed the worst-case first-deploy seed time. + #[serde( + with = "humantime_serde", + default = "uniswap_v3::default_pool_indexer_wait_until_timeout" + )] + wait_until_timeout: Duration, + }, +} + #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] enum UniswapV3Preset { @@ -581,6 +656,8 @@ enum UniswapV3Preset { } mod uniswap_v3 { + use std::time::Duration; + pub fn default_max_pools_to_initialize() -> usize { 100 } @@ -588,6 +665,10 @@ mod uniswap_v3 { pub fn default_max_pools_per_tick_query() -> usize { usize::MAX } + + pub fn default_pool_indexer_wait_until_timeout() -> Duration { + Duration::from_secs(300) + } } #[derive(Clone, Debug, Deserialize)] @@ -599,7 +680,7 @@ enum BalancerV2Config { /// Deny listed Balancer V2 pools. #[serde(default)] - pool_deny_list: Vec, + pool_deny_list: Vec, /// The URL used to connect to balancer v2 subgraph client. graph_url: Url, @@ -613,7 +694,7 @@ enum BalancerV2Config { #[serde(rename_all = "kebab-case")] Manual { /// Addresses of Balancer V2 compatible vault contract. - vault: eth::H160, + vault: eth::Address, /// The weighted pool factory contract addresses. #[serde(default)] @@ -640,7 +721,7 @@ enum BalancerV2Config { /// Deny listed Balancer V2 pools. #[serde(default)] - pool_deny_list: Vec, + pool_deny_list: Vec, /// The URL used to connect to balancer v2 subgraph client. graph_url: Url, @@ -711,50 +792,33 @@ pub struct LiquoriceConfig { } #[derive(Clone, Debug, Deserialize)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] -#[serde(tag = "estimator")] +#[serde(rename_all = "kebab-case", deny_unknown_fields, tag = "estimator")] pub enum GasEstimatorType { + Web3, + /// EIP-1559 gas estimator using alloy's algorithm. + /// Optionally configure the fee history query parameters. #[serde(rename_all = "kebab-case")] - Native { - // Effective reward value to be selected from each individual block - // Example: 20 means 20% of the transactions with the lowest gas price will be analyzed - #[serde(default = "default_max_reward_percentile")] - max_reward_percentile: usize, - // Economical priority fee to be selected from sorted individual block reward percentiles - // This constitutes the part of priority fee that doesn't depend on the time_limit - #[serde(default = "default_min_block_percentile")] - min_block_percentile: f64, - // Urgent priority fee to be selected from sorted individual block reward percentiles - // This constitutes the part of priority fee that depends on the time_limit - #[serde(default = "default_max_block_percentile")] - max_block_percentile: f64, + Alloy { + /// Number of blocks to look back for fee history (default: 10) + #[serde(default = "default_past_blocks")] + past_blocks: u64, + /// Percentile of rewards to use for priority fee estimation (default: + /// 20.0). This is what Metamask uses as medium priority: + /// https://github.com/MetaMask/core/blob/0fd4b397e7237f104d1c81579a0c4321624d076b/packages/gas-fee-controller/src/fetchGasEstimatesViaEthFeeHistory/calculateGasFeeEstimatesForPriorityLevels.ts#L14-L45 + #[serde(default = "default_reward_percentile")] + reward_percentile: f64, }, - Web3, - Alloy, } impl Default for GasEstimatorType { fn default() -> Self { - GasEstimatorType::Native { - max_reward_percentile: default_max_reward_percentile(), - min_block_percentile: default_min_block_percentile(), - max_block_percentile: default_max_block_percentile(), + Self::Alloy { + past_blocks: default_past_blocks(), + reward_percentile: default_reward_percentile(), } } } -fn default_max_reward_percentile() -> usize { - 20 -} - -fn default_min_block_percentile() -> f64 { - 30. -} - -fn default_max_block_percentile() -> f64 { - 60. -} - /// Defines various strategies to prioritize orders. #[derive(Debug, Deserialize)] #[serde(rename_all = "kebab-case", tag = "strategy")] @@ -811,10 +875,10 @@ fn default_simulation_bad_token_max_age() -> Duration { #[serde_as] #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] -pub struct BadTokenDetectionConfig { +pub struct BadOrderDetectionConfig { /// Which tokens are explicitly supported or unsupported by the solver. #[serde(default)] - pub token_supported: HashMap, + pub token_supported: HashMap, /// Whether the solver opted into detecting unsupported /// tokens with `trace_callMany` based simulation. @@ -822,46 +886,65 @@ pub struct BadTokenDetectionConfig { pub enable_simulation_strategy: bool, /// Whether the solver opted into detecting unsupported - /// tokens with metrics-based detection. - #[serde(default, rename = "enable-metrics-bad-token-detection")] + /// orders with metrics-based detection. Orders that continue to result + /// in reverting solutions will be ignored temporarily. + #[serde(default, rename = "enable-metrics-bad-order-detection")] pub enable_metrics_strategy: bool, - /// The ratio of failures to attempts that qualifies a token as unsupported. + /// The ratio of failures to attempts that qualifies an order as + /// unsupported. #[serde( - default = "default_metrics_bad_token_detector_failure_ratio", - rename = "metrics-bad-token-detection-failure-ratio" + default = "default_metrics_bad_order_detector_failure_ratio", + rename = "metrics-bad-order-detection-failure-ratio" )] pub metrics_strategy_failure_ratio: f64, - /// The minimum number of attempts required before evaluating a token’s + /// The minimum number of attempts required before evaluating an order’s /// quality. #[serde( - default = "default_metrics_bad_token_detector_required_measurements", - rename = "metrics-bad-token-detection-required-measurements" + default = "default_metrics_bad_order_detector_required_measurements", + rename = "metrics-bad-order-detection-required-measurements" )] pub metrics_strategy_required_measurements: u32, /// Controls whether the metrics based detection strategy should only log - /// unsupported tokens or actually filter them out. + /// unsupported orders or actually filter them out. #[serde( - default = "default_metrics_bad_token_detector_log_only", - rename = "metrics-bad-token-detection-log-only" + default = "default_metrics_bad_order_detector_log_only", + rename = "metrics-bad-order-detection-log-only" )] pub metrics_strategy_log_only: bool, - /// How long the metrics based bad token detection should flag a token as + /// How long the metrics based bad order detection should flag an order as /// unsupported before it allows to solve for that token again. #[serde( - default = "default_metrics_bad_token_detector_freeze_time", - rename = "metrics-bad-token-detection-token-freeze-time", + default = "default_metrics_bad_order_detector_freeze_time", + rename = "metrics-bad-order-detection-order-freeze-time", + with = "humantime_serde" + )] + pub metrics_strategy_freeze_time: Duration, + + /// How frequently we try to collect garbage on the metrics cache. + #[serde( + default = "default_metrics_bad_order_detector_gc_interval", + rename = "metrics-bad-order-detection-gc-interval", + with = "humantime_serde" + )] + pub metrics_strategy_gc_interval: Duration, + + /// How long we must not have seen an order in a solution before + /// the associated metrics get evicted from the cache. + #[serde( + default = "default_metrics_bad_order_detector_gc_max_age", + rename = "metrics-bad-order-detection-gc-max-age", with = "humantime_serde" )] - pub metrics_strategy_token_freeze_time: Duration, + pub metrics_strategy_gc_max_age: Duration, } -impl Default for BadTokenDetectionConfig { +impl Default for BadOrderDetectionConfig { fn default() -> Self { - serde_json::from_str("{}").expect("MetricsBadTokenDetectorConfig uses default values") + serde_json::from_str("{}").expect("MetricsBadOrderDetectorConfig uses default values") } } @@ -912,11 +995,11 @@ impl<'de> Deserialize<'de> for AppDataFetching { } } -fn default_metrics_bad_token_detector_failure_ratio() -> f64 { +fn default_metrics_bad_order_detector_failure_ratio() -> f64 { 0.9 } -fn default_metrics_bad_token_detector_required_measurements() -> u32 { +fn default_metrics_bad_order_detector_required_measurements() -> u32 { 20 } @@ -927,14 +1010,22 @@ fn default_settle_queue_size() -> usize { 2 } -fn default_metrics_bad_token_detector_log_only() -> bool { +fn default_metrics_bad_order_detector_log_only() -> bool { true } -fn default_metrics_bad_token_detector_freeze_time() -> Duration { +fn default_metrics_bad_order_detector_freeze_time() -> Duration { Duration::from_secs(60 * 10) } +fn default_metrics_bad_order_detector_gc_interval() -> Duration { + Duration::from_mins(1) +} + +fn default_metrics_bad_order_detector_gc_max_age() -> Duration { + Duration::from_hours(1) +} + /// According to statistics, the average size of the app-data is ~800 bytes. /// With this default, the approximate size of the cache will be ~1.6 MB. fn default_app_data_cache_size() -> u64 { @@ -951,3 +1042,190 @@ enum AtBlock { /// Use the latest finalized block. Finalized, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn gas_estimator_alloy_defaults() { + let config: GasEstimatorType = toml::from_str( + r#" + estimator = "alloy" + "#, + ) + .unwrap(); + + match config { + GasEstimatorType::Alloy { + past_blocks, + reward_percentile, + } => { + assert_eq!(past_blocks, 10); + assert_eq!(reward_percentile, 20.0); + } + _ => panic!("expected Alloy variant"), + } + } + + #[test] + fn gas_estimator_alloy_custom_past_blocks() { + let config: GasEstimatorType = toml::from_str( + r#" + estimator = "alloy" + past-blocks = 5 + "#, + ) + .unwrap(); + + match config { + GasEstimatorType::Alloy { + past_blocks, + reward_percentile, + } => { + assert_eq!(past_blocks, 5); + assert_eq!(reward_percentile, 20.0); + } + _ => panic!("expected Alloy variant"), + } + } + + #[test] + fn gas_estimator_alloy_custom_percentile() { + let config: GasEstimatorType = toml::from_str( + r#" + estimator = "alloy" + reward-percentile = 50.0 + "#, + ) + .unwrap(); + + match config { + GasEstimatorType::Alloy { + past_blocks, + reward_percentile, + } => { + assert_eq!(past_blocks, 10); + assert_eq!(reward_percentile, 50.0); + } + _ => panic!("expected Alloy variant"), + } + } + + #[test] + fn gas_estimator_alloy_all_custom() { + let config: GasEstimatorType = toml::from_str( + r#" + estimator = "alloy" + past-blocks = 20 + reward-percentile = 75.0 + "#, + ) + .unwrap(); + + match config { + GasEstimatorType::Alloy { + past_blocks, + reward_percentile, + } => { + assert_eq!(past_blocks, 20); + assert_eq!(reward_percentile, 75.0); + } + _ => panic!("expected Alloy variant"), + } + } + + #[test] + fn gas_estimator_web3() { + let config: GasEstimatorType = toml::from_str( + r#" + estimator = "web3" + "#, + ) + .unwrap(); + + assert!(matches!(config, GasEstimatorType::Web3)); + } + + #[test] + fn gas_estimator_default() { + let config = GasEstimatorType::default(); + + match config { + GasEstimatorType::Alloy { + past_blocks, + reward_percentile, + } => { + assert_eq!(past_blocks, 10); + assert_eq!(reward_percentile, 20.0); + } + _ => panic!("expected Alloy variant as default"), + } + } + + /// Mirrors how `submission-accounts` is declared on `SolverConfig` so the + /// tests exercise the real TOML deserialization path. + #[derive(Debug, Deserialize)] + #[serde(rename_all = "kebab-case")] + struct SubmissionAccountsConfig { + #[serde(default)] + submission_accounts: SubmissionAccounts, + } + + #[test] + fn submission_accounts_default_when_omitted() { + let config: SubmissionAccountsConfig = toml::from_str("").unwrap(); + + assert!(config.submission_accounts.into_inner().is_empty()); + } + + #[test] + fn submission_accounts_accepts_signers() { + let config: SubmissionAccountsConfig = toml::from_str( + r#" + submission-accounts = [ + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + ] + "#, + ) + .unwrap(); + + assert_eq!(config.submission_accounts.into_inner().len(), 1); + } + + #[test] + fn submission_accounts_rejects_address_only_on_deserialization() { + let err = toml::from_str::( + r#" + submission-accounts = ["0x0000000000000000000000000000000000000002"] + "#, + ) + .unwrap_err(); + + assert!(err.to_string().contains("must be signers")); + } + + #[test] + fn submission_accounts_new_accepts_signers() { + let signer = Account::PrivateKey( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + .parse() + .unwrap(), + ); + + let accounts = SubmissionAccounts::new(vec![signer]).unwrap(); + + assert_eq!(accounts.into_inner().len(), 1); + } + + #[test] + fn submission_accounts_new_rejects_address_only() { + let address = "0x0000000000000000000000000000000000000002" + .parse() + .unwrap(); + + let err = SubmissionAccounts::new(vec![Account::Address(address)]).unwrap_err(); + + assert!(err.to_string().contains("must be signers")); + } +} diff --git a/crates/driver/src/infra/config/mod.rs b/crates/driver/src/infra/config/mod.rs index 26e0b84c72..9d23d7780f 100644 --- a/crates/driver/src/infra/config/mod.rs +++ b/crates/driver/src/infra/config/mod.rs @@ -1,16 +1,13 @@ use { - crate::{ - domain::eth, - infra::{ - blockchain, - config::file::{AppDataFetching, GasEstimatorType, OrderPriorityStrategy}, - liquidity, - mempool, - notify, - simulator, - solver, - }, + crate::infra::{ + blockchain, + config::file::{AppDataFetching, GasEstimatorType, OrderPriorityStrategy}, + liquidity, + mempool, + notify, + solver, }, + eth_domain_types as eth, std::time::Duration, }; @@ -24,7 +21,7 @@ pub struct Config { pub solvers: Vec, pub liquidity: liquidity::Config, pub liquidity_sources_notifier: Option, - pub simulator: Option, + pub simulator: configs::simulator::Config, pub gas_estimator: GasEstimatorType, pub mempools: Vec, pub contracts: blockchain::contracts::Addresses, @@ -32,4 +29,5 @@ pub struct Config { pub simulation_bad_token_max_age: Duration, pub app_data_fetching: AppDataFetching, pub tx_gas_limit: eth::U256, + pub http: configs::http_client::HttpClient, } diff --git a/crates/driver/src/infra/liquidity/config.rs b/crates/driver/src/infra/liquidity/config.rs index b2f64faa63..1b7a69df84 100644 --- a/crates/driver/src/infra/liquidity/config.rs +++ b/crates/driver/src/infra/liquidity/config.rs @@ -1,13 +1,12 @@ use { - crate::domain::eth::{self, ContractAddress}, + crate::domain::blockchain::CodeDigest, alloy::primitives::Address, chain::Chain, - contracts::alloy::BalancerV2Vault, + contracts::BalancerV2Vault, derive_more::Debug, - ethrpc::alloy::conversions::IntoLegacy, + eth_domain_types::{self as eth, ContractAddress}, hex_literal::hex, - reqwest::Url, - shared::sources::uniswap_v2::{ + liquidity_sources::uniswap_v2::{ BAOSWAP_INIT, HONEYSWAP_INIT, SUSHISWAP_INIT, @@ -15,6 +14,7 @@ use { TESTNET_UNISWAP_INIT, UNISWAP_INIT, }, + reqwest::Url, std::{collections::HashSet, time::Duration}, }; @@ -52,7 +52,7 @@ pub struct UniswapV2 { pub router: eth::ContractAddress, /// The digest of the pool initialization code. This digest is used for /// computing the deterministic pool addresses per token pair. - pub pool_code: eth::CodeDigest, + pub pool_code: CodeDigest, /// How long liquidity should not be fetched for a token pair that didn't /// return useful liquidity before allowing to fetch it again. pub missing_pool_cache_time: Duration, @@ -63,9 +63,9 @@ impl UniswapV2 { #[expect(clippy::self_named_constructors)] pub fn uniswap_v2(chain: Chain) -> Option { Some(Self { - router: ContractAddress::from( - contracts::alloy::UniswapV2Router02::deployment_address(&chain.id())?.into_legacy(), - ), + router: ContractAddress::from(contracts::UniswapV2Router02::deployment_address( + &chain.id(), + )?), pool_code: UNISWAP_INIT.into(), missing_pool_cache_time: Duration::from_secs(60 * 60), }) @@ -74,9 +74,9 @@ impl UniswapV2 { /// Returns the liquidity configuration for SushiSwap. pub fn sushi_swap(chain: Chain) -> Option { Some(Self { - router: ContractAddress::from( - contracts::alloy::SushiSwapRouter::deployment_address(&chain.id())?.into_legacy(), - ), + router: ContractAddress::from(contracts::SushiSwapRouter::deployment_address( + &chain.id(), + )?), pool_code: SUSHISWAP_INIT.into(), missing_pool_cache_time: Duration::from_secs(60 * 60), }) @@ -85,9 +85,9 @@ impl UniswapV2 { /// Returns the liquidity configuration for Honeyswap. pub fn honeyswap(chain: Chain) -> Option { Some(Self { - router: ContractAddress::from( - contracts::alloy::BaoswapRouter::deployment_address(&chain.id())?.into_legacy(), - ), + router: ContractAddress::from(contracts::HoneyswapRouter::deployment_address( + &chain.id(), + )?), pool_code: HONEYSWAP_INIT.into(), missing_pool_cache_time: Duration::from_secs(60 * 60), }) @@ -96,9 +96,9 @@ impl UniswapV2 { /// Returns the liquidity configuration for Baoswap. pub fn baoswap(chain: Chain) -> Option { Some(Self { - router: ContractAddress::from( - contracts::alloy::BaoswapRouter::deployment_address(&chain.id())?.into_legacy(), - ), + router: ContractAddress::from(contracts::BaoswapRouter::deployment_address( + &chain.id(), + )?), pool_code: BAOSWAP_INIT.into(), missing_pool_cache_time: Duration::from_secs(60 * 60), }) @@ -112,9 +112,9 @@ impl UniswapV2 { } .into(); Some(Self { - router: ContractAddress::from( - contracts::alloy::PancakeRouter::deployment_address(&chain.id())?.into_legacy(), - ), + router: ContractAddress::from(contracts::PancakeRouter::deployment_address( + &chain.id(), + )?), pool_code, missing_pool_cache_time: Duration::from_secs(60 * 60), }) @@ -124,10 +124,9 @@ impl UniswapV2 { /// test networks. pub fn testnet_uniswapv2(chain: Chain) -> Option { Some(Self { - router: ContractAddress::from( - contracts::alloy::TestnetUniswapV2Router02::deployment_address(&chain.id())? - .into_legacy(), - ), + router: ContractAddress::from(contracts::TestnetUniswapV2Router02::deployment_address( + &chain.id(), + )?), pool_code: TESTNET_UNISWAP_INIT.into(), missing_pool_cache_time: Duration::from_secs(60 * 60), }) @@ -141,7 +140,7 @@ pub struct Swapr { pub router: eth::ContractAddress, /// The digest of the pool initialization code. This digest is used for /// computing the deterministic pool addresses per token pair. - pub pool_code: eth::CodeDigest, + pub pool_code: CodeDigest, /// How long liquidity should not be fetched for a token pair that didn't /// return useful liquidity before allowing to fetch it again. pub missing_pool_cache_time: Duration, @@ -152,15 +151,47 @@ impl Swapr { #[expect(clippy::self_named_constructors)] pub fn swapr(chain: Chain) -> Option { Some(Self { - router: ContractAddress::from( - contracts::alloy::SwaprRouter::deployment_address(&chain.id())?.into_legacy(), - ), + router: ContractAddress::from(contracts::SwaprRouter::deployment_address(&chain.id())?), pool_code: SWAPR_INIT.into(), missing_pool_cache_time: Duration::from_secs(60 * 60), }) } } +/// Subgraph-specific Uniswap V3 config. +#[derive(Clone, Debug)] +pub struct UniswapV3Subgraph { + pub url: Url, + + /// How many pool IDs can be present in a where clause of a Tick query at + /// once. Some subgraphs are overloaded and throw errors when there are + /// too many. + pub max_pools_per_tick_query: usize, +} + +/// Pool-indexer-specific Uniswap V3 config. +#[derive(Clone, Debug)] +pub struct UniswapV3PoolIndexer { + /// Service root, e.g. `http://pool-indexer/` exposing + /// `/api/v1/{network}/uniswap/v3/`. + pub url: Url, + + /// Upper bound on a single `wait_until` call. Size per-network to + /// comfortably exceed the worst-case first-deploy seed time (~13 min + /// for mainnet's ~60k pools; tens of seconds for smaller chains). + pub wait_until_timeout: Duration, +} + +/// Where Uniswap V3 pool definitions and tick data are fetched from. Exactly +/// one source is active per network. +#[derive(Clone, Debug)] +pub enum UniswapV3PoolSource { + /// A Uniswap V3 subgraph (typically Goldsky-hosted). + Subgraph(UniswapV3Subgraph), + /// A CoW pool-indexer service exposing `/api/v1/{network}/uniswap/v3/`. + PoolIndexer(UniswapV3PoolIndexer), +} + /// Uniswap V3 liquidity fetching options. #[derive(Clone, Debug)] pub struct UniswapV3 { @@ -170,35 +201,23 @@ pub struct UniswapV3 { /// How many pools should be initialized during start up. pub max_pools_to_initialize: usize, - /// The URL used to connect to uniswap v3 subgraph client. - pub graph_url: Url, + /// Where pool data is fetched from (subgraph or pool-indexer). + pub pool_source: UniswapV3PoolSource, /// How often the liquidity source should be reinitialized to /// become aware of new pools. pub reinit_interval: Option, - - /// How many pool IDs can be present in a where clause of a Tick query at - /// once. Some subgraphs are overloaded and throw errors when there are - /// too many. - pub max_pools_per_tick_query: usize, } impl UniswapV3 { /// Returns the liquidity configuration for Uniswap V3. #[expect(clippy::self_named_constructors)] - pub fn uniswap_v3( - graph_url: &Url, - chain: Chain, - max_pools_per_tick_query: usize, - ) -> Option { + pub fn uniswap_v3(pool_source: UniswapV3PoolSource, chain: Chain) -> Option { Some(Self { - router: contracts::alloy::UniswapV3SwapRouterV2::deployment_address(&chain.id())? - .into_legacy() - .into(), + router: contracts::UniswapV3SwapRouterV2::deployment_address(&chain.id())?.into(), max_pools_to_initialize: 100, - graph_url: graph_url.clone(), + pool_source, reinit_interval: None, - max_pools_per_tick_query, }) } } @@ -229,7 +248,7 @@ pub struct BalancerV2 { /// Since pools allow for custom controllers and logic, it is possible for /// pools to get "bricked". This configuration allows those pools to be /// ignored. - pub pool_deny_list: Vec, + pub pool_deny_list: Vec, /// The base URL used to connect to balancer v2 subgraph client. pub graph_url: Url, @@ -255,37 +274,37 @@ impl BalancerV2 { } Some(Self { - vault: ContractAddress(BalancerV2Vault::deployment_address(&chain.id())?.into_legacy()), + vault: ContractAddress::from(BalancerV2Vault::deployment_address(&chain.id())?), weighted: address_for!( chain, [ - contracts::alloy::BalancerV2WeightedPoolFactory, - contracts::alloy::BalancerV2WeightedPool2TokensFactory, + contracts::BalancerV2WeightedPoolFactory, + contracts::BalancerV2WeightedPool2TokensFactory, ] ), weighted_v3plus: address_for!( chain, [ - contracts::alloy::BalancerV2WeightedPoolFactoryV3, - contracts::alloy::BalancerV2WeightedPoolFactoryV4, + contracts::BalancerV2WeightedPoolFactoryV3, + contracts::BalancerV2WeightedPoolFactoryV4, ] ), - stable: address_for!(chain, [contracts::alloy::BalancerV2StablePoolFactoryV2,]), + stable: address_for!(chain, [contracts::BalancerV2StablePoolFactoryV2,]), liquidity_bootstrapping: address_for!( chain, [ - contracts::alloy::BalancerV2LiquidityBootstrappingPoolFactory, - contracts::alloy::BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory, + contracts::BalancerV2LiquidityBootstrappingPoolFactory, + contracts::BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory, ] ), composable_stable: address_for!( chain, [ - contracts::alloy::BalancerV2ComposableStablePoolFactory, - contracts::alloy::BalancerV2ComposableStablePoolFactoryV3, - contracts::alloy::BalancerV2ComposableStablePoolFactoryV4, - contracts::alloy::BalancerV2ComposableStablePoolFactoryV5, - contracts::alloy::BalancerV2ComposableStablePoolFactoryV6, + contracts::BalancerV2ComposableStablePoolFactory, + contracts::BalancerV2ComposableStablePoolFactoryV3, + contracts::BalancerV2ComposableStablePoolFactoryV4, + contracts::BalancerV2ComposableStablePoolFactoryV5, + contracts::BalancerV2ComposableStablePoolFactoryV6, ] ), pool_deny_list: Vec::new(), diff --git a/crates/driver/src/infra/mempool/mod.rs b/crates/driver/src/infra/mempool/mod.rs index f80d03ce04..5b7d3c9884 100644 --- a/crates/driver/src/infra/mempool/mod.rs +++ b/crates/driver/src/infra/mempool/mod.rs @@ -1,10 +1,21 @@ use { crate::{ - boundary::unbuffered_web3_client, - domain::{competition, eth, mempools}, - infra, + boundary::{Web3, unbuffered_web3}, + domain::mempools, + infra::{self, solver::Account}, }, - ethrpc::Web3, + alloy::{ + consensus::Transaction, + eips::{BlockNumberOrTag, eip1559::Eip1559Estimation}, + primitives::Address, + providers::{Provider, ext::TxPoolApi}, + rpc::types::TransactionRequest, + }, + anyhow::Context, + dashmap::DashMap, + eth_domain_types as eth, + std::sync::Arc, + url::Url, }; #[derive(Debug, Clone)] @@ -13,32 +24,30 @@ pub struct Config { pub gas_price_cap: eth::U256, pub target_confirm_time: std::time::Duration, pub retry_interval: std::time::Duration, - pub kind: Kind, + /// Optional block number to use when fetching nonces. If None, uses the + /// web3 lib's default behavior, which is `latest`. + pub nonce_block_number: Option, + pub url: Url, + pub name: String, + pub revert_protection: RevertProtection, + pub max_additional_tip: eth::U256, + pub additional_tip_percentage: f64, } -#[derive(Debug, Clone)] -pub enum Kind { - /// The public mempool of the [`Ethereum`] node. - Public { - max_additional_tip: eth::U256, - additional_tip_percentage: f64, - revert_protection: RevertProtection, - }, - /// The MEVBlocker private mempool. - MEVBlocker { - url: reqwest::Url, - max_additional_tip: eth::U256, - additional_tip_percentage: f64, - use_soft_cancellations: bool, - }, -} - -impl Kind { - /// for instrumentization purposes - pub fn format_variant(&self) -> &'static str { - match self { - Kind::Public { .. } => "PublicMempool", - Kind::MEVBlocker { .. } => "MEVBlocker", +#[cfg(test)] +impl Config { + pub fn test_config(url: Url) -> Self { + Self { + min_priority_fee: Default::default(), + gas_price_cap: eth::U256::from(1000000000000_u128), + target_confirm_time: Default::default(), + retry_interval: Default::default(), + name: "default_rpc".to_string(), + max_additional_tip: eth::U256::from(3000000000_u128), + additional_tip_percentage: 0., + revert_protection: infra::mempool::RevertProtection::Disabled, + nonce_block_number: None, + url, } } } @@ -58,78 +67,158 @@ pub enum RevertProtection { pub struct Mempool { transport: Web3, config: Config, + last_submissions: Arc>, +} + +#[derive(Debug, Clone)] +pub struct Submission { + pub nonce: u64, + pub gas_price: Eip1559Estimation, } impl std::fmt::Display for Mempool { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Mempool({})", self.config.kind.format_variant()) + write!(f, "Mempool({})", self.config.name) } } impl Mempool { - pub fn new(config: Config, transport: Web3) -> Self { - let transport = match &config.kind { - Kind::Public { .. } => transport, - // Flashbots Protect RPC fallback doesn't support buffered transport - Kind::MEVBlocker { url, .. } => unbuffered_web3_client(url), - }; - Self { config, transport } + pub fn new(config: Config, solver_accounts: Vec) -> Self { + let transport = unbuffered_web3(&config.url); + // Register the solver accounts into the wallet to submit txs on their behalf + for account in solver_accounts { + transport.wallet.register_signer(account); + } + Self { + transport, + config, + last_submissions: Default::default(), + } } - /// Fetches the pending transaction count (nonce) for the given address. - /// This includes both mined transactions and pending transactions in the - /// mempool. - pub async fn get_pending_nonce( - &self, - address: eth::Address, - ) -> Result { - self.transport - .eth() - .transaction_count(address.into(), Some(web3::types::BlockNumber::Pending)) - .await - .map_err(|err| { - mempools::Error::Other( - anyhow::Error::from(err).context("failed to fetch pending nonce"), - ) - }) + /// Fetches the transaction count (nonce) for the given address at the + /// specified block number. If no block number is provided in the config, + /// uses the alloy's default behavior. + pub async fn get_nonce(&self, address: eth::Address) -> Result { + let call = self.transport.provider.get_transaction_count(address); + match self.config.nonce_block_number { + Some(BlockNumberOrTag::Latest) => call.latest(), + Some(BlockNumberOrTag::Earliest) => call.earliest(), + Some(BlockNumberOrTag::Finalized) => call.finalized(), + Some(BlockNumberOrTag::Number(number)) => call.number(number), + Some(BlockNumberOrTag::Pending) => call.pending(), + Some(BlockNumberOrTag::Safe) => call.safe(), + None => call, + } + .await + .map_err(|err| { + mempools::Error::Other(anyhow::Error::from(err).context("failed to fetch nonce")) + }) } /// Submits a transaction to the mempool. Returns optimistically as soon as - /// the transaction is pending. + /// the transaction is pending. `signer` is the address that signs and pays + /// for gas (may differ from the solver address in EIP-7702 mode). pub async fn submit( &self, tx: eth::Tx, - gas: competition::solution::settlement::Gas, - solver: &infra::Solver, - nonce: eth::U256, + gas_price: Eip1559Estimation, + gas_limit: eth::Gas, + signer: eth::Address, + nonce: u64, ) -> Result { - ethcontract::transaction::TransactionBuilder::new(self.transport.legacy.clone()) - .from(solver.account().clone()) - .to(tx.to.into()) + let max_fee_per_gas = gas_price.max_fee_per_gas; + let max_priority_fee_per_gas = gas_price.max_priority_fee_per_gas; + let gas_limit = gas_limit.0.try_into().map_err(anyhow::Error::from)?; + + let tx_request = TransactionRequest::default() + .from(signer) + .to(tx.to) .nonce(nonce) - .gas_price(ethcontract::GasPrice::Eip1559 { - max_fee_per_gas: gas.price.max().into(), - max_priority_fee_per_gas: gas.price.tip().into(), - }) - .data(tx.input.into()) + .max_fee_per_gas(max_fee_per_gas) + .max_priority_fee_per_gas(max_priority_fee_per_gas) + .gas_limit(gas_limit) + .input(tx.input.into()) .value(tx.value.0) - .gas(gas.limit.0) - .access_list(web3::types::AccessList::from(tx.access_list)) - .resolve(ethcontract::transaction::ResolveCondition::Pending) - .send() + .access_list(tx.access_list.into()); + + let submission = self + .transport + .provider + .send_transaction(tx_request) .await - .map(|result| eth::TxId(result.hash())) - .map_err(|err| mempools::Error::Other(anyhow::Error::from(err))) + .map_err(anyhow::Error::from); + + match submission { + Ok(tx) => { + tracing::debug!( + ?nonce, + ?gas_price, + ?gas_limit, + ?signer, + "successfully submitted tx to mempool" + ); + self.last_submissions + .insert(signer, Submission { nonce, gas_price }); + Ok(eth::TxId(*tx.tx_hash())) + } + Err(err) => { + // log pending tx in case we failed to replace a pending tx + let last_submission = self.last_submission(signer); + + tracing::debug!( + ?err, + new_gas_price = ?gas_price, + ?nonce, + ?last_submission, + ?gas_limit, + ?signer, + "failed to submit tx to mempool" + ); + Err(mempools::Error::Other(err)) + } + } + } + + /// Queries the mempool for a pending transaction of the given solver and + /// nonce. + pub async fn find_pending_tx_in_mempool( + &self, + signer: eth::Address, + nonce: u64, + ) -> anyhow::Result> { + let tx_pool_content = self + .transport + .provider + .txpool_content_from(signer) + .await + .context("failed to query pending transactions")?; + + // find the one with the specified nonce + let pending_tx = tx_pool_content + .pending + .into_iter() + .chain(tx_pool_content.queued) + .find(|(_signer, tx)| tx.nonce() == nonce) + .map(|(_, tx)| tx); + Ok(pending_tx) + } + + /// Looks up the last tx that was submitted for that signer. + pub fn last_submission(&self, signer: eth::Address) -> Option { + self.last_submissions + .get(&signer) + .map(|entry| entry.value().clone()) } pub fn config(&self) -> &Config { &self.config } - pub fn may_revert(&self) -> bool { - match &self.config.kind { - Kind::Public { .. } => true, - Kind::MEVBlocker { .. } => false, - } + pub fn reverts_can_get_mined(&self) -> bool { + matches!( + self.config.revert_protection, + infra::mempool::RevertProtection::Disabled + ) } } diff --git a/crates/driver/src/infra/mod.rs b/crates/driver/src/infra/mod.rs index b33526f545..929d03119d 100644 --- a/crates/driver/src/infra/mod.rs +++ b/crates/driver/src/infra/mod.rs @@ -7,16 +7,8 @@ pub mod mempool; pub mod notify; pub mod observe; pub mod persistence; -pub mod simulator; pub mod solver; pub mod time; pub mod tokens; -pub use { - self::solver::Solver, - api::Api, - blockchain::Ethereum, - config::Config, - mempool::Mempool, - simulator::Simulator, -}; +pub use {self::solver::Solver, api::Api, blockchain::Ethereum, config::Config, mempool::Mempool}; diff --git a/crates/driver/src/infra/notify/liquidity_sources/liquorice/notifier.rs b/crates/driver/src/infra/notify/liquidity_sources/liquorice/notifier.rs index f951392ddf..182c384e00 100644 --- a/crates/driver/src/infra/notify/liquidity_sources/liquorice/notifier.rs +++ b/crates/driver/src/infra/notify/liquidity_sources/liquorice/notifier.rs @@ -20,7 +20,7 @@ use { alloy::primitives::Address, anyhow::{Context, Result, anyhow}, chrono::Utc, - contracts::alloy::LiquoriceSettlement, + contracts::LiquoriceSettlement, }; const NOTIFICATION_SOURCE: &str = "cow_protocol"; @@ -85,12 +85,11 @@ impl LiquiditySourceNotifying for Notifier { mod utils { use { crate::domain::{ + self, competition::solution::{self, Settlement}, - eth, }, alloy::{primitives::Address, sol_types::SolCall}, - contracts::alloy::LiquoriceSettlement, - ethrpc::alloy::conversions::IntoAlloy, + contracts::LiquoriceSettlement, std::collections::HashSet, }; @@ -113,7 +112,7 @@ mod utils { .iter() .filter_map(|interaction| match interaction { solution::Interaction::Custom(custom) => extract_rfq_id_from_interaction( - ð::Interaction { + &domain::Interaction { target: custom.target.into(), value: custom.value, call_data: custom.call_data.clone(), @@ -142,10 +141,10 @@ mod utils { /// `settleSingle` function of the LiquoriceSettlement contract /// pub fn extract_rfq_id_from_interaction( - interaction: ð::Interaction, + interaction: &domain::Interaction, liquorice_settlement_contract_address: Address, ) -> Option { - if interaction.target.0.into_alloy() != liquorice_settlement_contract_address { + if interaction.target != liquorice_settlement_contract_address { return None; } @@ -162,26 +161,24 @@ mod utils { mod tests { use { crate::{ - domain::eth, + domain, infra::notify::liquidity_sources::liquorice::notifier::utils::extract_rfq_id_from_interaction, - util::Bytes, }, - ethrpc::alloy::conversions::IntoAlloy, - primitive_types::H160, + alloy::primitives::{Address, Bytes}, }; #[test] fn test_extract_rfq_id_from_valid_settle_single_call() { let calldata = const_hex::decode("9935c868000000000000000000000000b10b9c690a681b6285c2e2df7734f9d729c5c4d500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000001dcd65000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab410000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000001dcd6500000000000000000000000000000000000000000000000000000000001dcd650000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000068a76fd0000000000000000000000000b10b9c690a681b6285c2e2df7734f9d729c5c4d5000000000000000000000000000000000000000000000000000000000000002463393964326533662d373032622d343963392d386262382d343337373537373066326633000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000041d44f6881d24cd3ad94561d1aad5e220929181cf728f89620629e0efbe3daa9833b9f2967bf37381f56b41266327a3804c92204f30a2d660cae8b42cd6f7d9b701c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); - let liquorice_settlement_address = H160::random().into(); + let liquorice_settlement_address = Address::random(); let rfq_id = extract_rfq_id_from_interaction( - ð::Interaction { + &domain::Interaction { target: liquorice_settlement_address, - call_data: Bytes(calldata), + call_data: calldata.into(), value: 0.into(), }, - liquorice_settlement_address.0.into_alloy(), + liquorice_settlement_address, ) .unwrap(); assert_eq!(rfq_id, "c99d2e3f-702b-49c9-8bb8-43775770f2f3".to_string()); @@ -189,14 +186,14 @@ mod utils { #[test] fn test_returns_none_for_arbitrary_call() { - let liquorice_settlement_address = H160::random().into(); + let liquorice_settlement_address = Address::random(); let rfq_id = extract_rfq_id_from_interaction( - ð::Interaction { + &domain::Interaction { target: liquorice_settlement_address, - call_data: Bytes(vec![]), + call_data: Bytes::new(), value: 0.into(), }, - liquorice_settlement_address.0.into_alloy(), + liquorice_settlement_address, ); assert!(rfq_id.is_none()); @@ -205,12 +202,12 @@ mod utils { #[test] fn test_returns_none_for_different_target() { let rfq_id = extract_rfq_id_from_interaction( - ð::Interaction { - target: H160::random().into(), - call_data: Bytes(vec![]), + &domain::Interaction { + target: Address::random(), + call_data: Bytes::new(), value: 0.into(), }, - H160::random().into_alloy(), + Address::random(), ); assert!(rfq_id.is_none()); diff --git a/crates/driver/src/infra/notify/liquidity_sources/mod.rs b/crates/driver/src/infra/notify/liquidity_sources/mod.rs index 2a7c409bf0..43adda3549 100644 --- a/crates/driver/src/infra/notify/liquidity_sources/mod.rs +++ b/crates/driver/src/infra/notify/liquidity_sources/mod.rs @@ -8,14 +8,13 @@ /// need to know as early as possible that their quote will be used for the /// settlement. It is crucial for risk management and leads to better /// pricing. -use futures::FutureExt; pub mod config; pub mod liquorice; pub use config::Config; use { crate::domain::competition::solution::settlement::Settlement, - ethcontract::jsonrpc::futures_util::future::join_all, + futures::{FutureExt, future::join_all}, std::{collections::HashMap, sync::Arc}, }; diff --git a/crates/driver/src/infra/notify/mod.rs b/crates/driver/src/infra/notify/mod.rs index 14187231b8..8e6d8d97d9 100644 --- a/crates/driver/src/infra/notify/mod.rs +++ b/crates/driver/src/infra/notify/mod.rs @@ -6,18 +6,8 @@ use { pub mod liquidity_sources; mod notification; -pub use notification::{ - BanReason, - Kind, - Notification, - ScoreKind, - Settlement, - SimulationSucceededAtLeastOnce, -}; -use { - super::simulator, - crate::domain::{eth, mempools::Error}, -}; +pub use notification::{Kind, Notification, ScoreKind, Settlement, SimulationSucceededAtLeastOnce}; +use {crate::domain::mempools::Error, eth_domain_types as eth}; pub fn solver_timeout(solver: &Solver, auction_id: Option) { solver.notify(auction_id, None, notification::Kind::Timeout); @@ -105,6 +95,14 @@ pub fn simulation_failed( solver.notify(auction_id, Some(solution_id.clone()), kind); } +pub fn settlement_started(solver: &Solver, auction_id: auction::Id, solution_id: &solution::Id) { + solver.notify( + Some(auction_id), + Some(solution_id.clone()), + notification::Kind::SettlementStarted, + ); +} + pub fn executed( solver: &Solver, auction_id: auction::Id, @@ -112,8 +110,8 @@ pub fn executed( res: &Result, ) { let kind = match res { - Ok(hash) => notification::Settlement::Success(hash.clone()), - Err(Error::Revert { tx_id: hash, .. }) => notification::Settlement::Revert(hash.clone()), + Ok(hash) => notification::Settlement::Success(*hash), + Err(Error::Revert { tx_id: hash, .. }) => notification::Settlement::Revert(*hash), Err(Error::SimulationRevert { .. }) => notification::Settlement::SimulationRevert, Err(Error::Expired { .. }) => notification::Settlement::Expired, Err(Error::Other(_) | Error::Disabled) => notification::Settlement::Fail, diff --git a/crates/driver/src/infra/notify/notification.rs b/crates/driver/src/infra/notify/notification.rs index 265bcab5b2..b8f50e0d9b 100644 --- a/crates/driver/src/infra/notify/notification.rs +++ b/crates/driver/src/infra/notify/notification.rs @@ -1,9 +1,6 @@ use { - crate::domain::{ - competition::{auction, solution}, - eth::{self, Ether, TokenAddress}, - }, - chrono::{DateTime, Utc}, + crate::domain::competition::{auction, solution}, + eth_domain_types::{self as eth, Ether, TokenAddress}, std::collections::BTreeSet, }; @@ -39,6 +36,8 @@ pub enum Kind { NonBufferableTokensUsed(TokensUsed), /// Solver don't have enough balance to submit the solution onchain. SolverAccountInsufficientBalance(RequiredEther), + /// Solver won, driver is trying to settle the transaction onchain. + SettlementStarted, /// Result of winning solver trying to settle the transaction onchain. Settled(Settlement), /// Some aspect of the driver logic failed preventing the solution from @@ -46,11 +45,6 @@ pub enum Kind { DriverError(String), /// On-chain solution postprocessing timed out. PostprocessingTimedOut, - /// The solver has been banned for a specific reason. - Banned { - reason: BanReason, - until: DateTime, - }, /// The solver sent an invalid request format DeserializationError(String), } @@ -66,14 +60,6 @@ pub enum ScoreKind { MissingPrice(TokenAddress), } -#[derive(Debug)] -pub enum BanReason { - /// The driver won multiple consecutive auctions but never settled them. - UnsettledConsecutiveAuctions, - /// Driver's settle failure rate is above the threshold. - HighSettleFailureRate, -} - #[derive(Debug)] pub enum Settlement { /// Winning solver settled successfully transaction onchain. diff --git a/crates/driver/src/infra/observe/metrics.rs b/crates/driver/src/infra/observe/metrics.rs index 6098c9bf2f..7177995b9d 100644 --- a/crates/driver/src/infra/observe/metrics.rs +++ b/crates/driver/src/infra/observe/metrics.rs @@ -25,9 +25,11 @@ pub struct Metrics { /// atempted and the error detection. #[metric(labels("mempool", "result"))] pub mempool_submission_results_blocks_passed: prometheus::IntCounterVec, + /// How many orders detected by specific solver and strategy. + #[metric(labels("solver"))] + pub bad_orders_detected: prometheus::IntCounterVec, /// How many tokens detected by specific solver and strategy. - #[metric(labels("solver", "strategy"))] - pub bad_tokens_detected: prometheus::IntCounterVec, + pub bad_tokens_detected: prometheus::IntCounter, /// Time spent in the auction preprocessing stage. #[metric( labels("stage"), @@ -39,16 +41,17 @@ pub struct Metrics { /// Remaining time the solver has to compute a solution. #[metric( - labels("solver"), + labels("solver", "kind"), buckets( - 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 7., 7.5, 8., 8.5, 9., 9.5, 10, 10.5, 11. + 0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 7., 7.5, 8., 8.5, 9., 9.5, + 10, 10.5, 11. ) )] pub remaining_solve_time: prometheus::HistogramVec, /// How much time it took to receive a response from the solver. #[metric( - labels("solver"), + labels("solver", "kind"), buckets( 0.5, 1, 1.5, 2, 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 7., 7.5, 8., 8.5, 9., 9.5, 10, 10.5, 11. diff --git a/crates/driver/src/infra/observe/mod.rs b/crates/driver/src/infra/observe/mod.rs index f6dbab6fec..bf52d5626f 100644 --- a/crates/driver/src/infra/observe/mod.rs +++ b/crates/driver/src/infra/observe/mod.rs @@ -4,7 +4,7 @@ //! and update the metrics, if the event is worth measuring. use { - super::{Ethereum, Mempool, simulator, solver::Timeouts}, + super::{Mempool, solver::Timeouts}, crate::{ boundary, domain::{ @@ -15,7 +15,6 @@ use { Solved, solution::{self, Settlement}, }, - eth::{self, Gas}, mempools::{self, SubmissionSuccess}, quote::{self, Quote}, time::{Deadline, Remaining}, @@ -23,7 +22,9 @@ use { infra::solver, util::http, }, + eth_domain_types as eth, ethrpc::block_stream::BlockInfo, + observe::tracing::lazy::Lazy, std::{ collections::{BTreeMap, HashSet}, time::Duration, @@ -36,8 +37,10 @@ pub mod metrics; /// Setup the observability. The log argument configures the tokio tracing /// framework. pub fn init(obs_config: observe::Config) { - observe::tracing::initialize_reentrant(&obs_config); + observe::tracing::init::initialize_reentrant(&obs_config); metrics::init(); + #[cfg(unix)] + observe::heap_dump_handler::spawn_heap_dump_handler(); } /// Observe a received auction. @@ -120,22 +123,34 @@ pub fn encoding(id: &solution::Id) { } /// Observe that settlement encoding failed. -pub fn encoding_failed(solver: &solver::Name, id: &solution::Id, err: &solution::Error) { - tracing::info!(?id, ?err, "discarded solution: settlement encoding"); +pub fn encoding_failed( + solver: &solver::Name, + id: &solution::Id, + err: &solution::Error, + has_haircut: bool, + orders: &[competition::order::Uid], +) { + tracing::info!( + ?id, + ?orders, + ?err, + has_haircut, + "discarded solution: settlement encoding" + ); + let reason = if has_haircut { + "SettlementEncodingHaircut" + } else { + "SettlementEncoding" + }; metrics::get() .dropped_solutions - .with_label_values(&[solver.as_str(), "SettlementEncoding"]) + .with_label_values(&[solver.as_str(), reason]) .inc(); } /// Observe that two solutions were merged. pub fn merged(first: &Solution, other: &Solution, result: &Solution) { - tracing::debug!(?first, ?other, ?result, "merged solutions"); -} - -/// Observe that it was not possible to merge two solutions. -pub fn not_merged(first: &Solution, other: &Solution, err: solution::error::Merge) { - tracing::debug!(?err, ?first, ?other, "solutions can't be merged"); + tracing::trace!(?first, ?other, ?result, "merged solutions"); } /// Observe that scoring is about to start. @@ -167,8 +182,27 @@ pub fn score(settlement: &Settlement, score: ð::Ether) { // Observe that the winning settlement started failing upon arrival of a new // block -pub fn winner_voided(block: BlockInfo, err: &simulator::RevertError) { - tracing::warn!(block = block.number, ?err, "solution reverts on new block"); +pub fn winner_voided( + solver: &solver::Name, + block: BlockInfo, + err: &simulator::RevertError, + has_haircut: bool, +) { + tracing::warn!( + block = block.number, + ?err, + has_haircut, + "solution reverts on new block" + ); + let reason = if has_haircut { + "SimulationRevertHaircut" + } else { + "SimulationRevert" + }; + metrics::get() + .dropped_solutions + .with_label_values(&[solver.as_str(), reason]) + .inc(); } pub fn revealing() { @@ -220,27 +254,27 @@ pub fn settled(solver: &solver::Name, result: &Result, competition::Error>) { +pub fn solved(solver: &str, result: &Result, competition::Error>) { match result { - Ok(Some(solved)) => { - tracing::info!(?solved, "solved auction"); + Ok(solutions) if solutions.is_empty() => { + tracing::debug!("no solution found"); metrics::get() .solutions - .with_label_values(&[solver.as_str(), "Success"]) + .with_label_values(&[solver, "SolutionNotFound"]) .inc(); } - Ok(None) => { - tracing::debug!("no solution found"); + Ok(solutions) => { + tracing::info!(?solutions, "solved auction"); metrics::get() .solutions - .with_label_values(&[solver.as_str(), "SolutionNotFound"]) - .inc(); + .with_label_values(&[solver, "Success"]) + .inc_by(solutions.len() as u64); } Err(err) => { tracing::warn!(?err, "failed to solve auction"); metrics::get() .solutions - .with_label_values(&[solver.as_str(), competition_error(err)]) + .with_label_values(&[solver, competition_error(err)]) .inc(); } } @@ -272,6 +306,10 @@ pub fn quoted(solver: &solver::Name, order: "e::Order, result: &Result { "NoSolutions" } + quote::Error::QuotingFailed(quote::QuotingFailed::Math) => "MathError", + quote::Error::QuotingFailed(quote::QuotingFailed::UnsupportedToken) => { + "UnsupportedToken" + } quote::Error::DeadlineExceeded(_) => "DeadlineExceeded", quote::Error::Blockchain(_) => "BlockchainError", quote::Error::Solver(solver::Error::Http(_)) => "SolverHttpError", @@ -279,6 +317,7 @@ pub fn quoted(solver: &solver::Name, order: "e::Order, result: &Result "SolverDtoError", + quote::Error::Solver(solver::Error::CustomError(_)) => "SolverCustomError", quote::Error::Boundary(_) => "Unknown", quote::Error::Encoding(_) => "Encoding", }, @@ -294,7 +333,8 @@ pub fn mounting_solver(solver: &solver::Name, path: &str) { } /// Observe that a request is about to be sent to the solver. -pub fn solver_request(endpoint: &Url, req: &str) { +pub fn solver_request(endpoint: &Url, req: impl AsRef<[u8]>) { + let req = Lazy(|| String::from_utf8_lossy(req.as_ref())); tracing::trace!(%endpoint, %req, "sending request to solver"); } @@ -304,6 +344,7 @@ pub fn solver_response( res: Result<&str, &http::Error>, solver: &str, compute_time: Duration, + is_quote_request: bool, ) { match res { Ok(res) => { @@ -313,86 +354,56 @@ pub fn solver_response( tracing::warn!(%endpoint, ?err, "failed to receive response from solver") } } + let kind = if is_quote_request { "quote" } else { "auction" }; metrics::get() .used_solve_time - .with_label_values(&[solver]) + .with_label_values(&[solver, kind]) .observe(compute_time.as_secs_f64()); } -/// Observe the result of mempool transaction execution. -pub fn mempool_executed( +/// Log a single mempool submission attempt. Called inline from the racing +/// task so that errors from mempools that later get superseded are still +/// visible in logs. Metrics are emitted separately from `update_metrics` +/// once the race outcome is known. +pub fn mempool_log( mempool: &Mempool, settlement: &Settlement, - res: &Result, + result: &Result, ) { - match res { - Ok(submission) => { - tracing::info!( - txid = ?submission.tx_hash, - %mempool, - ?settlement, - "sending transaction via mempool succeeded", - ); - } - Err(mempools::Error::Disabled) => { - tracing::debug!( - %mempool, - "sending transaction via mempool disabled", - ); - } - Err(err) => { - tracing::warn!( - ?err, - %mempool, - ?settlement, - "sending transaction via mempool failed", - ); - } + match result { + Ok(submission) => tracing::info!( + txid = ?submission.tx_hash, + %mempool, + ?settlement, + "sending transaction via mempool succeeded", + ), + Err(mempools::Error::Disabled) => tracing::debug!( + %mempool, + "mempool disabled, not sending transaction", + ), + Err(err) => tracing::warn!( + ?err, + %mempool, + ?settlement, + "sending transaction via mempool failed", + ), } - let result = match res { - Ok(_) => "Success", - Err(mempools::Error::Revert { .. } | mempools::Error::SimulationRevert { .. }) => "Revert", - Err(mempools::Error::Expired { .. }) => "Expired", - Err(mempools::Error::Other(_)) => "Other", - Err(mempools::Error::Disabled) => "Disabled", - }; +} + +/// Emit per-mempool race counters with the final, reclassified label +/// (`Success` / `Revert` / `Expired` / `Other` / `Superseded` / `Disabled`). +/// Called once per mempool after the race resolves. +pub fn mempool_submission_result(mempool: &Mempool, label: &str, blocks_passed: Option) { + let name = mempool.to_string(); metrics::get() .mempool_submission - .with_label_values(&[&mempool.to_string(), result]) + .with_label_values(&[name.as_str(), label]) .inc(); - - // For some of the errors we are interested in observing the exact block numbers - // passed since the first submission. - let blocks_passed = match res { - Ok(SubmissionSuccess { - submitted_at_block, - included_in_block, - .. - }) => Some(("Success", &submitted_at_block.0, &included_in_block.0)), - Err(mempools::Error::Revert { - tx_id: _, - submitted_at_block, - reverted_at_block, - }) => Some(("Revert", submitted_at_block, reverted_at_block)), - Err(mempools::Error::SimulationRevert { - submitted_at_block, - reverted_at_block, - }) => Some(("Revert", submitted_at_block, reverted_at_block)), - Err(mempools::Error::Expired { - tx_id: _, - submitted_at_block, - submission_deadline, - }) => Some(("Expired", submitted_at_block, submission_deadline)), - Err(mempools::Error::Other(_)) => None, - Err(mempools::Error::Disabled) => None, - }; - - if let Some((label, start, end)) = blocks_passed { - let blocks_passed = end.saturating_sub(*start); + if let Some(blocks) = blocks_passed { metrics::get() .mempool_submission_results_blocks_passed - .with_label_values(&[&mempool.to_string(), label]) - .inc_by(blocks_passed); + .with_label_values(&[name.as_str(), label]) + .inc_by(blocks); } } @@ -413,6 +424,7 @@ fn competition_error(err: &competition::Error) -> &'static str { competition::Error::Solver(solver::Error::Http(_)) => "SolverHttpError", competition::Error::Solver(solver::Error::Deserialize(_)) => "SolverDeserializeError", competition::Error::Solver(solver::Error::Dto(_)) => "SolverDtoError", + competition::Error::Solver(solver::Error::CustomError(_)) => "SolverCustomError", competition::Error::SubmissionError => "SubmissionError", competition::Error::TooManyPendingSettlements => "TooManyPendingSettlements", competition::Error::NoValidOrdersFound => "NoValidOrdersFound", @@ -421,14 +433,15 @@ fn competition_error(err: &competition::Error) -> &'static str { } pub fn deadline(deadline: &Deadline, timeouts: &Timeouts) { - tracing::debug!(?deadline, ?timeouts, "computed deadline"); + tracing::trace!(?deadline, ?timeouts, "computed deadline"); } -pub fn sending_solve_request(solver: &str, remaining_time: Duration) { +pub fn sending_solve_request(solver: &str, remaining_time: Duration, is_quote_request: bool) { tracing::trace!(?remaining_time, "sending solve request"); + let kind = if is_quote_request { "quote" } else { "auction" }; metrics::get() .remaining_solve_time - .with_label_values(&[solver]) + .with_label_values(&[solver, kind]) .observe(remaining_time.as_secs_f64()); } @@ -445,12 +458,3 @@ pub fn order_excluded_from_auction( ) { tracing::trace!(uid=?order.uid, ?reason, "order excluded from auction"); } - -/// Observe that a settlement was simulated -pub fn simulated(eth: &Ethereum, tx: ð::Tx, gas: &Result) { - let block: eth::BlockNo = eth.current_block().borrow().number.into(); - match gas { - Ok(gas) => tracing::debug!(block = ?block, gas = ?gas.0, ?tx, "simulated settlement"), - Err(err) => tracing::debug!(block = ?block, ?err, "simulated settlement"), - } -} diff --git a/crates/driver/src/infra/persistence/mod.rs b/crates/driver/src/infra/persistence/mod.rs index cddf37189c..c03a3e0840 100644 --- a/crates/driver/src/infra/persistence/mod.rs +++ b/crates/driver/src/infra/persistence/mod.rs @@ -3,8 +3,7 @@ use { domain::competition::auction::Id, infra::{config::file, solver::Config}, }, - serde::Serialize, - serde_json::to_value, + bytes::Bytes, std::sync::Arc, tracing::Instrument, }; @@ -55,20 +54,16 @@ impl Persistence { /// Saves the given auction with liquidity with fire and forget mentality /// (non-blocking operation) - pub fn archive_auction(&self, auction_id: Id, body: impl Serialize) { + pub fn archive_auction(&self, auction_id: Id, body: Bytes) { let Some(uploader) = self.s3.clone() else { return; }; - let body = match to_value(body) { - Ok(body) => body, - Err(err) => { - tracing::error!(?err, "failed to parse the auction with liquidity to JSON"); - return; - } - }; tokio::spawn( async move { - match uploader.upload(auction_id.to_string(), body).await { + match uploader + .upload_json_bytes(auction_id.to_string(), body) + .await + { Ok(key) => { tracing::debug!(?key, "uploaded auction with liquidity to s3"); } diff --git a/crates/driver/src/infra/simulator/enso/dto.rs b/crates/driver/src/infra/simulator/enso/dto.rs deleted file mode 100644 index 065bcf03a4..0000000000 --- a/crates/driver/src/infra/simulator/enso/dto.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! Data transfer objects for interacting with the Enso Trade Simulator API. - -use { - crate::{domain::eth, util::serialize}, - serde::{Deserialize, Serialize}, - serde_with::serde_as, -}; - -#[serde_as] -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Request { - pub chain_id: u64, - pub from: eth::H160, - pub to: eth::H160, - #[serde_as(as = "serialize::Hex")] - pub data: Vec, - pub value: eth::U256, - pub gas_limit: u64, - #[serde(skip_serializing_if = "Option::is_none")] - pub block_number: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub block_timestamp: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub access_list: Option, -} - -#[derive(Debug, Serialize)] -#[serde(transparent)] -pub struct AccessList(Vec); - -impl From for AccessList { - fn from(value: eth::AccessList) -> Self { - Self( - web3::types::AccessList::from(value) - .into_iter() - .map(|item| AccessListItem { - address: item.address, - storage_keys: item.storage_keys, - }) - .collect(), - ) - } -} - -#[serde_as] -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct AccessListItem { - pub address: eth::H160, - pub storage_keys: Vec, -} - -#[serde_as] -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Response { - pub gas_used: u64, - pub block_number: u64, - pub success: bool, - pub exit_reason: String, - #[serde_as(as = "serialize::Hex")] - pub return_data: Vec, -} diff --git a/crates/driver/src/infra/simulator/enso/mod.rs b/crates/driver/src/infra/simulator/enso/mod.rs deleted file mode 100644 index e7f30948ef..0000000000 --- a/crates/driver/src/infra/simulator/enso/mod.rs +++ /dev/null @@ -1,103 +0,0 @@ -use { - crate::domain::eth, - chain::Chain, - ethrpc::block_stream::CurrentBlockWatcher, - reqwest::ClientBuilder, - std::time::Duration, - thiserror::Error, -}; - -mod dto; - -const GAS_LIMIT: u64 = 30_000_000; - -#[derive(Debug, Clone)] -pub(super) struct Enso { - url: reqwest::Url, - chain: Chain, - current_block: CurrentBlockWatcher, - network_block_interval: Option, -} - -#[derive(Debug, Clone)] -pub struct Config { - /// The URL of the Transaction Simulator API. - pub url: reqwest::Url, - /// The time between new blocks in the network. - pub network_block_interval: Option, -} - -impl Enso { - pub(super) fn new(config: Config, chain: Chain, current_block: CurrentBlockWatcher) -> Self { - Self { - url: reqwest::Url::parse(&format!("{}api/v1/simulate", config.url)).unwrap(), - chain, - current_block, - network_block_interval: config.network_block_interval, - } - } - - pub(super) async fn simulate(&self, tx: eth::Tx) -> Result { - let current_block = *self.current_block.borrow(); - - let (block_number, block_timestamp) = match self.network_block_interval { - None => (None, None), // use default values which result in simulation on `latest` - Some(duration) => { - // We would like to simulate on the `pending` block instead of the `latest` - // block. Unfortunately `enso` does not support that so to get closer to - // the actual behavior of the `pending` block we use the block number of - // the `latest` block but the timestamp of the `pending` block. - let block_number = current_block.number; - let next_timestamp = current_block.timestamp + duration.as_secs(); - (Some(block_number), Some(next_timestamp)) - } - }; - - let res: dto::Response = ClientBuilder::new() - .build() - .unwrap() - .post(self.url.clone()) - .json(&dto::Request { - chain_id: self.chain.id(), - from: tx.from.into(), - to: tx.to.into(), - data: tx.input.into(), - value: tx.value.into(), - gas_limit: GAS_LIMIT, - block_number, - block_timestamp, - access_list: if tx.access_list.is_empty() { - None - } else { - Some(tx.access_list.into()) - }, - }) - .send() - .await? - .error_for_status()? - .json() - .await?; - - res.into() - } -} - -#[derive(Debug, Error)] -#[error("Enso tx simulation error")] -pub enum Error { - Http(#[from] reqwest::Error), - Revert(String), -} - -impl From for Result { - fn from(response: dto::Response) -> Self { - if !response.success { - return Err(Error::Revert(format!( - "{}: {}", - response.exit_reason, - const_hex::encode(&response.return_data) - ))); - } - Ok(response.gas_used.into()) - } -} diff --git a/crates/driver/src/infra/simulator/tenderly/dto.rs b/crates/driver/src/infra/simulator/tenderly/dto.rs deleted file mode 100644 index 14a691e073..0000000000 --- a/crates/driver/src/infra/simulator/tenderly/dto.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Data transfer objects for interacting with the Tenderly API. - -use { - crate::{domain::eth, util::serialize}, - itertools::Itertools, - serde::{Deserialize, Serialize}, - serde_with::serde_as, -}; - -#[serde_as] -#[derive(Debug, Serialize)] -pub struct Request { - pub network_id: String, - pub from: eth::H160, - pub to: eth::H160, - #[serde_as(as = "serialize::Hex")] - pub input: Vec, - pub value: eth::U256, - pub save: bool, - pub save_if_fails: bool, - pub generate_access_list: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub access_list: Option, - pub gas_price: u64, -} - -#[derive(Debug, Deserialize)] -pub struct Response { - pub transaction: Transaction, - pub generated_access_list: Option, - pub simulation: Simulation, -} - -#[derive(Debug, Deserialize)] -pub struct Transaction { - pub status: bool, - pub gas_used: u64, -} - -/// Tenderly requires access lists to be serialized with `snake_case` instead -/// of the standard `camelCase`. -#[derive(Debug, Default, Deserialize, Serialize)] -#[serde(transparent)] -pub struct AccessList(Vec); - -#[derive(Debug, Deserialize, Serialize)] -struct AccessListItem { - address: eth::H160, - #[serde(default)] - storage_keys: Vec, -} - -impl From for AccessList { - fn from(value: eth::AccessList) -> Self { - Self( - web3::types::AccessList::from(value) - .into_iter() - .map(|item| AccessListItem { - address: item.address, - storage_keys: item.storage_keys, - }) - .collect(), - ) - } -} - -impl From for eth::AccessList { - fn from(value: AccessList) -> Self { - value - .0 - .into_iter() - .map(|item| web3::types::AccessListItem { - address: item.address, - storage_keys: item.storage_keys, - }) - .collect_vec() - .into() - } -} - -#[derive(Debug, Deserialize)] -pub struct Simulation { - pub id: String, -} diff --git a/crates/driver/src/infra/simulator/tenderly/mod.rs b/crates/driver/src/infra/simulator/tenderly/mod.rs deleted file mode 100644 index 793290bb04..0000000000 --- a/crates/driver/src/infra/simulator/tenderly/mod.rs +++ /dev/null @@ -1,141 +0,0 @@ -use { - crate::{domain::eth, infra::Ethereum}, - thiserror::Error, -}; - -mod dto; - -const DEFAULT_URL: &str = "https://api.tenderly.co/api"; - -#[derive(Debug, Clone)] -pub(super) struct Tenderly { - endpoint: reqwest::Url, - client: reqwest::Client, - config: Config, - eth: Ethereum, -} - -#[derive(Debug, Clone)] -pub struct Config { - /// The URL of the Tenderly API. - pub url: Option, - /// The Tenderly API key. - pub api_key: String, - /// The user associated with the API key. - pub user: String, - /// The project to use. - pub project: String, - /// Save the transaction on Tenderly for later inspection, e.g. via the - /// dashboard. - pub save: bool, - /// Save the transaction as above, even in the case of failure. - pub save_if_fails: bool, -} - -impl Tenderly { - pub(super) fn new(config: Config, eth: Ethereum) -> Self { - let mut headers = reqwest::header::HeaderMap::new(); - headers.insert( - reqwest::header::CONTENT_TYPE, - "application/json".parse().unwrap(), - ); - headers.insert(reqwest::header::ACCEPT, "application/json".parse().unwrap()); - let mut api_key = reqwest::header::HeaderValue::from_str(&config.api_key).unwrap(); - api_key.set_sensitive(true); - headers.insert("x-access-key", api_key); - Self { - endpoint: reqwest::Url::parse(&format!( - "{}/v1/account/{}/project/{}/simulate", - config - .url - .as_ref() - .map(|url| url.to_string()) - .unwrap_or_else(|| DEFAULT_URL.to_owned()), - config.user, - config.project - )) - .unwrap(), - client: reqwest::ClientBuilder::new() - .default_headers(headers) - .build() - .unwrap(), - config, - eth, - } - } - - pub(super) async fn simulate( - &self, - tx: ð::Tx, - generate_access_list: GenerateAccessList, - ) -> Result { - let gas_price = self.eth.simulation_gas_price().await; - - let res: dto::Response = self - .client - .post(self.endpoint.clone()) - .json(&dto::Request { - network_id: self.eth.chain().id().to_string(), - from: tx.from.into(), - to: tx.to.into(), - input: tx.input.clone().into(), - value: tx.value.into(), - save: self.config.save, - save_if_fails: self.config.save_if_fails, - generate_access_list: generate_access_list == GenerateAccessList::Yes, - access_list: if tx.access_list.is_empty() { - None - } else { - Some(tx.access_list.clone().into()) - }, - gas_price: gas_price.unwrap_or_default().as_u64(), - }) - .send() - .await? - .error_for_status()? - .json() - .await?; - - res.into() - } -} - -#[derive(Debug)] -pub struct Simulation { - pub id: SimulationId, - pub gas: eth::Gas, - pub access_list: eth::AccessList, -} - -// We want the string to be printed together with a simulation so we -// don't care that it's not used for anything else. -#[derive(Debug)] -pub struct SimulationId(#[allow(dead_code, reason = "intended for Debug implementation")] String); - -#[derive(Debug, PartialEq, Eq)] -pub(super) enum GenerateAccessList { - Yes, - No, -} - -#[derive(Debug, Error)] -#[error("tenderly error")] -pub enum Error { - Http(#[from] reqwest::Error), - Revert(SimulationId), -} - -impl From for Result { - fn from(res: dto::Response) -> Self { - let id = SimulationId(res.simulation.id); - if res.transaction.status { - Ok(Simulation { - id, - gas: res.transaction.gas_used.into(), - access_list: res.generated_access_list.unwrap_or_default().into(), - }) - } else { - Err(Error::Revert(id)) - } - } -} diff --git a/crates/driver/src/infra/solver/dto/auction.rs b/crates/driver/src/infra/solver/dto/auction.rs index 1af418428a..99d9504706 100644 --- a/crates/driver/src/infra/solver/dto/auction.rs +++ b/crates/driver/src/infra/solver/dto/auction.rs @@ -1,19 +1,20 @@ use { crate::{ domain::{ + self, + Flashloan, competition::{ self, - order::{self, Side, fees, signature::Scheme}, + order::{self, Available, Side, fees, signature::Scheme}, }, - eth::{self}, liquidity, }, infra::{config::file::FeeHandler, solver::ManageNativeToken}, - util::conv::{rational_to_big_decimal, u256::U256Ext}, }, app_data::AppDataHash, - ethrpc::alloy::conversions::IntoLegacy, + eth_domain_types as eth, model::order::{BuyTokenDestination, SellTokenSource}, + number::conversions::rational_to_big_decimal, std::collections::HashMap, }; @@ -23,14 +24,15 @@ pub type WrapperCalls = HashMap, + flashloan_hints: &HashMap, wrappers: &WrapperCalls, deadline: chrono::DateTime, + haircut_bps: u32, ) -> solvers_dto::auction::Auction { - let mut tokens: HashMap = auction + let mut tokens: HashMap = auction .tokens() .iter() .map(|token| { @@ -111,10 +113,12 @@ pub fn new( } }) } + + apply_haircut(&mut available, order.side, haircut_bps, &order.uid); solvers_dto::auction::Order { uid: order.uid.into(), - sell_token: available.sell.token.into(), - buy_token: available.buy.token.into(), + sell_token: *available.sell.token, + buy_token: *available.buy.token, sell_amount: available.sell.amount.into(), buy_amount: available.buy.amount.into(), full_sell_amount: order.sell.amount.into(), @@ -123,8 +127,8 @@ pub fn new( Side::Buy => solvers_dto::auction::Kind::Buy, Side::Sell => solvers_dto::auction::Kind::Sell, }, - receiver: order.receiver.map(Into::into), - owner: order.signature.signer.into(), + receiver: order.receiver, + owner: order.signature.signer, partially_fillable: order.is_partial(), class: match order.kind { order::Kind::Market => solvers_dto::auction::Class::Market, @@ -182,15 +186,15 @@ pub fn new( solvers_dto::auction::Liquidity::ConstantProduct( solvers_dto::auction::ConstantProductPool { id: liquidity.id.0.to_string(), - address: pool.address.into(), - router: pool.router.into(), + address: pool.address, + router: *pool.router, gas_estimate: liquidity.gas.into(), tokens: pool .reserves .iter() .map(|asset| { ( - asset.token.into(), + *asset.token, solvers_dto::auction::ConstantProductReserve { balance: asset.amount.into(), }, @@ -205,10 +209,10 @@ pub fn new( solvers_dto::auction::Liquidity::ConcentratedLiquidity( solvers_dto::auction::ConcentratedLiquidityPool { id: liquidity.id.0.to_string(), - address: pool.address.0, - router: pool.router.into(), + address: *pool.address, + router: *pool.router, gas_estimate: liquidity.gas.0, - tokens: vec![pool.tokens.get().0.into(), pool.tokens.get().1.into()], + tokens: vec![*pool.tokens.get().0, *pool.tokens.get().1], sqrt_price: pool.sqrt_price.0, liquidity: pool.liquidity.0, tick: pool.tick.0, @@ -225,7 +229,7 @@ pub fn new( solvers_dto::auction::Liquidity::Stable(solvers_dto::auction::StablePool { id: liquidity.id.0.to_string(), address: pool.id.address().into(), - balancer_pool_id: pool.id.into(), + balancer_pool_id: pool.id.0, gas_estimate: liquidity.gas.into(), tokens: pool .reserves @@ -241,8 +245,8 @@ pub fn new( }) .collect(), amplification_parameter: rational_to_big_decimal(&num::BigRational::new( - pool.amplification_parameter.factor().to_big_int(), - pool.amplification_parameter.precision().to_big_int(), + pool.amplification_parameter.factor().into(), + pool.amplification_parameter.precision().into(), )), fee: fee_to_decimal(pool.fee), }) @@ -252,7 +256,7 @@ pub fn new( solvers_dto::auction::WeightedProductPool { id: liquidity.id.0.to_string(), address: pool.id.address().into(), - balancer_pool_id: pool.id.into(), + balancer_pool_id: pool.id.0, gas_estimate: liquidity.gas.into(), tokens: pool .reserves @@ -283,7 +287,7 @@ pub fn new( liquidity::Kind::Swapr(pool) => solvers_dto::auction::Liquidity::ConstantProduct( solvers_dto::auction::ConstantProductPool { id: liquidity.id.0.to_string(), - address: pool.base.address.into(), + address: pool.base.address, router: pool.base.router.into(), gas_estimate: liquidity.gas.into(), tokens: pool @@ -306,14 +310,16 @@ pub fn new( solvers_dto::auction::Liquidity::LimitOrder( solvers_dto::auction::ForeignLimitOrder { id: liquidity.id.0.to_string(), - address: limit_order.zeroex.address().into_legacy(), + address: *limit_order.zeroex.address(), gas_estimate: liquidity.gas.into(), hash: Default::default(), maker_token: limit_order.order.maker_token, taker_token: limit_order.order.taker_token, - maker_amount: limit_order.fillable.maker.into(), - taker_amount: limit_order.fillable.taker.into(), - taker_token_fee_amount: limit_order.order.taker_token_fee_amount.into(), + maker_amount: eth::U256::from(limit_order.fillable.maker), + taker_amount: eth::U256::from(limit_order.fillable.taker), + taker_token_fee_amount: eth::U256::from( + limit_order.order.taker_token_fee_amount, + ), }, ) } @@ -326,7 +332,6 @@ pub fn new( .surplus_capturing_jit_order_owners() .iter() .cloned() - .map(Into::into) .collect::>(), } } @@ -357,11 +362,11 @@ fn fee_policy_from_domain(value: fees::FeePolicy) -> solvers_dto::auction::FeePo } } -fn interaction_from_domain(value: eth::Interaction) -> solvers_dto::auction::InteractionData { +fn interaction_from_domain(value: domain::Interaction) -> solvers_dto::auction::InteractionData { solvers_dto::auction::InteractionData { - target: value.target.0, + target: value.target, value: value.value.0, - call_data: value.call_data.0, + call_data: value.call_data.to_vec(), } } @@ -383,15 +388,202 @@ fn buy_token_destination_from_domain( } fn fee_to_decimal(fee: liquidity::balancer::v2::Fee) -> bigdecimal::BigDecimal { - bigdecimal::BigDecimal::new(fee.as_raw().to_big_int(), 18) + bigdecimal::BigDecimal::new(fee.as_raw().into(), 18) } fn weight_to_decimal(weight: liquidity::balancer::v2::weighted::Weight) -> bigdecimal::BigDecimal { - bigdecimal::BigDecimal::new(weight.as_raw().to_big_int(), 18) + bigdecimal::BigDecimal::new(weight.as_raw().into(), 18) } fn scaling_factor_to_decimal( scale: liquidity::balancer::v2::ScalingFactor, ) -> bigdecimal::BigDecimal { - bigdecimal::BigDecimal::new(scale.as_raw().to_big_int(), 18) + bigdecimal::BigDecimal::new(scale.as_raw().into(), 18) +} + +/// The driver applies a haircut to the solver's solution after it is returned +/// (see `Solutions::into_domain`). This reduces the user's effective buy amount +/// (sell orders) or increases their effective sell amount (buy orders) without +/// the solver knowing about it. Tighten the order limits we send the solver by +/// the same factor so that any solution it produces still respects the user's +/// signed limit price after the haircut is applied. +/// +/// Sell orders: `buy.amount := buy.amount / (1 - h)`. +/// Buy orders: `sell.amount := sell.amount / (1 + h)`. +/// +/// `haircut_bps` is expected to be well below `super::MAX_BASE_POINT`; a debug +/// assertion catches misconfigs in dev builds. On `apply_factor` failure (only +/// reachable on overflow when scaling buy_amount upward) we fall back to `0` +/// — matching the volume-fee pre-processing above — and log a warning so +/// operators can spot the misconfiguration. +fn apply_haircut(available: &mut Available, side: Side, haircut_bps: u32, order_uid: &order::Uid) { + if haircut_bps == 0 { + return; + } + debug_assert!( + haircut_bps <= super::MAX_BASE_POINT, + "haircut_bps {haircut_bps} must be <= {}", + super::MAX_BASE_POINT, + ); + let haircut_factor = f64::from(haircut_bps) / f64::from(super::MAX_BASE_POINT); + let (amount, factor, leg) = match side { + Side::Buy => ( + &mut available.sell.amount, + 1.0 / (1.0 + haircut_factor), + "sell", + ), + Side::Sell => ( + &mut available.buy.amount, + 1.0 / (1.0 - haircut_factor), + "buy", + ), + }; + let tightened = amount.apply_factor(factor); + if tightened.is_none() { + tracing::warn!( + ?order_uid, + haircut_bps, + ?side, + leg, + factor, + ?amount, + "failed to tighten order limit for haircut; falling back to default", + ); + } + *amount = tightened.unwrap_or_default(); +} + +#[cfg(test)] +mod tests { + use {super::*, alloy::primitives::Address}; + + fn asset(amount: eth::U256) -> eth::Asset { + eth::Asset { + amount: amount.into(), + token: Address::repeat_byte(0xaa).into(), + } + } + + fn available(sell_amount: eth::U256, buy_amount: eth::U256) -> Available { + Available { + sell: asset(sell_amount), + buy: asset(buy_amount), + } + } + + /// Zero haircut leaves the order limits unchanged. + #[test] + fn haircut_zero_is_noop() { + let sell = eth::U256::from(500_000_000u64); + let buy = eth::U256::from(441_289_983_646_158_011_001u128); + + let mut a = available(sell, buy); + apply_haircut(&mut a, Side::Sell, 0, &order::Uid::default()); + assert_eq!(a.sell.amount.0, sell); + assert_eq!(a.buy.amount.0, buy); + + let mut a = available(sell, buy); + apply_haircut(&mut a, Side::Buy, 0, &order::Uid::default()); + assert_eq!(a.sell.amount.0, sell); + assert_eq!(a.buy.amount.0, buy); + } + + /// For sell orders, the buy amount sent to the solver is tightened + /// to `B / (1 - h)` so that the solver bids with enough headroom for + /// the driver's post-hoc haircut to still respect the signed limit `B`. + /// + /// Regression for the prod incident on order `0xa978e3ec…6a020c06`: + /// solver `0x4c52…f739` submitted a bid with ~83 bps headroom; the driver + /// applied the configured haircut and the on-chain `settle()` reverted + /// with `GPv2: limit price not respected`. With make-room, the limit the + /// solver sees is the tightened one, so the only solutions it can produce + /// already satisfy the signed limit post-haircut. + #[test] + fn haircut_tightens_buy_for_sell_order() { + let sell = eth::U256::from(500_000_000u64); + let signed_buy = eth::U256::from(441_289_983_646_158_011_001u128); + + let mut a = available(sell, signed_buy); + apply_haircut(&mut a, Side::Sell, 100, &order::Uid::default()); // 1% haircut + + // sell amount is untouched for sell orders. + assert_eq!(a.sell.amount.0, sell); + + // Expected tightened buy: signed_buy / (1 - 0.01). + let expected = eth::TokenAmount(signed_buy) + .apply_factor(1.0 / 0.99) + .unwrap() + .0; + assert_eq!(a.buy.amount.0, expected); + + // Sanity: any solver bid `E` that clears the tightened limit + // (`E >= expected`) survives the post-hoc haircut, i.e. + // `E * (1 - h) >= signed_buy`. + assert!(expected > signed_buy); + let post_haircut = a.buy.amount.apply_factor(0.99).unwrap().0; + // The post-haircut amount must be `>= signed_buy` (allow a tiny + // f64-rounding tolerance of a few wei). + let tolerance = eth::U256::from(10u64); + assert!( + post_haircut + tolerance >= signed_buy, + "post-haircut {post_haircut} < signed {signed_buy}" + ); + } + + /// Symmetric to the sell case: for buy orders the sell amount is + /// tightened to `S / (1 + h)` so the driver's post-hoc haircut (which + /// *adds* to the sell amount the user pays) still respects the signed + /// sell limit. + #[test] + fn haircut_tightens_sell_for_buy_order() { + let signed_sell = eth::U256::from(500_000_000u64); + let buy = eth::U256::from(441_289_983_646_158_011_001u128); + + let mut a = available(signed_sell, buy); + apply_haircut(&mut a, Side::Buy, 100, &order::Uid::default()); // 1% haircut + + // buy amount is untouched for buy orders. + assert_eq!(a.buy.amount.0, buy); + + // Expected tightened sell: signed_sell / (1 + 0.01). + let expected = eth::TokenAmount(signed_sell) + .apply_factor(1.0 / 1.01) + .unwrap() + .0; + assert_eq!(a.sell.amount.0, expected); + + // Solver pays at most `expected`; after the driver adds the haircut + // (`+ h`), the effective sell must not exceed `signed_sell`. + assert!(expected < signed_sell); + let post_haircut = a.sell.amount.apply_factor(1.01).unwrap().0; + let tolerance = eth::U256::from(10u64); + assert!( + post_haircut <= signed_sell + tolerance, + "post-haircut {post_haircut} > signed {signed_sell}" + ); + } + + /// `haircut_bps == MAX_BASE_POINT` makes `1 / (1 - 1) = inf`, the only + /// realistic way `apply_factor` returns `None` inside `apply_haircut`. The + /// fallback is `0` (matches the volume-fee pre-processing's + /// `unwrap_or_default()` behaviour). The debug-assert allows `<= + /// MAX_BASE_POINT` so this case is reachable in dev builds too. + #[test] + fn haircut_overflow_falls_back_to_default() { + let sell = eth::U256::from(500_000_000u64); + let signed_buy = eth::U256::from(441_289_983_646_158_011_001u128); + + let mut a = available(sell, signed_buy); + apply_haircut( + &mut a, + Side::Sell, + super::super::MAX_BASE_POINT, + &order::Uid::default(), + ); + + // buy.amount tightened with an infinite factor → fallback to 0. + assert_eq!(a.buy.amount, eth::TokenAmount::default()); + // sell.amount is untouched on the sell-side branch. + assert_eq!(a.sell.amount.0, sell); + } } diff --git a/crates/driver/src/infra/solver/dto/mod.rs b/crates/driver/src/infra/solver/dto/mod.rs index 4b3ac42c53..c04a0f202f 100644 --- a/crates/driver/src/infra/solver/dto/mod.rs +++ b/crates/driver/src/infra/solver/dto/mod.rs @@ -6,6 +6,10 @@ mod solution; pub use solution::Solutions; +/// One hundred percent expressed in basis points. Used everywhere the driver +/// converts a bps configuration value (haircut, fee policies, …) to a factor. +pub(super) const MAX_BASE_POINT: u32 = 10_000; + #[derive(Debug, thiserror::Error)] #[error("{0}")] pub struct Error(pub String); diff --git a/crates/driver/src/infra/solver/dto/notification.rs b/crates/driver/src/infra/solver/dto/notification.rs index 587d5c5c38..d974d577a0 100644 --- a/crates/driver/src/infra/solver/dto/notification.rs +++ b/crates/driver/src/infra/solver/dto/notification.rs @@ -18,10 +18,10 @@ pub fn new( solvers_dto::notification::Kind::SimulationFailed { block: block.0, tx: solvers_dto::notification::Tx { - from: tx.from.into(), - to: tx.to.into(), + from: tx.from, + to: tx.to, input: tx.input.into(), - value: tx.value.into(), + value: tx.value.0, access_list: tx.access_list.into(), }, succeeded_once, @@ -30,7 +30,7 @@ pub fn new( notify::Kind::ScoringFailed(scoring) => scoring.into(), notify::Kind::NonBufferableTokensUsed(tokens) => { solvers_dto::notification::Kind::NonBufferableTokensUsed { - tokens: tokens.into_iter().map(|token| token.0.0).collect(), + tokens: tokens.into_iter().map(|token| *token).collect(), } } notify::Kind::SolverAccountInsufficientBalance(required) => { @@ -44,6 +44,7 @@ pub fn new( notify::Kind::DriverError(reason) => { solvers_dto::notification::Kind::DriverError { reason } } + notify::Kind::SettlementStarted => solvers_dto::notification::Kind::SettlementStarted, notify::Kind::Settled(kind) => match kind { notify::Settlement::Success(hash) => solvers_dto::notification::Kind::Success { transaction: hash.0, @@ -58,17 +59,6 @@ pub fn new( notify::Kind::PostprocessingTimedOut => { solvers_dto::notification::Kind::PostprocessingTimedOut } - notify::Kind::Banned { reason, until } => solvers_dto::notification::Kind::Banned { - reason: match reason { - notify::BanReason::UnsettledConsecutiveAuctions => { - solvers_dto::notification::BanReason::UnsettledConsecutiveAuctions - } - notify::BanReason::HighSettleFailureRate => { - solvers_dto::notification::BanReason::HighSettleFailureRate - } - }, - until, - }, notify::Kind::DeserializationError(reason) => { solvers_dto::notification::Kind::DeserializationError { reason } } @@ -94,7 +84,7 @@ impl From for solvers_dto::notification::Kind { } notify::ScoreKind::MissingPrice(token_address) => { solvers_dto::notification::Kind::MissingPrice { - token_address: token_address.into(), + token_address: *token_address, } } } diff --git a/crates/driver/src/infra/solver/dto/solution.rs b/crates/driver/src/infra/solver/dto/solution.rs index f4592ed613..36dcef413e 100644 --- a/crates/driver/src/infra/solver/dto/solution.rs +++ b/crates/driver/src/infra/solver/dto/solution.rs @@ -1,36 +1,39 @@ use { crate::{ domain::{ - competition::{self, solution::WrapperCall}, - eth, + self, + competition::{self}, liquidity, }, infra::Solver, - util::Bytes, }, + alloy::primitives::Bytes, app_data::AppDataHash, - ethrpc::alloy::conversions::IntoAlloy, + eth_domain_types as eth, itertools::Itertools, model::{ DomainSeparator, order::{BuyTokenDestination, OrderData, OrderKind, SellTokenSource}, }, + simulator::encoding::WrapperCall, std::{collections::HashMap, str::FromStr}, }; #[derive(derive_more::From)] -pub struct Solutions(solvers_dto::solution::Solutions); +pub struct Solutions(Vec); impl Solutions { pub fn into_domain( self, auction: &competition::Auction, liquidity: &[liquidity::Liquidity], - weth: eth::WethAddress, + weth: eth::WrappedNativeToken, solver: Solver, - flashloan_hints: &HashMap, + flashloan_hints: &HashMap, ) -> Result, super::Error> { - self.0.solutions + let haircut_bps = solver.haircut_bps(); + + self.0 .into_iter() .map(|solution| { competition::Solution::new( @@ -40,15 +43,21 @@ impl Solutions { .iter() .map(|trade| match trade { solvers_dto::solution::Trade::Fulfillment(fulfillment) => { - let order = auction - .orders() - .iter() - .find(|order| order.uid == fulfillment.order.0) - // TODO this error should reference the UID - .ok_or(super::Error( - "invalid order UID specified in fulfillment".to_owned() - ))? - .clone(); + let order = + find_order(auction.orders(), &fulfillment.order)?.clone(); + + // Calculate haircut fee for conservative bidding. + // This reduces reported surplus without affecting executed amounts. + let haircut_fee = if haircut_bps > 0 { + eth::U256::from(fulfillment.executed_amount) + .checked_mul(eth::U256::from(haircut_bps)) + .and_then(|v| { + v.checked_div(eth::U256::from(super::MAX_BASE_POINT)) + }) + .unwrap_or_default() + } else { + Default::default() + }; competition::solution::trade::Fulfillment::new( order, @@ -59,62 +68,68 @@ impl Solutions { ), None => competition::solution::trade::Fee::Static, }, + haircut_fee, ) - .map(competition::solution::Trade::Fulfillment) - .map_err(|err| super::Error(format!("invalid fulfillment: {err}"))) + .map(competition::solution::Trade::Fulfillment) + .map_err(|err| super::Error(format!("invalid fulfillment: {err}"))) } solvers_dto::solution::Trade::Jit(jit) => { let jit_order: JitOrder = jit.order.clone().into(); Ok(competition::solution::Trade::Jit( - competition::solution::trade::Jit::new( - competition::order::Jit { - uid: jit_order.uid( - solver.eth.contracts().settlement_domain_separator(), - )?, - sell: eth::Asset { - amount: jit_order.0.sell_amount.into(), - token: jit_order.0.sell_token.into(), - }, - buy: eth::Asset { - amount: jit_order.0.buy_amount.into(), - token: jit_order.0.buy_token.into(), - }, - receiver: jit_order.0.receiver.into(), - partially_fillable: jit_order.0.partially_fillable, - valid_to: jit_order.0.valid_to.into(), - app_data: jit_order.0.app_data.into(), - side: match jit_order.0.kind { - solvers_dto::solution::Kind::Sell => competition::order::Side::Sell, - solvers_dto::solution::Kind::Buy => competition::order::Side::Buy, - }, - sell_token_balance: match jit_order.0.sell_token_balance { - solvers_dto::solution::SellTokenBalance::Erc20 => { - competition::order::SellTokenBalance::Erc20 - } - solvers_dto::solution::SellTokenBalance::Internal => { - competition::order::SellTokenBalance::Internal - } - solvers_dto::solution::SellTokenBalance::External => { - competition::order::SellTokenBalance::External - } - }, - buy_token_balance: match jit_order.0.buy_token_balance { - solvers_dto::solution::BuyTokenBalance::Erc20 => { - competition::order::BuyTokenBalance::Erc20 - } - solvers_dto::solution::BuyTokenBalance::Internal => { - competition::order::BuyTokenBalance::Internal - } + competition::solution::trade::Jit::new( + competition::order::Jit { + uid: jit_order.uid( + solver.eth.contracts().settlement_domain_separator(), + )?, + sell: eth::Asset { + amount: jit_order.0.sell_amount.into(), + token: jit_order.0.sell_token.into(), + }, + buy: eth::Asset { + amount: jit_order.0.buy_amount.into(), + token: jit_order.0.buy_token.into(), + }, + receiver: jit_order.0.receiver, + partially_fillable: jit_order.0.partially_fillable, + valid_to: jit_order.0.valid_to.into(), + app_data: jit_order.0.app_data.into(), + side: match jit_order.0.kind { + solvers_dto::solution::Kind::Sell => { + competition::order::Side::Sell + } + solvers_dto::solution::Kind::Buy => { + competition::order::Side::Buy + } + }, + sell_token_balance: match jit_order.0.sell_token_balance { + solvers_dto::solution::SellTokenBalance::Erc20 => { + competition::order::SellTokenBalance::Erc20 + } + solvers_dto::solution::SellTokenBalance::Internal => { + competition::order::SellTokenBalance::Internal + } + solvers_dto::solution::SellTokenBalance::External => { + competition::order::SellTokenBalance::External + } + }, + buy_token_balance: match jit_order.0.buy_token_balance { + solvers_dto::solution::BuyTokenBalance::Erc20 => { + competition::order::BuyTokenBalance::Erc20 + } + solvers_dto::solution::BuyTokenBalance::Internal => { + competition::order::BuyTokenBalance::Internal + } + }, + signature: jit_order.signature( + solver.eth.contracts().settlement_domain_separator(), + )?, }, - signature: jit_order.signature( - solver.eth.contracts().settlement_domain_separator(), - )?, - }, - jit.executed_amount.into(), - jit.fee.unwrap_or_default().into(), - ) - .map_err(|err| super::Error(format!("invalid JIT trade: {err}")))?, - ))}, + jit.executed_amount.into(), + jit.fee.unwrap_or_default().into(), + ) + .map_err(|err| super::Error(format!("invalid JIT trade: {err}")))?, + )) + } }) .try_collect()?, solution @@ -125,10 +140,10 @@ impl Solutions { solution .pre_interactions .into_iter() - .map(|interaction| eth::Interaction { - target: interaction.target.into(), + .map(|interaction| domain::Interaction { + target: interaction.target, value: interaction.value.into(), - call_data: Bytes(interaction.calldata), + call_data: Bytes::from(interaction.calldata), }) .collect(), solution @@ -147,8 +162,8 @@ impl Solutions { .map(|allowance| { eth::Allowance { token: allowance.token.into(), - spender: allowance.spender.into(), - amount: allowance.amount.into_alloy(), + spender: allowance.spender, + amount: allowance.amount, } .into() }) @@ -202,37 +217,55 @@ impl Solutions { solution .post_interactions .into_iter() - .map(|interaction| eth::Interaction { - target: interaction.target.into(), + .map(|interaction| domain::Interaction { + target: interaction.target, value: interaction.value.into(), - call_data: Bytes(interaction.calldata), + call_data: interaction.calldata.into(), }) .collect(), solver.clone(), weth, - solution.gas.map(|gas| eth::Gas(gas.into())), + solution.gas.map(eth::Gas::from), + solution + .gas_fee_override + .map(|o| { + Ok(competition::solution::GasFeeOverride { + max_fee_per_gas: o.max_fee_per_gas.try_into().map_err(|_| { + super::Error("max_fee_per_gas overflow".to_owned()) + })?, + max_priority_fee_per_gas: o + .max_priority_fee_per_gas + .try_into() + .map_err(|_| { + super::Error( + "max_priority_fee_per_gas overflow".to_owned(), + ) + })?, + }) + }) + .transpose()?, solver.config().fee_handler, auction.surplus_capturing_jit_order_owners(), solution.flashloans // convert the flashloan info provided by the solver - .map(|f| f.iter().map(|(order, loan)|(order.into(), loan.into())).collect()) + .map(|f| f.iter().map(|(order, loan)| (order.into(), loan.clone())).collect()) // or copy over the relevant flashloan hints from the solve request .unwrap_or_else(|| solution.trades.iter() .filter_map(|t| { - let solvers_dto::solution::Trade::Fulfillment(trade) = &t else { - // we don't have any flashloan data on JIT orders - return None; - }; - let uid = competition::order::Uid::from(&trade.order); - Some(( - uid, - flashloan_hints.get(&uid).cloned()?, - )) - }).collect()), + let solvers_dto::solution::Trade::Fulfillment(trade) = &t else { + // we don't have any flashloan data on JIT orders + return None; + }; + let uid = competition::order::Uid::from(&trade.order); + Some(( + uid, + flashloan_hints.get(&uid)?.into(), + )) + }).collect()), solution.wrappers.iter().cloned().map(|w| WrapperCall { - address: eth::Address(w.address), - data: w.data, - }).collect() + address: w.address, + data: w.data.into(), + }).collect(), ) .map_err(|err| match err { competition::solution::error::Solution::InvalidClearingPrices => { @@ -250,17 +283,32 @@ impl Solutions { } } +fn find_order<'a>( + orders: &'a [competition::Order], + uid: &solvers_dto::solution::OrderUid, +) -> Result<&'a competition::Order, super::Error> { + orders + .iter() + .find(|order| order.uid == uid.0) + .ok_or_else(|| { + super::Error(format!( + "invalid order UID specified in fulfillment: {}", + const_hex::encode_prefixed(uid.0) + )) + }) +} + #[derive(derive_more::From)] pub struct JitOrder(solvers_dto::solution::JitOrder); impl JitOrder { fn raw_order_data(&self) -> OrderData { OrderData { - sell_token: self.0.sell_token.into_alloy(), - buy_token: self.0.buy_token.into_alloy(), - receiver: Some(self.0.receiver.into_alloy()), - sell_amount: self.0.sell_amount.into_alloy(), - buy_amount: self.0.buy_amount.into_alloy(), + sell_token: self.0.sell_token, + buy_token: self.0.buy_token, + receiver: Some(self.0.receiver), + sell_amount: self.0.sell_amount, + buy_amount: self.0.buy_amount, valid_to: self.0.valid_to, app_data: AppDataHash(self.0.app_data), fee_amount: alloy::primitives::U256::ZERO, @@ -306,11 +354,13 @@ impl JitOrder { let signer = signature .to_boundary_signature() - .recover_owner( - self.0.signature.as_slice(), - &DomainSeparator(domain_separator.0), - &self.raw_order_data().hash_struct(), - ) + .and_then(|sig| { + sig.recover_owner( + self.0.signature.as_slice(), + &DomainSeparator(domain_separator.0), + &self.raw_order_data().hash_struct(), + ) + }) .map_err(|e| super::Error(e.to_string()))?; if matches!( @@ -321,10 +371,10 @@ impl JitOrder { // signature bytes. This leads to the owner being encoded twice in // the final settlement calldata unless we remove that from the raw // data. - signature.data = Bytes(self.0.signature[20..].to_vec()); + signature.data = Bytes::copy_from_slice(&self.0.signature[20..]); } - signature.signer = signer.into(); + signature.signer = signer; Ok(signature) } @@ -333,8 +383,26 @@ impl JitOrder { let order_data = self.raw_order_data(); let signature = self.signature(domain)?; Ok(order_data - .uid(&DomainSeparator(domain.0), &signature.signer.into()) + .uid(&DomainSeparator(domain.0), signature.signer) .0 .into()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fulfillment_unknown_uid_error_includes_uid() { + let missing = solvers_dto::solution::OrderUid([0xab; 56]); + let err = find_order(&[], &missing).unwrap_err(); + let expected_hex = "ab".repeat(56); + assert!( + err.0.contains(&expected_hex), + "error message {:?} should include the offending UID hex {}", + err.0, + expected_hex, + ); + } +} diff --git a/crates/driver/src/infra/solver/eip7702.rs b/crates/driver/src/infra/solver/eip7702.rs new file mode 100644 index 0000000000..24118e1674 --- /dev/null +++ b/crates/driver/src/infra/solver/eip7702.rs @@ -0,0 +1,584 @@ +use { + super::{Config, Solver}, + crate::infra::blockchain::Ethereum, + alloy::{ + eips::eip7702::{Authorization, SignedAuthorization}, + network::{ReceiptResponse, TransactionBuilder7702, TxSigner}, + primitives::{Address, B256, Bytes, U256, address}, + providers::Provider, + rpc::types::TransactionRequest, + sol_types::SolConstructor, + }, + anyhow::Context, + contracts::Solver7702Delegate::Solver7702Delegate, + hex_literal::hex, + std::{collections::HashSet, time::Duration}, + tracing::instrument, +}; + +/// EIP-7702 delegation prefix stored as account code prefix. If you call +/// eth_getCode on a delegated EOA, instead of getting empty bytes (normal EOA), +/// you get 0xef0100<20-byte contract address>. +pub const DELEGATION_PREFIX: [u8; 3] = [0xef, 0x01, 0x00]; +const DELEGATION_CODE_LEN: usize = DELEGATION_PREFIX.len() + Address::len_bytes(); +/// The maximum number of approved callers allowed by the Solver7702Delegate +/// ABI. +pub const MAX_APPROVED_CALLERS: usize = 5; +// Arachnid's deterministic-deployment-proxy. It is deployed at this same +// address on many EVM chains. Sending 32-byte salt || init code to it deploys +// that init code with CREATE2. We use it to derive and deploy the exact +// Solver7702Delegate address from this proxy address, zero salt, and init code. +pub const CREATE2_DEPLOYER: Address = address!("4e59b44847b379578588920cA78FbF26c0B4956C"); +const CREATE2_DEPLOYER_CODE: &[u8] = &hex!( + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" +); +// The ordered caller slots and zero salt are part of the CREATE2 input, so the +// same caller set keeps resolving to the same delegate target. +pub const CREATE2_SALT: B256 = B256::ZERO; + +/// Ensure EIP-7702 delegate deployment and solver delegation are set up for all +/// solvers with parallel submission accounts. Called once at driver startup. +/// +/// # Errors +/// - A solver has `submission-accounts`, but its main account is read-only and +/// cannot sign the EIP-7702 authorization. +/// - The deterministic CREATE2 deployer is missing or has unexpected code. +/// - The solver EOA already delegates to another target, or has non-delegation +/// code. +/// - The EIP-7702 authorization lands but the on-chain code does not reflect +/// the expected delegate, for example because a concurrent tx shifted the +/// nonce. +/// - Any underlying RPC error while fetching code, chain id, nonces, sending a +/// tx, or waiting for a receipt. +#[instrument(name = "setup_eip7702", skip_all)] +pub async fn setup(solvers: &[Solver], eth: &Ethereum) -> anyhow::Result<()> { + for solver in solvers { + let config = solver.config(); + if config.submission_accounts.is_empty() { + continue; + } + + // Register solver + submission accounts with the main wallet so we can + // send transactions via the provider during setup. + let web3 = eth.web3(); + web3.wallet.register_signer(config.account.clone()); + for acc in &config.submission_accounts { + web3.wallet.register_signer(acc.clone()); + } + + let submission_addresses = config + .submission_accounts + .iter() + .map(TxSigner::address) + .collect::>(); + let (delegate, approved_callers, init_code) = delegate_deployment(&submission_addresses)?; + + setup_solver(config, delegate, &approved_callers, &init_code, eth).await?; + } + Ok(()) +} + +pub fn delegate_address(callers: &[Address]) -> anyhow::Result
{ + Ok(delegate_deployment(callers)?.0) +} + +fn delegate_deployment( + callers: &[Address], +) -> anyhow::Result<(Address, [Address; MAX_APPROVED_CALLERS], Bytes)> { + anyhow::ensure!( + callers.len() <= MAX_APPROVED_CALLERS, + "Solver7702Delegate supports at most {MAX_APPROVED_CALLERS} submission accounts" + ); + anyhow::ensure!( + callers.iter().all(|caller| *caller != Address::ZERO), + "submission accounts cannot include the zero address" + ); + let mut seen = HashSet::with_capacity(callers.len()); + anyhow::ensure!( + callers.iter().all(|caller| seen.insert(*caller)), + "submission accounts must be unique" + ); + + let mut approved_callers = [Address::ZERO; MAX_APPROVED_CALLERS]; + approved_callers[..callers.len()].copy_from_slice(callers); + + anyhow::ensure!( + !Solver7702Delegate::BYTECODE.is_empty(), + "Solver7702Delegate creation bytecode is missing" + ); + let init_code = Solver7702Delegate::BYTECODE + .iter() + .chain(&SolConstructor::abi_encode( + &Solver7702Delegate::constructorCall { + approvedCallers: approved_callers, + }, + )) + .copied() + .collect::(); + + // The submission account order is part of the constructor args, so changing + // TOML order changes the CREATE2 delegate address. + let target = CREATE2_DEPLOYER.create2_from_code(CREATE2_SALT, &init_code); + + Ok((target, approved_callers, init_code)) +} + +#[instrument(skip_all, fields(delegate = ?delegate))] +async fn setup_solver( + config: &Config, + delegate: Address, + approved_callers: &[Address; MAX_APPROVED_CALLERS], + init_code: &Bytes, + eth: &Ethereum, +) -> anyhow::Result<()> { + let provider = ð.web3().provider; + let solver_address = config.account.address(); + let delegate_code = provider + .get_code_at(delegate) + .await + .context("reading Solver7702Delegate code")?; + let solver_code = provider + .get_code_at(solver_address) + .await + .context("reading solver EOA code")?; + + let delegate_missing = delegate_code.is_empty(); + match (DelegationStatus::from_code(&solver_code), delegate_missing) { + // The solver EOA already delegates somewhere else. Do not silently undo + // a manual change or incident response action. + (DelegationStatus::DelegatedTo(target), _) if target != delegate => anyhow::bail!( + "solver '{}': solver EOA {:?} already delegates to {:?}, expected {:?}; refusing to \ + re-delegate automatically on startup. Clear the existing delegation manually if this \ + is intentional.", + config.name, + solver_address, + target, + delegate, + ), + // The solver account has code that is not an EIP-7702 delegation. This + // is unexpected for an EOA, so fail instead of overwriting it. + (DelegationStatus::OtherCode, _) => anyhow::bail!( + "solver '{}': solver EOA {:?} has non-empty code that is not an EIP-7702 delegation; \ + refusing to overwrite it on startup", + config.name, + solver_address, + ), + // A previous setup attempt may have set the delegation but failed + // before CREATE2 deployment succeeded. The EOA already points to the + // right counterfactual address, so only deploy the missing code. + (DelegationStatus::DelegatedTo(_), true) => { + deploy_delegate( + config, + delegate, + approved_callers, + init_code, + DeploymentMode::DeployOnly, + eth, + ) + .await + } + // Everything is already set up. + (DelegationStatus::DelegatedTo(_), false) => { + tracing::info!( + solver = %config.name, + delegate = ?delegate, + "solver EOA already delegates to Solver7702Delegate" + ); + Ok(()) + } + // Fresh setup: neither the EOA delegation nor the CREATE2 delegate + // exists, so deploy and delegate in one transaction. + (DelegationStatus::Empty, true) => { + deploy_delegate( + config, + delegate, + approved_callers, + init_code, + DeploymentMode::DeployAndDelegate, + eth, + ) + .await + } + // The delegate was deployed already, but this solver EOA has no + // delegation yet. This can happen when another startup process deployed + // the shared CREATE2 target first, so warn and set delegation now. + (DelegationStatus::Empty, false) => { + tracing::warn!( + solver = %config.name, + solver_eoa = ?solver_address, + delegate = ?delegate, + "solver EOA has no EIP-7702 delegation but expected delegate already exists; \ + setting delegation" + ); + setup_delegation(config, delegate, eth).await + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum DeploymentMode { + DeployOnly, + DeployAndDelegate, +} + +impl DeploymentMode { + fn includes_delegation(self) -> bool { + matches!(self, Self::DeployAndDelegate) + } +} + +#[instrument(skip_all, fields(delegate = ?delegate))] +async fn deploy_delegate( + config: &Config, + delegate: Address, + approved_callers: &[Address; MAX_APPROVED_CALLERS], + init_code: &Bytes, + mode: DeploymentMode, + eth: &Ethereum, +) -> anyhow::Result<()> { + let provider = ð.web3().provider; + let deployer_code = provider + .get_code_at(CREATE2_DEPLOYER) + .await + .context("reading CREATE2 deployer code")?; + anyhow::ensure!( + deployer_code.as_ref() == CREATE2_DEPLOYER_CODE, + "CREATE2 deployer {CREATE2_DEPLOYER:?} has unexpected code", + ); + + let tx_sender = match mode { + DeploymentMode::DeployOnly => config + .submission_accounts + .first() + .map(TxSigner::address) + .unwrap_or_else(|| config.account.address()), + DeploymentMode::DeployAndDelegate => config.account.address(), + }; + let tx_nonce = wait_for_pending_txs(provider, tx_sender).await?; + let signed_auth = if mode.includes_delegation() { + let chain_id = provider + .get_chain_id() + .await + .context("reading chain id for EIP-7702 authorization")?; + Some(sign_authorization(config, chain_id, delegate, tx_nonce + 1).await?) + } else { + None + }; + let input = CREATE2_SALT + .iter() + .chain(init_code) + .copied() + .collect::(); + + tracing::info!( + delegate = ?delegate, + approved_callers = ?approved_callers, + tx_sender = ?tx_sender, + tx_nonce, + mode = ?mode, + "deploying Solver7702Delegate with CREATE2" + ); + let mut tx = TransactionRequest::default() + .from(tx_sender) + .to(CREATE2_DEPLOYER) + .nonce(tx_nonce) + .input(input.into()); + if let Some(signed_auth) = signed_auth { + tx = tx.with_authorization_list(vec![signed_auth]); + } + + let pending = provider + .send_transaction(tx) + .await + .context("sending Solver7702Delegate CREATE2 deployment tx")?; + let receipt = pending + .get_receipt() + .await + .context("waiting for Solver7702Delegate CREATE2 deployment receipt")?; + receipt + .ensure_success() + .context("Solver7702Delegate CREATE2 deployment tx reverted")?; + + let code = provider + .get_code_at(delegate) + .await + .context("reading Solver7702Delegate code after deployment")?; + anyhow::ensure!( + !code.is_empty(), + "Solver7702Delegate deployment tx {:?} did not create code at {:?}", + receipt.transaction_hash, + delegate, + ); + if mode.includes_delegation() { + let solver_code = provider + .get_code_at(tx_sender) + .await + .context("reading solver EOA code after combined deployment and delegation")?; + anyhow::ensure!( + is_delegated_to(&solver_code, delegate), + "Solver7702Delegate deployment tx {:?} did not delegate solver EOA {:?} to {:?}. \ + Expected auth_nonce={} (solver_nonce={} + 1). Check that no pending txs changed the \ + nonce between query and submission.", + receipt.transaction_hash, + tx_sender, + delegate, + tx_nonce + 1, + tx_nonce, + ); + } + tracing::info!( + tx_hash = ?receipt.transaction_hash, + block = ?receipt.block_number, + delegate = ?delegate, + mode = ?mode, + "Solver7702Delegate CREATE2 deployment confirmed" + ); + + Ok(()) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum DelegationStatus { + /// No code (`eth_getCode` returns empty); undelegated EOA. + Empty, + /// EIP-7702 delegation: code is [`DELEGATION_PREFIX`] followed by this + /// implementation address. + DelegatedTo(Address), + /// Non-empty code that is not an EIP-7702 delegation prefix. + OtherCode, +} + +impl DelegationStatus { + fn from_code(code: &[u8]) -> Self { + if code.is_empty() { + Self::Empty + } else if code.len() == DELEGATION_CODE_LEN && code.starts_with(&DELEGATION_PREFIX) { + Self::DelegatedTo(Address::from_slice(&code[DELEGATION_PREFIX.len()..])) + } else { + Self::OtherCode + } + } +} + +/// Check whether the account's code is an EIP-7702 delegation to +/// `expected_delegate`. +fn is_delegated_to(code: &[u8], expected_delegate: Address) -> bool { + matches!(DelegationStatus::from_code(code), DelegationStatus::DelegatedTo(delegate) if delegate == expected_delegate) +} + +/// Set up EIP-7702 delegation with a zero-address authorization transaction. +#[instrument(skip_all)] +async fn setup_delegation( + config: &Config, + delegate: Address, + eth: &Ethereum, +) -> anyhow::Result<()> { + let provider = ð.web3().provider; + let chain_id = provider + .get_chain_id() + .await + .context("reading chain id for EIP-7702 authorization")?; + let solver_address: Address = config.account.address(); + + // Wait for any pending solver txs to clear (e.g. in-flight settlements + // from a pre-7702 deployment). Submitting at the same nonce would replace + // the pending tx, silently dropping a valid settlement. + let solver_nonce = wait_for_pending_txs(provider, solver_address).await?; + + tracing::info!( + ?delegate, + solver_nonce, + auth_nonce = solver_nonce + 1, + "setting up EIP-7702 solver delegation" + ); + + // The auth nonce must be solver_nonce + 1: in EIP-7702 the sender's nonce + // is incremented before the authorization list is processed. Since the + // solver is both sender and authority, the nonce will already be + // solver_nonce + 1 by the time the auth is checked. + let signed_auth = sign_authorization(config, chain_id, delegate, solver_nonce + 1).await?; + + // This path is used when the CREATE2 delegate already exists. The tx only + // carries the auth, so use an inert zero-value call. + let tx = TransactionRequest::default() + .from(solver_address) + .to(Address::ZERO) + .value(U256::ZERO) + .nonce(solver_nonce) + .with_authorization_list(vec![signed_auth]); + + let pending = provider + .send_transaction(tx) + .await + .context("sending EIP-7702 delegation tx")?; + let receipt = pending + .get_receipt() + .await + .context("waiting for EIP-7702 delegation receipt")?; + receipt + .ensure_success() + .context("EIP-7702 delegation tx reverted")?; + tracing::info!( + tx_hash = ?receipt.transaction_hash, + block = ?receipt.block_number, + "EIP-7702 delegation tx confirmed" + ); + + // Verify the delegation was actually applied (EIP-7702 silently skips + // authorizations with mismatched nonces). + let code = provider + .get_code_at(solver_address) + .await + .context("reading solver EOA code after EIP-7702 delegation tx")?; + if !is_delegated_to(&code, delegate) { + anyhow::bail!( + "EIP-7702 delegation not applied after tx {:?}. Expected auth_nonce={} \ + (solver_nonce={} + 1). Check that no pending txs changed the nonce between query and \ + submission.", + receipt.transaction_hash, + solver_nonce + 1, + solver_nonce, + ); + } + + Ok(()) +} + +async fn sign_authorization( + config: &Config, + chain_id: u64, + delegate: Address, + auth_nonce: u64, +) -> anyhow::Result { + let auth = Authorization { + chain_id: U256::from(chain_id), + address: delegate, + nonce: auth_nonce, + }; + let sig = config + .account + .sign_hash(&auth.signature_hash()) + .await + .context("failed to sign EIP-7702 authorization")?; + + Ok(auth.into_signed(sig)) +} + +/// Wait until the solver has no pending transactions in the mempool. +/// Returns the confirmed nonce (safe to use for the next tx). +#[instrument(skip_all)] +async fn wait_for_pending_txs(provider: &impl Provider, address: Address) -> anyhow::Result { + const POLL_INTERVAL: Duration = Duration::from_secs(3); + const MAX_WAIT: Duration = Duration::from_secs(90); + + let deadline = tokio::time::Instant::now() + MAX_WAIT; + loop { + // Startup can happen while transactions from the previous driver process + // are still pending. Reusing that nonce would replace them. + // only counts txs in mined blocks + let latest = provider + .get_transaction_count(address) + .await + .context("reading latest solver nonce before EIP-7702 setup")?; + // also count txs in the mempool + let pending = provider + .get_transaction_count(address) + .pending() + .await + .context("reading pending solver nonce before EIP-7702 setup")?; + if pending <= latest { + return Ok(latest); + } + if tokio::time::Instant::now() > deadline { + anyhow::bail!( + "timed out waiting for {} pending solver txs to clear (latest nonce: {latest}, \ + pending nonce: {pending})", + pending - latest, + ); + } + tracing::info!( + latest_nonce = latest, + pending_nonce = pending, + pending_txs = pending - latest, + "waiting for pending solver txs to clear before delegation setup" + ); + tokio::time::sleep(POLL_INTERVAL).await; + } +} + +#[cfg(test)] +mod tests { + use {super::*, alloy::primitives::address}; + + const CALLER_A: Address = address!("0000000000000000000000000000000000000001"); + const CALLER_B: Address = address!("0000000000000000000000000000000000000002"); + const CALLER_C: Address = address!("0000000000000000000000000000000000000003"); + const CALLER_D: Address = address!("0000000000000000000000000000000000000004"); + const CALLER_E: Address = address!("0000000000000000000000000000000000000005"); + const CALLER_F: Address = address!("0000000000000000000000000000000000000006"); + + #[test] + fn delegate_target_is_stable_and_caller_sensitive() { + let (first, _, _) = delegate_deployment(&[CALLER_A, CALLER_B]).unwrap(); + let (same, _, _) = delegate_deployment(&[CALLER_A, CALLER_B]).unwrap(); + let (reordered, _, _) = delegate_deployment(&[CALLER_B, CALLER_A]).unwrap(); + + assert_eq!(first, same); + assert_ne!(first, reordered); + } + + #[test] + fn pads_approved_callers_to_contract_capacity() { + let (_, approved_callers, _) = delegate_deployment(&[CALLER_A, CALLER_B]).unwrap(); + + assert_eq!( + approved_callers, + [ + CALLER_A, + CALLER_B, + Address::ZERO, + Address::ZERO, + Address::ZERO + ] + ); + } + + #[test] + fn rejects_more_callers_than_the_delegate_supports() { + let err = + delegate_deployment(&[CALLER_A, CALLER_B, CALLER_C, CALLER_D, CALLER_E, CALLER_F]) + .unwrap_err(); + + assert!(err.to_string().contains("at most 5")); + } + + #[test] + fn rejects_zero_submission_account() { + let err = delegate_deployment(&[CALLER_A, Address::ZERO]).unwrap_err(); + + assert!(err.to_string().contains("zero address")); + } + + #[test] + fn rejects_duplicate_submission_accounts() { + let err = delegate_deployment(&[CALLER_A, CALLER_A]).unwrap_err(); + + assert!(err.to_string().contains("must be unique")); + } + + #[test] + fn detects_eip7702_delegation_target() { + let delegate = address!("0000000000000000000000000000000000000007"); + let other = address!("0000000000000000000000000000000000000008"); + let mut code = Vec::from(DELEGATION_PREFIX); + code.extend_from_slice(delegate.as_slice()); + + assert_eq!(DelegationStatus::from_code(&[]), DelegationStatus::Empty); + assert_eq!( + DelegationStatus::from_code(&[0x60, 0x00]), + DelegationStatus::OtherCode + ); + assert!(is_delegated_to(&code, delegate)); + assert!(!is_delegated_to(&code, other)); + } +} diff --git a/crates/driver/src/infra/solver/mod.rs b/crates/driver/src/infra/solver/mod.rs index 3c526f2cfa..c910c569a2 100644 --- a/crates/driver/src/infra/solver/mod.rs +++ b/crates/driver/src/infra/solver/mod.rs @@ -2,13 +2,13 @@ use { super::notify, crate::{ domain::{ + self, competition::{ auction::{self, Auction}, - bad_tokens, order, + risk_detector, solution::{self, Solution}, }, - eth, liquidity, time::Remaining, }, @@ -20,11 +20,18 @@ use { }, util, }, + alloy::{ + consensus::SignableTransaction, + network::TxSigner, + primitives::Address, + signers::{Signature, aws::AwsSigner, local::PrivateKeySigner}, + }, anyhow::Result, + bytes::Bytes, derive_more::{From, Into}, - ethrpc::alloy::conversions::IntoLegacy, + eth_domain_types as eth, num::BigRational, - observe::tracing::tracing_headers, + observe::tracing::distributed::headers::tracing_headers, reqwest::header::HeaderName, std::{ collections::HashMap, @@ -35,6 +42,7 @@ use { }; pub mod dto; +pub mod eip7702; // TODO At some point I should be checking that the names are unique, I don't // think I'm doing that. @@ -101,6 +109,69 @@ pub struct Solver { persistence: Persistence, } +#[derive(Debug, Clone)] +pub enum Account { + PrivateKey(PrivateKeySigner), + Kms(AwsSigner), + Address(Address), +} + +#[async_trait::async_trait] +impl TxSigner for Account { + fn address(&self) -> Address { + match self { + Account::PrivateKey(local_signer) => local_signer.address(), + Account::Kms(aws_signer) => aws_signer.address(), + Account::Address(address) => *address, + } + } + + async fn sign_transaction( + &self, + tx: &mut dyn SignableTransaction, + ) -> alloy::signers::Result { + match self { + Account::PrivateKey(local_signer) => local_signer.sign_transaction(tx).await, + Account::Kms(aws_signer) => aws_signer.sign_transaction(tx).await, + // The address actually can't sign anything but for TxSigner only the Tx matters + Account::Address(_) => Err(alloy::signers::Error::UnsupportedOperation( + alloy::signers::UnsupportedSignerOperation::SignHash, + )), + } + } +} + +impl Account { + /// Sign a hash using the underlying signer. Needed for EIP-7702 + /// authorization signing which requires `Signer::sign_hash` rather than + /// `TxSigner::sign_transaction`. + pub async fn sign_hash( + &self, + hash: &alloy::primitives::B256, + ) -> alloy::signers::Result { + use alloy::signers::Signer; + match self { + Account::PrivateKey(signer) => signer.sign_hash(hash).await, + Account::Kms(signer) => signer.sign_hash(hash).await, + Account::Address(_) => Err(alloy::signers::Error::UnsupportedOperation( + alloy::signers::UnsupportedSignerOperation::SignHash, + )), + } + } +} + +impl From for Account { + fn from(value: PrivateKeySigner) -> Self { + Self::PrivateKey(value) + } +} + +impl From for Account { + fn from(value: AwsSigner) -> Self { + Self::Kms(value) + } +} + #[derive(Debug, Clone)] pub struct Config { /// The endpoint of the solver, including the path (commonly "/solve"). @@ -111,7 +182,7 @@ pub struct Config { /// Whether or not liquidity is used by this solver. pub liquidity: Liquidity, /// The private key of this solver, used for settlement submission. - pub account: ethcontract::Account, + pub account: Account, /// How much time to spend for each step of the solving and competition. pub timeouts: Timeouts, /// HTTP headers that should be added to every request. @@ -130,7 +201,7 @@ pub struct Config { /// Which `tx.origin` is required to make quote verification pass. pub quote_tx_origin: Option, pub response_size_limit_max_bytes: usize, - pub bad_token_detection: BadTokenDetection, + pub bad_order_detection: BadOrderDetection, /// Max size of the pending settlements queue. pub settle_queue_size: usize, /// Whether flashloan hints should be sent to the solver. @@ -138,10 +209,56 @@ pub struct Config { /// Defines at which block the liquidity needs to be fetched on /solve /// requests. pub fetch_liquidity_at_block: infra::liquidity::AtBlock, + /// Quote haircut in basis points (0-10000). Applied to solver-reported + /// economics to make competition bids more conservative. Does not modify + /// interaction calldata. Default: 0 (no haircut). + pub haircut_bps: u32, + /// Additional EOAs for parallel settlement submission via EIP-7702. + /// When non-empty, these accounts submit txs to the solver EOA (which + /// delegates to Solver7702Delegate), enabling concurrent submissions. + pub submission_accounts: Vec, + /// Maximum number of solutions the driver proposes to the autopilot per + /// auction. When 1 (the default), only the best-scoring solution is sent. + pub max_solutions_to_propose: std::num::NonZeroUsize, + /// How many solutions the driver is allowed to post-process concurrently. + pub post_processing_concurrency_limit: std::num::NonZeroUsize, +} + +impl Config { + fn validate(&self) -> Result<()> { + if self.submission_accounts.is_empty() { + anyhow::ensure!( + self.max_solutions_to_propose.get() == 1, + "solver '{}': max-solutions-to-propose > 1 requires non-empty submission-accounts \ + (EIP-7702 parallel submission must be enabled)", + self.name, + ); + return Ok(()); + } + + anyhow::ensure!( + self.submission_accounts + .iter() + .all(|account| !matches!(account, Account::Address(_))), + "solver '{}': EIP-7702 submission accounts must be signers; address-only accounts \ + cannot sign delegated settlement transactions", + self.name, + ); + anyhow::ensure!( + !matches!(self.account, Account::Address(_)), + "solver '{}': main account must be a signer to set up EIP-7702 delegation when \ + submission accounts are configured", + self.name, + ); + + Ok(()) + } } impl Solver { pub async fn try_new(config: Config, eth: Ethereum) -> Result { + config.validate()?; + let mut headers = reqwest::header::HeaderMap::new(); headers.insert( reqwest::header::CONTENT_TYPE, @@ -159,6 +276,7 @@ impl Solver { Ok(Self { client: reqwest::ClientBuilder::new() .default_headers(headers) + .tcp_keepalive(Duration::from_secs(60)) .build()?, config, eth, @@ -166,8 +284,8 @@ impl Solver { }) } - pub fn bad_token_detection(&self) -> &BadTokenDetection { - &self.config.bad_token_detection + pub fn bad_order_detection(&self) -> &BadOrderDetection { + &self.config.bad_order_detection } pub fn persistence(&self) -> Persistence { @@ -190,11 +308,11 @@ impl Solver { /// The blockchain address of this solver. pub fn address(&self) -> eth::Address { - self.config.account.address().into() + self.config.account.address() } /// The account which should be used to sign settlements for this solver. - pub fn account(&self) -> ethcontract::Account { + pub fn account(&self) -> Account { self.config.account.clone() } @@ -228,6 +346,20 @@ impl Solver { self.config.fetch_liquidity_at_block.clone() } + /// Quote haircut in basis points (0-10000) for conservative bidding. + pub fn haircut_bps(&self) -> u32 { + self.config.haircut_bps + } + + /// Additional submission accounts for EIP-7702 parallel settlement. + pub fn submission_accounts(&self) -> &[Account] { + &self.config.submission_accounts + } + + pub fn max_solutions_to_propose(&self) -> usize { + self.config.max_solutions_to_propose.get() + } + /// Make a POST request instructing the solver to solve an auction. /// Allocates at most `timeout` time for the solving. #[instrument(name = "solver_engine", skip_all)] @@ -243,30 +375,32 @@ impl Solver { // Fetch the solutions from the solver. let weth = self.eth.contracts().weth_address(); - let auction_dto = dto::auction::new( - auction, - liquidity, - weth, - self.config.fee_handler, - self.config.solver_native_token, - &flashloan_hints, - &wrappers, - auction.deadline(self.timeouts()).solvers(), - ); let body = { + let auction_dto = dto::auction::new( + auction, + liquidity, + weth, + self.config.fee_handler, + self.config.solver_native_token, + &flashloan_hints, + &wrappers, + auction.deadline(self.timeouts()).solvers(), + self.config.haircut_bps, + ); + // pre-allocate a big enough buffer to avoid re-allocating memory // as the request gets serialized const BYTES_PER_ORDER: usize = 1_300; let mut buffer = Vec::with_capacity(auction.orders().len() * BYTES_PER_ORDER); serde_json::to_writer(&mut buffer, &auction_dto).unwrap(); - String::from_utf8(buffer).expect("serde_json only writes valid utf8") + Bytes::from(buffer) }; if let Some(id) = auction.id() { // Only auctions with IDs are real auctions (/quote requests don't have an ID). // Only for those it makes sense to archive them and measure the execution time. - self.persistence.archive_auction(id, &auction_dto); + self.persistence.archive_auction(id, body.clone()); ::observe::metrics::metrics().measure_auction_overhead( start, "driver", @@ -289,10 +423,14 @@ impl Solver { .body(body) .headers(tracing_headers()) .timeout(timeout); - if let Some(id) = observe::distributed_tracing::request_id::from_current_span() { + if let Some(id) = observe::tracing::distributed::request_id::from_current_span() { req = req.header("X-REQUEST-ID", id); } - super::observe::sending_solve_request(self.config.name.as_str(), timeout); + super::observe::sending_solve_request( + self.config.name.as_str(), + timeout, + auction.id().is_none(), + ); let started_at = std::time::Instant::now(); let res = util::http::send(self.config.response_size_limit_max_bytes, req).await; super::observe::solver_response( @@ -300,9 +438,10 @@ impl Solver { res.as_deref(), self.config.name.as_str(), started_at.elapsed(), + auction.id().is_none(), ); let res = res?; - let res: solvers_dto::solution::Solutions = + let res: solvers_dto::solution::SolverResponse = serde_json::from_str(&res).inspect_err(|err| { tracing::warn!(res, ?err, "failed to parse solver response"); self.notify( @@ -311,19 +450,31 @@ impl Solver { notify::Kind::DeserializationError(format!("Request format invalid: {err}")), ); })?; - let solutions = dto::Solutions::from(res).into_domain( - auction, - liquidity, - weth, - self.clone(), - &flashloan_hints, - )?; - super::observe::solutions(&solutions, auction.surplus_capturing_jit_order_owners()); - Ok(solutions) + match res { + solvers_dto::solution::SolverResponse::Error { error } => { + tracing::debug!(?error, "solver returned custom error"); + return Err(Error::CustomError(error)); + } + solvers_dto::solution::SolverResponse::Solutions { solutions } => { + let solutions = dto::Solutions::from(solutions).into_domain( + auction, + liquidity, + weth, + self.clone(), + &flashloan_hints, + )?; + + super::observe::solutions(&solutions, auction.surplus_capturing_jit_order_owners()); + Ok(solutions) + } + } } - fn assemble_flashloan_hints(&self, auction: &Auction) -> HashMap { + fn assemble_flashloan_hints( + &self, + auction: &Auction, + ) -> HashMap { if !self.config.flashloans_enabled { return Default::default(); } @@ -333,12 +484,12 @@ impl Solver { .iter() .flat_map(|order| { let hint = order.app_data.flashloan()?; - let flashloan = eth::Flashloan { - liquidity_provider: hint.liquidity_provider.into_legacy().into(), - protocol_adapter: hint.protocol_adapter.into_legacy().into(), - receiver: hint.receiver.into_legacy().into(), - token: hint.token.into_legacy().into(), - amount: hint.amount.into_legacy().into(), + let flashloan = domain::flashloan::Flashloan { + liquidity_provider: hint.liquidity_provider.into(), + protocol_adapter: hint.protocol_adapter.into(), + receiver: hint.receiver, + token: hint.token.into(), + amount: hint.amount.into(), }; Some((order.uid, flashloan)) }) @@ -357,7 +508,7 @@ impl Solver { let wrapper_calls = wrappers .iter() .map(|w| solvers_dto::auction::WrapperCall { - address: w.address.into_legacy(), + address: w.address, data: w.data.clone(), is_omittable: w.is_omittable, }) @@ -379,13 +530,15 @@ impl Solver { let url = shared::url::join(&self.config.endpoint, "notify"); super::observe::solver_request(&url, &body); let mut req = self.client.post(url).body(body).headers(tracing_headers()); - if let Some(id) = observe::distributed_tracing::request_id::from_current_span() { + if let Some(id) = observe::tracing::distributed::request_id::from_current_span() { req = req.header("X-REQUEST-ID", id); } let response_size = self.config.response_size_limit_max_bytes; let future = async move { - if let Err(error) = util::http::send(response_size, req).await { - tracing::warn!(?error, "failed to notify solver"); + if let Err(error) = util::http::send(response_size, req).await + && !matches!(error, util::http::Error::NotOk { code: 404, .. }) + { + tracing::debug!(?error, "failed to notify solver"); } }; tokio::task::spawn(future.in_current_span()); @@ -396,6 +549,103 @@ impl Solver { } } +#[cfg(test)] +mod tests { + use { + super::*, + alloy::primitives::{address, b256}, + std::num::NonZeroUsize, + }; + + const SOLVER: Address = address!("0000000000000000000000000000000000000001"); + const SUBMITTER: Address = address!("0000000000000000000000000000000000000002"); + + fn signer() -> Account { + Account::PrivateKey( + PrivateKeySigner::from_bytes(&b256!( + "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + )) + .unwrap(), + ) + } + + fn config() -> Config { + Config { + endpoint: "http://localhost/solve".parse().unwrap(), + name: Name("solver".to_string()), + slippage: Slippage { + relative: BigRational::from_integer(0.into()), + absolute: None, + }, + liquidity: Liquidity::Fetch, + account: Account::Address(SOLVER), + timeouts: Timeouts { + http_delay: chrono::Duration::seconds(1), + solving_share_of_deadline: 1.0.try_into().unwrap(), + }, + request_headers: Default::default(), + fee_handler: FeeHandler::Driver, + quote_using_limit_orders: false, + merge_solutions: SolutionMerging::Forbidden, + s3: None, + solver_native_token: ManageNativeToken { + wrap_address: false, + insert_unwraps: false, + }, + quote_tx_origin: None, + response_size_limit_max_bytes: 1024, + bad_order_detection: BadOrderDetection { + tokens_supported: Default::default(), + enable_simulation_strategy: false, + enable_metrics_strategy: false, + metrics_strategy_failure_ratio: 0.9, + metrics_strategy_required_measurements: 20, + metrics_strategy_log_only: true, + metrics_strategy_order_freeze_time: Duration::ZERO, + metrics_strategy_cache_gc_interval: Duration::ZERO, + metrics_strategy_cache_max_age: Duration::ZERO, + }, + settle_queue_size: 0, + flashloans_enabled: false, + fetch_liquidity_at_block: infra::liquidity::AtBlock::Latest, + haircut_bps: 0, + submission_accounts: vec![], + max_solutions_to_propose: NonZeroUsize::new(1).unwrap(), + post_processing_concurrency_limit: NonZeroUsize::MAX, + } + } + + #[test] + fn rejects_multiple_proposed_solutions_without_submission_accounts() { + let mut config = config(); + config.max_solutions_to_propose = NonZeroUsize::new(2).unwrap(); + + let err = config.validate().unwrap_err(); + + assert!(err.to_string().contains("requires non-empty")); + } + + #[test] + fn rejects_read_only_submission_accounts() { + let mut config = config(); + config.submission_accounts = vec![Account::Address(SUBMITTER)]; + + let err = config.validate().unwrap_err(); + + assert!(err.to_string().contains("must be signers")); + } + + #[test] + fn rejects_read_only_main_account_with_submission_accounts() { + let mut config = config(); + config.submission_accounts = vec![signer()]; + + let err = config.validate().unwrap_err(); + + assert!(err.to_string().contains("main account must be a signer")); + } +} + /// Controls whether or not the driver is allowed to merge multiple solutions /// of the same solver to produce an overall better solution. #[derive(Debug, Clone, Copy)] @@ -414,6 +664,8 @@ pub enum Error { Deserialize(#[from] serde_json::Error), #[error("solver dto error: {0}")] Dto(#[from] dto::Error), + #[error("solver returned custom error: {0:?}")] + CustomError(solvers_dto::solution::SolverError), } impl Error { @@ -423,16 +675,25 @@ impl Error { _ => false, } } + + pub fn custom_error(&self) -> Option<&solvers_dto::solution::SolverError> { + match self { + Self::CustomError(err) => Some(err), + _ => None, + } + } } #[derive(Debug, Clone)] -pub struct BadTokenDetection { +pub struct BadOrderDetection { /// Tokens that are explicitly allow- or deny-listed. - pub tokens_supported: HashMap, + pub tokens_supported: HashMap, pub enable_simulation_strategy: bool, pub enable_metrics_strategy: bool, pub metrics_strategy_failure_ratio: f64, pub metrics_strategy_required_measurements: u32, pub metrics_strategy_log_only: bool, - pub metrics_strategy_token_freeze_time: Duration, + pub metrics_strategy_order_freeze_time: Duration, + pub metrics_strategy_cache_gc_interval: Duration, + pub metrics_strategy_cache_max_age: Duration, } diff --git a/crates/driver/src/infra/tokens.rs b/crates/driver/src/infra/tokens.rs index cd8eca650b..cf91c35ab1 100644 --- a/crates/driver/src/infra/tokens.rs +++ b/crates/driver/src/infra/tokens.rs @@ -1,17 +1,12 @@ use { - crate::{ - domain::eth, - infra::{Ethereum, blockchain}, - }, + crate::infra::{Ethereum, blockchain}, anyhow::Result, - ethrpc::{ - alloy::conversions::IntoLegacy, - block_stream::{self, CurrentBlockWatcher}, - }, + eth_domain_types as eth, + ethrpc::block_stream::{self, CurrentBlockWatcher}, futures::{FutureExt, StreamExt}, itertools::Itertools, model::order::BUY_ETH_ADDRESS, - shared::request_sharing::BoxRequestSharing, + request_sharing::BoxRequestSharing, std::{ collections::HashMap, sync::{Arc, RwLock}, @@ -75,13 +70,7 @@ async fn update_task(blocks: CurrentBlockWatcher, inner: std::sync::Weak) /// Updates the settlement contract's balance for every cached token. async fn update_balances(inner: Arc) -> Result<(), blockchain::Error> { - let settlement = inner - .eth - .contracts() - .settlement() - .address() - .into_legacy() - .into(); + let settlement = *inner.eth.contracts().settlement().address(); let futures = { let cache = inner.cache.read().unwrap(); let tokens = cache.keys().cloned().collect::>(); @@ -141,13 +130,7 @@ impl Inner { &self, tokens: &[eth::TokenAddress], ) -> Vec> { - let settlement = self - .eth - .contracts() - .settlement() - .address() - .into_legacy() - .into(); + let settlement = *self.eth.contracts().settlement().address(); let futures = tokens.iter().map(|token| { let build_request = |token: ð::TokenAddress| { let token = self.eth.erc20(*token); diff --git a/crates/driver/src/main.rs b/crates/driver/src/main.rs index 13064f8724..ad758ab7fd 100644 --- a/crates/driver/src/main.rs +++ b/crates/driver/src/main.rs @@ -1,6 +1,11 @@ +#[cfg(feature = "mimalloc-allocator")] #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +#[cfg(not(feature = "mimalloc-allocator"))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + #[tokio::main] async fn main() { driver::start(std::env::args()).await; diff --git a/crates/driver/src/run.rs b/crates/driver/src/run.rs index 458edc5aec..a8649382d8 100644 --- a/crates/driver/src/run.rs +++ b/crates/driver/src/run.rs @@ -2,7 +2,7 @@ use { crate::{ domain::{ Mempools, - competition::{bad_tokens, order::app_data::AppDataRetriever}, + competition::{order::app_data::AppDataRetriever, risk_detector}, }, infra::{ self, @@ -12,13 +12,15 @@ use { config, liquidity, notify, - simulator::{self, Simulator}, solver::Solver, }, }, clap::Parser, + eth_domain_types as eth, futures::future::join_all, + http_client::HttpClientFactory, shared::arguments::tracing_config, + simulator::{self, Simulator}, std::{net::SocketAddr, sync::Arc, time::Duration}, tokio::sync::oneshot, }; @@ -55,7 +57,6 @@ async fn run_with(args: cli::Args, addr_sender: Option Some(AppDataRetriever::new(orderbook_url.clone(), *cache_size)), config::file::AppDataFetching::Disabled => None, }; + let solvers = solvers(&config, ð).await; + let http_factory = HttpClientFactory::new(&config.http); + // Set up EIP-7702 delegate deployment and solver delegation for solvers + // with parallel submission accounts. Must happen before the HTTP server + // starts accepting /settle requests. + infra::solver::eip7702::setup(&solvers, ð) + .await + .expect("EIP-7702 setup failed"); + let serve = Api { - solvers: solvers(&config, ð).await, + solvers, liquidity: liquidity(&config, ð).await, liquidity_sources_notifier: liquidity_sources_notifier(&config, ð), - simulator: simulator(&config, ð), + simulator: simulator(&config, simulator_eth, &http_factory), mempools: Mempools::try_new( config .mempools .iter() .map(|mempool| { - crate::infra::mempool::Mempool::new(mempool.to_owned(), web3.clone()) + crate::infra::mempool::Mempool::new( + mempool.to_owned(), + config + .solvers + .iter() + .flat_map(|config| { + std::iter::once(config.account.clone()) + .chain(config.submission_accounts.iter().cloned()) + }) + .collect(), + ) }) .collect(), eth.clone(), ) .unwrap(), - bad_token_detector: bad_tokens::simulation::Detector::new( + bad_token_detector: risk_detector::bad_tokens::Detector::new( config.simulation_bad_token_max_age, ð, ), @@ -118,34 +149,29 @@ async fn run_with(args: cli::Args, addr_sender: Option Simulator { +fn simulator( + config: &infra::Config, + eth: simulator::Ethereum, + http_factory: &HttpClientFactory, +) -> Simulator { let mut simulator = match &config.simulator { - Some(infra::simulator::Config::Tenderly(tenderly)) => Simulator::tenderly( - simulator::tenderly::Config { - url: tenderly.url.to_owned(), - api_key: tenderly.api_key.to_owned(), - user: tenderly.user.to_owned(), - project: tenderly.project.to_owned(), - save: tenderly.save, - save_if_fails: tenderly.save_if_fails, - }, - eth.to_owned(), - ), - Some(infra::simulator::Config::Enso(enso)) => Simulator::enso( - simulator::enso::Config { - url: enso.url.to_owned(), - network_block_interval: enso.network_block_interval.to_owned(), - }, - eth.to_owned(), - ), - None => Simulator::ethereum(eth.to_owned()), + configs::simulator::Config { + kind: configs::simulator::SimulatorKind::Tenderly(config), + .. + } => Simulator::tenderly(config, eth, http_factory), + configs::simulator::Config { + kind: configs::simulator::SimulatorKind::Ethereum, + .. + } => Simulator::ethereum(eth), }; + if config.disable_access_list_simulation { - simulator.disable_access_lists() + simulator.disable_access_lists(); } if let Some(gas) = config.disable_gas_simulation { - simulator.disable_gas(gas) + simulator.disable_gas(gas); } + simulator } @@ -174,8 +200,8 @@ async fn ethereum( ethrpc, config.contracts.clone(), gas, - config.tx_gas_limit, current_block_args, + eth::Gas(config.tx_gas_limit), ) .await } diff --git a/crates/driver/src/tests/boundary.rs b/crates/driver/src/tests/boundary.rs index 7efafe1835..94c73d61b9 100644 --- a/crates/driver/src/tests/boundary.rs +++ b/crates/driver/src/tests/boundary.rs @@ -3,31 +3,32 @@ pub use model::{DomainSeparator, order::OrderUid}; use { crate::domain::competition, - ethrpc::alloy::conversions::IntoAlloy, - secp256k1::SecretKey, - web3::signing::SecretKeyRef, + alloy::{ + primitives::{Address, U256}, + signers::local::PrivateKeySigner, + }, }; /// Order data used for calculating the order UID and signing. #[derive(Debug)] pub struct Order { - pub sell_token: ethcontract::H160, - pub buy_token: ethcontract::H160, - pub sell_amount: ethcontract::U256, - pub buy_amount: ethcontract::U256, + pub sell_token: Address, + pub buy_token: Address, + pub sell_amount: U256, + pub buy_amount: U256, pub valid_to: u32, - pub receiver: Option, - pub user_fee: ethcontract::U256, + pub receiver: Option
, + pub user_fee: U256, pub side: competition::order::Side, - pub secret_key: SecretKey, + pub secret_key: PrivateKeySigner, pub domain_separator: DomainSeparator, - pub owner: ethcontract::H160, + pub owner: Address, pub partially_fillable: bool, } impl Order { pub fn uid(&self) -> OrderUid { - self.build().data.uid(&self.domain_separator, &self.owner) + self.build().data.uid(&self.domain_separator, self.owner) } pub fn signature(&self) -> Vec { @@ -36,13 +37,13 @@ impl Order { fn build(&self) -> model::order::Order { model::order::OrderBuilder::default() - .with_sell_token(self.sell_token.into_alloy()) - .with_buy_token(self.buy_token.into_alloy()) - .with_sell_amount(self.sell_amount.into_alloy()) - .with_buy_amount(self.buy_amount.into_alloy()) + .with_sell_token(self.sell_token) + .with_buy_token(self.buy_token) + .with_sell_amount(self.sell_amount) + .with_buy_amount(self.buy_amount) .with_valid_to(self.valid_to) - .with_fee_amount(self.user_fee.into_alloy()) - .with_receiver(self.receiver.map(IntoAlloy::into_alloy)) + .with_fee_amount(self.user_fee) + .with_receiver(self.receiver) .with_kind(match self.side { competition::order::Side::Buy => model::order::OrderKind::Buy, competition::order::Side::Sell => model::order::OrderKind::Sell, @@ -51,7 +52,7 @@ impl Order { .sign_with( model::signature::EcdsaSigningScheme::Eip712, &self.domain_separator, - SecretKeyRef::new(&self.secret_key), + &self.secret_key, ) .build() } diff --git a/crates/driver/src/tests/cases/example_config.rs b/crates/driver/src/tests/cases/example_config.rs index 8035fcdd20..23f5e98149 100644 --- a/crates/driver/src/tests/cases/example_config.rs +++ b/crates/driver/src/tests/cases/example_config.rs @@ -1,4 +1,4 @@ -use {crate::tests, shared::addr}; +use {crate::tests, alloy::primitives::address}; /// Test that the example configuration file is valid by checking that the /// driver does not crash when started with this file. @@ -8,9 +8,9 @@ async fn test() { let example_config_file = std::env::current_dir().unwrap().join("example.toml"); tests::setup() .config(example_config_file) - .settlement_address(&addr!("9008D19f58AAbD9eD0D60971565AA8510560ab41")) - .balances_address(&addr!("3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b")) - .signatures_address(&addr!("8262d639c38470F38d2eff15926F7071c28057Af")) + .settlement_address(address!("9008D19f58AAbD9eD0D60971565AA8510560ab41")) + .balances_address(address!("3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b")) + .signatures_address(address!("8262d639c38470F38d2eff15926F7071c28057Af")) .done() .await; } diff --git a/crates/driver/src/tests/cases/fees.rs b/crates/driver/src/tests/cases/fees.rs index 8b511cbf39..dd4c9829d8 100644 --- a/crates/driver/src/tests/cases/fees.rs +++ b/crates/driver/src/tests/cases/fees.rs @@ -1,10 +1,13 @@ -use crate::{ - domain::competition::order, - infra::config::file::FeeHandler, - tests::{ - self, - setup::{ab_order, ab_pool, ab_solution, test_solver}, +use { + crate::{ + domain::competition::order, + infra::config::file::FeeHandler, + tests::{ + self, + setup::{ab_order, ab_pool, ab_solution, test_solver}, + }, }, + eth_domain_types as eth, }; #[tokio::test] @@ -14,7 +17,7 @@ async fn solver_fee() { let order = ab_order() .kind(order::Kind::Limit) .side(side) - .solver_fee(Some(500.into())); + .solver_fee(Some(eth::U256::from(500))); let test = tests::setup() .name(format!("Solver Fee: {side:?}")) .solvers(vec![test_solver().fee_handler(FeeHandler::Driver)]) diff --git a/crates/driver/src/tests/cases/flashloan_hints.rs b/crates/driver/src/tests/cases/flashloan_hints.rs index cdb2fa6440..08bcbb0002 100644 --- a/crates/driver/src/tests/cases/flashloan_hints.rs +++ b/crates/driver/src/tests/cases/flashloan_hints.rs @@ -8,8 +8,6 @@ use { }, alloy::primitives::Address, app_data::{Flashloan, ProtocolAppData, hash_full_app_data}, - ethrpc::alloy::conversions::IntoLegacy, - primitive_types::H160, std::sync::Arc, }; @@ -31,11 +29,11 @@ async fn solutions_with_flashloan() { protocol_app_data, ))); - let settlement = H160([5; 20]); + let settlement = Address::repeat_byte(5); let order = ab_order().app_data(app_data).receiver(Some(settlement)); let test = setup() - .settlement_address(&settlement) + .settlement_address(settlement) .pool(ab_pool()) .order(order.clone()) // This test is just about parsing the request JSON bodies so we don't care @@ -67,11 +65,11 @@ async fn solutions_without_flashloan() { let app_data = AppData::Full(Arc::new(protocol_app_data_into_validated( protocol_app_data, ))); - let settlement = H160([5; 20]); + let settlement = Address::repeat_byte(5); let order = ab_order().app_data(app_data).receiver(Some(settlement)); let test = setup() - .settlement_address(&settlement) + .settlement_address(settlement) .pool(ab_pool()) .order(order.clone()) .solution(ab_solution()) @@ -84,6 +82,55 @@ async fn solutions_without_flashloan() { test.solve().await.ok(); } +/// A flashloan-hint order is only visible as a flashloan order after +/// `update_orders` promotes its `AppData` from `Hash` to `Full`. If the +/// `flashloans_enabled=false` retain runs *before* promotion (as in the buggy +/// parallelized ordering), the driver sees `AppData::Hash(_).flashloan() == +/// None` and the order survives. When the bug regresses, the flashloan order +/// reaches the solver mock and the `/solve` body `assert_eq!` panics. +#[tokio::test] +#[ignore] +async fn flashloan_order_filtered_when_flashloans_disabled() { + let flashloan = Flashloan { + liquidity_provider: Address::from_slice(&[1; 20]), + receiver: Address::from_slice(&[2; 20]), + token: Address::from_slice(&[3; 20]), + protocol_adapter: Address::from_slice(&[4; 20]), + amount: ::alloy::primitives::U256::from(3), + }; + let protocol_app_data = ProtocolAppData { + flashloan: Some(flashloan), + ..Default::default() + }; + let app_data = AppData::Full(Arc::new(protocol_app_data_into_validated( + protocol_app_data, + ))); + + let test = setup() + .flashloans_enabled(false) + .pool(ab_pool()) + // Normal order: expected to reach the solver and settle. + .order(ab_order()) + // Flashloan-hint order: the driver must drop this before /solve. The + // mock orderbook indexes it by hash; the driver only sees the hash on + // /solve and must fetch + promote it before the retain runs. + .order( + ab_order() + .rename("flashloan-ab") + .app_data(app_data) + .filtered(), + ) + .solution(ab_solution()) + .done() + .await; + + // If the ordering bug regresses, the flashloan order reaches the solver + // and the solver mock's `check_solve_request` panics with + // "/solve request body does not match expectation" plus an orders-array + // diff. + test.solve().await.ok(); +} + fn protocol_app_data_into_validated(protocol: ProtocolAppData) -> app_data::ValidatedAppData { let root = app_data::Root::new(Some(protocol.clone())); let document = serde_json::to_string(&root).unwrap(); @@ -98,10 +145,10 @@ fn protocol_app_data_into_validated(protocol: ProtocolAppData) -> app_data::Vali fn flashloan_into_dto(flashloan: Flashloan) -> solvers_dto::solution::Flashloan { solvers_dto::solution::Flashloan { - liquidity_provider: flashloan.liquidity_provider.into_legacy(), - protocol_adapter: flashloan.protocol_adapter.into_legacy(), - receiver: flashloan.receiver.into_legacy(), - token: flashloan.token.into_legacy(), - amount: flashloan.amount.into_legacy(), + liquidity_provider: flashloan.liquidity_provider, + protocol_adapter: flashloan.protocol_adapter, + receiver: flashloan.receiver, + token: flashloan.token, + amount: flashloan.amount, } } diff --git a/crates/driver/src/tests/cases/gas_fee_override.rs b/crates/driver/src/tests/cases/gas_fee_override.rs new file mode 100644 index 0000000000..6eb7884b55 --- /dev/null +++ b/crates/driver/src/tests/cases/gas_fee_override.rs @@ -0,0 +1,60 @@ +use { + crate::tests::{ + self, + setup::{ab_order, ab_pool, ab_solution}, + }, + alloy::{consensus::Transaction, providers::Provider}, +}; + +const MAX_FEE_PER_GAS: u128 = 100_000_000_000; +const MAX_PRIORITY_FEE_PER_GAS: u128 = 2_000_000_000; + +/// Verify that a solution with custom gas fee overrides settles successfully +/// and the overrides are applied to the on-chain transaction. +#[tokio::test] +#[ignore] +async fn settle_with_gas_fee_override() { + let test = tests::setup() + .name("gas fee override") + .pool(ab_pool()) + .order(ab_order()) + .solution(ab_solution().gas_fee_override(MAX_FEE_PER_GAS, MAX_PRIORITY_FEE_PER_GAS)) + .done() + .await; + + let id = test.solve().await.ok().id(); + test.settle(id) + .await + .ok() + .await + .ab_order_executed(&test) + .await; + + // Verify the settlement transaction used the solver's gas fee override. + let block = test + .web3() + .provider + .get_block_by_number(Default::default()) + .await + .unwrap() + .unwrap(); + let tx_hash = block.transactions.hashes().next().unwrap(); + let tx = test + .web3() + .provider + .get_transaction_by_hash(tx_hash) + .await + .unwrap() + .unwrap(); + let consensus_tx: &dyn Transaction = &*tx.inner; + assert_eq!( + consensus_tx.max_fee_per_gas(), + MAX_FEE_PER_GAS, + "settlement tx should use the solver's maxFeePerGas override" + ); + assert_eq!( + consensus_tx.max_priority_fee_per_gas(), + Some(MAX_PRIORITY_FEE_PER_GAS), + "settlement tx should use the solver's maxPriorityFeePerGas override" + ); +} diff --git a/crates/driver/src/tests/cases/haircut.rs b/crates/driver/src/tests/cases/haircut.rs new file mode 100644 index 0000000000..6485ff408b --- /dev/null +++ b/crates/driver/src/tests/cases/haircut.rs @@ -0,0 +1,310 @@ +//! Tests for the haircut feature which applies conservative bidding by reducing +//! solver-reported economics. + +use { + crate::{ + domain::competition::order, + tests::{ + self, + cases::EtherExt, + setup::{ab_order, ab_pool, ab_solution}, + }, + }, + eth_domain_types as eth, + number::{testing::ApproxEq, units::EthUnit}, +}; + +/// Haircut in basis points used across tests (500 bps = 5%) +const HAIRCUT_BPS: u32 = 500; + +/// Test that haircut correctly reduces the solution score for sell orders. +/// The haircut reduces the reported buy_amount, making the bid more +/// conservative. +/// +/// Verifies that: +/// - `executedSell == signedSellAmount` (fill-or-kill requires exact execution) +/// - `executedBuy` with haircut < `executedBuy` without haircut (haircut +/// reduces output) +#[tokio::test] +#[ignore] +async fn order_haircut_reduces_score() { + // Use a limit order with enough slack for haircut + // The pool has 100000:6000 ratio, so selling 50 A gets ~2.97 B + // We set a generous buy_amount limit (e.g., 2 B) to create slack + let side = order::Side::Sell; + let kind = order::Kind::Limit; + let signed_sell_amount = ab_order().sell_amount; + + // First, get baseline without haircut + let test_no_haircut = tests::setup() + .name("Order haircut - baseline (0 bps)") + .pool(ab_pool()) + .order( + ab_order() + .side(side) + .kind(kind) + .buy_amount(2u64.eth()) // Low limit creates surplus + .solver_fee(Some(eth::U256::from(100))), + ) + .solution(ab_solution()) + .solvers(vec![tests::setup::test_solver().haircut_bps(0)]) + .done() + .await; + + let solve_no_haircut = test_no_haircut.solve().await.ok(); + let score_no_haircut = solve_no_haircut.score(); + + // Now test with 500 bps (5%) haircut + let test_with_haircut = tests::setup() + .name("Order haircut - with 500 bps (5%)") + .pool(ab_pool()) + .order( + ab_order() + .side(side) + .kind(kind) + .buy_amount(2u64.ether().into_wei()) // Same low limit + .solver_fee(Some(eth::U256::from(100))), + ) + .solution(ab_solution()) + .solvers(vec![tests::setup::test_solver().haircut_bps(HAIRCUT_BPS)]) + .done() + .await; + + let solve_with_haircut = test_with_haircut.solve().await.ok(); + let score_with_haircut = solve_with_haircut.score(); + + // With 500 bps (5%) haircut, the score should be reduced by approximately 5%. + // Compute the actual percentage: (score_with_haircut * 100) / score_no_haircut + // Should be approximately 95 (allowing 94-96 range for tolerance). + let percentage: u64 = ((score_with_haircut * eth::U256::from(100)) / score_no_haircut) + .try_into() + .unwrap(); + + assert!( + (94..=96).contains(&percentage), + "Haircut score {} should be ~95% of baseline {}, but was {}%", + score_with_haircut, + score_no_haircut, + percentage + ); + + // Extract executedBuy from baseline (no haircut) + let solution_no_haircut = solve_no_haircut.solution(); + let orders_no_haircut = solution_no_haircut + .get("orders") + .unwrap() + .as_object() + .unwrap(); + let executed_buy_no_haircut = orders_no_haircut + .values() + .next() + .unwrap() + .get("executedBuy") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + + // Verify that reported sell amount matches signed amount exactly. + // Fill-or-kill orders require exact execution. + let solution = solve_with_haircut.solution(); + let orders = solution.get("orders").unwrap().as_object().unwrap(); + for (_uid, order_data) in orders { + let executed_sell = order_data + .get("executedSell") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + let executed_buy = order_data + .get("executedBuy") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + let limit_sell = order_data + .get("limitSell") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + + assert!( + executed_sell == signed_sell_amount, + "Sell order: executedSell {} does not match signed sell amount {} (fill-or-kill \ + requires exact execution)", + executed_sell, + signed_sell_amount + ); + assert!( + executed_sell <= limit_sell, + "executedSell {} exceeds limitSell {}", + executed_sell, + limit_sell + ); + + // Verify haircut reduces executedBuy for sell orders by approximately + // HAIRCUT_BPS + let expected_buy = + executed_buy_no_haircut * eth::U256::from(10000 - HAIRCUT_BPS) / eth::U256::from(10000); + assert!( + executed_buy.is_approx_eq(&expected_buy, Some(0.01)), + "Sell order: executedBuy {} should be ~{}% of baseline {} (expected ~{})", + executed_buy, + 100 - HAIRCUT_BPS / 100, + executed_buy_no_haircut, + expected_buy + ); + } +} + +/// Test that haircut is properly applied for buy orders. +/// For buy orders, the haircut increases the sell_amount the user pays. +/// This reduces surplus and thus the score. +/// +/// Verifies that: +/// - `executedBuy == signedBuyAmount` (fill-or-kill must execute exactly) +/// - `executedSell <= sellLimit` (haircut increases sell, but must stay within +/// limit) +/// - `executedSell` with haircut > `executedSell` without haircut (haircut +/// increases cost) +#[tokio::test] +#[ignore] +async fn buy_order_haircut() { + let side = order::Side::Buy; + let kind = order::Kind::Limit; + let signed_buy_amount = 2u64.eth(); + let signed_sell_limit = 100u64.ether().into_wei(); + + // For buy orders, we need to set a buy_amount that creates enough surplus. + // The pool has 100000:6000 ratio. For a buy order wanting 2.97 B, + // we'd need to sell ~50 A. Setting a generous sell limit creates surplus. + let test_no_haircut = tests::setup() + .name("Buy order haircut - baseline") + .pool(ab_pool()) + .order( + ab_order() + .side(side) + .kind(kind) + .buy_amount(signed_buy_amount) // Target buy amount (what user signs for) + .sell_amount(signed_sell_limit) // Generous sell limit creates surplus + .solver_fee(Some(eth::U256::from(100))), + ) + .solution(ab_solution()) + .solvers(vec![tests::setup::test_solver().haircut_bps(0)]) + .done() + .await; + + let solve_no_haircut = test_no_haircut.solve().await.ok(); + let score_no_haircut = solve_no_haircut.score(); + + let test_with_haircut = tests::setup() + .name("Buy order haircut - with 500 bps") + .pool(ab_pool()) + .order( + ab_order() + .side(side) + .kind(kind) + .buy_amount(signed_buy_amount) // Same target buy amount + .sell_amount(signed_sell_limit) // Same generous sell limit + .solver_fee(Some(eth::U256::from(100))), + ) + .solution(ab_solution()) + .solvers(vec![tests::setup::test_solver().haircut_bps(HAIRCUT_BPS)]) + .done() + .await; + + let solve_with_haircut = test_with_haircut.solve().await.ok(); + let score_with_haircut = solve_with_haircut.score(); + + // For buy orders, the haircut is applied to the executed buy amount and then + // converted to sell token. The impact on score depends on the price ratio. + // With 500 bps (5%) haircut on a 2 ETH buy amount, the haircut is 0.1 ETH in + // buy token. When converted to sell token at the pool's price ratio, this + // results in a smaller percentage impact on the score compared to sell + // orders. Expected: score reduction of ~1% (percentage ~99%) rather than + // 5%. + let percentage: u64 = ((score_with_haircut * eth::U256::from(100)) / score_no_haircut) + .try_into() + .unwrap(); + + // For buy orders with this setup, expect ~99% (1% reduction) due to price + // conversion + assert!( + (98..=100).contains(&percentage) && score_with_haircut < score_no_haircut, + "Haircut score {} should be ~99% of baseline {} (reduced by ~1%), but was {}%", + score_with_haircut, + score_no_haircut, + percentage + ); + + // Extract executedSell from baseline (no haircut) + let solution_no_haircut = solve_no_haircut.solution(); + let orders_no_haircut = solution_no_haircut + .get("orders") + .unwrap() + .as_object() + .unwrap(); + let executed_sell_no_haircut = orders_no_haircut + .values() + .next() + .unwrap() + .get("executedSell") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + + // Verify buy order constraints: + // - Fill-or-kill must execute exactly (executedBuy == signedBuyAmount) + // - Don't take more than user's maximum (executedSell <= sellLimit) + let solution = solve_with_haircut.solution(); + let orders = solution.get("orders").unwrap().as_object().unwrap(); + for (_uid, order_data) in orders { + let executed_sell = order_data + .get("executedSell") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + let executed_buy = order_data + .get("executedBuy") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + let limit_sell = order_data + .get("limitSell") + .and_then(|v| v.as_str()) + .and_then(|s| eth::U256::from_str_radix(s, 10).ok()) + .unwrap(); + + assert!( + executed_buy == signed_buy_amount, + "Buy order: executedBuy {} does not match signed buy amount {} (fill-or-kill requires \ + exact execution)", + executed_buy, + signed_buy_amount + ); + assert!( + executed_sell <= signed_sell_limit, + "Buy order: executedSell {} exceeds sell limit {}. Haircut increases sell_amount but \ + it must still respect the user's limit!", + executed_sell, + signed_sell_limit + ); + assert!( + executed_sell <= limit_sell, + "executedSell {} exceeds limitSell {}", + executed_sell, + limit_sell + ); + + // Verify haircut increases executedSell for buy orders. + // For buy orders, haircut increases the sell amount proportionally. + let haircut_ratio = 1.0 + (HAIRCUT_BPS as f64 / 10000.0); // ~1.05 for 500 bps + let expected_sell = + eth::U256::from((executed_sell_no_haircut.to::() as f64 * haircut_ratio) as u128); + assert!( + executed_sell.is_approx_eq(&expected_sell, Some(0.02)), + "Buy order: executedSell {} should be ~{:.1}% higher than baseline {} (expected ~{})", + executed_sell, + (haircut_ratio - 1.0) * 100.0, + executed_sell_no_haircut, + expected_sell + ); + } +} diff --git a/crates/driver/src/tests/cases/haircut_pre_processing.rs b/crates/driver/src/tests/cases/haircut_pre_processing.rs new file mode 100644 index 0000000000..f6a9a310ee --- /dev/null +++ b/crates/driver/src/tests/cases/haircut_pre_processing.rs @@ -0,0 +1,253 @@ +//! Parameterized end-to-end tests for the haircut "make-room" pre-processing. +//! +//! The driver tightens each order's limits before sending the auction to the +//! solver, so that any bid the solver returns at the tightened limit still +//! respects the user's signed limit price after the post-hoc haircut is +//! applied. These tests prove that round-trip closes: solver bids exactly at +//! the tightened limit it sees, driver applies the haircut, and the reported +//! amounts land on the user's signed limit. +//! +//! Modelled on the `volume_protocol_fee_*_at_limit_price` cases in +//! [`super::protocol_fees`], which are the closest existing precedent — there +//! too, the driver post-processes the solver's bid and the test asserts that +//! the user lands on the signed limit. + +use { + crate::{ + domain::competition::order, + tests::{ + self, + cases::EtherExt, + setup::{ + ExpectedOrderAmounts, + Test, + ab_adjusted_pool, + ab_liquidity_quote, + ab_order, + ab_solution, + test_solver, + }, + }, + }, + eth_domain_types as eth, +}; + +struct Amounts { + sell: eth::U256, + buy: eth::U256, +} + +struct Execution { + // What the solver bids against the tightened limit it sees. + solver: Amounts, + // What the driver reports after applying the haircut. + driver: Amounts, +} + +struct Order { + sell_amount: eth::U256, + buy_amount: eth::U256, + side: order::Side, +} + +struct TestCase { + order: Order, + haircut_bps: u32, + execution: Execution, + expected_score: eth::U256, + partial: bool, +} + +async fn run(test_case: TestCase) { + let test_name = format!( + "Haircut make-room: {:?} {} bps{}", + test_case.order.side, + test_case.haircut_bps, + if test_case.partial { " partial" } else { "" }, + ); + let quote = ab_liquidity_quote() + .sell_amount(test_case.execution.solver.sell) + .buy_amount(test_case.execution.solver.buy); + let pool = ab_adjusted_pool(quote); + // Use a tiny constant network fee. The at-limit haircut math is sensitive + // to a percent-based `solver_fee` (the haircut conversion through clearing + // prices doesn't absorb it the way the volume-fee path does), and we still + // need a non-zero fee to keep these orders out of the StaticFee path. + let solver_fee = eth::U256::from(100); + let executed = match test_case.order.side { + order::Side::Buy => (test_case.order.buy_amount > test_case.execution.solver.buy) + .then_some(test_case.execution.solver.buy), + order::Side::Sell => (test_case.order.sell_amount > test_case.execution.solver.sell) + .then_some(test_case.execution.solver.sell - solver_fee), + }; + let expected_amounts = ExpectedOrderAmounts { + sell: test_case.execution.driver.sell, + buy: test_case.execution.driver.buy, + }; + + let mut order = ab_order() + .kind(order::Kind::Limit) + .sell_amount(test_case.order.sell_amount) + .buy_amount(test_case.order.buy_amount) + .solver_fee(Some(solver_fee)) + .side(test_case.order.side) + .executed(executed) + .no_surplus() + .expected_amounts(expected_amounts); + if test_case.partial { + order = order.partial(eth::U256::ZERO); + } + + let test: Test = tests::setup() + .name(test_name) + .pool(pool) + .order(order.clone()) + .solution(ab_solution()) + .solvers(vec![test_solver().haircut_bps(test_case.haircut_bps)]) + .done() + .await; + + let result = test.solve().await.ok(); + // At the limit price the make-room math closes to zero surplus over the + // signed limit, but the integer-price encoding leaves a few wei of noise. + // `is_approx_eq` would divide-by-zero against `expected_score = 0`, so + // compare with an absolute wei tolerance instead. + let score = result.score(); + let diff = if score > test_case.expected_score { + score - test_case.expected_score + } else { + test_case.expected_score - score + }; + assert!( + diff <= eth::U256::from(1_000_000u64), + "score {} differs from expected {} by {} wei", + score, + test_case.expected_score, + diff, + ); + result.orders(&[order]); +} + +/// Sell order: solver bids at the tightened buy limit (40 / (1 - 0.2) = 50) +/// and the driver's 2000 bps haircut brings the reported buy back to the +/// user's signed limit of 40 ETH. Mirrors +/// [`super::protocol_fees::volume_protocol_fee_sell_order_at_limit_price`]. +#[tokio::test] +#[ignore] +async fn sell_order_at_limit_price() { + let test_case = TestCase { + order: Order { + sell_amount: 50.ether().into_wei(), + buy_amount: 40.ether().into_wei(), + side: order::Side::Sell, + }, + haircut_bps: 2000, + execution: Execution { + // Solver clears at the tightened limit (40 / (1 - 0.2) = 50 buy). + solver: Amounts { + sell: 50.ether().into_wei(), + buy: 50.ether().into_wei(), + }, + // Driver subtracts the 20% haircut, landing exactly on the signed limit. + driver: Amounts { + sell: 50.ether().into_wei(), + buy: 40.ether().into_wei(), + }, + }, + expected_score: eth::U256::ZERO, + partial: false, + }; + run(test_case).await; +} + +/// Buy order: solver bids at the tightened sell limit (50 / (1 + 0.25) = 40) +/// and the driver's 2500 bps haircut adds back exactly the amount needed for +/// the reported sell to equal the user's signed limit of 50 ETH. Mirrors +/// [`super::protocol_fees::volume_protocol_fee_buy_order_at_limit_price`]. +#[tokio::test] +#[ignore] +async fn buy_order_at_limit_price() { + let test_case = TestCase { + order: Order { + sell_amount: 50.ether().into_wei(), + buy_amount: 40.ether().into_wei(), + side: order::Side::Buy, + }, + haircut_bps: 2500, + execution: Execution { + // Solver clears at the tightened limit (50 / (1 + 0.25) = 40 sell). + solver: Amounts { + sell: 40.ether().into_wei(), + buy: 40.ether().into_wei(), + }, + // Driver adds the 25% haircut, landing exactly on the signed limit. + driver: Amounts { + sell: 50.ether().into_wei(), + buy: 40.ether().into_wei(), + }, + }, + expected_score: eth::U256::ZERO, + partial: false, + }; + run(test_case).await; +} + +/// Partial sell order, scaled-down version of the at-limit case. Mirrors +/// [`super::protocol_fees::volume_protocol_fee_partial_sell_order_at_limit_price`]. +#[tokio::test] +#[ignore] +async fn partial_sell_order_at_limit_price() { + let test_case = TestCase { + order: Order { + sell_amount: 50.ether().into_wei(), + buy_amount: 50.ether().into_wei(), + side: order::Side::Sell, + }, + haircut_bps: 2000, + execution: Execution { + // 40% partial fill at the tightened limit (20 / (1 - 0.2) = 25 buy). + solver: Amounts { + sell: 20.ether().into_wei(), + buy: 25.ether().into_wei(), + }, + // 20% haircut on the partial buy lands on the partial signed limit. + driver: Amounts { + sell: 20.ether().into_wei(), + buy: 20.ether().into_wei(), + }, + }, + expected_score: eth::U256::ZERO, + partial: true, + }; + run(test_case).await; +} + +/// Partial buy order, scaled-down version of the at-limit case. Mirrors +/// [`super::protocol_fees::volume_protocol_fee_partial_buy_order_at_limit_price`]. +#[tokio::test] +#[ignore] +async fn partial_buy_order_at_limit_price() { + let test_case = TestCase { + order: Order { + sell_amount: 50.ether().into_wei(), + buy_amount: 50.ether().into_wei(), + side: order::Side::Buy, + }, + haircut_bps: 2500, + execution: Execution { + // 40% partial fill at the tightened limit (20 / (1 + 0.25) = 16 sell). + solver: Amounts { + sell: 16.ether().into_wei(), + buy: 20.ether().into_wei(), + }, + // 25% haircut on the partial sell lands on the partial signed limit. + driver: Amounts { + sell: 20.ether().into_wei(), + buy: 20.ether().into_wei(), + }, + }, + expected_score: eth::U256::ZERO, + partial: true, + }; + run(test_case).await; +} diff --git a/crates/driver/src/tests/cases/jit_orders.rs b/crates/driver/src/tests/cases/jit_orders.rs index 10b8f403e6..bfa8d4e46d 100644 --- a/crates/driver/src/tests/cases/jit_orders.rs +++ b/crates/driver/src/tests/cases/jit_orders.rs @@ -1,22 +1,22 @@ -use crate::{ - domain::{ - competition::{order, order::Side}, - eth, - }, - tests::{ - self, - cases::{EtherExt, is_approximately_equal}, - setup::{ +use { + crate::{ + domain::competition::{order, order::Side}, + tests::{ self, - ExpectedOrderAmounts, - Test, - ab_adjusted_pool, - ab_liquidity_quote, - ab_order, - ab_solution, - test_solver, + cases::EtherExt, + setup::{ + self, + ExpectedOrderAmounts, + Test, + ab_adjusted_pool, + ab_liquidity_quote, + ab_order, + ab_solution, + test_solver, + }, }, }, + eth_domain_types as eth, }; struct Amounts { @@ -55,6 +55,8 @@ struct TestCase { #[cfg(test)] async fn protocol_fee_test_case(test_case: TestCase) { + use number::testing::ApproxEq; + let test_name = format!("JIT Order: {:?}", test_case.solution.jit_order.order.side); // Adjust liquidity pools so that the order is executable at the amounts // expected from the solver. @@ -62,7 +64,7 @@ async fn protocol_fee_test_case(test_case: TestCase) { .sell_amount(test_case.execution.solver.sell) .buy_amount(test_case.execution.solver.buy); let pool = ab_adjusted_pool(quote); - let solver_fee = test_case.execution.driver.sell / 100; + let solver_fee = test_case.execution.driver.sell / eth::U256::from(100); // Amounts expected to be returned by the driver after fee processing let jit_order_expected_amounts = if test_case.is_surplus_capturing_jit_order { ExpectedOrderAmounts { @@ -93,7 +95,7 @@ async fn protocol_fee_test_case(test_case: TestCase) { .buy_amount(test_case.order.buy_amount) .solver_fee(Some(solver_fee)) .side(test_case.order.side) - .partial(0.into()) + .partial(eth::U256::ZERO) .no_surplus(); let solver = test_solver(); @@ -114,10 +116,11 @@ async fn protocol_fee_test_case(test_case: TestCase) { .await; let result = test.solve().await.ok(); - assert!(is_approximately_equal( - result.score(), - test_case.solution.expected_score, - )); + assert!( + result + .score() + .is_approx_eq(&test_case.solution.expected_score, None), + ); result.jit_orders(&[jit_order]); } diff --git a/crates/driver/src/tests/cases/mod.rs b/crates/driver/src/tests/cases/mod.rs index 15349cb5e5..e349d9b277 100644 --- a/crates/driver/src/tests/cases/mod.rs +++ b/crates/driver/src/tests/cases/mod.rs @@ -1,10 +1,10 @@ //! Test cases. use { - crate::{domain::eth, util::conv::u256::U256Ext}, bigdecimal::{BigDecimal, FromPrimitive, Signed, num_traits::CheckedMul}, + eth_domain_types as eth, num::BigRational, - number::conversions::big_decimal_to_big_rational, + number::{conversions::big_decimal_to_big_rational, u256_ext::U256Ext}, std::str::FromStr, }; @@ -12,6 +12,9 @@ pub mod buy_eth; pub mod example_config; pub mod fees; mod flashloan_hints; +pub mod gas_fee_override; +pub mod haircut; +pub mod haircut_pre_processing; pub mod internalization; pub mod jit_orders; pub mod merge_settlements; @@ -59,7 +62,7 @@ impl Ether { pub fn into_wei(self) -> eth::U256 { BigRational::from_f64(1e18) .and_then(|exp| self.0.checked_mul(&exp)) - .and_then(|wei| eth::U256::from_big_rational(&wei).ok()) + .and_then(|wei| eth::U256::from_big_rational(&wei)) .unwrap() } } @@ -118,14 +121,3 @@ impl EtherExt for f64 { Ether(BigRational::from_f64(self).unwrap()) } } - -// because of rounding errors, it's good enough to check that the expected value -// is within a very narrow range of the executed value -#[cfg(test)] -pub fn is_approximately_equal(executed_value: eth::U256, expected_value: eth::U256) -> bool { - let lower = - expected_value * eth::U256::from(99999999999u128) / eth::U256::from(100000000000u128); // in percents = 99.999999999% - let upper = - expected_value * eth::U256::from(100000000001u128) / eth::U256::from(100000000000u128); // in percents = 100.000000001% - executed_value >= lower && executed_value <= upper -} diff --git a/crates/driver/src/tests/cases/multiple_solutions.rs b/crates/driver/src/tests/cases/multiple_solutions.rs index 33c78efd5d..72b74f27e0 100644 --- a/crates/driver/src/tests/cases/multiple_solutions.rs +++ b/crates/driver/src/tests/cases/multiple_solutions.rs @@ -1,8 +1,20 @@ -use crate::tests::{ - setup, - setup::{ab_order, ab_pool, ab_solution}, +use { + crate::tests::{ + setup, + setup::{ab_order, ab_pool, ab_solution, ad_order, ad_pool, ad_solution, test_solver}, + }, + alloy::{primitives::b256, signers::local::PrivateKeySigner}, + eth_domain_types as eth, }; +fn submission_account() -> PrivateKeySigner { + // Well-known Anvil test key #1. Do not use as a production key. + PrivateKeySigner::from_bytes(&b256!( + "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + )) + .unwrap() +} + /// Test that the best-scoring solution is picked when the /solve endpoint /// returns multiple valid solutions. #[tokio::test] @@ -21,6 +33,98 @@ async fn valid() { test.reveal(id).await.ok().calldata(); } +/// Test that when multiple solutions are proposed they are returned sorted +/// best-first (by score) and each can be revealed independently. +/// Uses two different orders (AB and AD with different sell amounts) so the +/// solutions have genuinely different surplus and therefore different scores. +#[tokio::test] +#[ignore] +async fn all_proposed() { + let test = setup() + .solvers(vec![ + test_solver() + .max_solutions_to_propose(5) + .submission_account(submission_account()), + ]) + .pool(ab_pool()) + .pool(ad_pool()) + .order(ab_order()) + .order(ad_order()) + // Add the lower-scoring solution first so the sort has to reorder. + .solution(ad_solution()) + .solution(ab_solution()) + .done() + .await; + + let solve = test.solve().await.ok(); + let solutions = solve.solutions(); + assert_eq!(solutions.len(), 2); + + // Solutions must be sorted best-first (strictly descending score). + let score0 = solutions[0].get("score").unwrap().as_str().unwrap(); + let score1 = solutions[1].get("score").unwrap().as_str().unwrap(); + let score0 = eth::U256::from_str_radix(score0, 10).unwrap(); + let score1 = eth::U256::from_str_radix(score1, 10).unwrap(); + assert!(score0 > score1, "expected strictly descending scores"); + + // Both solutions should be revealable. + let id0 = solutions[0].get("solutionId").unwrap().as_u64().unwrap(); + let id1 = solutions[1].get("solutionId").unwrap().as_u64().unwrap(); + test.reveal(id0).await.ok().calldata(); + test.reveal(id1).await.ok().calldata(); +} + +/// Test that `max-solutions-to-propose` caps the number of returned solutions. +#[tokio::test] +#[ignore] +async fn capped() { + let test = setup() + .solvers(vec![ + test_solver() + .max_solutions_to_propose(1) + .submission_account(submission_account()), + ]) + .pool(ab_pool()) + .pool(ad_pool()) + .order(ab_order()) + .order(ad_order()) + .solution(ab_solution()) + .solution(ad_solution()) + .done() + .await; + + let solve = test.solve().await.ok(); + let solutions = solve.solutions(); + assert_eq!(solutions.len(), 1, "should be capped to 1 solution"); +} + +/// Test that when multiple solutions are proposed, invalid solutions are +/// discarded and only valid ones are returned. +#[tokio::test] +#[ignore] +async fn only_proposes_valid_solutions() { + let order = ab_order(); + let test = setup() + .solvers(vec![ + test_solver() + .max_solutions_to_propose(5) + .submission_account(submission_account()), + ]) + .pool(ab_pool()) + .order(order.clone()) + .solution(ab_solution()) + .solution(ab_solution().invalid()) + .done() + .await; + + let solve = test.solve().await.ok(); + let solutions = solve.solutions(); + assert_eq!(solutions.len(), 1); + + let id = solutions[0].get("solutionId").unwrap().as_u64().unwrap(); + test.reveal(id).await.ok().calldata(); +} + /// Test that the invalid solution is discarded when the /solve endpoint /// returns multiple solutions. #[tokio::test] diff --git a/crates/driver/src/tests/cases/order_prioritization.rs b/crates/driver/src/tests/cases/order_prioritization.rs index 302f8e2114..792bc1661f 100644 --- a/crates/driver/src/tests/cases/order_prioritization.rs +++ b/crates/driver/src/tests/cases/order_prioritization.rs @@ -6,6 +6,7 @@ use { setup::{Order, OrderQuote, ab_order, ab_pool, ab_solution, setup, test_solver}, }, }, + alloy::primitives::U256, chrono::Utc, std::time::Duration, }; @@ -264,7 +265,7 @@ async fn filtering() { .order( Order { sell_amount: "4999999999900.002".ether().into_wei(), - surplus_factor: 1.into(), + surplus_factor: U256::ONE, ..ab_order() } .rename("fourth order") diff --git a/crates/driver/src/tests/cases/protocol_fees.rs b/crates/driver/src/tests/cases/protocol_fees.rs index 9c17eefcdf..2612528223 100644 --- a/crates/driver/src/tests/cases/protocol_fees.rs +++ b/crates/driver/src/tests/cases/protocol_fees.rs @@ -1,20 +1,23 @@ -use crate::{ - domain::{competition::order, eth}, - infra::config::file::FeeHandler, - tests::{ - self, - cases::{EtherExt, is_approximately_equal}, - setup::{ - ExpectedOrderAmounts, - Test, - ab_adjusted_pool, - ab_liquidity_quote, - ab_order, - ab_solution, - fee::{Policy, Quote}, - test_solver, +use { + crate::{ + domain::competition::order, + infra::config::file::FeeHandler, + tests::{ + self, + cases::EtherExt, + setup::{ + ExpectedOrderAmounts, + Test, + ab_adjusted_pool, + ab_liquidity_quote, + ab_order, + ab_solution, + fee::{Policy, Quote}, + test_solver, + }, }, }, + eth_domain_types as eth, }; struct Amounts { @@ -45,6 +48,8 @@ struct TestCase { #[cfg(test)] async fn protocol_fee_test_case(test_case: TestCase) { + use number::testing::ApproxEq; + let test_name = format!( "Protocol Fee: {:?} {:?}", test_case.order.side, test_case.fee_policy @@ -55,7 +60,7 @@ async fn protocol_fee_test_case(test_case: TestCase) { .sell_amount(test_case.execution.solver.sell) .buy_amount(test_case.execution.solver.buy); let pool = ab_adjusted_pool(quote); - let solver_fee = test_case.execution.driver.sell / 100; + let solver_fee = test_case.execution.driver.sell / eth::U256::from(100); let executed = match test_case.order.side { order::Side::Buy => (test_case.order.buy_amount > test_case.execution.solver.buy) .then_some(test_case.execution.solver.buy), @@ -79,7 +84,7 @@ async fn protocol_fee_test_case(test_case: TestCase) { .side(test_case.order.side) .fee_policy(test_case.fee_policy) .executed(executed) - .partial(0.into()) + .partial(eth::U256::ZERO) // Surplus is configured explicitly via executed/quoted amounts .no_surplus() .expected_amounts(expected_amounts); @@ -94,10 +99,7 @@ async fn protocol_fee_test_case(test_case: TestCase) { .await; let result = test.solve().await.ok(); - assert!(is_approximately_equal( - result.score(), - test_case.expected_score - )); + assert!(result.score().is_approx_eq(&test_case.expected_score, None),); result.orders(&[order]); } diff --git a/crates/driver/src/tests/cases/quote.rs b/crates/driver/src/tests/cases/quote.rs index 0670cd5fb0..53b3ee76c5 100644 --- a/crates/driver/src/tests/cases/quote.rs +++ b/crates/driver/src/tests/cases/quote.rs @@ -1,11 +1,35 @@ -use crate::{ - domain::competition::order, - tests::{ - self, - setup::{self, ab_order, ab_pool, ab_solution}, +use { + crate::{ + domain::competition::order, + tests::{ + self, + cases::EtherExt, + setup::{self, ab_order, ab_pool, ab_solution}, + }, }, + eth_domain_types as eth, + number::testing::ApproxEq, }; +/// Extracts the buy amount from a quote response using clearing prices. +/// +/// For a sell order, calculates: `sell_amount * sell_price / buy_price` +/// Since the sell token has the lower price in our test setup, this becomes: +/// `sell_amount * price_low / price_high` +fn extract_buy_amount(response_body: &str, sell_amount: eth::U256) -> eth::U256 { + let body: serde_json::Value = serde_json::from_str(response_body).unwrap(); + let clearing_prices = body.get("clearingPrices").unwrap().as_object().unwrap(); + + let mut prices: Vec = clearing_prices + .values() + .map(|v| v.as_str().unwrap().parse::().unwrap()) + .collect(); + prices.sort(); + + let (price_low, price_high) = (prices[0], prices[1]); + sell_amount * price_low / price_high +} + /// Run a matrix of tests for all meaningful combinations of order kind and /// side, verifying that they get quoted successfully. #[tokio::test] @@ -64,3 +88,82 @@ async fn with_jit_order() { // Check whether the returned data aligns with the expected. quote.ok().amount().interactions().jit_order(); } + +/// Test that quote haircut correctly reduces the executed amount for quotes +/// when configured. The haircut should make quotes more conservative without +/// affecting the ability to place and execute orders. +#[tokio::test] +#[ignore] +async fn with_quote_haircut() { + // Test with a sell order - haircut should reduce the buy amount user receives + // Set up an order that sells 50 A tokens for at least 40 B tokens (creating + // slack) The solver will quote ~41-42 B tokens, leaving room for 2% haircut + let test_no_haircut = tests::setup() + .name("Sell order without haircut (baseline)") + .pool(ab_pool()) + .order( + ab_order() + .side(order::Side::Sell) + .kind(order::Kind::Limit) + .buy_amount(40u64.ether().into_wei()) // Set a limit to create slack + ) + .solution(ab_solution()) + .solvers(vec![tests::setup::test_solver().haircut_bps(0)]) // No haircut + .quote() + .done() + .await; + + let quote_no_haircut = test_no_haircut.quote().await; + let response_no_haircut = quote_no_haircut.ok(); + + let sell_amount = ab_order().sell_amount; + let buy_amount_no_haircut = extract_buy_amount(response_no_haircut.body(), sell_amount); + + // Now get a quote with 200 bps (2%) haircut + let test_with_haircut = tests::setup() + .name("Sell order with 200 bps (2%) haircut") + .pool(ab_pool()) + .order( + ab_order() + .side(order::Side::Sell) + .kind(order::Kind::Limit) + .buy_amount(40u64.ether().into_wei()) // Same limit to create slack + ) + .solution(ab_solution()) + .solvers(vec![tests::setup::test_solver().haircut_bps(200)]) // 2% haircut + .quote() + .done() + .await; + + let quote_with_haircut = test_with_haircut.quote().await; + let response_with_haircut = quote_with_haircut.ok(); + + let buy_amount_with_haircut = extract_buy_amount(response_with_haircut.body(), sell_amount); + + // Verify haircut was applied: haircutted amount should be ~2% less than + // baseline Expected: buy_amount_with_haircut ≈ buy_amount_no_haircut * 0.98 + let expected_haircutted = buy_amount_no_haircut * eth::U256::from(98) / eth::U256::from(100); + + // Calculate actual haircut in basis points for diagnostics + let ratio = buy_amount_with_haircut * eth::U256::from(10000) / buy_amount_no_haircut; + let haircut_bps = eth::U256::from(10000) - ratio; + + tracing::info!( + buy_amount_no_haircut = %buy_amount_no_haircut, + buy_amount_with_haircut = %buy_amount_with_haircut, + expected_haircutted = %expected_haircutted, + haircut_bps = %haircut_bps, + "Comparing buy amounts with and without haircut" + ); + + // The haircutted amount should be approximately 2% less (within 1% tolerance) + assert!( + buy_amount_with_haircut.is_approx_eq(&expected_haircutted, Some(0.01)), + "Haircutted amount {} should be approximately 2% less than baseline {} (expected: {}, \ + actual haircut: {} bps)", + buy_amount_with_haircut, + buy_amount_no_haircut, + expected_haircutted, + haircut_bps + ); +} diff --git a/crates/driver/src/tests/cases/settle.rs b/crates/driver/src/tests/cases/settle.rs index 7e05b486c9..0273694d0d 100644 --- a/crates/driver/src/tests/cases/settle.rs +++ b/crates/driver/src/tests/cases/settle.rs @@ -7,10 +7,10 @@ use { setup::{ab_order, ab_pool, ab_solution}, }, }, + alloy::providers::Provider, futures::future::join_all, itertools::Itertools, std::{sync::Arc, time::Duration}, - web3::Transport, }; /// Run a matrix of tests for all meaningful combinations of order kind and @@ -59,7 +59,7 @@ async fn solution_not_available() { } /// Checks that settlements with revert risk are not submitted via public -/// mempool. +/// mempool if at least 1 revert protected mempool exists. #[tokio::test] #[ignore] async fn private_rpc_with_high_risk_solution() { @@ -69,9 +69,10 @@ async fn private_rpc_with_high_risk_solution() { .order(ab_order()) .solution(ab_solution()) .mempools(vec![ - tests::setup::Mempool::Public, + tests::setup::Mempool::Default, tests::setup::Mempool::Private { url: Some("http://non-existant:8545".to_string()), + mines_reverting_txs: false, }, ]) .done() @@ -117,8 +118,8 @@ async fn submits_huge_solution() { // half of the block gas limit, we want it to be submitted/settled as long as it // fits in the block. test.web3() - .transport() - .execute("evm_setBlockGasLimit", vec![serde_json::json!(9_000_000)]) + .provider + .raw_request::<_, bool>("evm_setBlockGasLimit".into(), (9_000_000,)) .await .unwrap(); test.settle(id).await.ok().await; @@ -142,9 +143,15 @@ async fn does_not_bid_huge_solution() { test.solve().await.ok().empty(); } +/// Verifies the admission semaphore correctly limits in-flight settle requests +/// to `pool_slots + settle_queue_size` (default 1 + 2 = 3). We can submit as +/// many bids as we want as long as there is at least 1 settle queue spot +/// available, but once the queue is full, new /solve requests are rejected. +/// After the settlements complete, capacity is restored and new bids can be +/// submitted. #[tokio::test] #[ignore] -async fn discards_excess_settle_and_solve_requests() { +async fn settle_queue_capacity_is_respected() { let test = Arc::new( tests::setup() .allow_multiple_solve_requests() @@ -156,8 +163,9 @@ async fn discards_excess_settle_and_solve_requests() { .await, ); - // MAX_SOLUTION_STORAGE = 5. Since this is hardcoded, no more solutions can be - // stored. + // Admission permits are only consumed by /settle, not /solve, so we can + // generate as many bids as we want. MAX_SOLUTION_STORAGE = 5 is the only + // cap here. let solution_ids = join_all(vec![ test.solve(), test.solve(), @@ -173,142 +181,61 @@ async fn discards_excess_settle_and_solve_requests() { let unique_solutions_count = solution_ids.iter().unique().count(); assert_eq!(unique_solutions_count, solution_ids.len()); - // Disable auto mining to accumulate all the settlement requests. + // Disable auto mining so settlements block on confirmation. test.set_auto_mining(false).await; - // To avoid race conditions with the settlement queue processing, a - // `/settle` request needs to be sent first, so it is dequeued, and it's - // execution is paused before any subsequent request is received. - let test_clone = Arc::clone(&test); - let first_solution_id = solution_ids[0]; - let first_settlement_fut = - tokio::spawn(async move { test_clone.settle(first_solution_id).await }); - // Make sure the first settlement gets dequeued before sending the remaining - // requests. - tokio::time::sleep(Duration::from_millis(100)).await; - let remaining_solutions = solution_ids[1..].to_vec(); - let remaining_settlements = { + // Send settle requests one at a time so admission is deterministic. + // Admission capacity = 1 (pool slot) + 2 (settle_queue_size) = 3. + let mut settle_futs = Vec::new(); + for &id in &solution_ids { let test_clone = Arc::clone(&test); - remaining_solutions.into_iter().map(move |id| { - let test_clone = Arc::clone(&test_clone); - async move { test_clone.settle(id).await } - }) - }; - let remaining_settlements_fut = tokio::spawn(join_all(remaining_settlements)); + settle_futs.push(tokio::spawn(async move { test_clone.settle(id).await })); + tokio::time::sleep(Duration::from_millis(50)).await; + } - // Sleep for a bit to make sure all the settlement requests are queued. - tokio::time::sleep(Duration::from_millis(500)).await; + // Wait for all requests to be either in-flight or rejected. + tokio::time::sleep(Duration::from_millis(200)).await; - // While there is no room in the settlement queue, `/solve` requests must be - // rejected. + // While all admission slots are taken, /solve requests must be rejected. test.solve().await.err().kind("TooManyPendingSettlements"); // Enable auto mining to process all the settlement requests. + // *Note that processing the settlement requests will change the gas + // estimates!* test.set_auto_mining(true).await; - // The first settlement must be successful. - let first_settlement = first_settlement_fut.await.unwrap(); - first_settlement.ok().await.ab_order_executed(&test).await; - - let remaining_settlements = remaining_settlements_fut.await.unwrap(); - assert_eq!(remaining_settlements.len(), 4); - - for (idx, result) in remaining_settlements.into_iter().enumerate() { - match idx { - // The next 2 settlements failed to submit due to the framework's limitation(unable to - // fulfill the same order again). - 0 | 1 => result.err().kind("FailedToSubmit"), - // All the subsequent settlements rejected due to the settlement queue being full. - 2 | 3 => result.err().kind("TooManyPendingSettlements"), - _ => unreachable!(), - } - } - - // `/solve` works again. - test.solve().await.ok(); -} - -#[tokio::test] -#[ignore] -async fn accepts_new_settle_requests_after_timeout() { - let test = Arc::new( - tests::setup() - .allow_multiple_solve_requests() - .pool(ab_pool()) - .order(ab_order()) - .solution(ab_solution()) - .settle_submission_deadline(6) - .done() - .await, - ); - - // MAX_SOLUTION_STORAGE = 5. Since this is hardcoded, no more solutions can be - // stored. - let solution_ids = join_all(vec![ - test.solve(), - test.solve(), - test.solve(), - test.solve(), - test.solve(), - ]) - .await - .into_iter() - .map(|res| res.ok().id()) - .collect::>(); - - let unique_solutions_count = solution_ids.iter().unique().count(); - assert_eq!(unique_solutions_count, solution_ids.len()); - - // Disable auto mining to accumulate all the settlement requests. - test.set_auto_mining(false).await; - - // To avoid race conditions with the settlement queue processing, a - // `/settle` request needs to be sent first, so it is dequeued, and it's - // execution is paused before any subsequent request is received. - let test_clone = Arc::clone(&test); - let first_solution_id = solution_ids[0]; - let first_settlement_fut = - tokio::spawn(async move { test_clone.settle(first_solution_id).await }); - // Make sure the first settlement gets dequeued before sending the remaining - // requests. - tokio::time::sleep(Duration::from_millis(100)).await; - // Send only 3 more settle requests. - let additional_solutions = solution_ids[1..4].to_vec(); - let additional_settlements = { - let test_clone = Arc::clone(&test); - additional_solutions.into_iter().map(move |id| { - let test_clone = Arc::clone(&test_clone); - async move { test_clone.settle(id).await } - }) - }; - let additional_settlements_fut = tokio::spawn(join_all(additional_settlements)); - - // Sleep for a bit to make sure all the settlement requests are queued. - tokio::time::sleep(Duration::from_millis(500)).await; - test.set_auto_mining(true).await; + let results: Vec<_> = join_all(settle_futs) + .await + .into_iter() + .map(|r| r.unwrap()) + .collect(); - let first_settlement = first_settlement_fut.await.unwrap(); - // The first settlement must be successful. - first_settlement.ok().await.ab_order_executed(&test).await; + let mut results = results.into_iter(); - let additional_settlements = additional_settlements_fut.await.unwrap(); - assert_eq!(additional_settlements.len(), 3); + // The first settle should succeed on-chain. + results + .next() + .unwrap() + .ok() + .await + .ab_order_executed(&test) + .await; - for (idx, result) in additional_settlements.into_iter().enumerate() { + for (idx, result) in results.enumerate() { match idx { - // The next 2 settlements failed to submit due to the framework's limitation(unable to - // fulfill the same order again). + // Admitted but can't fulfill the same order again. 0 | 1 => result.err().kind("FailedToSubmit"), - // The next request gets rejected due to the settlement queue being full. - 2 => result.err().kind("TooManyPendingSettlements"), + // Rejected by the admission semaphore. + 2 | 3 => result.err().kind("TooManyPendingSettlements"), _ => unreachable!(), } } - // Now we send the last settlement request. It fails due to the framework's - // limitation(unable to fulfill the same order again). - test.settle(solution_ids[4]) + // Capacity is restored — settle works again. Use an existing solution ID + // (it was already removed from cache by the first settle, so this returns + // SolutionNotAvailable — but it proves admission doesn't reject). + test.settle(solution_ids[0]) .await .err() - .kind("FailedToSubmit"); + .kind("SolutionNotAvailable"); } diff --git a/crates/driver/src/tests/cases/solver_balance.rs b/crates/driver/src/tests/cases/solver_balance.rs index 2802327467..f4f3d2d2a9 100644 --- a/crates/driver/src/tests/cases/solver_balance.rs +++ b/crates/driver/src/tests/cases/solver_balance.rs @@ -1,9 +1,9 @@ -use crate::{ - domain::eth, - tests::{ +use { + crate::tests::{ setup, setup::{ab_order, ab_pool, ab_solution, test_solver}, }, + eth_domain_types as eth, }; /// Test that the `/solve` request errors when solver balance is too low. @@ -15,7 +15,7 @@ async fn test_unfunded() { .order(ab_order()) .solution(ab_solution()) .solvers(vec![ - test_solver().name("unfunded").balance(eth::U256::zero()), + test_solver().name("unfunded").balance(eth::U256::ZERO), ]) .done() .await; @@ -38,7 +38,7 @@ async fn test_just_enough_funded() { .name("barely_funded") // The solution uses ~500k gas units // With gas costs <20gwei, 0.01 ETH should suffice - .balance(eth::U256::exp10(16)), + .balance(eth::U256::from(10).pow(eth::U256::from(16))), ]) .done() .await; diff --git a/crates/driver/src/tests/mod.rs b/crates/driver/src/tests/mod.rs index 80718b9ed7..792e663a48 100644 --- a/crates/driver/src/tests/mod.rs +++ b/crates/driver/src/tests/mod.rs @@ -3,7 +3,3 @@ mod cases; mod setup; pub use setup::setup; - -fn hex_address(value: ethcontract::H160) -> String { - const_hex::encode_prefixed(value.as_bytes()) -} diff --git a/crates/driver/src/tests/setup/blockchain.rs b/crates/driver/src/tests/setup/blockchain.rs index 615d2413b8..c90e6f20f2 100644 --- a/crates/driver/src/tests/setup/blockchain.rs +++ b/crates/driver/src/tests/setup/blockchain.rs @@ -1,15 +1,17 @@ use { super::{Asset, Order, Partial}, crate::{ - domain::{competition::order, eth}, + domain::competition::order, tests::{self, boundary, cases::EtherExt}, }, alloy::{ primitives::{Address, U256}, + providers::{Provider, ext::AnvilApi}, + rpc::types::TransactionRequest, signers::local::{MnemonicBuilder, PrivateKeySigner}, sol_types::SolCall, }, - contracts::alloy::{ + contracts::{ BalancerV2Authorizer, BalancerV2Vault, ERC20, @@ -20,20 +22,14 @@ use { WETH9, support::{Balances, Signatures}, }, - ethcontract::PrivateKey, + eth_domain_types as eth, ethrpc::{ Web3, - alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + alloy::{CallBuilderExt, EvmProviderExt, ProviderExt}, }, futures::Future, - secp256k1::SecretKey, - serde_json::json, solvers_dto::solution::Flashloan, std::collections::HashMap, - web3::{Transport, signing::Key}, }; // TODO Possibly might be a good idea to use an enum for tokens instead of // &'static str @@ -42,13 +38,13 @@ use { pub struct Pair { token_a: &'static str, token_b: &'static str, - contract: contracts::alloy::IUniswapLikePair::Instance, + contract: contracts::IUniswapLikePair::Instance, pool: Pool, } #[derive(Debug)] pub struct Blockchain { - pub trader_secret_key: SecretKey, + pub trader_secret_key: PrivateKeySigner, pub web3: Web3, pub web3_url: String, pub web3_ws_url: String, @@ -70,7 +66,7 @@ pub struct Blockchain { #[derive(Debug, Clone, PartialEq)] pub struct Interaction { - pub address: ethcontract::H160, + pub address: eth::Address, pub calldata: Vec, pub inputs: Vec, pub outputs: Vec, @@ -108,7 +104,7 @@ impl Pool { ((input_reserve * output.amount * eth::U256::from(1000)) / ((output_reserve - output.amount) * eth::U256::from(997))) - + 1 + + eth::U256::ONE } } @@ -116,6 +112,7 @@ impl Pool { pub struct Solution { pub trades: Vec, pub flashloans: HashMap, + pub gas_fee_override: Option<(u128, u128)>, } #[derive(Debug, Clone)] @@ -177,13 +174,13 @@ impl QuotedOrder { /// The UID of the order. pub fn order_uid(&self, blockchain: &Blockchain) -> tests::boundary::OrderUid { - self.boundary(blockchain, blockchain.trader_secret_key) + self.boundary(blockchain, blockchain.trader_secret_key.clone()) .uid() } /// The signature of the order. pub fn order_signature(&self, blockchain: &Blockchain) -> Vec { - self.boundary(blockchain, blockchain.trader_secret_key) + self.boundary(blockchain, blockchain.trader_secret_key.clone()) .signature() } @@ -191,24 +188,29 @@ impl QuotedOrder { pub fn order_signature_with_private_key( &self, blockchain: &Blockchain, - private_key: &PrivateKey, + signer: PrivateKeySigner, ) -> Vec { - self.boundary(blockchain, **private_key).signature() + self.boundary(blockchain, signer).signature() } - fn boundary(&self, blockchain: &Blockchain, secret_key: SecretKey) -> tests::boundary::Order { + fn boundary( + &self, + blockchain: &Blockchain, + signer: PrivateKeySigner, + ) -> tests::boundary::Order { + let owner = signer.address(); tests::boundary::Order { - sell_token: blockchain.get_token(self.order.sell_token).into_legacy(), - buy_token: blockchain.get_token(self.order.buy_token).into_legacy(), + sell_token: blockchain.get_token(self.order.sell_token), + buy_token: blockchain.get_token(self.order.buy_token), sell_amount: self.sell_amount(), buy_amount: self.buy_amount(), valid_to: self.order.valid_to, receiver: self.order.receiver, user_fee: self.order.fee_amount, side: self.order.side, - secret_key, + secret_key: signer, domain_separator: blockchain.domain_separator, - owner: (&secret_key).address(), + owner, partially_fillable: matches!(self.order.partial, Partial::Yes { .. }), } } @@ -217,11 +219,11 @@ impl QuotedOrder { pub struct Config { pub pools: Vec, // Main trader secret key (the account deploying the contracts) - pub main_trader_secret_key: SecretKey, + pub main_trader_secret_key: PrivateKeySigner, pub solvers: Vec, - pub settlement_address: Option, - pub balances_address: Option, - pub signatures_address: Option, + pub settlement_address: Option, + pub balances_address: Option, + pub signatures_address: Option, pub rpc_args: Vec, } @@ -236,86 +238,80 @@ impl Blockchain { let node = Node::new(&config.rpc_args).await; let web3 = Web3::new_from_url(&node.url()); - let private_key = config.main_trader_secret_key.as_ref(); - let main_trader_account = ethcontract::Account::Offline( - ethcontract::PrivateKey::from_slice(private_key).unwrap(), - None, - ); - let signer = PrivateKeySigner::from_slice(private_key).unwrap(); - web3.wallet.register_signer(signer); - // This account is equivalent to `primary_account`, but due to the wallet + let main_trader_address = config.main_trader_secret_key.address(); + web3.wallet + .register_signer(config.main_trader_secret_key.clone()); + // This account is equivalent to the first test account, but due to the wallet // initialization process and the fact that we launch anvil manually, we need to // add it ourselves. // It also must be added after the main_trader because otherwise this will be // used as the default signing account - let anvil_test_account = MnemonicBuilder::english() + let primary_account = MnemonicBuilder::english() .phrase("test test test test test test test test test test test junk") .index(0) .unwrap() .build() .unwrap(); - web3.wallet.register_signer(anvil_test_account); - - let primary_account = primary_account(&web3).await; let primary_address = primary_account.address(); + web3.wallet.register_signer(primary_account); // Use the primary account to fund the trader, cow amm and the solver with ETH. - let balance = web3.eth().balance(primary_address, None).await.unwrap(); + let balance = web3.provider.get_balance(primary_address).await.unwrap(); wait_for( &web3, - web3.eth() - .send_transaction(web3::types::TransactionRequest { - from: primary_address, - to: Some(main_trader_account.address()), - value: Some(balance / 5), - ..Default::default() - }), + web3.provider.send_and_watch( + TransactionRequest::default() + .from(primary_address) + .to(main_trader_address) + .value(balance / alloy::primitives::U256::from(5)), + ), ) .await .unwrap(); - let weth = contracts::alloy::WETH9::Instance::deploy_builder(web3.alloy.clone()) - .from(main_trader_account.address().into_alloy()) + let weth = contracts::WETH9::Instance::deploy_builder(web3.provider.clone()) + .from(main_trader_address) .deploy() .await .unwrap(); - let weth = WETH9::WETH9::new(weth, web3.alloy.clone()); + let weth = WETH9::WETH9::new(weth, web3.provider.clone()); wait_for( &web3, - ethcontract::transaction::TransactionBuilder::new(web3.legacy.clone()) - .from(primary_account) - .to(weth.address().into_legacy()) - .value(balance / 5) - .send(), + web3.provider.send_and_watch( + TransactionRequest::default() + .from(primary_address) + .to(*weth.address()) + .value(balance / alloy::primitives::U256::from(5)), + ), ) .await .unwrap(); // Set up the settlement contract and related contracts. let vault_authorizer = BalancerV2Authorizer::Instance::deploy_builder( - web3.alloy.clone(), - main_trader_account.address().into_alloy(), + web3.provider.clone(), + main_trader_address, ) - .from(main_trader_account.address().into_alloy()) + .from(main_trader_address) .deploy() .await .unwrap(); let vault = BalancerV2Vault::Instance::deploy_builder( - web3.alloy.clone(), + web3.provider.clone(), vault_authorizer, *weth.address(), alloy::primitives::U256::ZERO, alloy::primitives::U256::ZERO, ) - .from(main_trader_account.address().into_alloy()) + .from(main_trader_address) .deploy() .await .unwrap(); - let authenticator = GPv2AllowListAuthentication::deploy(web3.alloy.clone()) + let authenticator = GPv2AllowListAuthentication::deploy(web3.provider.clone()) .await .unwrap(); let mut settlement = GPv2Settlement::GPv2Settlement::deploy( - web3.alloy.clone(), + web3.provider.clone(), *authenticator.address(), vault, ) @@ -327,103 +323,100 @@ impl Blockchain { // replace the vault relayer code to allow the settlement // contract at a specific address. let mut code = web3 - .eth() - .code(vault_relayer.into_legacy(), None) + .provider + .get_code_at(vault_relayer) .await .unwrap() - .0; + .to_vec(); + for i in 0..code.len() - 20 { let window = &mut code[i..][..20]; if window == settlement.address().as_slice() { - window.copy_from_slice(&settlement_address.0); + window.copy_from_slice(settlement_address.as_slice()); } } code }; - let settlement_code = web3 - .eth() - .code(settlement.address().into_legacy(), None) + web3.provider + .anvil_set_code(vault_relayer, vault_relayer_code.into()) .await - .unwrap() - .0; + .unwrap(); - set_code(&web3, vault_relayer.into_legacy(), &vault_relayer_code).await; - set_code(&web3, settlement_address, &settlement_code).await; + // Note: (settlement.address() == authenticator_address) != settlement_address + let settlement_code = web3 + .provider + .get_code_at(*settlement.address()) + .await + .unwrap(); + web3.provider + .anvil_set_code(settlement_address, settlement_code) + .await + .unwrap(); - settlement = GPv2Settlement::GPv2Settlement::new( - settlement_address.into_alloy(), - web3.alloy.clone(), - ); + settlement = + GPv2Settlement::GPv2Settlement::new(settlement_address, web3.provider.clone()); } let balances_address = match config.balances_address { - Some(balances_address) => balances_address.into_alloy(), - None => Balances::Instance::deploy_builder(web3.alloy.clone()) - .from(main_trader_account.address().into_alloy()) + Some(balances_address) => balances_address, + None => Balances::Instance::deploy_builder(web3.provider.clone()) + .from(main_trader_address) .deploy() .await .unwrap(), }; - let balances = Balances::Instance::new(balances_address, web3.alloy.clone()); + let balances = Balances::Instance::new(balances_address, web3.provider.clone()); authenticator - .initializeManager(main_trader_account.address().into_alloy()) - .from(main_trader_account.address().into_alloy()) + .initializeManager(main_trader_address) + .from(main_trader_address) .send_and_watch() .await .unwrap(); let signatures_address = if let Some(signatures_address) = config.signatures_address { - signatures_address.into_alloy() + signatures_address } else { - Signatures::Instance::deploy_builder(web3.alloy.clone()) - .from(main_trader_account.address().into_alloy()) + Signatures::Instance::deploy_builder(web3.provider.clone()) + .from(main_trader_address) .deploy() .await .unwrap() }; - let signatures = Signatures::Instance::new(signatures_address, web3.alloy.clone()); + let signatures = Signatures::Instance::new(signatures_address, web3.provider.clone()); let flashloan_router_address = - FlashLoanRouter::Instance::deploy_builder(web3.alloy.clone(), *settlement.address()) - .from(main_trader_account.address().into_alloy()) + FlashLoanRouter::Instance::deploy_builder(web3.provider.clone(), *settlement.address()) + .from(main_trader_address) .deploy() .await .unwrap(); let flashloan_router = - FlashLoanRouter::Instance::new(flashloan_router_address, web3.alloy.clone()); + FlashLoanRouter::Instance::new(flashloan_router_address, web3.provider.clone()); - let mut trader_accounts = Vec::new(); + let mut trader_addresses: Vec
= Vec::new(); for config in config.solvers { authenticator - .addSolver(config.address().into_alloy()) - .from(main_trader_account.address().into_alloy()) + .addSolver(config.address()) + .from(main_trader_address) .send_and_watch() .await .unwrap(); wait_for( &web3, - web3.eth() - .send_transaction(web3::types::TransactionRequest { - from: primary_address, - to: Some(config.address()), - value: Some(config.balance), - ..Default::default() - }), + web3.provider.send_and_watch( + TransactionRequest::default() + .from(primary_address) + .to(config.address()) + .value(config.balance), + ), ) .await .unwrap(); if !config.balance.is_zero() { - let private_key = config.private_key.as_ref(); - let signer = PrivateKeySigner::from_slice(private_key).unwrap(); - web3.wallet.register_signer(signer); - - let trader_account = ethcontract::Account::Offline( - ethcontract::PrivateKey::from_slice(private_key).unwrap(), - None, - ); - trader_accounts.push(trader_account); + trader_addresses.push(config.signer.address()); + web3.wallet.register_signer(config.signer); } } @@ -434,29 +427,29 @@ impl Blockchain { let mut tokens = HashMap::new(); for pool in config.pools.iter() { if pool.reserve_a.token != "WETH" && !tokens.contains_key(pool.reserve_a.token) { - let token = ERC20Mintable::Instance::deploy(web3.alloy.clone()) + let token = ERC20Mintable::Instance::deploy(web3.provider.clone()) .await .unwrap(); tokens.insert(pool.reserve_a.token, token); } if pool.reserve_b.token != "WETH" && !tokens.contains_key(pool.reserve_b.token) { - let token = ERC20Mintable::Instance::deploy(web3.alloy.clone()) + let token = ERC20Mintable::Instance::deploy(web3.provider.clone()) .await .unwrap(); tokens.insert(pool.reserve_b.token, token); } } // Create the uniswap factory. - let contract_address = contracts::alloy::UniswapV2Factory::Instance::deploy_builder( - web3.alloy.clone(), - main_trader_account.address().into_alloy(), + let contract_address = contracts::UniswapV2Factory::Instance::deploy_builder( + web3.provider.clone(), + main_trader_address, ) - .from(main_trader_account.address().into_alloy()) + .from(main_trader_address) .deploy() .await .unwrap(); let uniswap_factory = - contracts::alloy::UniswapV2Factory::Instance::new(contract_address, web3.alloy.clone()); + contracts::UniswapV2Factory::Instance::new(contract_address, web3.provider.clone()); // Create and fund a uniswap pair for each pool. Fund the settlement contract // with the same liquidity as the pool, to allow for internalized interactions. let mut pairs = Vec::new(); @@ -475,18 +468,18 @@ impl Blockchain { // Create the pair. uniswap_factory .createPair(token_a, token_b) - .from(main_trader_account.address().into_alloy()) + .from(main_trader_address) .send_and_watch() .await .unwrap(); // Fund the pair and the settlement contract. - let pair = contracts::alloy::IUniswapLikePair::Instance::new( + let pair = contracts::IUniswapLikePair::Instance::new( uniswap_factory .getPair(token_a, token_b) .call() .await .unwrap(), - web3.alloy.clone(), + web3.provider.clone(), ); pairs.push(Pair { token_a: pool.reserve_a.token, @@ -495,35 +488,32 @@ impl Blockchain { pool: pool.to_owned(), }); if pool.reserve_a.token == "WETH" { - weth.transfer(*pair.address(), pool.reserve_a.amount.into_alloy()) - .from(primary_address.into_alloy()) + weth.transfer(*pair.address(), pool.reserve_a.amount) + .from(primary_address) .send_and_watch() .await .unwrap(); - weth.transfer(*settlement.address(), pool.reserve_a.amount.into_alloy()) - .from(primary_address.into_alloy()) - .send_and_watch() - .await - .unwrap(); - for trader_account in trader_accounts.iter() { - weth.transfer( - trader_account.address().into_alloy(), - pool.reserve_a.amount.into_alloy(), - ) - .from(primary_address.into_alloy()) + weth.transfer(*settlement.address(), pool.reserve_a.amount) + .from(primary_address) .send_and_watch() .await .unwrap(); + for trader_address in trader_addresses.iter().copied() { + weth.transfer(trader_address, pool.reserve_a.amount) + .from(primary_address) + .send_and_watch() + .await + .unwrap(); } } else { - for trader_account in trader_accounts.iter() { + for trader_address in trader_addresses.iter().copied() { let vault_relayer = settlement.vaultRelayer().call().await.unwrap(); tokens .get(pool.reserve_a.token) .unwrap() .approve(vault_relayer, U256::MAX) - .from(trader_account.address().into_alloy()) + .from(trader_address) .send_and_watch() .await .unwrap(); @@ -532,8 +522,8 @@ impl Blockchain { tokens .get(pool.reserve_a.token) .unwrap() - .mint(*pair.address(), pool.reserve_a.amount.into_alloy()) - .from(main_trader_account.address().into_alloy()) + .mint(*pair.address(), pool.reserve_a.amount) + .from(main_trader_address) .send_and_watch() .await .unwrap(); @@ -541,56 +531,50 @@ impl Blockchain { tokens .get(pool.reserve_a.token) .unwrap() - .mint(*settlement.address(), pool.reserve_a.amount.into_alloy()) - .from(main_trader_account.address().into_alloy()) + .mint(*settlement.address(), pool.reserve_a.amount) + .from(main_trader_address) .send_and_watch() .await .unwrap(); - for trader_account in trader_accounts.iter() { + for trader_address in trader_addresses.iter().copied() { tokens .get(pool.reserve_a.token) .unwrap() - .mint( - trader_account.address().into_alloy(), - pool.reserve_a.amount.into_alloy(), - ) - .from(main_trader_account.address().into_alloy()) + .mint(trader_address, pool.reserve_a.amount) + .from(main_trader_address) .send_and_watch() .await .unwrap(); } } if pool.reserve_b.token == "WETH" { - weth.transfer(*pair.address(), pool.reserve_b.amount.into_alloy()) - .from(primary_address.into_alloy()) + weth.transfer(*pair.address(), pool.reserve_b.amount) + .from(primary_address) .send_and_watch() .await .unwrap(); - weth.transfer(*settlement.address(), pool.reserve_b.amount.into_alloy()) - .from(primary_address.into_alloy()) - .send_and_watch() - .await - .unwrap(); - for trader_account in trader_accounts.iter() { - weth.transfer( - trader_account.address().into_alloy(), - pool.reserve_b.amount.into_alloy(), - ) - .from(primary_address.into_alloy()) + weth.transfer(*settlement.address(), pool.reserve_b.amount) + .from(primary_address) .send_and_watch() .await .unwrap(); + for trader_address in trader_addresses.iter().copied() { + weth.transfer(trader_address, pool.reserve_b.amount) + .from(primary_address) + .send_and_watch() + .await + .unwrap(); } } else { - for trader_account in trader_accounts.iter() { + for trader_address in trader_addresses.iter().copied() { let vault_relayer = settlement.vaultRelayer().call().await.unwrap(); tokens .get(pool.reserve_b.token) .unwrap() .approve(vault_relayer, U256::MAX) - .from(trader_account.address().into_alloy()) + .from(trader_address) .send_and_watch() .await .unwrap(); @@ -599,8 +583,8 @@ impl Blockchain { tokens .get(pool.reserve_b.token) .unwrap() - .mint(*pair.address(), pool.reserve_b.amount.into_alloy()) - .from(main_trader_account.address().into_alloy()) + .mint(*pair.address(), pool.reserve_b.amount) + .from(main_trader_address) .send_and_watch() .await .unwrap(); @@ -608,20 +592,17 @@ impl Blockchain { tokens .get(pool.reserve_b.token) .unwrap() - .mint(*settlement.address(), pool.reserve_b.amount.into_alloy()) - .from(main_trader_account.address().into_alloy()) + .mint(*settlement.address(), pool.reserve_b.amount) + .from(main_trader_address) .send_and_watch() .await .unwrap(); - for trader_account in trader_accounts.iter() { + for trader_address in trader_addresses.iter().copied() { tokens .get(pool.reserve_b.token) .unwrap() - .mint( - trader_account.address().into_alloy(), - pool.reserve_b.amount.into_alloy(), - ) - .from(main_trader_account.address().into_alloy()) + .mint(trader_address, pool.reserve_b.amount) + .from(main_trader_address) .send_and_watch() .await .unwrap(); @@ -630,7 +611,7 @@ impl Blockchain { pair.mint(::alloy::primitives::address!( "0x8270bA71b28CF60859B547A2346aCDE824D6ed40" )) - .from(main_trader_account.address().into_alloy()) + .from(main_trader_address) .send_and_watch() .await .unwrap(); @@ -756,31 +737,30 @@ impl Blockchain { // Find the pair to use for this order and calculate the buy and sell amounts. let sell_token = ERC20::Instance::new( self.get_token_wrapped(order.sell_token), - self.web3.alloy.clone(), + self.web3.provider.clone(), ); let buy_token = ERC20::Instance::new( self.get_token_wrapped(order.buy_token), - self.web3.alloy.clone(), + self.web3.provider.clone(), ); let pair = self.find_pair(order); let execution = self.execution(order); + // Register the trader account as a signer + let trader_address = self.trader_secret_key.address(); + self.web3 + .wallet + .register_signer(self.trader_secret_key.clone()); + // Fund the trader account with tokens needed for the solution. - let trader_account = ethcontract::Account::Offline( - ethcontract::PrivateKey::from_slice(self.trader_secret_key.as_ref()).unwrap(), - None, - ); if order.sell_token == "WETH" { todo!("deposit trader funds into the weth contract, none of the tests do this yet") } else if order.funded { self.tokens .get(order.sell_token) .unwrap() - .mint( - trader_account.address().into_alloy(), - ("1e-7".ether().into_wei() * execution.sell).into_alloy(), - ) - .from(trader_account.address().into_alloy()) + .mint(trader_address, "1e-7".ether().into_wei() * execution.sell) + .from(trader_address) .send_and_watch() .await .unwrap(); @@ -793,7 +773,7 @@ impl Blockchain { .get(order.sell_token) .unwrap() .approve(vault_relayer, U256::MAX) - .from(trader_account.address().into_alloy()) + .from(trader_address) .send_and_watch() .await .unwrap(); @@ -801,14 +781,14 @@ impl Blockchain { // Create the interactions fulfilling the order. let transfer_interaction = ERC20::ERC20::transferCall { recipient: *pair.contract.address(), - amount: execution.sell.into_alloy(), + amount: execution.sell, } .abi_encode(); let (amount_a_out, amount_b_out) = if pair.token_a == order.sell_token { - (0.into(), execution.buy) + (eth::U256::ZERO, execution.buy) } else { // Surplus fees stay in the contract. - (execution.sell - order.surplus_fee(), 0.into()) + (execution.sell - order.surplus_fee(), eth::U256::ZERO) }; let (amount_0_out, amount_1_out) = if self.get_token(pair.token_a) < self.get_token(pair.token_b) { @@ -819,8 +799,8 @@ impl Blockchain { let swap_interaction = pair .contract .swap( - amount_0_out.into_alloy(), - amount_1_out.into_alloy(), + amount_0_out, + amount_1_out, *self.settlement.address(), Default::default(), ) @@ -831,7 +811,7 @@ impl Blockchain { execution: execution.clone(), interactions: vec![ Interaction { - address: sell_token.address().into_legacy(), + address: *sell_token.address(), calldata: match solution.calldata { super::Calldata::Valid { additional_bytes } => transfer_interaction .into_iter() @@ -844,7 +824,7 @@ impl Blockchain { internalize: false, }, Interaction { - address: pair.contract.address().into_legacy(), + address: *pair.contract.address(), calldata: match solution.calldata { super::Calldata::Valid { .. } => swap_interaction, super::Calldata::Invalid => { @@ -852,12 +832,12 @@ impl Blockchain { } }, inputs: vec![eth::Asset { - token: sell_token.address().into_legacy().into(), + token: (*sell_token.address()).into(), // Surplus fees stay in the contract. amount: (execution.sell - order.surplus_fee()).into(), }], outputs: vec![eth::Asset { - token: buy_token.address().into_legacy().into(), + token: (*buy_token.address()).into(), amount: execution.buy.into(), }], internalize: order.internalize, @@ -872,7 +852,7 @@ impl Blockchain { pub fn get_token(&self, token: &str) -> Address { match token { "WETH" => *self.weth.address(), - "ETH" => eth::ETH_TOKEN.0.0.into_alloy(), + "ETH" => *eth::ETH_TOKEN, _ => *self.tokens.get(token).unwrap().address(), } } @@ -887,18 +867,10 @@ impl Blockchain { } pub async fn set_auto_mining(&self, enabled: bool) { - self.web3 - .transport() - .execute("evm_setAutomine", vec![json!(enabled)]) - .await - .unwrap(); + self.web3.provider.evm_set_automine(enabled).await.unwrap(); } } -async fn primary_account(web3: &Web3) -> ethcontract::Account { - ethcontract::Account::Local(web3.eth().accounts().await.unwrap()[0], None) -} - /// A blockchain node for development purposes. Dropping this type will /// terminate the node. pub struct Node { @@ -994,7 +966,7 @@ impl Drop for Node { /// wait for transactions to be confirmed before proceeding with the test. When /// switching from geth back to hardhat, this function can be removed. pub async fn wait_for(web3: &Web3, fut: impl Future) -> T { - let block = web3.eth().block_number().await.unwrap().as_u64(); + let block = web3.provider.get_block_number().await.unwrap(); let result = fut.await; wait_for_block(web3, block + 1).await; result @@ -1004,7 +976,7 @@ pub async fn wait_for(web3: &Web3, fut: impl Future) -> T { pub async fn wait_for_block(web3: &Web3, block: u64) { tokio::time::timeout(std::time::Duration::from_secs(15), async { loop { - let next_block = web3.eth().block_number().await.unwrap().as_u64(); + let next_block = web3.provider.get_block_number().await.unwrap(); if next_block >= block { break; } @@ -1014,16 +986,3 @@ pub async fn wait_for_block(web3: &Web3, block: u64) { .await .expect("timeout while waiting for next block to be mined"); } - -/// Sets code at a specific address for testing. -pub async fn set_code(web3: &Web3, address: eth::H160, code: &[u8]) { - use web3::Transport; - - web3.transport() - .execute( - "anvil_setCode", - vec![json!(address), json!(const_hex::encode_prefixed(code))], - ) - .await - .unwrap(); -} diff --git a/crates/driver/src/tests/setup/driver.rs b/crates/driver/src/tests/setup/driver.rs index f32085f389..099a7f7037 100644 --- a/crates/driver/src/tests/setup/driver.rs +++ b/crates/driver/src/tests/setup/driver.rs @@ -3,13 +3,9 @@ use { crate::{ domain::competition::order, infra::config::file::OrderPriorityStrategy, - tests::{ - hex_address, - setup::{blockchain::Trade, orderbook::Orderbook}, - }, + tests::setup::{blockchain::Trade, orderbook::Orderbook}, }, const_hex::ToHexExt, - ethrpc::alloy::conversions::IntoLegacy, rand::seq::SliceRandom, serde_json::json, std::{io::Write, net::SocketAddr, path::PathBuf}, @@ -24,6 +20,7 @@ pub struct Config { pub mempools: Vec, pub order_priority_strategies: Vec, pub orderbook: Orderbook, + pub flashloans_enabled: bool, } pub struct Driver { @@ -73,7 +70,7 @@ pub fn solve_req(test: &Test) -> serde_json::Value { // The orders are shuffled before being sent to the driver, to ensure that the // driver sorts them correctly before forwarding them to the solver. let mut quotes = test.quoted_orders.clone(); - quotes.shuffle(&mut rand::thread_rng()); + quotes.shuffle(&mut rand::rng()); for quote in quotes.iter() { let mut order = json!({ "uid": quote.order_uid(&test.blockchain), @@ -99,7 +96,7 @@ pub fn solve_req(test: &Test) -> serde_json::Value { order::Side::Sell => "sell", order::Side::Buy => "buy", }, - "owner": hex_address(test.trader_address), + "owner": (test.trader_address.encode_hex_with_prefix()), "partiallyFillable": matches!(quote.order.partial, Partial::Yes { .. }), "executed": match quote.order.partial { Partial::Yes { executed } => executed.to_string(), @@ -117,7 +114,7 @@ pub fn solve_req(test: &Test) -> serde_json::Value { "quote": quote.order.quote, }); if let Some(receiver) = quote.order.receiver { - order["receiver"] = json!(hex_address(receiver)); + order["receiver"] = json!((receiver.encode_hex_with_prefix())); } orders_json.push(order); } @@ -223,7 +220,7 @@ async fn create_config_file( config.orderbook.addr ) .unwrap(); - writeln!(file, "flashloans-enabled = true").unwrap(); + writeln!(file, "flashloans-enabled = {}", config.flashloans_enabled).unwrap(); writeln!(file, "tx-gas-limit = \"45000000\"").unwrap(); write!( file, @@ -241,34 +238,34 @@ async fn create_config_file( blockchain.weth.address(), blockchain.balances.address(), blockchain.signatures.address(), - hex_address(blockchain.flashloan_router.address().into_legacy()), + blockchain.flashloan_router.address(), ) .unwrap(); for mempool in &config.mempools { match mempool { - Mempool::Public => { - write!( - file, - r#"[[submission.mempool]] - mempool = "public" + Mempool::Default => write!( + file, + r#"[[submission.mempool]] + url = "{}" additional-tip-percentage = 0.0 "#, - ) - .unwrap(); - } - Mempool::Private { url } => { - write!( - file, - r#"[[submission.mempool]] - mempool = "mev-blocker" - additional-tip-percentage = 0.0 + blockchain.web3_url, + ) + .unwrap(), + Mempool::Private { + url, + mines_reverting_txs, + } => write!( + file, + r#"[[submission.mempool]] url = "{}" + additional-tip-percentage = 0.0 + mines-reverting-txs = {mines_reverting_txs} "#, - url.clone().unwrap_or(blockchain.web3_url.clone()), - ) - .unwrap(); - } + url.clone().unwrap_or(blockchain.web3_url.clone()), + ) + .unwrap(), } } @@ -318,11 +315,13 @@ async fn create_config_file( endpoint = "http://{}" absolute-slippage = "{}" relative-slippage = "{}" - account = "0x{}" + account = "{}" solving-share-of-deadline = {} http-time-buffer = "{}ms" fee-handler = {} merge-solutions = {} + haircut-bps = {} + max-solutions-to-propose = {} "#, solver.name, addr, @@ -332,13 +331,24 @@ async fn create_config_file( .map(|abs| abs.0) .unwrap_or_default(), solver.slippage.relative, - const_hex::encode(solver.private_key.secret_bytes()), + solver.signer.to_bytes(), solver.timeouts.solving_share_of_deadline.get(), solver.timeouts.http_delay.num_milliseconds(), serde_json::to_string(&solver.fee_handler).unwrap(), solver.merge_solutions, + solver.haircut_bps, + solver.max_solutions_to_propose, ) .unwrap(); + if !solver.submission_accounts.is_empty() { + let accounts = solver + .submission_accounts + .iter() + .map(|a| format!("\"{}\"", a.to_bytes())) + .collect::>() + .join(", "); + writeln!(file, " submission-accounts = [{accounts}]").unwrap(); + } } file.into_temp_path() } diff --git a/crates/driver/src/tests/setup/fee.rs b/crates/driver/src/tests/setup/fee.rs index 384f2240f1..5a7a90d298 100644 --- a/crates/driver/src/tests/setup/fee.rs +++ b/crates/driver/src/tests/setup/fee.rs @@ -1,5 +1,5 @@ use { - crate::domain::eth, + eth_domain_types as eth, number::serialization::HexOrDecimalU256, serde_json::json, serde_with::serde_as, @@ -19,7 +19,7 @@ pub struct Quote { /// additional sell amount. #[serde_as(as = "HexOrDecimalU256")] pub network_fee: eth::U256, - pub solver: eth::H160, + pub solver: eth::Address, } #[serde_as] diff --git a/crates/driver/src/tests/setup/mod.rs b/crates/driver/src/tests/setup/mod.rs index 2e751dfc4e..2180cddae6 100644 --- a/crates/driver/src/tests/setup/mod.rs +++ b/crates/driver/src/tests/setup/mod.rs @@ -5,7 +5,6 @@ use { crate::{ domain::{ competition::order::{self, app_data::AppData}, - eth, time, }, infra::{ @@ -29,7 +28,6 @@ use { DEFAULT_SURPLUS_FACTOR, ETH_ORDER_AMOUNT, EtherExt, - is_approximately_equal, }, setup::{ blockchain::{Blockchain, Interaction, Trade}, @@ -37,16 +35,18 @@ use { }, }, }, - alloy::primitives::Address, + alloy::{ + primitives::{Address, U256, address, b256}, + providers::Provider, + signers::local::PrivateKeySigner, + }, + axum::http::StatusCode, bigdecimal::{BigDecimal, FromPrimitive}, - ethcontract::dyns::DynTransport, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + eth_domain_types as eth, + ethrpc::Web3, futures::future::join_all, - hyper::StatusCode, model::order::{BuyTokenDestination, SellTokenSource}, - number::serialization::HexOrDecimalU256, - primitive_types::H160, - secp256k1::SecretKey, + number::{serialization::HexOrDecimalU256, testing::ApproxEq}, serde::{Deserialize, de::IntoDeserializer}, serde_with::serde_as, solvers_dto::solution::Flashloan, @@ -142,8 +142,8 @@ pub struct Order { /// order? True by default. pub funded: bool, pub fee_policy: Vec, - pub owner: H160, - pub receiver: Option, + pub owner: eth::Address, + pub receiver: Option, pub fee_amount: eth::U256, pub sell_token_source: SellTokenSource, pub buy_token_destination: BuyTokenDestination, @@ -178,7 +178,7 @@ impl Order { /// has a negative score. pub fn no_surplus(self) -> Self { Self { - surplus_factor: 1.into(), + surplus_factor: U256::ONE, ..self } } @@ -297,11 +297,11 @@ impl Order { fn surplus_fee(&self) -> eth::U256 { match self.kind { order::Kind::Limit => self.solver_fee.unwrap_or_default(), - _ => 0.into(), + _ => eth::U256::ZERO, } } - pub fn receiver(self, receiver: Option) -> Self { + pub fn receiver(self, receiver: Option) -> Self { Self { receiver, ..self } } } @@ -330,7 +330,7 @@ impl Default for Order { factor: 0.0, max_volume_factor: 0.06, }], - owner: eth::H160::from_str(TRADER_ADDRESS).unwrap(), + owner: TRADER_ADDRESS, receiver: Default::default(), fee_amount: Default::default(), sell_token_source: Default::default(), @@ -349,7 +349,7 @@ pub struct Solver { /// How much ETH balance should the solver be funded with? 1 ETH by default. balance: eth::U256, /// The private key for this solver. - private_key: ethcontract::PrivateKey, + signer: PrivateKeySigner, /// The slippage for this solver. slippage: Slippage, /// The fraction of time used for solving @@ -359,6 +359,12 @@ pub struct Solver { /// Whether or not solver is allowed to combine multiple solutions into a /// new one. merge_solutions: bool, + /// Haircut in basis points (0-10000) for conservative bidding. + haircut_bps: u32, + /// Maximum number of solutions the driver proposes per auction. + max_solutions_to_propose: usize, + /// Additional submission accounts for EIP-7702 parallel settlement. + submission_accounts: Vec, } #[derive(Debug, Clone)] @@ -370,11 +376,10 @@ struct Slippage { pub fn test_solver() -> Solver { Solver { name: solver::NAME.to_owned(), - balance: eth::U256::exp10(18), - private_key: ethcontract::PrivateKey::from_slice( - const_hex::decode("a131a35fb8f614b31611f4fe68b6fc538b0febd2f75cd68e1282d8fd45b63326") - .unwrap(), - ) + balance: eth::U256::from(10).pow(eth::U256::from(18)), + signer: PrivateKeySigner::from_bytes(&b256!( + "a131a35fb8f614b31611f4fe68b6fc538b0febd2f75cd68e1282d8fd45b63326" + )) .unwrap(), slippage: Slippage { relative: BigDecimal::from_f64(0.3).unwrap(), @@ -386,12 +391,15 @@ pub fn test_solver() -> Solver { }, fee_handler: FeeHandler::default(), merge_solutions: false, + haircut_bps: 0, + max_solutions_to_propose: 1, + submission_accounts: vec![], } } impl Solver { - pub fn address(&self) -> eth::H160 { - self.private_key.public_address() + pub fn address(&self) -> eth::Address { + self.signer.address() } pub fn name(self, name: &str) -> Self { @@ -424,6 +432,23 @@ impl Solver { self.merge_solutions = true; self } + + pub fn haircut_bps(self, haircut_bps: u32) -> Self { + Self { + haircut_bps, + ..self + } + } + + pub fn max_solutions_to_propose(mut self, n: usize) -> Self { + self.max_solutions_to_propose = n; + self + } + + pub fn submission_account(mut self, signer: PrivateKeySigner) -> Self { + self.submission_accounts.push(signer); + self + } } #[derive(Debug, Clone, PartialEq)] @@ -472,10 +497,12 @@ fn ceil_div(x: eth::U256, y: eth::U256) -> eth::U256 { #[derive(Debug)] pub enum Mempool { - Public, + /// Uses the driver's main RPC URL + Default, Private { /// Uses ethrpc node if None url: Option, + mines_reverting_txs: bool, }, } @@ -484,11 +511,12 @@ pub fn setup() -> Setup { Setup { solvers: vec![test_solver()], enable_simulation: true, - mempools: vec![Mempool::Public], + mempools: vec![Mempool::Default], rpc_args: vec!["--gas-limit".into(), "10000000".into()], allow_multiple_solve_requests: false, auction_id: 1, settle_submission_deadline: 3, + flashloans_enabled: true, ..Default::default() } } @@ -509,19 +537,20 @@ pub struct Setup { /// Should simulation be enabled? True by default. enable_simulation: bool, /// Ensure the settlement contract is deployed on a specific address? - settlement_address: Option, + settlement_address: Option, /// Ensure the Balances contract is deployed on a specific address? - balances_address: Option, + balances_address: Option, /// Ensure the Signatures contract is deployed on a specific address? - signatures_address: Option, - /// Via which mempool the solutions should be submitted + signatures_address: Option, + /// Mempools that should be used for solution submission in addition + /// to the main RPC URL. mempools: Vec, /// Extra configuration for the RPC node rpc_args: Vec, /// List of jit orders returned by the solver jit_orders: Vec, /// List of surplus capturing JIT-order owners - surplus_capturing_jit_order_owners: Vec, + surplus_capturing_jit_order_owners: Vec, /// In case your test requires multiple `/solve` requests allow_multiple_solve_requests: bool, /// Auction ID used during tests @@ -529,6 +558,8 @@ pub struct Setup { /// The maximum number of blocks to wait for a settlement to appear on /// chain. settle_submission_deadline: u64, + /// Should flashloan-hint orders be accepted by the driver? True by default. + flashloans_enabled: bool, } /// The validity of a solution. @@ -550,6 +581,7 @@ pub struct Solution { pub calldata: Calldata, pub orders: Vec<&'static str>, pub flashloans: HashMap, + pub gas_fee_override: Option<(u128, u128)>, } impl Solution { @@ -595,6 +627,14 @@ impl Solution { self.flashloans.insert(order, flashloan); self } + + /// Set custom gas fee overrides for the solution. + pub fn gas_fee_override(self, max_fee_per_gas: u128, max_priority_fee_per_gas: u128) -> Self { + Self { + gas_fee_override: Some((max_fee_per_gas, max_priority_fee_per_gas)), + ..self + } + } } impl Default for Solution { @@ -605,6 +645,7 @@ impl Default for Solution { }, orders: Default::default(), flashloans: Default::default(), + gas_fee_override: None, } } } @@ -650,7 +691,7 @@ pub fn ab_solution() -> Solution { additional_bytes: 0, }, orders: vec!["A-B order"], - flashloans: Default::default(), + ..Default::default() } } @@ -682,7 +723,7 @@ pub fn ad_solution() -> Solution { additional_bytes: 0, }, orders: vec!["A-D order"], - flashloans: Default::default(), + ..Default::default() } } @@ -714,7 +755,7 @@ pub fn cd_solution() -> Solution { additional_bytes: 0, }, orders: vec!["C-D order"], - flashloans: Default::default(), + ..Default::default() } } @@ -745,12 +786,12 @@ pub fn eth_solution() -> Solution { additional_bytes: 0, }, orders: vec!["ETH order"], - flashloans: Default::default(), + ..Default::default() } } // Hardcoded trader account. Don't use this account for anything else!!! -pub const TRADER_ADDRESS: &str = "d2525C68A663295BBE347B65C87c8e17De936a0a"; +pub const TRADER_ADDRESS: Address = address!("d2525C68A663295BBE347B65C87c8e17De936a0a"); impl Setup { /// Set an explicit name for this test. If a name is set, it will be logged @@ -815,20 +856,20 @@ impl Setup { } /// Ensure that the settlement contract is deployed to a specific address. - pub fn settlement_address(mut self, address: &H160) -> Self { - self.settlement_address = Some(*address); + pub fn settlement_address(mut self, address: Address) -> Self { + self.settlement_address = Some(address); self } /// Ensure that the Balances contract is deployed to a specific address - pub fn balances_address(mut self, address: &H160) -> Self { - self.balances_address = Some(*address); + pub fn balances_address(mut self, address: Address) -> Self { + self.balances_address = Some(address); self } /// Ensure that the Signatures contract is deployed to a specific address. - pub fn signatures_address(mut self, address: &H160) -> Self { - self.signatures_address = Some(*address); + pub fn signatures_address(mut self, address: Address) -> Self { + self.signatures_address = Some(address); self } @@ -844,7 +885,7 @@ impl Setup { pub fn surplus_capturing_jit_order_owners( mut self, - surplus_capturing_jit_order_owners: Vec, + surplus_capturing_jit_order_owners: Vec
, ) -> Self { self.surplus_capturing_jit_order_owners .extend(surplus_capturing_jit_order_owners); @@ -868,10 +909,16 @@ impl Setup { self } + /// Toggle acceptance of flashloan-hint orders at the driver level. + pub fn flashloans_enabled(mut self, flashloans_enabled: bool) -> Self { + self.flashloans_enabled = flashloans_enabled; + self + } + /// Create the test: set up onchain contracts and pools, start a mock HTTP /// server for the solver and start the HTTP server for the driver. pub async fn done(self) -> Test { - observe::tracing::initialize_reentrant( + observe::tracing::init::initialize_reentrant( &observe::Config::default() .with_env_filter("driver=trace,driver::tests::setup::blockchain=debug,warn"), ); @@ -891,18 +938,14 @@ impl Setup { .. } = self; - // Hardcoded trader account. Don't use this account for anything else!!! - let trader_address = eth::H160::from_str(TRADER_ADDRESS).unwrap(); - let trader_secret_key = SecretKey::from_slice( - &const_hex::decode("f9f831cee763ef826b8d45557f0f8677b27045e0e011bcd78571a40acc8a6cc3") - .unwrap(), - ) - .unwrap(); - // Create the necessary components for testing. let blockchain = Blockchain::new(blockchain::Config { pools, - main_trader_secret_key: trader_secret_key, + // This PK is publicly known - don't send any funds to its account onchain!!! + main_trader_secret_key: PrivateKeySigner::from_bytes(&b256!( + "f9f831cee763ef826b8d45557f0f8677b27045e0e011bcd78571a40acc8a6cc3" + )) + .unwrap(), solvers: self.solvers.clone(), settlement_address: self.settlement_address, balances_address: self.balances_address, @@ -944,9 +987,10 @@ impl Setup { solutions.push(blockchain::Solution { trades: [fulfillment_trades, jit_trades].concat(), flashloans: solution.flashloans.clone(), + gas_fee_override: solution.gas_fee_override, }); } - let orderbook = Orderbook::start(&orders); + let orderbook = Orderbook::start(&orders).await; let quotes = orders .into_iter() .map(|order| blockchain.quote(&order)) @@ -960,16 +1004,18 @@ impl Setup { deadline: time::Deadline::new(deadline, solver.timeouts), quote: self.quote, fee_handler: solver.fee_handler, - private_key: solver.private_key.clone(), + private_key: solver.signer.clone(), expected_surplus_capturing_jit_order_owners: surplus_capturing_jit_order_owners .clone(), allow_multiple_solve_requests: self.allow_multiple_solve_requests, + haircut_bps: solver.haircut_bps, }) .await; (solver.clone(), instance.addr) })) .await; + let driver = Driver::new( &driver::Config { config_file, @@ -977,6 +1023,7 @@ impl Setup { mempools: self.mempools, order_priority_strategies: self.order_priority_strategies, orderbook, + flashloans_enabled: self.flashloans_enabled, }, &solvers_with_address, &blockchain, @@ -987,7 +1034,7 @@ impl Setup { blockchain, driver, client: Default::default(), - trader_address, + trader_address: TRADER_ADDRESS, trades: solutions.into_iter().flat_map(|s| s.trades).collect(), trusted, deadline, @@ -1028,7 +1075,7 @@ pub struct Test { blockchain: Blockchain, driver: Driver, client: reqwest::Client, - trader_address: eth::H160, + trader_address: eth::Address, trades: Vec, trusted: HashSet<&'static str>, deadline: chrono::DateTime, @@ -1036,7 +1083,7 @@ pub struct Test { /// Is this testing the /quote endpoint? quote: bool, /// List of surplus capturing JIT-order owners - surplus_capturing_jit_order_owners: Vec, + surplus_capturing_jit_order_owners: Vec, auction_id: i64, } @@ -1050,6 +1097,7 @@ impl Test { let res = self .client .post(format!("http://{}/{}/solve", self.driver.addr, solver)) + .header("X-Auction-Id", self.auction_id) .json(&driver::solve_req(self)) .send() .await @@ -1122,7 +1170,7 @@ impl Test { pub async fn settle_with_solver(&self, solver_name: &str, solution_id: u64) -> Settle { let submission_deadline_latest_block: u64 = - u64::try_from(self.web3().eth().block_number().await.unwrap()).unwrap() + self.web3().provider.get_block_number().await.unwrap() + self.settle_submission_deadline; let old_balances = self.balances().await; let res = self @@ -1158,36 +1206,34 @@ impl Test { let mut balances = HashMap::new(); for (token, contract) in self.blockchain.tokens.iter() { let balance = contract - .balanceOf(self.trader_address.into_alloy()) + .balanceOf(self.trader_address) .call() .await - .unwrap() - .into_legacy(); + .unwrap(); balances.insert(*token, balance); } balances.insert( "WETH", self.blockchain .weth - .balanceOf(self.trader_address.into_alloy()) + .balanceOf(self.trader_address) .call() .await - .unwrap() - .into_legacy(), + .unwrap(), ); balances.insert( "ETH", self.blockchain .web3 - .eth() - .balance(self.trader_address, None) + .provider + .get_balance(self.trader_address) .await .unwrap(), ); balances } - pub fn web3(&self) -> &web3::Web3 { + pub fn web3(&self) -> &Web3 { &self.blockchain.web3 } @@ -1221,7 +1267,7 @@ pub struct SolveOk<'a> { impl<'a> Solve<'a> { /// Expect the /solve endpoint to have returned a 200 OK response. pub fn ok(self) -> SolveOk<'a> { - assert_eq!(self.status, hyper::StatusCode::OK); + assert_eq!(self.status, axum::http::StatusCode::OK); SolveOk { body: self.body, trades: self.trades, @@ -1230,13 +1276,13 @@ impl<'a> Solve<'a> { } pub fn err(self) -> SolveErr { - assert_ne!(self.status, hyper::StatusCode::OK); + assert_ne!(self.status, axum::http::StatusCode::OK); SolveErr { body: self.body } } } impl SolveOk<'_> { - fn solutions(&self) -> Vec { + pub fn solutions(&self) -> Vec { #[derive(serde::Deserialize)] struct Body { solutions: Vec, @@ -1256,10 +1302,9 @@ impl SolveOk<'_> { .to_owned() } - /// Extracts the first solution from the response. This is expected to be - /// always valid if there is a valid solution, as we expect from driver to - /// not send multiple solutions (yet). - fn solution(&self) -> serde_json::Value { + /// Extracts the only solution from the response. Panics if the response + /// contains more than one solution (i.e. `max-solutions-to-propose > 1`). + pub fn solution(&self) -> serde_json::Value { let solutions = self.solutions(); assert_eq!(solutions.len(), 1); let solution = solutions[0].clone(); @@ -1275,7 +1320,7 @@ impl SolveOk<'_> { let solution = self.solution(); assert!(solution.get("score").is_some()); let score = solution.get("score").unwrap().as_str().unwrap(); - eth::U256::from_dec_str(score).unwrap() + eth::U256::from_str_radix(score, 10).unwrap() } /// Ensures that `/solve` returns no solutions. @@ -1306,8 +1351,9 @@ impl SolveOk<'_> { /// Find for a JIT order, given specific token pair and buy/sell amount, /// return true if the JIT order was found fn trade_matches(&self, trade: &serde_json::Value, expected: &JitOrder) -> bool { - let u256 = - |value: &serde_json::Value| eth::U256::from_dec_str(value.as_str().unwrap()).unwrap(); + let u256 = |value: &serde_json::Value| { + eth::U256::from_str_radix(value.as_str().unwrap(), 10).unwrap() + }; let sell_token = Address::deserialize(trade.get("sellToken").unwrap().into_deserializer()).unwrap(); let buy_token = @@ -1352,21 +1398,15 @@ impl SolveOk<'_> { .get(&uid.to_string()) .expect("Didn't find expected trade in solution"); let u256 = |value: &serde_json::Value| { - eth::U256::from_dec_str(value.as_str().unwrap()).unwrap() + eth::U256::from_str_radix(value.as_str().unwrap(), 10).unwrap() }; let (expected_sell, expected_buy) = match &expected.expected_amounts { Some(executed_amounts) => (executed_amounts.sell, executed_amounts.buy), None => (quoted_order.sell, quoted_order.buy), }; - assert!(is_approximately_equal( - u256(trade.get("executedSell").unwrap()), - expected_sell - )); - assert!(is_approximately_equal( - u256(trade.get("executedBuy").unwrap()), - expected_buy - )); + assert!(u256(trade.get("executedSell").unwrap()).is_approx_eq(&expected_sell, None)); + assert!(u256(trade.get("executedBuy").unwrap()).is_approx_eq(&expected_buy, None)); } self } @@ -1398,7 +1438,7 @@ pub struct Reveal { impl Reveal { /// Expect the /reveal endpoint to have returned a 200 OK response. pub fn ok(self) -> RevealOk { - assert_eq!(self.status, hyper::StatusCode::OK); + assert_eq!(self.status, axum::http::StatusCode::OK); RevealOk { body: self.body } } @@ -1474,7 +1514,7 @@ pub struct Quote<'a> { impl<'a> Quote<'a> { /// Expect the /quote endpoint to have returned a 200 OK response. pub fn ok(self) -> QuoteOk<'a> { - assert_eq!(self.status, hyper::StatusCode::OK); + assert_eq!(self.status, axum::http::StatusCode::OK); QuoteOk { trades: self.trades, body: self.body, @@ -1490,6 +1530,11 @@ pub struct QuoteOk<'a> { } impl QuoteOk<'_> { + /// Get the JSON response body. + pub fn body(&self) -> &str { + &self.body + } + /// Check that the quote returns the expected amount of tokens. This is /// based on the state of the blockchain and the test setup. pub fn amount(self) -> Self { @@ -1514,12 +1559,12 @@ impl QuoteOk<'_> { .as_object() .unwrap() .into_iter() - .map(|(token, price)| (H160::from_str(token).unwrap(), price.as_str().unwrap())) + .map(|(token, price)| (Address::from_str(token).unwrap(), price.as_str().unwrap())) .collect::>(); let amount = match quoted_order.order.side { - order::Side::Buy => clearing_prices.get(&buy_token.into_legacy()).unwrap(), - order::Side::Sell => clearing_prices.get(&sell_token.into_legacy()).unwrap(), + order::Side::Buy => clearing_prices.get(&buy_token).unwrap(), + order::Side::Sell => clearing_prices.get(&sell_token).unwrap(), }; let expected = match quoted_order.order.side { @@ -1622,11 +1667,11 @@ pub struct OrderQuote { pub buy_amount: eth::U256, #[serde_as(as = "HexOrDecimalU256")] pub fee: eth::U256, - pub solver: eth::H160, + pub solver: eth::Address, } impl OrderQuote { - pub fn solver(self, solver: eth::H160) -> Self { + pub fn solver(self, solver: eth::Address) -> Self { Self { solver, ..self } } } @@ -1679,7 +1724,7 @@ impl Settle { pub fn err(self) -> SettleErr { match self.status { SettleStatus::Err { status_code, body } => { - assert_eq!(status_code, hyper::StatusCode::BAD_REQUEST); + assert_eq!(status_code, axum::http::StatusCode::BAD_REQUEST); SettleErr { body } } _ => panic!("expected a 400 BAD REQUEST response"), diff --git a/crates/driver/src/tests/setup/orderbook.rs b/crates/driver/src/tests/setup/orderbook.rs index 440b6ec9cf..3d48174ada 100644 --- a/crates/driver/src/tests/setup/orderbook.rs +++ b/crates/driver/src/tests/setup/orderbook.rs @@ -7,7 +7,7 @@ use { Router, extract::Path, http::StatusCode, - response::IntoResponse, + response::{IntoResponse, Response}, routing::get, }, std::{collections::HashMap, net::SocketAddr}, @@ -27,7 +27,7 @@ impl Orderbook { /// /// # Returns /// The `Orderbook` instance with the server listening address. - pub fn start(orders: &[Order]) -> Self { + pub async fn start(orders: &[Order]) -> Self { let app_data_storage = orders .iter() .filter_map(|order| { @@ -43,15 +43,16 @@ impl Orderbook { .collect::>(); let app = Router::new() - .route("/api/v1/app_data/:app_data", get(Self::app_data_handler)) + .route("/api/v1/app_data/{app_data}", get(Self::app_data_handler)) .layer(Extension(app_data_storage)); - let server = - axum::Server::bind(&"0.0.0.0:0".parse().unwrap()).serve(app.into_make_service()); - let addr = server.local_addr(); + let listener = tokio::net::TcpListener::bind("0.0.0.0:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); tracing::info!("Orderbook mock server listening on {}", addr); - tokio::spawn(server); + tokio::spawn(async move { + axum::serve(listener, app).await.unwrap(); + }); Orderbook { addr } } @@ -59,7 +60,7 @@ impl Orderbook { async fn app_data_handler( Path(app_data): Path, Extension(app_data_storage): Extension>, - ) -> impl IntoResponse { + ) -> Response { tracing::debug!("Orderbook received an app_data request: {}", app_data); let app_data_hash = match app_data.parse::() { diff --git a/crates/driver/src/tests/setup/solver.rs b/crates/driver/src/tests/setup/solver.rs index e14d79c3e6..e3a8243125 100644 --- a/crates/driver/src/tests/setup/solver.rs +++ b/crates/driver/src/tests/setup/solver.rs @@ -7,25 +7,26 @@ use { crate::{ domain::{ competition::order, - eth, time::{self}, }, infra::{self, Ethereum, blockchain::contracts::Addresses, config::file::FeeHandler}, - tests::{hex_address, setup::blockchain::Trade}, + tests::setup::blockchain::Trade, }, + alloy::{primitives::Address, signers::local::PrivateKeySigner}, const_hex::ToHexExt, - contracts::alloy::ERC20, - ethereum_types::H160, - ethrpc::alloy::conversions::IntoLegacy, + contracts::ERC20, + eth_domain_types as eth, + gas_price_estimation::Eip1559EstimationExt, itertools::Itertools, - serde_json::json, + number::testing::ApproxEq, + serde_json::{Value, json}, + serde_with::{DisplayFromStr, serde_as}, solvers_dto::auction::FlashloanHint, std::{ collections::{HashMap, HashSet}, net::SocketAddr, sync::{Arc, Mutex}, }, - web3::signing::Key, }; pub const NAME: &str = "test-solver"; @@ -44,9 +45,10 @@ pub struct Config<'a> { /// Is this a test for the /quote endpoint? pub quote: bool, pub fee_handler: FeeHandler, - pub private_key: ethcontract::PrivateKey, - pub expected_surplus_capturing_jit_order_owners: Vec, + pub private_key: PrivateKeySigner, + pub expected_surplus_capturing_jit_order_owners: Vec
, pub allow_multiple_solve_requests: bool, + pub haircut_bps: u32, } impl Solver { @@ -91,6 +93,17 @@ impl Solver { _ => {} } } + // Make-room for the haircut: the driver subtracts a haircut + // post-hoc from buy_amount() (sell orders) / adds it to + // sell_amount() (buy orders). Tightening the auction limits + // here ensures solvers bid with enough headroom. + if config.haircut_bps > 0 { + let factor = f64::from(config.haircut_bps) / 10_000.0; + current_sell_amount = eth::TokenAmount(current_sell_amount) + .apply_factor(1.0 / (1.0 + factor)) + .unwrap() + .0; + } current_sell_amount.to_string() } _ => quote.sell_amount().to_string(), @@ -117,6 +130,15 @@ impl Solver { _ => {} } } + // Make-room for the haircut (see comment in the buy-side + // branch above). + if config.haircut_bps > 0 { + let factor = f64::from(config.haircut_bps) / 10_000.0; + current_buy_amount = eth::TokenAmount(current_buy_amount) + .apply_factor(1.0 / (1.0 - factor)) + .unwrap() + .0; + } current_buy_amount.to_string() } _ => quote.buy_amount().to_string(), @@ -131,7 +153,7 @@ impl Solver { "buyAmount": buy_amount, "fullBuyAmount": if config.quote { buy_amount } else { quote.buy_amount().to_string() }, "validTo": quote.order.valid_to, - "owner": if config.quote { H160::zero() } else { quote.order.owner }, + "owner": if config.quote { eth::Address::ZERO } else { quote.order.owner }, "preInteractions": json!([]), "postInteractions": json!([]), "sellTokenSource": quote.order.sell_token_source, @@ -151,15 +173,15 @@ impl Solver { "signingScheme": if config.quote { "eip1271" } else { "eip712" }, }); if let Some(receiver) = quote.order.receiver { - order["receiver"] = json!(hex_address(receiver)); + order["receiver"] = json!(receiver.encode_hex_with_prefix()); } if let Some(flashloan) = quote.order.app_data.flashloan() { order["flashloanHint"] = json!(FlashloanHint { - liquidity_provider: flashloan.liquidity_provider.into_legacy(), - protocol_adapter: flashloan.protocol_adapter.into_legacy(), - receiver: flashloan.receiver.into_legacy(), - token: flashloan.token.into_legacy(), - amount: flashloan.amount.into_legacy(), + liquidity_provider: flashloan.liquidity_provider, + protocol_adapter: flashloan.protocol_adapter, + receiver: flashloan.receiver, + token: flashloan.token, + amount: flashloan.amount, }); } if config.fee_handler == FeeHandler::Solver { @@ -195,19 +217,19 @@ impl Solver { json!({ "kind": "custom", "internalize": interaction.internalize, - "target": hex_address(interaction.address), + "target": interaction.address.encode_hex_with_prefix(), "value": "0", "callData": const_hex::encode_prefixed(&interaction.calldata), "allowances": [], "inputs": interaction.inputs.iter().map(|input| { json!({ - "token": hex_address(input.token.into()), + "token": eth::Address::from(input.token).encode_hex_with_prefix(), "amount": input.amount.to_string(), }) }).collect_vec(), "outputs": interaction.outputs.iter().map(|output| { json!({ - "token": hex_address(output.token.into()), + "token": eth::Address::from(output.token).encode_hex_with_prefix(), "amount": output.amount.to_string(), }) }).collect_vec(), @@ -275,19 +297,19 @@ impl Solver { json!({ "kind": "custom", "internalize": interaction.internalize, - "target": hex_address(interaction.address), + "target": interaction.address.encode_hex_with_prefix(), "value": "0", "callData": const_hex::encode_prefixed(&interaction.calldata), "allowances": [], "inputs": interaction.inputs.iter().map(|input| { json!({ - "token": hex_address(input.token.into()), + "token": eth::Address::from(input.token).encode_hex_with_prefix(), "amount": input.amount.to_string(), }) }).collect_vec(), "outputs": interaction.outputs.iter().map(|output| { json!({ - "token": hex_address(output.token.into()), + "token": eth::Address::from(output.token).encode_hex_with_prefix(), "amount": output.amount.to_string(), }) }).collect_vec(), @@ -298,19 +320,19 @@ impl Solver { json!({ "kind": "custom", "internalize": interaction.internalize, - "target": hex_address(interaction.address), + "target": interaction.address.encode_hex_with_prefix(), "value": "0", "callData": const_hex::encode_prefixed(&interaction.calldata), "allowances": [], "inputs": interaction.inputs.iter().map(|input| { json!({ - "token": hex_address(input.token.into()), + "token": eth::Address::from(input.token).encode_hex_with_prefix(), "amount": input.amount.to_string(), }) }).collect_vec(), "outputs": interaction.outputs.iter().map(|output| { json!({ - "token": hex_address(output.token.into()), + "token": eth::Address::from(output.token).encode_hex_with_prefix(), "amount": output.amount.to_string(), }) }).collect_vec(), @@ -356,7 +378,7 @@ impl Solver { let order = json!({ "sellToken": config.blockchain.get_token(jit.quoted_order.order.sell_token), "buyToken": config.blockchain.get_token(jit.quoted_order.order.buy_token), - "receiver": hex_address(jit.quoted_order.order.receiver.unwrap_or_default()), + "receiver": jit.quoted_order.order.receiver.unwrap_or_default().encode_hex_with_prefix(), "sellAmount": jit.quoted_order.order.sell_amount.to_string(), "buyAmount": jit.quoted_order.order.buy_amount.unwrap_or_default().to_string(), "validTo": jit.quoted_order.order.valid_to, @@ -367,7 +389,7 @@ impl Solver { }, "sellTokenBalance": jit.quoted_order.order.sell_token_source, "buyTokenBalance": jit.quoted_order.order.buy_token_destination, - "signature": const_hex::encode_prefixed(jit.quoted_order.order_signature_with_private_key(config.blockchain, &config.private_key)), + "signature": const_hex::encode_prefixed(jit.quoted_order.order_signature_with_private_key(config.blockchain, config.private_key.clone())), "signingScheme": if config.quote { "eip1271" } else { "eip712" }, }); trades_json.push(json!({ @@ -387,6 +409,10 @@ impl Solver { "interactions": interactions_json, "preInteractions": pre_interactions_json, }); + if let Some((max_fee, max_priority_fee)) = &solution.gas_fee_override { + solution_json["maxFeePerGas"] = json!(max_fee.to_string()); + solution_json["maxPriorityFeePerGas"] = json!(max_priority_fee.to_string()); + } if !solution.flashloans.is_empty() { solution_json["flashloans"] = serde_json::Value::Object( solution @@ -411,7 +437,7 @@ impl Solver { .flat_map(|f| { let build_token = |token_name: String| async move { let token = config.blockchain.get_token_wrapped(token_name.as_str()); - let contract = ERC20::Instance::new(token, config.blockchain.web3.alloy.clone()); + let contract = ERC20::Instance::new(token, config.blockchain.web3.provider.clone()); let settlement = config.blockchain.settlement.address(); ( token.encode_hex_with_prefix(), @@ -452,17 +478,9 @@ impl Solver { infra::blockchain::GasPriceEstimator::new( rpc.web3(), &Default::default(), - &[infra::mempool::Config { - min_priority_fee: Default::default(), - gas_price_cap: eth::U256::MAX, - target_confirm_time: Default::default(), - retry_interval: Default::default(), - kind: infra::mempool::Kind::Public { - max_additional_tip: 0.into(), - additional_tip_percentage: 0., - revert_protection: infra::mempool::RevertProtection::Disabled, - }, - }], + &[infra::mempool::Config::test_config( + config.blockchain.web3_url.parse().unwrap(), + )], ) .await .unwrap(), @@ -470,26 +488,19 @@ impl Solver { let eth = Ethereum::new( rpc, Addresses { - settlement: Some(config.blockchain.settlement.address().into_legacy().into()), - weth: Some(config.blockchain.weth.address().into_legacy().into()), - balances: Some(config.blockchain.balances.address().into_legacy().into()), - signatures: Some(config.blockchain.signatures.address().into_legacy().into()), + settlement: Some((*config.blockchain.settlement.address()).into()), + weth: Some((*config.blockchain.weth.address()).into()), + balances: Some((*config.blockchain.balances.address()).into()), + signatures: Some((*config.blockchain.signatures.address()).into()), cow_amm_helper_by_factory: Default::default(), - flashloan_router: Some( - config - .blockchain - .flashloan_router - .address() - .into_legacy() - .into(), - ), + flashloan_router: Some((*config.blockchain.flashloan_router.address()).into()), }, gas, - 45_000_000.into(), &shared::current_block::Arguments { block_stream_poll_interval: None, node_ws_url: Some(config.blockchain.web3_ws_url.parse().unwrap()), }, + eth_domain_types::Gas(eth_domain_types::U256::from(45_000_000u64)), ) .await; @@ -503,14 +514,8 @@ impl Solver { axum::routing::post( move |axum::extract::State(state): axum::extract::State, axum::extract::Json(req): axum::extract::Json| async move { - let effective_gas_price = eth - .gas_price(None) - .await - .unwrap() - .effective() - .0 - .0 - .to_string(); + let base_fee = eth.current_block().borrow().base_fee; + let effective_gas_price = eth.gas_price().await.unwrap().effective(base_fee).to_string(); let expected = json!({ "id": (!config.quote).then_some("1"), "tokens": tokens_json, @@ -520,7 +525,7 @@ impl Solver { "deadline": config.deadline.solvers(), "surplusCapturingJitOrderOwners": config.expected_surplus_capturing_jit_order_owners, }); - assert_eq!(req, expected, "unexpected /solve request"); + check_solve_request(req, expected); let mut state = state.0.lock().unwrap(); assert!( !state.called || state.allow_multiple_solve_requests, @@ -534,14 +539,51 @@ impl Solver { ), ) .with_state(State(state)); - let server = - axum::Server::bind(&"0.0.0.0:0".parse().unwrap()).serve(app.into_make_service()); - let addr = server.local_addr(); - tokio::spawn(async move { server.await.unwrap() }); + let listener = tokio::net::TcpListener::bind("0.0.0.0:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + tokio::spawn(async move { axum::serve(listener, app).await.unwrap() }); Self { addr } } } +/// Checks the provider /solve request against the expected values while keeping +/// some slack for the effective gas price, as it might vary between blockchain +/// requests. +/// +/// Context: when the gas-estimation crate was removed, the Alloy and Web3 +/// estimators started failing the driver tests: the request's effective gas +/// value did not match the expected. This did not happen with the previous +/// native estimator because it used a cache, and due to how short the test was +/// the cache always replied with the same value making the test pass. The new +/// estimators do not have a cache, as such the value might change; this check +/// takes that into account and validates the effective gas price within an +/// interval (15% at the time of writing). +fn check_solve_request(request: Value, expected: Value) { + #[serde_as] + #[derive(Debug, serde::Deserialize)] + #[serde(rename_all = "camelCase")] + struct SolveRequest { + #[serde_as(as = "DisplayFromStr")] + effective_gas_price: u128, + #[serde(flatten)] + rest: Value, + } + + let request: SolveRequest = + serde_json::from_value(request).expect("failed to deserialize /solve request body"); + let expected: SolveRequest = serde_json::from_value(expected) + .expect("failed to deserialize expected /solve request body"); + assert_eq!( + request.rest, expected.rest, + "/solve request body does not match expectation" + ); + assert!( + request + .effective_gas_price + .is_approx_eq(&expected.effective_gas_price, Some(1.0)), // 1.0% + ); +} + #[derive(Debug, Clone)] struct StateInner { /// Has this solver been called yet? If so, attempting to make another call diff --git a/crates/driver/src/util/bytes.rs b/crates/driver/src/util/bytes.rs deleted file mode 100644 index 7e3ade9e18..0000000000 --- a/crates/driver/src/util/bytes.rs +++ /dev/null @@ -1,30 +0,0 @@ -/// A thin wrapper around a collection of bytes. Provides hex debug formatting. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] -pub struct Bytes(pub T); - -impl std::fmt::Debug for Bytes -where - T: AsRef<[u8]>, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", const_hex::encode_prefixed(&self.0)) - } -} - -impl From for Bytes { - fn from(value: T) -> Self { - Self(value) - } -} - -impl From>> for Vec { - fn from(value: Bytes>) -> Self { - value.0 - } -} - -impl From> for [u8; N] { - fn from(value: Bytes<[u8; N]>) -> Self { - value.0 - } -} diff --git a/crates/driver/src/util/conv/mod.rs b/crates/driver/src/util/conv/mod.rs deleted file mode 100644 index 8010518d54..0000000000 --- a/crates/driver/src/util/conv/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod u256; - -pub fn rational_to_big_decimal(value: &num::rational::Ratio) -> bigdecimal::BigDecimal -where - T: Clone, - num::BigInt: From, -{ - let numer = num::BigInt::from(value.numer().clone()); - let denom = num::BigInt::from(value.denom().clone()); - bigdecimal::BigDecimal::new(numer, 0) / bigdecimal::BigDecimal::new(denom, 0) -} diff --git a/crates/driver/src/util/conv/u256.rs b/crates/driver/src/util/conv/u256.rs deleted file mode 100644 index b6528ad04f..0000000000 --- a/crates/driver/src/util/conv/u256.rs +++ /dev/null @@ -1,73 +0,0 @@ -use {crate::domain::eth, anyhow::Result, bigdecimal::Zero}; - -pub trait U256Ext: Sized { - fn to_big_int(&self) -> num::BigInt; - fn to_big_uint(&self) -> num::BigUint; - fn to_big_rational(&self) -> num::BigRational; - - fn checked_ceil_div(&self, other: &Self) -> Option; - fn ceil_div(&self, other: &Self) -> Self; - fn checked_mul_f64(&self, factor: f64) -> Option; - - fn from_big_int(input: &num::BigInt) -> Result; - fn from_big_uint(input: &num::BigUint) -> Result; - fn from_big_rational(value: &num::BigRational) -> Result; -} - -impl U256Ext for eth::U256 { - fn to_big_int(&self) -> num::BigInt { - num::BigInt::from_biguint(num::bigint::Sign::Plus, self.to_big_uint()) - } - - fn to_big_uint(&self) -> num::BigUint { - let mut bytes = [0; 32]; - self.to_big_endian(&mut bytes); - num::BigUint::from_bytes_be(&bytes) - } - - fn to_big_rational(&self) -> num::BigRational { - num::BigRational::new(self.to_big_int(), 1.into()) - } - - fn checked_ceil_div(&self, other: &Self) -> Option { - self.checked_add(other.checked_sub(1.into())?)? - .checked_div(*other) - } - - fn ceil_div(&self, other: &Self) -> Self { - self.checked_ceil_div(other) - .expect("ceiling division arithmetic error") - } - - fn checked_mul_f64(&self, factor: f64) -> Option { - // `factor` is first multiplied by the conversion factor to convert - // it to integer, to avoid rounding to 0. Then, the result is divided - // by the conversion factor to convert it back to the original scale. - // - // The higher the conversion factor (10^18) the precision is higher. E.g. - // 0.123456789123456789 will be converted to 123456789123456789. - // TODO: consider doing the computation with `BigRational` instead but - // that requires to double check and adjust a few tests due to tiny - // changes in rounding. - const CONVERSION_FACTOR: f64 = 1_000_000_000_000_000_000.; - let multiplied = self.checked_mul(Self::from_f64_lossy(factor * CONVERSION_FACTOR))? - / Self::from_f64_lossy(CONVERSION_FACTOR); - Some(multiplied) - } - - fn from_big_int(input: &num::BigInt) -> Result { - anyhow::ensure!(input.sign() != num::bigint::Sign::Minus, "negative"); - Self::from_big_uint(input.magnitude()) - } - - fn from_big_uint(input: &num::BigUint) -> Result { - let bytes = input.to_bytes_be(); - anyhow::ensure!(bytes.len() <= 32, "too large"); - Ok(eth::U256::from_big_endian(&bytes)) - } - - fn from_big_rational(value: &num::BigRational) -> Result { - anyhow::ensure!(*value.denom() != num::BigInt::zero(), "zero denominator"); - Self::from_big_int(&(value.numer() / value.denom())) - } -} diff --git a/crates/driver/src/util/http.rs b/crates/driver/src/util/http.rs index 47b2891610..fee7493b61 100644 --- a/crates/driver/src/util/http.rs +++ b/crates/driver/src/util/http.rs @@ -31,7 +31,7 @@ pub async fn send(limit_bytes: usize, req: reqwest::RequestBuilder) -> Result Option { // fast path when math in U256 doesn't overflow if let Some(p) = x.checked_mul(q) { - let (div, rem) = (p / d, p % d); + let (div, rem) = p.div_rem(d); return div.checked_add(U256::from(!rem.is_zero())); } let p = x.widening_mul(q); let d = U512::from(d); // SAFETY: at this point !d.is_zero() upholds - let (div, rem) = (p / d, p % d); + let (div, rem) = p.div_rem(d); let result = U256::uint_try_from(div).ok()?; result.checked_add(U256::from(!rem.is_zero())) diff --git a/crates/driver/src/util/mod.rs b/crates/driver/src/util/mod.rs index ba85b72931..38aff00c0d 100644 --- a/crates/driver/src/util/mod.rs +++ b/crates/driver/src/util/mod.rs @@ -1,9 +1,6 @@ -mod bytes; -pub mod conv; pub mod http; pub mod math; mod percent; -pub mod serialize; mod time; -pub use {bytes::Bytes, percent::Percent, time::Timestamp}; +pub use {percent::Percent, time::Timestamp}; diff --git a/crates/e2e/Cargo.toml b/crates/e2e/Cargo.toml index 292dc18361..d644e47f47 100644 --- a/crates/e2e/Cargo.toml +++ b/crates/e2e/Cargo.toml @@ -2,52 +2,80 @@ name = "e2e" version = "1.0.0" authors = [ - "Gnosis Developers ", - "Cow Protocol Developers ", + "Gnosis Developers ", + "Cow Protocol Developers ", ] edition = "2024" license = "MIT OR Apache-2.0" [dependencies] -alloy = { workspace = true, default-features = false, features = ["json-rpc", "providers", "rpc-client", "rpc-types", "transports", "reqwest", "signers", "signer-local", "signer-mnemonic", "provider-anvil-api", "provider-debug-api", "sol-types"] } -app-data = { workspace = true } +alloy = { + workspace = true, + default-features = false, + features = [ + "contract", + "json-rpc", + "provider-anvil-api", + "provider-debug-api", + "provider-txpool-api", + "providers", + "reqwest", + "rpc-client", + "rpc-types", + "signer-local", + "signer-mnemonic", + "signers", + "sol-types", + "transports", + ], +} +alloy-signer = { workspace = true, default-features = false, features = ["eip712"] } anyhow = { workspace = true } -autopilot = { workspace = true } +app-data = { workspace = true } +autopilot = { workspace = true, features = ["test-util"] } axum = { workspace = true } +balance-overrides = { workspace = true } bigdecimal = { workspace = true } chrono = { workspace = true } clap = { workspace = true } +configs = { workspace = true, features = ["test-util"] } +const-hex = { workspace = true } contracts = { workspace = true } cow-amm = { workspace = true } database = { workspace = true } driver = { workspace = true } -ethcontract = { workspace = true } +eth-domain-types = { workspace = true } ethrpc = { workspace = true, features = ["test-util"] } futures = { workspace = true } -const-hex = { workspace = true } hex-literal = { workspace = true } +itertools = { workspace = true } +liquidity-sources = { workspace = true } model = { workspace = true, features = ["e2e"] } number = { workspace = true } observe = { workspace = true } -orderbook = { workspace = true, features = ["e2e"] } -reqwest = { workspace = true, features = ["blocking"] } -secp256k1 = { workspace = true } +orderbook = { workspace = true, features = ["e2e", "test-util"] } +pool-indexer = { workspace = true } +price-estimation = { workspace = true } +reqwest = { workspace = true, features = ["blocking", "query"] } +serde = { workspace = true } serde_json = { workspace = true } shared = { workspace = true } +signature-validator = { workspace = true } +simulator = { workspace = true } solver = { workspace = true } solvers = { workspace = true } solvers-dto = { workspace = true } sqlx = { workspace = true } tempfile = { workspace = true } +testlib = { workspace = true } tokio = { workspace = true, features = ["macros", "process"] } toml = { workspace = true } tracing = { workspace = true } url = { workspace = true } -warp = { workspace = true } -web3 = { workspace = true, features = ["http"] } [dev-dependencies] refunder = { workspace = true } +rstest = { workspace = true } [lints] workspace = true diff --git a/crates/e2e/src/api/liquorice/server.rs b/crates/e2e/src/api/liquorice/server.rs index be107877f4..0f7bc8892e 100644 --- a/crates/e2e/src/api/liquorice/server.rs +++ b/crates/e2e/src/api/liquorice/server.rs @@ -1,9 +1,12 @@ use { + axum::Json, driver::infra::notify::liquidity_sources::liquorice::client::request::v1::intent_origin::notification, serde_json::json, - std::{convert::Infallible, net::SocketAddr, sync::Arc}, + std::{ + net::{Ipv4Addr, SocketAddr}, + sync::Arc, + }, tokio::sync::{Mutex, MutexGuard}, - warp::{Filter, Rejection}, }; pub struct State { @@ -22,14 +25,24 @@ impl LiquoriceApi { notification_requests: Default::default(), })); - let addr: SocketAddr = ([0, 0, 0, 0], 0).into(); - let server = warp::serve(Self::notification_route(state.clone())); - let (addr, server) = server.bind_ephemeral(addr); + let app = axum::Router::new() + .route( + "/v1/intent-origin/notification", + axum::routing::post(notification_handler), + ) + .with_state(state.clone()); + + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)); + let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); + let addr = listener.local_addr().unwrap(); let port = addr.port(); assert!(port > 0, "assigned port must be greater than 0"); tokio::spawn(async move { - server.await; + if let Err(err) = axum::serve(listener, app).await { + tracing::error!(?err, "Liquorice API server failed"); + panic!("Liquorice test server crashed: {}", err); + } }); tracing::info!("Started Liquorice API server at {}", addr); @@ -37,22 +50,15 @@ impl LiquoriceApi { Self { state, port } } - pub fn notification_route( - state: Arc>, - ) -> impl Filter + Clone { - warp::path!("v1" / "intent-origin" / "notification") - .and(warp::post()) - .and(warp::body::json::()) - .and_then(move |request| { - let state = state.clone(); - async move { - state.lock().await.notification_requests.push(request); - Ok::(warp::reply::json(&json!({}))) - } - }) - } - pub async fn get_state(&self) -> MutexGuard<'_, State> { self.state.lock().await } } + +async fn notification_handler( + axum::extract::State(state): axum::extract::State>>, + Json(request): Json, +) -> Json { + state.lock().await.notification_requests.push(request); + Json(json!({})) +} diff --git a/crates/e2e/src/api/zeroex.rs b/crates/e2e/src/api/zeroex.rs index 21fbf61376..f305302cc4 100644 --- a/crates/e2e/src/api/zeroex.rs +++ b/crates/e2e/src/api/zeroex.rs @@ -1,20 +1,26 @@ use { crate::setup::TestAccount, - autopilot::domain::eth::U256, + alloy::primitives::{Address, B256, U256}, + axum::Json, chrono::{DateTime, NaiveDateTime, Utc}, - driver::domain::eth::H256, - ethcontract::common::abi::{Token, encode}, hex_literal::hex, + liquidity_sources::zeroex::{self, Order, OrderMetadata, OrderRecord, ZeroExSignature}, model::DomainSeparator, - shared::{ - zeroex_api, - zeroex_api::{Order, OrderMetadata, OrderRecord, ZeroExSignature}, + std::{ + net::{Ipv4Addr, SocketAddr}, + sync::Arc, }, - std::{net::SocketAddr, sync::LazyLock}, - warp::{Filter, Reply}, - web3::{signing, types::H160}, }; +// Mock pagination constants for test API responses +const MOCK_PAGE: u64 = 1; +const MOCK_PER_PAGE: u64 = 100; + +#[derive(Clone)] +struct State { + orders: Arc>, +} + pub struct ZeroExApi { orders: Vec, } @@ -28,24 +34,25 @@ impl ZeroExApi { /// Starts the server and returns the assigned port number. pub async fn run(self) -> u16 { - let orders_route = warp::path!("orderbook" / "v1" / "orders").map(move || { - warp::reply::json(&zeroex_api::OrdersResponse { - total: self.orders.len() as u64, - page: 1, - per_page: 100, - records: self.orders.clone(), - }) - .into_response() - }); + let state = State { + orders: Arc::new(self.orders), + }; - let addr: SocketAddr = ([0, 0, 0, 0], 0).into(); - let server = warp::serve(orders_route); - let (addr, server) = server.bind_ephemeral(addr); + let app = axum::Router::new() + .route("/orderbook/v1/orders", axum::routing::get(orders_handler)) + .with_state(state); + + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)); + let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); + let addr = listener.local_addr().unwrap(); let port = addr.port(); assert!(port > 0, "assigned port must be greater than 0"); tokio::spawn(async move { - server.await; + if let Err(err) = axum::serve(listener, app).await { + tracing::error!(?err, "ZeroEx API server failed"); + panic!("ZeroEx test server crashed: {}", err); + } }); tracing::info!("Started ZeroEx API server at {}", addr); @@ -54,18 +61,29 @@ impl ZeroExApi { } } +async fn orders_handler( + axum::extract::State(state): axum::extract::State, +) -> Json { + Json(zeroex::OrdersResponse { + total: state.orders.len() as u64, + page: MOCK_PAGE, + per_page: MOCK_PER_PAGE, + records: (*state.orders).clone(), + }) +} + pub struct Eip712TypedZeroExOrder { - pub maker_token: H160, - pub taker_token: H160, + pub maker_token: Address, + pub taker_token: Address, pub maker_amount: u128, pub taker_amount: u128, pub remaining_fillable_taker_amount: u128, pub taker_token_fee_amount: u128, - pub maker: H160, - pub taker: H160, - pub sender: H160, - pub fee_recipient: H160, - pub pool: H256, + pub maker: Address, + pub taker: Address, + pub sender: Address, + pub fee_recipient: Address, + pub pool: B256, pub expiry: u64, pub salt: U256, } @@ -78,7 +96,7 @@ impl Eip712TypedZeroExOrder { pub fn to_order_record( &self, chain_id: u64, - verifying_contract: H160, + verifying_contract: Address, signer: TestAccount, ) -> OrderRecord { OrderRecord::new( @@ -131,19 +149,19 @@ impl Eip712TypedZeroExOrder { fn hash_struct(&self) -> [u8; 32] { let mut hash_data = [0u8; 416]; hash_data[0..32].copy_from_slice(&Self::ZEROEX_LIMIT_ORDER_TYPEHASH); - hash_data[44..64].copy_from_slice(self.maker_token.as_fixed_bytes()); - hash_data[76..96].copy_from_slice(self.taker_token.as_fixed_bytes()); + hash_data[44..64].copy_from_slice(self.maker_token.as_slice()); + hash_data[76..96].copy_from_slice(self.taker_token.as_slice()); hash_data[112..128].copy_from_slice(&self.maker_amount.to_be_bytes()); hash_data[144..160].copy_from_slice(&self.taker_amount.to_be_bytes()); hash_data[176..192].copy_from_slice(&self.taker_token_fee_amount.to_be_bytes()); - hash_data[204..224].copy_from_slice(self.maker.as_fixed_bytes()); - hash_data[236..256].copy_from_slice(self.taker.as_fixed_bytes()); - hash_data[268..288].copy_from_slice(self.sender.as_fixed_bytes()); - hash_data[300..320].copy_from_slice(self.fee_recipient.as_fixed_bytes()); - hash_data[320..352].copy_from_slice(self.pool.as_fixed_bytes()); + hash_data[204..224].copy_from_slice(self.maker.as_slice()); + hash_data[236..256].copy_from_slice(self.taker.as_slice()); + hash_data[268..288].copy_from_slice(self.sender.as_slice()); + hash_data[300..320].copy_from_slice(self.fee_recipient.as_slice()); + hash_data[320..352].copy_from_slice(self.pool.as_slice()); hash_data[376..384].copy_from_slice(&self.expiry.to_be_bytes()); - self.salt.to_big_endian(&mut hash_data[384..416]); - signing::keccak256(&hash_data) + hash_data[384..416].copy_from_slice(&self.salt.to_be_bytes::<32>()); + alloy::primitives::keccak256(hash_data).into() } } @@ -151,29 +169,15 @@ struct ZeroExDomainSeparator([u8; 32]); impl ZeroExDomainSeparator { // See - pub fn new(chain_id: u64, contract_addr: H160) -> Self { - /// The EIP-712 domain name used for computing the domain separator. - static DOMAIN_NAME: LazyLock<[u8; 32]> = LazyLock::new(|| signing::keccak256(b"ZeroEx")); - - /// The EIP-712 domain version used for computing the domain separator. - static DOMAIN_VERSION: LazyLock<[u8; 32]> = LazyLock::new(|| signing::keccak256(b"1.0.0")); - - /// The EIP-712 domain type used computing the domain separator. - static DOMAIN_TYPE_HASH: LazyLock<[u8; 32]> = LazyLock::new(|| { - signing::keccak256( - b"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)", - ) - }); - - let abi_encode_string = encode(&[ - Token::FixedBytes((*DOMAIN_TYPE_HASH).into()), - Token::FixedBytes((*DOMAIN_NAME).into()), - Token::FixedBytes((*DOMAIN_VERSION).into()), - Token::Uint(chain_id.into()), - Token::Address(contract_addr), - ]); - - Self(signing::keccak256(abi_encode_string.as_slice())) + pub fn new(chain_id: u64, contract_addr: Address) -> Self { + let domain = alloy::sol_types::eip712_domain! { + name: "ZeroEx", + version: "1.0.0", + chain_id: chain_id, + verifying_contract: contract_addr, + }; + + Self(domain.separator().into()) } pub fn to_domain_separator(&self) -> DomainSeparator { diff --git a/crates/e2e/src/nodes/forked_node.rs b/crates/e2e/src/nodes/forked_node.rs deleted file mode 100644 index 933fcec676..0000000000 --- a/crates/e2e/src/nodes/forked_node.rs +++ /dev/null @@ -1,64 +0,0 @@ -use { - ethcontract::{Account, H160, U256}, - reqwest::Url, - serde_json::json, - std::fmt::Debug, - web3::{Transport, api::Namespace, helpers::CallFuture}, -}; - -#[derive(Debug, Clone)] -pub struct ForkedNodeApi { - transport: T, -} - -impl Namespace for ForkedNodeApi { - fn new(transport: T) -> Self - where - Self: Sized, - { - ForkedNodeApi { transport } - } - - fn transport(&self) -> &T { - &self.transport - } -} - -/// Implements functions that are only available in a forked node. -/// -/// Relevant RPC calls for the Anvil network can be found at: -/// https://book.getfoundry.sh/reference/anvil/ -impl ForkedNodeApi { - pub fn fork(&self, fork_url: &Url) -> CallFuture<(), T::Out> { - CallFuture::new(self.transport.execute( - "anvil_reset", - vec![json!({ "forking": {"jsonRpcUrl": fork_url.to_string()} })], - )) - } - - pub async fn impersonate(&self, address: &H160) -> Result { - let json_address = serde_json::json!(address); - self.transport - .execute("anvil_impersonateAccount", vec![json_address]) - .await?; - - Ok(Account::Local(*address, None)) - } - - pub fn set_chain_id(&self, chain_id: u64) -> CallFuture<(), T::Out> { - let json_chain_id = serde_json::json!(chain_id); - CallFuture::new( - self.transport - .execute("anvil_setChainId", vec![json_chain_id]), - ) - } - - pub fn set_balance(&self, address: &H160, balance: U256) -> CallFuture<(), T::Out> { - let json_address = serde_json::json!(address); - let json_balance = serde_json::json!(format!("{:#032x}", balance)); - CallFuture::new( - self.transport - .execute("anvil_setBalance", vec![json_address, json_balance]), - ) - } -} diff --git a/crates/e2e/src/nodes/local_node.rs b/crates/e2e/src/nodes/local_node.rs deleted file mode 100644 index a0665e3883..0000000000 --- a/crates/e2e/src/nodes/local_node.rs +++ /dev/null @@ -1,81 +0,0 @@ -use { - chrono::{DateTime, Utc}, - ethcontract::{H160, U256}, - std::fmt::Debug, - web3::{Transport, api::Namespace, helpers::CallFuture}, -}; - -#[derive(Debug, Clone)] -pub struct TestNodeApi { - transport: T, -} - -impl Namespace for TestNodeApi { - fn new(transport: T) -> Self - where - Self: Sized, - { - TestNodeApi { transport } - } - - fn transport(&self) -> &T { - &self.transport - } -} - -/// Implements functions that are only available in a testing node. -/// -/// Relevant RPC calls for an Anvil node can be found at: -/// https://book.getfoundry.sh/reference/anvil/ -impl TestNodeApi { - pub fn snapshot(&self) -> CallFuture { - CallFuture::new(self.transport.execute("evm_snapshot", vec![])) - } - - pub fn revert(&self, snapshot_id: &U256) -> CallFuture { - let value_id = serde_json::json!(snapshot_id); - CallFuture::new(self.transport.execute("evm_revert", vec![value_id])) - } - - pub fn set_next_block_timestamp(&self, datetime: &DateTime) -> CallFuture<(), T::Out> { - let json_timestamp = serde_json::json!(datetime.timestamp()); - CallFuture::new( - self.transport - .execute("evm_setNextBlockTimestamp", vec![json_timestamp]), - ) - } - - pub fn mine_pending_block(&self) -> CallFuture { - CallFuture::new(self.transport.execute("evm_mine", vec![])) - } - - pub fn set_automine_enabled(&self, enabled: bool) -> CallFuture<(), T::Out> { - CallFuture::new( - self.transport - .execute("evm_setAutomine", vec![serde_json::json!(enabled)]), - ) - } - - pub fn set_mining_interval(&self, seconds: usize) -> CallFuture<(), T::Out> { - CallFuture::new( - self.transport - .execute("evm_setIntervalMining", vec![serde_json::json!(seconds)]), - ) - } - - pub fn set_block_gas_limit(&self, limit: usize) -> CallFuture { - CallFuture::new( - self.transport - .execute("evm_setBlockGasLimit", vec![serde_json::json!(limit)]), - ) - } - - pub fn set_balance(&self, address: &H160, balance: &U256) -> CallFuture<(), T::Out> { - let json_address = serde_json::json!(address); - let json_balance = serde_json::json!(format!("{:#032x}", balance)); - CallFuture::new( - self.transport - .execute("anvil_setBalance", vec![json_address, json_balance]), - ) - } -} diff --git a/crates/e2e/src/nodes/mod.rs b/crates/e2e/src/nodes/mod.rs index 68eca2bb79..49d1d6ca42 100644 --- a/crates/e2e/src/nodes/mod.rs +++ b/crates/e2e/src/nodes/mod.rs @@ -1,6 +1,3 @@ -pub mod forked_node; -pub mod local_node; - /// The default node URL that should be used for e2e tests. pub const NODE_HOST: &str = "http://127.0.0.1:8545"; diff --git a/crates/e2e/src/setup/colocation.rs b/crates/e2e/src/setup/colocation.rs index 3ad8af6d31..37247e8767 100644 --- a/crates/e2e/src/setup/colocation.rs +++ b/crates/e2e/src/setup/colocation.rs @@ -1,7 +1,6 @@ use { crate::{nodes::NODE_WS_HOST, setup::*}, ::alloy::primitives::Address, - ethcontract::H160, reqwest::Url, std::collections::HashSet, tokio::task::JoinHandle, @@ -13,17 +12,43 @@ pub struct SolverEngine { pub name: String, pub endpoint: Url, pub account: TestAccount, - pub base_tokens: Vec, + pub base_tokens: Vec
, pub merge_solutions: bool, + /// Haircut in basis points (0-10000) for conservative bidding. + pub haircut_bps: u32, + /// Additional EOAs that can submit settlement txs on behalf of the solver + /// via EIP-7702 delegation. When non-empty, enables parallel submission. + pub submission_keys: Vec, } pub async fn start_baseline_solver( name: String, account: TestAccount, weth: Address, - base_tokens: Vec, + base_tokens: Vec
, max_hops: usize, merge_solutions: bool, +) -> SolverEngine { + start_baseline_solver_with_haircut( + name, + account, + weth, + base_tokens, + max_hops, + merge_solutions, + 0, + ) + .await +} + +pub async fn start_baseline_solver_with_haircut( + name: String, + account: TestAccount, + weth: Address, + base_tokens: Vec
, + max_hops: usize, + merge_solutions: bool, + haircut_bps: u32, ) -> SolverEngine { let encoded_base_tokens = encode_base_tokens(base_tokens.clone()); let config_file = config_tmp_file(format!( @@ -44,6 +69,8 @@ uni-v3-node-url = "http://localhost:8545" account, base_tokens, merge_solutions, + haircut_bps, + submission_keys: vec![], } } @@ -98,7 +125,7 @@ http-timeout = "10s" r#" [[liquidity.uniswap-v3]] preset = "uniswap-v3" -graph-url = "{subgraph}" +indexer-config = {{ subgraph = {{ url = "{subgraph}" }} }} "# ), } @@ -134,17 +161,28 @@ pub fn start_driver_with_config_override( .collect(); let solvers = solvers .iter() - .map( - |SolverEngine { - name, - account, - endpoint, - base_tokens: _, - merge_solutions, - }| { - let account = const_hex::encode(account.private_key()); - format!( - r#" + .map(|solver| { + let SolverEngine { + name, + account, + endpoint, + merge_solutions, + haircut_bps, + .. + } = solver; + let account = account.signer.to_bytes(); + let submission_accounts_line = if solver.submission_keys.is_empty() { + String::new() + } else { + let keys: Vec = solver + .submission_keys + .iter() + .map(|k| format!("\"{}\"", k.signer.to_bytes())) + .collect(); + format!("submission-accounts = [{}]\n", keys.join(", ")) + }; + format!( + r#" [[solver]] name = "{name}" endpoint = "{endpoint}" @@ -153,13 +191,13 @@ account = "{account}" merge-solutions = {merge_solutions} quote-using-limit-orders = {quote_using_limit_orders} enable-simulation-bad-token-detection = true -enable-metrics-bad-token-detection = true +enable-metrics-bad-order-detection = true http-time-buffer = "100ms" solving-share-of-deadline = 1.0 -"# - ) - }, - ) +haircut-bps = {haircut_bps} +{submission_accounts_line}"# + ) + }) .collect::>() .join("\n"); let liquidity = liquidity.to_string(contracts); @@ -199,7 +237,7 @@ base-tokens = [{encoded_base_tokens}] gas-price-cap = "1000000000000" [[submission.mempool]] -mempool = "public" +url = "{NODE_HOST}" "#, contracts.gp_settlement.address(), contracts.weth.address(), @@ -227,7 +265,7 @@ mempool = "public" }) } -fn encode_base_tokens(tokens: impl IntoIterator) -> String { +fn encode_base_tokens(tokens: impl IntoIterator) -> String { tokens .into_iter() .map(|token| format!(r#""{token:x}""#)) diff --git a/crates/e2e/src/setup/deploy.rs b/crates/e2e/src/setup/deploy.rs index c5765e2e7c..b1e56f5d2f 100644 --- a/crates/e2e/src/setup/deploy.rs +++ b/crates/e2e/src/setup/deploy.rs @@ -1,25 +1,26 @@ use { - contracts::alloy::{ + alloy::{ + primitives::{Address, B256, U256, keccak256}, + providers::Provider, + sol_types::SolCall, + }, + contracts::{ BalancerV2Authorizer, BalancerV2Vault, CoWSwapEthFlow, FlashLoanRouter, GPv2AllowListAuthentication, GPv2Settlement, + HoneyswapRouter, HooksTrampoline, - InstanceExt, UniswapV2Factory, UniswapV2Router02, WETH9, support::{Balances, Signatures}, }, - ethcontract::{Address, H256}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::CallBuilderExt, model::DomainSeparator, - shared::ethrpc::Web3, + shared::web3::Web3, }; #[derive(Default)] @@ -48,54 +49,53 @@ pub struct Contracts { impl Contracts { pub async fn deployed_with(web3: &Web3, deployed: DeployedContracts) -> Self { let network_id = web3 - .eth() - .chain_id() + .provider + .get_chain_id() .await .expect("get network ID failed") .to_string(); tracing::info!("connected to forked test network {}", network_id); - let gp_settlement = GPv2Settlement::Instance::deployed(&web3.alloy) + let gp_settlement = GPv2Settlement::Instance::deployed(&web3.provider) .await .unwrap(); let balances = match deployed.balances { - Some(address) => Balances::Instance::new(address.into_alloy(), web3.alloy.clone()), - None => Balances::Instance::deployed(&web3.alloy) + Some(address) => Balances::Instance::new(address, web3.provider.clone()), + None => Balances::Instance::deployed(&web3.provider) .await .expect("failed to find balances contract"), }; let signatures = match deployed.signatures { - Some(address) => Signatures::Instance::new(address.into_alloy(), web3.alloy.clone()), - None => Signatures::Instance::deployed(&web3.alloy) + Some(address) => Signatures::Instance::new(address, web3.provider.clone()), + None => Signatures::Instance::deployed(&web3.provider) .await .expect("failed to find signatures contract"), }; - let flashloan_router = FlashLoanRouter::Instance::deployed(&web3.alloy).await.ok(); + let flashloan_router = FlashLoanRouter::Instance::deployed(&web3.provider) + .await + .ok(); Self { chain_id: network_id .parse() .expect("Couldn't parse network ID to u64"), - balancer_vault: BalancerV2Vault::Instance::deployed(&web3.alloy) - .await - .unwrap(), - gp_authenticator: GPv2AllowListAuthentication::Instance::deployed(&web3.alloy) + balancer_vault: BalancerV2Vault::Instance::deployed(&web3.provider) .await .unwrap(), - uniswap_v2_factory: UniswapV2Factory::Instance::deployed(&web3.alloy) + gp_authenticator: GPv2AllowListAuthentication::Instance::deployed(&web3.provider) .await .unwrap(), - uniswap_v2_router: UniswapV2Router02::Instance::deployed(&web3.alloy) + uniswap_v2_factory: UniswapV2Factory::Instance::deployed(&web3.provider) .await .unwrap(), - weth: WETH9::Instance::deployed(&web3.alloy).await.unwrap(), + uniswap_v2_router: uniswap_v2_router_for_chain(web3).await, + weth: WETH9::Instance::deployed(&web3.provider).await.unwrap(), allowance: gp_settlement .vaultRelayer() .call() .await - .expect("Couldn't get vault relayer address") - .into_legacy(), + .expect("Couldn't get vault relayer address"), domain_separator: DomainSeparator( gp_settlement .domainSeparator() @@ -105,11 +105,11 @@ impl Contracts { .0, ), ethflows: vec![ - CoWSwapEthFlow::Instance::deployed(&web3.alloy) + CoWSwapEthFlow::Instance::deployed(&web3.provider) .await .unwrap(), ], - hooks: HooksTrampoline::Instance::deployed(&web3.alloy) + hooks: HooksTrampoline::Instance::deployed(&web3.provider) .await .unwrap(), gp_settlement, @@ -121,67 +121,72 @@ impl Contracts { pub async fn deploy(web3: &Web3) -> Self { let network_id = web3 - .eth() - .chain_id() + .provider + .get_chain_id() .await .expect("get network ID failed") .to_string(); tracing::info!("connected to test network {}", network_id); - let accounts: Vec
= web3.eth().accounts().await.expect("get accounts failed"); + let accounts = web3 + .provider + .get_accounts() + .await + .expect("get accounts failed"); let admin = accounts[0]; - let weth = WETH9::Instance::deploy(web3.alloy.clone()).await.unwrap(); + let weth = WETH9::Instance::deploy(web3.provider.clone()) + .await + .unwrap(); let balancer_authorizer = - BalancerV2Authorizer::Instance::deploy(web3.alloy.clone(), admin.into_alloy()) + BalancerV2Authorizer::Instance::deploy(web3.provider.clone(), admin) .await .unwrap(); let balancer_vault = BalancerV2Vault::Instance::deploy( - web3.alloy.clone(), + web3.provider.clone(), *balancer_authorizer.address(), *weth.address(), - alloy::primitives::U256::ZERO, - alloy::primitives::U256::ZERO, + U256::ZERO, + U256::ZERO, ) .await .unwrap(); - let uniswap_v2_factory = - UniswapV2Factory::Instance::deploy(web3.alloy.clone(), accounts[0].into_alloy()) - .await - .unwrap(); + let uniswap_v2_factory = UniswapV2Factory::Instance::deploy(web3.provider.clone(), admin) + .await + .unwrap(); let uniswap_v2_router = UniswapV2Router02::Instance::deploy( - web3.alloy.clone(), + web3.provider.clone(), *uniswap_v2_factory.address(), *weth.address(), ) .await .unwrap(); - let gp_authenticator = GPv2AllowListAuthentication::Instance::deploy(web3.alloy.clone()) + let gp_authenticator = GPv2AllowListAuthentication::Instance::deploy(web3.provider.clone()) .await .unwrap(); gp_authenticator - .initializeManager(admin.into_alloy()) + .initializeManager(admin) .send_and_watch() .await .expect("failed to initialize manager"); let gp_settlement = GPv2Settlement::Instance::deploy( - web3.alloy.clone(), + web3.provider.clone(), *gp_authenticator.address(), *balancer_vault.address(), ) .await .unwrap(); - let balances = Balances::Instance::deploy(web3.alloy.clone()) + let balances = Balances::Instance::deploy(web3.provider.clone()) .await .unwrap(); - let signatures = Signatures::Instance::deploy(web3.alloy.clone()) + let signatures = Signatures::Instance::deploy(web3.provider.clone()) .await .unwrap(); - contracts::vault::grant_required_roles( + grant_required_roles( &balancer_authorizer, *balancer_vault.address(), gp_settlement @@ -190,15 +195,13 @@ impl Contracts { .await .expect("failed to retrieve Vault relayer contract address"), ) - .await - .expect("failed to authorize Vault relayer"); + .await; let allowance = gp_settlement .vaultRelayer() .call() .await - .expect("Couldn't get vault relayer address") - .into_legacy(); + .expect("Couldn't get vault relayer address"); let domain_separator = DomainSeparator( gp_settlement .domainSeparator() @@ -209,24 +212,25 @@ impl Contracts { ); let ethflow = CoWSwapEthFlow::Instance::deploy( - web3.alloy.clone(), + web3.provider.clone(), *gp_settlement.address(), *weth.address(), ) .await .unwrap(); let ethflow_secondary = CoWSwapEthFlow::Instance::deploy( - web3.alloy.clone(), + web3.provider.clone(), *gp_settlement.address(), *weth.address(), ) .await .unwrap(); - let hooks = HooksTrampoline::Instance::deploy(web3.alloy.clone(), *gp_settlement.address()) - .await - .unwrap(); + let hooks = + HooksTrampoline::Instance::deploy(web3.provider.clone(), *gp_settlement.address()) + .await + .unwrap(); let flashloan_router = - FlashLoanRouter::Instance::deploy(web3.alloy.clone(), *gp_settlement.address()) + FlashLoanRouter::Instance::deploy(web3.provider.clone(), *gp_settlement.address()) .await .unwrap(); @@ -251,10 +255,62 @@ impl Contracts { } } - pub fn default_pool_code(&self) -> H256 { + pub fn default_pool_code(&self) -> B256 { match self.chain_id { - 100 => H256(shared::sources::uniswap_v2::HONEYSWAP_INIT), - _ => H256(shared::sources::uniswap_v2::UNISWAP_INIT), + 100 => B256::new(liquidity_sources::uniswap_v2::HONEYSWAP_INIT), + _ => B256::new(liquidity_sources::uniswap_v2::UNISWAP_INIT), } } } + +/// Resolve a router with the canonical UniswapV2 ABI for the current chain. +async fn uniswap_v2_router_for_chain(web3: &Web3) -> UniswapV2Router02::Instance { + const GNOSIS_CHAIN_ID: u64 = 100; + let chain_id = web3 + .provider + .get_chain_id() + .await + .expect("get chain id failed"); + let address = match chain_id { + // Gnosis: no official Uniswap V2 deployment; use Honeyswap's router, + // which is what xdai's `honeyswap` preset binds in the driver. + GNOSIS_CHAIN_ID => HoneyswapRouter::deployment_address(&chain_id) + .expect("HoneyswapRouter deployment address registered for Gnosis"), + _ => { + return UniswapV2Router02::Instance::deployed(&web3.provider) + .await + .expect("UniswapV2Router02 deployment address registered for this chain"); + } + }; + UniswapV2Router02::Instance::new(address, web3.provider.clone()) +} + +fn role_id(vault: Address) -> B256 { + let mut data = [0u8; 36]; + data[12..32].copy_from_slice(vault.as_slice()); + data[32..36].copy_from_slice(&Call::SELECTOR); + keccak256(data) +} + +async fn grant_required_roles( + authorizer: &BalancerV2Authorizer::Instance, + vault: Address, + vault_relayer: Address, +) { + use contracts::BalancerV2Vault::BalancerV2Vault::{batchSwapCall, manageUserBalanceCall}; + + authorizer + .grantRoles( + vec![ + role_id::(vault).0.into(), + role_id::(vault).0.into(), + ], + vault_relayer, + ) + .send() + .await + .unwrap() + .watch() + .await + .unwrap(); +} diff --git a/crates/e2e/src/setup/fee.rs b/crates/e2e/src/setup/fee.rs deleted file mode 100644 index 25689cb9e1..0000000000 --- a/crates/e2e/src/setup/fee.rs +++ /dev/null @@ -1,99 +0,0 @@ -use chrono::{DateTime, Utc}; - -#[derive(Default)] -pub struct ProtocolFeesConfig { - pub protocol_fees: Vec, - pub upcoming_protocol_fees: Option, -} - -#[derive(Clone)] -pub struct UpcomingProtocolFees { - pub fee_policies: Vec, - pub effective_from_timestamp: DateTime, -} - -#[derive(Clone)] -pub struct ProtocolFee { - pub policy: FeePolicyKind, - pub policy_order_class: FeePolicyOrderClass, -} - -#[derive(Clone)] -pub enum FeePolicyOrderClass { - Market, - Limit, - Any, -} - -impl std::fmt::Display for FeePolicyOrderClass { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - FeePolicyOrderClass::Market => write!(f, "market"), - FeePolicyOrderClass::Limit => write!(f, "limit"), - FeePolicyOrderClass::Any => write!(f, "any"), - } - } -} - -#[derive(Clone)] -pub enum FeePolicyKind { - /// How much of the order's surplus should be taken as a protocol fee. - Surplus { factor: f64, max_volume_factor: f64 }, - /// How much of the order's volume should be taken as a protocol fee. - Volume { factor: f64 }, - /// How much of the order's price improvement should be taken as a protocol - /// fee where price improvement is a difference between the executed price - /// and the best quote. - PriceImprovement { factor: f64, max_volume_factor: f64 }, -} - -impl std::fmt::Display for ProtocolFee { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let order_class_str = &self.policy_order_class.to_string(); - match &self.policy { - FeePolicyKind::Surplus { - factor, - max_volume_factor, - } => write!(f, "surplus:{factor}:{max_volume_factor}:{order_class_str}"), - FeePolicyKind::Volume { factor } => { - write!(f, "volume:{factor}:{order_class_str}") - } - FeePolicyKind::PriceImprovement { - factor, - max_volume_factor, - } => write!( - f, - "priceImprovement:{factor}:{max_volume_factor}:{order_class_str}" - ), - } - } -} - -impl ProtocolFeesConfig { - pub fn into_args(self) -> Vec { - let mut args = Vec::new(); - let fees_str = self - .protocol_fees - .iter() - .map(|fee| fee.to_string()) - .collect::>() - .join(","); - args.push(format!("--fee-policies={fees_str}")); - - if let Some(upcoming_protocol_fees) = &self.upcoming_protocol_fees { - let upcoming_fees_str = upcoming_protocol_fees - .fee_policies - .iter() - .map(|fee| fee.to_string()) - .collect::>() - .join(","); - args.push(format!("--upcoming-fee-policies={}", upcoming_fees_str)); - args.push(format!( - "--upcoming-fee-policies-timestamp={}", - upcoming_protocol_fees.effective_from_timestamp.to_rfc3339() - )); - } - - args - } -} diff --git a/crates/e2e/src/setup/mod.rs b/crates/e2e/src/setup/mod.rs index 454d3b149a..3939588e9c 100644 --- a/crates/e2e/src/setup/mod.rs +++ b/crates/e2e/src/setup/mod.rs @@ -1,8 +1,7 @@ pub mod colocation; mod deploy; -#[macro_use] pub mod onchain_components; -pub mod fee; +pub mod proxy; mod services; mod solver; @@ -10,8 +9,8 @@ use { crate::nodes::{NODE_HOST, Node}, ::alloy::signers::local::{MnemonicBuilder, coins_bip39::English}, anyhow::{Result, anyhow}, - ethcontract::futures::FutureExt, ethrpc::Web3, + futures::FutureExt, std::{ future::Future, io::Write, @@ -95,6 +94,8 @@ const DEFAULT_FILTERS: &[&str] = &[ "solver=debug", "solvers=debug", "orderbook::api::request_summary=off", + "simulator=debug", + "price_estimation=debug", ]; fn with_default_filters(custom_filters: impl IntoIterator) -> Vec @@ -190,7 +191,7 @@ async fn run( false, None, ); - observe::tracing::initialize_reentrant(&obs_config); + observe::tracing::init::initialize_reentrant(&obs_config); observe::panic_hook::install(); services::ensure_e2e_readonly_user().await; diff --git a/crates/e2e/src/setup/onchain_components/mod.rs b/crates/e2e/src/setup/onchain_components/mod.rs index 9eac7591fa..3a9ebc53a8 100644 --- a/crates/e2e/src/setup/onchain_components/mod.rs +++ b/crates/e2e/src/setup/onchain_components/mod.rs @@ -1,132 +1,43 @@ use { - crate::{ - nodes::forked_node::ForkedNodeApi, - setup::{DeployedContracts, deploy::Contracts}, - }, + crate::setup::{DeployedContracts, deploy::Contracts}, ::alloy::{ - network::{Ethereum, NetworkWallet}, + network::{Ethereum, NetworkWallet, TransactionBuilder}, + primitives::{Address, U256, keccak256}, + providers::{ + Provider, + ext::{AnvilApi, ImpersonateConfig}, + }, + rpc::types::TransactionRequest, signers::local::PrivateKeySigner, }, app_data::Hook, - contracts::alloy::{ + contracts::{ ERC20Mintable, GPv2AllowListAuthentication::GPv2AllowListAuthentication, test::CowProtocolToken, }, - core::panic, - ethcontract::{ - Account, - H160, - PrivateKey, - U256, - transaction::{TransactionBuilder, TransactionResult}, - }, - ethrpc::alloy::{ - CallBuilderExt, - ProviderSignerExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::{CallBuilderExt, ProviderSignerExt}, hex_literal::hex, model::{ DomainSeparator, signature::{EcdsaSignature, EcdsaSigningScheme}, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, + number::units::EthUnit, + shared::web3::Web3, std::{borrow::BorrowMut, ops::Deref}, - web3::{ - Transport, - signing::{self, SecretKeyRef}, - }, }; pub mod alloy; pub mod safe; -#[macro_export] -macro_rules! tx_value { - ($acc:expr_2021, $value:expr_2021, $call:expr_2021) => {{ - const NAME: &str = stringify!($call); - $call - .from($acc.clone()) - .value($value) - .send() - .await - .expect(&format!("{} failed", NAME)) - }}; -} - -#[macro_export] -macro_rules! tx { - ($acc:expr_2021, $call:expr_2021) => { - $crate::tx_value!($acc, ethcontract::U256::zero(), $call) - }; -} - -#[macro_export] -macro_rules! deploy { - ($web3:expr, $contract:ident) => { deploy!($web3, $contract ()) }; - ($web3:expr, $contract:ident ( $($param:expr_2021),* $(,)? )) => { - deploy!($web3, $contract ($($param),*) as stringify!($contract)) - }; - ($web3:expr, $contract:ident ( $($param:expr_2021),* $(,)? ) as $name:expr_2021) => {{ - let name = $name; - $contract::builder(&$web3 $(, $param)*) - .deploy() - .await - .unwrap_or_else(|e| panic!("failed to deploy {name}: {e:?}")) - }}; -} - -pub fn to_wei_with_exp(base: u32, exp: usize) -> U256 { - U256::from(base) * U256::exp10(exp) -} - -pub fn to_wei(base: u32) -> U256 { - to_wei_with_exp(base, 18) -} - -/// Returns the provided Eth amount in wei. -/// -/// Equivalent to `amount * 10^18`. -pub fn eth(amount: u32) -> ::alloy::primitives::U256 { - ::alloy::primitives::U256::from(amount) * ::alloy::primitives::utils::Unit::ETHER.wei() -} - -pub async fn hook_for_transaction(tx: TransactionBuilder) -> Hook -where - T: web3::Transport, -{ - let gas_limit = tx - .clone() - .estimate_gas() - .await - .expect("transaction reverted when estimating gas") - .as_u64(); - Hook { - target: tx.to.map(IntoAlloy::into_alloy).unwrap(), - call_data: tx.data.unwrap().0, - gas_limit, - } -} - #[derive(Clone, Debug)] pub struct TestAccount { - account: Account, - private_key: [u8; 32], + pub signer: PrivateKeySigner, } impl TestAccount { - pub fn account(&self) -> &Account { - &self.account - } - - pub fn address(&self) -> H160 { - self.account.address() - } - - pub fn private_key(&self) -> &[u8; 32] { - &self.private_key + pub fn address(&self) -> Address { + self.signer.address() } pub fn sign_typed_data( @@ -138,13 +49,13 @@ impl TestAccount { EcdsaSigningScheme::Eip712, domain_separator, struct_hash, - SecretKeyRef::from(&SecretKey::from_slice(self.private_key()).unwrap()), + &PrivateKeySigner::from_bytes(&self.signer.to_bytes()).unwrap(), ) } - pub async fn nonce(&self, web3: &Web3) -> U256 { - web3.eth() - .transaction_count(self.address(), None) + pub async fn nonce(&self, web3: &Web3) -> u64 { + web3.provider + .get_transaction_count(self.address()) .await .unwrap() } @@ -173,14 +84,11 @@ impl Iterator for AccountGenerator { self.id = self.id.checked_add(1)?; buffer[24..].copy_from_slice(&self.id.to_be_bytes()); - let Ok(pk) = PrivateKey::from_raw(buffer) else { + let Some(signer) = PrivateKeySigner::from_slice(&buffer).ok() else { continue; }; - break Some(TestAccount { - account: Account::Offline(pk, None), - private_key: buffer, - }); + break Some(TestAccount { signer }); } } } @@ -188,14 +96,14 @@ impl Iterator for AccountGenerator { #[derive(Debug)] pub struct MintableToken { contract: ERC20Mintable::Instance, - minter: Account, + minter: Address, } impl MintableToken { - pub async fn mint(&self, to: H160, amount: U256) { + pub async fn mint(&self, to: Address, amount: U256) { self.contract - .mint(to.into_alloy(), amount.into_alloy()) - .from(self.minter.address().into_alloy()) + .mint(to, amount) + .from(self.minter) .send_and_watch() .await .unwrap(); @@ -213,51 +121,45 @@ impl Deref for MintableToken { #[derive(Debug)] pub struct CowToken { contract: CowProtocolToken::Instance, - holder: Account, + holder: Address, } impl CowToken { - pub async fn fund(&self, to: H160, amount: U256) { + pub async fn fund(&self, to: Address, amount: U256) { self.contract - .transfer(to.into_alloy(), amount.into_alloy()) - .from(self.holder.address().into_alloy()) + .transfer(to, amount) + .from(self.holder) .send_and_watch() .await .unwrap(); } - pub async fn permit(&self, owner: &TestAccount, spender: H160, value: U256) -> Hook { + pub async fn permit(&self, owner: &TestAccount, spender: Address, value: U256) -> Hook { let domain = self.contract.DOMAIN_SEPARATOR().call().await.unwrap(); - let nonce = self - .contract - .nonces(owner.address().into_alloy()) - .call() - .await - .unwrap() - .into_legacy(); - let deadline = U256::max_value(); + let nonce = self.contract.nonces(owner.address()).call().await.unwrap(); + let deadline = U256::MAX; let struct_hash = { let mut buffer = [0_u8; 192]; buffer[0..32].copy_from_slice(&hex!( "6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9" )); - buffer[44..64].copy_from_slice(owner.address().as_bytes()); - buffer[76..96].copy_from_slice(spender.as_bytes()); - value.to_big_endian(&mut buffer[96..128]); - nonce.to_big_endian(&mut buffer[128..160]); - deadline.to_big_endian(&mut buffer[160..192]); + buffer[44..64].copy_from_slice(owner.address().as_slice()); + buffer[76..96].copy_from_slice(spender.as_slice()); + buffer[96..128].copy_from_slice(value.to_be_bytes::<32>().as_slice()); + buffer[128..160].copy_from_slice(nonce.to_be_bytes::<32>().as_slice()); + buffer[160..192].copy_from_slice(deadline.to_be_bytes::<32>().as_slice()); - signing::keccak256(&buffer) + keccak256(buffer) }; let signature = owner.sign_typed_data(&DomainSeparator(domain.0), &struct_hash); let permit = self.contract.permit( - owner.address().into_alloy(), - spender.into_alloy(), - value.into_alloy(), - deadline.into_alloy(), + owner.address(), + spender, + value, + deadline, signature.v, signature.r.0.into(), signature.s.0.into(), @@ -325,9 +227,7 @@ impl OnchainComponents { assert_eq!(res.len(), N); for account in &res { - let signer = PrivateKeySigner::from_slice(account.private_key()).unwrap(); - self.web3.wallet.register_signer(signer); - + self.web3.wallet.register_signer(account.signer.clone()); self.send_wei(account.address(), with_wei).await; } @@ -340,13 +240,11 @@ impl OnchainComponents { let solvers = self.make_accounts::(with_wei).await; for solver in &solvers { - self.web3 - .wallet - .register_signer(PrivateKeySigner::from_slice(solver.private_key()).unwrap()); + self.web3.wallet.register_signer(solver.signer.clone()); self.contracts .gp_authenticator - .addSolver(solver.address().into_alloy()) + .addSolver(solver.address()) .send_and_watch() .await .expect("failed to add solver"); @@ -355,18 +253,18 @@ impl OnchainComponents { solvers } - pub async fn set_solver_allowed(&self, solver: H160, allowed: bool) { + pub async fn set_solver_allowed(&self, solver: Address, allowed: bool) { if allowed { self.contracts .gp_authenticator - .addSolver(solver.into_alloy()) + .addSolver(solver) .send_and_watch() .await .expect("failed to add solver"); } else { self.contracts .gp_authenticator - .removeSolver(solver.into_alloy()) + .removeSolver(solver) .send_and_watch() .await .expect("failed to remove solver"); @@ -380,22 +278,9 @@ impl OnchainComponents { with_wei: U256, ) -> [TestAccount; N] { let authenticator = &self.contracts.gp_authenticator; + let auth_manager = authenticator.manager().call().await.unwrap(); - let auth_manager = authenticator.manager().call().await.unwrap().into_legacy(); - - let forked_node_api = self.web3.api::>(); - - forked_node_api - .set_balance(&auth_manager, to_wei(100)) - .await - .expect("could not set auth_manager balance"); - - let impersonated_authenticator = { - forked_node_api - .impersonate(&auth_manager) - .await - .expect("could not impersonate auth_manager"); - + let gpv2_auth = { // we create a new provider without a wallet so that // alloy does not try to sign the tx with it and instead // forwards the tx to the node for signing. This will @@ -407,43 +292,63 @@ impl OnchainComponents { let solvers = self.make_accounts::(with_wei).await; for solver in &solvers { - impersonated_authenticator - .addSolver(solver.address().into_alloy()) - .from(auth_manager.into_alloy()) - .send_and_watch() + self.web3 + .provider + .anvil_send_impersonated_transaction_with_config( + gpv2_auth + .addSolver(solver.address()) + .from(auth_manager) + .into_transaction_request(), + ImpersonateConfig { + fund_amount: Some(100u64.eth()), + stop_impersonate: true, + }, + ) .await - .expect("failed to add solver"); + .unwrap() + .watch() + .await + .unwrap(); } if let Some(router) = &self.contracts.flashloan_router { - impersonated_authenticator - .addSolver(*router.address()) - .from(auth_manager.into_alloy()) - .send_and_watch() + self.web3 + .provider + .anvil_send_impersonated_transaction_with_config( + gpv2_auth + .addSolver(*router.address()) + .from(auth_manager) + .into_transaction_request(), + ImpersonateConfig { + fund_amount: Some(100u64.eth()), + stop_impersonate: true, + }, + ) + .await + .unwrap() + .watch() .await - .expect("failed to add flashloan wrapper"); + .unwrap(); } solvers } /// Deploy `N` tokens without any onchain liquidity - pub async fn deploy_tokens(&self, minter: &Account) -> [MintableToken; N] { + pub async fn deploy_tokens(&self, minter: Address) -> [MintableToken; N] { let mut res = Vec::with_capacity(N); for _ in 0..N { - let contract_address = ERC20Mintable::Instance::deploy_builder(self.web3.alloy.clone()) + let contract_address = ERC20Mintable::Instance::deploy_builder(self.web3.provider.clone()) // We can't escape the .from here because we need to ensure Minter permissions later on - .from(minter.address().into_alloy()) + .from(minter) .deploy() .await .expect("ERC20Mintable deployment failed"); - let contract = ERC20Mintable::Instance::new(contract_address, self.web3.alloy.clone()); + let contract = + ERC20Mintable::Instance::new(contract_address, self.web3.provider.clone()); - res.push(MintableToken { - contract, - minter: minter.clone(), - }); + res.push(MintableToken { contract, minter }); } res.try_into().unwrap() @@ -455,15 +360,13 @@ impl OnchainComponents { token_amount: U256, weth_amount: U256, ) -> [MintableToken; N] { - let minter = Account::Local( - self.web3 - .eth() - .accounts() - .await - .expect("getting accounts failed")[0], - None, - ); - let tokens = self.deploy_tokens::(&minter).await; + let minter = self + .web3 + .provider + .get_accounts() + .await + .expect("getting accounts failed")[0]; + let tokens = self.deploy_tokens::(minter).await; self.seed_weth_uni_v2_pools(tokens.iter(), token_amount, weth_amount) .await; tokens @@ -477,8 +380,8 @@ impl OnchainComponents { ) { for MintableToken { contract, minter } in tokens { contract - .mint(minter.address().into_alloy(), token_amount.into_alloy()) - .from(minter.address().into_alloy()) + .mint(*minter, token_amount) + .from(*minter) .send_and_watch() .await .unwrap(); @@ -486,8 +389,8 @@ impl OnchainComponents { self.contracts .weth .deposit() - .value(weth_amount.into_alloy()) - .from(minter.address().into_alloy()) + .value(weth_amount) + .from(*minter) .send_and_watch() .await .unwrap(); @@ -495,28 +398,22 @@ impl OnchainComponents { self.contracts .uniswap_v2_factory .createPair(*contract.address(), *self.contracts.weth.address()) - .from(minter.address().into_alloy()) + .from(*minter) .send_and_watch() .await .unwrap(); contract - .approve( - *self.contracts.uniswap_v2_router.address(), - token_amount.into_alloy(), - ) - .from(minter.address().into_alloy()) + .approve(*self.contracts.uniswap_v2_router.address(), token_amount) + .from(*minter) .send_and_watch() .await .unwrap(); self.contracts .weth - .approve( - *self.contracts.uniswap_v2_router.address(), - weth_amount.into_alloy(), - ) - .from(minter.address().into_alloy()) + .approve(*self.contracts.uniswap_v2_router.address(), weth_amount) + .from(*minter) .send_and_watch() .await .unwrap(); @@ -526,14 +423,14 @@ impl OnchainComponents { .addLiquidity( *contract.address(), *self.contracts.weth.address(), - token_amount.into_alloy(), - weth_amount.into_alloy(), - ::alloy::primitives::U256::ZERO, - ::alloy::primitives::U256::ZERO, - minter.address().into_alloy(), - ::alloy::primitives::U256::MAX, + token_amount, + weth_amount, + U256::ZERO, + U256::ZERO, + *minter, + U256::MAX, ) - .from(minter.address().into_alloy()) + .from(*minter) .send_and_watch() .await .unwrap(); @@ -545,36 +442,30 @@ impl OnchainComponents { asset_a: (&MintableToken, U256), asset_b: (&MintableToken, U256), ) { - let lp = &asset_a.0.minter; - asset_a.0.mint(lp.address(), asset_a.1).await; - asset_b.0.mint(lp.address(), asset_b.1).await; + let lp = asset_a.0.minter; + asset_a.0.mint(lp, asset_a.1).await; + asset_b.0.mint(lp, asset_b.1).await; self.contracts .uniswap_v2_factory .createPair(*asset_a.0.address(), *asset_b.0.address()) - .from(lp.address().into_alloy()) + .from(lp) .send_and_watch() .await .unwrap(); asset_a .0 - .approve( - *self.contracts.uniswap_v2_router.address(), - asset_a.1.into_alloy(), - ) - .from(lp.address().into_alloy()) + .approve(*self.contracts.uniswap_v2_router.address(), asset_a.1) + .from(lp) .send_and_watch() .await .unwrap(); asset_b .0 - .approve( - *self.contracts.uniswap_v2_router.address(), - asset_b.1.into_alloy(), - ) - .from(lp.address().into_alloy()) + .approve(*self.contracts.uniswap_v2_router.address(), asset_b.1) + .from(lp) .send_and_watch() .await .unwrap(); @@ -583,14 +474,14 @@ impl OnchainComponents { .addLiquidity( *asset_a.0.address(), *asset_b.0.address(), - asset_a.1.into_alloy(), - asset_b.1.into_alloy(), - ::alloy::primitives::U256::ZERO, - ::alloy::primitives::U256::ZERO, - lp.address().into_alloy(), - ::alloy::primitives::U256::MAX, + asset_a.1, + asset_b.1, + U256::ZERO, + U256::ZERO, + lp, + U256::MAX, ) - .from(lp.address().into_alloy()) + .from(lp) .send_and_watch() .await .unwrap(); @@ -600,32 +491,32 @@ impl OnchainComponents { /// /// This can be used to modify the pool reserves during a test. pub async fn mint_token_to_weth_uni_v2_pool(&self, token: &MintableToken, amount: U256) { - let pair = contracts::alloy::IUniswapLikePair::Instance::new( + let pair = contracts::IUniswapLikePair::Instance::new( self.contracts .uniswap_v2_factory .getPair(*self.contracts.weth.address(), *token.address()) .call() .await .expect("failed to get Uniswap V2 pair"), - self.web3.alloy.clone(), + self.web3.provider.clone(), ); assert!(!pair.address().is_zero(), "Uniswap V2 pair is not deployed"); // Mint amount + 1 to the pool, and then swap out 1 of the minted token // in order to force it to update its K-value. - token.mint(pair.address().into_legacy(), amount + 1).await; + token.mint(*pair.address(), amount + U256::ONE).await; let (out0, out1) = if self.contracts.weth.address() < token.address() { (1, 0) } else { (0, 1) }; pair.swap( - ::alloy::primitives::U256::from(out0), - ::alloy::primitives::U256::from(out1), - token.minter.address().into_alloy(), + U256::from(out0), + U256::from(out1), + token.minter, Default::default(), ) - .from(token.minter.address().into_alloy()) + .from(token.minter) .send_and_watch() .await .expect("Uniswap V2 pair couldn't mint"); @@ -633,12 +524,11 @@ impl OnchainComponents { pub async fn deploy_cow_token(&self, supply: U256) -> CowToken { let holder = NetworkWallet::::default_signer_address(&self.web3().wallet); - let holder = Account::Local(holder.into_legacy(), None); let contract = CowProtocolToken::CowProtocolToken::deploy( - self.web3.alloy.clone(), - holder.address().into_alloy(), - holder.address().into_alloy(), - supply.into_alloy(), + self.web3.provider.clone(), + holder, + holder, + supply, ) .await .expect("CowProtocolToken deployment failed"); @@ -656,8 +546,8 @@ impl OnchainComponents { self.contracts .weth .deposit() - .value(weth_amount.into_alloy()) - .from(cow.holder.address().into_alloy()) + .value(weth_amount) + .from(cow.holder) .send_and_watch() .await .unwrap(); @@ -665,25 +555,19 @@ impl OnchainComponents { self.contracts .uniswap_v2_factory .createPair(*cow.address(), *self.contracts.weth.address()) - .from(cow.holder.address().into_alloy()) + .from(cow.holder) + .send_and_watch() + .await + .unwrap(); + cow.approve(*self.contracts.uniswap_v2_router.address(), cow_amount) + .from(cow.holder) .send_and_watch() .await .unwrap(); - cow.approve( - *self.contracts.uniswap_v2_router.address(), - cow_amount.into_alloy(), - ) - .from(cow.holder.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); self.contracts .weth - .approve( - *self.contracts.uniswap_v2_router.address(), - weth_amount.into_alloy(), - ) - .from(cow.holder.address().into_alloy()) + .approve(*self.contracts.uniswap_v2_router.address(), weth_amount) + .from(cow.holder) .send_and_watch() .await .unwrap(); @@ -692,14 +576,14 @@ impl OnchainComponents { .addLiquidity( *cow.address(), *self.contracts.weth.address(), - cow_amount.into_alloy(), - weth_amount.into_alloy(), - ::alloy::primitives::U256::ZERO, - ::alloy::primitives::U256::ZERO, - cow.holder.address().into_alloy(), - ::alloy::primitives::U256::MAX, + cow_amount, + weth_amount, + U256::ZERO, + U256::ZERO, + cow.holder, + U256::MAX, ) - .from(cow.holder.address().into_alloy()) + .from(cow.holder) .send_and_watch() .await .unwrap(); @@ -707,35 +591,29 @@ impl OnchainComponents { cow } - pub async fn send_wei(&self, to: H160, amount: U256) { - let balance_before = self.web3.eth().balance(to, None).await.unwrap(); - let receipt = TransactionBuilder::new(self.web3.legacy.clone()) - .value(amount) - .to(to) - .send() + pub async fn send_wei(&self, to: Address, amount: U256) { + let balance_before = self.web3.provider.get_balance(to).await.unwrap(); + self.web3 + .provider + .send_transaction(TransactionRequest::default().with_to(to).with_value(amount)) + .await + .unwrap() + .watch() .await .unwrap(); - let TransactionResult::Receipt(receipt) = receipt else { - panic!("expected to get a transaction receipt"); - }; - assert_eq!(receipt.status, Some(1.into())); // There seems to be a bug in anvil where sending ETH does not work // reliably with a forked node. On some block numbers the transaction // supposedly succeeds but the balances still don't get changed. // If you hit this assert try using a different block number for your // forked test. - let balance_after = self.web3.eth().balance(to, None).await.unwrap(); + let balance_after = self.web3.provider.get_balance(to).await.unwrap(); assert_eq!(balance_after, balance_before + amount); } pub async fn mint_block(&self) { tracing::info!("mining block"); - self.web3 - .transport() - .execute("evm_mine", vec![]) - .await - .unwrap(); + self.web3.provider.evm_mine(None).await.unwrap(); } pub fn contracts(&self) -> &Contracts { diff --git a/crates/e2e/src/setup/onchain_components/safe.rs b/crates/e2e/src/setup/onchain_components/safe.rs index fd92cc71a9..550cc27a84 100644 --- a/crates/e2e/src/setup/onchain_components/safe.rs +++ b/crates/e2e/src/setup/onchain_components/safe.rs @@ -1,21 +1,17 @@ use { super::{OnchainComponents, TestAccount}, alloy::{ - primitives::{Address, Bytes, U256}, + primitives::{Address, Bytes, U256, keccak256}, providers::Provider, rpc::types::TransactionRequest, }, - contracts::alloy::{ + contracts::{ GnosisSafe::{self, GnosisSafe::execTransactionCall}, GnosisSafeCompatibilityFallbackHandler, GnosisSafeProxy, GnosisSafeProxyFactory, }, - ethcontract::transaction::TransactionBuilder, - ethrpc::{ - AlloyProvider, - alloy::{CallBuilderExt, conversions::IntoAlloy}, - }, + ethrpc::{AlloyProvider, alloy::CallBuilderExt}, hex_literal::hex, model::{ DomainSeparator, @@ -23,7 +19,6 @@ use { signature::{Signature, hashed_eip712_message}, }, std::marker::PhantomData, - web3::signing::{self}, }; pub struct Infrastructure { @@ -69,10 +64,7 @@ impl Infrastructure { let safe = GnosisSafe::Instance::new(safe_proxy, self.provider.clone()); safe.setup( - owners - .into_iter() - .map(|owner| owner.address().into_alloy()) - .collect(), + owners.into_iter().map(|owner| owner.address()).collect(), U256::from(threshold), Address::default(), // delegate call Bytes::default(), // delegate call bytes @@ -134,31 +126,14 @@ impl Safe { Default::default(), Default::default(), Default::default(), - crate::setup::safe::gnosis_safe_prevalidated_signature( - self.owner.address().into_alloy(), - ), + crate::setup::safe::gnosis_safe_prevalidated_signature(self.owner.address()), ) - .from(self.owner.address().into_alloy()) + .from(self.owner.address()) .send_and_watch() .await .unwrap(); } - pub async fn exec_call( - &self, - tx: ethcontract::dyns::DynMethodBuilder, - ) { - let TransactionBuilder { - data, value, to, .. - } = tx.tx; - self.exec_alloy_tx( - to.unwrap().into_alloy(), - value.unwrap_or_default().into_alloy(), - alloy::primitives::Bytes::from(data.unwrap_or_default().0), - ) - .await; - } - pub async fn exec_alloy_call(&self, tx: TransactionRequest) { let to = tx.to.unwrap().into_to().unwrap(); let value = tx.value.unwrap_or_default(); @@ -182,8 +157,10 @@ impl Safe { to: alloy::primitives::Address, data: Vec, nonce: alloy::primitives::U256, - ) -> alloy::contract::CallBuilder<&contracts::alloy::Provider, PhantomData> - { + ) -> alloy::contract::CallBuilder< + &alloy::providers::DynProvider, + PhantomData, + > { let signature = self.sign({ // `SafeTx` struct hash computation ported from the Safe Solidity code: // @@ -195,7 +172,7 @@ impl Safe { "bb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8" )); buffer[44..64].copy_from_slice(to.as_slice()); - buffer[96..128].copy_from_slice(&signing::keccak256(&data)); + buffer[96..128].copy_from_slice(keccak256(&data).as_slice()); nonce.copy_be_bytes_to(&mut buffer[320..352]); // Since the [`sign_transaction`] transaction method only accepts @@ -203,7 +180,7 @@ impl Safe { // We can leave the rest of the buffer 0-ed out (as we have 0 // values for those fields). - signing::keccak256(&buffer) + *keccak256(buffer) }); self.contract.execTransaction( @@ -232,9 +209,9 @@ impl Safe { // "60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca" )); - buffer[32..64].copy_from_slice(&signing::keccak256(message)); + buffer[32..64].copy_from_slice(keccak256(message).as_slice()); - signing::keccak256(&buffer) + *keccak256(buffer) }) } @@ -267,7 +244,7 @@ impl Safe { self.chain_id.copy_be_bytes_to(&mut buffer[32..64]); buffer[76..96].copy_from_slice(self.contract.address().as_slice()); - DomainSeparator(signing::keccak256(&buffer)) + DomainSeparator(*keccak256(buffer)) } /// Creates an ECDSA signature with the [`Safe`]'s `owner` and encodes to @@ -278,8 +255,8 @@ impl Safe { // Signature format specified here: // [ - signature.r.as_bytes(), - signature.s.as_bytes(), + signature.r.as_slice(), + signature.s.as_slice(), &[signature.v], ] .concat() diff --git a/crates/e2e/src/setup/proxy.rs b/crates/e2e/src/setup/proxy.rs new file mode 100644 index 0000000000..726b0cf90c --- /dev/null +++ b/crates/e2e/src/setup/proxy.rs @@ -0,0 +1,210 @@ +//! Simple HTTP reverse proxy with automatic failover for e2e testing. +//! +//! This module provides a test-only reverse proxy that simulates how Kubernetes +//! service pools work in production. In production, when multiple instances of +//! a service run (e.g., autopilot with leader/follower pattern), Kubernetes +//! routes traffic to the active instance and automatically fails over to a +//! backup when the primary becomes unavailable. +//! +//! The proxy maintains a queue of backend URLs and automatically rotates +//! through them when the currently active backend fails. This allows e2e tests +//! to simulate production failover behavior without requiring a full k8s +//! cluster. + +use { + axum::{ + Router, + body::Body, + http::Request, + response::{IntoResponse, Response}, + }, + std::{collections::VecDeque, net::SocketAddr, sync::Arc}, + tokio::{sync::RwLock, task::JoinHandle}, + url::Url, +}; + +pub type OnRequest = Arc; + +/// HTTP reverse proxy with automatic failover that permanently switches +/// to the fallback backend when the current backend fails. +/// +/// This simulates k8s service pools where traffic is automatically routed +/// to healthy backend instances. +pub struct ReverseProxy { + _server_handle: JoinHandle<()>, +} + +#[derive(Clone)] +struct ProxyState { + backends: Arc>>, + on_request: Option, +} + +impl ProxyState { + /// Returns the current active backend URL. + async fn get_current_backend(&self) -> Url { + self.backends + .read() + .await + .front() + .cloned() + .expect("backends should never be empty") + } + + /// Rotates to the next backend by moving the current backend to the end of + /// the queue. + async fn rotate_backends(&self) { + let mut backends = self.backends.write().await; + if let Some(current) = backends.pop_front() { + backends.push_back(current); + } + } + + /// Returns the total number of backends configured. + /// + /// Used to determine how many retry attempts to make before giving up. + async fn backend_count(&self) -> usize { + self.backends.read().await.len() + } +} + +impl ReverseProxy { + /// Start a new proxy server with automatic failover between backends + /// + /// # Panics + /// Panics if `backends` is empty. At least one backend URL is required. + pub fn start(listen_addr: SocketAddr, backends: &[Url]) -> Self { + Self::start_inner(listen_addr, backends, None) + } + + /// Start a new proxy server with a callback invoked on each request + /// before it is forwarded to the backend. + /// + /// # Panics + /// Panics if `backends` is empty. At least one backend URL is required. + pub fn start_with_callback( + listen_addr: SocketAddr, + backends: &[Url], + on_request: OnRequest, + ) -> Self { + Self::start_inner(listen_addr, backends, Some(on_request)) + } + + fn start_inner( + listen_addr: SocketAddr, + backends: &[Url], + on_request: Option, + ) -> Self { + assert!( + !backends.is_empty(), + "At least one backend URL is required for the proxy" + ); + + let backends_queue: VecDeque = backends.iter().cloned().collect(); + + let state = ProxyState { + backends: Arc::new(RwLock::new(backends_queue)), + on_request, + }; + + let backends_log: Vec = backends.to_vec(); + let server_handle = tokio::spawn(serve(listen_addr, backends_log, state)); + + Self { + _server_handle: server_handle, + } + } +} + +async fn serve(listen_addr: SocketAddr, backends: Vec, state: ProxyState) { + let client = reqwest::Client::new(); + + let proxy_handler = move |req: Request| { + let client = client.clone(); + let state = state.clone(); + async move { handle_request(client, state, req).await } + }; + + let app = Router::new().fallback(proxy_handler); + + tracing::info!(?listen_addr, ?backends, "starting reverse proxy"); + let listener = tokio::net::TcpListener::bind(listen_addr).await.unwrap(); + axum::serve(listener, app).await.unwrap(); +} + +async fn handle_request( + client: reqwest::Client, + state: ProxyState, + req: Request, +) -> Response { + let (parts, body) = req.into_parts(); + + // Convert body to bytes once for reuse across retries + // SAFETY: usize::MAX is ok here because it's a test + let body_bytes = match axum::body::to_bytes(body, usize::MAX).await { + Ok(bytes) => bytes, + Err(err) => { + return ( + axum::http::StatusCode::BAD_REQUEST, + format!("Failed to read request body: {}", err), + ) + .into_response(); + } + }; + + if let Some(on_request) = &state.on_request { + on_request(&parts, &body_bytes); + } + + let backend_count = state.backend_count().await; + + for attempt in 0..backend_count { + let backend = state.get_current_backend().await; + + match try_backend(&client, &parts, body_bytes.to_vec(), &backend).await { + Ok(response) => return response.into_response(), + Err(err) => { + tracing::warn!(?err, ?backend, attempt, "backend failed, rotating to next"); + state.rotate_backends().await; + } + } + } + + ( + axum::http::StatusCode::BAD_GATEWAY, + "All backends unavailable", + ) + .into_response() +} + +async fn try_backend( + client: &reqwest::Client, + parts: &axum::http::request::Parts, + body: Vec, + backend: &Url, +) -> Result<(axum::http::StatusCode, Vec), reqwest::Error> { + let path = parts + .uri + .path_and_query() + .map(|pq| pq.as_str()) + .unwrap_or(""); + + // Build the full URL by combining backend and path. + // Url Display always includes a trailing slash, so trim it to avoid + // double slashes (e.g. "http://host:port//path"). + let url = format!("{}{}", backend.as_str().trim_end_matches('/'), path); + // Build a reqwest request with the same method + let mut backend_req = client.request(parts.method.clone(), &url); + // Forward all headers from the original request + for (name, value) in &parts.headers { + backend_req = backend_req.header(name, value); + } + + // Attach the body + backend_req = backend_req.body(body); + + let backend_resp = backend_req.send().await?; + let status = axum::http::StatusCode::from_u16(backend_resp.status().as_u16()).unwrap(); + let bytes = backend_resp.bytes().await?; + Ok((status, bytes.to_vec())) +} diff --git a/crates/e2e/src/setup/services.rs b/crates/e2e/src/setup/services.rs index 3930a37d47..b0124ce0fc 100644 --- a/crates/e2e/src/setup/services.rs +++ b/crates/e2e/src/setup/services.rs @@ -1,33 +1,45 @@ use { super::TestAccount, - crate::setup::{ - Contracts, - OnchainComponents, - TIMEOUT, - colocation::{self, SolverEngine}, - wait_for_condition, + crate::{ + nodes::NODE_WS_HOST, + setup::{ + Contracts, + OnchainComponents, + TIMEOUT, + colocation::{self, SolverEngine}, + wait_for_condition, + }, + }, + alloy::{ + primitives::{Address, B256, U256}, + providers::ext::AnvilApi, }, app_data::{AppDataDocument, AppDataHash}, autopilot::infra::persistence::dto, - clap::Parser, - ethcontract::{H160, H256}, + configs::{ + autopilot::{ + Configuration, + ethflow::EthflowConfig, + native_price::NativePriceConfig, + run_loop::RunLoopConfig, + }, + native_price_estimators::{NativePriceEstimator, NativePriceEstimators}, + order_quoting::{ExternalSolver, OrderQuoting}, + shared::{GasEstimatorType, SharedConfig}, + test_util::TestDefault, + }, + ethrpc::Web3, model::{ - order::{Order, OrderCreation, OrderUid}, + AuctionId, + order::{CancellationPayload, Order, OrderCreation, OrderUid}, quote::{NativeTokenPrice, OrderQuoteRequest, OrderQuoteResponse}, solver_competition_v2, trade::Trade, }, reqwest::{Client, StatusCode, Url}, - shared::ethrpc::Web3, sqlx::Connection, - std::{ - collections::{HashMap, hash_map::Entry}, - ops::DerefMut, - sync::LazyLock, - time::Duration, - }, + std::{ops::DerefMut, str::FromStr, time::Duration}, tokio::task::JoinHandle, - web3::Transport, }; pub const API_HOST: &str = "http://127.0.0.1:8080"; @@ -37,24 +49,19 @@ pub const ACCOUNT_ENDPOINT: &str = "/api/v1/account"; pub const AUCTION_ENDPOINT: &str = "/api/v1/auction"; pub const TRADES_ENDPOINT: &str = "/api/v1/trades"; pub const VERSION_ENDPOINT: &str = "/api/v1/version"; +pub const READY_ENDPOINT: &str = "/api/v1/ready"; pub const SOLVER_COMPETITION_ENDPOINT: &str = "/api/v2/solver_competition"; const LOCAL_DB_URL: &str = "postgresql://"; -static LOCAL_READ_ONLY_DB_URL: LazyLock = LazyLock::new(|| { - format!( - "postgresql://readonly@localhost/{db}", - db = std::env::var("USER").unwrap() - ) -}); fn order_status_endpoint(uid: &OrderUid) -> String { format!("/api/v1/orders/{uid}/status") } -fn orders_for_tx_endpoint(tx_hash: &H256) -> String { +fn orders_for_tx_endpoint(tx_hash: &B256) -> String { format!("/api/v1/transactions/{tx_hash:?}/orders") } -fn orders_for_owner(owner: &H160, offset: u64, limit: u64) -> String { +fn orders_for_owner(owner: &Address, offset: u64, limit: u64) -> String { format!("{ACCOUNT_ENDPOINT}/{owner:?}/orders?offset={offset}&limit={limit}") } @@ -122,48 +129,28 @@ impl<'a> Services<'a> { ServicesBuilder::new() } - fn api_autopilot_arguments(&self) -> impl Iterator + use<> { - [ - "--native-price-estimators=test_quoter|http://localhost:11088/test_solver".to_string(), - "--amount-to-estimate-prices-with=1000000000000000000".to_string(), - "--block-stream-poll-interval=1s".to_string(), - "--simulation-node-url=http://localhost:8545".to_string(), - "--native-price-cache-max-age=2s".to_string(), - "--native-price-prefetch-time=500ms".to_string(), - format!( - "--hooks-contract-address={:?}", - self.contracts.hooks.address() - ), - "--db-read-url".to_string(), - LOCAL_READ_ONLY_DB_URL.clone(), - ] - .into_iter() - } - - fn api_autopilot_solver_arguments(&self) -> impl Iterator + use<> { - [ - "--baseline-sources=None".to_string(), - "--network-block-interval=1s".to_string(), - "--solver-competition-auth=super_secret_key".to_string(), - format!( - "--settlement-contract-address={:?}", - self.contracts.gp_settlement.address() - ), - format!( - "--balances-contract-address={:?}", - self.contracts.balances.address() - ), - format!( - "--signatures-contract-address={:?}", - self.contracts.signatures.address() - ), - format!("--native-token-address={:?}", self.contracts.weth.address()), - format!( - "--balancer-v2-vault-address={:?}", - self.contracts.balancer_vault.address() - ), - ] - .into_iter() + fn shared_config(&self) -> configs::shared::SharedConfig { + configs::shared::SharedConfig { + current_block: configs::shared::CurrentBlockConfig { + poll_interval: Some(Duration::from_secs(1)), + ws_url: Some(NODE_WS_HOST.parse().unwrap()), + }, + simulation_node_url: Some("http://localhost:8545".parse().unwrap()), + contracts: configs::shared::ContractAddresses { + settlement: Some(*self.contracts.gp_settlement.address()), + balances: Some(*self.contracts.balances.address()), + signatures: Some(*self.contracts.signatures.address()), + native_token: Some(*self.contracts.weth.address()), + hooks: Some(*self.contracts.hooks.address()), + balancer_v2_vault: Some(*self.contracts.balancer_vault.address()), + flashloan_router: self + .contracts + .flashloan_router + .as_ref() + .map(|c| *c.address()), + }, + ..Default::default() + } } /// Start the autopilot service in a background task. @@ -174,38 +161,36 @@ impl<'a> Services<'a> { /// Allows to externally control the shutdown of autopilot. pub async fn start_autopilot_with_shutdown_controller( &self, - solve_deadline: Option, - extra_args: Vec, + min_solve_time: Option, + config: configs::autopilot::Configuration, control: autopilot::shutdown_controller::ShutdownController, ) -> JoinHandle<()> { - let solve_deadline = solve_deadline.unwrap_or(Duration::from_secs(2)); + let min_solve_time = min_solve_time.unwrap_or(Duration::from_secs(2)); let ethflow_contracts = self .contracts .ethflows .iter() - .map(|c| format!("{:?}", c.address())) - .collect::>() - .join(","); - - let args = [ - "autopilot".to_string(), - "--non-settling-solvers-blacklisting-enabled=false".to_string(), - "--low-settling-solvers-blacklisting-enabled=false".to_string(), - "--max-run-loop-delay=100ms".to_string(), - "--run-loop-native-price-timeout=500ms".to_string(), - format!("--ethflow-contracts={ethflow_contracts}"), - "--skip-event-sync=true".to_string(), - format!("--solve-deadline={solve_deadline:?}"), - ] - .into_iter() - .chain(self.api_autopilot_solver_arguments()) - .chain(self.api_autopilot_arguments()) - .chain(extra_args) - .collect(); - let args = ignore_overwritten_cli_params(args); - - let args = autopilot::arguments::Arguments::try_parse_from(args).unwrap(); - let join_handle = tokio::task::spawn(autopilot::run(args, control)); + .map(|c| *c.address()) + .collect::>(); + + let config = configs::autopilot::Configuration { + shared: configs::shared::SharedConfig { + volume_fee_bucket_overrides: config.shared.volume_fee_bucket_overrides.clone(), + enable_sell_equals_buy_volume_fee: config.shared.enable_sell_equals_buy_volume_fee, + ..self.shared_config() + }, + ethflow: EthflowConfig { + contracts: ethflow_contracts, + ..config.ethflow + }, + run_loop: RunLoopConfig { + min_solve_time, + ..config.run_loop + }, + ..config + }; + + let join_handle = tokio::task::spawn(autopilot::run(config, control)); self.wait_until_autopilot_ready().await; join_handle @@ -219,11 +204,11 @@ impl<'a> Services<'a> { pub async fn start_autopilot( &self, solve_deadline: Option, - extra_args: Vec, + config: configs::autopilot::Configuration, ) -> JoinHandle<()> { self.start_autopilot_with_shutdown_controller( solve_deadline, - extra_args, + config, autopilot::shutdown_controller::ShutdownController::default(), ) .await @@ -231,77 +216,91 @@ impl<'a> Services<'a> { /// Start the api service in a background tasks. /// Wait until the service is responsive. - pub async fn start_api(&self, extra_args: Vec) { - let args: Vec<_> = [ - "orderbook".to_string(), - "--quote-timeout=10s".to_string(), - "--quote-verification=enforce-when-possible".to_string(), - ] - .into_iter() - .chain(self.api_autopilot_solver_arguments()) - .chain(self.api_autopilot_arguments()) - .chain(extra_args) - .collect(); - let args = ignore_overwritten_cli_params(args); - - let args = orderbook::arguments::Arguments::try_parse_from(args).unwrap(); - tokio::task::spawn(orderbook::run(args)); + pub async fn start_api(&self, config: configs::orderbook::Configuration) { + let config = configs::orderbook::Configuration { + shared: configs::shared::SharedConfig { + volume_fee_bucket_overrides: config.shared.volume_fee_bucket_overrides.clone(), + enable_sell_equals_buy_volume_fee: config.shared.enable_sell_equals_buy_volume_fee, + ..self.shared_config() + }, + ..config + }; + + tokio::task::spawn(orderbook::run(config)); Self::wait_for_api_to_come_up().await; } /// Starts a basic version of the protocol with a single baseline solver. pub async fn start_protocol(&self, solver: TestAccount) { - self.start_protocol_with_args(Default::default(), solver) + self.start_protocol_with_args( + configs::autopilot::Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + } + + pub async fn start_protocol_with_args( + &self, + autopilot_config: configs::autopilot::Configuration, + orderbook_config: configs::orderbook::Configuration, + solver: TestAccount, + ) { + self.start_protocol_with_args_and_haircut(autopilot_config, orderbook_config, solver, 0) .await; } - pub async fn start_protocol_with_args(&self, args: ExtraServiceArgs, solver: TestAccount) { + pub async fn start_protocol_with_args_and_haircut( + &self, + autopilot_config: configs::autopilot::Configuration, + orderbook_config: configs::orderbook::Configuration, + solver: TestAccount, + haircut_bps: u32, + ) { colocation::start_driver( self.contracts, vec![ - colocation::start_baseline_solver( + colocation::start_baseline_solver_with_haircut( "test_solver".into(), solver.clone(), *self.contracts.weth.address(), vec![], 1, true, + haircut_bps, ) .await, ], colocation::LiquidityProvider::UniswapV2, false, ); - self.start_autopilot( - None, - [ - vec![ - format!( - "--drivers=test_solver|http://localhost:11088/test_solver|{}|requested-timeout-on-problems", - const_hex::encode(solver.address()) - ), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - "--gas-estimators=http://localhost:11088/gasprice".to_string(), - ], - args.autopilot, - ] - .concat(), - ) - .await; - self.start_api( - [ - vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - "--gas-estimators=http://localhost:11088/gasprice".to_string(), - ], - args.api, - ] - .concat(), - ) - .await; + + let test_quoter = ExternalSolver::new("test_quoter", "http://localhost:11088/test_solver"); + + let autopilot_config = Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![test_quoter.clone()]), + shared: SharedConfig { + gas_estimators: vec![GasEstimatorType::Driver { + url: Url::from_str("http://localhost:11088/gasprice").unwrap(), + }], + ..autopilot_config.shared + }, + ..autopilot_config + }; + let orderbook_config = configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![test_quoter]), + shared: SharedConfig { + gas_estimators: vec![GasEstimatorType::Driver { + url: Url::from_str("http://localhost:11088/gasprice").unwrap(), + }], + ..orderbook_config.shared + }, + ..orderbook_config + }; + + self.start_autopilot(None, autopilot_config).await; + self.start_api(orderbook_config).await; } /// Starts a basic version of the protocol with a single external solver. @@ -321,9 +320,53 @@ impl<'a> Services<'a> { endpoint: external_solver_endpoint, base_tokens: vec![], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }]; - let (autopilot_args, api_args) = if run_baseline { + let shared_native_price_config = configs::native_price::NativePriceConfig { + cache: configs::native_price::CacheConfig { + max_age: Duration::from_secs(2), + ..Default::default() + }, + ..Default::default() + }; + + // Create TOML config files + let autopilot_config = Configuration { + native_price_estimation: { + if run_baseline { + NativePriceConfig { + estimators: NativePriceEstimators::new(vec![vec![ + NativePriceEstimator::driver( + "test_quoter".to_string(), + Url::from_str("http://localhost:11088/baseline_solver").unwrap(), + ), + NativePriceEstimator::driver( + "test_solver".to_string(), + Url::from_str("http://localhost:11088/test_solver").unwrap(), + ), + ]]), + shared: shared_native_price_config.clone(), + ..NativePriceConfig::test_default() + } + } else { + NativePriceConfig { + estimators: NativePriceEstimators::new(vec![vec![ + NativePriceEstimator::driver( + "test_quoter".to_string(), + Url::from_str("http://localhost:11088/test_solver").unwrap(), + ), + ]]), + shared: shared_native_price_config, + ..NativePriceConfig::test_default() + } + } + }, + ..Configuration::test("test_solver", solver.address()) + }; + + let drivers = if run_baseline { solvers.push( colocation::start_baseline_solver( "baseline_solver".into(), @@ -338,35 +381,24 @@ impl<'a> Services<'a> { // Here we call the baseline_solver "test_quoter" to make the native price // estimation use the baseline_solver instead of the test_quoter - let autopilot_args = vec![ - format!("--drivers=test_solver|http://localhost:11088/test_solver|{}", const_hex::encode(solver.address())), - "--price-estimation-drivers=test_quoter|http://localhost:11088/baseline_solver,test_solver|http://localhost:11088/test_solver".to_string(), - "--native-price-estimators=test_quoter|http://localhost:11088/baseline_solver,test_solver|http://localhost:11088/test_solver".to_string(), - ]; - let api_args = vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/baseline_solver,test_solver|http://localhost:11088/test_solver".to_string(), - "--native-price-estimators=test_quoter|http://localhost:11088/baseline_solver,test_solver|http://localhost:11088/test_solver".to_string(), - ]; - (autopilot_args, api_args) + vec![ + ExternalSolver::new("test_quoter", "http://localhost:11088/baseline_solver"), + ExternalSolver::new("test_solver", "http://localhost:11088/test_solver"), + ] } else { - let autopilot_args = vec![ - format!( - "--drivers=test_solver|http://localhost:11088/test_solver|{}", - const_hex::encode(solver.address()) - ), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - "--native-price-estimators=test_quoter|http://localhost:11088/test_solver" - .to_string(), - ]; - - let api_args = vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - "--native-price-estimators=test_quoter|http://localhost:11088/test_solver" - .to_string(), - ]; - (autopilot_args, api_args) + vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )] + }; + + let autopilot_config = Configuration { + order_quoting: OrderQuoting::test_with_drivers(drivers.clone()), + ..autopilot_config + }; + let orderbook_config = configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(drivers), + ..configs::orderbook::Configuration::test_default() }; colocation::start_driver( @@ -376,14 +408,14 @@ impl<'a> Services<'a> { false, ); - self.start_autopilot(Some(Duration::from_secs(11)), autopilot_args) + self.start_autopilot(Some(Duration::from_secs(11)), autopilot_config) .await; - self.start_api(api_args).await; + self.start_api(orderbook_config).await; } async fn wait_for_api_to_come_up() { let is_up = || async { - reqwest::get(format!("{API_HOST}{VERSION_ENDPOINT}")) + reqwest::get(format!("{API_HOST}{READY_ENDPOINT}")) .await .is_ok() }; @@ -431,7 +463,7 @@ impl<'a> Services<'a> { pub async fn get_solver_competition( &self, - hash: H256, + hash: B256, ) -> Result { let response = self .http @@ -469,6 +501,28 @@ impl<'a> Services<'a> { } } + pub async fn get_solver_competition_unfiltered( + &self, + auction_id: AuctionId, + ) -> Result { + let response = self + .http + .get(format!( + "{API_HOST}/restricted/api/v2/solver_competition/{auction_id}" + )) + .send() + .await + .unwrap(); + + let status = response.status(); + let body = response.text().await.unwrap(); + + match status { + StatusCode::OK => Ok(serde_json::from_str(&body).unwrap()), + code => Err(code), + } + } + pub async fn get_trades(&self, order: &OrderUid) -> Result, StatusCode> { let url = format!("{API_HOST}/api/v1/trades?orderUid={order}"); let response = self.http.get(url).send().await.unwrap(); @@ -532,7 +586,7 @@ impl<'a> Services<'a> { pub async fn get_native_price( &self, - token: &H160, + token: &Address, ) -> Result { let response = self .http @@ -593,7 +647,7 @@ impl<'a> Services<'a> { pub async fn get_orders_for_tx( &self, - tx_hash: &H256, + tx_hash: &B256, ) -> Result, (StatusCode, String)> { let response = self .http @@ -613,7 +667,7 @@ impl<'a> Services<'a> { pub async fn get_orders_for_owner( &self, - owner: &H160, + owner: &Address, offset: u64, limit: u64, ) -> Result, (StatusCode, String)> { @@ -699,6 +753,130 @@ impl<'a> Services<'a> { .await } + /// Get trades with pagination (v2 endpoint) + pub async fn get_trades_v2( + &self, + order_uid: Option<&OrderUid>, + owner: Option<&Address>, + offset: u64, + limit: u64, + ) -> Result, (StatusCode, String)> { + let mut query_params = vec![("offset", offset.to_string()), ("limit", limit.to_string())]; + if let Some(uid) = order_uid { + query_params.push(("orderUid", uid.to_string())); + } + if let Some(owner_addr) = owner { + query_params.push(("owner", owner_addr.to_string())); + } + + let url = Url::from_str(format!("{API_HOST}/api/v2/trades").as_str()) + .expect("string should be a valid URL"); + + let response = self + .http + .get(url) + .query(&query_params) + .send() + .await + .unwrap(); + + let status = response.status(); + let body = response.text().await.unwrap(); + + match status { + StatusCode::OK => Ok(serde_json::from_str(&body).unwrap()), + code => Err((code, body)), + } + } + + /// Get token metadata + pub async fn get_token_metadata( + &self, + token: &Address, + ) -> Result { + let response = self + .http + .get(format!("{API_HOST}/api/v1/token/{token:?}/metadata")) + .send() + .await + .unwrap(); + + let status = response.status(); + let body = response.text().await.unwrap(); + + match status { + StatusCode::OK => Ok(serde_json::from_str(&body).unwrap()), + code => Err((code, body)), + } + } + + /// Get API version + pub async fn get_api_version(&self) -> Result { + let response = self + .http + .get(format!("{API_HOST}{VERSION_ENDPOINT}")) + .send() + .await + .unwrap(); + + let status = response.status(); + let body = response.text().await.unwrap(); + + match status { + StatusCode::OK => Ok(body), + code => Err((code, body)), + } + } + + /// Cancel a single order (deprecated endpoint) + pub async fn cancel_order_single( + &self, + uid: &OrderUid, + payload: &CancellationPayload, + ) -> Result { + let response = self + .http + .delete(format!("{API_HOST}{ORDERS_ENDPOINT}/{uid}")) + .json(payload) + .send() + .await + .unwrap(); + + let status = response.status(); + let body = response.text().await.unwrap(); + + match status { + StatusCode::OK => Ok(serde_json::from_str(&body).unwrap()), + code => Err((code, body)), + } + } + + /// Get total surplus for a user (unstable endpoint) + pub async fn get_user_total_surplus( + &self, + user: &Address, + ) -> Result { + let response = self + .http + .get(format!("{API_HOST}/api/v1/users/{user:?}/total_surplus")) + .send() + .await + .unwrap(); + + let status = response.status(); + let body = response.text().await.unwrap(); + + match status { + StatusCode::OK => { + // Parse JSON response manually to extract totalSurplus + let json: serde_json::Value = serde_json::from_str(&body).unwrap(); + let total_surplus_str = json["totalSurplus"].as_str().unwrap(); + Ok(U256::from_str_radix(total_surplus_str, 10).unwrap()) + } + code => Err((code, body)), + } + } + pub fn client(&self) -> &Client { &self.http } @@ -711,11 +889,7 @@ impl<'a> Services<'a> { async fn mint_block(&self) { tracing::info!("mining block"); - self.web3 - .transport() - .execute("evm_mine", vec![]) - .await - .unwrap(); + self.web3.provider.evm_mine(None).await.unwrap(); } } @@ -804,32 +978,3 @@ pub async fn ensure_e2e_readonly_user() { } pub type Db = sqlx::Pool; - -/// Clap does not allow you to overwrite CLI arguments easily. This -/// function loops over all provided arguments and only keeps the -/// last one if there are multiples. -fn ignore_overwritten_cli_params(mut params: Vec) -> Vec { - let mut defined_args = HashMap::new(); - params.reverse(); // reverse to give later params higher priority - params.retain(move |param| { - let Some((arg, value)) = param.split_once('=') else { - return true; // keep anything we can't parse (e.g. program name) - }; - match defined_args.entry(arg.to_string()) { - Entry::Occupied(val) => { - tracing::info!( - ignored = ?param, - kept = format!("{arg}={}", val.get()), - "ignoring overwritten CLI argument" - ); - false - } - Entry::Vacant(slot) => { - slot.insert(value.to_string()); - true - } - } - }); - params.reverse(); // reverse to restore original order again - params -} diff --git a/crates/e2e/src/setup/solver/mock.rs b/crates/e2e/src/setup/solver/mock.rs index dc29236ff4..749e6ed3e3 100644 --- a/crates/e2e/src/setup/solver/mock.rs +++ b/crates/e2e/src/setup/solver/mock.rs @@ -7,7 +7,7 @@ use { reqwest::Url, solvers_dto::{ auction::Auction, - solution::{Solution, Solutions}, + solution::{Solution, SolverResponse}, }, std::sync::{Arc, Mutex, MutexGuard}, }; @@ -25,24 +25,45 @@ pub struct Mock { pub struct State { /// In-memory set of the auctions received by the solver. auctions: Arc>>, - /// The currently configured solution to return. - solution: Arc>, + /// The currently configured response to return. + response: Arc>, } type SolutionFuture = Arc BoxFuture<'static, Option> + Send + Sync>; +type ResponseFuture = Arc BoxFuture<'static, SolverResponse> + Send + Sync>; impl Mock { + /// Instructs the solver to return a new response from now on. + pub fn configure_response(&self, response: SolverResponse) { + *self.state.response.lock().unwrap() = Arc::new(move || { + let response = response.clone(); + async move { response }.boxed() + }); + } + + /// Instructs the solver to return a new response from now on. + pub fn configure_response_async(&self, response: ResponseFuture) { + *self.state.response.lock().unwrap() = response; + } + /// Instructs the solver to return a new solution from now on. pub fn configure_solution(&self, solution: Option) { - *self.state.solution.lock().unwrap() = Arc::new(move || { - let solution = solution.clone(); - async move { solution }.boxed() + self.configure_response(SolverResponse::Solutions { + solutions: solution.into_iter().collect(), }); } /// Instructs the solver to return a new solution from now on. pub fn configure_solution_async(&self, solution: SolutionFuture) { - *self.state.solution.lock().unwrap() = solution; + self.configure_response_async(Arc::new(move || { + let solution = solution.clone(); + async move { + SolverResponse::Solutions { + solutions: solution().await.into_iter().collect(), + } + } + .boxed() + })); } /// Returns all the auctions received by the solver @@ -51,10 +72,17 @@ impl Mock { } } -impl Default for Mock { - fn default() -> Self { +impl Mock { + pub async fn new() -> Self { let state = State { - solution: Arc::new(Mutex::new(Arc::new(|| async { None }.boxed()))), + response: Arc::new(Mutex::new(Arc::new(|| { + async { + SolverResponse::Solutions { + solutions: Vec::new(), + } + } + .boxed() + }))), auctions: Arc::new(Mutex::new(vec![])), }; @@ -62,31 +90,33 @@ impl Default for Mock { .route("/solve", axum::routing::post(solve)) .with_state(state.clone()); - let server = - axum::Server::bind(&"0.0.0.0:0".parse().unwrap()).serve(app.into_make_service()); - - let mock = Mock { - state, - url: format!("http://{}", server.local_addr()).parse().unwrap(), - }; + let listener = tokio::net::TcpListener::bind("0.0.0.0:0").await.unwrap(); + let local_addr = listener.local_addr().unwrap(); - tokio::task::spawn(server.with_graceful_shutdown(shutdown_signal())); + tokio::task::spawn(async move { + axum::serve(listener, app) + .with_graceful_shutdown(shutdown_signal()) + .await + .unwrap(); + }); - mock + Mock { + state, + url: format!("http://{}", local_addr).parse().unwrap(), + } } } async fn solve( state: axum::extract::State, Json(auction): Json, -) -> (axum::http::StatusCode, Json) { +) -> (axum::http::StatusCode, Json) { let auction_id = auction.id.unwrap_or_default(); state.auctions.lock().unwrap().push(auction); - let solutions: Vec<_> = { - let solution_generator = state.solution.lock().unwrap().clone(); - solution_generator().await.into_iter().collect() + let response = { + let response_generator = state.response.lock().unwrap().clone(); + response_generator().await }; - let solutions = Solutions { solutions }; - tracing::trace!(?auction_id, ?solutions, "/solve"); - (axum::http::StatusCode::OK, Json(solutions)) + tracing::trace!(?auction_id, ?response, "/solve"); + (axum::http::StatusCode::OK, Json(response)) } diff --git a/crates/e2e/src/setup/solver/solution.rs b/crates/e2e/src/setup/solver/solution.rs index 938507e6ac..f6ce6f34d0 100644 --- a/crates/e2e/src/setup/solver/solution.rs +++ b/crates/e2e/src/setup/solver/solution.rs @@ -1,14 +1,12 @@ use { + alloy::{primitives::Address, signers::local::PrivateKeySigner}, app_data::AppDataHash, - ethcontract::common::abi::ethereum_types::Address, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, model::{ DomainSeparator, order::{BuyTokenDestination, OrderData, OrderKind, OrderUid, SellTokenSource}, signature::EcdsaSigningScheme, }, solvers_dto::solution::{Asset, Kind}, - web3::signing::SecretKeyRef, }; #[derive(Clone, Debug)] @@ -26,11 +24,11 @@ pub struct JitOrder { impl JitOrder { fn data(&self) -> OrderData { OrderData { - sell_token: self.sell.token.into_alloy(), - buy_token: self.buy.token.into_alloy(), - receiver: Some(self.receiver.into_alloy()), - sell_amount: self.sell.amount.into_alloy(), - buy_amount: self.buy.amount.into_alloy(), + sell_token: self.sell.token, + buy_token: self.buy.token, + receiver: Some(self.receiver), + sell_amount: self.sell.amount, + buy_amount: self.buy.amount, valid_to: self.valid_to, app_data: AppDataHash(self.app_data.0), fee_amount: alloy::primitives::U256::ZERO, @@ -45,7 +43,7 @@ impl JitOrder { self, signing_scheme: EcdsaSigningScheme, domain: &DomainSeparator, - key: SecretKeyRef, + key: &PrivateKeySigner, ) -> (solvers_dto::solution::JitOrder, OrderUid) { let data = self.data(); let signature = model::signature::EcdsaSignature::sign( @@ -57,7 +55,7 @@ impl JitOrder { .to_signature(signing_scheme); let order_uid = data.uid( domain, - &signature + signature .recover_owner(&signature.to_bytes(), domain, &data.hash_struct()) .unwrap(), ); @@ -68,14 +66,11 @@ impl JitOrder { model::signature::Signature::PreSign => panic!("Not supported PreSigned JIT orders"), }; let order = solvers_dto::solution::JitOrder { - sell_token: data.sell_token.into_legacy(), - buy_token: data.buy_token.into_legacy(), - receiver: data - .receiver - .map(IntoLegacy::into_legacy) - .unwrap_or_default(), - sell_amount: data.sell_amount.into_legacy(), - buy_amount: data.buy_amount.into_legacy(), + sell_token: data.sell_token, + buy_token: data.buy_token, + receiver: data.receiver.unwrap_or_default(), + sell_amount: data.sell_amount, + buy_amount: data.buy_amount, partially_fillable: data.partially_fillable, valid_to: data.valid_to, app_data: data.app_data.0, diff --git a/crates/e2e/tests/e2e/api_version.rs b/crates/e2e/tests/e2e/api_version.rs new file mode 100644 index 0000000000..8cf68b94bc --- /dev/null +++ b/crates/e2e/tests/e2e/api_version.rs @@ -0,0 +1,31 @@ +use {e2e::setup::*, number::units::EthUnit, shared::web3::Web3}; + +#[tokio::test] +#[ignore] +async fn local_node_api_version() { + run_test(api_version).await; +} + +/// Test that the API version endpoint returns a version string +async fn api_version(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + // Get the API version + let version = services.get_api_version().await.unwrap(); + + // Version should match git describe format + // Format examples: v1.2.3, v1.2.3-4-gabcd1234, or abcd1234 + let is_valid_version = version.starts_with('v') + || version + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '.'); + + assert!( + is_valid_version, + "Version should be valid git describe format: {version}" + ); +} diff --git a/crates/e2e/tests/e2e/app_data.rs b/crates/e2e/tests/e2e/app_data.rs index 499380b97d..cd60790f08 100644 --- a/crates/e2e/tests/e2e/app_data.rs +++ b/crates/e2e/tests/e2e/app_data.rs @@ -1,20 +1,16 @@ use { app_data::{AppDataHash, hash_full_app_data}, - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderCreationAppData, OrderKind}, quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::EcdsaSigningScheme, }, + number::units::EthUnit, reqwest::StatusCode, - secp256k1::SecretKey, - shared::ethrpc::Web3, + shared::web3::Web3, std::str::FromStr, - web3::signing::SecretKeyRef, }; #[tokio::test] @@ -32,17 +28,17 @@ async fn local_node_app_data_full_format() { // Test that orders can be placed with the new app data format. async fn app_data(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token_a.mint(trader.address(), to_wei(10)).await; + token_a.mint(trader.address(), 10u64.eth()).await; token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -51,10 +47,10 @@ async fn app_data(web3: Web3) { let mut create_order = |app_data| { let order = OrderCreation { app_data, - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 2u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), valid_to, kind: OrderKind::Sell, ..Default::default() @@ -62,7 +58,7 @@ async fn app_data(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); // Adjust valid to make sure we get unique UIDs. valid_to += 1; @@ -194,17 +190,17 @@ async fn app_data(web3: Web3) { /// all supported features. async fn app_data_full_format(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token_a.mint(trader.address(), to_wei(10)).await; + token_a.mint(trader.address(), 10u64.eth()).await; token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -213,10 +209,10 @@ async fn app_data_full_format(web3: Web3) { let mut create_order = |app_data| { let order = OrderCreation { app_data, - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 2u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), valid_to, kind: OrderKind::Sell, ..Default::default() @@ -224,7 +220,7 @@ async fn app_data_full_format(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); // Adjust valid to make sure we get unique UIDs. valid_to += 1; diff --git a/crates/e2e/tests/e2e/app_data_signer.rs b/crates/e2e/tests/e2e/app_data_signer.rs index 43a28a7f30..b08811dd32 100644 --- a/crates/e2e/tests/e2e/app_data_signer.rs +++ b/crates/e2e/tests/e2e/app_data_signer.rs @@ -1,17 +1,13 @@ use { alloy::primitives::Address, - e2e::setup::{OnchainComponents, Services, TestAccount, eth, run_test, safe::Safe, to_wei}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + e2e::setup::{OnchainComponents, Services, TestAccount, run_test, safe::Safe}, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderCreationAppData, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -22,25 +18,25 @@ async fn local_node_order_creation_checks_metadata_signer() { async fn order_creation_checks_metadata_signer(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader, adversary, safe_owner] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader, adversary, safe_owner] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token_a.mint(trader.address(), to_wei(10)).await; + token_a.mint(trader.address(), 10u64.eth()).await; token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); - token_a.mint(adversary.address(), to_wei(10)).await; + token_a.mint(adversary.address(), 10u64.eth()).await; token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(adversary.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(adversary.address()) .send_and_watch() .await .unwrap(); @@ -49,10 +45,10 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { let mut create_order = |app_data| { let order = OrderCreation { app_data, - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 2u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), valid_to, kind: OrderKind::Sell, ..Default::default() @@ -65,7 +61,7 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { order_creation.sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(signer.private_key()).unwrap()), + &signer.signer, ) }; @@ -73,13 +69,13 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { services.start_protocol(solver).await; // Rejected: app data with different signer. - let full_app_data = full_app_data_with_signer(adversary.address().into_alloy()); + let full_app_data = full_app_data_with_signer(adversary.address()); let order1 = sign(create_order(full_app_data), &trader); let err = services.create_order(&order1).await.unwrap_err(); assert!(dbg!(err).1.contains("WrongOwner")); // Accepted: app data with correct signer. - let full_app_data = full_app_data_with_signer(trader.address().into_alloy()); + let full_app_data = full_app_data_with_signer(trader.address()); let order2 = sign(create_order(full_app_data.clone()), &trader); let uid = services.create_order(&order2).await.unwrap(); assert!(matches!(services.get_order(&uid).await, Ok(..))); @@ -98,11 +94,11 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { // EIP-1271 - let safe = Safe::deploy(safe_owner.clone(), web3.alloy.clone()).await; - token_a.mint(safe.address().into_legacy(), to_wei(10)).await; + let safe = Safe::deploy(safe_owner.clone(), web3.provider.clone()).await; + token_a.mint(safe.address(), 10u64.eth()).await; safe.exec_alloy_call( token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) + .approve(onchain.contracts().allowance, 10u64.eth()) .into_transaction_request(), ) .await; @@ -114,9 +110,9 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { assert!(matches!(services.create_order(&order4).await, Ok(..))); // Rejected: from and signer are inconsistent. - let full_app_data = full_app_data_with_signer(adversary.address().into_alloy()); + let full_app_data = full_app_data_with_signer(adversary.address()); let mut order5 = create_order(full_app_data); - order5.from = Some(safe.address().into_legacy()); + order5.from = Some(safe.address()); safe.sign_order(&mut order5, &onchain); let err = services.create_order(&order5).await.unwrap_err(); assert!(err.1.contains("AppdataFromMismatch")); diff --git a/crates/e2e/tests/e2e/autopilot_leader.rs b/crates/e2e/tests/e2e/autopilot_leader.rs index 5eece8c177..fc752dc2d5 100644 --- a/crates/e2e/tests/e2e/autopilot_leader.rs +++ b/crates/e2e/tests/e2e/autopilot_leader.rs @@ -1,26 +1,23 @@ use { autopilot::shutdown_controller::ShutdownController, + configs::{ + autopilot::{Configuration, run_loop::RunLoopConfig}, + order_quoting::{ExternalSolver, OrderQuoting}, + shared::SharedConfig, + test_util::TestDefault, + }, e2e::setup::{ OnchainComponents, Services, TIMEOUT, colocation, - eth, + proxy::ReverseProxy, run_test, - to_wei, wait_for_condition, }, - ethrpc::{ - Web3, - alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, - }, + ethrpc::{Web3, alloy::CallBuilderExt}, model::order::{OrderCreation, OrderKind}, - secp256k1::SecretKey, - std::time::Duration, - web3::signing::SecretKeyRef, + number::units::EthUnit, }; #[tokio::test] @@ -33,22 +30,22 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { // TODO: Implement test that checks auction creation frequency against db // to see that only one autopilot produces auctions let mut onchain = OnchainComponents::deploy(web3).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; - let [solver1, solver2] = onchain.make_solvers(to_wei(1)).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + let [solver1, solver2] = onchain.make_solvers(1u64.eth()).await; let [token_a] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader, settlement accounts, and pool creation - token_a.mint(solver1.address(), to_wei(1000)).await; - token_a.mint(solver2.address(), to_wei(1000)).await; + token_a.mint(solver1.address(), 1000u64.eth()).await; + token_a.mint(solver2.address(), 1000u64.eth()).await; - token_a.mint(trader.address(), to_wei(200)).await; + token_a.mint(trader.address(), 200u64.eth()).await; // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(1000)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 1000u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -85,37 +82,86 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { let services = Services::new(&onchain).await; let (manual_shutdown, control) = ShutdownController::new_manual_shutdown(); - // Configure autopilot-leader only with test_solver - let autopilot_leader = services.start_autopilot_with_shutdown_controller(None, vec![ - format!("--drivers=test_solver|http://localhost:11088/test_solver|{}|requested-timeout-on-problems", - const_hex::encode(solver1.address())), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - "--gas-estimators=http://localhost:11088/gasprice".to_string(), - "--metrics-address=0.0.0.0:9590".to_string(), - "--enable-leader-lock=true".to_string(), - ], control).await; - - // Configure autopilot-backup only with test_solver2 - let _autopilot_follower = services.start_autopilot(None, vec![ - format!("--drivers=test_solver2|http://localhost:11088/test_solver2|{}|requested-timeout-on-problems", - const_hex::encode(solver2.address())), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver2".to_string(), - "--gas-estimators=http://localhost:11088/gasprice".to_string(), - "--enable-leader-lock=true".to_string(), - ]).await; + // Start proxy for native price API with automatic failover + let _proxy = ReverseProxy::start( + "0.0.0.0:9588".parse().unwrap(), + &[ + "http://0.0.0.0:12088".parse().unwrap(), // autopilot_leader + "http://0.0.0.0:12089".parse().unwrap(), // autopilot_follower + ], + ); + + let leader_config = Configuration::test("test_solver", solver1.address()); + let leader_config = Configuration { + metrics_address: "0.0.0.0:9590".parse().unwrap(), + api_address: "0.0.0.0:12088".parse().unwrap(), + run_loop: RunLoopConfig { + enable_leader_lock: true, + ..leader_config.run_loop + }, + shared: SharedConfig { + gas_estimators: vec![TestDefault::test_default()], + ..leader_config.shared + }, + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + + ..leader_config + }; + + let autopilot_leader = services + .start_autopilot_with_shutdown_controller(None, leader_config, control) + .await; + + let follower_config = Configuration::test("test_solver2", solver2.address()); + let follower_config = Configuration { + metrics_address: "0.0.0.0:9591".parse().unwrap(), + api_address: "0.0.0.0:12089".parse().unwrap(), + run_loop: RunLoopConfig { + enable_leader_lock: true, + ..follower_config.run_loop + }, + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver2", + )]), + shared: SharedConfig { + gas_estimators: vec![TestDefault::test_default()], + ..follower_config.shared + }, + ..follower_config + }; + + let _autopilot_follower = services.start_autopilot(None, follower_config).await; services - .start_api(vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver1,test_solver2|http://localhost:11088/test_solver2".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ + ExternalSolver::new("test_quoter", "http://localhost:11088/test_solver1"), + ExternalSolver::new("test_solver2", "http://localhost:11088/test_solver2"), + ]), + native_price_estimation: configs::orderbook::native_price::NativePriceConfig { + estimators: configs::native_price_estimators::NativePriceEstimators::new(vec![ + vec![ + configs::native_price_estimators::NativePriceEstimator::forwarder( + "http://0.0.0.0:9588".parse().unwrap(), + ), + ], + ]), + ..configs::orderbook::native_price::NativePriceConfig::test_default() + }, + ..configs::orderbook::Configuration::test_default() + }) .await; let order = || { OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -123,7 +169,7 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { .sign( model::signature::EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ) }; @@ -139,14 +185,13 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { if let Some(trade) = services.get_trades(&uid).await.unwrap().first() { services - .get_solver_competition(trade.tx_hash.unwrap().into_legacy()) + .get_solver_competition(trade.tx_hash.unwrap()) .await .ok() .as_ref() .and_then(|competition| competition.solutions.first()) .map(|solution| { - solution.is_winner - && solution.solver_address == solver1.address().into_alloy() + solution.is_winner && solution.solver_address == solver1.address() }) } else { None @@ -157,18 +202,45 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { // Stop autopilot-leader, follower should take over manual_shutdown.shutdown(); - onchain.mint_block().await; - assert!( - tokio::time::timeout(Duration::from_secs(15), autopilot_leader) - .await - .is_ok() - ); + let is_leader_shutdown = || async { + onchain.mint_block().await; + autopilot_leader.is_finished() + }; + wait_for_condition(TIMEOUT, is_leader_shutdown) + .await + .unwrap(); + + // Wait for the follower to step up as leader by checking its metrics endpoint + let is_follower_leader = || async { + onchain.mint_block().await; + let Ok(response) = reqwest::get("http://0.0.0.0:9591/metrics").await else { + return false; + }; + let Ok(body) = response.text().await else { + return false; + }; + body.lines() + .any(|line| line.trim().contains("leader_lock_tracker_is_leader 1")) + }; + wait_for_condition(TIMEOUT, is_follower_leader) + .await + .unwrap(); // Run 10 txs, autopilot-backup is in charge // - only test_solver2 should participate and settle for i in 1..=10 { tracing::info!("Tx with autopilot-backup {i}"); - let uid = services.create_order(&order()).await.unwrap(); + let uid_cell = std::cell::Cell::new(None); + let try_create_order = || async { + onchain.mint_block().await; + if let Ok(uid) = services.create_order(&order()).await { + uid_cell.set(Some(uid)); + return true; + } + false + }; + wait_for_condition(TIMEOUT, try_create_order).await.unwrap(); + let uid = uid_cell.into_inner().unwrap(); tracing::info!("waiting for trade"); let indexed_trades = || async { @@ -176,14 +248,13 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { if let Some(trade) = services.get_trades(&uid).await.unwrap().first() { services - .get_solver_competition(trade.tx_hash.unwrap().into_legacy()) + .get_solver_competition(trade.tx_hash.unwrap()) .await .ok() .as_ref() .and_then(|competition| competition.solutions.first()) .map(|solution| { - solution.is_winner - && solution.solver_address == solver2.address().into_alloy() + solution.is_winner && solution.solver_address == solver2.address() }) } else { None diff --git a/crates/e2e/tests/e2e/banned_users.rs b/crates/e2e/tests/e2e/banned_users.rs index abd741e855..b1ee2c6bfd 100644 --- a/crates/e2e/tests/e2e/banned_users.rs +++ b/crates/e2e/tests/e2e/banned_users.rs @@ -3,20 +3,11 @@ use { primitives::{Address, address}, providers::ext::{AnvilApi, ImpersonateConfig}, }, - contracts::alloy::ERC20, - e2e::setup::{ - OnchainComponents, - Services, - eth, - run_forked_test_with_block_number, - to_wei, - to_wei_with_exp, - }, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - }, + contracts::ERC20, + e2e::setup::{OnchainComponents, Services, run_forked_test_with_block_number}, + ethrpc::Web3, model::quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, + number::units::EthUnit, reqwest::StatusCode, }; @@ -33,29 +24,29 @@ async fn forked_node_mainnet_single_limit_order() { } /// The block number from which we will fetch state for the forked tests. -const FORK_BLOCK_MAINNET: u64 = 23112197; +const FORK_BLOCK_MAINNET: u64 = 24843565; /// DAI whale address as per [FORK_BLOCK_MAINNET]. -const DAI_WHALE_MAINNET: Address = address!("762d46904B93a1EEDBfF2fD50445CB8ffA41F9FB"); +const DAI_WHALE_MAINNET: Address = address!("28c6c06298d514db089934071355e5743bf21d60"); const BANNED_USER: Address = address!("7F367cC41522cE07553e823bf3be79A889DEbe1B"); async fn forked_mainnet_onchain_banned_user_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; let token_dai = ERC20::Instance::new( address!("6b175474e89094c44da98b954eedeac495271d0f"), - web3.alloy.clone(), + web3.provider.clone(), ); let token_usdt = ERC20::Instance::new( address!("dac17f958d2ee523a2206206994597c13d831ec7"), - web3.alloy.clone(), + web3.provider.clone(), ); - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_dai - .transfer(BANNED_USER, to_wei_with_exp(1000, 18).into_alloy()) + .transfer(BANNED_USER, 1000u64.eth()) .from(DAI_WHALE_MAINNET) .into_transaction_request(), ImpersonateConfig { @@ -70,17 +61,14 @@ async fn forked_mainnet_onchain_banned_user_test(web3: Web3) { .unwrap(); // Approve GPv2 for trading - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_dai - .approve( - onchain.contracts().allowance.into_alloy(), - to_wei_with_exp(1000, 18).into_alloy(), - ) + .approve(onchain.contracts().allowance, 1000u64.eth()) .from(BANNED_USER) .into_transaction_request(), ImpersonateConfig { - fund_amount: Some(eth(1)), + fund_amount: Some(1u64.eth()), stop_impersonate: true, }, ) @@ -96,16 +84,25 @@ async fn forked_mainnet_onchain_banned_user_test(web3: Web3) { let result = services .submit_quote(&OrderQuoteRequest { - sell_token: token_dai.address().into_legacy(), - buy_token: token_usdt.address().into_legacy(), + sell_token: *token_dai.address(), + buy_token: *token_usdt.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei_with_exp(1000, 18).try_into().unwrap(), + value: (1000u64.eth()).try_into().unwrap(), }, }, - from: BANNED_USER.into_legacy(), + from: BANNED_USER, ..Default::default() }) .await; - assert!(matches!(result, Err((StatusCode::FORBIDDEN, _)))); + + match result { + Err((StatusCode::FORBIDDEN, _)) => { /* passed! */ } + Err((status_code, _)) => panic!( + "expected status_code to be {}; got {}", + StatusCode::FORBIDDEN, + status_code + ), + Ok(result) => panic!("expected error, got {:?}", result), + } } diff --git a/crates/e2e/tests/e2e/buffers.rs b/crates/e2e/tests/e2e/buffers.rs index 688378b39e..87f23c1b6e 100644 --- a/crates/e2e/tests/e2e/buffers.rs +++ b/crates/e2e/tests/e2e/buffers.rs @@ -1,17 +1,18 @@ use { ::alloy::primitives::U256, - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + configs::{ + autopilot::trusted_tokens::TrustedTokensConfig, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, }, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -23,28 +24,25 @@ async fn local_node_buffers() { async fn onchain_settlement_without_liquidity(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader, settlement accounts, and pool creation - token_a.mint(trader.address(), to_wei(100)).await; + token_a.mint(trader.address(), 100u64.eth()).await; token_b - .mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(5), - ) + .mint(*onchain.contracts().gp_settlement.address(), 5u64.eth()) .await; - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -70,34 +68,39 @@ async fn onchain_settlement_without_liquidity(web3: Web3) { services .start_autopilot( None, - vec![ - format!( - "--trusted-tokens={weth:#x},{token_a:#x},{token_b:#x}", - weth = onchain.contracts().weth.address(), - token_a = token_a.address(), - token_b = token_b.address() - ), - format!( - "--drivers=test_solver|http://localhost:11088/test_solver|{}", - const_hex::encode(solver.address()) - ), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - ], + configs::autopilot::Configuration { + trusted_tokens: TrustedTokensConfig { + tokens: vec![ + *onchain.contracts().weth.address(), + *token_a.address(), + *token_b.address(), + ], + ..Default::default() + }, + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..configs::autopilot::Configuration::test("test_solver", solver.address()) + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Place Order let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(9), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 9u64.eth(), + buy_token: *token_b.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Buy, ..Default::default() @@ -105,20 +108,14 @@ async fn onchain_settlement_without_liquidity(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap(); tracing::info!("waiting for first trade"); onchain.mint_block().await; - let trade_happened = || async { - token_b - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap() - == order.buy_amount.into_alloy() - }; + let trade_happened = + || async { token_b.balanceOf(trader.address()).call().await.unwrap() == order.buy_amount }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); // Check that settlement buffers were traded. @@ -138,19 +135,15 @@ async fn onchain_settlement_without_liquidity(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap(); tracing::info!("waiting for second trade"); let trade_happened = || async { onchain.mint_block().await; - token_b - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap() - == (order.buy_amount.into_alloy() * U256::from(2)) + token_b.balanceOf(trader.address()).call().await.unwrap() + == (order.buy_amount * ::alloy::primitives::U256::from(2)) }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); } diff --git a/crates/e2e/tests/e2e/contract_revert.rs b/crates/e2e/tests/e2e/contract_revert.rs new file mode 100644 index 0000000000..f19012f5f9 --- /dev/null +++ b/crates/e2e/tests/e2e/contract_revert.rs @@ -0,0 +1,61 @@ +use { + ::alloy::primitives::Address, + contracts::IERC4626, + e2e::setup::*, + ethrpc::alloy::errors::ContractErrorExt, + shared::web3::Web3, + testlib::tokens::{BNT, GNO, STETH, SUSDE, USDC, WETH}, +}; + +/// The block number from which we will fetch state for the forked test. +const FORK_BLOCK_MAINNET: u64 = 23112197; + +/// Verifies that calling `asset()` on contracts that don't implement the +/// EIP-4626 selector is correctly classified as a contract revert by +/// `is_contract_revert`, regardless of how each node encodes the failure +/// (empty revert data, geth code 3, "execution reverted" message, +/// `EVM error InvalidFEOpcode`, ...). +#[tokio::test] +#[ignore] +async fn forked_node_mainnet_asset_call_is_contract_revert() { + run_forked_test_with_block_number( + asset_call_is_contract_revert_test, + std::env::var("FORK_URL_MAINNET") + .expect("FORK_URL_MAINNET must be set to run forked tests"), + FORK_BLOCK_MAINNET, + ) + .await; +} + +async fn asset_call_is_contract_revert_test(web3: Web3) { + // sUSDe is a real EIP-4626 vault — `asset()` succeeds. + let vault = IERC4626::IERC4626::new(SUSDE, &web3.provider); + let asset = vault + .asset() + .call() + .await + .expect("asset() on sUSDe must succeed"); + assert_ne!( + asset, + Address::ZERO, + "sUSDe asset() returned the zero address" + ); + + // For each non-vault contract, `asset()` must classify as a contract revert + // (i.e. the call reached the contract and the contract rejected it because + // it doesn't implement the selector — not a transport failure). Each entry + // exercises a different failure shape: USDC is an empty-data revert, BNT + // hits the INVALID (0xFE) opcode, the rest are plain reverts. + for token in [USDC, WETH, BNT, STETH, GNO] { + let vault = IERC4626::IERC4626::new(token, &web3.provider); + let err = vault + .asset() + .call() + .await + .expect_err(&format!("asset() on {token} must fail")); + assert!( + err.is_contract_revert(), + "asset() on {token} must classify as contract revert, got: {err:?}", + ); + } +} diff --git a/crates/e2e/tests/e2e/cors.rs b/crates/e2e/tests/e2e/cors.rs new file mode 100644 index 0000000000..fb2475970b --- /dev/null +++ b/crates/e2e/tests/e2e/cors.rs @@ -0,0 +1,119 @@ +//! Tests for CORS behavior to ensure the warp-to-axum migration preserves +//! headers. + +use { + configs::{ + order_quoting::{ExternalSolver, OrderQuoting}, + shared::SharedConfig, + test_util::TestDefault, + }, + e2e::setup::{API_HOST, OnchainComponents, Services, run_test}, + reqwest::{Method, StatusCode}, + shared::web3::Web3, +}; + +#[tokio::test] +#[ignore] +async fn local_node_cors_preflight() { + run_test(cors_preflight).await; +} + +async fn cors_preflight(web3: Web3) { + let onchain = OnchainComponents::deploy(web3).await; + let services = Services::new(&onchain).await; + // since we're testing malformed paths, etc; + // we don't really need the rest of the protocol + services + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + shared: SharedConfig { + gas_estimators: vec![TestDefault::test_default()], + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }) + .await; + let client = services.client(); + + let response = client + .request(Method::OPTIONS, format!("{API_HOST}/api/v1/orders")) + .header("Origin", "https://swap.cow.fi") + .header("Access-Control-Request-Method", "POST") + .header("Access-Control-Request-Headers", "Content-Type") + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + + let headers = response.headers(); + + let allow_methods = headers + .get("access-control-allow-methods") + .expect("Missing access-control-allow-methods header") + .to_str() + .unwrap(); + for method in ["GET", "POST", "DELETE", "OPTIONS", "PUT", "PATCH", "HEAD"] { + assert!( + allow_methods.contains(method), + "access-control-allow-methods missing {method}: {allow_methods}" + ); + } + + let allow_headers = headers + .get("access-control-allow-headers") + .expect("Missing access-control-allow-headers header") + .to_str() + .unwrap() + .to_lowercase(); + for header in ["origin", "content-type", "x-auth-token", "x-appid"] { + assert!( + allow_headers.contains(header), + "access-control-allow-headers missing {header}: {allow_headers}" + ); + } +} + +#[tokio::test] +#[ignore] +async fn local_node_cors_headers_on_error() { + run_test(cors_headers_on_error).await; +} + +async fn cors_headers_on_error(web3: Web3) { + let onchain = OnchainComponents::deploy(web3).await; + let services = Services::new(&onchain).await; + // since we're testing malformed paths, etc; + // we don't really need the rest of the protocol + services + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + shared: SharedConfig { + gas_estimators: vec![TestDefault::test_default()], + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }) + .await; + let client = services.client(); + + let response = client + .get(format!("{API_HOST}/api/v1/nonexistent")) + .header("Origin", "https://swap.cow.fi") + .send() + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::NOT_FOUND); + assert!( + response + .headers() + .contains_key("access-control-allow-origin"), + "CORS headers should be present on 404 responses" + ); +} diff --git a/crates/e2e/tests/e2e/cow_amm.rs b/crates/e2e/tests/e2e/cow_amm.rs index 259f742867..77fb134f95 100644 --- a/crates/e2e/tests/e2e/cow_amm.rs +++ b/crates/e2e/tests/e2e/cow_amm.rs @@ -1,39 +1,40 @@ use { alloy::{ primitives::{Address, Bytes, FixedBytes, U256, address}, - providers::ext::{AnvilApi, ImpersonateConfig}, + providers::{ + Provider, + ext::{AnvilApi, ImpersonateConfig}, + }, + }, + configs::{ + autopilot::{Configuration, solver::Solver}, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, }, - contracts::alloy::{ + contracts::{ ERC20, support::{Balances, Signatures}, }, - driver::domain::eth::NonZeroU256, e2e::setup::{ DeployedContracts, OnchainComponents, Services, TIMEOUT, colocation::{self, SolverEngine}, - eth, mock::Mock, run_forked_test_with_block_number, run_test, - to_wei, - to_wei_with_exp, wait_for_condition, }, - ethcontract::{BlockId, BlockNumber, H160}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + eth_domain_types::NonZeroU256, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderClass, OrderCreation, OrderKind, OrderUid}, quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::{addr, ethrpc::Web3}, + number::units::EthUnit, + shared::web3::Web3, solvers_dto::solution::{ BuyTokenBalance, Call, @@ -43,7 +44,6 @@ use { Solution, }, std::collections::{HashMap, HashSet}, - web3::signing::SecretKeyRef, }; #[tokio::test] @@ -57,41 +57,40 @@ async fn local_node_cow_amm_jit() { async fn cow_amm_jit(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(100)).await; - let [bob, cow_amm_owner] = onchain.make_accounts(to_wei(1000)).await; + let [solver] = onchain.make_solvers(100u64.eth()).await; + let [bob, cow_amm_owner] = onchain.make_accounts(1000u64.eth()).await; let [dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(100)) + .deploy_tokens_with_weth_uni_v2_pools(300_000u64.eth(), 100u64.eth()) .await; // Fund the buffers with a lot of buy tokens so we can pay out the required // tokens for 2 orders in the same direction without having to worry about // getting the liquidity on-chain. dai.mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(100_000), + *onchain.contracts().gp_settlement.address(), + 100_000u64.eth(), ) .await; // set up cow_amm let oracle = - contracts::alloy::cow_amm::CowAmmUniswapV2PriceOracle::Instance::deploy(web3.alloy.clone()) + contracts::cow_amm::CowAmmUniswapV2PriceOracle::Instance::deploy(web3.provider.clone()) .await .unwrap(); - let cow_amm_factory = - contracts::alloy::cow_amm::CowAmmConstantProductFactory::Instance::deploy( - web3.alloy.clone(), - *onchain.contracts().gp_settlement.address(), - ) - .await - .unwrap(); + let cow_amm_factory = contracts::cow_amm::CowAmmConstantProductFactory::Instance::deploy( + web3.provider.clone(), + *onchain.contracts().gp_settlement.address(), + ) + .await + .unwrap(); // Fund cow amm owner with 2_000 dai and allow factory take them - dai.mint(cow_amm_owner.address(), to_wei(2_000)).await; + dai.mint(cow_amm_owner.address(), 2_000u64.eth()).await; - dai.approve(*cow_amm_factory.address(), eth(2_000)) - .from(cow_amm_owner.address().into_alloy()) + dai.approve(*cow_amm_factory.address(), 2_000u64.eth()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -100,16 +99,16 @@ async fn cow_amm_jit(web3: Web3) { .contracts() .weth .deposit() - .value(eth(1)) - .from(cow_amm_owner.address().into_alloy()) + .value(1u64.eth()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .approve(*cow_amm_factory.address(), eth(1)) - .from(cow_amm_owner.address().into_alloy()) + .approve(*cow_amm_factory.address(), 1u64.eth()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -124,7 +123,7 @@ async fn cow_amm_jit(web3: Web3) { let cow_amm = cow_amm_factory .ammDeterministicAddress( - cow_amm_owner.address().into_alloy(), + cow_amm_owner.address(), *dai.address(), *onchain.contracts().weth.address(), ) @@ -139,25 +138,25 @@ async fn cow_amm_jit(web3: Web3) { cow_amm_factory .create( *dai.address(), - to_wei(2_000).into_alloy(), + 2_000u64.eth(), *onchain.contracts().weth.address(), - to_wei(1).into_alloy(), + 1u64.eth(), U256::ZERO, // min traded token *oracle.address(), Bytes::copy_from_slice(&oracle_data), FixedBytes(APP_DATA), ) - .from(cow_amm_owner.account().address().into_alloy()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); - let cow_amm = contracts::alloy::cow_amm::CowAmm::Instance::new(cow_amm, web3.alloy.clone()); + let cow_amm = contracts::cow_amm::CowAmm::Instance::new(cow_amm, web3.provider.clone()); // Start system with the regular baseline solver as a quoter but a mock solver // for the actual solver competition. That way we can handcraft a solution // for this test and don't have to implement complete support for CoW AMMs // in the baseline solver. - let mock_solver = Mock::default(); + let mock_solver = Mock::new().await; colocation::start_driver( onchain.contracts(), vec![ @@ -176,41 +175,47 @@ async fn cow_amm_jit(web3: Web3) { endpoint: mock_solver.url.clone(), base_tokens: vec![], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, ], colocation::LiquidityProvider::UniswapV2, false, ); let services = Services::new(&onchain).await; + services .start_autopilot( None, - vec![ - format!( - "--drivers=mock_solver|http://localhost:11088/mock_solver|{}", - const_hex::encode(solver.address()) - ), - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver" - .to_string(), - ], + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test("mock_solver", solver.address()) + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Derive the order's valid_to from the blockchain because the cow amm enforces // a relatively small valid_to and we initialize the chain with a date in // the past so the computer's current time is way ahead of the blockchain. let block = web3 - .eth() - .block(BlockId::Number(BlockNumber::Latest)) + .provider + .get_block(alloy::eips::BlockId::latest()) .await .unwrap() .unwrap(); - let valid_to = block.timestamp.as_u32() + 300; + let valid_to = u32::try_from(block.header.timestamp).unwrap() + 300; // CoW AMM order with a limit price extremely close to the AMM's current price. // current price => 1 WETH == 2000 DAI @@ -218,12 +223,12 @@ async fn cow_amm_jit(web3: Web3) { // oracle price => 100 WETH == 300000 DAI => 1 WETH == 3000 DAI // If this order gets settled around the oracle price it will receive plenty of // surplus. - let cow_amm_order = contracts::alloy::cow_amm::CowAmm::GPv2Order::Data { + let cow_amm_order = contracts::cow_amm::CowAmm::GPv2Order::Data { sellToken: *onchain.contracts().weth.address(), buyToken: *dai.address(), receiver: Default::default(), - sellAmount: U256::from(10).pow(U256::from(17)), - buyAmount: to_wei(230).into_alloy(), + sellAmount: 0.1.eth(), + buyAmount: 230u64.eth(), validTo: valid_to, appData: FixedBytes(APP_DATA), feeAmount: U256::ZERO, @@ -241,7 +246,7 @@ async fn cow_amm_jit(web3: Web3) { .unwrap(), ), // erc20 }; - let trading_params = contracts::alloy::cow_amm::CowAmm::ConstantProduct::TradingParams { + let trading_params = contracts::cow_amm::CowAmm::ConstantProduct::TradingParams { minTradedToken0: U256::ZERO, priceOracle: *oracle.address(), priceOracleData: Bytes::copy_from_slice(&oracle_data), @@ -262,8 +267,8 @@ async fn cow_amm_jit(web3: Web3) { &onchain.contracts().domain_separator, ); let cow_amm_commitment = Call { - target: cow_amm_commitment_data.target.into_legacy(), - value: cow_amm_commitment_data.value.into_legacy(), + target: cow_amm_commitment_data.target, + value: cow_amm_commitment_data.value, calldata: cow_amm_commitment_data.call_data, }; @@ -272,29 +277,26 @@ async fn cow_amm_jit(web3: Web3) { .contracts() .weth .deposit() - .from(bob.address().into_alloy()) - .value(alloy::primitives::U256::from(10u64.pow(17))) + .from(bob.address()) + .value(0.1.eth()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .approve( - onchain.contracts().allowance.into_alloy(), - alloy::primitives::U256::MAX, - ) - .from(bob.address().into_alloy()) + .approve(onchain.contracts().allowance, U256::MAX) + .from(bob.address()) .send_and_watch() .await .unwrap(); // place user order with the same limit price as the CoW AMM order let user_order = OrderCreation { - sell_token: onchain.contracts().weth.address().into_legacy(), - sell_amount: ethcontract::U256::exp10(17), // 0.1 WETH - buy_token: dai.address().into_legacy(), - buy_amount: to_wei(230), // 230 DAI + sell_token: *onchain.contracts().weth.address(), + sell_amount: 0.1.eth(), // 0.1 WETH + buy_token: *dai.address(), + buy_amount: 230u64.eth(), // 230 DAI valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -302,37 +304,30 @@ async fn cow_amm_jit(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(bob.private_key()).unwrap()), + &bob.signer, ); let user_order_id = services.create_order(&user_order).await.unwrap(); let amm_balance_before = dai.balanceOf(*cow_amm.address()).call().await.unwrap(); - let bob_balance_before = dai - .balanceOf(bob.address().into_alloy()) - .call() - .await - .unwrap(); + let bob_balance_before = dai.balanceOf(bob.address()).call().await.unwrap(); - let fee = ethcontract::U256::exp10(16); // 0.01 WETH + let fee = 0.01.eth(); // 0.01 WETH mock_solver.configure_solution(Some(Solution { id: 1, // assume price of the univ2 pool prices: HashMap::from([ - (dai.address().into_legacy(), to_wei(100)), - ( - onchain.contracts().weth.address().into_legacy(), - to_wei(300_000), - ), + (*dai.address(), 100u64.eth()), + (*onchain.contracts().weth.address(), 300_000u64.eth()), ]), trades: vec![ solvers_dto::solution::Trade::Jit(solvers_dto::solution::JitTrade { order: solvers_dto::solution::JitOrder { - sell_token: cow_amm_order.sellToken.into_legacy(), - buy_token: cow_amm_order.buyToken.into_legacy(), - receiver: cow_amm_order.receiver.into_legacy(), - sell_amount: cow_amm_order.sellAmount.into_legacy(), - buy_amount: cow_amm_order.buyAmount.into_legacy(), + sell_token: cow_amm_order.sellToken, + buy_token: cow_amm_order.buyToken, + receiver: cow_amm_order.receiver, + sell_amount: cow_amm_order.sellAmount, + buy_amount: cow_amm_order.buyAmount, partially_fillable: cow_amm_order.partiallyFillable, valid_to: cow_amm_order.validTo, app_data: cow_amm_order.appData.0, @@ -342,12 +337,12 @@ async fn cow_amm_jit(web3: Web3) { signing_scheme: SigningScheme::Eip1271, signature, }, - executed_amount: cow_amm_order.sellAmount.into_legacy() - fee, + executed_amount: cow_amm_order.sellAmount - fee, fee: Some(fee), }), solvers_dto::solution::Trade::Fulfillment(solvers_dto::solution::Fulfillment { order: solvers_dto::solution::OrderUid(user_order_id.0), - executed_amount: user_order.sell_amount - fee, + executed_amount: (user_order.sell_amount - fee), fee: Some(fee), }), ], @@ -357,6 +352,7 @@ async fn cow_amm_jit(web3: Web3) { gas: None, flashloans: None, wrappers: vec![], + gas_fee_override: None, })); // Drive solution @@ -364,17 +360,13 @@ async fn cow_amm_jit(web3: Web3) { onchain.mint_block().await; wait_for_condition(TIMEOUT, || async { let amm_balance = dai.balanceOf(*cow_amm.address()).call().await.unwrap(); - let bob_balance = dai - .balanceOf(bob.address().into_alloy()) - .call() - .await - .unwrap(); + let bob_balance = dai.balanceOf(bob.address()).call().await.unwrap(); let amm_received = amm_balance - amm_balance_before; let bob_received = bob_balance - bob_balance_before; // bob and CoW AMM both got surplus and an equal amount - amm_received >= cow_amm_order.buyAmount && bob_received > user_order.buy_amount.into_alloy() + amm_received >= cow_amm_order.buyAmount && bob_received > user_order.buy_amount }) .await .unwrap(); @@ -400,21 +392,21 @@ async fn cow_amm_driver_support(web3: Web3) { // since changing the forked number would result in very costly ~1 year of event // syncing, we deploy the following SCs let deployed_contracts = { - let balances = Balances::Instance::deploy(web3.alloy.clone()) + let balances = Balances::Instance::deploy(web3.provider.clone()) .await .unwrap(); - let signatures = Signatures::Instance::deploy(web3.alloy.clone()) + let signatures = Signatures::Instance::deploy(web3.provider.clone()) .await .unwrap(); DeployedContracts { - balances: Some(balances.address().into_legacy()), - signatures: Some(signatures.address().into_legacy()), + balances: Some(*balances.address()), + signatures: Some(*signatures.address()), } }; let mut onchain = OnchainComponents::deployed_with(web3.clone(), deployed_contracts).await; - let [solver] = onchain.make_solvers_forked(to_wei(11)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(11u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; // find some USDC available onchain const USDC_WHALE_MAINNET: Address = address!("28c6c06298d514db089934071355e5743bf21d60"); @@ -422,38 +414,34 @@ async fn cow_amm_driver_support(web3: Web3) { // create necessary token instances let usdc = ERC20::Instance::new( address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), - web3.alloy.clone(), + web3.provider.clone(), ); let usdt = ERC20::Instance::new( address!("dac17f958d2ee523a2206206994597c13d831ec7"), - web3.alloy.clone(), + web3.provider.clone(), ); // Unbalance the cow amm enough that baseline is able to rebalance // it with the current liquidity. - const USDC_WETH_COW_AMM: H160 = H160(hex_literal::hex!( - "f08d4dea369c456d26a3168ff0024b904f2d8b91" - )); + const USDC_WETH_COW_AMM: Address = address!("f08d4dea369c456d26a3168ff0024b904f2d8b91"); let weth_balance = onchain .contracts() .weth - .balanceOf(USDC_WETH_COW_AMM.into_alloy()) + .balanceOf(USDC_WETH_COW_AMM) .call() .await .unwrap(); // Assuming that the pool is balanced, imbalance it by ~30%, so the driver can // crate a CoW AMM JIT order. This imbalance shouldn't exceed 50%, since // such an order will be rejected by the SC: - let weth_to_send = weth_balance - .checked_div(alloy::primitives::U256::from(3)) - .unwrap(); + let weth_to_send = weth_balance.checked_div(U256::from(3)).unwrap(); onchain .contracts() .weth .deposit() - .from(solver.address().into_alloy()) + .from(solver.address()) .value(weth_to_send) .send_and_watch() .await @@ -461,31 +449,24 @@ async fn cow_amm_driver_support(web3: Web3) { onchain .contracts() .weth - .transfer(USDC_WETH_COW_AMM.into_alloy(), weth_to_send) - .from(solver.address().into_alloy()) + .transfer(USDC_WETH_COW_AMM, weth_to_send) + .from(solver.address()) .send_and_watch() .await .unwrap(); - let amm_usdc_balance_before = usdc - .balanceOf(USDC_WETH_COW_AMM.into_alloy()) - .call() - .await - .unwrap(); + let amm_usdc_balance_before = usdc.balanceOf(USDC_WETH_COW_AMM).call().await.unwrap(); // Now we create an unfillable order just so the orderbook is not empty. // Otherwise all auctions would be skipped because there is no user order to // settle. // Give trader some USDC - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( - usdc.transfer( - trader.address().into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) - .from(USDC_WHALE_MAINNET) - .into_transaction_request(), + usdc.transfer(trader.address(), 1000u64.matom()) + .from(USDC_WHALE_MAINNET) + .into_transaction_request(), ImpersonateConfig { fund_amount: None, stop_impersonate: true, @@ -498,27 +479,24 @@ async fn cow_amm_driver_support(web3: Web3) { .unwrap(); // Approve GPv2 for trading - usdc.approve( - onchain.contracts().allowance.into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) - .from(trader.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); + usdc.approve(onchain.contracts().allowance, 1000u64.matom()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); // Empty liquidity of one of the AMMs to test EmptyPoolRemoval maintenance job. const ZERO_BALANCE_AMM: Address = address!("b3bf81714f704720dcb0351ff0d42eca61b069fc"); let pendle_token = ERC20::Instance::new( address!("808507121b80c02388fad14726482e061b8da827"), - web3.alloy.clone(), + web3.provider.clone(), ); let balance = pendle_token .balanceOf(ZERO_BALANCE_AMM) .call() .await .unwrap(); - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( pendle_token .transfer( @@ -548,7 +526,7 @@ async fn cow_amm_driver_support(web3: Web3) { ); // spawn a mock solver so we can later assert things about the received auction - let mock_solver = Mock::default(); + let mock_solver = Mock::new().await; colocation::start_driver_with_config_override( onchain.contracts(), vec![ @@ -567,6 +545,8 @@ async fn cow_amm_driver_support(web3: Web3) { endpoint: mock_solver.url.clone(), base_tokens: vec![], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, ], colocation::LiquidityProvider::UniswapV2, @@ -584,29 +564,45 @@ factory = "0xf76c421bAb7df8548604E60deCCcE50477C10462" services .start_autopilot( None, - vec![ - format!("--drivers=test_solver|http://localhost:11088/test_solver|{},mock_solver|http://localhost:11088/mock_solver|{}", const_hex::encode(solver.address()), const_hex::encode(solver.address())), - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver" - .to_string(), - // it uses an older helper contract that was deployed before the desired cow amm - "--cow-amm-configs=0xf76c421bAb7df8548604E60deCCcE50477C10462|0x3FF0041A614A9E6Bf392cbB961C97DA214E9CB31|20476672".to_string() - ], + Configuration { + drivers: vec![ + Solver::test("test_solver", solver.address()), + Solver::test("mock_solver", solver.address()), + ], + cow_amm: configs::autopilot::cow_amm::CowAmmGroupConfig { + contracts: vec![configs::autopilot::cow_amm::CowAmmConfig { + factory: address!("f76c421bAb7df8548604E60deCCcE50477C10462"), + helper: address!("3FF0041A614A9E6Bf392cbB961C97DA214E9CB31"), + index_start: 20476672, + }], + ..Default::default() + }, + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test_no_drivers() + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; onchain.mint_block().await; // Place Orders let order = OrderCreation { - sell_token: usdc.address().into_legacy(), - sell_amount: to_wei_with_exp(1000, 6), - buy_token: usdt.address().into_legacy(), - buy_amount: to_wei_with_exp(2000, 6), + sell_token: *usdc.address(), + sell_amount: 1000u64.matom(), + buy_token: *usdt.address(), + buy_amount: 2000u64.matom(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -614,18 +610,18 @@ factory = "0xf76c421bAb7df8548604E60deCCcE50477C10462" .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); // Warm up co-located driver by quoting the order (otherwise placing an order // may time out) let _ = services .submit_quote(&OrderQuoteRequest { - sell_token: usdc.address().into_legacy(), - buy_token: usdt.address().into_legacy(), + sell_token: *usdc.address(), + buy_token: *usdt.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei_with_exp(1000, 6).try_into().unwrap(), + value: (1000u64.matom()).try_into().unwrap(), }, }, ..Default::default() @@ -643,11 +639,7 @@ factory = "0xf76c421bAb7df8548604E60deCCcE50477C10462" onchain.mint_block().await; tokio::time::sleep(tokio::time::Duration::from_millis(1_000)).await; - let amm_usdc_balance_after = usdc - .balanceOf(USDC_WETH_COW_AMM.into_alloy()) - .call() - .await - .unwrap(); + let amm_usdc_balance_after = usdc.balanceOf(USDC_WETH_COW_AMM).call().await.unwrap(); // CoW AMM traded automatically amm_usdc_balance_after != amm_usdc_balance_before }) @@ -671,8 +663,8 @@ factory = "0xf76c421bAb7df8548604E60deCCcE50477C10462" // all tokens traded by the cow amms tracing::info!("Waiting for all relevant native prices to be indexed."); let expected_prices = [ - addr!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH - addr!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC + address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH + address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC ]; wait_for_condition(TIMEOUT, || async { @@ -690,8 +682,8 @@ factory = "0xf76c421bAb7df8548604E60deCCcE50477C10462" let found_amm_jit_orders = auctions.iter().any(|auction| { auction.orders.iter().any(|order| { order.owner == USDC_WETH_COW_AMM - && order.sell_token == onchain.contracts().weth.address().into_legacy() - && order.buy_token == usdc.address().into_legacy() + && order.sell_token == *onchain.contracts().weth.address() + && order.buy_token == *usdc.address() }) }); @@ -714,11 +706,11 @@ async fn local_node_cow_amm_opposite_direction() { async fn cow_amm_opposite_direction(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(100)).await; - let [bob, cow_amm_owner] = onchain.make_accounts(to_wei(1000)).await; + let [solver] = onchain.make_solvers(100u64.eth()).await; + let [bob, cow_amm_owner] = onchain.make_accounts(1000u64.eth()).await; let [dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(100)) + .deploy_tokens_with_weth_uni_v2_pools(300_000u64.eth(), 100u64.eth()) .await; // No need to fund the buffers since we're testing the CoW AMM directly filling @@ -726,24 +718,23 @@ async fn cow_amm_opposite_direction(web3: Web3) { // Set up the CoW AMM as before let oracle = - contracts::alloy::cow_amm::CowAmmUniswapV2PriceOracle::Instance::deploy(web3.alloy.clone()) + contracts::cow_amm::CowAmmUniswapV2PriceOracle::Instance::deploy(web3.provider.clone()) .await .unwrap(); - let cow_amm_factory = - contracts::alloy::cow_amm::CowAmmConstantProductFactory::Instance::deploy( - web3.alloy.clone(), - *onchain.contracts().gp_settlement.address(), - ) - .await - .unwrap(); + let cow_amm_factory = contracts::cow_amm::CowAmmConstantProductFactory::Instance::deploy( + web3.provider.clone(), + *onchain.contracts().gp_settlement.address(), + ) + .await + .unwrap(); // Fund the CoW AMM owner with DAI and WETH and approve the factory to transfer // them - dai.mint(cow_amm_owner.address(), to_wei(2_000)).await; + dai.mint(cow_amm_owner.address(), 2_000u64.eth()).await; - dai.approve(*cow_amm_factory.address(), eth(2_000)) - .from(cow_amm_owner.address().into_alloy()) + dai.approve(*cow_amm_factory.address(), 2_000u64.eth()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -752,16 +743,16 @@ async fn cow_amm_opposite_direction(web3: Web3) { .contracts() .weth .deposit() - .from(cow_amm_owner.address().into_alloy()) - .value(eth(1)) + .from(cow_amm_owner.address()) + .value(1u64.eth()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .approve(*cow_amm_factory.address(), eth(1)) - .from(cow_amm_owner.address().into_alloy()) + .approve(*cow_amm_factory.address(), 1u64.eth()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -770,8 +761,8 @@ async fn cow_amm_opposite_direction(web3: Web3) { .contracts() .weth .deposit() - .from(solver.address().into_alloy()) - .value(eth(1)) + .from(solver.address()) + .value(1u64.eth()) .send_and_watch() .await .unwrap(); @@ -786,7 +777,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { let cow_amm_address = cow_amm_factory .ammDeterministicAddress( - cow_amm_owner.address().into_alloy(), + cow_amm_owner.address(), *dai.address(), *onchain.contracts().weth.address(), ) @@ -802,24 +793,23 @@ async fn cow_amm_opposite_direction(web3: Web3) { cow_amm_factory .create( *dai.address(), - to_wei(2_000).into_alloy(), + 2_000u64.eth(), *onchain.contracts().weth.address(), - to_wei(1).into_alloy(), + 1u64.eth(), U256::ZERO, // min traded token *oracle.address(), Bytes::copy_from_slice(&oracle_data), FixedBytes(APP_DATA), ) - .from(cow_amm_owner.account().address().into_alloy()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); - let cow_amm = - contracts::alloy::cow_amm::CowAmm::Instance::new(cow_amm_address, web3.alloy.clone()); + let cow_amm = contracts::cow_amm::CowAmm::Instance::new(cow_amm_address, web3.provider.clone()); // Start system with the mocked solver. Baseline is still required for the // native price estimation. - let mock_solver = Mock::default(); + let mock_solver = Mock::new().await; colocation::start_driver( onchain.contracts(), vec![ @@ -838,48 +828,54 @@ async fn cow_amm_opposite_direction(web3: Web3) { endpoint: mock_solver.url.clone(), base_tokens: vec![], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, ], colocation::LiquidityProvider::UniswapV2, true, ); let services = Services::new(&onchain).await; + services .start_autopilot( None, - vec![ - format!( - "--drivers=mock_solver|http://localhost:11088/mock_solver|{}", - const_hex::encode(solver.address()) - ), - "--price-estimation-drivers=mock_solver|http://localhost:11088/mock_solver" - .to_string(), - ], + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "mock_solver", + "http://localhost:11088/mock_solver", + )]), + ..Configuration::test("mock_solver", solver.address()) + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=mock_solver|http://localhost:11088/mock_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "mock_solver", + "http://localhost:11088/mock_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Get the current block timestamp let block = web3 - .eth() - .block(BlockId::Number(BlockNumber::Latest)) + .provider + .get_block(alloy::eips::BlockId::latest()) .await .unwrap() .unwrap(); - let valid_to = block.timestamp.as_u32() + 300; - let executed_amount = to_wei(230); + let valid_to = u32::try_from(block.header.timestamp).unwrap() + 300; + let executed_amount = 230u64.eth(); // CoW AMM order remains the same (selling WETH for DAI) - let cow_amm_order = contracts::alloy::cow_amm::CowAmm::GPv2Order::Data { + let cow_amm_order = contracts::cow_amm::CowAmm::GPv2Order::Data { sellToken: *onchain.contracts().weth.address(), buyToken: *dai.address(), receiver: Default::default(), - sellAmount: U256::from(10).pow(U256::from(17)), - buyAmount: executed_amount.into_alloy(), + sellAmount: 0.1.eth(), + buyAmount: executed_amount, validTo: valid_to, appData: FixedBytes(APP_DATA), feeAmount: U256::ZERO, @@ -897,7 +893,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { .unwrap(), ), // erc20 }; - let trading_params = contracts::alloy::cow_amm::CowAmm::ConstantProduct::TradingParams { + let trading_params = contracts::cow_amm::CowAmm::ConstantProduct::TradingParams { minTradedToken0: U256::ZERO, priceOracle: *oracle.address(), priceOracleData: Bytes::copy_from_slice(&oracle_data), @@ -917,22 +913,19 @@ async fn cow_amm_opposite_direction(web3: Web3) { &onchain.contracts().domain_separator, ); let cow_amm_commitment = Call { - target: cow_amm_commitment_data.target.into_legacy(), - value: cow_amm_commitment_data.value.into_legacy(), + target: cow_amm_commitment_data.target, + value: cow_amm_commitment_data.value, calldata: cow_amm_commitment_data.call_data, }; // Fund trader "bob" with DAI and approve allowance - dai.mint(bob.address(), to_wei(250)).await; + dai.mint(bob.address(), 250u64.eth()).await; - dai.approve( - onchain.contracts().allowance.into_alloy(), - alloy::primitives::U256::MAX, - ) - .from(bob.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); + dai.approve(onchain.contracts().allowance, alloy::primitives::U256::MAX) + .from(bob.address()) + .send_and_watch() + .await + .unwrap(); // Get balances before the trade let amm_weth_balance_before = onchain @@ -945,7 +938,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { let bob_weth_balance_before = onchain .contracts() .weth - .balanceOf(bob.address().into_alloy()) + .balanceOf(bob.address()) .call() .await .unwrap(); @@ -955,27 +948,24 @@ async fn cow_amm_opposite_direction(web3: Web3) { tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; // Set the fees appropriately - let fee_cow_amm = ethcontract::U256::exp10(16); // 0.01 WETH - let fee_user = to_wei(1); // 1 DAI + let fee_cow_amm = 0.01.eth(); // 0.01 WETH + let fee_user = 1u64.eth(); // 1 DAI let mocked_solutions = |order_uid: OrderUid| { Solution { id: 1, prices: HashMap::from([ - (dai.address().into_legacy(), to_wei(1)), // 1 DAI = $1 - ( - onchain.contracts().weth.address().into_legacy(), - to_wei(2300), - ), // 1 WETH = $2300 + (*dai.address(), 1u64.eth()), // 1 DAI = $1 + (*onchain.contracts().weth.address(), 2300u64.eth()), // 1 WETH = $2300 ]), trades: vec![ solvers_dto::solution::Trade::Jit(solvers_dto::solution::JitTrade { order: solvers_dto::solution::JitOrder { - sell_token: cow_amm_order.sellToken.into_legacy(), - buy_token: cow_amm_order.buyToken.into_legacy(), - receiver: cow_amm_order.receiver.into_legacy(), - sell_amount: cow_amm_order.sellAmount.into_legacy(), - buy_amount: cow_amm_order.buyAmount.into_legacy(), + sell_token: cow_amm_order.sellToken, + buy_token: cow_amm_order.buyToken, + receiver: cow_amm_order.receiver, + sell_amount: cow_amm_order.sellAmount, + buy_amount: cow_amm_order.buyAmount, partially_fillable: cow_amm_order.partiallyFillable, valid_to: cow_amm_order.validTo, app_data: cow_amm_order.appData.0, @@ -985,7 +975,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { signing_scheme: SigningScheme::Eip1271, signature: signature.clone(), }, - executed_amount: cow_amm_order.sellAmount.into_legacy() - fee_cow_amm, + executed_amount: cow_amm_order.sellAmount - fee_cow_amm, fee: Some(fee_cow_amm), }), solvers_dto::solution::Trade::Fulfillment(solvers_dto::solution::Fulfillment { @@ -1000,6 +990,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { gas: None, flashloans: None, wrappers: vec![], + gas_fee_override: None, } }; @@ -1009,8 +1000,8 @@ async fn cow_amm_opposite_direction(web3: Web3) { let quote_request = OrderQuoteRequest { from: bob.address(), - sell_token: dai.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + sell_token: *dai.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(executed_amount).unwrap(), @@ -1022,25 +1013,21 @@ async fn cow_amm_opposite_direction(web3: Web3) { // Must align with the mocked_solutions. let quote_response = services.submit_quote("e_request).await.unwrap(); assert!(quote_response.verified); - assert_eq!(quote_response.quote.sell_token, dai.address().into_legacy()); + assert_eq!(quote_response.quote.sell_token, *dai.address()); assert_eq!( quote_response.quote.buy_token, - onchain.contracts().weth.address().into_legacy() + *onchain.contracts().weth.address() ); // Ensure the amounts are the same as the solution proposes. assert_eq!(quote_response.quote.sell_amount, executed_amount); - assert_eq!( - quote_response.quote.buy_amount, - ethcontract::U256::exp10(17) - ); + assert_eq!(quote_response.quote.buy_amount, 0.1.eth()); // Place user order where bob sells DAI to buy WETH (opposite direction) let user_order = OrderCreation { - sell_token: dai.address().into_legacy(), + sell_token: *dai.address(), sell_amount: executed_amount, // 230 DAI - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: ethcontract::U256::from(90000000000000000u64), /* 0.09 WETH to generate some - * surplus */ + buy_token: *onchain.contracts().weth.address(), + buy_amount: 0.09.eth(), // 0.09 WETH to generate some surplus valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -1048,7 +1035,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(bob.private_key()).unwrap()), + &bob.signer, ); let user_order_id = services.create_order(&user_order).await.unwrap(); @@ -1070,7 +1057,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { let bob_weth_balance_after = onchain .contracts() .weth - .balanceOf(bob.address().into_alloy()) + .balanceOf(bob.address()) .call() .await .unwrap(); @@ -1079,8 +1066,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { let bob_weth_received = bob_weth_balance_after - bob_weth_balance_before; // Bob should receive WETH, CoW AMM's WETH balance decreases - bob_weth_received >= user_order.buy_amount.into_alloy() - && amm_weth_sent == cow_amm_order.sellAmount + bob_weth_received >= user_order.buy_amount && amm_weth_sent == cow_amm_order.sellAmount }) .await .unwrap(); diff --git a/crates/e2e/tests/e2e/debug_order.rs b/crates/e2e/tests/e2e/debug_order.rs new file mode 100644 index 0000000000..c98fdd4d8d --- /dev/null +++ b/crates/e2e/tests/e2e/debug_order.rs @@ -0,0 +1,277 @@ +use { + configs::test_util::TestDefault, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, + model::{ + debug_report::DebugReport, + order::{OrderCreation, OrderKind}, + signature::EcdsaSigningScheme, + }, + number::units::EthUnit, + reqwest::StatusCode, + shared::web3::Web3, +}; + +#[tokio::test] +#[ignore] +async fn local_node_debug_order() { + run_test(debug_order).await; +} + +async fn debug_order(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(3u64.eth()) + .send_and_watch() + .await + .unwrap(); + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + configs::autopilot::Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + + let order = OrderCreation { + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Buy, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + let uid = services.create_order(&order).await.unwrap(); + onchain.mint_block().await; + + tracing::info!("Waiting for trade."); + let trade_happened = || async { + onchain.mint_block().await; + !token + .balanceOf(trader.address()) + .call() + .await + .unwrap() + .is_zero() + }; + wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); + + let client = services.client(); + + // Helper to fetch the debug report. + let fetch_debug_report = || async { + let response = client + .get(format!("{API_HOST}/restricted/api/v1/debug/order/{uid}")) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + response.json::().await.unwrap() + }; + + // Wait until the debug report is fully populated (settlement data is + // written asynchronously, so we poll until trades appear). + let report_populated = || async { + let report = fetch_debug_report().await; + !report.trades.is_empty() + }; + wait_for_condition(TIMEOUT, report_populated).await.unwrap(); + + // Deserializing into DebugOrderResponse validates all field names and types. + let report = fetch_debug_report().await; + + assert_eq!(report.order_uid, uid); + assert_eq!(report.order.data.kind, OrderKind::Buy); + + assert!( + report.events.len() == 4 || report.events.len() == 5, + "got {:?}", + report.events + ); + assert_eq!(report.events[0].label, "created"); + assert_eq!(report.events[1].label, "ready"); + assert_eq!(report.events[2].label, "executing"); + // The in_flight filtered event may or may not sneak in before traded + // depending on timing. + let last = report.events.last().unwrap(); + assert!( + last.label == "traded" || last.label == "filtered", + "unexpected last event: {:?}", + last + ); + + assert!(!report.trades.is_empty(), "expected at least one trade"); + assert!(!report.auctions.is_empty(), "expected at least one auction"); + + let auction = &report.auctions[0]; + assert!( + !auction.native_prices.is_empty(), + "expected native prices for sell/buy tokens" + ); + assert!( + !auction.proposed_solutions.is_empty(), + "expected at least one proposed solution" + ); + assert!( + !auction.executions.is_empty(), + "expected at least one execution" + ); + assert!( + !auction.settlement_attempts.is_empty(), + "expected at least one settlement attempt" + ); + + // Non-existent order -> 404. + let fake_uid = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/order/{fake_uid}" + )) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::NOT_FOUND); +} + +#[tokio::test] +#[ignore] +async fn local_node_debug_order_filter_reason() { + run_test(debug_order_filter_reason).await; +} + +async fn debug_order_filter_reason(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(3u64.eth()) + .send_and_watch() + .await + .unwrap(); + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + configs::autopilot::Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + + let order = OrderCreation { + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Buy, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + let uid = services.create_order(&order).await.unwrap(); + + // Withdraw WETH so the order becomes invalid due to insufficient balance. + onchain + .contracts() + .weth + .withdraw(3u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let client = services.client(); + + // Wait for the autopilot to pick up the order and mark it invalid. + let has_invalid_event = || async { + onchain.mint_block().await; + let response = client + .get(format!("{API_HOST}/restricted/api/v1/debug/order/{uid}")) + .send() + .await + .unwrap(); + let report = response.json::().await.unwrap(); + report + .events + .iter() + .any(|e| e.label == "invalid" && e.reason.is_some()) + }; + wait_for_condition(TIMEOUT, has_invalid_event) + .await + .unwrap(); + + let response = client + .get(format!("{API_HOST}/restricted/api/v1/debug/order/{uid}")) + .send() + .await + .unwrap(); + let report = response.json::().await.unwrap(); + + let invalid_event = report + .events + .iter() + .find(|e| e.label == "invalid") + .expect("expected an invalid event"); + assert_eq!( + invalid_event.reason.as_deref(), + Some("insufficient_balance"), + "expected insufficient_balance reason, got {:?}", + invalid_event.reason + ); + + // Non-invalid events should have no reason. + let created = report + .events + .iter() + .find(|e| e.label == "created") + .expect("expected a created event"); + assert_eq!(created.reason, None); +} diff --git a/crates/e2e/tests/e2e/deprecated_endpoints.rs b/crates/e2e/tests/e2e/deprecated_endpoints.rs new file mode 100644 index 0000000000..1c803cd433 --- /dev/null +++ b/crates/e2e/tests/e2e/deprecated_endpoints.rs @@ -0,0 +1,88 @@ +use { + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, + model::{ + order::{CancellationPayload, OrderCancellation, OrderCreation, OrderKind}, + signature::EcdsaSigningScheme, + }, + number::units::EthUnit, + shared::web3::Web3, +}; + +#[tokio::test] +#[ignore] +async fn local_node_single_order_cancellation() { + run_test(single_order_cancellation).await; +} + +/// Test the deprecated single order cancellation endpoint (DELETE +/// /api/v1/orders/{UID}) +async fn single_order_cancellation(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + let [token_a, token_b] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + token_a.mint(trader.address(), 10u64.eth()).await; + + token_a + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + // Create an order + let order = OrderCreation { + sell_token: *token_a.address(), + sell_amount: 5u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let uid = services.create_order(&order).await.unwrap(); + + // Verify order exists + let order_result = services.get_order(&uid).await; + assert!( + order_result.is_ok(), + "Order should exist before cancellation" + ); + + // Cancel the order using the deprecated single order cancellation endpoint + let cancellation = + OrderCancellation::for_order(uid, &onchain.contracts().domain_separator, &trader.signer); + + let payload = CancellationPayload { + signature: cancellation.signature, + signing_scheme: cancellation.signing_scheme, + }; + + let result = services.cancel_order_single(&uid, &payload).await; + + assert_eq!( + result.unwrap(), + "Cancelled", + "Cancellation response should be 'Cancelled'" + ); + + // Verify order status is cancelled + let status = services.get_order_status(&uid).await.unwrap(); + assert!( + matches!(status, orderbook::dto::order::Status::Cancelled), + "Order should be in Cancelled status" + ); +} diff --git a/crates/e2e/tests/e2e/eip4626.rs b/crates/e2e/tests/e2e/eip4626.rs new file mode 100644 index 0000000000..492c375e9d --- /dev/null +++ b/crates/e2e/tests/e2e/eip4626.rs @@ -0,0 +1,417 @@ +use { + ::alloy::{ + primitives::{Address, U256, address}, + providers::ext::{AnvilApi, ImpersonateConfig}, + }, + configs::{ + autopilot::{Configuration, native_price::NativePriceConfig}, + native_price_estimators::{NativePriceEstimator, NativePriceEstimators}, + test_util::TestDefault, + }, + contracts::ERC20, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, + futures::{FutureExt, future::BoxFuture}, + model::{ + order::BUY_ETH_ADDRESS, + quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, + }, + number::units::EthUnit, + price_estimation::{ + HEALTHY_PRICE_ESTIMATION_TIME, + native::{Eip4626, NativePriceEstimateResult, NativePriceEstimating}, + }, + shared::web3::Web3, + std::time::Duration, + testlib::tokens::GNO, +}; + +/// The block number from which we will fetch state for the forked test. +const FORK_BLOCK_MAINNET: u64 = 23112197; + +/// sDAI (Savings DAI) – an EIP-4626 vault wrapping DAI. +const SDAI: Address = address!("83F20F44975D03b1b09e64809B757c47f942BEeA"); + +/// sDAI whale at [`FORK_BLOCK_MAINNET`]. +const SDAI_WHALE: Address = address!("4C612E3B15b96Ff9A6faED838F8d07d479a8dD4c"); + +/// WETH on mainnet. +const WETH: Address = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); + +/// USDC on mainnet. The proxy has no `asset()` selector, so calls to it +/// revert with *empty* revert data — the regression case below. +const USDC: Address = address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); + +/// DAI on mainnet — 18-decimal counterpart to USDC for testing the +/// `6-decimal vault wrapping 18-decimal asset` direction. +const DAI: Address = address!("6B175474E89094C44Da98b954EedeAC495271d0F"); + +#[tokio::test] +#[ignore] +async fn forked_node_mainnet_eip4626_native_price() { + run_forked_test_with_block_number( + eip4626_native_price_test, + std::env::var("FORK_URL_MAINNET") + .expect("FORK_URL_MAINNET must be set to run forked tests"), + FORK_BLOCK_MAINNET, + ) + .await; +} + +async fn eip4626_native_price_test(web3: Web3) { + let mut onchain = OnchainComponents::deployed(web3.clone()).await; + + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + + let sdai = ERC20::Instance::new(SDAI, web3.provider.clone()); + + // Transfer sDAI from whale to trader. + web3.provider + .anvil_send_impersonated_transaction_with_config( + sdai.transfer(trader.address(), 1000u64.eth()) + .from(SDAI_WHALE) + .into_transaction_request(), + ImpersonateConfig { + fund_amount: Some(1u64.eth()), + stop_impersonate: true, + }, + ) + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + // Approve the vault-relayer for trading. + sdai.approve(onchain.contracts().allowance, 1000u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let driver_url: url::Url = "http://localhost:11088/test_solver".parse().unwrap(); + let autopilot_config = Configuration { + native_price_estimation: NativePriceConfig { + eip4626: true, + estimators: NativePriceEstimators::new(vec![vec![NativePriceEstimator::driver( + "test_quoter".to_string(), + driver_url, + )]]), + shared: configs::native_price::NativePriceConfig { + results_required: 1.try_into().unwrap(), + ..Default::default() + }, + ..NativePriceConfig::test_default() + }, + ..Configuration::test("test_solver", solver.address()) + }; + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + autopilot_config, + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + + onchain.mint_block().await; + + // Submit a quote selling sDAI for WETH. If the EIP-4626 native price + // estimator works, the protocol can price sDAI and the quote succeeds. + let quote = services + .submit_quote(&OrderQuoteRequest { + from: trader.address(), + sell_token: SDAI, + buy_token: WETH, + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: (100u64.eth()).try_into().unwrap(), + }, + }, + ..Default::default() + }) + .await; + + assert!( + quote.is_ok(), + "quote for sDAI should succeed with EIP-4626 native price estimator: {:?}", + quote.err() + ); +} + +#[tokio::test] +#[ignore] +async fn forked_node_mainnet_eip4626_recursive_native_price() { + run_forked_test_with_block_number( + eip4626_recursive_native_price_test, + std::env::var("FORK_URL_MAINNET") + .expect("FORK_URL_MAINNET must be set to run forked tests"), + FORK_BLOCK_MAINNET, + ) + .await; +} + +/// Tests pricing of mock EIP-4626 vaults with non-trivial conversion rates. +/// Deploys wrapper vaults on top of sDAI (which itself wraps DAI) with +/// different rates and verifies native prices are proportional to their +/// conversion rates. +async fn eip4626_recursive_native_price_test(web3: Web3) { + let mut onchain = OnchainComponents::deployed(web3.clone()).await; + + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; + + // Deploy mock EIP-4626 vaults wrapping sDAI with different conversion rates. + // Each wrapper applies `convertToAssets(shares) = shares * num / den`, so a + // (3, 2) wrapper means 1 share = 1.5 sDAI, making it 1.5x the sDAI price. + let rates: &[(u64, u64)] = &[(3, 2), (2, 1), (1, 3)]; + let mut wrapper_addrs = Vec::with_capacity(rates.len()); + for &(num, den) in rates { + let wrapper = contracts::test::MockERC4626Wrapper::Instance::deploy( + web3.provider.clone(), + SDAI, + 18u8, + U256::from(num), + U256::from(den), + ) + .await + .unwrap(); + wrapper_addrs.push(*wrapper.address()); + } + + let driver_url: url::Url = "http://localhost:11088/test_solver".parse().unwrap(); + let autopilot_config = Configuration { + native_price_estimation: NativePriceConfig { + eip4626: true, + estimators: NativePriceEstimators::new(vec![vec![NativePriceEstimator::driver( + "test_quoter".to_string(), + driver_url, + )]]), + shared: configs::native_price::NativePriceConfig { + results_required: 1.try_into().unwrap(), + ..Default::default() + }, + ..NativePriceConfig::test_default() + }, + ..Configuration::test("test_solver", solver.address()) + }; + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + autopilot_config, + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + + onchain.mint_block().await; + + // Verify native prices: use the first wrapper (3/2) as a baseline and + // check that the others are priced proportionally to their conversion rate. + let baseline_addr = wrapper_addrs[0]; + wait_for_condition(TIMEOUT, || async { + services.get_native_price(&baseline_addr).await.is_ok() + }) + .await + .expect("native price for wrapper (3/2) should be available"); + let baseline_price = services + .get_native_price(&baseline_addr) + .await + .unwrap() + .price; + + // Wrapper (2/1) has rate 2/1 vs baseline 3/2, so its price should be + // (2/1) / (3/2) = 4/3 of the baseline. + let addr = wrapper_addrs[1]; + wait_for_condition(TIMEOUT, || async { + services.get_native_price(&addr).await.is_ok() + }) + .await + .expect("native price for wrapper (2/1) should be available"); + let price = services.get_native_price(&addr).await.unwrap().price; + let ratio = price / baseline_price; + assert!( + (ratio - 4.0 / 3.0).abs() / (4.0 / 3.0) < 0.01, + "wrapper (2/1) price ratio to baseline (3/2) should be 4/3: got {ratio:.6}", + ); + + // Wrapper (1/3) has rate 1/3 vs baseline 3/2, so its price should be + // (1/3) / (3/2) = 2/9 of the baseline. + let addr = wrapper_addrs[2]; + wait_for_condition(TIMEOUT, || async { + services.get_native_price(&addr).await.is_ok() + }) + .await + .expect("native price for wrapper (1/3) should be available"); + let price = services.get_native_price(&addr).await.unwrap().price; + let ratio = price / baseline_price; + assert!( + (ratio - 2.0 / 9.0).abs() / (2.0 / 9.0) < 0.01, + "wrapper (1/3) price ratio to baseline (3/2) should be 2/9: got {ratio:.6}", + ); +} + +/// Vault and underlying decimals must be threaded through `conversion_rate` +/// correctly in both directions. Native prices are quoted per *atom*, so a +/// wrapper whose whole-share rate is 1:1 with its underlying must still be +/// priced differently when their decimals differ — by exactly +/// `10^(asset_decimals - vault_decimals)`. Exercises both asymmetries: +/// - 18-decimal vault wrapping 6-decimal USDC → per-atom factor = `10^-12` +/// (lands the vault in DAI's `~10^-4` wei/atom range, not USDC's `~10^8`). +/// - 6-decimal vault wrapping 18-decimal DAI → per-atom factor = `10^12` +/// (vice versa). +#[tokio::test] +#[ignore] +async fn forked_node_mainnet_eip4626_decimal_mismatch_native_price() { + run_forked_test_with_block_number( + eip4626_decimal_mismatch_native_price_test, + std::env::var("FORK_URL_MAINNET") + .expect("FORK_URL_MAINNET must be set to run forked tests"), + FORK_BLOCK_MAINNET, + ) + .await; +} + +async fn eip4626_decimal_mismatch_native_price_test(web3: Web3) { + let mut onchain = OnchainComponents::deployed(web3.clone()).await; + + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; + + // `MockERC4626Wrapper` implements `convertToAssets(shares) = shares * num + // / den`. Setting `num` and `den` to the atom-count of one whole asset + // and one whole vault token (respectively) yields a 1:1 *whole-token* + // rate — `convertToAssets(one_whole_vault) = one_whole_asset`. + let one_whole_6_dec = 1u64.matom(); // 10^6 atoms = 1 whole 6-decimal token + let one_whole_18_dec = 1u64.eth(); // 10^18 atoms = 1 whole 18-decimal token + + // 18-decimal wrapper of 6-decimal USDC at a 1:1 whole-token rate. + // `convertToAssets(10^18) = 10^18 * 10^6 / 10^18 = 10^6` (= 1 whole USDC + // in atoms), so the per-atom factor is `10^-12`. + let wrapper_18_over_6 = contracts::test::MockERC4626Wrapper::Instance::deploy( + web3.provider.clone(), + USDC, + 18u8, + one_whole_6_dec, // num: atoms in 1 whole asset (USDC) + one_whole_18_dec, // den: atoms in 1 whole vault share + ) + .await + .unwrap(); + let wrapper_18_over_6_addr = *wrapper_18_over_6.address(); + + // 6-decimal wrapper of 18-decimal DAI at a 1:1 whole-token rate. + // `convertToAssets(10^6) = 10^6 * 10^18 / 10^6 = 10^18` (= 1 whole DAI in + // atoms), so the per-atom factor is `10^12`. + let wrapper_6_over_18 = contracts::test::MockERC4626Wrapper::Instance::deploy( + web3.provider.clone(), + DAI, + 6u8, + one_whole_18_dec, // num: atoms in 1 whole asset (DAI) + one_whole_6_dec, // den: atoms in 1 whole vault share + ) + .await + .unwrap(); + let wrapper_6_over_18_addr = *wrapper_6_over_18.address(); + + let driver_url: url::Url = "http://localhost:11088/test_solver".parse().unwrap(); + let autopilot_config = Configuration { + native_price_estimation: NativePriceConfig { + eip4626: true, + estimators: NativePriceEstimators::new(vec![vec![NativePriceEstimator::driver( + "test_quoter".to_string(), + driver_url, + )]]), + shared: configs::native_price::NativePriceConfig { + results_required: 1.try_into().unwrap(), + ..Default::default() + }, + ..NativePriceConfig::test_default() + }, + ..Configuration::test("test_solver", solver.address()) + }; + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + autopilot_config, + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + + onchain.mint_block().await; + + let fetch_price = async |addr: &Address, label: &str| -> f64 { + wait_for_condition(TIMEOUT, || async { + services.get_native_price(addr).await.is_ok() + }) + .await + .unwrap_or_else(|_| panic!("native price for {label} should be available")); + services.get_native_price(addr).await.unwrap().price + }; + + let usdc_price = fetch_price(&USDC, "USDC").await; + let dai_price = fetch_price(&DAI, "DAI").await; + + // 18→6: wrapper is priced per-atom like an 18-decimal stablecoin (DAI's + // range), so `wrapper_price / usdc_price ≈ 10^-12`. + let wrapper_18_over_6_price = fetch_price(&wrapper_18_over_6_addr, "18→6 wrapper").await; + let ratio = wrapper_18_over_6_price / usdc_price; + assert!( + (ratio - 1e-12).abs() / 1e-12 < 0.01, + "18→6 wrapper / USDC ratio should be 1e-12, got {ratio:e}", + ); + + // 6→18: wrapper is priced per-atom like a 6-decimal stablecoin (USDC's + // range), so `wrapper_price / dai_price ≈ 10^12`. + let wrapper_6_over_18_price = fetch_price(&wrapper_6_over_18_addr, "6→18 wrapper").await; + let ratio = wrapper_6_over_18_price / dai_price; + assert!( + (ratio - 1e12).abs() / 1e12 < 0.01, + "6→18 wrapper / DAI ratio should be 1e12, got {ratio:e}", + ); +} + +/// Regression: tokens that revert `asset()` with empty data (e.g. USDC) must +/// classify as non-vault, not abort as a transport failure. +#[tokio::test] +#[ignore] +async fn forked_node_mainnet_eip4626_empty_revert_terminal_token() { + run_forked_test_with_block_number( + eip4626_empty_revert_terminal_token_test, + std::env::var("FORK_URL_MAINNET") + .expect("FORK_URL_MAINNET must be set to run forked tests"), + FORK_BLOCK_MAINNET, + ) + .await; +} + +async fn eip4626_empty_revert_terminal_token_test(web3: Web3) { + // USDC is expected to classify as non-vault, so `inner`'s price round-trips + // unchanged — any fixed value works. + let expected_price = 0.0001; + let inner = FixedPrice(expected_price); + let estimator = Eip4626::new(Box::new(inner), web3.provider); + + for token in [BUY_ETH_ADDRESS, USDC, GNO] { + let price = estimator + .estimate_native_price(token, HEALTHY_PRICE_ESTIMATION_TIME) + .await + .expect("empty-revert on terminal token must not abort the unwrap"); + assert_eq!(price, expected_price); + } +} + +struct FixedPrice(f64); + +impl NativePriceEstimating for FixedPrice { + fn estimate_native_price( + &self, + _token: Address, + _timeout: Duration, + ) -> BoxFuture<'_, NativePriceEstimateResult> { + let price = self.0; + async move { Ok(price) }.boxed() + } +} diff --git a/crates/e2e/tests/e2e/eth_integration.rs b/crates/e2e/tests/e2e/eth_integration.rs index d84854417b..fcd368ba7c 100644 --- a/crates/e2e/tests/e2e/eth_integration.rs +++ b/crates/e2e/tests/e2e/eth_integration.rs @@ -1,19 +1,14 @@ use { - e2e::setup::{eth, *}, - ethcontract::prelude::Address, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ::alloy::{primitives::Address, providers::Provider}, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{BUY_ETH_ADDRESS, OrderCreation, OrderKind}, quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::EcdsaSigningScheme, }, - number::nonzero::U256 as NonZeroU256, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::{nonzero::NonZeroU256, units::EthUnit}, + shared::web3::Web3, }; #[tokio::test] @@ -25,33 +20,33 @@ async fn local_node_eth_integration() { async fn eth_integration(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a, trader_b] = onchain.make_accounts(1u64.eth()).await; // Create & mint tokens to trade, pools for fee connections let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) + .deploy_tokens_with_weth_uni_v2_pools(100_000u64.eth(), 100_000u64.eth()) .await; - token.mint(trader_a.address(), to_wei(51)).await; - token.mint(trader_b.address(), to_wei(51)).await; + token.mint(trader_a.address(), 51u64.eth()).await; + token.mint(trader_b.address(), 51u64.eth()).await; // Approve GPv2 for trading token - .approve(onchain.contracts().allowance.into_alloy(), eth(51)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 51u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token - .approve(onchain.contracts().allowance.into_alloy(), eth(51)) - .from(trader_b.address().into_alloy()) + .approve(onchain.contracts().allowance, 51u64.eth()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); - let trader_a_eth_balance_before = web3.eth().balance(trader_a.address(), None).await.unwrap(); + let trader_a_eth_balance_before = web3.provider.get_balance(trader_a.address()).await.unwrap(); let services = Services::new(&onchain).await; services.start_protocol(solver).await; @@ -65,7 +60,7 @@ async fn eth_integration(web3: Web3) { from: Address::default(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { - value: NonZeroU256::try_from(to_wei(43)).unwrap(), + value: NonZeroU256::try_from(43u64.eth()).unwrap(), }, }, ..Default::default() @@ -73,59 +68,52 @@ async fn eth_integration(web3: Web3) { services.submit_quote(&request).await } }; - quote(token.address().into_legacy(), BUY_ETH_ADDRESS) - .await - .unwrap(); + quote(*token.address(), BUY_ETH_ADDRESS).await.unwrap(); // Eth is only supported as the buy token - let (status, body) = quote(BUY_ETH_ADDRESS, token.address().into_legacy()) - .await - .unwrap_err(); + let (status, body) = quote(BUY_ETH_ADDRESS, *token.address()).await.unwrap_err(); assert_eq!(status, 400, "{body}"); // Place Orders - assert_ne!( - onchain.contracts().weth.address().into_legacy(), - BUY_ETH_ADDRESS - ); + assert_ne!(*onchain.contracts().weth.address(), BUY_ETH_ADDRESS); let order_buy_eth_a = OrderCreation { kind: OrderKind::Buy, - sell_token: token.address().into_legacy(), - sell_amount: to_wei(50), + sell_token: *token.address(), + sell_amount: 50u64.eth(), buy_token: BUY_ETH_ADDRESS, - buy_amount: to_wei(49), + buy_amount: 49u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, ..Default::default() } .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); services.create_order(&order_buy_eth_a).await.unwrap(); let order_buy_eth_b = OrderCreation { kind: OrderKind::Sell, - sell_token: token.address().into_legacy(), - sell_amount: to_wei(50), + sell_token: *token.address(), + sell_amount: 50u64.eth(), buy_token: BUY_ETH_ADDRESS, - buy_amount: to_wei(49), + buy_amount: 49u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, ..Default::default() } .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()), + &trader_b.signer, ); services.create_order(&order_buy_eth_b).await.unwrap(); tracing::info!("Waiting for trade."); onchain.mint_block().await; let trade_happened = || async { - let balance_a = web3.eth().balance(trader_a.address(), None).await.unwrap(); - let balance_b = web3.eth().balance(trader_b.address(), None).await.unwrap(); + let balance_a = web3.provider.get_balance(trader_a.address()).await.unwrap(); + let balance_b = web3.provider.get_balance(trader_b.address()).await.unwrap(); - let trader_a_eth_decreased = (balance_a - trader_a_eth_balance_before) == to_wei(49); - let trader_b_eth_increased = balance_b >= to_wei(49); + let trader_a_eth_decreased = (balance_a - trader_a_eth_balance_before) == 49u64.eth(); + let trader_b_eth_increased = balance_b >= 49u64.eth(); trader_a_eth_decreased && trader_b_eth_increased }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); diff --git a/crates/e2e/tests/e2e/eth_safe.rs b/crates/e2e/tests/e2e/eth_safe.rs index c23ae7eacd..5b9cd7aa32 100644 --- a/crates/e2e/tests/e2e/eth_safe.rs +++ b/crates/e2e/tests/e2e/eth_safe.rs @@ -1,24 +1,13 @@ use { ::alloy::{primitives::U256, providers::Provider}, - e2e::setup::{ - OnchainComponents, - Services, - TIMEOUT, - eth, - run_test, - safe::Safe, - to_wei, - wait_for_condition, - }, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + e2e::setup::{OnchainComponents, Services, TIMEOUT, run_test, safe::Safe, wait_for_condition}, + ethrpc::alloy::CallBuilderExt, model::{ order::{BUY_ETH_ADDRESS, OrderCreation, OrderKind}, signature::{Signature, hashed_eip712_message}, }, - shared::ethrpc::Web3, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -31,25 +20,25 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; - let safe = Safe::deploy(trader.clone(), web3.alloy.clone()).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let safe = Safe::deploy(trader.clone(), web3.provider.clone()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1000), to_wei(1000)) + .deploy_tokens_with_weth_uni_v2_pools(1000u64.eth(), 1000u64.eth()) .await; - token.mint(trader.address(), to_wei(4)).await; + token.mint(trader.address(), 4u64.eth()).await; safe.exec_alloy_call( token - .approve(onchain.contracts().allowance.into_alloy(), eth(4)) + .approve(onchain.contracts().allowance, 4u64.eth()) .into_transaction_request(), ) .await; - token.mint(safe.address().into_legacy(), to_wei(4)).await; + token.mint(safe.address(), 4u64.eth()).await; token - .approve(onchain.contracts().allowance.into_alloy(), eth(4)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 4u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -68,15 +57,15 @@ async fn test(web3: Web3) { .unwrap(); assert_eq!(balance, ::alloy::primitives::U256::ZERO); let mut order = OrderCreation { - from: Some(safe.address().into_legacy()), - sell_token: token.address().into_legacy(), - sell_amount: to_wei(4), + from: Some(safe.address()), + sell_token: *token.address(), + sell_amount: 4u64.eth(), buy_token: BUY_ETH_ADDRESS, - buy_amount: to_wei(3), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, partially_fillable: true, kind: OrderKind::Sell, - receiver: Some(safe.address().into_legacy()), + receiver: Some(safe.address()), ..Default::default() }; order.signature = Signature::Eip1271(safe.sign_message(&hashed_eip712_message( @@ -88,7 +77,7 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); let trade_happened = || async { - let safe_balance = web3.alloy.get_balance(safe.address()).await.unwrap(); + let safe_balance = web3.provider.get_balance(safe.address()).await.unwrap(); // the balance is slightly less because of the fee U256::from(3_899_000_000_000_000_000_u128) <= safe_balance && safe_balance <= U256::from(4_000_000_000_000_000_000_u128) diff --git a/crates/e2e/tests/e2e/ethflow.rs b/crates/e2e/tests/e2e/ethflow.rs index 2d3be7829c..df67390aab 100644 --- a/crates/e2e/tests/e2e/ethflow.rs +++ b/crates/e2e/tests/e2e/ethflow.rs @@ -1,12 +1,18 @@ use { alloy::{ - primitives::{Address, Bytes}, + primitives::{Address, B256, Bytes, U256}, + providers::Provider, rpc::types::TransactionReceipt, }, anyhow::bail, autopilot::database::onchain_order_events::ethflow_events::WRAP_ALL_SELECTOR, - contracts::alloy::{CoWSwapEthFlow, ERC20Mintable, WETH9}, - database::order_events::OrderEventLabel, + configs::{ + autopilot::Configuration, + orderbook::order_validation::OrderValidationConfig, + test_util::TestDefault, + }, + contracts::{CoWSwapEthFlow, ERC20Mintable, WETH9}, + database::{byte_array::ByteArray, order_events::OrderEventLabel}, e2e::setup::{ ACCOUNT_ENDPOINT, API_HOST, @@ -16,24 +22,14 @@ use { TIMEOUT, TRADES_ENDPOINT, TestAccount, - eth, run_test, - to_wei, wait_for_condition, }, - ethcontract::{Account, H160, H256, U256}, - ethrpc::{ - Web3, - alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, - block_stream::timestamp_of_current_block_in_seconds, - }, - hex_literal::hex, + ethrpc::{Web3, alloy::CallBuilderExt, block_stream::timestamp_of_current_block_in_seconds}, model::{ DomainSeparator, order::{ + BUY_ETH_ADDRESS, BuyTokenDestination, EthflowData, OnchainOrderData, @@ -56,13 +52,14 @@ use { signature::{Signature, hashed_eip712_message}, trade::Trade, }, - number::nonzero::U256 as NonZeroU256, - refunder::refund_service::{INVALIDATED_OWNER, NO_OWNER}, + number::{nonzero::NonZeroU256, units::EthUnit}, + refunder::RefundStatus, reqwest::Client, - shared::signature_validator::check_erc1271_result, + signature_validator::check_erc1271_result, + std::ops::DerefMut, }; -const DAI_PER_ETH: u32 = 1_000; +const DAI_PER_ETH: u64 = 1_000; #[tokio::test] #[ignore] @@ -76,6 +73,15 @@ async fn local_node_eth_flow_without_quote() { run_test(eth_flow_without_quote).await; } +/// Native "bridging" round-trip: an ethflow order that sells native ETH and +/// buys native ETH (`BUY_ETH_ADDRESS`), carrying a custom post-hook that stands +/// in for the bridge call. +#[tokio::test] +#[ignore] +async fn local_node_eth_flow_native_bridge_post_hook() { + run_test(eth_flow_native_bridge_post_hook).await; +} + #[tokio::test] #[ignore] async fn local_node_eth_flow_indexing_after_refund() { @@ -93,18 +99,18 @@ async fn local_node_eth_flow_zero_buy_amount() { async fn eth_flow_tx(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(2u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; // Create token with Uniswap pool for price estimation let [dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(DAI_PER_ETH * 1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools((DAI_PER_ETH * 1_000).eth(), 1_000u64.eth()) .await; // Get a quote from the services - let buy_token = dai.address().into_legacy(); - let receiver = H160([0x42; 20]); - let sell_amount = to_wei(1); + let buy_token = *dai.address(); + let receiver = Address::repeat_byte(0x42); + let sell_amount = 1u64.eth(); let intent = EthFlowTradeIntent { sell_amount, buy_token, @@ -115,7 +121,7 @@ async fn eth_flow_tx(web3: Web3) { services.start_protocol(solver).await; let approve_call_data = { - let call_builder = dai.approve(trader.address().into_alloy(), eth(10)); + let call_builder = dai.approve(trader.address(), 10u64.eth()); let calldata = call_builder.calldata(); const_hex::encode_prefixed(calldata) }; @@ -144,7 +150,7 @@ async fn eth_flow_tx(web3: Web3) { }} }} }}"#, - dai.address().into_legacy(), + dai.address(), approve_call_data, onchain.contracts().weth.address(), approve_call_data, @@ -157,13 +163,13 @@ async fn eth_flow_tx(web3: Web3) { app_data: OrderCreationAppData::Hash { hash: app_data::AppDataHash(const_hex::decode(&hash[2..]).unwrap().try_into().unwrap()), }, - ..intent.to_quote_request(trader.account().address(), &onchain.contracts().weth) + ..intent.to_quote_request(trader.address(), &onchain.contracts().weth) }; let quote: OrderQuoteResponse = test_submit_quote(&services, "e_request).await; let valid_to = chrono::offset::Utc::now().timestamp() as u32 - + timestamp_of_current_block_in_seconds(&web3.alloy) + + timestamp_of_current_block_in_seconds(&web3.provider) .await .unwrap() + 3600; @@ -173,7 +179,7 @@ async fn eth_flow_tx(web3: Web3) { let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); submit_order( ðflow_order, - trader.account(), + trader.address(), onchain.contracts(), ethflow_contract, ) @@ -203,7 +209,7 @@ async fn eth_flow_tx(web3: Web3) { ) .await .unwrap(); - order.metadata.executed_fee > U256::zero() + order.metadata.executed_fee > U256::ZERO }; wait_for_condition(TIMEOUT, fee_charged).await.unwrap(); @@ -221,26 +227,26 @@ async fn eth_flow_tx(web3: Web3) { // which proofs that the interactions were correctly sandboxed. let trampoline = *onchain.contracts().hooks.address(); let allowance = dai - .allowance(trampoline, trader.address().into_alloy()) + .allowance(trampoline, trader.address()) .call() .await .unwrap(); - assert_eq!(allowance, eth(10)); + assert_eq!(allowance, 10u64.eth()); let allowance = onchain .contracts() .weth - .allowance(trampoline, trader.address().into_alloy()) + .allowance(trampoline, trader.address()) .call() .await .unwrap(); - assert_eq!(allowance, eth(10)); + assert_eq!(allowance, 10u64.eth()); // Just to be super sure we assert that we indeed were not // able to set an allowance on behalf of the settlement contract. let settlement = onchain.contracts().gp_settlement.address(); let allowance = dai - .allowance(*settlement, trader.address().into_alloy()) + .allowance(*settlement, trader.address()) .call() .await .unwrap(); @@ -249,35 +255,197 @@ async fn eth_flow_tx(web3: Web3) { let allowance = onchain .contracts() .weth - .allowance(*settlement, trader.address().into_alloy()) + .allowance(*settlement, trader.address()) .call() .await .unwrap(); assert_eq!(allowance, alloy::primitives::U256::ZERO); + + // Check that true_valid_to is equal to the ethflow_order's valid to + let uid = ethflow_order + .uid(onchain.contracts(), ethflow_contract) + .await; + let mut db = services.db().acquire().await.unwrap(); + let true_valid_to: (i64,) = sqlx::query_as("SELECT true_valid_to FROM orders WHERE uid = $1") + .bind(ByteArray(uid.0)) + .fetch_one(db.deref_mut()) + .await + .unwrap(); + assert_eq!( + true_valid_to.0, + services + .get_order(&uid) + .await + .unwrap() + .metadata + .ethflow_data + .unwrap() + .user_valid_to + ); +} + +/// Proves the full pipeline a native-bridge integration would rely on: +/// +/// 1. The post-hook (here, the bridge action) is published as an app-data +/// document via `PUT /app_data`. +/// 2. An ethflow order is created on-chain referencing that app-data hash and +/// buying native ETH (`BUY_ETH_ADDRESS`) — a same sell/buy token order in +/// the native-equivalent sense (sell WETH, buy native ETH). +/// 3. The autopilot indexes the on-chain order and resolves the published +/// app-data, attaching the post-hook. +/// 4. The settlement wraps the user's ETH into WETH (ethflow's default +/// `WRAP_ALL` pre-interaction), settles the same-token swap delivering +/// native ETH to the receiver, and finally runs the post-hook. +/// +/// The "bridge" is represented by a `Counter` contract whose `incrementCounter` +/// we assert ran exactly once — the same hook-proving approach used in +/// `hooks.rs` and `submission.rs`. +/// +/// Note: on-chain ethflow orders are not subject to the orderbook's +/// `SameTokensPolicy` during indexing, but the *quote* request is, so the +/// orderbook must run with at least `AllowSell` for this flow to work. +async fn eth_flow_native_bridge_post_hook(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(2u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; + + // Stand-in for the bridge call the post-hook would perform. + let counter = contracts::test::Counter::Instance::deploy(web3.provider.clone()) + .await + .unwrap(); + let increment = counter.incrementCounter("post".to_string()); + let post_call_data = const_hex::encode_prefixed(increment.calldata()); + + let services = Services::new(&onchain).await; + // `AllowSell` is required for the same-token (WETH -> native ETH) quote below. + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + order_validation: OrderValidationConfig { + same_tokens_policy: shared::order_validation::SameTokensPolicy::AllowSell, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }, + solver.clone(), + ) + .await; + + // Publish the app-data carrying the bridge post-hook so both the quote and + // the autopilot can resolve it by hash. + let hash = services + .put_app_data( + None, + &format!( + r#"{{ + "metadata": {{ + "hooks": {{ + "post": [ + {{ + "target": "{:?}", + "callData": "{}", + "gasLimit": "100000" + }} + ] + }} + }} +}}"#, + counter.address(), + post_call_data, + ), + ) + .await + .unwrap(); + + let receiver = Address::repeat_byte(0x42); + let sell_amount = 1u64.eth(); + let quote_request = OrderQuoteRequest { + app_data: OrderCreationAppData::Hash { + hash: app_data::AppDataHash(const_hex::decode(&hash[2..]).unwrap().try_into().unwrap()), + }, + ..EthFlowTradeIntent { + sell_amount, + buy_token: BUY_ETH_ADDRESS, + receiver, + } + .to_quote_request(trader.address(), &onchain.contracts().weth) + }; + let quote = services.submit_quote("e_request).await.unwrap(); + assert!(quote.id.is_some()); + assert!(quote.verified); + + let valid_to = chrono::offset::Utc::now().timestamp() as u32 + + timestamp_of_current_block_in_seconds(&web3.provider) + .await + .unwrap() + + 3600; + let ethflow_order = + ExtendedEthFlowOrder::from_quote("e, valid_to).include_slippage_bps(300); + assert_eq!(ethflow_order.0.buyToken, BUY_ETH_ADDRESS); + + let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); + submit_order( + ðflow_order, + trader.address(), + onchain.contracts(), + ethflow_contract, + ) + .await; + + // The bridge hook must not have run before settlement. + assert_eq!( + counter.counters("post".to_string()).call().await.unwrap(), + U256::ZERO, + ); + + tracing::info!("waiting for trade"); + // The buy side is native ETH (not an ERC20), so we check the native balance. + // The order being settled at all proves the autopilot indexed it. We require + // the receiver to get back roughly the full sell amount to prove the native + // value actually round-tripped out, not just dust. + // + // 95% floor = the order's 3% slippage tolerance (`include_slippage_bps(300)` + // above) plus a small safety margin. It's a "real value vs. dust" floor, not + // a tight bound; lower it if the slippage bps grow. + let min_delivered = sell_amount * U256::from(95) / U256::from(100); + wait_for_condition(TIMEOUT, || async { + onchain.mint_block().await; + web3.provider.get_balance(receiver).await.unwrap() >= min_delivered + }) + .await + .unwrap(); + + assert_eq!( + counter.counters("post".to_string()).call().await.unwrap(), + U256::from(1), + "bridge post-hook must have run exactly once as part of the settlement" + ); } async fn eth_flow_without_quote(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(2u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; // Create token with Uniswap pool for price estimation let [dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(DAI_PER_ETH * 1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools((DAI_PER_ETH * 1_000).eth(), 1_000u64.eth()) .await; let services = Services::new(&onchain).await; services.start_protocol(solver).await; let valid_to = chrono::offset::Utc::now().timestamp() as u32 - + timestamp_of_current_block_in_seconds(&web3.alloy) + + timestamp_of_current_block_in_seconds(&web3.provider) .await .unwrap() + 3600; let ethflow_order = ExtendedEthFlowOrder(CoWSwapEthFlow::EthFlowOrder::Data { buyToken: *dai.address(), - sellAmount: eth(1), + sellAmount: 1u64.eth(), buyAmount: alloy::primitives::U256::ONE, validTo: valid_to, partiallyFillable: false, @@ -290,7 +458,7 @@ async fn eth_flow_without_quote(web3: Web3) { let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); submit_order( ðflow_order, - trader.account(), + trader.address(), onchain.contracts(), ethflow_contract, ) @@ -312,17 +480,17 @@ async fn eth_flow_without_quote(web3: Web3) { async fn eth_flow_indexing_after_refund(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader, dummy_trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(2u64.eth()).await; + let [trader, dummy_trader] = onchain.make_accounts(2u64.eth()).await; let [dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(DAI_PER_ETH * 1000), to_wei(1000)) + .deploy_tokens_with_weth_uni_v2_pools((DAI_PER_ETH * 1000).eth(), 1000u64.eth()) .await; let services = Services::new(&onchain).await; services.start_protocol(solver).await; // Create an order that only exists to be cancelled. - let valid_to = timestamp_of_current_block_in_seconds(&web3.alloy) + let valid_to = timestamp_of_current_block_in_seconds(&web3.provider) .await .unwrap() + 60; @@ -330,11 +498,11 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { &test_submit_quote( &services, &(EthFlowTradeIntent { - sell_amount: 42.into(), - buy_token: dai.address().into_legacy(), - receiver: H160([42; 20]), + sell_amount: alloy::primitives::U256::from(42), + buy_token: *dai.address(), + receiver: Address::repeat_byte(42), }) - .to_quote_request(dummy_trader.account().address(), &onchain.contracts().weth), + .to_quote_request(dummy_trader.address(), &onchain.contracts().weth), ) .await, valid_to, @@ -343,7 +511,7 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); submit_order( &dummy_order, - dummy_trader.account(), + dummy_trader.address(), onchain.contracts(), ethflow_contract, ) @@ -351,15 +519,15 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { onchain.mint_block().await; dummy_order - .mine_order_invalidation(dummy_trader.address().into_alloy(), ethflow_contract) + .mine_order_invalidation(dummy_trader.address(), ethflow_contract) .await; // Create the actual order that should be picked up by the services and matched. - let buy_token = dai.address().into_legacy(); - let receiver = H160([0x42; 20]); - let sell_amount = to_wei(1); + let buy_token = *dai.address(); + let receiver = Address::repeat_byte(0x42); + let sell_amount = 1u64.eth(); let valid_to = chrono::offset::Utc::now().timestamp() as u32 - + timestamp_of_current_block_in_seconds(&web3.alloy) + + timestamp_of_current_block_in_seconds(&web3.provider) .await .unwrap() + 60; @@ -371,7 +539,7 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { buy_token, receiver, }) - .to_quote_request(trader.account().address(), &onchain.contracts().weth), + .to_quote_request(trader.address(), &onchain.contracts().weth), ) .await, valid_to, @@ -379,7 +547,7 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { .include_slippage_bps(300); submit_order( ðflow_order, - trader.account(), + trader.address(), onchain.contracts(), ethflow_contract, ) @@ -408,9 +576,9 @@ async fn test_submit_quote( // Ideally the fee would be nonzero, but this is not the case in the test // environment assert_ne!(response.quote.fee_amount, 0.into()); // Amount is reasonable (±10% from real price) - let approx_output: U256 = response.quote.sell_amount * DAI_PER_ETH; - assert!(response.quote.buy_amount.gt(&(approx_output * 9u64 / 10))); - assert!(response.quote.buy_amount.lt(&(approx_output * 11u64 / 10))); + let approx_output: U256 = response.quote.sell_amount * U256::from(DAI_PER_ETH); + assert!(response.quote.buy_amount > (approx_output * U256::from(9u64) / U256::from(10))); + assert!(response.quote.buy_amount < (approx_output * U256::from(11u64) / U256::from(10))); let OrderQuoteSide::Sell { sell_amount: @@ -429,29 +597,29 @@ async fn test_submit_quote( async fn submit_order( ethflow_order: &ExtendedEthFlowOrder, - user: &Account, + user: Address, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, ) { assert_eq!( ethflow_order.status(contracts, ethflow_contract).await, - EthFlowOrderOnchainStatus::Free + RefundStatus::Invalid ); let result = ethflow_order - .mine_order_creation(user.address().into_alloy(), ethflow_contract) + .mine_order_creation(user, ethflow_contract) .await; assert!(result.status()); // success assert_eq!( ethflow_order.status(contracts, ethflow_contract).await, - EthFlowOrderOnchainStatus::Created(user.address(), ethflow_order.0.validTo) + RefundStatus::NotYetRefunded(user) ); } async fn test_order_availability_in_api( services: &Services<'_>, order: &ExtendedEthFlowOrder, - owner: &H160, + owner: &Address, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, ) { @@ -464,7 +632,7 @@ async fn test_order_availability_in_api( // Api returns eth flow orders for both eth-flow contract address and actual // owner - for address in [owner, ðflow_contract.address().into_legacy()] { + for address in [owner, ethflow_contract.address()] { test_account_query( address, services.client(), @@ -480,7 +648,7 @@ async fn test_order_availability_in_api( async fn test_trade_availability_in_api( client: &Client, order: &ExtendedEthFlowOrder, - owner: &H160, + owner: &Address, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, ) { @@ -494,7 +662,7 @@ async fn test_trade_availability_in_api( // Api returns eth flow orders for both eth-flow contract address and actual // owner - for address in [owner, ðflow_contract.address().into_legacy()] { + for address in [owner, ethflow_contract.address()] { test_trade_query( &TradeQuery::ByOwner(*address), client, @@ -509,7 +677,7 @@ async fn test_order_was_settled(ethflow_order: &ExtendedEthFlowOrder, onchain: & wait_for_condition(TIMEOUT, || async { onchain.mint_block().await; let buy_token = - ERC20Mintable::Instance::new(ethflow_order.0.buyToken, onchain.web3().alloy.clone()); + ERC20Mintable::Instance::new(ethflow_order.0.buyToken, onchain.web3().provider.clone()); let receiver_buy_token_balance = buy_token .balanceOf(ethflow_order.0.receiver) .call() @@ -525,7 +693,7 @@ async fn test_order_was_settled(ethflow_order: &ExtendedEthFlowOrder, onchain: & async fn test_orders_query( services: &Services<'_>, order: &ExtendedEthFlowOrder, - owner: &H160, + owner: &Address, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, ) { @@ -537,10 +705,10 @@ async fn test_orders_query( } async fn test_account_query( - queried_account: &H160, + queried_account: &Address, client: &Client, order: &ExtendedEthFlowOrder, - owner: &H160, + owner: &Address, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, ) { @@ -560,7 +728,7 @@ async fn test_account_query( enum TradeQuery { ByUid(OrderUid), - ByOwner(H160), + ByOwner(Address), } async fn test_trade_query( @@ -590,7 +758,7 @@ async fn test_trade_query( async fn test_order_parameters( response: &Order, order: &ExtendedEthFlowOrder, - owner: &H160, + owner: &Address, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, ) { @@ -610,7 +778,7 @@ async fn test_order_parameters( assert_eq!( response.metadata.onchain_order_data, Some(OnchainOrderData { - sender: owner.into_alloy(), + sender: *owner, placement_error: None, }) ); @@ -637,13 +805,10 @@ impl ExtendedEthFlowOrder { pub fn from_quote(quote_response: &OrderQuoteResponse, valid_to: u32) -> Self { let quote = "e_response.quote; ExtendedEthFlowOrder(CoWSwapEthFlow::EthFlowOrder::Data { - buyToken: quote.buy_token.into_alloy(), - receiver: quote - .receiver - .expect("eth-flow order without receiver") - .into_alloy(), - sellAmount: quote.sell_amount.into_alloy(), - buyAmount: quote.buy_amount.into_alloy(), + buyToken: quote.buy_token, + receiver: quote.receiver.expect("eth-flow order without receiver"), + sellAmount: quote.sell_amount, + buyAmount: quote.buy_amount, appData: quote.app_data.hash().0.into(), feeAmount: alloy::primitives::U256::ZERO, validTo: valid_to, // note: valid to in the quote is always unlimited @@ -670,7 +835,7 @@ impl ExtendedEthFlowOrder { .with_valid_to(u32::MAX) .with_app_data(self.0.appData.0) .with_class(OrderClass::Market) // Eth-flow orders only support market orders at this point in time - .with_eip1271(ethflow_contract.address().into_legacy(), hex!("").into()) + .with_eip1271(*ethflow_contract.address(), vec![]) .build() } @@ -690,9 +855,9 @@ impl ExtendedEthFlowOrder { &self, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, - ) -> EthFlowOrderOnchainStatus { + ) -> RefundStatus { ethflow_contract - .orders(self.hash(contracts, ethflow_contract).await.0.into()) + .orders(self.hash(contracts, ethflow_contract).await) .call() .await .expect("Couldn't fetch order status") @@ -716,10 +881,7 @@ impl ExtendedEthFlowOrder { let result = ethflow_contract .isValidSignature( - self.hash(contracts, ethflow_contract) - .await - .to_fixed_bytes() - .into(), + self.hash(contracts, ethflow_contract).await, Bytes::from(bytes), ) .call() @@ -764,7 +926,7 @@ impl ExtendedEthFlowOrder { &self, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, - ) -> H256 { + ) -> B256 { let domain_separator = DomainSeparator( contracts .gp_settlement @@ -774,13 +936,13 @@ impl ExtendedEthFlowOrder { .expect("Couldn't query domain separator") .0, ); - H256(hashed_eip712_message( + hashed_eip712_message( &domain_separator, &self .to_cow_swap_order(ethflow_contract, &contracts.weth) .data .hash_struct(), - )) + ) } pub async fn uid( @@ -799,40 +961,23 @@ impl ExtendedEthFlowOrder { ); self.to_cow_swap_order(ethflow_contract, &contracts.weth) .data - .uid(&domain_separator, ðflow_contract.address().into_legacy()) - } -} - -#[derive(Debug, PartialEq, Eq)] -pub enum EthFlowOrderOnchainStatus { - Invalidated, - Created(H160, u32), - Free, -} - -impl From for EthFlowOrderOnchainStatus { - fn from(value: CoWSwapEthFlow::CoWSwapEthFlow::ordersReturn) -> Self { - match value.owner { - owner if owner == NO_OWNER => Self::Free, - owner if owner == INVALIDATED_OWNER => Self::Invalidated, - _ => Self::Created(value.owner.into_legacy(), value.validTo), - } + .uid(&domain_separator, *ethflow_contract.address()) } } pub struct EthFlowTradeIntent { - pub sell_amount: U256, - pub buy_token: H160, - pub receiver: H160, + pub sell_amount: alloy::primitives::U256, + pub buy_token: Address, + pub receiver: Address, } impl EthFlowTradeIntent { // How a user trade intent is converted into a quote request by the frontend - pub fn to_quote_request(&self, from: H160, weth: &WETH9::Instance) -> OrderQuoteRequest { + pub fn to_quote_request(&self, from: Address, weth: &WETH9::Instance) -> OrderQuoteRequest { OrderQuoteRequest { from, // Even if the user sells ETH, we request a quote for WETH - sell_token: weth.address().into_legacy(), + sell_token: *weth.address(), buy_token: self.buy_token, receiver: Some(self.receiver), validity: Validity::For(3600), @@ -857,12 +1002,12 @@ impl EthFlowTradeIntent { async fn eth_flow_zero_buy_amount(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(2u64.eth()).await; + let [trader_a, trader_b] = onchain.make_accounts(2u64.eth()).await; // Create token with Uniswap pool for price estimation let [dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(DAI_PER_ETH * 1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools((DAI_PER_ETH * 1_000).eth(), 1_000u64.eth()) .await; let services = Services::new(&onchain).await; @@ -870,13 +1015,13 @@ async fn eth_flow_zero_buy_amount(web3: Web3) { let place_order = async |trader: TestAccount, buy_amount: u64| { let valid_to = chrono::offset::Utc::now().timestamp() as u32 - + timestamp_of_current_block_in_seconds(&web3.alloy) + + timestamp_of_current_block_in_seconds(&web3.provider) .await .unwrap() + 3600; let ethflow_order = ExtendedEthFlowOrder(CoWSwapEthFlow::EthFlowOrder::Data { buyToken: *dai.address(), - sellAmount: eth(1), + sellAmount: 1u64.eth(), buyAmount: alloy::primitives::U256::from(buy_amount), validTo: valid_to, partiallyFillable: false, @@ -889,7 +1034,7 @@ async fn eth_flow_zero_buy_amount(web3: Web3) { let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); submit_order( ðflow_order, - trader.account(), + trader.address(), onchain.contracts(), ethflow_contract, ) diff --git a/crates/e2e/tests/e2e/hooks.rs b/crates/e2e/tests/e2e/hooks.rs index d0006408c7..8b17ec3af4 100644 --- a/crates/e2e/tests/e2e/hooks.rs +++ b/crates/e2e/tests/e2e/hooks.rs @@ -1,32 +1,28 @@ use { - alloy::providers::Provider, + alloy::{ + primitives::{Address, Bytes, U256}, + providers::Provider, + }, app_data::Hook, e2e::setup::{ OnchainComponents, Services, TIMEOUT, - eth, onchain_components, run_test, safe::Safe, - to_wei, wait_for_condition, }, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderCreationAppData, OrderKind}, quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::{EcdsaSigningScheme, Signature, hashed_eip712_message}, }, - number::nonzero::U256 as NonZeroU256, + number::{nonzero::NonZeroU256, units::EthUnit}, reqwest::StatusCode, - secp256k1::SecretKey, serde_json::json, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + shared::web3::Web3, }; #[tokio::test] @@ -62,16 +58,16 @@ async fn local_node_quote_verification() { async fn gas_limit(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let cow = onchain - .deploy_cow_weth_pool(to_wei(1_000_000), to_wei(1_000), to_wei(1_000)) + .deploy_cow_weth_pool(1_000_000u64.eth(), 1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts and approve relayer - cow.fund(trader.address(), to_wei(5)).await; - cow.approve(onchain.contracts().allowance.into_alloy(), eth(5)) - .from(trader.address().into_alloy()) + cow.fund(trader.address(), 5u64.eth()).await; + cow.approve(onchain.contracts().allowance, 5u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -80,10 +76,10 @@ async fn gas_limit(web3: Web3) { services.start_protocol(solver).await; let order = OrderCreation { - sell_token: cow.address().into_legacy(), - sell_amount: to_wei(4), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(3), + sell_token: *cow.address(), + sell_amount: 4u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, app_data: OrderCreationAppData::Full { @@ -91,7 +87,7 @@ async fn gas_limit(web3: Web3) { "metadata": { "hooks": { "pre": [Hook { - target: trader.address().into_alloy(), + target: trader.address(), call_data: Default::default(), gas_limit: 8_000_000, }], @@ -106,7 +102,7 @@ async fn gas_limit(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let error = services.create_order(&order).await.unwrap_err(); assert_eq!(error.0, StatusCode::BAD_REQUEST); @@ -116,25 +112,25 @@ async fn gas_limit(web3: Web3) { async fn allowance(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let cow = onchain - .deploy_cow_weth_pool(to_wei(1_000_000), to_wei(1_000), to_wei(1_000)) + .deploy_cow_weth_pool(1_000_000u64.eth(), 1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts - cow.fund(trader.address(), to_wei(5)).await; + cow.fund(trader.address(), 5u64.eth()).await; // Sign a permit pre-interaction for trading. let permit = cow - .permit(&trader, onchain.contracts().allowance, to_wei(5)) + .permit(&trader, onchain.contracts().allowance, 5u64.eth()) .await; // Setup a malicious interaction for setting approvals to steal funds from // the settlement contract. let steal_cow = { let tx = cow - .approve(trader.address().into_alloy(), alloy::primitives::U256::MAX) - .from(solver.address().into_alloy()); + .approve(trader.address(), U256::MAX) + .from(solver.address()); Hook { target: *cow.address(), call_data: tx.calldata().to_vec(), @@ -142,10 +138,10 @@ async fn allowance(web3: Web3) { } }; let steal_weth = { - let approve = onchain.contracts().weth.approve( - trader.address().into_alloy(), - ::alloy::primitives::U256::MAX, - ); + let approve = onchain + .contracts() + .weth + .approve(trader.address(), U256::MAX); Hook { target: *onchain.contracts().weth.address(), call_data: approve.calldata().to_vec(), @@ -157,10 +153,10 @@ async fn allowance(web3: Web3) { services.start_protocol(solver).await; let order = OrderCreation { - sell_token: cow.address().into_legacy(), - sell_amount: to_wei(5), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(3), + sell_token: *cow.address(), + sell_amount: 5u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, app_data: OrderCreationAppData::Full { @@ -179,21 +175,17 @@ async fn allowance(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap(); onchain.mint_block().await; - let balance = cow - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - assert_eq!(balance, eth(5)); + let balance = cow.balanceOf(trader.address()).call().await.unwrap(); + assert_eq!(balance, 5u64.eth()); tracing::info!("Waiting for trade."); let trade_happened = || async { - cow.balanceOf(trader.address().into_alloy()) + cow.balanceOf(trader.address()) .call() .await .unwrap() @@ -205,11 +197,11 @@ async fn allowance(web3: Web3) { let balance = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); - assert!(balance >= order.buy_amount.into_alloy()); + assert!(balance >= order.buy_amount); tracing::info!("Waiting for auction to be cleared."); let auction_is_empty = || async { services.get_auction().await.auction.orders.is_empty() }; @@ -219,58 +211,52 @@ async fn allowance(web3: Web3) { let allowance = cow .allowance( *onchain.contracts().gp_settlement.address(), - trader.address().into_alloy(), + trader.address(), ) .call() .await .unwrap(); - assert_eq!(allowance, alloy::primitives::U256::ZERO); + assert_eq!(allowance, U256::ZERO); let allowance = onchain .contracts() .weth .allowance( *onchain.contracts().gp_settlement.address(), - trader.address().into_alloy(), + trader.address(), ) .call() .await .unwrap(); - assert_eq!(allowance, ::alloy::primitives::U256::ZERO); + assert_eq!(allowance, U256::ZERO); // Note that the allowances were set with the `HooksTrampoline` contract! // This is OK since the `HooksTrampoline` contract is not used for holding // any funds. let allowance = cow - .allowance( - *onchain.contracts().hooks.address(), - trader.address().into_alloy(), - ) + .allowance(*onchain.contracts().hooks.address(), trader.address()) .call() .await .unwrap(); - assert_eq!(allowance, alloy::primitives::U256::MAX); + assert_eq!(allowance, U256::MAX); let allowance = onchain .contracts() .weth - .allowance( - *onchain.contracts().hooks.address(), - trader.address().into_alloy(), - ) + .allowance(*onchain.contracts().hooks.address(), trader.address()) .call() .await .unwrap(); - assert_eq!(allowance, ::alloy::primitives::U256::MAX); + assert_eq!(allowance, U256::MAX); } async fn signature(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let chain_id = alloy::primitives::U256::from(web3.alloy.get_chain_id().await.unwrap()); + let chain_id = U256::from(web3.provider.get_chain_id().await.unwrap()); - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; - let safe_infra = onchain_components::safe::Infrastructure::new(web3.alloy.clone()).await; + let safe_infra = onchain_components::safe::Infrastructure::new(web3.provider.clone()).await; // Prepare the Safe creation transaction, but don't execute it! This will // be executed as a pre-hook. @@ -279,14 +265,14 @@ async fn signature(web3: Web3) { safe_infra .singleton .setup( - vec![trader.address().into_alloy()], // owners - alloy::primitives::U256::ONE, // threshold - alloy::primitives::Address::default(), // delegate call - alloy::primitives::Bytes::default(), // delegate call bytes + vec![trader.address()], // owners + U256::ONE, // threshold + Address::default(), // delegate call + Bytes::default(), // delegate call bytes *safe_infra.fallback.address(), - alloy::primitives::Address::default(), // relayer payment token - alloy::primitives::U256::ZERO, // relayer payment amount - alloy::primitives::Address::default(), // relayer address + Address::default(), // relayer payment token + U256::ZERO, // relayer payment amount + Address::default(), // relayer address ) .calldata() .clone(), @@ -301,26 +287,22 @@ async fn signature(web3: Web3) { let safe_address = safe_creation_builder.clone().call().await.unwrap(); let safe = Safe::deployed( chain_id, - contracts::alloy::GnosisSafe::Instance::new(safe_address, web3.alloy.clone()), + contracts::GnosisSafe::Instance::new(safe_address, web3.provider.clone()), trader.clone(), ); let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) + .deploy_tokens_with_weth_uni_v2_pools(100_000u64.eth(), 100_000u64.eth()) .await; - token.mint(safe.address().into_legacy(), to_wei(5)).await; + token.mint(safe.address(), 5u64.eth()).await; // Sign an approval transaction for trading. This will be at nonce 0 because // it is the first transaction evah! let approval_call_data = token - .approve(onchain.contracts().allowance.into_alloy(), eth(5)) + .approve(onchain.contracts().allowance, 5u64.eth()) .calldata() .to_vec(); - let approval_builder = safe.sign_transaction( - *token.address(), - approval_call_data, - alloy::primitives::U256::ZERO, - ); + let approval_builder = safe.sign_transaction(*token.address(), approval_call_data, U256::ZERO); let call_data = approval_builder.calldata().to_vec(); let target = approval_builder .into_transaction_request() @@ -342,17 +324,17 @@ async fn signature(web3: Web3) { // Place Orders let mut order = OrderCreation { - from: Some(safe.address().into_legacy()), + from: Some(safe.address()), // Quotes for trades where the pre-interactions deploy a contract // at the `from` address currently can't be verified. // To not throw an error because we can't get a verifiable quote // we make the order partially fillable and sell slightly more than // `from` currently has. - sell_amount: to_wei(6), + sell_amount: 6u64.eth(), partially_fillable: true, - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(3), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, app_data: OrderCreationAppData::Full { @@ -375,20 +357,11 @@ async fn signature(web3: Web3) { services.create_order(&order).await.unwrap(); onchain.mint_block().await; - let balance = token - .balanceOf(safe.address()) - .call() - .await - .unwrap() - .into_legacy(); - assert_eq!(balance, to_wei(5)); + let balance = token.balanceOf(safe.address()).call().await.unwrap(); + assert_eq!(balance, 5u64.eth()); // Check that the Safe really hasn't been deployed yet. - let code = web3 - .eth() - .code(safe.address().into_legacy(), None) - .await - .unwrap(); + let code = web3.provider.get_code_at(safe.address()).await.unwrap(); assert_eq!(code.0.len(), 0); tracing::info!("Waiting for trade."); @@ -411,14 +384,10 @@ async fn signature(web3: Web3) { .call() .await .unwrap(); - assert!(balance >= order.buy_amount.into_alloy()); + assert!(balance >= order.buy_amount); // Check Safe was deployed - let code = web3 - .eth() - .code(safe.address().into_legacy(), None) - .await - .unwrap(); + let code = web3.provider.get_code_at(safe.address()).await.unwrap(); assert_ne!(code.0.len(), 0); tracing::info!("Waiting for auction to be cleared."); @@ -429,58 +398,48 @@ async fn signature(web3: Web3) { async fn partial_fills(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(3)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(3u64.eth()).await; - let counter = contracts::alloy::test::Counter::Instance::deploy(web3.alloy.clone()) + let counter = contracts::test::Counter::Instance::deploy(web3.provider.clone()) .await .unwrap(); let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; let sell_token = onchain.contracts().weth.clone(); sell_token - .approve(onchain.contracts().allowance.into_alloy(), eth(2)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 2u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); sell_token .deposit() - .from(trader.address().into_alloy()) - .value(eth(1)) + .from(trader.address()) + .value(1u64.eth()) .send_and_watch() .await .unwrap(); - let balance_before_first_trade = sell_token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before_first_trade = sell_token.balanceOf(trader.address()).call().await.unwrap(); tracing::info!("Starting services."); let services = Services::new(&onchain).await; services.start_protocol(solver).await; - let pre_inc = counter.setCounterToBalance( - "pre".to_string(), - *sell_token.address(), - trader.address().into_alloy(), - ); + let pre_inc = + counter.setCounterToBalance("pre".to_string(), *sell_token.address(), trader.address()); let pre_hook = Hook { target: *counter.address(), call_data: pre_inc.calldata().to_vec(), gas_limit: pre_inc.estimate_gas().await.unwrap(), }; - let post_inc = counter.setCounterToBalance( - "post".to_string(), - *sell_token.address(), - trader.address().into_alloy(), - ); + let post_inc = + counter.setCounterToBalance("post".to_string(), *sell_token.address(), trader.address()); let post_hook = Hook { target: *counter.address(), call_data: post_inc.calldata().to_vec(), @@ -489,10 +448,10 @@ async fn partial_fills(web3: Web3) { tracing::info!("Placing order"); let order = OrderCreation { - sell_token: sell_token.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *sell_token.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: true, @@ -512,7 +471,7 @@ async fn partial_fills(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap(); onchain.mint_block().await; @@ -520,7 +479,7 @@ async fn partial_fills(web3: Web3) { tracing::info!("Waiting for first trade."); let trade_happened = || async { sell_token - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap() @@ -531,11 +490,8 @@ async fn partial_fills(web3: Web3) { counter.counters("pre".to_string()).call().await.unwrap(), balance_before_first_trade ); - let post_balance_after_first_trade = sell_token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let post_balance_after_first_trade = + sell_token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!( counter.counters("post".to_string()).call().await.unwrap(), post_balance_after_first_trade @@ -544,8 +500,8 @@ async fn partial_fills(web3: Web3) { tracing::info!("Fund remaining sell balance."); sell_token .deposit() - .from(trader.address().into_alloy()) - .value(eth(1)) + .from(trader.address()) + .value(1u64.eth()) .send_and_watch() .await .unwrap(); @@ -558,11 +514,7 @@ async fn partial_fills(web3: Web3) { ); assert_eq!( counter.counters("post".to_string()).call().await.unwrap(), - sell_token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap() + sell_token.balanceOf(trader.address()).call().await.unwrap() ); } @@ -571,12 +523,12 @@ async fn partial_fills(web3: Web3) { async fn quote_verification(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let chain_id = alloy::primitives::U256::from(web3.alloy.get_chain_id().await.unwrap()); + let chain_id = U256::from(web3.provider.get_chain_id().await.unwrap()); - let [trader] = onchain.make_accounts(to_wei(1)).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; - let safe_infra = onchain_components::safe::Infrastructure::new(web3.alloy.clone()).await; + let safe_infra = onchain_components::safe::Infrastructure::new(web3.provider.clone()).await; // Prepare the Safe creation transaction, but don't execute it! This will // be executed as a pre-hook. @@ -585,14 +537,14 @@ async fn quote_verification(web3: Web3) { safe_infra .singleton .setup( - vec![trader.address().into_alloy()], // owners - alloy::primitives::U256::ONE, // threshold - alloy::primitives::Address::default(), // delegate call - alloy::primitives::Bytes::default(), // delegate call bytes + vec![trader.address()], // owners + U256::ONE, // threshold + Address::default(), // delegate call + Bytes::default(), // delegate call bytes *safe_infra.fallback.address(), - alloy::primitives::Address::default(), // relayer payment token - alloy::primitives::U256::ZERO, // relayer payment amount - alloy::primitives::Address::default(), // relayer address + Address::default(), // relayer payment token + U256::ZERO, // relayer payment amount + Address::default(), // relayer address ) .calldata() .clone(), @@ -602,18 +554,18 @@ async fn quote_verification(web3: Web3) { let safe = Safe::deployed( chain_id, - contracts::alloy::GnosisSafe::Instance::new(safe_address, web3.alloy.clone()), + contracts::GnosisSafe::Instance::new(safe_address, web3.provider.clone()), trader.clone(), ); let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) + .deploy_tokens_with_weth_uni_v2_pools(100_000u64.eth(), 100_000u64.eth()) .await; - token.mint(safe.address().into_legacy(), to_wei(5)).await; + token.mint(safe.address(), 5u64.eth()).await; token - .approve(onchain.contracts().allowance.into_alloy(), eth(5)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 5u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -623,10 +575,10 @@ async fn quote_verification(web3: Web3) { let transfer_builder = safe.sign_transaction( *token.address(), token - .transfer(trader.address().into_alloy(), eth(5)) + .transfer(trader.address(), 5u64.eth()) .calldata() .to_vec(), - alloy::primitives::U256::ZERO, + U256::ZERO, ); let call_data = transfer_builder.calldata().to_vec(); let target = transfer_builder @@ -648,11 +600,11 @@ async fn quote_verification(web3: Web3) { let quote = services .submit_quote(&OrderQuoteRequest { from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: NonZeroU256::try_from(to_wei(5)).unwrap(), + value: NonZeroU256::try_from(5u64.eth()).unwrap(), }, }, app_data: OrderCreationAppData::Full { diff --git a/crates/e2e/tests/e2e/jit_orders.rs b/crates/e2e/tests/e2e/jit_orders.rs index 52555d75d0..f04096a19b 100644 --- a/crates/e2e/tests/e2e/jit_orders.rs +++ b/crates/e2e/tests/e2e/jit_orders.rs @@ -1,19 +1,20 @@ use { ::alloy::primitives::U256, - e2e::setup::{colocation::SolverEngine, eth, mock::Mock, solution::JitOrder, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + configs::{ + autopilot::Configuration, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, }, + e2e::setup::{colocation::SolverEngine, mock::Mock, solution::JitOrder, *}, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderClass, OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, + number::units::EthUnit, + shared::web3::Web3, solvers_dto::solution::{Asset, Solution}, std::collections::HashMap, - web3::signing::SecretKeyRef, }; #[tokio::test] @@ -25,20 +26,20 @@ async fn local_node_single_limit_order() { async fn single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(100)).await; - let [trader] = onchain.make_accounts(to_wei(100)).await; + let [solver] = onchain.make_solvers(100u64.eth()).await; + let [trader] = onchain.make_accounts(100u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(300_000u64.eth(), 1_000u64.eth()) .await; - token.mint(solver.address(), to_wei(100)).await; + token.mint(solver.address(), 100u64.eth()).await; onchain .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(20)) + .from(trader.address()) + .value(20u64.eth()) .send_and_watch() .await .unwrap(); @@ -46,22 +47,22 @@ async fn single_limit_order_test(web3: Web3) { onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), U256::MAX) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, U256::MAX) + .from(trader.address()) .send_and_watch() .await .unwrap(); token - .approve(onchain.contracts().allowance.into_alloy(), U256::MAX) - .from(solver.address().into_alloy()) + .approve(onchain.contracts().allowance, U256::MAX) + .from(solver.address()) .send_and_watch() .await .unwrap(); let services = Services::new(&onchain).await; - let mock_solver = Mock::default(); + let mock_solver = Mock::new().await; // Start system colocation::start_driver( @@ -80,8 +81,10 @@ async fn single_limit_order_test(web3: Web3) { name: "mock_solver".into(), account: solver.clone(), endpoint: mock_solver.url.clone(), - base_tokens: vec![token.address().into_legacy()], + base_tokens: vec![*token.address()], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, ], colocation::LiquidityProvider::UniswapV2, @@ -93,28 +96,31 @@ async fn single_limit_order_test(web3: Web3) { services .start_autopilot( None, - vec![ - format!( - "--drivers=mock_solver|http://localhost:11088/mock_solver|{}", - const_hex::encode(solver.address()) - ), - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver" - .to_string(), - ], + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test("mock_solver", solver.address()) + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Place order let order = OrderCreation { - sell_token: onchain.contracts().weth.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *onchain.contracts().weth.address(), + sell_amount: 10u64.eth(), + buy_token: *token.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -122,19 +128,11 @@ async fn single_limit_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); - let trader_balance_before = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let solver_balance_before = token - .balanceOf(solver.address().into_alloy()) - .call() - .await - .unwrap(); + let trader_balance_before = token.balanceOf(trader.address()).call().await.unwrap(); + let solver_balance_before = token.balanceOf(solver.address()).call().await.unwrap(); let order_id = services.create_order(&order).await.unwrap(); let limit_order = services.get_order(&order_id).await.unwrap(); onchain.mint_block().await; @@ -143,12 +141,12 @@ async fn single_limit_order_test(web3: Web3) { let (jit_order, jit_order_uid) = JitOrder { owner: trader.address(), sell: Asset { - amount: to_wei(10), - token: token.address().into_legacy(), + amount: 10u64.eth(), + token: *token.address(), }, buy: Asset { - amount: to_wei(1), - token: onchain.contracts().weth.address().into_legacy(), + amount: 1u64.eth(), + token: *onchain.contracts().weth.address(), }, kind: OrderKind::Sell, partially_fillable: false, @@ -159,26 +157,26 @@ async fn single_limit_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(solver.private_key()).unwrap()), + &solver.signer, ); mock_solver.configure_solution(Some(Solution { id: 0, prices: HashMap::from([ - (token.address().into_legacy(), to_wei(1)), - (onchain.contracts().weth.address().into_legacy(), to_wei(1)), + (*token.address(), 1u64.eth()), + (*onchain.contracts().weth.address(), 1u64.eth()), ]), trades: vec![ solvers_dto::solution::Trade::Jit(solvers_dto::solution::JitTrade { order: jit_order, // Making it 9 + 1 so we cover the edge case of fill-or-kill solution mismatches // when observing settlements https://github.com/cowprotocol/services/pull/3440 - executed_amount: to_wei(9), - fee: Some(to_wei(1)), + executed_amount: 9u64.eth(), + fee: Some(1u64.eth()), }), solvers_dto::solution::Trade::Fulfillment(solvers_dto::solution::Fulfillment { executed_amount: order.sell_amount, - fee: Some(0.into()), + fee: Some(::alloy::primitives::U256::ZERO), order: solvers_dto::solution::OrderUid(order_id.0), }), ], @@ -188,29 +186,22 @@ async fn single_limit_order_test(web3: Web3) { gas: None, flashloans: None, wrappers: vec![], + gas_fee_override: None, })); // Drive solution tracing::info!("Waiting for trade."); onchain.mint_block().await; wait_for_condition(TIMEOUT, || async { - let trader_balance_after = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let solver_balance_after = token - .balanceOf(solver.address().into_alloy()) - .call() - .await - .unwrap(); + let trader_balance_after = token.balanceOf(trader.address()).call().await.unwrap(); + let solver_balance_after = token.balanceOf(solver.address()).call().await.unwrap(); let trader_balance_increased = - trader_balance_after.saturating_sub(trader_balance_before) >= eth(5); + trader_balance_after.saturating_sub(trader_balance_before) >= 5u64.eth(); // Since the fee is 0 in the custom solution, the balance difference has to be // exactly 10 wei let solver_balance_decreased = - solver_balance_before.saturating_sub(solver_balance_after) == eth(10); + solver_balance_before.saturating_sub(solver_balance_after) == 10u64.eth(); trader_balance_increased && solver_balance_decreased }) .await @@ -230,10 +221,7 @@ async fn single_limit_order_test(web3: Web3) { .tx_hash?; // jit order can be found on /api/v1/transactions/{tx_hash}/orders - let orders_by_tx = services - .get_orders_for_tx(&tx_hash.into_legacy()) - .await - .ok()?; + let orders_by_tx = services.get_orders_for_tx(&tx_hash).await.ok()?; // jit order can be found on /api/v1/account/{owner}/orders let orders_by_owner = services diff --git a/crates/e2e/tests/e2e/limit_orders.rs b/crates/e2e/tests/e2e/limit_orders.rs index 05156a58c6..3c9da8d972 100644 --- a/crates/e2e/tests/e2e/limit_orders.rs +++ b/crates/e2e/tests/e2e/limit_orders.rs @@ -5,25 +5,42 @@ use { providers::ext::{AnvilApi, ImpersonateConfig}, }, bigdecimal::BigDecimal, - contracts::alloy::ERC20, + configs::{ + autopilot::{ + Configuration, + fee_policy::{FeePoliciesConfig, FeePolicy, FeePolicyKind}, + run_loop::RunLoopConfig, + solver::{Account, Solver}, + }, + order_quoting::{ExternalSolver, OrderQuoting}, + orderbook::order_validation::OrderValidationConfig, + test_util::TestDefault, + }, + contracts::ERC20, database::byte_array::ByteArray, - driver::domain::eth::NonZeroU256, - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + e2e::setup::{ + proxy::{OnRequest, ReverseProxy}, + *, }, - fee::{FeePolicyOrderClass, ProtocolFee, ProtocolFeesConfig}, + eth_domain_types::NonZeroU256, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderClass, OrderCreation, OrderKind}, quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::EcdsaSigningScheme, }, - number::conversions::big_decimal_to_big_uint, - secp256k1::SecretKey, - shared::ethrpc::Web3, - std::{collections::HashMap, ops::DerefMut}, - web3::signing::SecretKeyRef, + number::{conversions::big_decimal_to_big_uint, units::EthUnit}, + shared::web3::Web3, + std::{ + collections::HashMap, + ops::DerefMut, + str::FromStr, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + }, + }, + url::Url, }; #[tokio::test] @@ -62,10 +79,31 @@ async fn local_node_no_liquidity_limit_order() { run_test(no_liquidity_limit_order).await; } +/// Test that sell orders with haircut configured execute on-chain with +/// haircutted amounts. The haircut reduces both the reported buy_amount and +/// the on-chain buy_amount (they should match). User receives less than +/// without haircut, with the difference going to the settlement contract. +#[tokio::test] +#[ignore] +async fn local_node_limit_order_with_haircut() { + run_test(sell_order_with_haircut_test).await; +} + +/// Test that buy orders with haircut configured execute on-chain with +/// haircutted amounts. The haircut increases both the reported sell_amount and +/// the on-chain sell_amount (they should match). Verifies that: +/// - executedBuy == signedBuyAmount (user gets exactly what they signed for) +/// - executedSell includes haircut (but still <= sellLimit) +#[tokio::test] +#[ignore] +async fn local_node_buy_order_with_haircut() { + run_test(buy_order_with_haircut_test).await; +} + /// The block number from which we will fetch state for the forked tests. -const FORK_BLOCK_MAINNET: u64 = 23112197; -/// USDC whale address as per [FORK_BLOCK_MAINNET]. -const USDC_WHALE_MAINNET: Address = address!("28c6c06298d514db089934071355e5743bf21d60"); +const FORK_BLOCK_MAINNET: u64 = 24843565; +/// USDT whale address as per [FORK_BLOCK_MAINNET]. +const USDT_WHALE_MAINNET: Address = address!("F977814e90dA44bFA03b6295A0616a897441aceC"); #[tokio::test] #[ignore] @@ -79,7 +117,7 @@ async fn forked_node_mainnet_single_limit_order() { .await; } -const FORK_BLOCK_GNOSIS: u64 = 41502478; +const FORK_BLOCK_GNOSIS: u64 = 45588623; /// USDC whale address as per [FORK_BLOCK_GNOSIS]. const USDC_WHALE_GNOSIS: Address = address!("d4A39d219ADB43aB00739DC5D876D98Fdf0121Bf"); @@ -97,37 +135,43 @@ async fn forked_node_gnosis_single_limit_order() { async fn single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), 10u64.eth()).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -137,14 +181,14 @@ async fn single_limit_order_test(web3: Web3) { .addLiquidity( *token_a.address(), *token_b.address(), - eth(1000), - eth(1000), + 1000u64.eth(), + 1000u64.eth(), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -152,8 +196,8 @@ async fn single_limit_order_test(web3: Web3) { // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -163,10 +207,10 @@ async fn single_limit_order_test(web3: Web3) { services.start_protocol(solver).await; let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *token_b.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -174,13 +218,9 @@ async fn single_limit_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); - let balance_before = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_b.balanceOf(trader_a.address()).call().await.unwrap(); let order_id = services.create_order(&order).await.unwrap(); // we hide the quote's execution plan while the order is still fillable @@ -197,12 +237,8 @@ async fn single_limit_order_test(web3: Web3) { // Drive solution tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - balance_after.checked_sub(balance_before).unwrap() >= eth(5) + let balance_after = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + balance_after.checked_sub(balance_before).unwrap() >= 5u64.eth() }) .await .unwrap(); @@ -220,38 +256,44 @@ async fn single_limit_order_test(web3: Web3) { async fn two_limit_orders_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a, trader_b] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts and prepare funding Uniswap pool - token_a.mint(trader_a.address(), to_wei(10)).await; - token_b.mint(trader_b.address(), to_wei(10)).await; - token_a.mint(solver.address(), to_wei(1_000)).await; - token_b.mint(solver.address(), to_wei(1_000)).await; + token_a.mint(trader_a.address(), 10u64.eth()).await; + token_b.mint(trader_b.address(), 10u64.eth()).await; + token_a.mint(solver.address(), 1_000u64.eth()).await; + token_b.mint(solver.address(), 1_000u64.eth()).await; // Create and fund Uniswap pool onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -261,14 +303,14 @@ async fn two_limit_orders_test(web3: Web3) { .addLiquidity( *token_a.address(), *token_b.address(), - eth(1000), - eth(1000), + 1000u64.eth(), + 1000u64.eth(), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -276,28 +318,67 @@ async fn two_limit_orders_test(web3: Web3) { // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_b - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_b.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); // Place Orders let services = Services::new(&onchain).await; - services.start_protocol(solver).await; + + // Start a reverse proxy between autopilot and the driver to inspect + // requests and assert that /solve requests are brotli-compressed. + let saw_compressed_solve = Arc::new(AtomicBool::new(false)); + let flag = saw_compressed_solve.clone(); + let on_request: OnRequest = Arc::new(move |parts, _body| { + let path = parts.uri.path(); + let has_br = parts + .headers + .get("content-encoding") + .and_then(|v: &axum::http::HeaderValue| v.to_str().ok()) + .is_some_and(|v| v == "br"); + if path.contains("/solve") && has_br { + flag.store(true, Ordering::Release); + } + }); + let proxy_addr: std::net::SocketAddr = "0.0.0.0:11089".parse().unwrap(); + let backend: Url = "http://0.0.0.0:11088".parse().unwrap(); + let _proxy = ReverseProxy::start_with_callback(proxy_addr, &[backend], on_request); + + let config = Configuration::test_no_drivers(); + let config = Configuration { + drivers: vec![Solver::new( + "test_solver".to_string(), + "http://localhost:11089/test_solver".parse().unwrap(), + Account::Address(solver.address()), + )], + run_loop: RunLoopConfig { + compress_solve_request: true, + ..config.run_loop + }, + ..config + }; + services + .start_protocol_with_args( + config, + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; let order_a = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *token_b.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -305,19 +386,11 @@ async fn two_limit_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); - let balance_before_a = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - let balance_before_b = token_a - .balanceOf(trader_b.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before_a = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + let balance_before_b = token_a.balanceOf(trader_b.address()).call().await.unwrap(); let order_id = services.create_order(&order_a).await.unwrap(); onchain.mint_block().await; @@ -326,10 +399,10 @@ async fn two_limit_orders_test(web3: Web3) { assert!(limit_order.metadata.class.is_limit()); let order_b = OrderCreation { - sell_token: token_b.address().into_legacy(), - sell_amount: to_wei(5), - buy_token: token_a.address().into_legacy(), - buy_amount: to_wei(2), + sell_token: *token_b.address(), + sell_amount: 5u64.eth(), + buy_token: *token_a.address(), + buy_amount: 2u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -337,7 +410,7 @@ async fn two_limit_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::EthSign, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()), + &trader_b.signer, ); let order_id = services.create_order(&order_b).await.unwrap(); @@ -347,62 +420,59 @@ async fn two_limit_orders_test(web3: Web3) { // Drive solution tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after_a = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - let balance_after_b = token_a - .balanceOf(trader_b.address().into_alloy()) - .call() - .await - .unwrap(); - let order_a_settled = balance_after_a.saturating_sub(balance_before_a) >= eth(5); - let order_b_settled = balance_after_b.saturating_sub(balance_before_b) >= eth(2); + let balance_after_a = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + let balance_after_b = token_a.balanceOf(trader_b.address()).call().await.unwrap(); + let order_a_settled = balance_after_a.saturating_sub(balance_before_a) >= 5u64.eth(); + let order_b_settled = balance_after_b.saturating_sub(balance_before_b) >= 2u64.eth(); order_a_settled && order_b_settled }) .await .unwrap(); + + assert!( + saw_compressed_solve.load(Ordering::Acquire), + "expected /solve requests to be brotli-compressed" + ); } async fn two_limit_orders_multiple_winners_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver_a, solver_b] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver_a, solver_b] = onchain.make_solvers(1u64.eth()).await; + let [trader_a, trader_b] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b, token_c, token_d] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund traders - token_a.mint(trader_a.address(), to_wei(10)).await; - token_b.mint(trader_b.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), 10u64.eth()).await; + token_b.mint(trader_b.address(), 10u64.eth()).await; // Create more liquid routes between token_a (token_b) and weth via base_a // (base_b). base_a has more liquidity than base_b, leading to the solver that // knows about base_a to offer different solution. let [base_a, base_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(10_000), to_wei(10_000)) + .deploy_tokens_with_weth_uni_v2_pools(100_000u64.eth(), 100_000u64.eth()) .await; onchain - .seed_uni_v2_pool((&token_a, to_wei(100_000)), (&base_a, to_wei(100_000))) + .seed_uni_v2_pool((&token_a, 100_000u64.eth()), (&base_a, 100_000u64.eth())) .await; onchain - .seed_uni_v2_pool((&token_b, to_wei(10_000)), (&base_b, to_wei(10_000))) + .seed_uni_v2_pool((&token_b, 10_000u64.eth()), (&base_b, 10_000u64.eth())) .await; // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_b - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_b.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -416,7 +486,7 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { "test_solver".into(), solver_a.clone(), *onchain.contracts().weth.address(), - vec![base_a.address().into_legacy()], + vec![*base_a.address()], 2, false, ) @@ -425,7 +495,7 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { "solver2".into(), solver_b.clone(), *onchain.contracts().weth.address(), - vec![base_b.address().into_legacy()], + vec![*base_b.address()], 2, false, ) @@ -437,17 +507,32 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { let services = Services::new(&onchain).await; services - .start_api(vec![ - "--price-estimation-drivers=solver1|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "solver1", + "http://localhost:11088/test_solver", + )]), + native_price_estimation: configs::orderbook::native_price::NativePriceConfig { + estimators: configs::native_price_estimators::NativePriceEstimators::new(vec![ + vec![ + configs::native_price_estimators::NativePriceEstimator::driver( + "test_quoter".to_string(), + "http://localhost:11088/test_solver".parse().unwrap(), + ), + ], + ]), + ..configs::orderbook::native_price::NativePriceConfig::test_default() + }, + ..configs::orderbook::Configuration::test_default() + }) .await; // Place Orders let order_a = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_c.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *token_c.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -455,15 +540,15 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); let uid_a = services.create_order(&order_a).await.unwrap(); let order_b = OrderCreation { - sell_token: token_b.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_d.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_b.address(), + sell_amount: 10u64.eth(), + buy_token: *token_d.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -471,20 +556,37 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()), + &trader_b.signer, ); let uid_b = services.create_order(&order_b).await.unwrap(); // Start autopilot only once all the orders are created. - services.start_autopilot( - None, - vec![ - format!("--drivers=solver1|http://localhost:11088/test_solver|{}|10000000000000000,solver2|http://localhost:11088/solver2|{}", - const_hex::encode(solver_a.address()), const_hex::encode(solver_b.address())), - "--price-estimation-drivers=solver1|http://localhost:11088/test_solver".to_string(), - "--max-winners-per-auction=2".to_string(), - ], - ).await; + + let config = Configuration::test_no_drivers(); + services + .start_autopilot( + None, + Configuration { + drivers: vec![ + Solver::new( + "solver1".to_string(), + Url::from_str("http://localhost:11088/test_solver").unwrap(), + Account::Address(solver_a.address()), + ), + Solver::test("solver2", solver_b.address()), + ], + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "solver1", + "http://localhost:11088/test_solver", + )]), + run_loop: RunLoopConfig { + max_winners_per_auction: std::num::NonZeroUsize::new(2).unwrap(), + ..config.run_loop + }, + ..config + }, + ) + .await; // Wait for trade let indexed_trades = || async { @@ -496,10 +598,10 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { matches!( ( services - .get_solver_competition(trade_a.tx_hash.unwrap().into_legacy()) + .get_solver_competition(trade_a.tx_hash.unwrap()) .await, services - .get_solver_competition(trade_b.tx_hash.unwrap().into_legacy()) + .get_solver_competition(trade_b.tx_hash.unwrap()) .await ), (Ok(_), Ok(_)) @@ -512,23 +614,23 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { let trades = services.get_trades(&uid_a).await.unwrap(); let competition = services - .get_solver_competition(trades[0].tx_hash.unwrap().into_legacy()) + .get_solver_competition(trades[0].tx_hash.unwrap()) .await .unwrap(); // Verify that both transactions were properly indexed assert_eq!(competition.transaction_hashes.len(), 2); // Verify that settlement::Observed properly handled events let order_a_settled = services.get_order(&uid_a).await.unwrap(); - assert!(order_a_settled.metadata.executed_fee > 0.into()); + assert!(order_a_settled.metadata.executed_fee > U256::ZERO); let order_b_settled = services.get_order(&uid_b).await.unwrap(); - assert!(order_b_settled.metadata.executed_fee > 0.into()); + assert!(order_b_settled.metadata.executed_fee > U256::ZERO); let mut ex = services.db().acquire().await.unwrap(); let solver_a_winning_solutions = database::solver_competition_v2::fetch_solver_winning_solutions( &mut ex, competition.auction_id, - ByteArray(solver_a.address().0), + ByteArray(solver_a.address().0.0), ) .await .unwrap(); @@ -536,7 +638,7 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { database::solver_competition_v2::fetch_solver_winning_solutions( &mut ex, competition.auction_id, - ByteArray(solver_b.address().0), + ByteArray(solver_b.address().0.0), ) .await .unwrap(); @@ -573,10 +675,10 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { .unwrap(); assert_eq!(settlements.len(), 2); assert!(settlements.iter().any(|settlement| settlement.solver - == ByteArray(solver_a.address().0) + == ByteArray(solver_a.address().0.0) && settlement.solution_uid == solver_a_winning_solutions[0].uid)); assert!(settlements.iter().any(|settlement| settlement.solver - == ByteArray(solver_b.address().0) + == ByteArray(solver_b.address().0.0) && settlement.solution_uid == solver_b_winning_solutions[0].uid)); // Ensure all the reference scores are indexed @@ -591,11 +693,11 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { // fetch the reference scores of both winners let solver_a_reference_score = reference_scores - .get(&ByteArray(solver_a.address().0)) + .get(&ByteArray(solver_a.address().0.0)) .unwrap() .clone(); let solver_b_reference_score = reference_scores - .get(&ByteArray(solver_b.address().0)) + .get(&ByteArray(solver_b.address().0.0)) .unwrap() .clone(); @@ -610,18 +712,19 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { async fn too_many_limit_orders_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let solver_address = solver.address(); + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_a] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token_a.mint(trader.address(), to_wei(1)).await; + token_a.mint(trader.address(), 1u64.eth()).await; // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(101)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 101u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -644,18 +747,38 @@ async fn too_many_limit_orders_test(web3: Web3) { colocation::LiquidityProvider::UniswapV2, false, ); + + services + .start_autopilot( + None, + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test("test_solver", solver_address) + }, + ) + .await; services - .start_api(vec![ - "--max-limit-orders-per-user=1".into(), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + order_validation: OrderValidationConfig { + max_limit_orders_per_user: 1, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }) .await; let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(1), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 1u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -663,17 +786,17 @@ async fn too_many_limit_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap(); // Attempt to place another order, but the orderbook is configured to allow only // one limit order per user. let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(1), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(2), + sell_token: *token_a.address(), + sell_amount: 1u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 2u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -681,7 +804,7 @@ async fn too_many_limit_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let (status, body) = services.create_order(&order).await.unwrap_err(); @@ -692,18 +815,19 @@ async fn too_many_limit_orders_test(web3: Web3) { async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let solver_address = solver.address(); + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token.mint(trader.address(), to_wei(100)).await; + token.mint(trader.address(), 100u64.eth()).await; // Approve GPv2 for trading token - .approve(onchain.contracts().allowance.into_alloy(), eth(101)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 101u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -726,20 +850,40 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { colocation::LiquidityProvider::UniswapV2, false, ); + + services + .start_autopilot( + None, + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test("test_solver", solver_address) + }, + ) + .await; services - .start_api(vec![ - "--max-limit-orders-per-user=1".into(), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + order_validation: OrderValidationConfig { + max_limit_orders_per_user: 1, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }) .await; let quote_request = OrderQuoteRequest { from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: NonZeroU256::try_from(to_wei(5)).unwrap(), + value: NonZeroU256::try_from(5u64.eth()).unwrap(), }, }, ..Default::default() @@ -748,10 +892,10 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place "in-market" order let order = OrderCreation { - sell_token: token.address().into_legacy(), + sell_token: *token.address(), sell_amount: quote.quote.sell_amount, - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(4)), + buy_token: *onchain.contracts().weth.address(), + buy_amount: quote.quote.buy_amount.saturating_sub(4u64.eth()), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -759,16 +903,16 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); assert!(services.create_order(&order).await.is_ok()); // Place a "limit" order let order = OrderCreation { - sell_token: token.address().into_legacy(), - sell_amount: to_wei(1), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(3), + sell_token: *token.address(), + sell_amount: 1u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -776,7 +920,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let order_id = services.create_order(&order).await.unwrap(); let limit_order = services.get_order(&order_id).await.unwrap(); @@ -784,10 +928,10 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place another "in-market" order in order to check it is not limited let order = OrderCreation { - sell_token: token.address().into_legacy(), + sell_token: *token.address(), sell_amount: quote.quote.sell_amount, - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(2)), + buy_token: *onchain.contracts().weth.address(), + buy_amount: quote.quote.buy_amount.saturating_sub(2u64.eth()), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -795,16 +939,16 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); assert!(services.create_order(&order).await.is_ok()); // Place a "limit" order in order to see if fails let order = OrderCreation { - sell_token: token.address().into_legacy(), - sell_amount: to_wei(1), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(2), + sell_token: *token.address(), + sell_amount: 1u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 2u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -812,7 +956,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let (status, body) = services.create_order(&order).await.unwrap_err(); @@ -823,29 +967,26 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { async fn forked_mainnet_single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let token_usdc = ERC20::Instance::new( address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), - web3.alloy.clone(), + web3.provider.clone(), ); let token_usdt = ERC20::Instance::new( address!("dac17f958d2ee523a2206206994597c13d831ec7"), - web3.alloy.clone(), + web3.provider.clone(), ); - // Give trader some USDC - web3.alloy + // Give trader some USDT + web3.provider .anvil_send_impersonated_transaction_with_config( - token_usdc - .transfer( - trader.address().into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) - .from(USDC_WHALE_MAINNET) + token_usdt + .transfer(trader.address(), 1000u64.matom()) + .from(USDT_WHALE_MAINNET) .into_transaction_request(), ImpersonateConfig { fund_amount: None, @@ -859,12 +1000,9 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { .unwrap(); // Approve GPv2 for trading - token_usdc - .approve( - onchain.contracts().allowance.into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) - .from(trader.address().into_alloy()) + token_usdt + .approve(onchain.contracts().allowance, 1000u64.matom()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -876,10 +1014,10 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { onchain.mint_block().await; let order = OrderCreation { - sell_token: token_usdc.address().into_legacy(), - sell_amount: to_wei_with_exp(1000, 6), - buy_token: token_usdt.address().into_legacy(), - buy_amount: to_wei_with_exp(500, 6), + sell_token: *token_usdt.address(), + sell_amount: 1000u64.matom(), + buy_token: *token_usdc.address(), + buy_amount: 500u64.matom(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -887,34 +1025,26 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); // Warm up co-located driver by quoting the order (otherwise placing an order // may time out) let _ = services .submit_quote(&OrderQuoteRequest { - sell_token: token_usdc.address().into_legacy(), - buy_token: token_usdt.address().into_legacy(), + sell_token: *token_usdt.address(), + buy_token: *token_usdc.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei_with_exp(1000, 6).try_into().unwrap(), + value: (1000u64.matom()).try_into().unwrap(), }, }, ..Default::default() }) .await; - let sell_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_before = token_usdt - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_usdt.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); let order_id = services.create_order(&order).await.unwrap(); let limit_order = services.get_order(&order_id).await.unwrap(); assert_eq!(limit_order.metadata.class, OrderClass::Limit); @@ -924,20 +1054,11 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { wait_for_condition(TIMEOUT, || async { onchain.mint_block().await; - let sell_token_balance_after = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_after = token_usdt - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_after = token_usdt.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_after = token_usdc.balanceOf(trader.address()).call().await.unwrap(); (sell_token_balance_before > sell_token_balance_after) - && (buy_token_balance_after - >= buy_token_balance_before + to_wei_with_exp(500, 6).into_alloy()) + && (buy_token_balance_after >= buy_token_balance_before + 500u64.matom()) }) .await .unwrap(); @@ -946,28 +1067,25 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { async fn forked_gnosis_single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let token_usdc = ERC20::Instance::new( address!("ddafbb505ad214d7b80b1f830fccc89b60fb7a83"), - web3.alloy.clone(), + web3.provider.clone(), ); let token_wxdai = ERC20::Instance::new( address!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), - web3.alloy.clone(), + web3.provider.clone(), ); // Give trader some USDC - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer( - trader.address().into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) + .transfer(trader.address(), 1000u64.matom()) .from(USDC_WHALE_GNOSIS) .into_transaction_request(), ImpersonateConfig { @@ -983,11 +1101,8 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { // Approve GPv2 for trading token_usdc - .approve( - onchain.contracts().allowance.into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 1000u64.matom()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -997,10 +1112,10 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { services.start_protocol(solver).await; let order = OrderCreation { - sell_token: token_usdc.address().into_legacy(), - sell_amount: to_wei_with_exp(1000, 6), - buy_token: token_wxdai.address().into_legacy(), - buy_amount: to_wei(500), + sell_token: *token_usdc.address(), + sell_amount: 1000u64.matom(), + buy_token: *token_wxdai.address(), + buy_amount: 500u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -1008,15 +1123,11 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); - let sell_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); let buy_token_balance_before = token_wxdai - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -1028,19 +1139,15 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { // Drive solution tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let sell_token_balance_after = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_after = token_usdc.balanceOf(trader.address()).call().await.unwrap(); let buy_token_balance_after = token_wxdai - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); (sell_token_balance_before > sell_token_balance_after) - && (buy_token_balance_after >= buy_token_balance_before + eth(500)) + && (buy_token_balance_after >= buy_token_balance_before + 500u64.eth()) }) .await .unwrap(); @@ -1049,65 +1156,63 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { async fn no_liquidity_limit_order(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10_000)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; - let [token_a, unsupported] = onchain.deploy_tokens(solver.account()).await; + let [solver] = onchain.make_solvers(10_000u64.eth()).await; + let [trader_a] = onchain.make_accounts(1u64.eth()).await; + let [token_a, unsupported] = onchain.deploy_tokens(solver.address()).await; // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), 10u64.eth()).await; // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); // Setup services - let protocol_fee_args = ProtocolFeesConfig { - protocol_fees: vec![ - ProtocolFee { - policy: fee::FeePolicyKind::Surplus { - factor: 0.5, - max_volume_factor: 0.01, - }, - policy_order_class: FeePolicyOrderClass::Limit, - }, - ProtocolFee { - policy: fee::FeePolicyKind::PriceImprovement { - factor: 0.5, - max_volume_factor: 0.01, - }, - policy_order_class: FeePolicyOrderClass::Market, - }, - ], - ..Default::default() - } - .into_args(); let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - autopilot: [ - protocol_fee_args, - vec![format!("--unsupported-tokens={:#x}", unsupported.address())], - ] - .concat(), - ..Default::default() + Configuration { + drivers: vec![Solver::test("test_solver", solver.address())], + unsupported_tokens: vec![*unsupported.address()], + fee_policies: FeePoliciesConfig { + policies: vec![ + FeePolicy { + kind: FeePolicyKind::Surplus { + factor: 0.5.try_into().unwrap(), + max_volume_factor: 0.01.try_into().unwrap(), + }, + order_class: configs::autopilot::fee_policy::FeePolicyOrderClass::Limit, + }, + FeePolicy { + kind: FeePolicyKind::PriceImprovement { + factor: 0.5.try_into().unwrap(), + max_volume_factor: 0.01.try_into().unwrap(), + }, + order_class: + configs::autopilot::fee_policy::FeePolicyOrderClass::Market, + }, + ], + ..Default::default() + }, + ..Configuration::test_no_drivers() }, + configs::orderbook::Configuration::test_default(), solver, ) .await; // Place order let mut order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -1115,7 +1220,7 @@ async fn no_liquidity_limit_order(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); let order_id = services.create_order(&order).await.unwrap(); onchain.mint_block().await; @@ -1123,12 +1228,12 @@ async fn no_liquidity_limit_order(web3: Web3) { assert_eq!(limit_order.metadata.class, OrderClass::Limit); // Cannot place orders with unsupported tokens - order.sell_token = unsupported.address().into_legacy(); + order.sell_token = *unsupported.address(); services .create_order(&order.sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, )) .await .unwrap_err(); @@ -1136,14 +1241,14 @@ async fn no_liquidity_limit_order(web3: Web3) { let balance_before = onchain .contracts() .weth - .balanceOf(trader_a.address().into_alloy()) + .balanceOf(trader_a.address()) .call() .await .unwrap(); // Create liquidity onchain - .seed_weth_uni_v2_pools([&token_a].iter().copied(), to_wei(1000), to_wei(1000)) + .seed_weth_uni_v2_pools([&token_a].iter().copied(), 1000u64.eth(), 1000u64.eth()) .await; // Drive solution @@ -1180,9 +1285,398 @@ async fn no_liquidity_limit_order(web3: Web3) { let balance_after = onchain .contracts() .weth - .balanceOf(trader_a.address().into_alloy()) + .balanceOf(trader_a.address()) + .call() + .await + .unwrap(); + assert!(balance_after.checked_sub(balance_before).unwrap() >= 5u64.eth()); +} + +/// Test that a limit order with haircut configured executes on-chain with +/// haircutted amounts. The haircut reduces the buy_amount the user receives, +/// both in reported amounts and on-chain execution (they should match). +/// The haircut difference goes to the settlement contract. +async fn sell_order_with_haircut_test(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a] = onchain.make_accounts(1u64.eth()).await; + let [token_a, token_b] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + // Fund trader accounts + token_a.mint(trader_a.address(), 10u64.eth()).await; + + // Create and fund Uniswap pool + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; + onchain + .contracts() + .uniswap_v2_factory + .createPair(*token_a.address(), *token_b.address()) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + token_a + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + token_b + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + onchain + .contracts() + .uniswap_v2_router + .addLiquidity( + *token_a.address(), + *token_b.address(), + 1000u64.eth(), + 1000u64.eth(), + U256::ZERO, + U256::ZERO, + solver.address(), + U256::MAX, + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + // Approve GPv2 for trading + token_a + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader_a.address()) + .send_and_watch() + .await + .unwrap(); + + // Place Orders + let services = Services::new(&onchain).await; + + // Start protocol with 500 bps (5%) haircut + services + .start_protocol_with_args_and_haircut( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), + solver, + 500, + ) + .await; + + // Create order with generous limit to ensure there's slack for haircut + // Sell 10 A for at least 5 B (pool has 1:1 ratio so we'd get ~9.9 B without + // fees) + let order = OrderCreation { + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *token_b.address(), + buy_amount: 5u64.eth(), // Generous limit creates slack for haircut + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader_a.signer, + ); + let trader_balance_before = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + let settlement_balance_before = token_b + .balanceOf(*onchain.contracts().gp_settlement.address()) + .call() + .await + .unwrap(); + let order_id = services.create_order(&order).await.unwrap(); + + onchain.mint_block().await; + let limit_order = services.get_order(&order_id).await.unwrap(); + assert_eq!(limit_order.metadata.class, OrderClass::Limit); + + // Drive solution - order should execute even with haircut applied + tracing::info!("Waiting for trade with haircut."); + wait_for_condition(TIMEOUT, || async { + let balance_after = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + balance_after.checked_sub(trader_balance_before).unwrap() >= 5u64.eth() + }) + .await + .unwrap(); + + // Verify that haircut DOES affect on-chain execution. + // The haircut reduces the buy_amount the user receives, with the difference + // going to the settlement contract. + let trader_balance_after = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + let settlement_balance_after = token_b + .balanceOf(*onchain.contracts().gp_settlement.address()) .call() .await .unwrap(); - assert!(balance_after.checked_sub(balance_before).unwrap() >= eth(5)); + + let trader_received = trader_balance_after + .checked_sub(trader_balance_before) + .unwrap(); + let settlement_received = settlement_balance_after + .checked_sub(settlement_balance_before) + .unwrap(); + + // With 500 bps (5%) haircut on ~9.87 ETH buy amount, settlement should receive + // ~0.49 ETH. Allow some tolerance for AMM fees and rounding. + assert!( + settlement_received >= 0.4.eth() && settlement_received <= 0.6.eth(), + "Settlement contract should have received haircut (~0.49 ETH), but got {}", + settlement_received + ); + + // Expected trader amount: AMM output minus haircut (~9.87 - 0.49 = ~9.38 ETH). + // Haircut reduces what trader receives on-chain. + assert!( + trader_received >= 9u64.eth() && trader_received <= 9.5.eth(), + "Trader should have received AMM output minus haircut (~9.38 ETH), but got {}", + trader_received + ); + + // Wait for solver competition data to be indexed + tracing::info!("Waiting for solver competition to be indexed"); + let indexed = || async { + onchain.mint_block().await; + match services.get_trades(&order_id).await.unwrap().first() { + Some(trade) => services + .get_solver_competition(trade.tx_hash.unwrap()) + .await + .is_ok(), + None => false, + } + }; + wait_for_condition(TIMEOUT, indexed).await.unwrap(); + + let trades = services.get_trades(&order_id).await.unwrap(); + let tx_hash = trades[0].tx_hash.unwrap(); + let competition = services.get_solver_competition(tx_hash).await.unwrap(); + + // Find our order in the winning solution + let winner = competition + .solutions + .iter() + .find(|s| s.is_winner) + .expect("Should have winning solution"); + + let reported_order = winner + .orders + .iter() + .find(|o| o.id == order_id) + .expect("Order should be in solution"); + + let signed_sell_amount = U256::from(order.sell_amount); + let reported_sell_amount = reported_order.sell_amount; + + assert!( + reported_sell_amount <= signed_sell_amount, + "Driver reported sell_amount {} exceeds signed sell_amount {}. Haircut should reduce \ + surplus/score, not inflate the reported sell amount!", + reported_sell_amount, + signed_sell_amount + ); +} + +/// Test that a buy order with haircut configured executes correctly. +/// For buy orders, the user signs for a specific buy_amount they want to +/// receive, and sell_amount is the maximum they're willing to pay. +/// Haircut increases the sell_amount on-chain (user pays more). +/// Verifies that reported amounts match on-chain execution. +async fn buy_order_with_haircut_test(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + let [token_a, token_b] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + // Create and fund Uniswap pool (1:1 ratio) + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; + onchain + .contracts() + .uniswap_v2_factory + .createPair(*token_a.address(), *token_b.address()) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + token_a + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + token_b + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + onchain + .contracts() + .uniswap_v2_router + .addLiquidity( + *token_a.address(), + *token_b.address(), + 1000u64.eth(), + 1000u64.eth(), + U256::ZERO, + U256::ZERO, + solver.address(), + U256::MAX, + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + // Fund trader with token_a for selling + token_a.mint(trader.address(), 100u64.eth()).await; + token_a + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + // Start protocol with 500 bps (5%) haircut + let services = Services::new(&onchain).await; + + // Start protocol with 500 bps (5%) haircut + services + .start_protocol_with_args_and_haircut( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), + solver, + 500, + ) + .await; + + // Create BUY order: want to buy 5 token_b, willing to sell up to 10 token_a. + // At 1:1 ratio (with ~0.3% AMM fee), we'd need ~5.04 token_a. + // We use a generous sell_limit to ensure the order executes, then verify + // that the driver's reported sell_amount doesn't exceed reasonable bounds. + let signed_buy_amount = 5u64.eth(); + let sell_limit = 10u64.eth(); // Generous limit to ensure execution + let order = OrderCreation { + sell_token: *token_a.address(), + sell_amount: sell_limit, + buy_token: *token_b.address(), + buy_amount: signed_buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Buy, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + let order_id = services.create_order(&order).await.unwrap(); + + onchain.mint_block().await; + let limit_order = services.get_order(&order_id).await.unwrap(); + assert_eq!(limit_order.metadata.class, OrderClass::Limit); + + // Wait for trade to execute + tracing::info!("Waiting for buy order trade with haircut."); + let trader_b_balance_before = token_b.balanceOf(trader.address()).call().await.unwrap(); + wait_for_condition(TIMEOUT, || async { + let balance_after = token_b.balanceOf(trader.address()).call().await.unwrap(); + balance_after > trader_b_balance_before + }) + .await + .unwrap(); + + // Wait for solver competition data to be indexed + tracing::info!("Waiting for solver competition to be indexed"); + let indexed = || async { + onchain.mint_block().await; + match services.get_trades(&order_id).await.unwrap().first() { + Some(trade) => services + .get_solver_competition(trade.tx_hash.unwrap()) + .await + .is_ok(), + None => false, + } + }; + wait_for_condition(TIMEOUT, indexed).await.unwrap(); + + let trades = services.get_trades(&order_id).await.unwrap(); + let tx_hash = trades[0].tx_hash.unwrap(); + let competition = services.get_solver_competition(tx_hash).await.unwrap(); + + // Find our order in the winning solution + let winner = competition + .solutions + .iter() + .find(|s| s.is_winner) + .expect("Should have winning solution"); + + let reported_order = winner + .orders + .iter() + .find(|o| o.id == order_id) + .expect("Order should be in solution"); + + let signed_buy_amount_u256 = U256::from(signed_buy_amount); + let sell_limit_u256 = U256::from(sell_limit); + let reported_sell_amount = reported_order.sell_amount; + let reported_buy_amount = reported_order.buy_amount; + + // For buy orders: + // 1. User should get at least what they signed for + assert!( + reported_buy_amount >= signed_buy_amount_u256, + "Buy order: reported buy_amount {} is less than signed buy_amount {}", + reported_buy_amount, + signed_buy_amount_u256 + ); + + // 2. Don't take more than user's maximum + assert!( + reported_sell_amount <= sell_limit_u256, + "Driver reported sell_amount {} exceeds sell limit {}", + reported_sell_amount, + sell_limit_u256 + ); + + // 3. For buy orders, haircut INCREASES sell_amount (user pays more). Base + // needed is ~5.04 ETH, with 5% haircut on 5 ETH buy amount = 0.25 ETH. So + // sell_amount should be ~5.04 + 0.25 = ~5.29 ETH. We allow up to 5.5 ETH to + // account for variance. + let reasonable_max_sell = 5.5.eth(); + assert!( + reported_sell_amount <= reasonable_max_sell, + "Driver reported sell_amount {} exceeds expected max {} (actual needed + haircut is ~5.29 \ + ETH)", + reported_sell_amount, + reasonable_max_sell + ); } diff --git a/crates/e2e/tests/e2e/liquidity.rs b/crates/e2e/tests/e2e/liquidity.rs index 1598e095f4..5133e5e4e1 100644 --- a/crates/e2e/tests/e2e/liquidity.rs +++ b/crates/e2e/tests/e2e/liquidity.rs @@ -1,11 +1,18 @@ use { alloy::{ - primitives::{Address, address}, - providers::ext::{AnvilApi, ImpersonateConfig}, + primitives::{Address, B256, address}, + providers::{ + Provider, + ext::{AnvilApi, ImpersonateConfig}, + }, }, chrono::{NaiveDateTime, Utc}, - contracts::alloy::{ERC20, IZeroex, InstanceExt}, - driver::domain::eth::H160, + configs::{ + autopilot::Configuration, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, + }, + contracts::{ERC20, IZeroex}, e2e::{ api::zeroex::{Eip712TypedZeroExOrder, ZeroExApi}, assert_approximately_eq, @@ -16,30 +23,20 @@ use { TestAccount, colocation, run_forked_test_with_block_number, - to_wei, - to_wei_with_exp, wait_for_condition, }, }, - ethcontract::{Account, H256, prelude::U256}, - ethrpc::{ - Web3, - alloy::{ - CallBuilderExt, - ProviderSignerExt, - conversions::{IntoAlloy, IntoLegacy, TryIntoAlloyAsync}, - }, - }, + ethrpc::{Web3, alloy::CallBuilderExt}, + liquidity_sources::zeroex, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - web3::signing::SecretKeyRef, + number::units::EthUnit, }; /// The block number from which we will fetch state for the forked tests. -pub const FORK_BLOCK: u64 = 23112197; +pub const FORK_BLOCK: u64 = 24843565; pub const USDT_WHALE: Address = address!("F977814e90dA44bFA03b6295A0616a897441aceC"); pub const USDC_WHALE: Address = address!("28c6c06298d514db089934071355e5743bf21d60"); @@ -58,32 +55,29 @@ async fn forked_node_zero_ex_liquidity_mainnet() { async fn zero_ex_liquidity(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; - let [trader, zeroex_maker] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; + let [trader, zeroex_maker] = onchain.make_accounts(1u64.eth()).await; let token_usdc = ERC20::Instance::new( address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), - web3.alloy.clone(), + web3.provider.clone(), ); let token_usdt = ERC20::Instance::new( address!("dac17f958d2ee523a2206206994597c13d831ec7"), - web3.alloy.clone(), + web3.provider.clone(), ); - let zeroex_provider = { - let signer = solver.account().clone().try_into_alloy().await.unwrap(); - web3.alloy.with_signer(signer) - }; - let zeroex = IZeroex::Instance::deployed(&zeroex_provider).await.unwrap(); + web3.wallet.register_signer(solver.signer.clone()); + let zeroex = IZeroex::Instance::deployed(&web3.provider).await.unwrap(); - let amount = to_wei_with_exp(5, 8).into_alloy(); + let amount = 500u64.matom(); // Give trader some USDC - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(trader.address().into_alloy(), amount) + .transfer(trader.address(), amount) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -99,11 +93,11 @@ async fn zero_ex_liquidity(web3: Web3) { // Give 0x maker a bit more USDT // With a lower amount 0x contract shows much lower fillable amount - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_usdt .transfer( - zeroex_maker.address().into_alloy(), + zeroex_maker.address(), amount * alloy::primitives::U256::from(4), ) .from(USDT_WHALE) @@ -119,10 +113,10 @@ async fn zero_ex_liquidity(web3: Web3) { .await .unwrap(); // Required for the remaining fillable taker amount - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(solver.address().into_alloy(), amount) + .transfer(solver.address(), amount) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -137,30 +131,30 @@ async fn zero_ex_liquidity(web3: Web3) { .unwrap(); token_usdc - .approve(onchain.contracts().allowance.into_alloy(), amount) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, amount) + .from(trader.address()) .send_and_watch() .await .unwrap(); // With a lower amount 0x contract shows much lower fillable amount token_usdt .approve(*zeroex.address(), amount * alloy::primitives::U256::from(4)) - .from(zeroex_maker.address().into_alloy()) + .from(zeroex_maker.address()) .send_and_watch() .await .unwrap(); token_usdc .approve(*zeroex.address(), amount) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); let order = OrderCreation { - sell_token: token_usdc.address().into_legacy(), - sell_amount: amount.into_legacy(), - buy_token: token_usdt.address().into_legacy(), - buy_amount: amount.into_legacy(), + sell_token: *token_usdc.address(), + sell_amount: amount, + buy_token: *token_usdt.address(), + buy_amount: amount, valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -168,16 +162,16 @@ async fn zero_ex_liquidity(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); - let chain_id = web3.eth().chain_id().await.unwrap().as_u64(); + let chain_id = web3.provider.get_chain_id().await.unwrap(); let zeroex_liquidity_orders = create_zeroex_liquidity_orders( order.clone(), zeroex_maker.clone(), - zeroex.address().into_legacy(), + *zeroex.address(), chain_id, - onchain.contracts().weth.address().into_legacy(), + *onchain.contracts().weth.address(), ); let zeroex_api_port = ZeroExApi::new(zeroex_liquidity_orders.to_vec()).run().await; @@ -201,36 +195,32 @@ async fn zero_ex_liquidity(web3: Web3) { }, false, ); + services .start_autopilot( None, - vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - format!( - "--drivers=test_solver|http://localhost:11088/test_solver|{}", - const_hex::encode(solver.address()) - ), - ], + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test("test_solver", solver.address()) + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Drive solution - let sell_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_before = token_usdt - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_before = token_usdt.balanceOf(trader.address()).call().await.unwrap(); services.create_order(&order).await.unwrap(); onchain.mint_block().await; @@ -238,7 +228,7 @@ async fn zero_ex_liquidity(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { token_usdc - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .is_ok_and(|balance| balance < sell_token_balance_before) @@ -247,7 +237,7 @@ async fn zero_ex_liquidity(web3: Web3) { .unwrap(); wait_for_condition(TIMEOUT, || async { token_usdt - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .is_ok_and(|balance| balance >= buy_token_balance_before + amount) @@ -274,8 +264,8 @@ async fn zero_ex_liquidity(web3: Web3) { // Fill the remaining part of the 0x order let zeroex_order = Eip712TypedZeroExOrder { - maker_token: token_usdt.address().into_legacy(), - taker_token: token_usdc.address().into_legacy(), + maker_token: *token_usdt.address(), + taker_token: *token_usdc.address(), maker_amount: zeroex_order_amounts.fillable, taker_amount: zeroex_order_amounts.fillable, // doesn't participate in the hash calculation @@ -284,13 +274,13 @@ async fn zero_ex_liquidity(web3: Web3) { maker: zeroex_maker.address(), taker: Default::default(), sender: Default::default(), - fee_recipient: zeroex.address().into_legacy(), - pool: H256::default(), + fee_recipient: *zeroex.address(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), } - .to_order_record(chain_id, zeroex.address().into_legacy(), zeroex_maker); - fill_or_kill_zeroex_limit_order(&zeroex, &zeroex_order, solver.account().clone()) + .to_order_record(chain_id, *zeroex.address(), zeroex_maker); + fill_or_kill_zeroex_limit_order(&zeroex, &zeroex_order, solver.address()) .await .unwrap(); let zeroex_order_amounts = get_zeroex_order_amounts(&zeroex, &zeroex_order) @@ -309,28 +299,32 @@ async fn zero_ex_liquidity(web3: Web3) { fn create_zeroex_liquidity_orders( order_creation: OrderCreation, zeroex_maker: TestAccount, - zeroex_addr: H160, + zeroex_addr: Address, chain_id: u64, - weth_address: H160, -) -> [shared::zeroex_api::OrderRecord; 3] { + weth_address: Address, +) -> [zeroex::OrderRecord; 3] { let typed_order = Eip712TypedZeroExOrder { maker_token: order_creation.buy_token, taker_token: order_creation.sell_token, // fully covers execution costs - maker_amount: order_creation.buy_amount.as_u128() * 3, - taker_amount: order_creation.sell_amount.as_u128() * 2, + maker_amount: u128::try_from(order_creation.buy_amount).unwrap() * 3, + taker_amount: u128::try_from(order_creation.sell_amount).unwrap() * 2, // makes 0x order partially filled, but the amount is higher than the cowswap order to // make sure the 0x order is not overfilled in the end of the e2e test - remaining_fillable_taker_amount: order_creation.sell_amount.as_u128() * 3 / 2, + remaining_fillable_taker_amount: (order_creation.sell_amount + * alloy::primitives::U256::from(3) + / alloy::primitives::U256::from(2)) + .try_into() + .unwrap(), taker_token_fee_amount: 0, maker: zeroex_maker.address(), // Makes it possible for anyone to fill the order taker: Default::default(), sender: Default::default(), fee_recipient: zeroex_addr, - pool: H256::default(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), }; let usdt_weth_order = Eip712TypedZeroExOrder { maker_token: weth_address, @@ -338,16 +332,16 @@ fn create_zeroex_liquidity_orders( // the value comes from the `--amount-to-estimate-prices-with` config to provide // sufficient liquidity maker_amount: 1_000_000_000_000_000_000u128, - taker_amount: order_creation.sell_amount.as_u128(), - remaining_fillable_taker_amount: order_creation.sell_amount.as_u128(), + taker_amount: order_creation.sell_amount.try_into().unwrap(), + remaining_fillable_taker_amount: order_creation.sell_amount.try_into().unwrap(), taker_token_fee_amount: 0, maker: zeroex_maker.address(), taker: Default::default(), sender: Default::default(), fee_recipient: zeroex_addr, - pool: H256::default(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), }; let usdc_weth_order = Eip712TypedZeroExOrder { maker_token: weth_address, @@ -355,16 +349,16 @@ fn create_zeroex_liquidity_orders( // the value comes from the `--amount-to-estimate-prices-with` config to provide // sufficient liquidity maker_amount: 1_000_000_000_000_000_000u128, - taker_amount: order_creation.sell_amount.as_u128(), - remaining_fillable_taker_amount: order_creation.sell_amount.as_u128(), + taker_amount: order_creation.sell_amount.try_into().unwrap(), + remaining_fillable_taker_amount: order_creation.sell_amount.try_into().unwrap(), taker_token_fee_amount: 0, maker: zeroex_maker.address(), taker: Default::default(), sender: Default::default(), fee_recipient: zeroex_addr, - pool: H256::default(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), }; [typed_order, usdt_weth_order, usdc_weth_order] .map(|order| order.to_order_record(chain_id, zeroex_addr, zeroex_maker.clone())) @@ -378,29 +372,29 @@ struct ZeroExOrderAmounts { async fn get_zeroex_order_amounts( zeroex: &IZeroex::Instance, - zeroex_order: &shared::zeroex_api::OrderRecord, + zeroex_order: &zeroex::OrderRecord, ) -> anyhow::Result { Ok(zeroex .getLimitOrderRelevantState( IZeroex::LibNativeOrder::LimitOrder { - makerToken: zeroex_order.order().maker_token.into_alloy(), - takerToken: zeroex_order.order().taker_token.into_alloy(), + makerToken: zeroex_order.order().maker_token, + takerToken: zeroex_order.order().taker_token, makerAmount: zeroex_order.order().maker_amount, takerAmount: zeroex_order.order().taker_amount, takerTokenFeeAmount: zeroex_order.order().taker_token_fee_amount, - maker: zeroex_order.order().maker.into_alloy(), - taker: zeroex_order.order().taker.into_alloy(), - sender: zeroex_order.order().sender.into_alloy(), - feeRecipient: zeroex_order.order().fee_recipient.into_alloy(), - pool: zeroex_order.order().pool.into_alloy(), + maker: zeroex_order.order().maker, + taker: zeroex_order.order().taker, + sender: zeroex_order.order().sender, + feeRecipient: zeroex_order.order().fee_recipient, + pool: zeroex_order.order().pool, expiry: zeroex_order.order().expiry, - salt: zeroex_order.order().salt.into_alloy(), + salt: zeroex_order.order().salt, }, IZeroex::LibSignature::Signature { signatureType: zeroex_order.order().signature.signature_type, v: zeroex_order.order().signature.v, - r: zeroex_order.order().signature.r.into_alloy(), - s: zeroex_order.order().signature.s.into_alloy(), + r: zeroex_order.order().signature.r, + s: zeroex_order.order().signature.s, }, ) .call() @@ -413,38 +407,39 @@ async fn get_zeroex_order_amounts( async fn fill_or_kill_zeroex_limit_order( zeroex: &IZeroex::Instance, - zeroex_order: &shared::zeroex_api::OrderRecord, - from_account: Account, -) -> anyhow::Result { + zeroex_order: &zeroex::OrderRecord, + from: Address, +) -> anyhow::Result { + let order = zeroex_order.order(); let tx_hash = zeroex .fillOrKillLimitOrder( IZeroex::LibNativeOrder::LimitOrder { - makerToken: zeroex_order.order().maker_token.into_alloy(), - takerToken: zeroex_order.order().taker_token.into_alloy(), - makerAmount: zeroex_order.order().maker_amount, - takerAmount: zeroex_order.order().taker_amount, - takerTokenFeeAmount: zeroex_order.order().taker_token_fee_amount, - maker: zeroex_order.order().maker.into_alloy(), - taker: zeroex_order.order().taker.into_alloy(), - sender: zeroex_order.order().sender.into_alloy(), - feeRecipient: zeroex_order.order().fee_recipient.into_alloy(), - pool: zeroex_order.order().pool.into_alloy(), - expiry: zeroex_order.order().expiry, - salt: zeroex_order.order().salt.into_alloy(), + makerToken: order.maker_token, + takerToken: order.taker_token, + makerAmount: order.maker_amount, + takerAmount: order.taker_amount, + takerTokenFeeAmount: order.taker_token_fee_amount, + maker: order.maker, + taker: order.taker, + sender: order.sender, + feeRecipient: order.fee_recipient, + pool: order.pool, + expiry: order.expiry, + salt: order.salt, }, IZeroex::LibSignature::Signature { - signatureType: zeroex_order.order().signature.signature_type, - v: zeroex_order.order().signature.v, - r: zeroex_order.order().signature.r.into_alloy(), - s: zeroex_order.order().signature.s.into_alloy(), + signatureType: order.signature.signature_type, + v: order.signature.v, + r: order.signature.r, + s: order.signature.s, }, zeroex_order.order().taker_amount, ) - .from(from_account.address().into_alloy()) + .from(from) .send() .await? .watch() .await?; - Ok(tx_hash.into_legacy()) + Ok(tx_hash) } diff --git a/crates/e2e/tests/e2e/liquidity_source_notification.rs b/crates/e2e/tests/e2e/liquidity_source_notification.rs index 500210efa9..38c7fa9194 100644 --- a/crates/e2e/tests/e2e/liquidity_source_notification.rs +++ b/crates/e2e/tests/e2e/liquidity_source_notification.rs @@ -2,10 +2,15 @@ use { alloy::{ primitives::{Address, Bytes, U256, address}, providers::ext::{AnvilApi, ImpersonateConfig}, - signers::{SignerSync, local::PrivateKeySigner}, + signers::SignerSync, }, chrono::Utc, - contracts::alloy::{ERC20, InstanceExt, LiquoriceSettlement}, + configs::{ + autopilot::Configuration, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, + }, + contracts::{ERC20, LiquoriceSettlement}, driver::infra, e2e::{ api, @@ -16,30 +21,21 @@ use { colocation::{self, SolverEngine}, mock::Mock, run_forked_test_with_block_number, - to_wei, - to_wei_with_exp, wait_for_condition, }, }, - ethrpc::{ - Web3, - alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, - }, + ethrpc::{Web3, alloy::CallBuilderExt}, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, + number::units::EthUnit, solvers_dto::solution::Solution, std::collections::HashMap, - web3::signing::SecretKeyRef, }; /// The block number from which we will fetch state for the forked tests. -pub const FORK_BLOCK: u64 = 23326100; +pub const FORK_BLOCK: u64 = 24843565; pub const USDT_WHALE: Address = address!("6AC38D1b2f0c0c3b9E816342b1CA14d91D5Ff60B"); pub const USDC_WHALE: Address = address!("01b8697695eab322a339c4bf75740db75dc9375e"); @@ -60,34 +56,34 @@ async fn liquidity_source_notification(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; // Define trade params - let trade_amount = to_wei_with_exp(5, 8); + let trade_amount = 500u64.matom(); // Create parties accounts // solver - represents both baseline solver engine for quoting and liquorice // solver engine for solving - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; // trader - the account that will place CoW order // liquorice_maker - the account that will place Liquorice order to fill CoW // order with - let [trader, liquorice_maker] = onchain.make_accounts(to_wei(1)).await; + let [trader, liquorice_maker] = onchain.make_accounts(1u64.eth()).await; // Access trade tokens contracts let token_usdc = ERC20::Instance::new( address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), - web3.alloy.clone(), + web3.provider.clone(), ); let token_usdt = ERC20::Instance::new( address!("dac17f958d2ee523a2206206994597c13d831ec7"), - web3.alloy.clone(), + web3.provider.clone(), ); // CoW onchain setup // Fund trader - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(trader.address().into_alloy(), trade_amount.into_alloy()) + .transfer(trader.address(), trade_amount) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -102,10 +98,10 @@ async fn liquidity_source_notification(web3: Web3) { .unwrap(); // Fund solver - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(solver.address().into_alloy(), trade_amount.into_alloy()) + .transfer(solver.address(), trade_amount) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -121,11 +117,8 @@ async fn liquidity_source_notification(web3: Web3) { // Trader gives approval to the CoW allowance contract token_usdc - .approve( - onchain.contracts().allowance.into_alloy(), - alloy::primitives::U256::MAX, - ) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, U256::MAX) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -134,7 +127,7 @@ async fn liquidity_source_notification(web3: Web3) { // Liquorice settlement contract through which we will trade with the // `liquorice_maker` - let liquorice_settlement = LiquoriceSettlement::Instance::deployed(&web3.alloy) + let liquorice_settlement = LiquoriceSettlement::Instance::deployed(&web3.provider) .await .unwrap(); @@ -142,17 +135,13 @@ async fn liquidity_source_notification(web3: Web3) { .BALANCE_MANAGER() .call() .await - .expect("no balance manager found") - .into_legacy(); + .expect("no balance manager found"); // Fund `liquorice_maker` - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( token_usdt - .transfer( - liquorice_maker.address().into_alloy(), - trade_amount.into_alloy(), - ) + .transfer(liquorice_maker.address(), trade_amount) .from(USDT_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -168,11 +157,8 @@ async fn liquidity_source_notification(web3: Web3) { // Maker gives approval to the Liquorice balance manager contract token_usdt - .approve( - liquorice_balance_manager_address.into_alloy(), - alloy::primitives::U256::MAX, - ) - .from(liquorice_maker.address().into_alloy()) + .approve(liquorice_balance_manager_address, U256::MAX) + .from(liquorice_maker.address()) .send_and_watch() .await .unwrap(); @@ -181,7 +167,7 @@ async fn liquidity_source_notification(web3: Web3) { let liquorice_api = api::liquorice::server::LiquoriceApi::start().await; // CoW services setup - let liquorice_solver_api_mock = Mock::default(); + let liquorice_solver_api_mock = Mock::new().await; let services = Services::new(&onchain).await; colocation::start_driver_with_config_override( @@ -202,6 +188,8 @@ async fn liquidity_source_notification(web3: Web3) { endpoint: liquorice_solver_api_mock.url.clone(), base_tokens: vec![], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, ], colocation::LiquidityProvider::UniswapV2, @@ -217,31 +205,35 @@ http-timeout = "10s" liquorice_api.port )), ); + services .start_autopilot( None, - vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - format!( - "--drivers=liquorice_solver|http://localhost:11088/liquorice_solver|{}", - const_hex::encode(solver.address()) - ), - ], + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test("liquorice_solver", solver.address()) + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Create CoW order let order_id = { let order = OrderCreation { - sell_token: token_usdc.address().into_legacy(), + sell_token: *token_usdc.address(), sell_amount: trade_amount, - buy_token: token_usdt.address().into_legacy(), + buy_token: *token_usdt.address(), buy_amount: trade_amount, valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, @@ -250,7 +242,7 @@ http-timeout = "10s" .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap() }; @@ -265,11 +257,11 @@ http-timeout = "10s" effectiveTrader: *onchain.contracts().gp_settlement.address(), baseToken: *token_usdc.address(), quoteToken: *token_usdt.address(), - baseTokenAmount: trade_amount.into_alloy(), - quoteTokenAmount: trade_amount.into_alloy(), + baseTokenAmount: trade_amount, + quoteTokenAmount: trade_amount, minFillAmount: U256::from(1), quoteExpiry: U256::from(Utc::now().timestamp() as u64 + 10), - recipient: liquorice_maker.address().into_alloy(), + recipient: liquorice_maker.address(), }; // Create calldata @@ -281,13 +273,14 @@ http-timeout = "10s" .unwrap(); // Create Liquorice order signature - let signer = PrivateKeySigner::from_slice(liquorice_maker.private_key()).unwrap(); + let liquorice_maker_address = liquorice_maker.address(); + let signer = liquorice_maker.signer; let liquorice_order_signature = signer.sign_hash_sync(&liquorice_order_hash).unwrap(); // Create Liquorice settlement calldata liquorice_settlement .settleSingle( - liquorice_maker.address().into_alloy(), + liquorice_maker_address, liquorice_order.clone(), LiquoriceSettlement::Signature::TypedSignature { signatureType: 3, // EIP712 @@ -310,24 +303,24 @@ http-timeout = "10s" liquorice_solver_api_mock.configure_solution(Some(Solution { id: 1, prices: HashMap::from([ - (token_usdc.address().into_legacy(), to_wei(11)), - (token_usdt.address().into_legacy(), to_wei(10)), + (*token_usdc.address(), 11u64.eth()), + (*token_usdt.address(), 10u64.eth()), ]), trades: vec![solvers_dto::solution::Trade::Fulfillment( solvers_dto::solution::Fulfillment { executed_amount: trade_amount, - fee: Some(0.into()), + fee: Some(U256::ZERO), order: solvers_dto::solution::OrderUid(order_id.0), }, )], pre_interactions: vec![], interactions: vec![solvers_dto::solution::Interaction::Custom( solvers_dto::solution::CustomInteraction { - target: liquorice_settlement.address().into_legacy(), + target: *liquorice_settlement.address(), calldata: liquorice_solution_calldata, - value: 0.into(), + value: U256::ZERO, allowances: vec![solvers_dto::solution::Allowance { - token: token_usdc.address().into_legacy(), + token: *token_usdc.address(), spender: liquorice_balance_manager_address, amount: trade_amount, }], @@ -340,6 +333,7 @@ http-timeout = "10s" gas: None, flashloans: None, wrappers: vec![], + gas_fee_override: None, })); // Wait for trade @@ -348,7 +342,7 @@ http-timeout = "10s" let trade = services.get_trades(&order_id).await.unwrap().pop()?; Some( services - .get_solver_competition(trade.tx_hash?.into_legacy()) + .get_solver_competition(trade.tx_hash?) .await .is_ok(), ) diff --git a/crates/e2e/tests/e2e/main.rs b/crates/e2e/tests/e2e/main.rs index 02a8bd9d7f..630d76d77f 100644 --- a/crates/e2e/tests/e2e/main.rs +++ b/crates/e2e/tests/e2e/main.rs @@ -4,13 +4,19 @@ // tests we want to run. // Each of the following modules contains tests. +mod api_version; mod app_data; mod app_data_signer; mod autopilot_leader; mod banned_users; mod buffers; +mod contract_revert; +mod cors; mod cow_amm; mod database; +mod debug_order; +mod deprecated_endpoints; +mod eip4626; mod eth_integration; mod eth_safe; mod ethflow; @@ -19,11 +25,15 @@ mod jit_orders; mod limit_orders; mod liquidity; mod liquidity_source_notification; +mod malformed_requests; mod order_cancellation; +mod order_simulation; +mod parallel_settlement; mod partial_fill; mod partially_fillable_balance; mod partially_fillable_pool; mod place_order_with_quote; +mod pool_indexer; mod protocol_fee; mod quote_verification; mod quoting; @@ -31,10 +41,12 @@ mod refunder; mod replace_order; mod smart_contract_orders; mod solver_competition; -mod solver_participation_guard; mod submission; +mod token_metadata; mod tracking_insufficient_funds; +mod trades_v2; mod uncovered_order; mod univ2; +mod user_surplus; mod vault_balances; mod wrapper; diff --git a/crates/e2e/tests/e2e/malformed_requests.rs b/crates/e2e/tests/e2e/malformed_requests.rs new file mode 100644 index 0000000000..9f04f39f52 --- /dev/null +++ b/crates/e2e/tests/e2e/malformed_requests.rs @@ -0,0 +1,499 @@ +//! Tests for malformed request handling and missing endpoints to ensure error +//! responses are preserved. + +use { + configs::{ + order_quoting::{ExternalSolver, OrderQuoting}, + shared::SharedConfig, + test_util::TestDefault, + }, + e2e::setup::{API_HOST, OnchainComponents, Services, run_test}, + model::order::{ORDER_UID_LIMIT, OrderUid}, + orderbook::api::Error, + reqwest::StatusCode, + serde_json::json, + shared::web3::Web3, +}; + +const VALID_ORDER_UID: &str = "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; +const VALID_ADDRESS: &str = "0x0000000000000000000000000000000000000001"; + +#[tokio::test] +#[ignore] +async fn local_node_http_validation() { + run_test(http_validation).await; +} + +/// HTTP validation test covering malformed parameters, request +/// bodies, missing endpoints, and error response formats. +async fn http_validation(web3: Web3) { + let onchain = OnchainComponents::deploy(web3).await; + let services = Services::new(&onchain).await; + // since we're testing malformed paths, etc; + // we don't really need the rest of the protocol + services + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + shared: SharedConfig { + gas_estimators: vec![TestDefault::test_default()], + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }) + .await; + let client = services.client(); + + // Test malformed order UIDs + let too_long_uid = format!("0x{}", "0".repeat(200)); + let non_hex_uid = format!("0x{}", "GG".repeat(56)); + + let invalid_order_uids: Vec<(&str, &str)> = vec![ + ("0x1234", "too short"), + (&too_long_uid, "too long"), + (&non_hex_uid, "non-hex characters"), + ("not-hex-at-all", "no hex prefix"), + ]; + + for (uid, description) in invalid_order_uids { + let response = client + .get(format!("{API_HOST}/api/v1/orders/{uid}")) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "Expected 400 for invalid OrderUid ({description}): {uid}" + ); + } + + // Test malformed addresses + let invalid_hex_addr = format!("0x{}", "G".repeat(40)); + + let invalid_addresses: Vec<(&str, &str)> = vec![ + ("0x123", "too short"), + ("not-an-address", "not hex format"), + (&invalid_hex_addr, "invalid hex characters"), + ]; + + for (addr, description) in invalid_addresses { + let response = client + .get(format!("{API_HOST}/api/v1/account/{addr}/orders")) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "Expected 400 for invalid Address ({description}): {addr}" + ); + } + + for (addr, description) in [("0x123", "too short"), ("invalid", "not hex")] { + let response = client + .get(format!("{API_HOST}/api/v1/token/{addr}/native_price")) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "Expected 400 for invalid token Address ({description}): {addr}" + ); + } + + // Test malformed transaction hashes + let invalid_hex_hash = format!("0x{}", "Z".repeat(64)); + + let invalid_hashes: Vec<(&str, &str)> = vec![ + ("0x123", "too short"), + ("invalid-hash", "not hex format"), + (&invalid_hex_hash, "invalid hex characters"), + ]; + + for (hash, description) in invalid_hashes { + let response = client + .get(format!("{API_HOST}/api/v1/transactions/{hash}/orders")) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "Expected 400 for invalid tx hash ({description}): {hash}" + ); + } + + // Test missing/invalid endpoints + let extra_segment_path = format!("/api/v1/orders/{VALID_ORDER_UID}/extra"); + let wrong_nested_path = format!("/api/v1/account/{VALID_ADDRESS}/trades"); + + let missing_endpoint_cases: Vec<(&str, &str)> = vec![ + ("/api/v1/nonexistent", "completely invalid path"), + ("/api/v3/orders", "wrong API version"), + (&extra_segment_path, "extra path segment after order UID"), + ("/v1/orders", "missing /api prefix"), + ("/api/v1/order", "typo - singular instead of plural"), + ( + &wrong_nested_path, + "wrong nested path - trades instead of orders", + ), + ("/api/v1/tokens", "nonexistent tokens endpoint"), + ("/api/v2/orders", "v2 orders doesn't exist"), + ]; + + for (path, description) in missing_endpoint_cases { + let response = client + .get(format!("{API_HOST}{path}")) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::NOT_FOUND, + "Expected 404 for {description}: {path}" + ); + } + + // Test malformed request bodies - Invalid JSON syntax + let response = client + .post(format!("{API_HOST}/api/v1/orders")) + .header("Content-Type", "application/json") + .body("{invalid json}") + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "Invalid JSON syntax should return 400" + ); + + // Empty body returns 411 Length Required (valid HTTP semantics) + let response = client + .post(format!("{API_HOST}/api/v1/orders")) + .header("Content-Type", "application/json") + .body("") + .send() + .await + .unwrap(); + + assert!( + response.status() == StatusCode::BAD_REQUEST + || response.status() == StatusCode::LENGTH_REQUIRED, + "Empty body should return 400 or 411, got {}", + response.status() + ); + + // Missing required fields (empty object) + let response = client + .post(format!("{API_HOST}/api/v1/orders")) + .header("Content-Type", "application/json") + .json(&json!({})) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::UNPROCESSABLE_ENTITY, + "Missing required fields should return 422" + ); + + // Wrong field types + let response = client + .post(format!("{API_HOST}/api/v1/orders")) + .header("Content-Type", "application/json") + .json(&json!({ + "sellToken": "not-an-address", + "buyToken": "also-not-an-address", + "sellAmount": "not-a-number", + "buyAmount": 12345, + "validTo": "not-a-number", + "kind": "sell", + "signature": "0x" + })) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::UNPROCESSABLE_ENTITY, + "Wrong field types should return 422" + ); + + // Invalid enum value + let response = client + .post(format!("{API_HOST}/api/v1/quote")) + .header("Content-Type", "application/json") + .json(&json!({ + "sellToken": VALID_ADDRESS, + "buyToken": VALID_ADDRESS, + "kind": "invalidKind", + "from": VALID_ADDRESS + })) + .send() + .await + .unwrap(); + + assert_eq!( + response.status(), + StatusCode::UNPROCESSABLE_ENTITY, + "Invalid enum value should return 422" + ); + + // Test error response formats + // Deserialization errors return plain text with error description + let response = client + .post(format!("{API_HOST}/api/v1/orders")) + .header("Content-Type", "application/json") + .json(&json!({})) + .send() + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); + + let body_text = response.text().await.unwrap(); + assert!( + body_text.contains("deserialize") + || body_text.contains("missing field") + || body_text.contains("Failed to deserialize"), + "Deserialization error should contain helpful description. Got: {body_text}" + ); + + // Business logic errors (e.g., order not found) return JSON format + let response = client + .get(format!("{API_HOST}/api/v1/orders/{VALID_ORDER_UID}")) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::NOT_FOUND); + + let body_text = response.text().await.unwrap(); + let error: Error = serde_json::from_str(&body_text).unwrap_or_else(|e| { + panic!("Failed to parse 404 response as Error: {e}. Body was: {body_text}") + }); + + assert!( + !error.error_type.is_empty(), + "Error response should have non-empty 'errorType' field" + ); + assert!( + !error.description.is_empty(), + "Error response should have non-empty 'description' field" + ); + + // /api/v1/orders/by_uids requires Json body + let response = client + .post(format!("{API_HOST}/api/v1/orders/by_uids")) + .header("Content-Type", "application/json") + .body("Not json") + .send() + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // Querying for more than ORDER_UID_LIMIT orders should fail + let response = client + .post(format!("{API_HOST}/api/v1/orders/by_uids")) + .header("Content-Type", "application/json") + .json(&json!( + (0..ORDER_UID_LIMIT + 1) + .map(|_| OrderUid::default()) + .collect::>() + )) + .send() + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // GET /restricted/api/v1/debug/simulation/{uid} error cases + + // Malformed UID → 400 + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/bad_uid" + )) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "malformed UID should return 400" + ); + + // Valid UID but order not found → 404 + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/{VALID_ORDER_UID}" + )) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::NOT_FOUND, + "unknown order UID should return 404" + ); + let body: Error = response.json().await.unwrap(); + assert!(!body.error_type.is_empty()); + assert!(!body.description.is_empty()); + + // Invalid block_number query param → 400 + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/{VALID_ORDER_UID}?\ + block_number=notanumber" + )) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "non-numeric block_number should return 400" + ); + + // POST /restricted/api/v1/debug/simulation error cases + + // Invalid JSON body → 400 + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .header("Content-Type", "application/json") + .body("{invalid json}") + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "invalid JSON should return 400" + ); + + // Missing required fields → 422 + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .json(&json!({})) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::UNPROCESSABLE_ENTITY, + "missing required fields should return 422" + ); + + // Invalid field type (bad address) → 422 + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .json(&json!({ + "sellToken": "not-an-address", + "buyToken": VALID_ADDRESS, + "sellAmount": "1000000000000000000", + "buyAmount": "1000000000000000000", + "kind": "sell", + "owner": VALID_ADDRESS, + })) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::UNPROCESSABLE_ENTITY, + "invalid address field should return 422" + ); + + // Zero sellAmount (NonZeroU256 rejects zero at deserialization) → 422 + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .json(&json!({ + "sellToken": VALID_ADDRESS, + "buyToken": VALID_ADDRESS, + "sellAmount": "0", + "buyAmount": "1000000000000000000", + "kind": "sell", + "owner": VALID_ADDRESS, + })) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::UNPROCESSABLE_ENTITY, + "zero sellAmount should return 422" + ); + + // some fields missing → 422 + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .json(&json!({ + "sellToken": VALID_ADDRESS, + "buyToken": VALID_ADDRESS, + "sellAmount": "1000000000000000000", + "buyAmount": "1000000000000000000", + "kind": "unknownKind", + "owner": VALID_ADDRESS, + })) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::UNPROCESSABLE_ENTITY, + "invalid kind enum should return 422" + ); + + // Invalid appData (non-JSON string triggers MalformedInput) → 400 + let bad_app_data = "not valid json"; + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .json(&json!({ + "sellToken": VALID_ADDRESS, + "buyToken": VALID_ADDRESS, + "sellAmount": "1000000000000000000", + "buyAmount": "1000000000000000000", + "kind": "sell", + "owner": VALID_ADDRESS, + "appData": bad_app_data, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "signingScheme": "eip1271", + "signature": "0x000000", + "feeAmount": "0", + "validTo": 12341234, + "partiallyFillable": false, + })) + .send() + .await + .unwrap(); + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "malformed appData should return 400" + ); + let body: Error = response.json().await.unwrap(); + assert!( + body.description.contains("app data"), + "error description should name the failing field. Got: {}", + body.description + ); + assert!( + body.description.contains(bad_app_data), + "error description should include the bad value. Got: {}", + body.description + ); +} diff --git a/crates/e2e/tests/e2e/order_cancellation.rs b/crates/e2e/tests/e2e/order_cancellation.rs index c73e76a815..fdbf0c2c45 100644 --- a/crates/e2e/tests/e2e/order_cancellation.rs +++ b/crates/e2e/tests/e2e/order_cancellation.rs @@ -1,10 +1,13 @@ use { - database::order_events::OrderEventLabel, - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + ::alloy::primitives::U256, + configs::{ + autopilot::Configuration, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, }, + database::order_events::OrderEventLabel, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{ CancellationPayload, @@ -19,11 +22,9 @@ use { quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::{EcdsaSignature, EcdsaSigningScheme}, }, - number::nonzero::U256 as NonZeroU256, - secp256k1::SecretKey, + number::{nonzero::NonZeroU256, units::EthUnit}, serde_json::json, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + shared::web3::Web3, }; #[tokio::test] @@ -35,19 +36,19 @@ async fn local_node_order_cancellation() { async fn order_cancellation(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token.mint(trader.address(), to_wei(10)).await; + token.mint(trader.address(), 10u64.eth()).await; // Approve GPv2 for trading token - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -72,16 +73,26 @@ async fn order_cancellation(web3: Web3) { services .start_autopilot( None, - vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" - .to_string(), - ], + // Empty drivers to prevent settlement — this test places multiple + // orders and asserts exact auction counts, which would race with the + // solver settling them. + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test_no_drivers() + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; onchain.mint_block().await; @@ -93,11 +104,11 @@ async fn order_cancellation(web3: Web3) { let request = OrderQuoteRequest { from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { - value: NonZeroU256::try_from(to_wei(1)).unwrap(), + value: NonZeroU256::try_from(1u64.eth()).unwrap(), }, }, app_data: OrderCreationAppData::Full { @@ -112,9 +123,9 @@ async fn order_cancellation(web3: Web3) { kind: quote.kind, sell_token: quote.sell_token, sell_amount: quote.sell_amount, - fee_amount: 0.into(), + fee_amount: U256::ZERO, buy_token: quote.buy_token, - buy_amount: (quote.buy_amount * 99) / 100, + buy_amount: ((quote.buy_amount * U256::from(99)) / U256::from(100)), valid_to: quote.valid_to, app_data: quote.app_data, ..Default::default() @@ -122,7 +133,7 @@ async fn order_cancellation(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap() } @@ -133,7 +144,7 @@ async fn order_cancellation(web3: Web3) { let cancellation = OrderCancellation::for_order( order_uid, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); async move { @@ -159,7 +170,7 @@ async fn order_cancellation(web3: Web3) { EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, &cancellations.hash_struct(), - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let signed_cancellations = SignedOrderCancellations { @@ -188,7 +199,14 @@ async fn order_cancellation(web3: Web3) { ]; onchain.mint_block().await; wait_for_condition(TIMEOUT, || async { - services.get_auction().await.auction.orders.len() == 3 + const WAIT_FOR_N_ORDERS: usize = 3; + let n_orders = services.get_auction().await.auction.orders.len(); + tracing::debug!( + "received number of orders: {}, waiting for {}", + n_orders, + WAIT_FOR_N_ORDERS + ); + n_orders == WAIT_FOR_N_ORDERS }) .await .unwrap(); @@ -212,8 +230,10 @@ async fn order_cancellation(web3: Web3) { // Cancel one of them. cancel_order(order_uids[0]).await; - onchain.mint_block().await; wait_for_condition(TIMEOUT, || async { + // continue minting another block to make sure the autopilot eventually + // refreshes its cache + onchain.mint_block().await; services.get_auction().await.auction.orders.len() == 2 }) .await @@ -236,8 +256,10 @@ async fn order_cancellation(web3: Web3) { // Cancel the other two. cancel_orders(vec![order_uids[1], order_uids[2]]).await; - onchain.mint_block().await; wait_for_condition(TIMEOUT, || async { + // continue minting another block to make sure the autopilot eventually + // refreshes its cache + onchain.mint_block().await; services.get_auction().await.auction.orders.is_empty() }) .await diff --git a/crates/e2e/tests/e2e/order_simulation.rs b/crates/e2e/tests/e2e/order_simulation.rs new file mode 100644 index 0000000000..1217ed2d69 --- /dev/null +++ b/crates/e2e/tests/e2e/order_simulation.rs @@ -0,0 +1,425 @@ +use { + alloy::{ + primitives::{Address, ruint::aliases::U256}, + providers::Provider, + }, + configs::test_util::TestDefault, + e2e::setup::{API_HOST, OnchainComponents, Services, TIMEOUT, run_test, wait_for_condition}, + ethrpc::{Web3, alloy::CallBuilderExt}, + model::{ + order::{ + BuyTokenDestination, + OrderCreation, + OrderCreationAppData, + OrderKind, + SellTokenSource, + }, + signature::EcdsaSigningScheme, + }, + number::units::EthUnit, + orderbook::dto::OrderSimulationResult, + reqwest::StatusCode, + simulator::tenderly::dto::SimulationType, +}; + +#[tokio::test] +#[ignore] +async fn local_node_order_simulation() { + run_test(order_simulation).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_custom_order_simulation() { + run_test(custom_order_simulation).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_order_simulation_partial_fill() { + run_test(order_simulation_partial_fill).await; +} + +async fn custom_order_simulation(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + configs::autopilot::Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + + let client = services.client(); + let valid_to = model::time::now_in_epoch_seconds() + 100; + + let sell_amount = 1u64.eth(); + let app_data = "{}"; + + // Sign an OrderCreation with the same fields the simulation will encode. + // simulate_custom_order hashes `app_data` with keccak256; OrderCreation::Full + // does the same, so the signature covers exactly the same OrderData hash. + let signed = OrderCreation { + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), + sell_amount, + buy_amount: 1u64.eth(), + kind: OrderKind::Sell, + receiver: Some(Address::default()), + sell_token_balance: SellTokenSource::Erc20, + buy_token_balance: BuyTokenDestination::Erc20, + fee_amount: U256::ZERO, + valid_to, + app_data: OrderCreationAppData::Full { + full: app_data.to_string(), + }, + partially_fillable: false, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let request = orderbook::dto::OrderSimulationRequest { + sell_token: signed.sell_token, + buy_token: signed.buy_token, + sell_amount: signed.sell_amount.try_into().unwrap(), + buy_amount: signed.buy_amount, + kind: signed.kind, + owner: trader.address(), + receiver: signed.receiver, + sell_token_balance: signed.sell_token_balance, + buy_token_balance: signed.buy_token_balance, + app_data: app_data.to_string(), + block_number: None, + signature: signed.signature, + fee_amount: signed.fee_amount, + valid_to: signed.valid_to, + partially_fillable: signed.partially_fillable, + }; + + // Trader has no sell tokens — simulation should revert. + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .json(&request) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + let result = response.json::().await.unwrap(); + assert!( + result.error.is_some(), + "expected simulation error when trader has no funds" + ); + assert!(result.error.unwrap().contains("reverted")); + + // Fund the trader and approve the vault relayer. + token.mint(trader.address(), sell_amount).await; + token + .approve(onchain.contracts().allowance, sell_amount) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + // Simulation should now succeed. + let response = client + .post(format!("{API_HOST}/restricted/api/v1/debug/simulation")) + .json(&request) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + let result = response.json::().await.unwrap(); + assert!( + result.error.is_none(), + "expected simulation to pass after funding the trader" + ); +} + +async fn order_simulation(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + // Fund trader so the order passes balance validation at submission time. + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(3u64.eth()) + .send_and_watch() + .await + .unwrap(); + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + configs::autopilot::Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), + solver, + ) + .await; + + let order = OrderCreation { + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Buy, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + let uid = services.create_order(&order).await.unwrap(); + + // Transfer all WETH away from the trader — now they have no sell-token + // balance. The current block becomes the "no funds" snapshot. + let burn = Address::from([0x42u8; 20]); + onchain + .contracts() + .weth + .transfer(burn, 3u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + let block_no_funds = web3.provider.get_block_number().await.unwrap(); + + // Re-deposit WETH. The current block now has the trader fully funded again. + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(3u64.eth()) + .send_and_watch() + .await + .unwrap(); + let block_with_funds = web3.provider.get_block_number().await.unwrap(); + + let client = services.client(); + + // Simulation at the block where the trader had no WETH must fail. + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/{uid}?block_number={block_no_funds}" + )) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + let result = response.json::().await.unwrap(); + assert!( + result.error.is_some(), + "expected simulation failure at block {block_no_funds} (no funds), got success" + ); + assert!(result.error.unwrap().contains("reverted")); + + // Simulation at the block where the trader has WETH must succeed. + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/{uid}?block_number={block_with_funds}" + )) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + let result = response.json::().await.unwrap(); + assert_eq!( + result.error, None, + "expected simulation success at block {block_with_funds} (funded), got error: {:?}", + result.error + ); + + // Simulation at the latest block (block_number parameter omitted), must + // succeed. + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/{uid}" + )) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + let result = response.json::().await.unwrap(); + assert_eq!( + result.error, None, + "expected simulation success at block {block_with_funds} (funded), got error: {:?}", + result.error + ); + + let tenderly = result.tenderly_request; + // check if the fields that are directly derived from the simulation have + // correct values in the tenderly request object + assert_eq!(tenderly.to, *onchain.contracts().gp_settlement.address()); + assert_eq!(tenderly.simulation_type, Some(SimulationType::Full)); + assert_eq!(tenderly.value, None); +} + +// Uses a shallow pool to force a partial fill (same setup as partial_fill.rs). +// The test verifies two things: +// +// 1. Before any on-chain fill: filledAmount=0, full 4 WETH needed; trader only +// has 1 WETH → simulation must fail. +// +// 2. After ~2 WETH is settled on-chain (pool depth limits the fill): the +// simulator reads filledAmount from the settlement contract and only +// simulates the ~2 WETH remaining. Trader holds ~2 WETH, so simulation must +// pass. If the simulator did NOT read on-chain state it would try to +// simulate the full 4 WETH and revert (trader only has ~2 WETH). +async fn order_simulation_partial_fill(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + // Shallow pool forces the solver to only partially fill the order + // (same pool size as partial_fill.rs). + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(10u64.eth(), 10u64.eth()) + .await; + + // Fund with 4 WETH so the order passes balance validation on submission. + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(4u64.eth()) + .send_and_watch() + .await + .unwrap(); + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 4u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services.start_protocol(solver.clone()).await; + + // Same order as partial_fill.rs: pool can only fill ~2 WETH at this price. + let order = OrderCreation { + sell_token: *onchain.contracts().weth.address(), + sell_amount: 4u64.eth(), + buy_token: *token.address(), + buy_amount: 3u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + partially_fillable: true, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + let uid = services.create_order(&order).await.unwrap(); + + // Before any block is minted the autopilot has not yet processed the order. + // Burn 3 WETH so the trader holds only 1 WETH; filledAmount is still 0. + let burn = Address::from([0x42u8; 20]); + onchain + .contracts() + .weth + .transfer(burn, 3u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let client = services.client(); + + // filledAmount=0 on-chain; full 4 WETH needed; trader only has 1 → must fail. + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/{uid}" + )) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + let result = response.json::().await.unwrap(); + assert!( + result.error.is_some(), + "expected simulation failure: filledAmount=0 so full 4 WETH is needed, but trader has 1" + ); + assert!(result.error.unwrap().contains("reverted")); + + // Restore 4 WETH so the solver can actually execute the partial fill. + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(3u64.eth()) + .send_and_watch() + .await + .unwrap(); + + // Trigger the autopilot to pick up the order and settle a partial fill. + onchain.mint_block().await; + + let trade_happened = || async { + !token + .balanceOf(trader.address()) + .call() + .await + .unwrap() + .is_zero() + }; + wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); + + // Simulation must pass. After the ~2 WETH partial fill: + // - filledAmount ≈ 2 WETH on-chain + // - remaining sell ≈ 2 WETH + // - trader WETH balance ≈ 2 WETH (started with 4, ~2 sold) + // Without reading on-chain fill state the simulator would need the full + // 4 WETH from the trader (who only holds ~2) and revert. + let response = client + .get(format!( + "{API_HOST}/restricted/api/v1/debug/simulation/{uid}" + )) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); + let result = response.json::().await.unwrap(); + + assert_eq!( + result.error, None, + "expected simulation success after partial fill (on-chain filledAmount reduces the \ + simulated sell amount to match trader balance), got error: {:?}", + result.error + ); +} diff --git a/crates/e2e/tests/e2e/parallel_settlement.rs b/crates/e2e/tests/e2e/parallel_settlement.rs new file mode 100644 index 0000000000..42d1a96d41 --- /dev/null +++ b/crates/e2e/tests/e2e/parallel_settlement.rs @@ -0,0 +1,360 @@ +use { + ::alloy::{ + consensus::Transaction as _, + primitives::{Address, Bytes, U256}, + providers::{Provider, ext::TxPoolApi}, + sol_types::SolConstructor, + }, + contracts::Solver7702Delegate::Solver7702Delegate, + driver::infra::solver::eip7702::{DELEGATION_PREFIX, MAX_APPROVED_CALLERS, delegate_address}, + e2e::setup::{colocation, *}, + ethrpc::{ + Web3, + alloy::{CallBuilderExt, EvmProviderExt}, + }, + model::{ + order::{OrderCreation, OrderKind}, + signature::EcdsaSigningScheme, + }, + number::units::EthUnit, + std::time::Duration, +}; + +/// Tests that the driver can process two settlement requests concurrently, +/// resulting in both settlement transactions being pending in the mempool +/// simultaneously. +/// +/// Bypasses the autopilot (which settles one solution per auction) and sends +/// two /solve + /settle requests directly to the driver. +/// +/// Uses EIP-7702 delegation: the driver deploys Solver7702Delegate for the +/// submission accounts and delegates the solver EOA to it. Two submission +/// accounts send settlement txs through the solver EOA in parallel, each using +/// their own nonce. +#[tokio::test] +#[ignore] +async fn local_node_parallel_settlement_submission() { + run_test(test_parallel_settlement_submission).await; +} + +async fn test_parallel_settlement_submission(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + // Two submission accounts for parallel settlement via EIP-7702. + let [submitter_a, submitter_b] = onchain.make_accounts(10u64.eth()).await; + + // Deploy two independent token pairs so settlements don't conflict on the + // same Uniswap pool when mined in the same block. + let [token_a, token_b] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + // Fund trader with WETH and approve the vault relayer. + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(5u64.eth()) + .send_and_watch() + .await + .unwrap(); + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 5u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + // Start driver + baseline solver. Each /solve call is a separate auction + // so solutions are independent regardless of merge_solutions. + let mut solver_engine = colocation::start_baseline_solver( + "test_solver".into(), + solver.clone(), + *onchain.contracts().weth.address(), + vec![], + 1, + false, + ) + .await; + solver_engine.submission_keys = vec![submitter_a.clone(), submitter_b.clone()]; + + colocation::start_driver( + onchain.contracts(), + vec![solver_engine], + colocation::LiquidityProvider::UniswapV2, + false, + ); + + // Wait for the driver to become available. + let driver_url = "http://localhost:11088/test_solver"; + wait_for_condition(TIMEOUT, || async { + reqwest::get(format!("{driver_url}/healthz")).await.is_ok() + }) + .await + .expect("driver did not start in time"); + assert_solver_delegates_to_expected_contract( + &web3, + solver.address(), + [submitter_a.address(), submitter_b.address()], + ) + .await; + + let valid_to = model::time::now_in_epoch_seconds() + 300; + let make_buy_order = |buy_token: Address| { + OrderCreation { + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token, + buy_amount: 1u64.eth(), + valid_to, + kind: OrderKind::Buy, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ) + }; + let order_a = make_buy_order(*token_a.address()); + let order_b = make_buy_order(*token_b.address()); + + onchain.mint_block().await; + + let block_number = web3.provider.get_block_number().await.unwrap(); + let http = reqwest::Client::builder() + .timeout(Duration::from_secs(30)) + .build() + .unwrap(); + + // Send /solve for each order as a separate auction. The driver caches + // the resulting settlement for each, keyed by (auction_id, solution_id). + let solution_id_a = + solve_order(&http, driver_url, 1, &order_a, trader.address(), &onchain).await; + let solution_id_b = + solve_order(&http, driver_url, 2, &order_b, trader.address(), &onchain).await; + + // Disable automine so settlement txs stay pending in the mempool. + web3.provider + .evm_set_automine(false) + .await + .expect("Must be able to disable automine"); + + // Send both /settle requests concurrently. With parallel submission, both + // submission accounts send txs to the solver EOA simultaneously. + let submission_deadline = block_number + 100; + let settle_url = format!("{driver_url}/settle"); + let spawn_settle = |auction_id: &'static str, solution_id: u64| { + let http = http.clone(); + let settle_url = settle_url.clone(); + tokio::spawn(async move { + http.post(&settle_url) + .json(&serde_json::json!({ + "solutionId": solution_id, + "submissionDeadlineLatestBlock": submission_deadline, + "auctionId": auction_id + })) + .send() + .await + }) + }; + let settle_a = spawn_settle("1", solution_id_a); + let settle_b = spawn_settle("2", solution_id_b); + + // Assert that TWO settlement txs are pending simultaneously: one direct + // (solver EOA → settlement contract) and one delegated (submission EOA → + // solver EOA via EIP-7702 delegation). The driver uses the direct slot + // when no settlement is in flight (cheaper), and falls back to 7702 for + // concurrent submissions. + let solver_address = solver.address(); + let settlement_address = *onchain.contracts().gp_settlement.address(); + let parallel_txs_observed = wait_for_condition(Duration::from_secs(15), || { + let web3 = web3.clone(); + async move { + let txpool = web3 + .provider + .txpool_content() + .await + .expect("must be able to inspect mempool"); + let pending: Vec<_> = txpool + .pending + .values() + .flat_map(|nonce_map| nonce_map.values()) + .collect(); + + let direct = pending + .iter() + .filter(|tx| tx.inner.to() == Some(settlement_address)) + .count(); + let delegated = pending + .iter() + .filter(|tx| tx.inner.to() == Some(solver_address)) + .count(); + + tracing::debug!(direct, delegated, "checking for parallel pending txs"); + direct == 1 && delegated == 1 + } + }) + .await; + + assert!( + parallel_txs_observed.is_ok(), + "Expected one direct settlement tx (to settlement contract) and one delegated tx (to \ + solver EOA via EIP-7702) pending simultaneously." + ); + + // Re-enable automine and verify both orders get settled. + web3.provider + .evm_set_automine(true) + .await + .expect("Must be able to enable automine"); + + // Wait for the /settle HTTP calls to complete (they block until mined). + assert_settle_success(settle_a.await, "1").await; + assert_settle_success(settle_b.await, "2").await; + + for token in [&token_a, &token_b] { + wait_for_condition(TIMEOUT, || async { + let balance = token.balanceOf(trader.address()).call().await.unwrap(); + balance > U256::ZERO + }) + .await + .unwrap(); + } +} + +async fn assert_solver_delegates_to_expected_contract( + web3: &Web3, + solver: Address, + callers: [Address; 2], +) { + let delegate = solver_delegate_address(callers); + let delegate_code = web3.provider.get_code_at(delegate).await.unwrap(); + assert!( + !delegate_code.is_empty(), + "delegate contract was not deployed" + ); + + let solver_code = web3.provider.get_code_at(solver).await.unwrap(); + let mut expected_solver_code = Vec::from(DELEGATION_PREFIX); + expected_solver_code.extend_from_slice(delegate.as_slice()); + assert_eq!( + solver_code.as_ref(), + expected_solver_code, + "solver EOA does not delegate to expected Solver7702Delegate" + ); +} + +fn solver_delegate_address(callers: [Address; 2]) -> Address { + let mut approved_callers = [Address::ZERO; MAX_APPROVED_CALLERS]; + approved_callers[..callers.len()].copy_from_slice(&callers); + let init_code = Solver7702Delegate::BYTECODE + .iter() + .chain(&SolConstructor::abi_encode( + &Solver7702Delegate::constructorCall { + approvedCallers: approved_callers, + }, + )) + .copied() + .collect::(); + + let local = delegate_address(&callers).unwrap(); + assert_eq!( + local, + driver::infra::solver::eip7702::CREATE2_DEPLOYER + .create2_from_code(driver::infra::solver::eip7702::CREATE2_SALT, &init_code) + ); + local +} + +/// Sends a /solve request to the driver for a single order and returns the +/// solution_id from the response. +async fn solve_order( + http: &reqwest::Client, + driver_url: &str, + auction_id: i64, + order: &OrderCreation, + owner: Address, + onchain: &OnchainComponents, +) -> u64 { + let weth = onchain.contracts().weth.address(); + let uid = order + .data() + .uid(&onchain.contracts().domain_separator, owner); + let sig_bytes = order.signature.to_bytes(); + let deadline = (chrono::Utc::now() + chrono::Duration::seconds(3)).to_rfc3339(); + + let response = http + .post(format!("{driver_url}/solve")) + .header("X-Auction-Id", auction_id.to_string()) + .json(&serde_json::json!({ + "id": auction_id.to_string(), + "tokens": [ + {"address": format!("{weth:?}"), "price": "1000000000000000000", "trusted": true}, + {"address": format!("{:?}", order.buy_token), "price": "1000000000000000000", "trusted": false}, + ], + "orders": [{ + "uid": format!("{uid}"), + "sellToken": format!("{:?}", order.sell_token), + "buyToken": format!("{:?}", order.buy_token), + "sellAmount": order.sell_amount.to_string(), + "buyAmount": order.buy_amount.to_string(), + "protocolFees": [], + "created": model::time::now_in_epoch_seconds(), + "validTo": order.valid_to, + "kind": "buy", + "receiver": null, + "owner": format!("{owner:?}"), + "partiallyFillable": false, + "executed": "0", + "preInteractions": [], + "postInteractions": [], + "class": "market", + "appData": format!("0x{}", const_hex::encode([0u8; 32])), + "signingScheme": "eip712", + "signature": format!("0x{}", const_hex::encode(&sig_bytes)), + }], + "deadline": deadline, + })) + .send() + .await + .expect("failed to send /solve request"); + + let status = response.status(); + let text = response + .text() + .await + .expect("failed to read /solve response"); + assert!(status.is_success(), "/solve failed ({status}): {text}"); + + let body: serde_json::Value = serde_json::from_str(&text).expect("invalid JSON from /solve"); + + let solution_id = body["solutions"][0]["solutionId"] + .as_u64() + .unwrap_or_else(|| panic!("no solutionId in /solve response: {text}")); + + tracing::info!(auction_id, solution_id, "solve succeeded"); + solution_id +} + +async fn assert_settle_success( + settle_result: Result, tokio::task::JoinError>, + auction_id: &str, +) { + let response = settle_result + .unwrap_or_else(|err| panic!("/settle task for auction {auction_id} panicked: {err}")) + .unwrap_or_else(|err| panic!("/settle request for auction {auction_id} failed: {err}")); + let status = response.status(); + let body = response.text().await.unwrap_or_else(|err| { + panic!("failed to read /settle response for auction {auction_id}: {err}") + }); + assert!( + status.is_success(), + "/settle failed for auction {auction_id} ({status}): {body}" + ); +} diff --git a/crates/e2e/tests/e2e/partial_fill.rs b/crates/e2e/tests/e2e/partial_fill.rs index 5779dce5df..7da2b5c875 100644 --- a/crates/e2e/tests/e2e/partial_fill.rs +++ b/crates/e2e/tests/e2e/partial_fill.rs @@ -1,18 +1,14 @@ use { ::alloy::primitives::U256, e2e::setup::*, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::{EcdsaSigningScheme, Signature, SigningScheme}, }, + number::units::EthUnit, orderbook::dto::order::Status, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + shared::web3::Web3, }; #[tokio::test] @@ -25,18 +21,18 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; // Use a shallow pool to make partial fills easier to setup. let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(10), to_wei(10)) + .deploy_tokens_with_weth_uni_v2_pools(10u64.eth(), 10u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(4)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 4u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -44,8 +40,8 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(4)) + .from(trader.address()) + .value(4u64.eth()) .send_and_watch() .await .unwrap(); @@ -55,17 +51,13 @@ async fn test(web3: Web3) { services.start_protocol(solver.clone()).await; tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { - sell_token: onchain.contracts().weth.address().into_legacy(), - sell_amount: to_wei(4), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(3), + sell_token: *onchain.contracts().weth.address(), + sell_amount: 4u64.eth(), + buy_token: *token.address(), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, partially_fillable: true, kind: OrderKind::Sell, @@ -75,7 +67,7 @@ async fn test(web3: Web3) { .sign( EcdsaSigningScheme::EthSign, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let uid = services.create_order(&order).await.unwrap(); @@ -83,12 +75,12 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); let trade_happened = || async { - token - .balanceOf(trader.address().into_alloy()) + !token + .balanceOf(trader.address()) .call() .await .unwrap() - != U256::ZERO + .is_zero() }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); @@ -96,7 +88,7 @@ async fn test(web3: Web3) { let sell_balance = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -105,11 +97,7 @@ async fn test(web3: Web3) { (1_999_000_000_000_000_000_u128..2_000_000_000_000_000_000_u128) .contains(&u128::try_from(sell_balance).unwrap()) ); - let buy_balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let buy_balance = token.balanceOf(trader.address()).call().await.unwrap(); assert!( (1_650_000_000_000_000_000_u128..1_670_000_000_000_000_000_u128) .contains(&u128::try_from(buy_balance).unwrap()) @@ -118,17 +106,14 @@ async fn test(web3: Web3) { let settlement_event_processed = || async { onchain.mint_block().await; let order = services.get_order(&uid).await.unwrap(); - order.metadata.executed_fee > U256::ZERO.into_legacy() + order.metadata.executed_fee > U256::ZERO }; wait_for_condition(TIMEOUT, settlement_event_processed) .await .unwrap(); let tx_hash = services.get_trades(&uid).await.unwrap()[0].tx_hash.unwrap(); - let competition = services - .get_solver_competition(tx_hash.into_legacy()) - .await - .unwrap(); + let competition = services.get_solver_competition(tx_hash).await.unwrap(); assert!(!competition.solutions.is_empty()); assert!(competition.auction.orders.contains(&uid)); let latest_competition = services.get_latest_solver_competition().await.unwrap(); diff --git a/crates/e2e/tests/e2e/partially_fillable_balance.rs b/crates/e2e/tests/e2e/partially_fillable_balance.rs index f8148a3b69..520ba5d8fd 100644 --- a/crates/e2e/tests/e2e/partially_fillable_balance.rs +++ b/crates/e2e/tests/e2e/partially_fillable_balance.rs @@ -1,17 +1,13 @@ use { ::alloy::primitives::U256, - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -23,35 +19,41 @@ async fn local_node_partially_fillable_balance() { async fn test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(10_000), to_wei(10_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token_a.mint(trader_a.address(), to_wei(50)).await; - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(trader_a.address(), 50u64.eth()).await; + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -61,21 +63,21 @@ async fn test(web3: Web3) { .addLiquidity( *token_a.address(), *token_b.address(), - eth(1000), - eth(1000), + 1000u64.eth(), + 1000u64.eth(), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(500)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 500u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -84,10 +86,10 @@ async fn test(web3: Web3) { services.start_protocol(solver).await; let order_a = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(100), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(50), + sell_token: *token_a.address(), + sell_amount: 100u64.eth(), + buy_token: *token_b.address(), + buy_amount: 50u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: true, @@ -96,7 +98,7 @@ async fn test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); let order_uid = services.create_order(&order_a).await.unwrap(); onchain.mint_block().await; @@ -106,11 +108,7 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); !balance.is_zero() }) .await @@ -118,18 +116,10 @@ async fn test(web3: Web3) { // Expecting a partial fill because order sells 100 but user only has balance of // 50. - let sell_balance = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_balance = token_a.balanceOf(trader_a.address()).call().await.unwrap(); // Depending on how the solver works might not have sold all balance. assert!(U256::ZERO <= sell_balance && sell_balance < U256::from(10u64.pow(18))); - let buy_balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let buy_balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); // We don't know exact buy balance because of the fee. assert!( U256::from(45) * U256::from(10u64.pow(18)) <= buy_balance diff --git a/crates/e2e/tests/e2e/partially_fillable_pool.rs b/crates/e2e/tests/e2e/partially_fillable_pool.rs index 6d39aee755..84e5c8a7ab 100644 --- a/crates/e2e/tests/e2e/partially_fillable_pool.rs +++ b/crates/e2e/tests/e2e/partially_fillable_pool.rs @@ -1,17 +1,13 @@ use { ::alloy::primitives::U256, - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] #[ignore] @@ -22,35 +18,41 @@ async fn local_node_partially_fillable_pool() { async fn test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token_a.mint(trader_a.address(), to_wei(500)).await; - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(trader_a.address(), 500u64.eth()).await; + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -60,21 +62,21 @@ async fn test(web3: Web3) { .addLiquidity( *token_a.address(), *token_b.address(), - eth(1000), - eth(1000), + 1000u64.eth(), + 1000u64.eth(), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(500)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 500u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -84,10 +86,10 @@ async fn test(web3: Web3) { onchain.mint_block().await; let order_a = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(500), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(390), + sell_token: *token_a.address(), + sell_amount: 500u64.eth(), + buy_token: *token_b.address(), + buy_amount: 390u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: true, @@ -96,7 +98,7 @@ async fn test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); let uid = services.create_order(&order_a).await.unwrap(); let order = services.get_order(&uid).await.unwrap(); @@ -105,11 +107,7 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); onchain.mint_block().await; !balance.is_zero() }) @@ -117,21 +115,13 @@ async fn test(web3: Web3) { .unwrap(); // Expecting a partial fill because the pool cannot trade the full amount. - let sell_balance = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_balance = token_a.balanceOf(trader_a.address()).call().await.unwrap(); assert!( // Sell balance is strictly less than 250.0 because of the fee. (249_999_000_000_000_000_000_u128..250_000_000_000_000_000_000_u128) .contains(&u128::try_from(sell_balance).unwrap()) ); - let buy_balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let buy_balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); assert!( (199_000_000_000_000_000_000_u128..201_000_000_000_000_000_000_u128) .contains(&u128::try_from(buy_balance).unwrap()) diff --git a/crates/e2e/tests/e2e/place_order_with_quote.rs b/crates/e2e/tests/e2e/place_order_with_quote.rs index ab8ad8ade6..b62b6d6591 100644 --- a/crates/e2e/tests/e2e/place_order_with_quote.rs +++ b/crates/e2e/tests/e2e/place_order_with_quote.rs @@ -1,42 +1,56 @@ use { ::alloy::primitives::U256, - driver::domain::eth::NonZeroU256, - e2e::{nodes::local_node::TestNodeApi, setup::*}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + autopilot::shutdown_controller::ShutdownController, + configs::{ + autopilot::Configuration, + order_quoting::{ExternalSolver, OrderQuoting}, + shared::SharedConfig, + test_util::TestDefault, }, + e2e::setup::{colocation, wait_for_condition, *}, + ethrpc::alloy::{CallBuilderExt, EvmProviderExt}, model::{ - order::{OrderCreation, OrderKind}, + order::{BUY_ETH_ADDRESS, OrderCreation, OrderKind}, quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, + number::{nonzero::NonZeroU256, units::EthUnit}, + shared::web3::Web3, std::ops::DerefMut, - web3::signing::SecretKeyRef, }; #[tokio::test] #[ignore] -async fn local_node_test() { +async fn local_node_place_order_with_quote_basic() { run_test(place_order_with_quote).await; } +#[tokio::test] +#[ignore] +async fn local_node_disabled_same_sell_and_buy_token_order_feature() { + run_test(disabled_same_sell_and_buy_token_order_feature).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_fallback_native_price_estimator() { + run_test(fallback_native_price_estimator).await; +} + async fn place_order_with_quote(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -44,8 +58,8 @@ async fn place_order_with_quote(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(3)) + .from(trader.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); @@ -55,17 +69,17 @@ async fn place_order_with_quote(web3: Web3) { services.start_protocol(solver.clone()).await; // Disable auto-mine so we don't accidentally mine a settlement - web3.api::>() - .set_automine_enabled(false) + web3.provider + .evm_set_automine(false) .await .expect("Must be able to disable automine"); tracing::info!("Quoting"); - let quote_sell_amount = to_wei(1); + let quote_sell_amount = 1u64.eth(); let quote_request = OrderQuoteRequest { from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(quote_sell_amount).unwrap(), @@ -84,17 +98,13 @@ async fn place_order_with_quote(web3: Web3) { tracing::debug!(?quote_metadata); tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { quote_id: quote_response.id, - sell_token: onchain.contracts().weth.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), sell_amount: quote_sell_amount, - buy_token: token.address().into_legacy(), + buy_token: *token.address(), buy_amount: quote_response.quote.buy_amount, valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, @@ -103,7 +113,7 @@ async fn place_order_with_quote(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let order_uid = services.create_order(&order).await.unwrap(); @@ -118,3 +128,248 @@ async fn place_order_with_quote(web3: Web3) { assert_eq!(quote_response.verified, order_quote.verified); assert_eq!(quote_metadata.unwrap().0, order_quote.metadata); } + +async fn disabled_same_sell_and_buy_token_order_feature(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + token.mint(trader.address(), 10u64.eth()).await; + + token + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + services.start_protocol(solver.clone()).await; + + // Disable auto-mine so we don't accidentally mine a settlement + web3.provider + .evm_set_automine(false) + .await + .expect("Must be able to disable automine"); + + tracing::info!("Quoting same sell and buy token pair"); + let quote_sell_amount = 1u64.eth(); + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: *token.address(), + buy_token: *token.address(), + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(quote_sell_amount).unwrap(), + }, + }, + ..Default::default() + }; + let Err((status, response)) = services.submit_quote("e_request).await else { + panic!("expected error response"); + }; + assert_eq!(status, reqwest::StatusCode::BAD_REQUEST); + assert!(response.contains("SameBuyAndSellToken")); + + tracing::info!("Quoting selling same sell and buy token pair of native token"); + let quote_sell_amount = 1u64.eth(); + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: *onchain.contracts().weth.address(), + buy_token: BUY_ETH_ADDRESS, + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(quote_sell_amount).unwrap(), + }, + }, + ..Default::default() + }; + let Err((status, response)) = services.submit_quote("e_request).await else { + panic!("expected error response"); + }; + assert_eq!(status, reqwest::StatusCode::BAD_REQUEST); + assert!(response.contains("SameBuyAndSellToken")); +} + +async fn fallback_native_price_estimator(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 6u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(6u64.eth()) + .send_and_watch() + .await + .unwrap(); + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + + colocation::start_driver( + onchain.contracts(), + vec![ + colocation::start_baseline_solver( + "test_solver".into(), + solver.clone(), + *onchain.contracts().weth.address(), + vec![], + 1, + true, + ) + .await, + ], + colocation::LiquidityProvider::UniswapV2, + false, + ); + + let (manual_shutdown, control) = ShutdownController::new_manual_shutdown(); + let autopilot_handle = services + .start_autopilot_with_shutdown_controller( + None, + Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + shared: SharedConfig { + gas_estimators: vec![TestDefault::test_default()], + ..Default::default() + }, + ..Configuration::test("test_solver", solver.address()) + }, + control, + ) + .await; + + services + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_solver", + )]), + native_price_estimation: configs::orderbook::native_price::NativePriceConfig { + fallback_estimators: Some( + configs::native_price_estimators::NativePriceEstimators::new(vec![vec![ + configs::native_price_estimators::NativePriceEstimator::driver( + "test_quoter".to_string(), + "http://localhost:11088/test_solver".parse().unwrap(), + ), + ]]), + ), + shared: configs::native_price::NativePriceConfig { + cache: configs::native_price::CacheConfig { + max_age: std::time::Duration::from_secs(2), + ..Default::default() + }, + ..Default::default() + }, + ..configs::orderbook::native_price::NativePriceConfig::test_default() + }, + shared: SharedConfig { + gas_estimators: vec![TestDefault::test_default()], + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }) + .await; + + tracing::info!("Quoting with autopilot running"); + let quote_sell_amount = 1u64.eth(); + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(quote_sell_amount).unwrap(), + }, + }, + ..Default::default() + }; + let quote_response = services.submit_quote("e_request).await.unwrap(); + tracing::debug!(?quote_response); + assert!(quote_response.id.is_some()); + + tracing::info!("Placing order with autopilot running"); + let order = OrderCreation { + quote_id: quote_response.id, + sell_token: *onchain.contracts().weth.address(), + sell_amount: quote_sell_amount, + buy_token: *token.address(), + buy_amount: quote_response.quote.buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + services.create_order(&order).await.unwrap(); + + tracing::info!("Shutting down autopilot"); + manual_shutdown.shutdown(); + wait_for_condition(TIMEOUT, || async { + onchain.mint_block().await; + autopilot_handle.is_finished() + }) + .await + .unwrap(); + + // Wait for native price cache to expire (max age = 2s) + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + + // The FallbackNativePriceEstimator switches to fallback after 3 consecutive + // ProtocolInternal errors from the primary (forwarder → dead autopilot). + tracing::info!("Waiting for native price fallback to activate"); + wait_for_condition(TIMEOUT, || async { + services.get_native_price(token.address()).await.is_ok() + }) + .await + .unwrap(); + + tracing::info!("Quoting after autopilot shutdown (via fallback)"); + let quote_response = services.submit_quote("e_request).await.unwrap(); + tracing::debug!(?quote_response); + assert!(quote_response.id.is_some()); + + tracing::info!("Placing order after autopilot shutdown (via fallback)"); + let order = OrderCreation { + quote_id: quote_response.id, + sell_token: *onchain.contracts().weth.address(), + sell_amount: quote_sell_amount, + buy_token: *token.address(), + buy_amount: quote_response.quote.buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + services.create_order(&order).await.unwrap(); +} diff --git a/crates/e2e/tests/e2e/pool_indexer.rs b/crates/e2e/tests/e2e/pool_indexer.rs new file mode 100644 index 0000000000..86a9c3b84c --- /dev/null +++ b/crates/e2e/tests/e2e/pool_indexer.rs @@ -0,0 +1,644 @@ +//! End-to-end check that the driver consumes pool data from `pool-indexer` +//! when `pool-indexer-url` is set. Pre-seeds the indexer checkpoint so the +//! subgraph_seeder bootstrap is skipped (Anvil has no subgraph); only the +//! live-indexing and HTTP-serving paths are exercised. + +use { + alloy::{ + primitives::{ + Address, + aliases::{I24, U24, U160}, + }, + providers::Provider, + sol, + sol_types::SolEvent, + }, + e2e::setup::{OnchainComponents, TIMEOUT, colocation, run_test, wait_for_condition}, + ethrpc::Web3, + number::units::EthUnit, + pool_indexer::config::{ + ApiConfig, + Configuration, + DatabaseConfig, + FactoryConfig, + MetricsConfig, + NetworkConfig, + NetworkName, + }, + serde::Deserialize, + sqlx::PgPool, + std::{ + future::Future, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + num::NonZeroU32, + }, +}; + +// Mock V3 factory. Bytecode compiled from the .sol source below with solc +// 0.8.30 --optimize --optimize-runs 1000000, evm-version shanghai. +// +// // SPDX-License-Identifier: GPL-3.0-or-later +// pragma solidity ^0.8.17; +// import "./MockUniswapV3Pool.sol"; +// contract MockUniswapV3Factory { +// event PoolCreated( +// address indexed token0, address indexed token1, uint24 indexed fee, +// int24 tickSpacing, address pool +// ); +// function createPool(address tokenA, address tokenB, uint24 _fee) +// external returns (address pool) +// { +// (address t0, address t1) = +// tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); +// MockUniswapV3Pool p = new MockUniswapV3Pool(t0, t1, _fee); +// pool = address(p); +// emit PoolCreated(t0, t1, _fee, int24(10), pool); +// } +// } +sol! { + #[allow(missing_docs)] + #[sol(rpc, bytecode = "0x6080604052348015600e575f5ffd5b506106dd8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063a16712951461002d575b5f5ffd5b61004061003b3660046101ab565b610069565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b5f5f5f8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16106100a65784866100a9565b85855b915091505f8282866040516100bd90610176565b73ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015262ffffff166040820152606001604051809103905ff080158015610106573d5f5f3e3d5ffd5b5060408051600a815273ffffffffffffffffffffffffffffffffffffffff808416602083015292965086935062ffffff88169280861692908716917f783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118910160405180910390a45050509392505050565b6104da806101f783390190565b803573ffffffffffffffffffffffffffffffffffffffff811681146101a6575f5ffd5b919050565b5f5f5f606084860312156101bd575f5ffd5b6101c684610183565b92506101d460208501610183565b9150604084013562ffffff811681146101eb575f5ffd5b80915050925092509256fe60e060405234801561000f575f5ffd5b506040516104da3803806104da83398101604081905261002e91610069565b6001600160a01b03928316608052911660a05262ffffff1660c0526100b4565b80516001600160a01b0381168114610064575f5ffd5b919050565b5f5f5f6060848603121561007b575f5ffd5b6100848461004e565b92506100926020850161004e565b9150604084015162ffffff811681146100a9575f5ffd5b809150509250925092565b60805160a05160c0516103fd6100dd5f395f61012c01525f61010501525f607801526103fd5ff3fe608060405234801561000f575f5ffd5b506004361061006f575f3560e01c8063ddca3f431161004d578063ddca3f4314610127578063efe27fa314610162578063f637731d14610177575f5ffd5b80630dfe1681146100735780631a686502146100c4578063d21220a714610100575b5f5ffd5b61009a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b5f546100df906fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020016100bb565b61009a7f000000000000000000000000000000000000000000000000000000000000000081565b61014e7f000000000000000000000000000000000000000000000000000000000000000081565b60405162ffffff90911681526020016100bb565b610175610170366004610312565b61018a565b005b61017561018536600461037b565b610287565b5f805482919081906101af9084906fffffffffffffffffffffffffffffffff1661039d565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508160020b8360020b8573ffffffffffffffffffffffffffffffffffffffff167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde33855f5f604051610279949392919073ffffffffffffffffffffffffffffffffffffffff9490941684526fffffffffffffffffffffffffffffffff9290921660208401526040830152606082015260800190565b60405180910390a450505050565b6040805173ffffffffffffffffffffffffffffffffffffffff831681525f60208201527f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c95910160405180910390a150565b73ffffffffffffffffffffffffffffffffffffffff811681146102f9575f5ffd5b50565b8035600281900b811461030d575f5ffd5b919050565b5f5f5f5f60808587031215610325575f5ffd5b8435610330816102d8565b935061033e602086016102fc565b925061034c604086016102fc565b915060608501356fffffffffffffffffffffffffffffffff81168114610370575f5ffd5b939692955090935050565b5f6020828403121561038b575f5ffd5b8135610396816102d8565b9392505050565b6fffffffffffffffffffffffffffffffff81811683821601908111156103ea577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000aa164736f6c634300081e000a")] + contract MockUniswapV3Factory { + event PoolCreated( + address indexed token0, + address indexed token1, + uint24 indexed fee, + int24 tickSpacing, + address pool + ); + + function createPool( + address tokenA, + address tokenB, + uint24 _fee + ) external returns (address pool); + } +} + +// Mock V3 pool. Compiled identically to the factory above. +// +// // SPDX-License-Identifier: GPL-3.0-or-later +// pragma solidity ^0.8.17; +// contract MockUniswapV3Pool { +// address public immutable token0; +// address public immutable token1; +// uint24 public immutable fee; +// uint128 public liquidity; +// event Initialize(uint160 sqrtPriceX96, int24 tick); +// event Mint( +// address sender, address indexed owner, +// int24 indexed tickLower, int24 indexed tickUpper, +// uint128 amount, uint256 amount0, uint256 amount1 +// ); +// constructor(address _token0, address _token1, uint24 _fee) { +// token0 = _token0; token1 = _token1; fee = _fee; +// } +// function initialize(uint160 sqrtPriceX96) external { +// emit Initialize(sqrtPriceX96, int24(0)); +// } +// function mockMint( +// address owner, int24 tickLower, int24 tickUpper, uint128 amount +// ) external { +// liquidity += amount; +// emit Mint(msg.sender, owner, tickLower, tickUpper, amount, 0, 0); +// } +// } +sol! { + #[allow(missing_docs)] + #[sol(rpc, bytecode = "0x60e060405234801561000f575f5ffd5b506040516104da3803806104da83398101604081905261002e91610069565b6001600160a01b03928316608052911660a05262ffffff1660c0526100b4565b80516001600160a01b0381168114610064575f5ffd5b919050565b5f5f5f6060848603121561007b575f5ffd5b6100848461004e565b92506100926020850161004e565b9150604084015162ffffff811681146100a9575f5ffd5b809150509250925092565b60805160a05160c0516103fd6100dd5f395f61012c01525f61010501525f607801526103fd5ff3fe608060405234801561000f575f5ffd5b506004361061006f575f3560e01c8063ddca3f431161004d578063ddca3f4314610127578063efe27fa314610162578063f637731d14610177575f5ffd5b80630dfe1681146100735780631a686502146100c4578063d21220a714610100575b5f5ffd5b61009a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b5f546100df906fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020016100bb565b61009a7f000000000000000000000000000000000000000000000000000000000000000081565b61014e7f000000000000000000000000000000000000000000000000000000000000000081565b60405162ffffff90911681526020016100bb565b610175610170366004610312565b61018a565b005b61017561018536600461037b565b610287565b5f805482919081906101af9084906fffffffffffffffffffffffffffffffff1661039d565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508160020b8360020b8573ffffffffffffffffffffffffffffffffffffffff167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde33855f5f604051610279949392919073ffffffffffffffffffffffffffffffffffffffff9490941684526fffffffffffffffffffffffffffffffff9290921660208401526040830152606082015260800190565b60405180910390a450505050565b6040805173ffffffffffffffffffffffffffffffffffffffff831681525f60208201527f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c95910160405180910390a150565b73ffffffffffffffffffffffffffffffffffffffff811681146102f9575f5ffd5b50565b8035600281900b811461030d575f5ffd5b919050565b5f5f5f5f60808587031215610325575f5ffd5b8435610330816102d8565b935061033e602086016102fc565b925061034c604086016102fc565b915060608501356fffffffffffffffffffffffffffffffff81168114610370575f5ffd5b939692955090935050565b5f6020828403121561038b575f5ffd5b8135610396816102d8565b9392505050565b6fffffffffffffffffffffffffffffffff81811683821601908111156103ea577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea164736f6c634300081e000a")] + contract MockUniswapV3Pool { + event Initialize(uint160 sqrtPriceX96, int24 tick); + event Mint( + address sender, + address indexed owner, + int24 indexed tickLower, + int24 indexed tickUpper, + uint128 amount, + uint256 amount0, + uint256 amount1 + ); + + function initialize(uint160 sqrtPriceX96) external; + function mockMint( + address owner, + int24 tickLower, + int24 tickUpper, + uint128 amount + ) external; + } +} + +const POOL_INDEXER_PORT: u16 = 7778; +const POOL_INDEXER_HOST: &str = "http://127.0.0.1:7778"; +const POOL_INDEXER_METRICS_PORT: u16 = 7779; +const LOCAL_DB_URL: &str = "postgresql://"; + +// sqrt(1) * 2^96 — valid starting price +const INITIAL_SQRT_PRICE: u128 = 1u128 << 96; + +// Never queried — the pre-seeded checkpoint short-circuits the seeder. +const PLACEHOLDER_SUBGRAPH_URL: &str = "http://127.0.0.1:1/never-queried"; + +/// Typed shape of `GET /api/v1/{network}/uniswap/v3/pools`. +#[derive(Deserialize)] +struct PoolsListResponse { + block_number: u64, + pools: Vec, + #[serde(default)] + next_cursor: Option, +} + +#[derive(Deserialize)] +struct PoolEntry { + id: String, +} + +/// Typed shape of `GET /api/v1/{network}/uniswap/v3/pools/{pool}/ticks`. +#[derive(Deserialize)] +struct TicksResponse { + ticks: Vec, +} + +#[derive(Deserialize)] +struct TickEntry {} + +async fn clear_pool_indexer_tables(db: &PgPool) { + sqlx::query( + "TRUNCATE uniswap_v3_ticks, uniswap_v3_pool_states, uniswap_v3_pools, \ + pool_indexer_checkpoints", + ) + .execute(db) + .await + .unwrap(); +} + +async fn seed_checkpoint(db: &PgPool, factory: Address, block: u64) { + sqlx::query( + "INSERT INTO pool_indexer_checkpoints (contract_address, block_number) + VALUES ($1, $2) + ON CONFLICT (contract_address) DO UPDATE SET block_number = EXCLUDED.block_number", + ) + .bind(factory.as_slice()) + .bind(block.cast_signed()) + .execute(db) + .await + .unwrap(); +} + +/// Spawns the pool-indexer task and waits for its `/health` endpoint to come +/// up. +async fn spawn_pool_indexer(factory: Address, metrics_port: u16) -> tokio::task::JoinHandle<()> { + let config = Configuration { + database: DatabaseConfig { + url: LOCAL_DB_URL.parse().unwrap(), + max_connections: NonZeroU32::new(5).unwrap(), + }, + network: NetworkConfig { + name: NetworkName::new("mainnet"), + chain_id: 1, + rpc_url: "http://127.0.0.1:8545".parse().unwrap(), + factories: vec![FactoryConfig { address: factory }], + chunk_size: 1000, + poll_interval_secs: 1, + use_latest: true, + subgraph_url: PLACEHOLDER_SUBGRAPH_URL.parse().unwrap(), + seed_block: None, + fetch_concurrency: 8, + prefetch_concurrency: 50, + }, + api: ApiConfig { + bind_address: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, POOL_INDEXER_PORT)), + }, + metrics: MetricsConfig { + bind_address: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, metrics_port)), + }, + }; + let handle = tokio::task::spawn(pool_indexer::run(config)); + wait_for_condition(TIMEOUT, || async { + reqwest::get(format!("{POOL_INDEXER_HOST}/health")) + .await + .is_ok_and(|r| r.status().is_success()) + }) + .await + .expect("pool-indexer API did not come up"); + handle +} + +/// Runs `body` with a freshly-started pool-indexer. The indexer is spawned +/// before the closure runs, then `abort`ed and `await`ed after — so the port +/// is fully released before this returns, and a follow-up call can re-bind it. +async fn with_pool_indexer_at(factory: Address, metrics_port: u16, body: F) -> T +where + F: FnOnce() -> Fut, + Fut: Future, +{ + let handle = spawn_pool_indexer(factory, metrics_port).await; + let result = body().await; + handle.abort(); + let _ = handle.await; + result +} + +/// Polls `/pools` until the indexer has reached `head` and surfaced at least +/// `min_pools` pools. `min_pools = 0` means "any state is fine, just check +/// block_number". +async fn wait_for_indexer(head: u64, min_pools: usize) { + wait_for_condition(TIMEOUT, || async { + let resp = reqwest::get(format!( + "{POOL_INDEXER_HOST}/api/v1/mainnet/uniswap/v3/pools" + )) + .await + .ok()?; + let body: PoolsListResponse = resp.json().await.ok()?; + Some(body.block_number >= head && body.pools.len() >= min_pools) + }) + .await + .expect("indexer did not reach target state"); +} + +/// Samples `(pool_count, sqrt_price_x96, tick, liquidity)` for a single pool. +async fn snapshot_pool_state(db: &PgPool, pool_addr: Address) -> (i64, String, i32, String) { + let pool_count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM uniswap_v3_pools") + .fetch_one(db) + .await + .unwrap(); + let (sqrt_price, tick, liquidity): (String, i32, String) = sqlx::query_as( + "SELECT sqrt_price_x96::TEXT, tick, liquidity::TEXT + FROM uniswap_v3_pool_states + WHERE pool_address = $1", + ) + .bind(pool_addr.as_slice()) + .fetch_one(db) + .await + .unwrap(); + (pool_count, sqrt_price, tick, liquidity) +} + +/// Create + initialise a single pool inside an already-deployed factory. +/// fee must be unique within the factory for token0/token1 ([1u8;20],[2u8;20]). +async fn create_pool( + factory: &MockUniswapV3Factory::MockUniswapV3FactoryInstance, + fee: u32, +) -> Address { + let provider = factory.provider(); + let token0 = Address::repeat_byte(1); + let token1 = Address::repeat_byte(2); + + factory + .createPool(token0, token1, U24::from(fee)) + .send() + .await + .unwrap() + .watch() + .await + .unwrap(); + + let block = provider.get_block_number().await.unwrap(); + let logs = provider + .get_logs( + &alloy::rpc::types::Filter::new() + .from_block(block) + .to_block(block) + .event_signature(MockUniswapV3Factory::PoolCreated::SIGNATURE_HASH), + ) + .await + .unwrap(); + let pool_addr = MockUniswapV3Factory::PoolCreated::decode_log(&logs[0].inner) + .unwrap() + .data + .pool; + + let pool = MockUniswapV3Pool::MockUniswapV3PoolInstance::new(pool_addr, provider); + + pool.initialize(U160::from(INITIAL_SQRT_PRICE)) + .send() + .await + .unwrap() + .watch() + .await + .unwrap(); + + pool.mockMint( + token0, + I24::try_from(-100i32).unwrap(), + I24::try_from(100i32).unwrap(), + 1_000_000u128, + ) + .send() + .await + .unwrap() + .watch() + .await + .unwrap(); + + pool_addr +} + +/// Deploy mock V3 contracts and set up a pool with liquidity. +async fn deploy_univ3( + web3: &Web3, +) -> ( + MockUniswapV3Factory::MockUniswapV3FactoryInstance, + Address, +) { + let provider = web3.provider.clone().erased(); + + let factory = MockUniswapV3Factory::deploy(provider.clone()) + .await + .unwrap(); + let pool_addr = create_pool(&factory, 500).await; + + (factory, pool_addr) +} + +/// Parse the `pool_indexer_api_requests` Prometheus counter for a given +/// route from the indexer's /metrics endpoint. +async fn api_requests_counter(metrics_port: u16, route: &'static str) -> u64 { + let body = reqwest::get(format!("http://127.0.0.1:{metrics_port}/metrics")) + .await + .unwrap() + .text() + .await + .unwrap(); + let needle = format!("pool_indexer_api_requests{{route=\"{route}\""); + for line in body.lines() { + if line.starts_with('#') { + continue; + } + if let Some(idx) = line.find(&needle) { + // pool_indexer_api_requests{route="...",status="200"} 3 + let after = line[idx + needle.len()..].trim(); + if let Some(value) = after.split_whitespace().last() { + return value.parse().unwrap_or(0); + } + } + } + 0 +} + +#[tokio::test] +#[ignore] +async fn local_node_pool_indexer_driver_integration() { + run_test(driver_integration).await; +} + +/// Asserts (via the indexer's own request counters) that a driver pointed at +/// `pool-indexer-url` fetched pools AND their ticks. Ticks is the stronger +/// signal — only hit after `UniswapV3PoolFetcher::new` sees a non-empty set. +async fn driver_integration(web3: Web3) { + const POOLS_ROUTE: &str = "/api/v1/{network}/uniswap/v3/pools"; + const POOLS_BY_IDS_ROUTE: &str = "/api/v1/{network}/uniswap/v3/pools/by-ids"; + const TICKS_ROUTE: &str = "/api/v1/{network}/uniswap/v3/pools/ticks"; + + let db = PgPool::connect(LOCAL_DB_URL).await.unwrap(); + clear_pool_indexer_tables(&db).await; + + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + + let (factory, pool_addr) = deploy_univ3(&web3).await; + let factory_addr = *factory.address(); + let head = web3.provider.get_block_number().await.unwrap(); + seed_checkpoint(&db, factory_addr, 0).await; + + with_pool_indexer_at(factory_addr, POOL_INDEXER_METRICS_PORT, || async { + // Without the min_pools=1 gate the driver could race against an empty + // set and skip the ticks fetch this test asserts on. + wait_for_indexer(head, 1).await; + + // Mock tokens have no real `decimals()`; backfill plausible values so + // the driver's `pools_tokens_have_decimals` filter doesn't drop them. + sqlx::query( + "UPDATE uniswap_v3_pools SET token0_decimals = 18, token1_decimals = 6 WHERE address \ + = $1", + ) + .bind(pool_addr.as_slice()) + .execute(&db) + .await + .unwrap(); + + // Baseline AFTER warm-up polling so bumps below are driver-attributable. + let baseline_pools = api_requests_counter(POOL_INDEXER_METRICS_PORT, POOLS_ROUTE).await; + let baseline_pools_by_ids = + api_requests_counter(POOL_INDEXER_METRICS_PORT, POOLS_BY_IDS_ROUTE).await; + let baseline_ticks = api_requests_counter(POOL_INDEXER_METRICS_PORT, TICKS_ROUTE).await; + + let baseline_solver = colocation::start_baseline_solver( + "test_solver".into(), + solver.clone(), + *onchain.contracts().weth.address(), + vec![], + 1, + true, + ) + .await; + + // Router address only used at settlement time; any 20-byte value works. + let config_override = format!( + r#" +[[liquidity.uniswap-v3]] +router = "0x000000000000000000000000000000000000dEaD" +indexer-config = {{ pool-indexer = {{ url = "{POOL_INDEXER_HOST}" }} }} +max-pools-to-initialize = 10 +"# + ); + let driver_handle = colocation::start_driver_with_config_override( + onchain.contracts(), + vec![baseline_solver], + colocation::LiquidityProvider::UniswapV2, + false, + Some(&config_override), + ); + + wait_for_condition(TIMEOUT, || async { + let pools = api_requests_counter(POOL_INDEXER_METRICS_PORT, POOLS_ROUTE).await; + let pools_by_ids = + api_requests_counter(POOL_INDEXER_METRICS_PORT, POOLS_BY_IDS_ROUTE).await; + let ticks = api_requests_counter(POOL_INDEXER_METRICS_PORT, TICKS_ROUTE).await; + pools > baseline_pools && pools_by_ids > baseline_pools_by_ids && ticks > baseline_ticks + }) + .await + .expect("driver did not complete pool + tick fetch from pool-indexer within timeout"); + + let count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM uniswap_v3_pools") + .fetch_one(&db) + .await + .unwrap(); + assert!(count > 0, "expected pools persisted to DB"); + + driver_handle.abort(); + }) + .await; +} + +#[tokio::test] +#[ignore] +async fn local_node_pool_indexer_checkpoint_resume() { + run_test(checkpoint_resume).await; +} + +/// Re-running the indexer over the same DB must merge into existing rows +/// (no duplicates) and leave per-pool state untouched. Asserts that pool +/// count, sqrt_price / tick / liquidity, and the checkpoint all survive a +/// stop+start. +async fn checkpoint_resume(web3: Web3) { + let db = PgPool::connect(LOCAL_DB_URL).await.unwrap(); + clear_pool_indexer_tables(&db).await; + + let (factory, pool_addr) = deploy_univ3(&web3).await; + let factory_addr = *factory.address(); + let head = web3.provider.get_block_number().await.unwrap(); + seed_checkpoint(&db, factory_addr, 0).await; + + let before = indexer_pass_snapshot(factory_addr, head, &db, pool_addr).await; + let after = indexer_pass_snapshot(factory_addr, head, &db, pool_addr).await; + assert_eq!(before, after, "indexer state changed across restart"); + + let checkpoint: i64 = sqlx::query_scalar( + "SELECT block_number FROM pool_indexer_checkpoints WHERE contract_address = $1", + ) + .bind(factory_addr.as_slice()) + .fetch_one(&db) + .await + .unwrap(); + assert!( + checkpoint as u64 >= head, + "checkpoint did not advance to head" + ); +} + +/// One full indexer lifecycle (start → wait for head → snapshot → stop). +/// Two calls in sequence over the same DB are how `checkpoint_resume` +/// proves the restart preserves state. +async fn indexer_pass_snapshot( + factory_addr: Address, + head: u64, + db: &PgPool, + pool_addr: Address, +) -> (i64, String, i32, String) { + with_pool_indexer_at(factory_addr, POOL_INDEXER_METRICS_PORT, || async { + wait_for_indexer(head, 0).await; + snapshot_pool_state(db, pool_addr).await + }) + .await +} + +#[tokio::test] +#[ignore] +async fn local_node_pool_indexer_api_errors() { + run_test(api_errors).await; +} + +/// Input-validation surface: an unparseable pool address must come back as +/// 400, a valid-but-unknown address must come back as 200 with empty ticks. +/// Lets callers distinguish "garbage input" from "no data yet". +async fn api_errors(web3: Web3) { + let db = PgPool::connect(LOCAL_DB_URL).await.unwrap(); + clear_pool_indexer_tables(&db).await; + + let (factory, _pool) = deploy_univ3(&web3).await; + let factory_addr = *factory.address(); + let head = web3.provider.get_block_number().await.unwrap(); + seed_checkpoint(&db, factory_addr, 0).await; + + with_pool_indexer_at(factory_addr, POOL_INDEXER_METRICS_PORT, || async { + wait_for_indexer(head, 0).await; + invalid_address_returns_400().await; + unknown_address_returns_empty_ticks().await; + }) + .await; +} + +async fn invalid_address_returns_400() { + let status = reqwest::get(format!( + "{POOL_INDEXER_HOST}/api/v1/mainnet/uniswap/v3/pools/not-an-address/ticks" + )) + .await + .unwrap() + .status(); + assert_eq!(u16::from(status), 400, "expected 400 for invalid address"); +} + +async fn unknown_address_returns_empty_ticks() { + let unknown = Address::repeat_byte(0xAB); + let resp: TicksResponse = reqwest::get(format!( + "{POOL_INDEXER_HOST}/api/v1/mainnet/uniswap/v3/pools/{unknown:?}/ticks" + )) + .await + .unwrap() + .json() + .await + .unwrap(); + assert!( + resp.ticks.is_empty(), + "expected empty ticks for unknown pool" + ); +} + +#[tokio::test] +#[ignore] +async fn local_node_pool_indexer_pagination() { + run_test(pagination).await; +} + +/// Cursor pagination: stepping through /pools with limit=1 must traverse +/// every pool exactly once. Three pools is the smallest set that exercises +/// a mid-stream cursor and the `next_cursor = null` terminator. +async fn pagination(web3: Web3) { + let db = PgPool::connect(LOCAL_DB_URL).await.unwrap(); + clear_pool_indexer_tables(&db).await; + + let (factory, _pool1) = deploy_univ3(&web3).await; + let _pool2 = create_pool(&factory, 3000).await; + let _pool3 = create_pool(&factory, 10000).await; + let factory_addr = *factory.address(); + let head = web3.provider.get_block_number().await.unwrap(); + seed_checkpoint(&db, factory_addr, 0).await; + + with_pool_indexer_at(factory_addr, POOL_INDEXER_METRICS_PORT, || async { + wait_for_indexer(head, 3).await; + + let mut all_ids: Vec = Vec::new(); + let mut cursor: Option = None; + loop { + let url = match &cursor { + None => format!("{POOL_INDEXER_HOST}/api/v1/mainnet/uniswap/v3/pools?limit=1"), + Some(c) => { + format!("{POOL_INDEXER_HOST}/api/v1/mainnet/uniswap/v3/pools?limit=1&after={c}") + } + }; + let resp: PoolsListResponse = reqwest::get(&url).await.unwrap().json().await.unwrap(); + if resp.pools.is_empty() { + break; + } + for p in resp.pools { + all_ids.push(p.id); + } + cursor = resp.next_cursor; + if cursor.is_none() { + break; + } + } + + let db_count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM uniswap_v3_pools") + .fetch_one(&db) + .await + .unwrap(); + assert_eq!( + i64::try_from(all_ids.len()).unwrap(), + db_count, + "paginated count doesn't match DB" + ); + assert!( + db_count >= 3, + "expected at least 3 pools to exercise pagination" + ); + let unique: std::collections::HashSet<_> = all_ids.iter().collect(); + assert_eq!( + unique.len(), + all_ids.len(), + "pagination returned duplicates" + ); + }) + .await; +} diff --git a/crates/e2e/tests/e2e/protocol_fee.rs b/crates/e2e/tests/e2e/protocol_fee.rs index 6a3e5b5005..820a604a16 100644 --- a/crates/e2e/tests/e2e/protocol_fee.rs +++ b/crates/e2e/tests/e2e/protocol_fee.rs @@ -1,15 +1,25 @@ use { - driver::domain::eth::NonZeroU256, - e2e::{ - assert_approximately_eq, - setup::{eth, fee::*, *}, - }, - ethcontract::{Address, prelude::U256}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + ::alloy::primitives::{Address, U256}, + configs::{ + autopilot::{ + Configuration, + fee_policy::{ + FeePoliciesConfig, + FeePolicy as ConfigFeePolicy, + FeePolicyKind as ConfigFeePolicyKind, + FeePolicyOrderClass as ConfigFeePolicyOrderClass, + UpcomingFeePolicies, + }, + solver::Solver, + }, + fee_factor::FeeFactor, + test_util::TestDefault, }, + e2e::{assert_approximately_eq, setup::*}, + eth_domain_types::NonZeroU256, + ethrpc::alloy::CallBuilderExt, model::{ + fee_policy::FeePolicy, order::{Order, OrderCreation, OrderCreationAppData, OrderKind}, quote::{ OrderQuote, @@ -21,11 +31,10 @@ use { }, signature::EcdsaSigningScheme, }, + number::units::EthUnit, reqwest::StatusCode, - secp256k1::SecretKey, serde_json::json, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + shared::web3::Web3, }; #[tokio::test] @@ -52,20 +61,26 @@ async fn local_node_surplus_partner_fee() { run_test(surplus_partner_fee).await; } +#[tokio::test] +#[ignore] +async fn local_node_volume_fee_overrides() { + run_test(volume_fee_overrides).await; +} + async fn combined_protocol_fees(web3: Web3) { - let limit_surplus_policy = ProtocolFee { - policy: FeePolicyKind::Surplus { - factor: 0.3, - max_volume_factor: 0.9, + let limit_surplus_policy = ConfigFeePolicy { + kind: ConfigFeePolicyKind::Surplus { + factor: 0.3.try_into().unwrap(), + max_volume_factor: 0.9.try_into().unwrap(), }, - policy_order_class: FeePolicyOrderClass::Limit, + order_class: ConfigFeePolicyOrderClass::Limit, }; - let market_price_improvement_policy = ProtocolFee { - policy: FeePolicyKind::PriceImprovement { - factor: 0.3, - max_volume_factor: 0.9, + let market_price_improvement_policy = ConfigFeePolicy { + kind: ConfigFeePolicyKind::PriceImprovement { + factor: 0.3.try_into().unwrap(), + max_volume_factor: 0.9.try_into().unwrap(), }, - policy_order_class: FeePolicyOrderClass::Market, + order_class: ConfigFeePolicyOrderClass::Market, }; let partner_fee_app_data = OrderCreationAppData::Full { full: json!({ @@ -82,14 +97,14 @@ async fn combined_protocol_fees(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(200)).await; - let [trader] = onchain.make_accounts(to_wei(200)).await; + let [solver] = onchain.make_solvers(200u64.eth()).await; + let [trader] = onchain.make_accounts(200u64.eth()).await; let [ limit_order_token, market_order_token, partner_fee_order_token, ] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(20), to_wei(20)) + .deploy_tokens_with_weth_uni_v2_pools(20u64.eth(), 20u64.eth()) .await; for token in &[ @@ -97,18 +112,24 @@ async fn combined_protocol_fees(web3: Web3) { &market_order_token, &partner_fee_order_token, ] { - token.mint(solver.address(), to_wei(1000)).await; + token.mint(solver.address(), 1000u64.eth()).await; token - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(100)) - .from(trader.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 100u64.eth(), + ) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -117,8 +138,8 @@ async fn combined_protocol_fees(web3: Web3) { onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -126,43 +147,43 @@ async fn combined_protocol_fees(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(100)) + .from(trader.address()) + .value(100u64.eth()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(200)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 200u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); - let autopilot_config = [ - ProtocolFeesConfig { - protocol_fees: vec![limit_surplus_policy, market_price_improvement_policy], - ..Default::default() - } - .into_args(), - vec!["--fee-policy-max-partner-fee=0.02".to_string()], - ] - .concat(); let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - autopilot: autopilot_config, - ..Default::default() + Configuration { + drivers: vec![Solver::test("test_solver", solver.address())], + fee_policies: FeePoliciesConfig { + policies: vec![limit_surplus_policy, market_price_improvement_policy], + max_partner_fee: 0.02.try_into().unwrap(), + ..Default::default() + }, + ..Configuration::test_no_drivers() }, + configs::orderbook::Configuration::test_default(), solver, ) .await; tracing::info!("Acquiring quotes."); let quote_valid_to = model::time::now_in_epoch_seconds() + 300; - let sell_amount = to_wei(10); + let sell_amount = 10u64.eth(); let [limit_quote_before, market_quote_before, partner_fee_quote] = futures::future::try_join_all( [ @@ -173,8 +194,8 @@ async fn combined_protocol_fees(web3: Web3) { .map(|token| { get_quote( &services, - onchain.contracts().weth.address().into_legacy(), - token.address().into_legacy(), + *onchain.contracts().weth.address(), + *token.address(), OrderKind::Sell, sell_amount, quote_valid_to, @@ -189,47 +210,47 @@ async fn combined_protocol_fees(web3: Web3) { let market_price_improvement_order = OrderCreation { sell_amount, // to make sure the order is in-market - buy_amount: market_quote_before.quote.buy_amount * 2 / 3, + buy_amount: market_quote_before.quote.buy_amount * U256::from(2) / U256::from(3), ..sell_order_from_quote(&market_quote_before) } .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let limit_surplus_order = OrderCreation { sell_amount, // to make sure the order is out-of-market - buy_amount: limit_quote_before.quote.buy_amount * 3 / 2, + buy_amount: limit_quote_before.quote.buy_amount * U256::from(3) / U256::from(2), ..sell_order_from_quote(&limit_quote_before) } .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let partner_fee_order = OrderCreation { sell_amount, // to make sure the order is out-of-market - buy_amount: partner_fee_quote.quote.buy_amount * 3 / 2, + buy_amount: (partner_fee_quote.quote.buy_amount * U256::from(3) / U256::from(2)), app_data: partner_fee_app_data.clone(), ..sell_order_from_quote(&partner_fee_quote) } .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); tracing::info!("Rebalancing AMM pools for market & limit order."); onchain - .mint_token_to_weth_uni_v2_pool(&market_order_token, to_wei(1000)) + .mint_token_to_weth_uni_v2_pool(&market_order_token, 1000u64.eth()) .await; onchain - .mint_token_to_weth_uni_v2_pool(&limit_order_token, to_wei(1000)) + .mint_token_to_weth_uni_v2_pool(&limit_order_token, 1000u64.eth()) .await; onchain - .mint_token_to_weth_uni_v2_pool(&partner_fee_order_token, to_wei(1000)) + .mint_token_to_weth_uni_v2_pool(&partner_fee_order_token, 1000u64.eth()) .await; tracing::info!("Waiting for liquidity state to update"); @@ -238,8 +259,8 @@ async fn combined_protocol_fees(web3: Web3) { onchain.mint_block().await; let new_market_order_quote = get_quote( &services, - onchain.contracts().weth.address().into_legacy(), - market_order_token.address().into_legacy(), + *onchain.contracts().weth.address(), + *market_order_token.address(), OrderKind::Sell, sell_amount, model::time::now_in_epoch_seconds() + 300, @@ -249,7 +270,8 @@ async fn combined_protocol_fees(web3: Web3) { // Only proceed with test once the quote changes significantly (2x) to avoid // progressing due to tiny fluctuations in gas price which would lead to // errors down the line. - new_market_order_quote.quote.buy_amount > market_quote_before.quote.buy_amount * 2 + new_market_order_quote.quote.buy_amount + > market_quote_before.quote.buy_amount * U256::from(2) }) .await .expect("Timeout waiting for eviction of the cached liquidity"); @@ -267,8 +289,8 @@ async fn combined_protocol_fees(web3: Web3) { .map(|token| { get_quote( &services, - onchain.contracts().weth.address().into_legacy(), - token.address().into_legacy(), + *onchain.contracts().weth.address(), + *token.address(), OrderKind::Sell, sell_amount, quote_valid_to, @@ -335,21 +357,27 @@ async fn combined_protocol_fees(web3: Web3) { .buy_amount .saturating_sub(market_quote_before.quote.buy_amount); // see `market_price_improvement_policy.factor`, which is 0.3 - assert!(market_executed_fee_in_buy_token >= market_quote_diff * 3 / 10); + assert!( + market_executed_fee_in_buy_token >= (market_quote_diff * U256::from(3) / U256::from(10)) + ); let partner_fee_order = services.get_order(&partner_fee_order_uid).await.unwrap(); let partner_fee_executed_fee_in_buy_token = fee_in_buy_token(&partner_fee_order, &partner_fee_quote_after.quote); assert!( - // see `--fee-policy-max-partner-fee` autopilot config argument, which is 0.02 - partner_fee_executed_fee_in_buy_token >= partner_fee_quote.quote.buy_amount * 2 / 100 + // see `max-partner-fee` in the `[fee-policies]` autopilot config, which is 0.02 + partner_fee_executed_fee_in_buy_token + >= (partner_fee_quote.quote.buy_amount * U256::from(2) / U256::from(100)) ); let limit_quote_diff = partner_fee_quote_after .quote .buy_amount - .saturating_sub(partner_fee_order.data.buy_amount.into_legacy()); + .saturating_sub(partner_fee_order.data.buy_amount); // see `limit_surplus_policy.factor`, which is 0.3 - assert!(partner_fee_executed_fee_in_buy_token >= limit_quote_diff * 3 / 10); + assert!( + partner_fee_executed_fee_in_buy_token + >= (limit_quote_diff * U256::from(3) / U256::from(10)) + ); let limit_surplus_order = services.get_order(&limit_surplus_order_uid).await.unwrap(); let limit_executed_fee_in_buy_token = @@ -357,9 +385,9 @@ async fn combined_protocol_fees(web3: Web3) { let limit_quote_diff = limit_quote_after .quote .buy_amount - .saturating_sub(limit_surplus_order.data.buy_amount.into_legacy()); + .saturating_sub(limit_surplus_order.data.buy_amount); // see `limit_surplus_policy.factor`, which is 0.3 - assert!(limit_executed_fee_in_buy_token >= limit_quote_diff * 3 / 10); + assert!(limit_executed_fee_in_buy_token >= (limit_quote_diff * U256::from(3) / U256::from(10))); let [ market_order_token_balance, @@ -376,31 +404,24 @@ async fn combined_protocol_fees(web3: Web3) { .balanceOf(*onchain.contracts().gp_settlement.address()) .call() .await - .map(IntoLegacy::into_legacy) }), ) .await .unwrap() .try_into() .expect("Expected exactly four elements"); + assert_approximately_eq!(market_executed_fee_in_buy_token, market_order_token_balance); + assert_approximately_eq!(limit_executed_fee_in_buy_token, limit_order_token_balance); assert_approximately_eq!( - market_executed_fee_in_buy_token.into_alloy(), - market_order_token_balance.into_alloy() - ); - assert_approximately_eq!( - limit_executed_fee_in_buy_token.into_alloy(), - limit_order_token_balance.into_alloy() - ); - assert_approximately_eq!( - partner_fee_executed_fee_in_buy_token.into_alloy(), - partner_fee_order_token_balance.into_alloy() + partner_fee_executed_fee_in_buy_token, + partner_fee_order_token_balance ); } /// Tests that a partner can provide multiple partner fees and also use /// the `Surplus` and `PriceImprovement` fee policies. Also checks that /// the partner fees can not exceed the globally defined -/// `--fee-policy-max-partner-fee` which defines how much of an order's volume +/// `max-partner-fee` config which defines how much of an order's volume /// may be captured in total by partner fees. async fn surplus_partner_fee(web3: Web3) { // All these values are unreasonably high but result in easier math @@ -438,32 +459,38 @@ async fn surplus_partner_fee(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(200)).await; - let [trader] = onchain.make_accounts(to_wei(200)).await; + let [solver] = onchain.make_solvers(200u64.eth()).await; + let [trader] = onchain.make_accounts(200u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(20), to_wei(20)) + .deploy_tokens_with_weth_uni_v2_pools(20u64.eth(), 20u64.eth()) .await; - token.mint(solver.address(), to_wei(1000)).await; + token.mint(solver.address(), 1000u64.eth()).await; token - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(100)) - .from(trader.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 100u64.eth(), + ) + .from(trader.address()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -471,16 +498,19 @@ async fn surplus_partner_fee(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(100)) + .from(trader.address()) + .value(100u64.eth()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(200)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 200u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -488,22 +518,25 @@ async fn surplus_partner_fee(web3: Web3) { let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - autopilot: vec![format!( - "--fee-policy-max-partner-fee={MAX_PARTNER_VOLUME_FEE}" - )], - ..Default::default() + Configuration { + drivers: vec![Solver::test("test_solver", solver.address())], + fee_policies: FeePoliciesConfig { + max_partner_fee: MAX_PARTNER_VOLUME_FEE.try_into().unwrap(), + ..Default::default() + }, + ..Configuration::test_no_drivers() }, + configs::orderbook::Configuration::test_default(), solver, ) .await; let order = OrderCreation { - sell_amount: to_wei(10), - sell_token: onchain.contracts().weth.address().into_legacy(), + sell_amount: 10u64.eth(), + sell_token: *onchain.contracts().weth.address(), // just set any low amount since it doesn't matter for this test - buy_amount: to_wei(1), - buy_token: token.address().into_legacy(), + buy_amount: 1u64.eth(), + buy_token: *token.address(), app_data: partner_fee_app_data.clone(), valid_to: model::time::now_in_epoch_seconds() + 300, ..Default::default() @@ -511,7 +544,7 @@ async fn surplus_partner_fee(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let order_uid = services.create_order(&order).await.unwrap(); @@ -598,11 +631,11 @@ async fn get_quote( let side = match kind { OrderKind::Sell => OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: NonZeroU256::try_from(amount.as_u128()).unwrap(), + value: NonZeroU256::try_from(amount.to::()).unwrap(), }, }, OrderKind::Buy => OrderQuoteSide::Buy { - buy_amount_after_fee: NonZeroU256::try_from(amount.as_u128()).unwrap(), + buy_amount_after_fee: NonZeroU256::try_from(amount.to::()).unwrap(), }, }; let quote_request = OrderQuoteRequest { @@ -633,64 +666,60 @@ fn sell_order_from_quote(quote: &OrderQuoteResponse) -> OrderCreation { } async fn volume_fee_buy_order_test(web3: Web3) { - let fee_policy = FeePolicyKind::Volume { factor: 0.1 }; - let outdated_fee_policy = FeePolicyKind::Volume { factor: 0.0002 }; - let protocol_fee = ProtocolFee { - policy: fee_policy, + let fee_policy = ConfigFeePolicy { + kind: ConfigFeePolicyKind::Volume { + factor: 0.1.try_into().unwrap(), + }, // The order is in-market, but specifying `Any` order class to make sure it is properly // applied - policy_order_class: FeePolicyOrderClass::Any, + order_class: ConfigFeePolicyOrderClass::Any, }; - let outdated_protocol_fee = ProtocolFee { - policy: outdated_fee_policy, - policy_order_class: FeePolicyOrderClass::Any, + let outdated_fee_policy = ConfigFeePolicy { + kind: ConfigFeePolicyKind::Volume { + factor: 0.0002.try_into().unwrap(), + }, + order_class: ConfigFeePolicyOrderClass::Any, }; - // Protocol fee set twice to test that only one policy will apply if the - // autopilot is not configured to support multiple fees - let protocol_fee_args = ProtocolFeesConfig { - protocol_fees: vec![outdated_protocol_fee.clone(), outdated_protocol_fee], - upcoming_protocol_fees: Some(UpcomingProtocolFees { - fee_policies: vec![protocol_fee.clone(), protocol_fee], - // Set the effective time to 10 minutes ago to make sure the new policy - // is applied - effective_from_timestamp: chrono::Utc::now() - chrono::Duration::minutes(10), - }), - } - .into_args(); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_gno, token_dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1000u64.eth()) .await; // Fund trader accounts - token_gno.mint(trader.address(), to_wei(100)).await; + token_gno.mint(trader.address(), 100u64.eth()).await; // Create and fund Uniswap pool - token_gno.mint(solver.address(), to_wei(1000)).await; - token_dai.mint(solver.address(), to_wei(1000)).await; + token_gno.mint(solver.address(), 1000u64.eth()).await; + token_dai.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_gno.address(), *token_dai.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_gno - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_dai - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -700,14 +729,14 @@ async fn volume_fee_buy_order_test(web3: Web3) { .addLiquidity( *token_gno.address(), *token_dai.address(), - eth(1000), - eth(1000), - ::alloy::primitives::U256::ZERO, - ::alloy::primitives::U256::ZERO, - solver.address().into_alloy(), - ::alloy::primitives::U256::MAX, + 1000u64.eth(), + 1000u64.eth(), + U256::ZERO, + U256::ZERO, + solver.address(), + U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -715,30 +744,45 @@ async fn volume_fee_buy_order_test(web3: Web3) { // Approve GPv2 for trading token_gno - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); // Place Orders + // Protocol fee set twice to test that only one policy will apply if the + // autopilot is not configured to support multiple fees let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - autopilot: protocol_fee_args, - ..Default::default() + Configuration { + drivers: vec![Solver::test("test_solver", solver.address())], + fee_policies: FeePoliciesConfig { + policies: vec![outdated_fee_policy.clone(), outdated_fee_policy], + upcoming_policies: UpcomingFeePolicies { + policies: vec![fee_policy.clone(), fee_policy], + // Set the effective time to 10 minutes ago to make sure the new policy + // is applied + effective_from_timestamp: Some( + chrono::Utc::now() - chrono::Duration::minutes(10), + ), + }, + ..Default::default() + }, + ..Configuration::test_no_drivers() }, + configs::orderbook::Configuration::test_default(), solver, ) .await; let quote = get_quote( &services, - token_gno.address().into_legacy(), - token_dai.address().into_legacy(), + *token_gno.address(), + *token_dai.address(), OrderKind::Buy, - to_wei(5), + 5u64.eth(), model::time::now_in_epoch_seconds() + 300, ) .await @@ -746,10 +790,10 @@ async fn volume_fee_buy_order_test(web3: Web3) { .quote; let order = OrderCreation { - sell_token: token_gno.address().into_legacy(), - sell_amount: quote.sell_amount * 3 / 2, - buy_token: token_dai.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_gno.address(), + sell_amount: (quote.sell_amount * U256::from(3) / U256::from(2)), + buy_token: *token_dai.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Buy, ..Default::default() @@ -757,7 +801,7 @@ async fn volume_fee_buy_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let uid = services.create_order(&order).await.unwrap(); @@ -772,77 +816,72 @@ async fn volume_fee_buy_order_test(web3: Web3) { let order = services.get_order(&uid).await.unwrap(); let fee_in_buy_token = quote.fee_amount * quote.buy_amount / quote.sell_amount; - assert!(order.metadata.executed_fee >= fee_in_buy_token + quote.sell_amount / 10); + assert!(order.metadata.executed_fee >= fee_in_buy_token + (quote.sell_amount / U256::from(10))); // Check settlement contract balance let balance_after = token_gno .balanceOf(*onchain.contracts().gp_settlement.address()) .call() .await - .unwrap() - .into_legacy(); + .unwrap(); assert_eq!(order.metadata.executed_fee, balance_after); } async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { - let fee_policy = FeePolicyKind::Volume { factor: 0.1 }; - let future_fee_policy = FeePolicyKind::Volume { factor: 0.0002 }; - let protocol_fee = ProtocolFee { - policy: fee_policy, + let fee_policy = ConfigFeePolicy { + kind: ConfigFeePolicyKind::Volume { + factor: 0.1.try_into().unwrap(), + }, // The order is in-market, but specifying `Any` order class to make sure it is properly // applied - policy_order_class: FeePolicyOrderClass::Any, + order_class: ConfigFeePolicyOrderClass::Any, }; - let future_protocol_fee = ProtocolFee { - policy: future_fee_policy, - policy_order_class: FeePolicyOrderClass::Any, + let future_fee_policy = ConfigFeePolicy { + kind: ConfigFeePolicyKind::Volume { + factor: 0.0002.try_into().unwrap(), + }, + order_class: ConfigFeePolicyOrderClass::Any, }; - // Protocol fee set twice to test that only one policy will apply if the - // autopilot is not configured to support multiple fees - let protocol_fee_args = ProtocolFeesConfig { - protocol_fees: vec![protocol_fee.clone(), protocol_fee], - upcoming_protocol_fees: Some(UpcomingProtocolFees { - fee_policies: vec![future_protocol_fee.clone(), future_protocol_fee], - // Set the effective time to far in the future to make sure the new policy - // is NOT applied - effective_from_timestamp: chrono::Utc::now() + chrono::Duration::days(1), - }), - } - .into_args(); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_gno, token_dai] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1000u64.eth()) .await; // Fund trader accounts - token_gno.mint(trader.address(), to_wei(100)).await; + token_gno.mint(trader.address(), 100u64.eth()).await; // Create and fund Uniswap pool - token_gno.mint(solver.address(), to_wei(1000)).await; - token_dai.mint(solver.address(), to_wei(1000)).await; + token_gno.mint(solver.address(), 1000u64.eth()).await; + token_dai.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_gno.address(), *token_dai.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_gno - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_dai - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -852,14 +891,14 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { .addLiquidity( *token_gno.address(), *token_dai.address(), - eth(1000), - eth(1000), - ::alloy::primitives::U256::ZERO, - ::alloy::primitives::U256::ZERO, - solver.address().into_alloy(), - ::alloy::primitives::U256::MAX, + 1000u64.eth(), + 1000u64.eth(), + U256::ZERO, + U256::ZERO, + solver.address(), + U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -867,30 +906,45 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { // Approve GPv2 for trading token_gno - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); // Place Orders + // Protocol fee set twice to test that only one policy will apply if the + // autopilot is not configured to support multiple fees let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - autopilot: protocol_fee_args, - ..Default::default() + Configuration { + drivers: vec![Solver::test("test_solver", solver.address())], + fee_policies: FeePoliciesConfig { + policies: vec![fee_policy.clone(), fee_policy], + upcoming_policies: UpcomingFeePolicies { + policies: vec![future_fee_policy.clone(), future_fee_policy], + // Set the effective time to far in the future to make sure the new policy + // is NOT applied + effective_from_timestamp: Some( + chrono::Utc::now() + chrono::Duration::days(1), + ), + }, + ..Default::default() + }, + ..Configuration::test_no_drivers() }, + configs::orderbook::Configuration::test_default(), solver, ) .await; let quote = get_quote( &services, - token_gno.address().into_legacy(), - token_dai.address().into_legacy(), + *token_gno.address(), + *token_dai.address(), OrderKind::Buy, - to_wei(5), + 5u64.eth(), model::time::now_in_epoch_seconds() + 300, ) .await @@ -898,10 +952,10 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { .quote; let order = OrderCreation { - sell_token: token_gno.address().into_legacy(), - sell_amount: quote.sell_amount * 3 / 2, - buy_token: token_dai.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_gno.address(), + sell_amount: (quote.sell_amount * U256::from(3) / U256::from(2)), + buy_token: *token_dai.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Buy, ..Default::default() @@ -909,7 +963,7 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let uid = services.create_order(&order).await.unwrap(); @@ -924,14 +978,293 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { let order = services.get_order(&uid).await.unwrap(); let fee_in_buy_token = quote.fee_amount * quote.buy_amount / quote.sell_amount; - assert!(order.metadata.executed_fee >= fee_in_buy_token + quote.sell_amount / 10); + assert!(order.metadata.executed_fee >= fee_in_buy_token + (quote.sell_amount / U256::from(10))); // Check settlement contract balance let balance_after = token_gno .balanceOf(*onchain.contracts().gp_settlement.address()) .call() .await - .unwrap() - .into_legacy(); + .unwrap(); + assert_eq!(order.metadata.executed_fee, balance_after); } + +/// Volume fees can be overriden by defining "buckets" of tokens that have +/// different vol fees than the default. If an order has both the buy and sell +/// token in a bucket its vol fees are used. We test that: +/// - Earlier buckets take precedence +/// - Token bucket overrides apply when both tokens are in the bucket +async fn volume_fee_overrides(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(200u64.eth()).await; + let [trader] = onchain.make_accounts(200u64.eth()).await; + + // Deploy tokens: USDC, DAI, USDT (stablecoins), and WETH (non-stablecoin) + let [token_usdc, token_dai, token_usdt, token_weth] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1000u64.eth(), 1000u64.eth()) + .await; + + // Fund solver and trader + for token in &[&token_usdc, &token_dai, &token_usdt, &token_weth] { + token.mint(solver.address(), 10000u64.eth()).await; + token.mint(trader.address(), 1000u64.eth()).await; + + token + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 10000u64.eth(), + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + token + .approve(onchain.contracts().allowance, 1000u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + } + + // Create liquidity pools for all token pairs + for (token_a, token_b) in [ + (&token_usdc, &token_dai), + (&token_dai, &token_usdt), + (&token_usdc, &token_weth), + ] { + onchain + .contracts() + .uniswap_v2_factory + .createPair(*token_a.address(), *token_b.address()) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + onchain + .contracts() + .uniswap_v2_router + .addLiquidity( + *token_a.address(), + *token_b.address(), + 1000u64.eth(), + 1000u64.eth(), + U256::ZERO, + U256::ZERO, + solver.address(), + U256::MAX, + ) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + } + + // Default volume fee: 1% (0.01) + let default_volume_fee = ConfigFeePolicy { + kind: ConfigFeePolicyKind::Volume { + factor: 0.01.try_into().unwrap(), + }, + order_class: ConfigFeePolicyOrderClass::Any, + }; + + // Bucket overrides (checked in order, first match wins): + // - 2-token pair: USDC-DAI has 0.05% fee (checked first, has precedence) + // - Stablecoins: USDC, DAI, USDT have 0% fee (checked second) + let volume_fee_bucket_overrides = vec![ + configs::shared::TokenBucketFeeOverride { + tokens: [*token_usdc.address(), *token_dai.address()] + .into_iter() + .collect(), + factor: FeeFactor::new(0.0005), + }, + configs::shared::TokenBucketFeeOverride { + tokens: [ + *token_usdc.address(), + *token_dai.address(), + *token_usdt.address(), + ] + .into_iter() + .collect(), + factor: FeeFactor::new(0.0), + }, + ]; + + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + Configuration { + shared: configs::shared::SharedConfig { + volume_fee_bucket_overrides: volume_fee_bucket_overrides.clone(), + ..Default::default() + }, + drivers: vec![Solver::test("test_solver", solver.address())], + fee_policies: FeePoliciesConfig { + policies: vec![default_volume_fee], + ..Default::default() + }, + ..Configuration::test_no_drivers() + }, + configs::orderbook::Configuration { + shared: configs::shared::SharedConfig { + volume_fee_bucket_overrides, + ..Default::default() + }, + volume_fee: Some(configs::orderbook::VolumeFeeConfig { + factor: Some(FeeFactor::new(0.01)), // Default 1% volume fee + effective_from_timestamp: None, + }), + ..configs::orderbook::Configuration::test_default() + }, + solver, + ) + .await; + + let sell_amount = 10u64.eth(); + let quote_valid_to = model::time::now_in_epoch_seconds() + 300; + + // Test Case 1: USDC-DAI uses first bucket (2-token bucket, 0.05%) + let usdc_dai_quote = get_quote( + &services, + *token_usdc.address(), + *token_dai.address(), + OrderKind::Sell, + sell_amount, + quote_valid_to, + ) + .await + .unwrap(); + + let usdc_dai_order = OrderCreation { + sell_amount, + buy_amount: usdc_dai_quote.quote.buy_amount * U256::from(9) / U256::from(10), + ..sell_order_from_quote(&usdc_dai_quote) + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let usdc_dai_uid = services.create_order(&usdc_dai_order).await.unwrap(); + + // Test Case 2: DAI-USDT uses stablecoin bucket (0%) + let dai_usdt_quote = get_quote( + &services, + *token_dai.address(), + *token_usdt.address(), + OrderKind::Sell, + sell_amount, + quote_valid_to, + ) + .await + .unwrap(); + + let dai_usdt_order = OrderCreation { + sell_amount, + buy_amount: dai_usdt_quote.quote.buy_amount * U256::from(9) / U256::from(10), + ..sell_order_from_quote(&dai_usdt_quote) + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let dai_usdt_uid = services.create_order(&dai_usdt_order).await.unwrap(); + + // Test Case 3: USDC-WETH uses default fee (1%) + let usdc_weth_quote = get_quote( + &services, + *token_usdc.address(), + *token_weth.address(), + OrderKind::Sell, + sell_amount, + quote_valid_to, + ) + .await + .unwrap(); + + let usdc_weth_order = OrderCreation { + sell_amount, + buy_amount: usdc_weth_quote.quote.buy_amount * U256::from(9) / U256::from(10), + ..sell_order_from_quote(&usdc_weth_quote) + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let usdc_weth_uid = services.create_order(&usdc_weth_order).await.unwrap(); + + onchain.mint_block().await; + + // Wait for all orders to trade + let metadata_updated = || async { + onchain.mint_block().await; + futures::future::join_all( + [&usdc_dai_uid, &dai_usdt_uid, &usdc_weth_uid].map(|uid| async { + services + .get_order(uid) + .await + .is_ok_and(|order| !order.metadata.executed_fee.is_zero()) + }), + ) + .await + .into_iter() + .all(std::convert::identity) + }; + wait_for_condition(TIMEOUT, metadata_updated) + .await + .expect("Timeout waiting for the orders to trade"); + + // Verify trades endpoint returns correct executedProtocolFees + let usdc_dai_trade = &services.get_trades(&usdc_dai_uid).await.unwrap()[0]; + let dai_usdt_trade = &services.get_trades(&dai_usdt_uid).await.unwrap()[0]; + let usdc_weth_trade = &services.get_trades(&usdc_weth_uid).await.unwrap()[0]; + + assert_volume_fee(usdc_dai_trade, *token_dai.address(), 0.0005, sell_amount); + assert_volume_fee(dai_usdt_trade, *token_usdt.address(), 0.0, sell_amount); + assert_volume_fee(usdc_weth_trade, *token_weth.address(), 0.01, sell_amount); +} + +fn assert_volume_fee( + trade: &model::trade::Trade, + expected_fee_token: ::alloy::primitives::Address, + expected_factor: f64, + sell_amount: U256, +) { + assert_eq!( + trade.executed_protocol_fees.len(), + 1, + "Trade should have exactly one protocol fee" + ); + let executed_fee = &trade.executed_protocol_fees[0]; + assert_eq!(executed_fee.token, expected_fee_token, "Fee token mismatch"); + match executed_fee.policy { + FeePolicy::Volume { factor } => { + assert_eq!(factor, expected_factor, "Volume fee factor mismatch"); + } + _ => panic!("Expected Volume fee policy, got {:?}", executed_fee.policy), + } + + let fee_amount = U256::from(executed_fee.amount); + if expected_factor == 0.0 { + assert!(fee_amount.is_zero(), "Fee should be zero for 0% factor"); + } else { + // Integer math for: expected_fee = sell_amount * factor + let factor_scaled = (expected_factor * 10_000.0) as u64; + let expected_fee = sell_amount * U256::from(factor_scaled) / U256::from(10_000); + + let lower = expected_fee * U256::from(98) / U256::from(100); + let upper = expected_fee * U256::from(102) / U256::from(100); + assert!( + fee_amount >= lower && fee_amount <= upper, + "Fee should be ~{expected_fee} (±2%), got {fee_amount}" + ); + } +} diff --git a/crates/e2e/tests/e2e/quote_verification.rs b/crates/e2e/tests/e2e/quote_verification.rs index a4f788d820..dbfc6a00c7 100644 --- a/crates/e2e/tests/e2e/quote_verification.rs +++ b/crates/e2e/tests/e2e/quote_verification.rs @@ -1,37 +1,17 @@ use { - ::alloy::primitives::{Address, U256, address}, - bigdecimal::{BigDecimal, Zero}, - e2e::setup::{eth, *}, - ethcontract::H160, - ethrpc::{ - Web3, - alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, - }, - model::{ - interaction::InteractionData, - order::{BuyTokenDestination, OrderKind, SellTokenSource}, - quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, + ::alloy::{ + primitives::{Address, U256, address, map::AddressMap}, + providers::Provider, + rpc::types::state::StateOverride, }, - number::nonzero::U256 as NonZeroU256, + balance_overrides::{BalanceOverrideRequest, StateOverrides, StateOverriding}, + configs::{autopilot::Configuration, test_util::TestDefault}, + contracts::ERC20, + e2e::setup::*, + ethrpc::{Web3, alloy::CallBuilderExt}, + model::quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, + number::units::EthUnit, serde_json::json, - shared::{ - addr, - price_estimation::{ - Estimate, - Verification, - trade_verifier::{ - PriceQuery, - TradeVerifier, - TradeVerifying, - balance_overrides::BalanceOverrides, - }, - }, - trade_finding::{Interaction, LegacyTrade, QuoteExecution, TradeKind}, - }, - std::{str::FromStr, sync::Arc}, }; #[tokio::test] @@ -40,18 +20,6 @@ async fn local_node_standard_verified_quote() { run_test(standard_verified_quote).await; } -#[tokio::test] -#[ignore] -async fn forked_node_bypass_verification_for_rfq_quotes() { - run_forked_test_with_block_number( - test_bypass_verification_for_rfq_quotes, - std::env::var("FORK_URL_MAINNET") - .expect("FORK_URL_MAINNET must be set to run forked tests"), - FORK_BLOCK_MAINNET, - ) - .await; -} - #[tokio::test] #[ignore] async fn local_node_verified_quote_eth_balance() { @@ -70,6 +38,12 @@ async fn local_node_verified_quote_with_simulated_balance() { run_test(verified_quote_with_simulated_balance).await; } +#[tokio::test] +#[ignore] +async fn local_node_trace_based_balance_detection() { + run_test(trace_based_balance_detection).await; +} + #[tokio::test] #[ignore] async fn forked_node_mainnet_usdt_quote() { @@ -82,22 +56,41 @@ async fn forked_node_mainnet_usdt_quote() { .await; } +/// Quote verification for an Aave v3 aToken as the sell token. +#[tokio::test] +#[ignore] +async fn forked_node_mainnet_aave_atoken_quote() { + // Fork a block that matches the solver whitelist used for the quotes we + // inspected on barn (same day as the debugging session). The default + // `FORK_BLOCK_MAINNET` is a few weeks older and can miss newly + // whitelisted solvers. + const FORK_BLOCK: u64 = 24920000; + run_forked_test_with_extra_filters_and_block_number( + aave_atoken_quote_verification, + std::env::var("FORK_URL_MAINNET") + .expect("FORK_URL_MAINNET must be set to run forked tests"), + FORK_BLOCK, + ["price_estimation=trace", "balance_overrides=trace"], + ) + .await; +} + /// Verified quotes work as expected. async fn standard_verified_quote(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token.mint(trader.address(), to_wei(1)).await; + token.mint(trader.address(), 1u64.eth()).await; token - .approve(onchain.contracts().allowance.into_alloy(), eth(1)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 1u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -110,11 +103,11 @@ async fn standard_verified_quote(web3: Web3) { let response = services .submit_quote(&OrderQuoteRequest { from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(1).try_into().unwrap(), + value: (1u64.eth()).try_into().unwrap(), }, }, ..Default::default() @@ -124,124 +117,15 @@ async fn standard_verified_quote(web3: Web3) { assert!(response.verified); } -/// The block number from which we will fetch state for the forked tests. -const FORK_BLOCK_MAINNET: u64 = 23112197; - -/// Tests that quotes requesting `tx_origin: 0x0000` bypass the verification -/// because those are currently used by some solvers to provide market maker -/// integrations. Based on an RFQ quote we saw on prod: -/// https://www.tdly.co/shared/simulation/7402de5e-e524-4e24-9af8-50d0a38c105b -async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { - // This RPC node should support websockets - let mut url: url::Url = std::env::var("FORK_URL_MAINNET") - .expect("FORK_URL_MAINNET must be set to run forked tests") - .parse() - .unwrap(); - match url.scheme() { - "http" => url.set_scheme("ws").unwrap(), - "https" => url.set_scheme("wss").unwrap(), - _ => unreachable!("unexpected scheme"), - } - let block_stream = ethrpc::block_stream::current_block_ws_stream(web3.alloy.clone(), url) - .await - .unwrap(); - let onchain = OnchainComponents::deployed(web3.clone()).await; - - let verifier = TradeVerifier::new( - web3.clone(), - None, - Arc::new(web3.clone()), - Arc::new(BalanceOverrides::default()), - block_stream, - onchain.contracts().gp_settlement.address().into_legacy(), - onchain.contracts().weth.address().into_legacy(), - BigDecimal::zero(), - Default::default(), - ) - .await - .unwrap(); - - let verify_trade = |tx_origin| { - let verifier = verifier.clone(); - async move { - verifier - .verify( - &PriceQuery { - sell_token: H160::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599") - .unwrap(), - buy_token: H160::from_str("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") - .unwrap(), - kind: OrderKind::Sell, - in_amount: NonZeroU256::new(12.into()).unwrap(), - }, - &Verification { - from: H160::from_str("0x73688c2b34bf6c09c125fed02fe92d17a94b897a").unwrap(), - receiver: H160::from_str("0x73688c2b34bf6c09c125fed02fe92d17a94b897a") - .unwrap(), - pre_interactions: vec![], - post_interactions: vec![], - sell_token_source: SellTokenSource::Erc20, - buy_token_destination: BuyTokenDestination::Erc20, - }, - TradeKind::Legacy(LegacyTrade { - out_amount: U256::from(16380122291179526144u128), - gas_estimate: Some(225000), - interactions: vec![Interaction { - target: address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - data: const_hex::decode("aa77476c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000000000000000000000000000e357b42c3a9d8ccf0000000000000000000000000000000000000000000000000000000004d0e79e000000000000000000000000a69babef1ca67a37ffaf7a485dfff3382056e78c0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066360af101ffffffffffffffffffffffffffffffffffffff0f3f47f166360a8d0000003f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000001c66b3383f287dd9c85ad90e7c5a576ea4ba1bdf5a001d794a9afa379e6b2517b47e487a1aef32e75af432cbdbd301ada42754eaeac21ec4ca744afd92732f47540000000000000000000000000000000000000000000000000000000004d0c80f").unwrap(), - value: U256::ZERO, - }], - solver: address!("0xe3067c7c27c1038de4e8ad95a83b927d23dfbd99") - , - tx_origin, - }), - ) - .await - } - }; - - let verified_quote = Estimate { - out_amount: 16380122291179526144u128.into(), - gas: 225000, - solver: H160::from_str("0xe3067c7c27c1038de4e8ad95a83b927d23dfbd99").unwrap(), - verified: true, - execution: QuoteExecution { - interactions: vec![InteractionData { - target: address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - value: ::alloy::primitives::U256::ZERO, - call_data: const_hex::decode("aa77476c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000000000000000000000000000e357b42c3a9d8ccf0000000000000000000000000000000000000000000000000000000004d0e79e000000000000000000000000a69babef1ca67a37ffaf7a485dfff3382056e78c0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066360af101ffffffffffffffffffffffffffffffffffffff0f3f47f166360a8d0000003f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000001c66b3383f287dd9c85ad90e7c5a576ea4ba1bdf5a001d794a9afa379e6b2517b47e487a1aef32e75af432cbdbd301ada42754eaeac21ec4ca744afd92732f47540000000000000000000000000000000000000000000000000000000004d0c80f").unwrap() - }], - pre_interactions: vec![], - jit_orders: vec![], - }, - }; - - // `tx_origin: 0x0000` is currently used to bypass quote verification due to an - // implementation detail of zeroex RFQ orders. - // TODO: remove with #2693 - let verification = verify_trade(Some(Address::ZERO)).await; - assert_eq!(&verification.unwrap(), &verified_quote); - - // Trades using any other `tx_origin` can not bypass the verification. - let verification = verify_trade(None).await; - assert_eq!( - verification.unwrap(), - Estimate { - verified: false, - ..verified_quote - } - ); -} - /// Verified quotes work as for WETH trades without wrapping or approvals. async fn verified_quote_eth_balance(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; let weth = &onchain.contracts().weth; @@ -252,30 +136,27 @@ async fn verified_quote_eth_balance(web3: Web3) { // quote where the trader has no WETH balances or approval set, but // sufficient ETH for the trade assert!( - weth.balanceOf(trader.address().into_alloy()) + weth.balanceOf(trader.address()) .call() .await .unwrap() .is_zero() ); assert!( - weth.allowance( - trader.address().into_alloy(), - onchain.contracts().allowance.into_alloy() - ) - .call() - .await - .unwrap() - .is_zero() + weth.allowance(trader.address(), onchain.contracts().allowance) + .call() + .await + .unwrap() + .is_zero() ); let response = services .submit_quote(&OrderQuoteRequest { from: trader.address(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(1).try_into().unwrap(), + value: (1u64.eth()).try_into().unwrap(), }, }, ..Default::default() @@ -291,19 +172,16 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(3)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(3u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Send 3 ETH to the settlement contract so we can get verified quotes for // selling WETH. onchain - .send_wei( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(3), - ) + .send_wei(*onchain.contracts().gp_settlement.address(), 3u64.eth()) .await; tracing::info!("Starting services."); @@ -311,11 +189,11 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { services.start_protocol(solver.clone()).await; let request = OrderQuoteRequest { - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(3).try_into().unwrap(), + value: (3u64.eth()).try_into().unwrap(), }, }, ..Default::default() @@ -324,7 +202,7 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where settlement contract is trader and implicit receiver let response = services .submit_quote(&OrderQuoteRequest { - from: onchain.contracts().gp_settlement.address().into_legacy(), + from: *onchain.contracts().gp_settlement.address(), receiver: None, ..request.clone() }) @@ -335,8 +213,8 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where settlement contract is trader and explicit receiver let response = services .submit_quote(&OrderQuoteRequest { - from: onchain.contracts().gp_settlement.address().into_legacy(), - receiver: Some(onchain.contracts().gp_settlement.address().into_legacy()), + from: *onchain.contracts().gp_settlement.address(), + receiver: Some(*onchain.contracts().gp_settlement.address()), ..request.clone() }) .await @@ -346,7 +224,7 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where settlement contract is trader and not the receiver let response = services .submit_quote(&OrderQuoteRequest { - from: onchain.contracts().gp_settlement.address().into_legacy(), + from: *onchain.contracts().gp_settlement.address(), receiver: Some(trader.address()), ..request.clone() }) @@ -358,7 +236,7 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { let response = services .submit_quote(&OrderQuoteRequest { from: trader.address(), - receiver: Some(onchain.contracts().gp_settlement.address().into_legacy()), + receiver: Some(*onchain.contracts().gp_settlement.address()), ..request.clone() }) .await @@ -372,10 +250,10 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(0)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(0u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; let weth = &onchain.contracts().weth; @@ -383,17 +261,8 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - api: vec![ - // The OpenZeppelin `ERC20Mintable` token uses a mapping in - // the first (0'th) storage slot for balances. - format!("--quote-token-balance-overrides={:?}@0", token.address()), - // We don't configure the WETH token and instead rely on - // auto-detection for balance overrides. - "--quote-autodetect-token-balance-overrides=true".to_string(), - ], - ..Default::default() - }, + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), solver, ) .await; @@ -401,33 +270,23 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // quote where the trader has no balances or approval set from TOKEN->WETH assert_eq!( ( + token.balanceOf(trader.address()).call().await.unwrap(), token - .balanceOf(trader.address().into_alloy()) + .allowance(trader.address(), onchain.contracts().allowance) .call() .await .unwrap(), - token - .allowance( - trader.address().into_alloy(), - onchain.contracts().allowance.into_alloy() - ) - .call() - .await - .unwrap(), - ), - ( - ::alloy::primitives::U256::ZERO, - ::alloy::primitives::U256::ZERO ), + (U256::ZERO, U256::ZERO), ); let response = services .submit_quote(&OrderQuoteRequest { from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: weth.address().into_legacy(), + sell_token: *token.address(), + buy_token: *weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(1).try_into().unwrap(), + value: (1u64.eth()).try_into().unwrap(), }, }, ..Default::default() @@ -440,37 +299,34 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { assert!( onchain .web3() - .eth() - .balance(trader.address(), None) + .provider + .get_balance(trader.address()) .await .unwrap() .is_zero() ); assert!( - weth.balanceOf(trader.address().into_alloy()) + weth.balanceOf(trader.address()) .call() .await .unwrap() .is_zero() ); assert!( - weth.allowance( - trader.address().into_alloy(), - onchain.contracts().allowance.into_alloy() - ) - .call() - .await - .unwrap() - .is_zero() + weth.allowance(trader.address(), onchain.contracts().allowance) + .call() + .await + .unwrap() + .is_zero() ); let response = services .submit_quote(&OrderQuoteRequest { from: trader.address(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(1).try_into().unwrap(), + value: (1u64.eth()).try_into().unwrap(), }, }, ..Default::default() @@ -483,12 +339,12 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // which is used when no wallet is connected in the frontend let response = services .submit_quote(&OrderQuoteRequest { - from: H160::zero(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: Address::ZERO, + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(1).try_into().unwrap(), + value: (1u64.eth()).try_into().unwrap(), }, }, ..Default::default() @@ -501,12 +357,12 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // if the user provided pre-interactions. This works now. let response = services .submit_quote(&OrderQuoteRequest { - from: H160::zero(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: Address::ZERO, + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(1).try_into().unwrap(), + value: (1u64.eth()).try_into().unwrap(), }, }, app_data: model::order::OrderCreationAppData::Full { @@ -537,19 +393,17 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { async fn usdt_quote_verification(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; - let usdc = addr!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); - let usdt = addr!("dac17f958d2ee523a2206206994597c13d831ec7"); + let usdc = address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); + let usdt = address!("dac17f958d2ee523a2206206994597c13d831ec7"); // Place Orders let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - api: vec!["--quote-autodetect-token-balance-overrides=true".to_string()], - ..Default::default() - }, + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration::test_default(), solver, ) .await; @@ -560,7 +414,7 @@ async fn usdt_quote_verification(web3: Web3) { buy_token: usdc, side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei_with_exp(1000, 18).try_into().unwrap(), + value: (1000u64.eth()).try_into().unwrap(), }, }, ..Default::default() @@ -569,3 +423,165 @@ async fn usdt_quote_verification(web3: Web3) { .unwrap(); assert!(quote.verified); } + +/// Tests that balance override detection works for tokens with non-standard +/// storage layouts, including struct-offset and remote-storage patterns. +async fn trace_based_balance_detection(web3: Web3) { + tracing::info!("Setting up chain state."); + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + + let weth = *onchain.contracts().weth.address(); + + let struct_offset_token = + contracts::test::NonStandardERC20Balances::Instance::deploy(web3.provider.clone()) + .await + .unwrap(); + + // Deploy the NonStandardERC20BalancesEntrance token - as if the previous + // contract wasnt complicated enough, this contract will selectively + // delegate the balance it returns between itself (allowing for testing of + // calling another contract to get a balance--or calling another contract to + // *not* get a balance) + let local_storage_token = + contracts::test::RemoteERC20Balances::Instance::deploy(web3.provider.clone(), weth, true) + .await + .unwrap(); + let delegated_storage_token = + contracts::test::RemoteERC20Balances::Instance::deploy(web3.provider.clone(), weth, false) + .await + .unwrap(); + + // Mint some tokens to the trader (so the contract has non-zero state) + struct_offset_token + .mint(trader.address(), 100u64.eth()) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + local_storage_token + .mint(trader.address(), 123u64.eth()) + .from(solver.address()) + .send_and_watch() + .await + .unwrap(); + + let test_account = address!("0000000000000000000000000000000000000042"); + let test_balance = U256::from(123_456_789_u64); + + async fn test_balance_override( + web3: &Web3, + token: Address, + test_account: Address, + test_balance: U256, + ) { + let balance_overrides = StateOverrides::new(web3.clone()); + + let override_result = balance_overrides + .balance_override(BalanceOverrideRequest { + token, + holder: test_account, + amount: test_balance, + }) + .await; + + assert!(override_result.is_some(), "Should produce state override"); + let (override_token, state_override) = override_result.unwrap(); + + let token_contract = ERC20::Instance::new(token, web3.provider.clone()); + let balance = token_contract + .balanceOf(test_account) + .state(AddressMap::from_iter([( + override_token, + state_override.clone(), + )])) + .call() + .await + .unwrap(); + + assert_eq!( + balance, test_balance, + "Balance override should work for token {:?}", + token + ); + + tracing::info!( + ?token, + ?balance, + ?override_token, + ?state_override, + "✓ Balance override verified for token", + ); + } + + test_balance_override(&web3, weth, test_account, test_balance).await; + test_balance_override( + &web3, + *struct_offset_token.address(), + test_account, + test_balance, + ) + .await; + test_balance_override( + &web3, + *delegated_storage_token.address(), + test_account, + test_balance, + ) + .await; + test_balance_override( + &web3, + *local_storage_token.address(), + test_account, + test_balance, + ) + .await; +} + +/// Exercises the `AaveV3AToken` balance override strategy against a real +/// mainnet fork. We build the override with the forked web3 (so it reads +/// the live `getReserveNormalizedIncome` from the Aave v3 Pool), then apply +/// it in an `eth_call` to `aToken.balanceOf(holder)` and assert the +/// reported balance matches the requested amount within one wei of ray +/// rounding. This is the property `TradeVerifier` relies on when using +/// the override to fund the spardose. +async fn aave_atoken_quote_verification(web3: Web3) { + // aEthWETH / WETH / Aave v3 Pool on mainnet. + let a_eth_weth = address!("4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8"); + let spardose = address!("0000000000000000000000000000000000020000"); + + let balance_overrides = StateOverrides::new(web3.clone()); + + let amount = 5u64.eth(); // 5 aEthWETH + + let (target, override_) = balance_overrides + .balance_override(BalanceOverrideRequest { + token: a_eth_weth, + holder: spardose, + amount, + }) + .await + .expect("override computed"); + assert_eq!(target, a_eth_weth); + + // Apply the override to a live `balanceOf` call via the forked node and + // make sure the contract now reports the requested amount (± 1 wei of + // ray rounding). + let overrides: StateOverride = [(target, override_)].into_iter().collect(); + let a_token_contract = ERC20::Instance::new(a_eth_weth, web3.provider.clone()); + let reported = a_token_contract + .balanceOf(spardose) + .state(overrides) + .call() + .await + .unwrap(); + + let diff = reported.abs_diff(amount); + assert!( + diff <= U256::from(1u64), + "balanceOf after override returned {reported}, expected ~{amount} (diff {diff} wei)", + ); +} diff --git a/crates/e2e/tests/e2e/quoting.rs b/crates/e2e/tests/e2e/quoting.rs index 0711effbfe..4701666578 100644 --- a/crates/e2e/tests/e2e/quoting.rs +++ b/crates/e2e/tests/e2e/quoting.rs @@ -1,24 +1,28 @@ use { - e2e::setup::{colocation::SolverEngine, eth, mock::Mock, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + configs::{ + autopilot::Configuration, + fee_factor::FeeFactor, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, }, + e2e::setup::{colocation::SolverEngine, mock::Mock, *}, + eth_domain_types::Address, + ethrpc::alloy::CallBuilderExt, futures::FutureExt, model::{ order::{OrderCreation, OrderCreationAppData, OrderKind}, quote::{OrderQuoteRequest, OrderQuoteSide, QuoteSigningScheme, SellAmount}, signature::EcdsaSigningScheme, }, - number::nonzero::U256 as NonZeroU256, - secp256k1::SecretKey, + number::{nonzero::NonZeroU256, units::EthUnit}, + reqwest::StatusCode, serde_json::json, - shared::ethrpc::Web3, + shared::web3::Web3, + solvers_dto::solution::{SolverError, SolverErrorCode, SolverResponse}, std::{ sync::Arc, time::{Duration, Instant}, }, - web3::signing::SecretKeyRef, }; #[tokio::test] @@ -45,6 +49,24 @@ async fn local_node_volume_fee() { run_test(volume_fee).await; } +#[tokio::test] +#[ignore] +async fn local_node_quote_custom_solver_errors() { + run_test(quote_custom_solver_errors).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_native_price_custom_solver_errors() { + run_test(native_price_custom_solver_errors).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_quote_custom_solver_errors_prioritized() { + run_test(quote_custom_solver_errors_prioritized).await; +} + // Test that quoting works as expected, specifically, that we can quote for a // token pair and additional gas from ERC-1271 and hooks are included in the // quoted fee amount. @@ -52,17 +74,17 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -70,8 +92,8 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(3)) + .from(trader.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); @@ -79,24 +101,29 @@ async fn test(web3: Web3) { tracing::info!("Starting services."); let services = Services::new(&onchain).await; // Start API with 0.02% (2 bps) volume fee - let args = ExtraServiceArgs { - api: vec![ - "--volume-fee-factor=0.0002".to_string(), - // Set a far future effective timestamp to ensure the fee is not applied - "--volume-fee-effective-timestamp=2099-01-01T10:00:00Z".to_string(), - ], - ..Default::default() - }; - services.start_protocol_with_args(args, solver).await; + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + volume_fee: Some(configs::orderbook::VolumeFeeConfig { + factor: Some(FeeFactor::new(0.0002)), + // Set a far future effective timestamp to ensure the fee is not applied + effective_from_timestamp: Some("2099-01-01T10:00:00Z".parse().unwrap()), + }), + ..configs::orderbook::Configuration::test_default() + }, + solver, + ) + .await; tracing::info!("Quoting order"); let request = OrderQuoteRequest { from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: NonZeroU256::try_from(to_wei(1)).unwrap(), + value: NonZeroU256::try_from(1u64.eth()).unwrap(), }, }, ..Default::default() @@ -200,17 +227,17 @@ async fn uses_stale_liquidity(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(1)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 1u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -218,8 +245,8 @@ async fn uses_stale_liquidity(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(1)) + .from(trader.address()) + .value(1u64.eth()) .send_and_watch() .await .unwrap(); @@ -230,11 +257,11 @@ async fn uses_stale_liquidity(web3: Web3) { let quote = OrderQuoteRequest { from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { - value: NonZeroU256::new(to_wei(1)).unwrap(), + value: NonZeroU256::new(1u64.eth()).unwrap(), }, }, ..Default::default() @@ -246,7 +273,7 @@ async fn uses_stale_liquidity(web3: Web3) { // Now, we want to manually unbalance the pools and assert that the quote // doesn't change (as the price estimation will use stale pricing data). onchain - .mint_token_to_weth_uni_v2_pool(&token, to_wei(1_000)) + .mint_token_to_weth_uni_v2_pool(&token, 1_000u64.eth()) .await; tracing::info!("performining second quote, which should match first"); @@ -272,16 +299,16 @@ async fn quote_timeout(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; let [sell_token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; tracing::info!("Starting services."); let services = Services::new(&onchain).await; - let mock_solver = Mock::default(); + let mock_solver = Mock::new().await; // Start system colocation::start_driver( @@ -291,37 +318,61 @@ async fn quote_timeout(web3: Web3) { name: "test_solver".into(), account: solver.clone(), endpoint: mock_solver.url.clone(), - base_tokens: vec![sell_token.address().into_legacy()], + base_tokens: vec![*sell_token.address()], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, SolverEngine { name: "test_quoter".into(), account: solver.clone(), endpoint: mock_solver.url.clone(), - base_tokens: vec![sell_token.address().into_legacy()], + base_tokens: vec![*sell_token.address()], merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, ], colocation::LiquidityProvider::UniswapV2, false, ); - /// The default and maximum quote timeout enforced by the backend. - /// (configurable but always 500ms in e2e tests) - const MAX_QUOTE_TIME_MS: u64 = 500; + /// The default quote timeout used when the user does not override it. + const DEFAULT_QUOTE_TIMEOUT_MS: u64 = 500; + + /// The maximum quote timeout the user is allowed to configure. + const MAX_QUOTE_TIMEOUT_MS: u64 = 1000; services - .start_api(vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_quoter".to_string(), - format!("--quote-timeout={MAX_QUOTE_TIME_MS}ms"), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_quoter", + )]), + native_price_estimation: configs::orderbook::native_price::NativePriceConfig { + estimators: configs::native_price_estimators::NativePriceEstimators::new(vec![ + vec![ + configs::native_price_estimators::NativePriceEstimator::driver( + "test_quoter".to_string(), + "http://localhost:11088/test_solver".parse().unwrap(), + ), + ], + ]), + ..configs::orderbook::native_price::NativePriceConfig::test_default() + }, + price_estimation: configs::price_estimation::PriceEstimation { + quote_timeout: Duration::from_millis(DEFAULT_QUOTE_TIMEOUT_MS), + max_quote_timeout: Duration::from_millis(MAX_QUOTE_TIMEOUT_MS), + ..configs::orderbook::Configuration::test_default().price_estimation + }, + ..configs::orderbook::Configuration::test_default() + }) .await; mock_solver.configure_solution_async(Arc::new(|| { async { - // make the solver always exceeds the maximum allowed timeout - // (by default 500ms in e2e tests) - tokio::time::sleep(Duration::from_millis(MAX_QUOTE_TIME_MS + 300)).await; + // make the solver always exceed the max quote timeout + tokio::time::sleep(Duration::from_millis(MAX_QUOTE_TIMEOUT_MS + 100)).await; // we only care about timeout management so no need to return // a working solution None @@ -331,11 +382,13 @@ async fn quote_timeout(web3: Web3) { let quote_request = |timeout| OrderQuoteRequest { from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: sell_token.address().into_legacy(), + // use random address to avoid tokens getting cached as unquotable + // due to repeated quoting errors + sell_token: Address::random(), + buy_token: Address::random(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: NonZeroU256::try_from(to_wei(1)).unwrap(), + value: NonZeroU256::try_from(1u64.eth()).unwrap(), }, }, timeout, @@ -352,21 +405,19 @@ async fn quote_timeout(web3: Web3) { assert!((min..max).contains(&elapsed)); }; - // native token price requests are also capped to the max timeout + // native token price requests use the default timeout let start = std::time::Instant::now(); - let res = services - .get_native_price(&sell_token.address().into_legacy()) - .await; + let res = services.get_native_price(&Address::random()).await; assert!(res.unwrap_err().1.contains("NoLiquidity")); - assert_within_variance(start, MAX_QUOTE_TIME_MS); + assert_within_variance(start, DEFAULT_QUOTE_TIMEOUT_MS); - // not providing a timeout uses the backend's default timeout (500ms) + // not providing a quote timeout uses the backend's default timeout (500ms) let start = std::time::Instant::now(); let res = services.submit_quote("e_request(None)).await; assert!(res.unwrap_err().1.contains("NoLiquidity")); - assert_within_variance(start, MAX_QUOTE_TIME_MS); + assert_within_variance(start, DEFAULT_QUOTE_TIMEOUT_MS); - // timeouts below the max timeout get enforced correctly + // timeouts below the default timeout get enforced correctly let start = std::time::Instant::now(); let res = services .submit_quote("e_request(Some(Duration::from_millis(300)))) @@ -374,31 +425,39 @@ async fn quote_timeout(web3: Web3) { assert!(res.unwrap_err().1.contains("NoLiquidity")); assert_within_variance(start, 300); - // user provided timeouts get capped at the backend's max timeout (500ms) + // timeouts between default and max value get enforced correctly + let start = std::time::Instant::now(); + let res = services + .submit_quote("e_request(Some(Duration::from_millis(700)))) + .await; + assert!(res.unwrap_err().1.contains("NoLiquidity")); + assert_within_variance(start, 700); + + // user provided timeouts get capped at the backend's max timeout (1000ms) let start = std::time::Instant::now(); let res = services .submit_quote("e_request(Some(Duration::from_millis( - MAX_QUOTE_TIME_MS * 2, + MAX_QUOTE_TIMEOUT_MS * 2, )))) .await; assert!(res.unwrap_err().1.contains("NoLiquidity")); - assert_within_variance(start, MAX_QUOTE_TIME_MS); + assert_within_variance(start, MAX_QUOTE_TIMEOUT_MS); // set up trader to pass balance checks during order creation - sell_token.mint(trader.address(), to_wei(1)).await; + sell_token.mint(trader.address(), 1u64.eth()).await; sell_token - .approve(onchain.contracts().allowance.into_alloy(), eth(1)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 1u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); let order = OrderCreation { - sell_token: sell_token.address().into_legacy(), - sell_amount: to_wei(1), + sell_token: *sell_token.address(), + sell_amount: 1u64.eth(), buy_token: Default::default(), - buy_amount: to_wei(1), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: true, @@ -407,7 +466,7 @@ async fn quote_timeout(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); // order creation requests always use the default quote time @@ -416,24 +475,361 @@ async fn quote_timeout(web3: Web3) { let start = std::time::Instant::now(); let res = services.create_order(&order).await; assert!(res.unwrap_err().1.contains("NoLiquidity")); - assert_within_variance(start, MAX_QUOTE_TIME_MS); + assert_within_variance(start, DEFAULT_QUOTE_TIMEOUT_MS); +} + +async fn quote_custom_solver_errors(web3: Web3) { + tracing::info!("Setting up chain state."); + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; + let [sell_token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + + let mock_solver = Mock::new().await; + + colocation::start_driver( + onchain.contracts(), + vec![ + SolverEngine { + name: "test_solver".into(), + account: solver.clone(), + endpoint: mock_solver.url.clone(), + base_tokens: vec![*sell_token.address()], + merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], + }, + SolverEngine { + name: "test_quoter".into(), + account: solver.clone(), + endpoint: mock_solver.url.clone(), + base_tokens: vec![*sell_token.address()], + merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], + }, + ], + colocation::LiquidityProvider::UniswapV2, + false, + ); + + services + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_quoter", + )]), + native_price_estimation: configs::orderbook::native_price::NativePriceConfig { + estimators: configs::native_price_estimators::NativePriceEstimators::new(vec![ + vec![ + configs::native_price_estimators::NativePriceEstimator::driver( + "test_quoter".to_string(), + "http://localhost:11088/test_quoter".parse().unwrap(), + ), + ], + ]), + ..configs::orderbook::native_price::NativePriceConfig::test_default() + }, + ..configs::orderbook::Configuration::test_default() + }) + .await; + + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *sell_token.address(), + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(1u64.eth()).unwrap(), + }, + }, + ..Default::default() + }; + + let cases = vec![ + ( + SolverErrorCode::TradingOutsideAllowedWindow, + "TradingOutsideAllowedWindow", + None, + "Token can only be traded during specific time windows", + ), + ( + SolverErrorCode::TokenTemporarilySuspended, + "TokenTemporarilySuspended", + Some("token is suspended"), + "token is suspended", + ), + ( + SolverErrorCode::InsufficientLiquidity, + "InsufficientLiquidity", + Some("not enough liquidity"), + "not enough liquidity", + ), + ( + SolverErrorCode::Other, + "CustomSolverError", + Some("some solver specific error"), + "some solver specific error", + ), + ]; + + for (code, expected_kind, sent_message, expected_message) in cases { + mock_solver.configure_response(SolverResponse::Error { + error: SolverError { + code, + message: sent_message.map(str::to_string), + }, + }); + + let (status, body) = services.submit_quote("e_request).await.unwrap_err(); + assert_eq!(status, StatusCode::BAD_REQUEST); + assert!( + body.contains(expected_kind), + "response should include error kind {expected_kind}, got {body}" + ); + assert!( + body.contains(expected_message), + "response should include error message {expected_message}, got {body}" + ); + } +} + +async fn native_price_custom_solver_errors(web3: Web3) { + tracing::info!("Setting up chain state."); + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [_trader] = onchain.make_accounts(2u64.eth()).await; + let [sell_token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + + let mock_solver = Mock::new().await; + + colocation::start_driver( + onchain.contracts(), + vec![ + SolverEngine { + name: "test_solver".into(), + account: solver.clone(), + endpoint: mock_solver.url.clone(), + base_tokens: vec![*sell_token.address()], + merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], + }, + SolverEngine { + name: "test_quoter".into(), + account: solver.clone(), + endpoint: mock_solver.url.clone(), + base_tokens: vec![*sell_token.address()], + merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], + }, + ], + colocation::LiquidityProvider::UniswapV2, + false, + ); + + services + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_quoter", + "http://localhost:11088/test_quoter", + )]), + native_price_estimation: configs::orderbook::native_price::NativePriceConfig { + estimators: configs::native_price_estimators::NativePriceEstimators::new(vec![ + vec![ + configs::native_price_estimators::NativePriceEstimator::driver( + "test_quoter".to_string(), + "http://localhost:11088/test_quoter".parse().unwrap(), + ), + ], + ]), + ..configs::orderbook::native_price::NativePriceConfig::test_default() + }, + ..configs::orderbook::Configuration::test_default() + }) + .await; + + let cases = vec![ + ( + SolverErrorCode::TradingOutsideAllowedWindow, + "TradingOutsideAllowedWindow", + "native window closed", + ), + ( + SolverErrorCode::TokenTemporarilySuspended, + "TokenTemporarilySuspended", + "native token suspended", + ), + ( + SolverErrorCode::InsufficientLiquidity, + "InsufficientLiquidity", + "native not enough liquidity", + ), + ( + SolverErrorCode::Other, + "CustomSolverError", + "native custom solver reason", + ), + ]; + + for (code, expected_kind, message) in cases { + mock_solver.configure_response(SolverResponse::Error { + error: SolverError { + code, + message: Some(message.to_string()), + }, + }); + + let (status, body) = services + .get_native_price(sell_token.address()) + .await + .unwrap_err(); + assert_eq!(status, StatusCode::BAD_REQUEST); + assert!( + body.contains(expected_kind), + "response should include error kind {expected_kind}, got {body}" + ); + assert!( + body.contains(message), + "response should include error message {message}, got {body}" + ); + } +} + +async fn quote_custom_solver_errors_prioritized(web3: Web3) { + tracing::info!("Setting up chain state."); + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; + let [sell_token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + + let custom_error_solver = Mock::new().await; + let no_liquidity_solver = Mock::new().await; + + colocation::start_driver( + onchain.contracts(), + vec![ + SolverEngine { + name: "custom_solver".into(), + account: solver.clone(), + endpoint: custom_error_solver.url.clone(), + base_tokens: vec![*sell_token.address()], + merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], + }, + SolverEngine { + name: "no_liquidity_solver".into(), + account: solver.clone(), + endpoint: no_liquidity_solver.url.clone(), + base_tokens: vec![*sell_token.address()], + merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], + }, + ], + colocation::LiquidityProvider::UniswapV2, + false, + ); + + services + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ + ExternalSolver::new("custom_solver", "http://localhost:11088/custom_solver"), + ExternalSolver::new( + "no_liquidity_solver", + "http://localhost:11088/no_liquidity_solver", + ), + ]), + native_price_estimation: configs::orderbook::native_price::NativePriceConfig { + estimators: configs::native_price_estimators::NativePriceEstimators::new(vec![ + vec![ + configs::native_price_estimators::NativePriceEstimator::driver( + "custom_solver".to_string(), + "http://localhost:11088/custom_solver".parse().unwrap(), + ), + configs::native_price_estimators::NativePriceEstimator::driver( + "no_liquidity_solver".to_string(), + "http://localhost:11088/no_liquidity_solver" + .parse() + .unwrap(), + ), + ], + ]), + ..configs::orderbook::native_price::NativePriceConfig::test_default() + }, + ..configs::orderbook::Configuration::test_default() + }) + .await; + + custom_error_solver.configure_response(SolverResponse::Error { + error: SolverError { + code: SolverErrorCode::Other, + message: Some("priority custom solver error".to_string()), + }, + }); + no_liquidity_solver.configure_response(SolverResponse::Solutions { + solutions: Vec::new(), + }); + + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *sell_token.address(), + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(1u64.eth()).unwrap(), + }, + }, + ..Default::default() + }; + + let (status, body) = services.submit_quote("e_request).await.unwrap_err(); + assert_eq!(status, StatusCode::BAD_REQUEST); + assert!( + body.contains("CustomSolverError"), + "response should include custom solver error, got {body}" + ); + assert!( + body.contains("priority custom solver error"), + "response should include prioritized custom error message, got {body}" + ); } /// Test that volume fees are correctly applied to quotes. async fn volume_fee(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; - let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token, override_token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -441,33 +837,52 @@ async fn volume_fee(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(3)) + .from(trader.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); tracing::info!("Starting services with volume fee."); let services = Services::new(&onchain).await; - // Start API with 0.02% (2 bps) volume fee - let args = ExtraServiceArgs { - api: vec![ - "--volume-fee-factor=0.0002".to_string(), - // Set a past effective timestamp to ensure the fee is applied - "--volume-fee-effective-timestamp=2000-01-01T10:00:00Z".to_string(), - ], - ..Default::default() - }; - services.start_protocol_with_args(args, solver).await; + // Start API with 0.02% (2 bps) default volume fee + // Bucket override: WETH<->override_token pair gets 5 bps (both tokens must be + // in bucket) + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + shared: configs::shared::SharedConfig { + volume_fee_bucket_overrides: vec![configs::shared::TokenBucketFeeOverride { + tokens: [ + *onchain.contracts().weth.address(), + *override_token.address(), + ] + .into_iter() + .collect(), + factor: FeeFactor::new(0.0005), + }], + ..Default::default() + }, + volume_fee: Some(configs::orderbook::VolumeFeeConfig { + factor: Some(FeeFactor::new(0.0002)), + // Set a past effective timestamp to ensure the fee is applied + effective_from_timestamp: Some("2000-01-01T10:00:00Z".parse().unwrap()), + }), + ..configs::orderbook::Configuration::test_default() + }, + solver, + ) + .await; tracing::info!("Testing SELL quote with volume fee"); let sell_request = OrderQuoteRequest { from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: NonZeroU256::try_from(to_wei(1)).unwrap(), + value: NonZeroU256::try_from(1u64.eth()).unwrap(), }, }, ..Default::default() @@ -482,10 +897,10 @@ async fn volume_fee(web3: Web3) { tracing::info!("Testing BUY quote with volume fee"); let buy_request = OrderQuoteRequest { from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Buy { - buy_amount_after_fee: NonZeroU256::try_from(to_wei(1)).unwrap(), + buy_amount_after_fee: NonZeroU256::try_from(1u64.eth()).unwrap(), }, ..Default::default() }; @@ -495,4 +910,29 @@ async fn volume_fee(web3: Web3) { // Verify protocol fee fields are present assert!(buy_quote.protocol_fee_bps.is_some()); assert_eq!(buy_quote.protocol_fee_bps.as_ref().unwrap(), "2"); + + // Test bucket override: override_token should get 5 bps instead of 2 bps + tracing::info!("Testing quote with bucket override (5 bps)"); + let override_request = OrderQuoteRequest { + from: trader.address(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *override_token.address(), + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(1u64.eth()).unwrap(), + }, + }, + ..Default::default() + }; + + let override_quote = services.submit_quote(&override_request).await.unwrap(); + + // Verify override token gets 5 bps (from bucket override) instead of 2 bps + // (default) + assert!(override_quote.protocol_fee_bps.is_some()); + assert_eq!( + override_quote.protocol_fee_bps.as_ref().unwrap(), + "5", + "Bucket override should apply 5 bps, not default 2 bps" + ); } diff --git a/crates/e2e/tests/e2e/refunder.rs b/crates/e2e/tests/e2e/refunder.rs index badd6f96d2..728bd0cd4c 100644 --- a/crates/e2e/tests/e2e/refunder.rs +++ b/crates/e2e/tests/e2e/refunder.rs @@ -1,179 +1,675 @@ +//! # Regarding Order Settlement +//! +//! For tests requiring actual settlement, use `Utc::now()` for `valid_to` when +//! creating a new test order. See `refunder_skips_settled_orders` for an +//! example. + use { - crate::ethflow::{EthFlowOrderOnchainStatus, ExtendedEthFlowOrder}, - chrono::{TimeZone, Utc}, - e2e::{nodes::local_node::TestNodeApi, setup::*}, - ethcontract::{H160, U256}, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy, TryIntoAlloyAsync}, - block_stream::timestamp_of_current_block_in_seconds, + crate::ethflow::ExtendedEthFlowOrder, + ::alloy::{primitives::Address, providers::ext::AnvilApi}, + chrono::Utc, + e2e::setup::*, + ethrpc::{Web3, alloy::EvmProviderExt, block_stream::timestamp_of_current_block_in_seconds}, + model::{ + order::OrderUid, + quote::{OrderQuoteRequest, OrderQuoteSide, QuoteSigningScheme, Validity}, }, - model::quote::{OrderQuoteRequest, OrderQuoteSide, QuoteSigningScheme, Validity}, - number::nonzero::U256 as NonZeroU256, - refunder::refund_service::RefundService, - sqlx::PgPool, + number::{nonzero::NonZeroU256, units::EthUnit}, + refunder::{RefundStatus, refund_service::RefundService}, + rstest::{Context, rstest}, }; -#[tokio::test] -#[ignore] -async fn local_node_refunder_tx() { - run_test(refunder_tx).await; -} +// Common constants for refunder tests +const SELL_AMOUNT: u128 = 3_000_000_000_000_000; // 0.003 ETH +const MAX_GAS_PRICE: u64 = 2_000_000_000_000; // 2000 Gwei +const START_PRIORITY_FEE_TIP: u64 = 30_000_000_000; // 30 Gwei +const SLIPPAGE_BPS: u16 = 300; // 3% +const RECEIVER: Address = Address::repeat_byte(42); -async fn refunder_tx(web3: Web3) { - let mut onchain = OnchainComponents::deploy(web3.clone()).await; - - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [user, refunder] = onchain.make_accounts(to_wei(10)).await; - let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) - .await; +/// Advances the blockchain time past the given expiration timestamp. +async fn advance_time_past_expiration(web3: &Web3, valid_to: u32) { + // Add 60 seconds buffer so the order is definitively expired, not just at the + // boundary. + let target_timestamp = valid_to as u64 + 60; + web3.provider + .evm_set_next_block_timestamp(target_timestamp) + .await + .expect("Must be able to set block timestamp"); + web3.provider + .evm_mine(None) + .await + .expect("Unable to mine next block"); +} - let services = Services::new(&onchain).await; - services.start_protocol(solver).await; +/// Waits for an order to be indexed by the orderbook service. +async fn wait_for_order_indexed( + services: &Services<'_>, + onchain: &OnchainComponents, + order_id: &OrderUid, +) { + tracing::info!("Waiting for order to be indexed."); + wait_for_condition(TIMEOUT, || async { + onchain.mint_block().await; + services.get_order(order_id).await.is_ok() + }) + .await + .expect("Timed out waiting for order to be indexed"); +} - // Get quote id for order placement - let buy_token = token.address().into_legacy(); - let receiver = Some(H160([42; 20])); - let sell_amount = U256::from("3000000000000000"); +/// Waits for an order to be settled and indexed in the database. +async fn wait_for_order_settlement( + services: &Services<'_>, + onchain: &OnchainComponents, + order_id: &OrderUid, +) { + tracing::info!("Waiting for order to be settled."); + wait_for_condition(TIMEOUT, || async { + onchain.mint_block().await; + services + .get_order(order_id) + .await + .map(|o| o.metadata.status == model::order::OrderStatus::Fulfilled) + .unwrap_or(false) + }) + .await + .expect("Timed out waiting for order to be settled"); +} - let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); - let quote = OrderQuoteRequest { - from: ethflow_contract.address().into_legacy(), - sell_token: onchain.contracts().weth.address().into_legacy(), +/// Creates a standard quote request for ethflow orders. +fn default_quote_request( + from: Address, + weth: &contracts::WETH9::Instance, + buy_token: Address, + sell_amount: NonZeroU256, +) -> OrderQuoteRequest { + OrderQuoteRequest { + from, + sell_token: *weth.address(), buy_token, - receiver, + receiver: Some(RECEIVER), validity: Validity::For(3600), signing_scheme: QuoteSigningScheme::Eip1271 { onchain_order: true, verification_gas_limit: 0, }, side: OrderQuoteSide::Sell { - sell_amount: model::quote::SellAmount::AfterFee { - value: NonZeroU256::try_from(sell_amount).unwrap(), - }, + sell_amount: model::quote::SellAmount::AfterFee { value: sell_amount }, }, ..Default::default() - }; - let quote_response = services.submit_quote("e).await.unwrap(); + } +} + +/// Builder for creating and indexing ethflow orders in tests. +struct EthflowOrderBuilder<'a> { + // Core dependencies + services: &'a Services<'a>, + onchain: &'a OnchainComponents, + user: &'a TestAccount, + buy_token: Address, + + // Builder state (SQL filter control) + sell_amount: NonZeroU256, + slippage_bps: u16, + valid_to: u32, + should_invalidate: bool, + ethflow_index: usize, +} + +impl<'a> EthflowOrderBuilder<'a> { + /// Create a new builder with sensible defaults + fn new( + services: &'a Services<'a>, + onchain: &'a OnchainComponents, + user: &'a TestAccount, + buy_token: Address, + ) -> Self { + Self { + services, + onchain, + user, + buy_token, + sell_amount: NonZeroU256::try_from(SELL_AMOUNT).unwrap(), + slippage_bps: SLIPPAGE_BPS, + valid_to: 60, + should_invalidate: false, + ethflow_index: 0, + } + } + + /// Set the sell amount for the order. + fn with_sell_amount(mut self, amount: NonZeroU256) -> Self { + self.sell_amount = amount; + self + } + + /// Set slippage in basis points (e.g., 500 = 5%). + fn with_slippage_bps(mut self, bps: u16) -> Self { + self.slippage_bps = bps; + self + } + + /// Set order expiration timestamp (absolute, seconds since epoch). + fn with_valid_to(mut self, valid_to: u32) -> Self { + self.valid_to = valid_to; + self + } + + /// Mark order as invalidated on-chain after creation. + fn invalidated(mut self) -> Self { + self.should_invalidate = true; + self + } + + /// Select which ethflow contract to use. + fn with_ethflow_index(mut self, index: usize) -> Self { + self.ethflow_index = index; + self + } + + /// Creates the order, mines it on-chain, waits for indexing, and optionally + /// invalidates. + async fn create_and_index(self) -> (ExtendedEthFlowOrder, OrderUid, u32) { + let ethflow_contract = self + .onchain + .contracts() + .ethflows + .get(self.ethflow_index) + .expect("could not locate ethflow contract at given position"); + + // Get quote + let quote = default_quote_request( + *ethflow_contract.address(), + &self.onchain.contracts().weth, + self.buy_token, + self.sell_amount, + ); + let quote_response = self.services.submit_quote("e).await.unwrap(); + + let valid_to = self.valid_to; + + // Create ethflow order with slippage + let ethflow_order = ExtendedEthFlowOrder::from_quote("e_response, valid_to) + .include_slippage_bps(self.slippage_bps); + + // Mine order creation + ethflow_order + .mine_order_creation(self.user.address(), ethflow_contract) + .await; + + // Get order UID + let order_id = ethflow_order + .uid(self.onchain.contracts(), ethflow_contract) + .await; - let validity_duration = 600; - let valid_to = timestamp_of_current_block_in_seconds(&web3.alloy) + // Wait for indexing + wait_for_order_indexed(self.services, self.onchain, &order_id).await; + + // Optionally invalidate + if self.should_invalidate { + ethflow_order + .mine_order_invalidation(self.user.address(), ethflow_contract) + .await; + + // Wait for invalidation to be indexed + wait_for_condition(TIMEOUT, || async { + self.onchain.mint_block().await; + let order = self.services.get_order(&order_id).await.unwrap(); + order.metadata.status == model::order::OrderStatus::Cancelled + }) + .await + .unwrap(); + } + + (ethflow_order, order_id, valid_to) + } +} + +/// Pair of order's validity duration and refunder's enforced minimum. +#[derive(Debug, Clone, Copy)] +struct ValidityDuration { + /// The order's validity duration (valid_to - creation_timestamp). + order: u32, + /// The refunder's minimum validity duration threshold. + enforced: i64, +} + +/// Pair of order's slippage and refunder's enforced minimum price deviation. +#[derive(Debug, Clone, Copy)] +struct SlippageBps { + /// The order's slippage in basis points. + order: u16, + /// The refunder's minimum price deviation threshold in basis points. + enforced: i64, +} + +/// Runs a refunder threshold test. +/// +/// # Settlement Isolation +/// +/// Threshold tests verify the refunder's SQL eligibility filters (slippage and +/// validity duration), not settlement behavior. Orders in these tests use +/// blockchain time for `valid_to`, which combined with Anvil's genesis +/// timestamp of Jan 1, 2020 causes the autopilot to reject them as expired (it +/// validates against wall-clock time). This isolation is intentional: the +/// refunder uses blockchain time internally, so it correctly processes these +/// "expired" orders. +#[tracing::instrument] +async fn run_refunder_threshold_test( + web3: Web3, + slippage: SlippageBps, + validity: ValidityDuration, + expect_refund: bool, + description: &str, +) { + tracing::info!("Running refunder threshold test"); + + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [user, refunder_account] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + let buy_token = *token.address(); + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); + + // Compute absolute valid_to timestamp from blockchain time + duration + let valid_to = timestamp_of_current_block_in_seconds(&web3.provider) .await .unwrap() - + validity_duration; - // Accounting for slippage is necessary for the order to be picked up by the - // refunder - let ethflow_order = - ExtendedEthFlowOrder::from_quote("e_response, valid_to).include_slippage_bps(9999); + + validity.order; - // create second ethflow order using secondary ethflow contract - let ethflow_contract_2 = onchain.contracts().ethflows.get(1).unwrap(); + // Testing slippage/validity boundaries: order slippage >= enforced threshold + let (ethflow_order, _order_id, valid_to) = + EthflowOrderBuilder::new(&services, &onchain, &user, buy_token) + .with_slippage_bps(slippage.order) + .with_valid_to(valid_to) + .create_and_index() + .await; - let quote = OrderQuoteRequest { - from: ethflow_contract_2.address().into_legacy(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token, - receiver, - validity: Validity::For(3600), - signing_scheme: QuoteSigningScheme::Eip1271 { - onchain_order: true, - verification_gas_limit: 0, - }, - side: OrderQuoteSide::Sell { - sell_amount: model::quote::SellAmount::AfterFee { - value: NonZeroU256::try_from(sell_amount).unwrap(), - }, - }, - ..Default::default() - }; - let quote_response = services.submit_quote("e).await.unwrap(); - let ethflow_order_2 = - ExtendedEthFlowOrder::from_quote("e_response, valid_to).include_slippage_bps(9999); + advance_time_past_expiration(&web3, valid_to).await; - ethflow_order - .mine_order_creation(user.address().into_alloy(), ethflow_contract) - .await; - ethflow_order_2 - .mine_order_creation(user.address().into_alloy(), ethflow_contract_2) + let mut refund_service = RefundService::from_components( + services.db().clone(), + web3.clone(), + vec![*ethflow_contract.address()], + validity.enforced, + slippage.enforced, + refunder_account.signer.clone(), + MAX_GAS_PRICE, + START_PRIORITY_FEE_TIP, + None, + ); + + // Verify order is still eligible for refund (not yet reimbursed) + assert_ne!( + ethflow_order + .status(onchain.contracts(), ethflow_contract) + .await, + RefundStatus::Refunded + ); + + refund_service + .try_to_refund_all_eligible_orders() + .await + .unwrap(); + + // Check the expected outcome + let status = ethflow_order + .status(onchain.contracts(), ethflow_contract) .await; - let order_id = ethflow_order - .uid(onchain.contracts(), ethflow_contract) + assert!( + expect_refund == (status == RefundStatus::Refunded), + "Test failed: {description}.\nExpected refund: {expect_refund}, but got status: {status:?}" + ); +} + +#[rstest] +// Tests that orders with slippage below, at, or above the min_price_deviation +// threshold are refunded according to the SQL >= check. +#[case::slippage_below_threshold( + SlippageBps { order: 50, enforced: 100 }, + ValidityDuration { order: 600, enforced: 0 }, + false +)] +#[case::slippage_above_threshold( + SlippageBps { order: 500, enforced: 100 }, + ValidityDuration { order: 600, enforced: 0 }, + true +)] +// Tests that orders with validity duration below, at, or above the +// min_validity_duration threshold are refunded according to the SQL > check. +#[case::validity_below_duration( + SlippageBps { order: 9999, enforced: 0 }, + ValidityDuration { order: 100, enforced: 200 }, + false +)] +#[case::validity_above_duration( + SlippageBps { order: 9999, enforced: 0 }, + ValidityDuration { order: 600, enforced: 100 }, + true +)] +#[ignore] +#[tokio::test] +async fn local_node_refunder_thresholds( + #[case] slippage: SlippageBps, + #[case] validity: ValidityDuration, + #[case] expect_refund: bool, + #[context] context: Context, +) { + let description = context.description.unwrap_or("unknown"); + run_test(|web3| { + run_refunder_threshold_test(web3, slippage, validity, expect_refund, description) + }) + .await; +} + +/// Test that orders already invalidated on-chain by the user are NOT refunded +/// by the refunder service (SQL filter: `o_inv.uid is null`). +/// +/// Uses wall-clock time for `valid_to` so orders could potentially settle. +/// The on-chain invalidation is the sole reason the refunder skips this order. +#[ignore] +#[tokio::test] +async fn local_node_refunder_skips_invalidated_orders() { + run_test(refunder_skips_invalidated_orders).await; +} + +async fn refunder_skips_invalidated_orders(web3: Web3) { + tracing::info!("Testing that already-invalidated orders are skipped by the refunder"); + + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [user, refunder_account] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - let order_id_2 = ethflow_order_2 - .uid(onchain.contracts(), ethflow_contract_2) + let buy_token = *token.address(); + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); + + // Use wall-clock time so orders could potentially settle. The +600s (10 min) + // validity window allows time for indexing/invalidation before we advance + // blockchain time past expiration. The invalidation (not expiration) is the + // sole reason the refunder skips this order. + let valid_to = Utc::now().timestamp() as u32 + 600; + + // Create an invalidated order. Even though it would pass slippage/validity + // checks, the SQL filter `o_inv.uid is null` (ethflow_orders.rs:137) + // excludes it from the refundable set. The refunder uses permissive + // thresholds (min_validity_duration=0, min_price_deviation_bps=0 at lines + // 577-582), so slippage and validity are irrelevant. + let (ethflow_order, order_id, valid_to) = EthflowOrderBuilder::new( + &services, + &onchain, + &user, + buy_token, + ) + .with_valid_to(valid_to) + .invalidated() // KEY: This is what the test verifies + .create_and_index() + .await; + + advance_time_past_expiration(&web3, valid_to).await; + + let mut refund_service = RefundService::from_components( + services.db().clone(), + web3.clone(), + vec![*ethflow_contract.address()], + 0, // min_validity_duration = 0 (permissive) + 0, // min_price_deviation_bps = 0 (permissive) + refunder_account.signer.clone(), + MAX_GAS_PRICE, + START_PRIORITY_FEE_TIP, + None, + ); + + // The order should already be invalidated on-chain before the refunder runs + assert_eq!( + ethflow_order + .status(onchain.contracts(), ethflow_contract) + .await, + RefundStatus::Refunded, + "Order should already be invalidated by user" + ); + + // Run the refunder - it should NOT try to refund this already-invalidated order + refund_service + .try_to_refund_all_eligible_orders() + .await + .unwrap(); + + // The order should still be invalidated (status unchanged) + assert_eq!( + ethflow_order + .status(onchain.contracts(), ethflow_contract) + .await, + RefundStatus::Refunded + ); + + // Verify no refund TX was recorded (the refunder didn't process this order) + let order = services.get_order(&order_id).await.unwrap(); + assert!( + order + .metadata + .ethflow_data + .unwrap() + .refund_tx_hash + .is_none(), + "Refunder should not have created a refund TX for an already-invalidated order" + ); +} + +/// Test that orders already settled (with trades) are NOT refunded +/// by the refunder service (SQL filters: t.order_uid is null). +/// +/// This test needs actual settlement, which requires real-world timestamps +/// (autopilot validates against wall-clock time). +#[ignore] +#[tokio::test] +async fn local_node_refunder_skips_settled_orders() { + run_test(refunder_skips_settled_orders).await; +} + +async fn refunder_skips_settled_orders(web3: Web3) { + tracing::info!("Testing that already-settled orders are skipped by the refunder"); + + // This test requires special setup for the order to be fillable by solvers: + // larger sell amount (1 ETH), low slippage (300 bps), and real-world + // timestamps for autopilot validation. + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [user, refunder_account] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - tracing::info!("Waiting for orders to be indexed."); - wait_for_condition(TIMEOUT, || async { - onchain.mint_block().await; - services.get_order(&order_id).await.is_ok() && services.get_order(&order_id_2).await.is_ok() - }) - .await - .unwrap(); - - let time_after_expiration = valid_to as i64 + 60; - web3.api::>() - .set_next_block_timestamp( - &Utc.timestamp_millis_opt(time_after_expiration * 1_000) - .unwrap(), - ) + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + let buy_token = *token.address(); + + // Anvil starts with a hardcoded timestamp of Jan 1, 2020 (see nodes/mod.rs). + // The autopilot validates orders against real-world time, so valid_to must + // exceed the current wall clock (which also exceeds anvil's simulated time). + let valid_to = Utc::now().timestamp() as u32 + 3600; + + let (ethflow_order, order_id, valid_to) = + EthflowOrderBuilder::new(&services, &onchain, &user, buy_token) + .with_sell_amount(NonZeroU256::try_from(1u64.eth()).unwrap()) + .with_slippage_bps(300) + .with_valid_to(valid_to) + .create_and_index() + .await; + + let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); + + wait_for_order_settlement(&services, &onchain, &order_id).await; + + tracing::info!("Order was settled. Now advancing time past expiration."); + advance_time_past_expiration(&web3, valid_to).await; + + // Verify the order is NOT invalidated on-chain (it was settled, not + // invalidated) + assert_ne!( + ethflow_order + .status(onchain.contracts(), ethflow_contract) + .await, + RefundStatus::Refunded, + "Settled order should not be invalidated on-chain" + ); + + let mut refund_service = RefundService::from_components( + services.db().clone(), + web3.clone(), + vec![*ethflow_contract.address()], + 0, // min_validity_duration = 0 (permissive) + 0, // min_price_deviation_bps = 0 (permissive) + refunder_account.signer, + MAX_GAS_PRICE, + START_PRIORITY_FEE_TIP, + None, + ); + + // Run the refunder - it should NOT try to refund this already-settled order + refund_service + .try_to_refund_all_eligible_orders() .await - .expect("Must be able to set block timestamp"); - // mine next block to push time forward - web3.api::>() - .mine_pending_block() + .unwrap(); + + // The order should still NOT be invalidated (refunder skipped it) + assert_ne!( + ethflow_order + .status(onchain.contracts(), ethflow_contract) + .await, + RefundStatus::Refunded, + "Refunder should not have invalidated the already-settled order" + ); + + // Verify no refund TX was recorded + let order = services.get_order(&order_id).await.unwrap(); + assert!( + order + .metadata + .ethflow_data + .unwrap() + .refund_tx_hash + .is_none(), + "Refunder should not have created a refund TX for an already-settled order" + ); +} + +/// Tests that the refunder can process orders from multiple ethflow contracts. +/// +/// Orders won't settle because they use blockchain time for `valid_to`, making +/// them appear expired to the autopilot. This isolation allows the test to +/// focus on verifying multi-contract refund processing without settlement +/// complexity. +#[ignore] +#[tokio::test] +async fn local_node_refunder_multiple_ethflow_contracts() { + run_test(refunder_multiple_ethflow_contracts).await; +} + +async fn refunder_multiple_ethflow_contracts(web3: Web3) { + // This test creates orders on TWO different ethflow contracts + // to verify the refunder can handle multiple contracts. + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [user, refunder] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + let buy_token = *token.address(); + + let validity_duration = 600u32; + let valid_to = timestamp_of_current_block_in_seconds(&web3.provider) .await - .expect("Unable to mine next block"); + .unwrap() + + validity_duration; - // Create the refund service and execute the refund tx - let pg_pool = PgPool::connect_lazy("postgresql://").expect("failed to create database"); - let refunder_signer = { - match refunder.account().clone().try_into_alloy().await.unwrap() { - ethrpc::alloy::Account::Signer(signer) => signer, - _ => panic!("Refunder account must be a signer"), - } - }; - let mut refunder = RefundService::new( - pg_pool, + // Create first order on primary ethflow contract (index 0) + let (ethflow_order, order_id, valid_to) = + EthflowOrderBuilder::new(&services, &onchain, &user, buy_token) + .with_slippage_bps(500) + .with_valid_to(valid_to) + .with_ethflow_index(0) + .create_and_index() + .await; + + // Create second order on secondary ethflow contract (index 1) + let (ethflow_order_2, order_id_2, _) = + EthflowOrderBuilder::new(&services, &onchain, &user, buy_token) + .with_slippage_bps(500) + .with_valid_to(valid_to) + .with_ethflow_index(1) + .create_and_index() + .await; + + let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); + let ethflow_contract_2 = onchain.contracts().ethflows.get(1).unwrap(); + + advance_time_past_expiration(&web3, valid_to).await; + + let mut refund_service = RefundService::from_components( + services.db().clone(), web3, - vec![ethflow_contract.clone(), ethflow_contract_2.clone()], + vec![*ethflow_contract.address(), *ethflow_contract_2.address()], validity_duration as i64 / 2, - 10i64, - refunder_signer, - 2_000_000_000_000, // max_gas_price: 2000 Gwei - 30_000_000_000, // start_priority_fee_tip: 30 Gwei + 10, + refunder.signer, + MAX_GAS_PRICE, + START_PRIORITY_FEE_TIP, + None, ); + // Verify orders are not yet refunded assert_ne!( ethflow_order .status(onchain.contracts(), ethflow_contract) .await, - EthFlowOrderOnchainStatus::Invalidated + RefundStatus::Refunded ); assert_ne!( ethflow_order_2 .status(onchain.contracts(), ethflow_contract_2) .await, - EthFlowOrderOnchainStatus::Invalidated + RefundStatus::Refunded ); - refunder.try_to_refund_all_eligble_orders().await.unwrap(); + refund_service + .try_to_refund_all_eligible_orders() + .await + .unwrap(); + // Both orders should now be refunded assert_eq!( ethflow_order .status(onchain.contracts(), ethflow_contract) .await, - EthFlowOrderOnchainStatus::Invalidated + RefundStatus::Refunded ); assert_eq!( ethflow_order_2 .status(onchain.contracts(), ethflow_contract_2) .await, - EthFlowOrderOnchainStatus::Invalidated + RefundStatus::Refunded ); + // Wait for autopilot to index refund tx hashes tracing::info!("Waiting for autopilot to index refund tx hash."); for order in &[order_id, order_id_2] { let has_tx_hash = || async { diff --git a/crates/e2e/tests/e2e/replace_order.rs b/crates/e2e/tests/e2e/replace_order.rs index 979e532ce2..2856a67123 100644 --- a/crates/e2e/tests/e2e/replace_order.rs +++ b/crates/e2e/tests/e2e/replace_order.rs @@ -1,28 +1,70 @@ use { ::alloy::primitives::U256, - e2e::{ - nodes::local_node::TestNodeApi, - setup::{eth, *}, - }, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + configs::test_util::TestDefault, + e2e::setup::*, + ethrpc::alloy::{CallBuilderExt, EvmProviderExt}, model::{ order::{OrderCreation, OrderCreationAppData, OrderKind, OrderStatus}, signature::EcdsaSigningScheme, }, + number::units::EthUnit, orderbook::{ - api::IntoWarpReply, + api::Error as ApiError, orderbook::{OrderCancellationError, OrderReplacementError}, }, reqwest::StatusCode, - secp256k1::SecretKey, - shared::ethrpc::Web3, - warp::reply::Reply, - web3::signing::SecretKeyRef, + shared::web3::Web3, }; +// Parse OrderReplacementError from HTTP response +// Flow: JSON -> orderbook::api::Error -> OrderReplacementError +// Note: Returns None for unknown error types (cannot construct Other variant +// without anyhow::Error) +fn parse_order_replacement_error(status: StatusCode, body: &str) -> Option { + let error: ApiError = serde_json::from_str(body).ok()?; + + match status { + StatusCode::BAD_REQUEST => match error.error_type.as_ref() { + "InvalidSignature" => Some(OrderReplacementError::InvalidSignature), + "OldOrderActivelyBidOn" => Some(OrderReplacementError::OldOrderActivelyBidOn), + _ => None, + }, + StatusCode::UNAUTHORIZED if error.error_type == "WrongOwner" => { + Some(OrderReplacementError::WrongOwner) + } + _ => None, + } +} + +// Parse OrderCancellationError from HTTP response +// Flow: JSON -> orderbook::api::Error -> OrderCancellationError +// Note: Returns None for unknown error types (cannot construct Other variant +// without anyhow::Error) +fn parse_order_cancellation_error( + status: StatusCode, + body: &str, +) -> Option { + let error: ApiError = serde_json::from_str(body).ok()?; + + match status { + StatusCode::BAD_REQUEST => match error.error_type.as_ref() { + "InvalidSignature" => Some(OrderCancellationError::InvalidSignature), + "AlreadyCancelled" => Some(OrderCancellationError::AlreadyCancelled), + "OrderFullyExecuted" => Some(OrderCancellationError::OrderFullyExecuted), + "OrderExpired" => Some(OrderCancellationError::OrderExpired), + "OnChainOrder" => Some(OrderCancellationError::OnChainOrder), + _ => None, + }, + StatusCode::NOT_FOUND if error.error_type == "OrderNotFound" => { + Some(OrderCancellationError::OrderNotFound) + } + StatusCode::UNAUTHORIZED if error.error_type == "WrongOwner" => { + Some(OrderCancellationError::WrongOwner) + } + _ => None, + } +} + #[tokio::test] #[ignore] async fn local_node_replace_order() { @@ -44,37 +86,43 @@ async fn local_node_try_replace_executed_order() { async fn try_replace_unreplaceable_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts - token_a.mint(trader.address(), to_wei(30)).await; + token_a.mint(trader.address(), 30u64.eth()).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -84,14 +132,14 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { .addLiquidity( *token_a.address(), *token_b.address(), - eth(1000), - eth(1000), + 1000u64.eth(), + 1000u64.eth(), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -99,27 +147,24 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 15u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); // disable auto mining to prevent order being immediately executed - web3.api::>() - .set_automine_enabled(false) - .await - .unwrap(); + web3.provider.evm_set_automine(false).await.unwrap(); // Place Orders let services = Services::new(&onchain).await; services.start_protocol(solver).await; let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *token_b.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -127,13 +172,9 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); - let balance_before = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_a.balanceOf(trader.address()).call().await.unwrap(); onchain.mint_block().await; let order_id = services.create_order(&order).await.unwrap(); @@ -151,10 +192,10 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { // Replace order let new_order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(3), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 3u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: false, @@ -168,37 +209,31 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let response = services.create_order(&new_order).await; let (error_code, error_message) = response.err().unwrap(); assert_eq!(error_code, StatusCode::BAD_REQUEST); - - let expected_response = OrderReplacementError::OldOrderActivelyBidOn - .into_warp_reply() - .into_response() - .into_body(); - let expected_body_bytes = warp::hyper::body::to_bytes(expected_response) - .await - .unwrap(); - let expected_body = String::from_utf8(expected_body_bytes.to_vec()).unwrap(); - assert_eq!(error_message, expected_body); + let parsed_error = parse_order_replacement_error(error_code, &error_message) + .expect("Failed to parse error response"); + assert!( + matches!(parsed_error, OrderReplacementError::OldOrderActivelyBidOn), + "Expected OldOrderActivelyBidOn error, got: {:?} (body: {})", + parsed_error, + error_message + ); // Continue automining so our order can be executed - web3.api::>() - .set_automine_enabled(true) + web3.provider + .evm_set_automine(true) .await .expect("Must be able to disable auto-mining"); tracing::info!("Waiting for the old order to be executed"); wait_for_condition(TIMEOUT, || async { - let balance_after = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - balance_before.saturating_sub(balance_after) == eth(10) + let balance_after = token_a.balanceOf(trader.address()).call().await.unwrap(); + balance_before.saturating_sub(balance_after) == 10u64.eth() && !services.get_trades(&order_id).await.unwrap().is_empty() }) .await @@ -210,52 +245,57 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { let (error_code, error_message) = response.err().unwrap(); assert_eq!(error_code, StatusCode::BAD_REQUEST); - let expected_response = OrderCancellationError::OrderFullyExecuted - .into_warp_reply() - .into_response() - .into_body(); - let expected_body_bytes = warp::hyper::body::to_bytes(expected_response) - .await - .unwrap(); - let expected_body = String::from_utf8(expected_body_bytes.to_vec()).unwrap(); - assert_eq!(error_message, expected_body); + let parsed_error = parse_order_cancellation_error(error_code, &error_message) + .expect("Failed to parse error response"); + assert!( + matches!(parsed_error, OrderCancellationError::OrderFullyExecuted), + "Expected OrderFullyExecuted error, got: {:?} (body: {})", + parsed_error, + error_message + ); } async fn try_replace_someone_else_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a, trader_b] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(30)).await; - token_a.mint(trader_b.address(), to_wei(30)).await; + token_a.mint(trader_a.address(), 30u64.eth()).await; + token_a.mint(trader_b.address(), 30u64.eth()).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -265,14 +305,14 @@ async fn try_replace_someone_else_order_test(web3: Web3) { .addLiquidity( *token_a.address(), *token_b.address(), - eth(1000), - eth(1000), + 1000u64.eth(), + 1000u64.eth(), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -280,15 +320,15 @@ async fn try_replace_someone_else_order_test(web3: Web3) { // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 15u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader_b.address().into_alloy()) + .approve(onchain.contracts().allowance, 15u64.eth()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -300,10 +340,10 @@ async fn try_replace_someone_else_order_test(web3: Web3) { onchain.mint_block().await; let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *token_b.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, partially_fillable: false, kind: OrderKind::Sell, @@ -312,16 +352,16 @@ async fn try_replace_someone_else_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); let order_id = services.create_order(&order).await.unwrap(); // Replace order let new_order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(3), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 3u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: false, @@ -335,13 +375,9 @@ async fn try_replace_someone_else_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()), + &trader_b.signer, ); - let balance_before = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_a.balanceOf(trader_a.address()).call().await.unwrap(); let response = services.create_order(&new_order).await; let (error_code, _) = response.err().unwrap(); assert_eq!(error_code, StatusCode::UNAUTHORIZED); @@ -350,12 +386,8 @@ async fn try_replace_someone_else_order_test(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { onchain.mint_block().await; - let balance_after = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - balance_before.saturating_sub(balance_after) == eth(10) + let balance_after = token_a.balanceOf(trader_a.address()).call().await.unwrap(); + balance_before.saturating_sub(balance_after) == 10u64.eth() }) .await .unwrap(); @@ -364,37 +396,43 @@ async fn try_replace_someone_else_order_test(web3: Web3) { async fn single_replace_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts - token_a.mint(trader.address(), to_wei(30)).await; + token_a.mint(trader.address(), 30u64.eth()).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), 1000u64.eth()).await; + token_b.mint(solver.address(), 1000u64.eth()).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .approve( + *onchain.contracts().uniswap_v2_router.address(), + 1000u64.eth(), + ) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -404,14 +442,14 @@ async fn single_replace_order_test(web3: Web3) { .addLiquidity( *token_a.address(), *token_b.address(), - eth(1000), - eth(1000), + 1000u64.eth(), + 1000u64.eth(), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -419,8 +457,8 @@ async fn single_replace_order_test(web3: Web3) { // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 15u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -430,29 +468,30 @@ async fn single_replace_order_test(web3: Web3) { onchain.set_solver_allowed(solver.address(), false).await; let services = Services::new(&onchain).await; + // To avoid race conditions we have to start the protocol + // with the solver being banned. To allow us to still create + // orders we override the quote verification to prefer mode. + let orderbook_config = configs::orderbook::Configuration { + price_estimation: configs::price_estimation::PriceEstimation { + quote_verification: configs::price_estimation::QuoteVerificationMode::Prefer, + ..configs::orderbook::Configuration::test_default().price_estimation + }, + ..configs::orderbook::Configuration::test_default() + }; services .start_protocol_with_args( - ExtraServiceArgs { - // To avoid race conditions we have to start the protocol - // with the solver being banned. To allow us to still create - // orders we override the quote verification to be disabled. - api: vec!["--quote-verification=prefer".into()], - ..Default::default() - }, + configs::autopilot::Configuration::test("test_solver", solver.address()), + orderbook_config, solver.clone(), ) .await; - let balance_before = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_a.balanceOf(trader.address()).call().await.unwrap(); let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *token_b.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -460,7 +499,7 @@ async fn single_replace_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let order_id = services.create_order(&order).await.unwrap(); @@ -478,10 +517,10 @@ async fn single_replace_order_test(web3: Web3) { // Replace order let new_order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(3), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 3u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: false, @@ -493,7 +532,7 @@ async fn single_replace_order_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let new_order_uid = services.create_order(&new_order).await.unwrap(); @@ -526,13 +565,9 @@ async fn single_replace_order_test(web3: Web3) { // Drive solution to verify that new order can be settled tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = token_a.balanceOf(trader.address()).call().await.unwrap(); onchain.mint_block().await; - balance_before.saturating_sub(balance_after) == eth(3) + balance_before.saturating_sub(balance_after) == 3u64.eth() }) .await .unwrap(); diff --git a/crates/e2e/tests/e2e/smart_contract_orders.rs b/crates/e2e/tests/e2e/smart_contract_orders.rs index eb17c02e2e..e6dab581ca 100644 --- a/crates/e2e/tests/e2e/smart_contract_orders.rs +++ b/crates/e2e/tests/e2e/smart_contract_orders.rs @@ -1,16 +1,15 @@ use { - e2e::setup::{eth, safe::Safe, *}, - ethcontract::{H160, U256}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ::alloy::primitives::{Address, U256}, + configs::{orderbook::order_validation::OrderValidationConfig, test_util::TestDefault}, + e2e::setup::{safe::Safe, *}, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderCreationAppData, OrderKind, OrderStatus, OrderUid}, signature::Signature, }, + number::units::EthUnit, reqwest::StatusCode, - shared::ethrpc::Web3, + shared::web3::Web3, }; #[tokio::test] @@ -28,20 +27,20 @@ async fn local_node_max_gas_limit() { async fn smart_contract_orders(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; - let safe = Safe::deploy(trader, web3.alloy.clone()).await; + let safe = Safe::deploy(trader, web3.provider.clone()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) + .deploy_tokens_with_weth_uni_v2_pools(100_000u64.eth(), 100_000u64.eth()) .await; - token.mint(safe.address().into_legacy(), to_wei(10)).await; + token.mint(safe.address(), 10u64.eth()).await; // Approve GPv2 for trading safe.exec_alloy_call( token - .approve(onchain.contracts().allowance.into_alloy(), eth(10)) + .approve(onchain.contracts().allowance, 10u64.eth()) .into_transaction_request(), ) .await; @@ -51,10 +50,10 @@ async fn smart_contract_orders(web3: Web3) { let order_template = OrderCreation { kind: OrderKind::Sell, - sell_token: token.address().into_legacy(), - sell_amount: to_wei(5), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(3), + sell_token: *token.address(), + sell_amount: 5u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, ..Default::default() }; @@ -63,12 +62,12 @@ async fn smart_contract_orders(web3: Web3) { // Check that we can't place invalid orders. let orders = [ OrderCreation { - from: Some(safe.address().into_legacy()), + from: Some(safe.address()), signature: Signature::Eip1271(b"invalid signature".to_vec()), ..order_template.clone() }, OrderCreation { - from: Some(H160(*b"invalid address\0\0\0\0\0")), + from: Some(Address::new(*b"invalid address\0\0\0\0\0")), signature: Signature::Eip1271(signature1271.clone()), ..order_template.clone() }, @@ -81,7 +80,7 @@ async fn smart_contract_orders(web3: Web3) { // Place orders let orders = [ OrderCreation { - from: Some(safe.address().into_legacy()), + from: Some(safe.address()), signature: Signature::Eip1271(signature1271), ..order_template.clone() }, @@ -89,7 +88,7 @@ async fn smart_contract_orders(web3: Web3) { app_data: OrderCreationAppData::Full { full: "{\"salt\": \"second\"}".to_string(), }, - from: Some(safe.address().into_legacy()), + from: Some(safe.address()), signature: Signature::PreSign, ..order_template.clone() }, @@ -147,7 +146,7 @@ async fn smart_contract_orders(web3: Web3) { .await .expect("Couldn't fetch native token balance"); - token_balance.is_zero() && weth_balance > eth(6) + token_balance.is_zero() && weth_balance > 6u64.eth() }) .await .unwrap(); @@ -156,24 +155,20 @@ async fn smart_contract_orders(web3: Web3) { async fn erc1271_gas_limit(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let trader = contracts::alloy::test::GasHog::Instance::deploy(web3.alloy.clone()) + let [solver] = onchain.make_solvers(1u64.eth()).await; + let trader = contracts::test::GasHog::Instance::deploy(web3.provider.clone()) .await .unwrap(); let cow = onchain - .deploy_cow_weth_pool(to_wei(1_000_000), to_wei(1_000), to_wei(1_000)) + .deploy_cow_weth_pool(1_000_000u64.eth(), 1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader accounts and approve relayer - cow.fund(trader.address().into_legacy(), to_wei(5)).await; + cow.fund(*trader.address(), 5u64.eth()).await; trader - .approve( - *cow.address(), - onchain.contracts().allowance.into_alloy(), - eth(10), - ) - .from(solver.address().into_alloy()) + .approve(*cow.address(), onchain.contracts().allowance, 10u64.eth()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -181,27 +176,30 @@ async fn erc1271_gas_limit(web3: Web3) { let services = Services::new(&onchain).await; services .start_protocol_with_args( - ExtraServiceArgs { - api: vec!["--max-gas-per-order=1000000".to_string()], - ..Default::default() + configs::autopilot::Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + order_validation: OrderValidationConfig { + max_gas_per_order: 1_000_000, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() }, solver, ) .await; // Use 1M gas units during signature verification - let mut signature = [0; 32]; - U256::exp10(6).to_big_endian(&mut signature); + let signature = U256::from(1_000_000).to_be_bytes::<32>(); let order = OrderCreation { - sell_token: cow.address().into_legacy(), - sell_amount: to_wei(4), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(3), + sell_token: *cow.address(), + sell_amount: 4u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 3u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, signature: Signature::Eip1271(signature.to_vec()), - from: Some(trader.address().into_legacy()), + from: Some(*trader.address()), ..Default::default() }; diff --git a/crates/e2e/tests/e2e/solver_competition.rs b/crates/e2e/tests/e2e/solver_competition.rs index 85dcbcd069..4004436dcb 100644 --- a/crates/e2e/tests/e2e/solver_competition.rs +++ b/crates/e2e/tests/e2e/solver_competition.rs @@ -1,19 +1,26 @@ use { - ::alloy::primitives::U256, - e2e::setup::{colocation::SolverEngine, eth, mock::Mock, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + ::alloy::primitives::{U256, address}, + configs::{ + autopilot::{ + Configuration, + run_loop::RunLoopConfig, + solver::{Account, Solver}, + }, + order_quoting::{ExternalSolver, OrderQuoting}, + test_util::TestDefault, }, + e2e::setup::{colocation::SolverEngine, mock::Mock, *}, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, + number::units::EthUnit, + reqwest::StatusCode, + shared::web3::Web3, solvers_dto::solution::Solution, - std::collections::HashMap, - web3::signing::SecretKeyRef, + std::{collections::HashMap, str::FromStr}, + url::Url, }; #[tokio::test] @@ -37,21 +44,21 @@ async fn local_node_store_filtered_solutions() { async fn solver_competition(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token_a] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund trader, settlement accounts, and pool creation - token_a.mint(trader.address(), to_wei(10)).await; - token_a.mint(solver.address(), to_wei(1000)).await; + token_a.mint(trader.address(), 10u64.eth()).await; + token_a.mint(solver.address(), 1000u64.eth()).await; // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -84,24 +91,45 @@ async fn solver_competition(web3: Web3) { ); let services = Services::new(&onchain).await; - services.start_autopilot( - None, - vec![ - format!("--drivers=test_solver|http://localhost:11088/test_solver|{},solver2|http://localhost:11088/solver2|{}", const_hex::encode(solver.address()), const_hex::encode(solver.address()) - ), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver,solver2|http://localhost:11088/solver2".to_string(), - ], - ).await; - services.start_api(vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver,solver2|http://localhost:11088/solver2".to_string(), - ]).await; + + let base_config = Configuration::test_no_drivers(); + services + .start_autopilot( + None, + Configuration { + drivers: vec![ + Solver::test("test_solver", solver.address()), + Solver::test("solver2", solver.address()), + ], + order_quoting: OrderQuoting::test_with_drivers(vec![ + ExternalSolver::new("test_quoter", "http://localhost:11088/test_solver"), + ExternalSolver::new("solver2", "http://localhost:11088/solver2"), + ]), + run_loop: RunLoopConfig { + submission_deadline: 3, + ..base_config.run_loop + }, + ..base_config + }, + ) + .await; + services + .start_api(configs::orderbook::Configuration { + hide_competition_before_deadline: true, + order_quoting: OrderQuoting::test_with_drivers(vec![ + ExternalSolver::new("test_quoter", "http://localhost:11088/test_solver"), + ExternalSolver::new("solver2", "http://localhost:11088/solver2"), + ]), + ..configs::orderbook::Configuration::test_default() + }) + .await; // Place Order let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -109,7 +137,7 @@ async fn solver_competition(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let uid = services.create_order(&order).await.unwrap(); onchain.mint_block().await; @@ -117,19 +145,44 @@ async fn solver_competition(web3: Web3) { tracing::info!("waiting for trade"); let trade_happened = || async { token_a - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap() - == U256::ZERO + .is_zero() }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); + // Competition data is saved before the settlement tx, so it is already in + // the DB. The deadline hasn't passed yet → 404. + assert_eq!( + services.get_latest_solver_competition().await.unwrap_err(), + StatusCode::NOT_FOUND, + ); + + // The internal (unfiltered) endpoint returns the data regardless. + let auction_id: i64 = { + let mut db = services.db().acquire().await.unwrap(); + sqlx::query_scalar("SELECT id FROM competition_auctions ORDER BY id DESC LIMIT 1") + .fetch_one(&mut *db) + .await + .unwrap() + }; + assert!( + services + .get_solver_competition_unfiltered(auction_id) + .await + .is_ok() + ); + + // The indexed_trades poll mints a block on every iteration, which will + // advance past the 3-block deadline while also waiting for the event + // indexer to pick up the settlement. let indexed_trades = || async { onchain.mint_block().await; match services.get_trades(&uid).await.unwrap().first() { Some(trade) => services - .get_solver_competition(trade.tx_hash.unwrap().into_legacy()) + .get_solver_competition(trade.tx_hash.unwrap()) .await .is_ok(), None => false, @@ -139,7 +192,7 @@ async fn solver_competition(web3: Web3) { let trades = services.get_trades(&uid).await.unwrap(); let competition = services - .get_solver_competition(trades[0].tx_hash.unwrap().into_legacy()) + .get_solver_competition(trades[0].tx_hash.unwrap()) .await .unwrap(); @@ -156,41 +209,41 @@ async fn solver_competition(web3: Web3) { async fn wrong_solution_submission_address(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader_a, trader_b] = onchain.make_accounts(1u64.eth()).await; let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; // Fund traders - token_a.mint(trader_a.address(), to_wei(10)).await; - token_b.mint(trader_b.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), 10u64.eth()).await; + token_b.mint(trader_b.address(), 10u64.eth()).await; // Create more liquid routes between token_a (token_b) and weth via base_a // (base_b). base_a has more liquidity then base_b, leading to the solver that // knows about base_a to win let [base_a, base_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(10_000), to_wei(10_000)) + .deploy_tokens_with_weth_uni_v2_pools(10_000u64.eth(), 10_000u64.eth()) .await; onchain - .seed_uni_v2_pool((&token_a, to_wei(100_000)), (&base_a, to_wei(100_000))) + .seed_uni_v2_pool((&token_a, 100_000u64.eth()), (&base_a, 100_000u64.eth())) .await; onchain - .seed_uni_v2_pool((&token_b, to_wei(10_000)), (&base_b, to_wei(10_000))) + .seed_uni_v2_pool((&token_b, 10_000u64.eth()), (&base_b, 10_000u64.eth())) .await; // Approve GPv2 for trading token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_b - .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_b.address().into_alloy()) + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -204,7 +257,7 @@ async fn wrong_solution_submission_address(web3: Web3) { "test_solver".into(), solver.clone(), *onchain.contracts().weth.address(), - vec![base_a.address().into_legacy()], + vec![*base_a.address()], 1, true, ) @@ -213,7 +266,7 @@ async fn wrong_solution_submission_address(web3: Web3) { "solver2".into(), solver.clone(), *onchain.contracts().weth.address(), - vec![base_b.address().into_legacy()], + vec![*base_b.address()], 1, true, ) @@ -224,26 +277,45 @@ async fn wrong_solution_submission_address(web3: Web3) { ); let services = Services::new(&onchain).await; - services.start_autopilot( - None, - // Solver 1 has a wrong submission address, meaning that the solutions should be discarded from solver1 - vec![ - format!("--drivers=solver1|http://localhost:11088/test_solver|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2,solver2|http://localhost:11088/solver2|{}", const_hex::encode(solver.address())), - "--price-estimation-drivers=solver1|http://localhost:11088/test_solver".to_string(), - ], - ).await; + + services + .start_autopilot( + None, + Configuration { + drivers: vec![ + // Solver 1 has a wrong submission address, meaning that the solutions should + // be discarded from solver1 + Solver::new( + "solver1".to_string(), + Url::from_str("http://localhost:11088/test_solver").unwrap(), + Account::Address(address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")), + ), + Solver::test("solver2", solver.address()), + ], + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "solver1", + "http://localhost:11088/test_solver", + )]), + ..Configuration::test_no_drivers() + }, + ) + .await; services - .start_api(vec![ - "--price-estimation-drivers=solver1|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "solver1", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Place Orders let order_a = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_a.address(), + sell_amount: 10u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -251,17 +323,17 @@ async fn wrong_solution_submission_address(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); let uid_a = services.create_order(&order_a).await.unwrap(); onchain.mint_block().await; let order_b = OrderCreation { - sell_token: token_b.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(5), + sell_token: *token_b.address(), + sell_amount: 10u64.eth(), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 5u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -269,7 +341,7 @@ async fn wrong_solution_submission_address(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()), + &trader_b.signer, ); services.create_order(&order_b).await.unwrap(); @@ -278,7 +350,7 @@ async fn wrong_solution_submission_address(web3: Web3) { onchain.mint_block().await; match services.get_trades(&uid_a).await.unwrap().first() { Some(trade) => services - .get_solver_competition(trade.tx_hash.unwrap().into_legacy()) + .get_solver_competition(trade.tx_hash.unwrap()) .await .is_ok(), None => false, @@ -289,13 +361,13 @@ async fn wrong_solution_submission_address(web3: Web3) { // Verify that test_solver was excluded due to wrong driver address let trades = services.get_trades(&uid_a).await.unwrap(); let competition = services - .get_solver_competition(trades[0].tx_hash.unwrap().into_legacy()) + .get_solver_competition(trades[0].tx_hash.unwrap()) .await .unwrap(); tracing::info!(?competition, "competition"); assert_eq!( competition.solutions.last().unwrap().solver_address, - solver.address().into_alloy() + solver.address() ); assert_eq!(competition.solutions.len(), 1); } @@ -303,48 +375,38 @@ async fn wrong_solution_submission_address(web3: Web3) { async fn store_filtered_solutions(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [good_solver_account, bad_solver_account] = onchain.make_solvers(to_wei(100)).await; - let [trader] = onchain.make_accounts(to_wei(100)).await; + let [good_solver_account, bad_solver_account] = onchain.make_solvers(100u64.eth()).await; + let [trader] = onchain.make_accounts(100u64.eth()).await; let [token_a, token_b, token_c] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(300_000u64.eth(), 1_000u64.eth()) .await; // give the settlement contract a ton of the traded tokens so that the mocked // solver solutions can simply give money away to make the trade execute token_b - .mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(50), - ) + .mint(*onchain.contracts().gp_settlement.address(), 50u64.eth()) .await; token_c - .mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(50), - ) + .mint(*onchain.contracts().gp_settlement.address(), 50u64.eth()) .await; // set up trader for their order - token_a.mint(trader.address(), to_wei(2)).await; + token_a.mint(trader.address(), 2u64.eth()).await; token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(2)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 2u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); let services = Services::new(&onchain).await; - let good_solver = Mock::default(); - let bad_solver = Mock::default(); + let good_solver = Mock::new().await; + let bad_solver = Mock::new().await; // Start system - let base_tokens = vec![ - token_a.address().into_legacy(), - token_b.address().into_legacy(), - token_c.address().into_legacy(), - ]; + let base_tokens = vec![*token_a.address(), *token_b.address(), *token_c.address()]; colocation::start_driver( onchain.contracts(), vec![ @@ -363,6 +425,8 @@ async fn store_filtered_solutions(web3: Web3) { endpoint: good_solver.url.clone(), base_tokens: base_tokens.clone(), merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, SolverEngine { name: "bad_solver".into(), @@ -370,6 +434,8 @@ async fn store_filtered_solutions(web3: Web3) { endpoint: bad_solver.url.clone(), base_tokens, merge_solutions: true, + haircut_bps: 0, + submission_keys: vec![], }, ], colocation::LiquidityProvider::UniswapV2, @@ -378,33 +444,43 @@ async fn store_filtered_solutions(web3: Web3) { // We start the quoter as the baseline solver, and the mock solver as the one // returning the solution + let config = Configuration::test_no_drivers(); services .start_autopilot( None, - vec![ - format!( - "--drivers=good_solver|http://localhost:11088/good_solver|{},bad_solver|http://localhost:11088/bad_solver|{}", - const_hex::encode(good_solver_account.address()), - const_hex::encode(bad_solver_account.address()), - ), - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver" - .to_string(), - "--max-winners-per-auction=10".to_string(), - ], + Configuration { + drivers: vec![ + Solver::test("good_solver", good_solver_account.address()), + Solver::test("bad_solver", bad_solver_account.address()), + ], + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + run_loop: RunLoopConfig { + max_winners_per_auction: std::num::NonZeroUsize::new(10).unwrap(), + ..config.run_loop + }, + ..config + }, ) .await; services - .start_api(vec![ - "--price-estimation-drivers=test_solver|http://localhost:11088/test_solver".to_string(), - ]) + .start_api(configs::orderbook::Configuration { + order_quoting: OrderQuoting::test_with_drivers(vec![ExternalSolver::new( + "test_solver", + "http://localhost:11088/test_solver", + )]), + ..configs::orderbook::Configuration::test_default() + }) .await; // Place order let order_ab = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(1), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 1u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -412,14 +488,14 @@ async fn store_filtered_solutions(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let order_ac = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(1), - buy_token: token_c.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *token_a.address(), + sell_amount: 1u64.eth(), + buy_token: *token_c.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -427,7 +503,7 @@ async fn store_filtered_solutions(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let order_ab_id = services.create_order(&order_ab).await.unwrap(); @@ -446,13 +522,13 @@ async fn store_filtered_solutions(web3: Web3) { good_solver.configure_solution(Some(Solution { id: 0, prices: HashMap::from([ - (token_a.address().into_legacy(), to_wei(3)), - (token_b.address().into_legacy(), to_wei(1)), + (*token_a.address(), 3u64.eth()), + (*token_b.address(), 1u64.eth()), ]), trades: vec![solvers_dto::solution::Trade::Fulfillment( solvers_dto::solution::Fulfillment { executed_amount: order_ab.sell_amount, - fee: Some(0.into()), + fee: Some(::alloy::primitives::U256::ZERO), order: solvers_dto::solution::OrderUid(order_ab_id.0), }, )], @@ -462,6 +538,7 @@ async fn store_filtered_solutions(web3: Web3) { gas: None, flashloans: None, wrappers: vec![], + gas_fee_override: None, })); // bad solver settles both orders at 2:1. Because it can't beat the @@ -470,19 +547,19 @@ async fn store_filtered_solutions(web3: Web3) { bad_solver.configure_solution(Some(Solution { id: 0, prices: HashMap::from([ - (token_a.address().into_legacy(), to_wei(2)), - (token_b.address().into_legacy(), to_wei(1)), - (token_c.address().into_legacy(), to_wei(1)), + (*token_a.address(), 2u64.eth()), + (*token_b.address(), 1u64.eth()), + (*token_c.address(), 1u64.eth()), ]), trades: vec![ solvers_dto::solution::Trade::Fulfillment(solvers_dto::solution::Fulfillment { executed_amount: order_ab.sell_amount, - fee: Some(0.into()), + fee: Some(::alloy::primitives::U256::ZERO), order: solvers_dto::solution::OrderUid(order_ab_id.0), }), solvers_dto::solution::Trade::Fulfillment(solvers_dto::solution::Fulfillment { executed_amount: order_ac.sell_amount, - fee: Some(0.into()), + fee: Some(::alloy::primitives::U256::ZERO), order: solvers_dto::solution::OrderUid(order_ac_id.0), }), ], @@ -492,6 +569,7 @@ async fn store_filtered_solutions(web3: Web3) { gas: None, flashloans: None, wrappers: vec![], + gas_fee_override: None, })); // Drive solution @@ -501,7 +579,7 @@ async fn store_filtered_solutions(web3: Web3) { let trade = services.get_trades(&order_ab_id).await.unwrap().pop()?; Some( services - .get_solver_competition(trade.tx_hash?.into_legacy()) + .get_solver_competition(trade.tx_hash?) .await .is_ok(), ) @@ -517,7 +595,7 @@ async fn store_filtered_solutions(web3: Web3) { .unwrap(); let competition = services - .get_solver_competition(trade.tx_hash.unwrap().into_legacy()) + .get_solver_competition(trade.tx_hash.unwrap()) .await .unwrap(); @@ -529,8 +607,8 @@ async fn store_filtered_solutions(web3: Web3) { assert_eq!( competition .reference_scores - .get(&good_solver_account.address().into_alloy()), - Some(&0.into()) + .get(&good_solver_account.address()), + Some(&U256::ZERO) ); assert_eq!(competition.solutions.len(), 2); @@ -540,10 +618,7 @@ async fn store_filtered_solutions(web3: Web3) { assert_eq!(bad_solution.ranking, 2); assert!(bad_solution.filtered_out); assert!(!bad_solution.is_winner); - assert_eq!( - bad_solution.solver_address, - bad_solver_account.address().into_alloy() - ); + assert_eq!(bad_solution.solver_address, bad_solver_account.address()); assert!(bad_solution.tx_hash.is_none()); assert!(bad_solution.reference_score.is_none()); @@ -551,13 +626,10 @@ async fn store_filtered_solutions(web3: Web3) { assert_eq!(good_solution.ranking, 1); assert!(!good_solution.filtered_out); assert!(good_solution.is_winner); - assert_eq!( - good_solution.solver_address, - good_solver_account.address().into_alloy() - ); + assert_eq!(good_solution.solver_address, good_solver_account.address()); assert_eq!(good_solution.tx_hash.unwrap(), trade.tx_hash.unwrap()); // since the only other solutions were unfair the reference score is zero - assert_eq!(good_solution.reference_score, Some(0.into())); + assert_eq!(good_solution.reference_score, Some(U256::ZERO)); // check that new DB tables contain the filtered solution let mut db = services.db().acquire().await.unwrap(); diff --git a/crates/e2e/tests/e2e/solver_participation_guard.rs b/crates/e2e/tests/e2e/solver_participation_guard.rs deleted file mode 100644 index dcc1e34ebe..0000000000 --- a/crates/e2e/tests/e2e/solver_participation_guard.rs +++ /dev/null @@ -1,374 +0,0 @@ -use { - alloy::primitives::U256, - e2e::setup::{ - Db, - ExtraServiceArgs, - MintableToken, - OnchainComponents, - Services, - TIMEOUT, - TestAccount, - eth, - run_test, - to_wei, - wait_for_condition, - }, - ethrpc::{ - Web3, - alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, - }, - model::{ - order::{OrderClass, OrderCreation, OrderKind}, - signature::EcdsaSigningScheme, - }, - secp256k1::SecretKey, - sqlx::Row, - std::time::Instant, - web3::{signing::SecretKeyRef, types::H160}, -}; - -#[tokio::test] -#[ignore] -async fn local_node_non_settling_solver() { - run_test(non_settling_solver).await; -} - -#[tokio::test] -#[ignore] -async fn local_node_low_settling_solver() { - run_test(low_settling_solver).await; -} - -#[tokio::test] -#[ignore] -async fn local_node_not_allowed_solver() { - run_test(not_allowed_solver).await; -} - -async fn non_settling_solver(web3: Web3) { - let mut onchain = OnchainComponents::deploy(web3.clone()).await; - - let [solver, solver_b] = onchain.make_solvers(to_wei(1)).await; - let (trader_a, token_a, token_b) = setup(&mut onchain, &solver).await; - - let services = Services::new(&onchain).await; - let args = ExtraServiceArgs { - autopilot: vec![ - "--non-settling-solvers-blacklisting-enabled=true".to_string(), - "--low-settling-solvers-blacklisting-enabled=true".to_string(), - // The solver gets banned for 40s. - "--solver-blacklist-cache-ttl=40s".to_string(), - ], - ..Default::default() - }; - services.start_protocol_with_args(args, solver).await; - - // Amount of order should be more or equal the non-settling threshold, which is - // 3. - for _ in 0..4 { - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .unwrap(); - } - - let pool = services.db(); - let settled_auction_ids = fetch_last_settled_auction_ids(pool).await; - assert_eq!(settled_auction_ids.len(), 4); - // Build 5 blocks to make sure the submission deadline is passed, which is 5 by - // default. - for _ in 0..5 { - onchain.mint_block().await; - } - - // Simulate failed settlements by replacing the solver for the last 3 - // settlements. - let last_auctions = settled_auction_ids - .iter() - .take(3) - .cloned() - .collect::>(); - replace_solver_for_auction_ids(pool, &last_auctions, &solver_b.address()).await; - // The competition still passes since the stats are updated only after a new - // solution from anyone is received and stored. - let now = Instant::now(); - assert!( - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .is_ok() - ); - // Now, the stat is updated, and the solver is banned. - assert!( - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .is_err() - ); - - // 40 seconds is the cache TTL, and 5 seconds is added to compensate any - // possible delays. - let sleep_timeout_secs = 40 - now.elapsed().as_secs() + 5; - println!( - "Sleeping for {sleep_timeout_secs} seconds to reset the solver participation guard cache" - ); - tokio::time::sleep(tokio::time::Duration::from_secs(sleep_timeout_secs)).await; - // The cache is reset, and the solver is allowed to participate again. - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .unwrap(); -} - -async fn low_settling_solver(web3: Web3) { - let mut onchain = OnchainComponents::deploy(web3.clone()).await; - - let [solver, solver_b] = onchain.make_solvers(to_wei(1)).await; - let (trader_a, token_a, token_b) = setup(&mut onchain, &solver).await; - - let services = Services::new(&onchain).await; - let args = ExtraServiceArgs { - autopilot: vec![ - "--non-settling-solvers-blacklisting-enabled=true".to_string(), - "--low-settling-solvers-blacklisting-enabled=true".to_string(), - // The solver gets banned for 40s. - "--solver-blacklist-cache-ttl=40s".to_string(), - // The solver is banned if the failure settlement rate is above 55%. - "--solver-max-settlement-failure-rate=0.55".to_string(), - ], - ..Default::default() - }; - services.start_protocol_with_args(args, solver).await; - - // Create 5 orders, to easily test 60% of them failing, which is 3/5. - for _ in 0..5 { - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .unwrap(); - } - - let pool = services.db(); - let settled_auction_ids = fetch_last_settled_auction_ids(pool).await; - assert_eq!(settled_auction_ids.len(), 5); - // Build 5 blocks to make sure the submission deadline is passed, which is 5 by - // default. - for _ in 0..5 { - onchain.mint_block().await; - } - - // Simulate low settling rate by replacing the solver for the 60% of the - // settlements. - let random_auctions = settled_auction_ids - .iter() - .enumerate() - .filter_map(|(i, id)| (i % 2 == 0).then_some(*id)) - .collect::>(); - replace_solver_for_auction_ids(pool, &random_auctions, &solver_b.address()).await; - // The competition still passes since the stats are updated only after a new - // solution from anyone is received and stored. - let now = Instant::now(); - assert!( - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .is_ok() - ); - // Now, the stat is updated, and the solver is banned. - assert!( - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .is_err() - ); - - // 40 seconds is the cache TTL, and 5 seconds is added to compensate any - // possible delays. - let sleep_timeout_secs = 40 - now.elapsed().as_secs() + 5; - println!( - "Sleeping for {sleep_timeout_secs} seconds to reset the solver participation guard cache" - ); - tokio::time::sleep(tokio::time::Duration::from_secs(sleep_timeout_secs)).await; - // The cache is reset, and the solver is allowed to participate again. - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .unwrap(); -} - -async fn not_allowed_solver(web3: Web3) { - let mut onchain = OnchainComponents::deploy(web3.clone()).await; - - let [solver] = onchain.make_solvers(to_wei(1)).await; - let (trader_a, token_a, token_b) = setup(&mut onchain, &solver).await; - - let solver_address = solver.address(); - let services = Services::new(&onchain).await; - services.start_protocol(solver).await; - - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .unwrap(); - - // Ban the solver - onchain - .contracts() - .gp_authenticator - .removeSolver(solver_address.into_alloy()) - .send_and_watch() - .await - .unwrap(); - - assert!( - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .is_err() - ); - - // Unban the solver - onchain - .contracts() - .gp_authenticator - .addSolver(solver_address.into_alloy()) - .send_and_watch() - .await - .unwrap(); - - execute_order(&onchain, &trader_a, &token_a, &token_b, &services) - .await - .unwrap(); -} - -async fn setup( - onchain: &mut OnchainComponents, - solver: &TestAccount, -) -> (TestAccount, MintableToken, MintableToken) { - let [trader_a] = onchain.make_accounts(to_wei(1)).await; - let [token_a, token_b] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) - .await; - - // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(1000)).await; - - // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; - onchain - .contracts() - .uniswap_v2_factory - .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); - - token_a - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); - - token_b - .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); - onchain - .contracts() - .uniswap_v2_router - .addLiquidity( - *token_a.address(), - *token_b.address(), - eth(1000), - eth(1000), - U256::ZERO, - U256::ZERO, - solver.address().into_alloy(), - U256::MAX, - ) - .from(solver.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); - - // Approve GPv2 for trading - - token_a - .approve(onchain.contracts().allowance.into_alloy(), eth(1000)) - .from(trader_a.address().into_alloy()) - .send_and_watch() - .await - .unwrap(); - - (trader_a, token_a, token_b) -} - -async fn replace_solver_for_auction_ids(pool: &Db, auction_ids: &[i64], solver: &H160) { - for auction_id in auction_ids { - sqlx::query("UPDATE settlements SET solver = $1 WHERE auction_id = $2") - .bind(solver.0) - .bind(auction_id) - .execute(pool) - .await - .unwrap(); - } -} - -async fn fetch_last_settled_auction_ids(pool: &Db) -> Vec { - sqlx::query("SELECT auction_id FROM settlements ORDER BY auction_id DESC") - .fetch_all(pool) - .await - .unwrap() - .into_iter() - .filter_map(|row| { - let auction_id: Option = row.try_get(0).unwrap(); - auction_id - }) - .collect() -} - -async fn execute_order( - onchain: &OnchainComponents, - trader_a: &TestAccount, - token_a: &MintableToken, - token_b: &MintableToken, - services: &Services<'_>, -) -> anyhow::Result<()> { - let order = OrderCreation { - sell_token: token_a.address().into_legacy(), - sell_amount: to_wei(10), - buy_token: token_b.address().into_legacy(), - buy_amount: to_wei(5), - valid_to: model::time::now_in_epoch_seconds() + 300, - kind: OrderKind::Sell, - ..Default::default() - } - .sign( - EcdsaSigningScheme::Eip712, - &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), - ); - let balance_before = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - let order_id = services.create_order(&order).await.unwrap(); - onchain.mint_block().await; - let limit_order = services.get_order(&order_id).await.unwrap(); - assert_eq!(limit_order.metadata.class, OrderClass::Limit); - let auction_ids_before = fetch_last_settled_auction_ids(services.db()).await.len(); - - // Drive solution - tracing::info!("Waiting for trade."); - wait_for_condition(TIMEOUT, || async { - let balance_after = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - let balance_changes = balance_after.checked_sub(balance_before).unwrap() >= eth(5); - let auction_ids_after = - fetch_last_settled_auction_ids(services.db()).await.len() > auction_ids_before; - balance_changes && auction_ids_after - }) - .await -} diff --git a/crates/e2e/tests/e2e/submission.rs b/crates/e2e/tests/e2e/submission.rs index 89416eba00..3d2937a7ae 100644 --- a/crates/e2e/tests/e2e/submission.rs +++ b/crates/e2e/tests/e2e/submission.rs @@ -1,43 +1,83 @@ use { - ::alloy::primitives::U256, - e2e::{nodes::local_node::TestNodeApi, setup::*}, - ethcontract::{BlockId, H160, H256}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, + ::alloy::{ + primitives::{Address, B256, U256}, + providers::{Provider, ext::TxPoolApi}, + rpc::{ + client::PollerStream, + types::{Transaction, TransactionReceipt}, + }, }, - futures::{Stream, StreamExt}, + app_data::Hook, + configs::{ + autopilot::Configuration, + orderbook::order_validation::OrderValidationConfig, + test_util::TestDefault, + }, + e2e::setup::*, + ethrpc::alloy::{CallBuilderExt, EvmProviderExt}, + futures::StreamExt, model::{ - order::{OrderCreation, OrderKind}, + order::{BUY_ETH_ADDRESS, OrderCreation, OrderCreationAppData, OrderKind}, + quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, + number::{nonzero::NonZeroU256, testing::ApproxEq, units::EthUnit}, + serde_json::json, + shared::web3::Web3, std::time::Duration, - web3::signing::SecretKeyRef, }; #[tokio::test] #[ignore] -async fn local_node_test() { +async fn local_node_on_expiry() { run_test(test_cancel_on_expiry).await; } +#[tokio::test] +#[ignore] +async fn local_node_execute_same_sell_and_buy_token() { + run_test(test_execute_same_sell_and_buy_token).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_submit_same_sell_and_buy_token_order_without_quote() { + run_test(test_submit_same_sell_and_buy_token_order_without_quote).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_execute_same_sell_and_buy_native_token() { + run_test(test_execute_same_sell_and_buy_native_token).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_execute_same_sell_and_buy_native_token_buy_order() { + run_test(test_execute_same_sell_and_buy_native_token_buy_order).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_solver_pays_for_pre_hook_on_same_token_order() { + run_test(test_solver_pays_for_pre_hook_on_same_token_order).await; +} + async fn test_cancel_on_expiry(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; let nonce = solver.nonce(&web3).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -45,8 +85,8 @@ async fn test_cancel_on_expiry(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(3)) + .from(trader.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); @@ -56,23 +96,19 @@ async fn test_cancel_on_expiry(web3: Web3) { services.start_protocol(solver.clone()).await; // Disable auto-mine so we don't accidentally mine a settlement - web3.api::>() - .set_automine_enabled(false) + web3.provider + .evm_set_automine(false) .await .expect("Must be able to disable automine"); tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { - sell_token: onchain.contracts().weth.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Buy, ..Default::default() @@ -80,35 +116,33 @@ async fn test_cancel_on_expiry(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap(); onchain.mint_block().await; // Start tracking confirmed blocks so we can find the transaction later let block_stream = web3 - .eth_filter() - .create_blocks_filter() + .provider + .watch_blocks() .await .expect("must be able to create blocks filter") - .stream(Duration::from_millis(50)); + .into_stream(); // Wait for settlement tx to appear in txpool wait_for_condition(TIMEOUT, || async { - get_pending_tx(solver.account().address(), &web3) - .await - .is_some() + get_pending_tx(solver.address(), &web3).await.is_some() }) .await .unwrap(); // Restart mining, but with blocks that are too small to fit the settlement - web3.api::>() - .set_block_gas_limit(100_000) + web3.provider + .evm_set_block_gas_limit(100_000) .await .expect("Must be able to set block gas limit"); - web3.api::>() - .set_mining_interval(1) + web3.provider + .evm_set_interval_mining(1) .await .expect("Must be able to set mining interval"); @@ -120,39 +154,875 @@ async fn test_cancel_on_expiry(web3: Web3) { // Check that it's actually a cancellation let tx = tokio::time::timeout( TIMEOUT, - get_confirmed_transaction(solver.account().address(), &web3, block_stream), + get_confirmed_transaction(solver.address(), &web3, block_stream), + ) + .await + .unwrap(); + assert_eq!(tx.to, Some(solver.address())) +} + +async fn test_submit_same_sell_and_buy_token_order_without_quote(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + token.mint(trader.address(), 10u64.eth()).await; + + token + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + order_validation: OrderValidationConfig { + same_tokens_policy: shared::order_validation::SameTokensPolicy::AllowSell, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }, + solver.clone(), + ) + .await; + + // Disable auto-mine so we don't accidentally mine a settlement + web3.provider + .evm_set_automine(false) + .await + .expect("Must be able to disable automine"); + + let initial_balance = token.balanceOf(trader.address()).call().await.unwrap(); + assert_eq!(initial_balance, 10u64.eth()); + + let sell_amount = 1u64.eth(); // Sell 1 eth + let buy_amount = 0.99.eth(); // For 0.99 ETH, for order to execute + + tracing::info!("Placing order"); + let order = OrderCreation { + sell_token: *token.address(), + sell_amount, + buy_token: *token.address(), + buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + services.create_order(&order).await.unwrap(); + // Start tracking confirmed blocks so we can find the transaction later + let block_stream = web3 + .provider + .watch_blocks() + .await + .expect("must be able to create blocks filter") + .into_stream(); + + tracing::info!("Waiting for trade."); + onchain.mint_block().await; + + // Wait for settlement tx to appear in txpool + wait_for_condition(TIMEOUT, || async { + get_pending_tx(solver.address(), &web3).await.is_some() + }) + .await + .unwrap(); + + // Continue mining to confirm the settlement + web3.provider + .evm_set_automine(true) + .await + .expect("Must be able to enable automine"); + + // Wait for the settlement to be confirmed on chain + let tx = tokio::time::timeout( + Duration::from_secs(5), + get_confirmed_transaction(solver.address(), &web3, block_stream), + ) + .await + .unwrap(); + + // Verify the transaction is to the settlement contract (not a cancellation) + assert_eq!(tx.to, Some(*onchain.contracts().gp_settlement.address())); + + // Verify that the balance changed (settlement happened on chain) + let trade_happened = || async { + let balance = token.balanceOf(trader.address()).call().await.unwrap(); + // Balance should change due to fees even if sell token == buy token + balance != initial_balance + }; + wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); + + let final_balance = token.balanceOf(trader.address()).call().await.unwrap(); + tracing::info!(?initial_balance, ?final_balance, "Trade completed"); + + // Verify that the balance changed (settlement happened on chain) + assert!( + final_balance < initial_balance, + "Final balance should be smaller than initial balance due to fees" + ); +} + +async fn test_execute_same_sell_and_buy_token(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + token.mint(trader.address(), 10u64.eth()).await; + + token + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + order_validation: OrderValidationConfig { + same_tokens_policy: shared::order_validation::SameTokensPolicy::AllowSell, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }, + solver.clone(), + ) + .await; + + // Disable auto-mine so we don't accidentally mine a settlement + web3.provider + .evm_set_automine(false) + .await + .expect("Must be able to disable automine"); + + tracing::info!("Quoting"); + let quote_sell_amount = 1u64.eth(); + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: *token.address(), + buy_token: *token.address(), + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(quote_sell_amount).unwrap(), + }, + }, + ..Default::default() + }; + let quote_response = services.submit_quote("e_request).await.unwrap(); + tracing::info!(?quote_response); + assert!(quote_response.id.is_some()); + assert!(quote_response.verified); + assert!(quote_response.quote.buy_amount < quote_sell_amount); + + // check that a different receiver does not affect the quoted amount + let quote_request_different_receiver = OrderQuoteRequest { + receiver: Some(Address::repeat_byte(0x01)), + ..quote_request + }; + let quote_response_different_receiver = services + .submit_quote("e_request_different_receiver) + .await + .unwrap(); + + tracing::info!(?quote_response_different_receiver); + assert!(quote_response_different_receiver.id.is_some()); + assert!(quote_response_different_receiver.verified); + assert!( + quote_response_different_receiver + .quote + .buy_amount + .is_approx_eq("e_response.quote.buy_amount, Some(0.0001)) + ); + assert!( + quote_response_different_receiver + .quote + .sell_amount + .is_approx_eq("e_response.quote.sell_amount, Some(0.0001)) + ); + + let quote_metadata = + crate::database::quote_metadata(services.db(), quote_response.id.unwrap()).await; + assert!(quote_metadata.is_some()); + tracing::debug!(?quote_metadata); + + tracing::info!("Placing order"); + let initial_balance = token.balanceOf(trader.address()).call().await.unwrap(); + assert_eq!(initial_balance, 10u64.eth()); + + let order = OrderCreation { + kind: OrderKind::Sell, + sell_token: *token.address(), + buy_token: *token.address(), + quote_id: quote_response.id, + sell_amount: quote_sell_amount, + buy_amount: quote_response.quote.buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + assert!(services.create_order(&order).await.is_ok()); + + // Start tracking confirmed blocks so we can find the transaction later + let block_stream = web3 + .provider + .watch_blocks() + .await + .expect("must be able to create blocks filter") + .into_stream(); + + tracing::info!("Waiting for trade."); + onchain.mint_block().await; + + // Wait for settlement tx to appear in txpool + wait_for_condition(TIMEOUT, || async { + get_pending_tx(solver.address(), &web3).await.is_some() + }) + .await + .unwrap(); + + // Continue mining to confirm the settlement + web3.provider + .evm_set_automine(true) + .await + .expect("Must be able to enable automine"); + + // Wait for the settlement to be confirmed on chain + let tx = tokio::time::timeout( + Duration::from_secs(5), + get_confirmed_transaction(solver.address(), &web3, block_stream), ) .await .unwrap(); - assert_eq!(tx.to, Some(solver.account().address())) + + // Verify the transaction is to the settlement contract (not a cancellation) + assert_eq!(tx.to, Some(*onchain.contracts().gp_settlement.address())); + + // Verify that the balance changed (settlement happened on chain) + let trade_happened = || async { + let balance = token.balanceOf(trader.address()).call().await.unwrap(); + // Balance should change due to fees even if sell token == buy token + balance != initial_balance + }; + wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); + + let final_balance = token.balanceOf(trader.address()).call().await.unwrap(); + tracing::info!(?initial_balance, ?final_balance, "Trade completed"); + + // Verify that the balance changed (settlement happened on chain) + assert!( + final_balance < initial_balance, + "Final balance should be smaller than initial balance due to fees" + ); } -async fn get_pending_tx(account: H160, web3: &Web3) -> Option { +async fn test_execute_same_sell_and_buy_native_token(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(5u64.eth()) + .send_and_watch() + .await + .unwrap(); + + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 5u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + order_validation: OrderValidationConfig { + same_tokens_policy: shared::order_validation::SameTokensPolicy::AllowSell, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }, + solver.clone(), + ) + .await; + + // Disable auto-mine so we don't accidentally mine a settlement + web3.provider + .evm_set_automine(false) + .await + .expect("Must be able to disable automine"); + + tracing::info!("Quoting"); + let quote_sell_amount = 1u64.eth(); + let weth_address = *onchain.contracts().weth.address(); + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: weth_address, + buy_token: BUY_ETH_ADDRESS, + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(quote_sell_amount).unwrap(), + }, + }, + ..Default::default() + }; + let quote_response = services.submit_quote("e_request).await.unwrap(); + tracing::info!(?quote_response); + assert!(quote_response.id.is_some()); + assert!(quote_response.verified); + assert!(quote_response.quote.buy_amount < quote_sell_amount); + + // check that a different receiver does not affect the quoted amount + let quote_request_different_receiver = OrderQuoteRequest { + receiver: Some(Address::repeat_byte(0x01)), + ..quote_request + }; + let quote_response_different_receiver = services + .submit_quote("e_request_different_receiver) + .await + .unwrap(); + + tracing::info!(?quote_response_different_receiver); + assert!(quote_response_different_receiver.id.is_some()); + assert!(quote_response_different_receiver.verified); + assert!( + quote_response_different_receiver + .quote + .buy_amount + .is_approx_eq("e_response.quote.buy_amount, Some(0.0001)) + ); + assert!( + quote_response_different_receiver + .quote + .sell_amount + .is_approx_eq("e_response.quote.sell_amount, Some(0.0001)) + ); + + let quote_metadata = + crate::database::quote_metadata(services.db(), quote_response.id.unwrap()).await; + assert!(quote_metadata.is_some()); + tracing::debug!(?quote_metadata); + + tracing::info!("Placing order"); + let initial_balance = onchain + .contracts() + .weth + .balanceOf(trader.address()) + .call() + .await + .unwrap(); + assert_eq!(initial_balance, 5u64.eth()); + + let order = OrderCreation { + kind: OrderKind::Sell, + sell_token: weth_address, + buy_token: BUY_ETH_ADDRESS, + quote_id: quote_response.id, + sell_amount: quote_sell_amount, + buy_amount: quote_response.quote.buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + assert!(services.create_order(&order).await.is_ok()); + + // Start tracking confirmed blocks so we can find the transaction later + let block_stream = web3 + .provider + .watch_blocks() + .await + .expect("must be able to create blocks filter") + .into_stream(); + + tracing::info!("Waiting for trade."); + onchain.mint_block().await; + + // Wait for settlement tx to appear in txpool + wait_for_condition(TIMEOUT, || async { + get_pending_tx(solver.address(), &web3).await.is_some() + }) + .await + .unwrap(); + + // Continue mining to confirm the settlement + web3.provider + .evm_set_automine(true) + .await + .expect("Must be able to enable automine"); + + // Wait for the settlement to be confirmed on chain + let tx = tokio::time::timeout( + Duration::from_secs(5), + get_confirmed_transaction(solver.address(), &web3, block_stream), + ) + .await + .unwrap(); + + // Verify the transaction is to the settlement contract (not a cancellation) + assert_eq!(tx.to, Some(*onchain.contracts().gp_settlement.address())); + + // Verify that the WETH balance decreased (sell happened on chain) + let trade_happened = || async { + let balance = onchain + .contracts() + .weth + .balanceOf(trader.address()) + .call() + .await + .unwrap(); + balance != initial_balance + }; + wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); + + let final_balance = onchain + .contracts() + .weth + .balanceOf(trader.address()) + .call() + .await + .unwrap(); + tracing::info!(?initial_balance, ?final_balance, "Trade completed"); + + assert!( + final_balance < initial_balance, + "Final WETH balance should be smaller than initial balance due to sell" + ); +} + +/// Native-equivalent same-token **Buy** order (sell WETH, buy native ETH via +/// `BUY_ETH_ADDRESS`), mirroring `test_execute_same_sell_and_buy_native_token` +/// but with `OrderKind::Buy`. +/// +/// Exercises buy-side support for same sell/buy token orders enabled by +/// `SameTokensPolicy::Allow` (issue #3963, +/// https://github.com/cowprotocol/services/issues/3963). The order commits +/// `sell_amount + fee` so the solver has the headroom to settle it. +async fn test_execute_same_sell_and_buy_native_token_buy_order(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + + onchain + .contracts() + .weth + .deposit() + .from(trader.address()) + .value(5u64.eth()) + .send_and_watch() + .await + .unwrap(); + + onchain + .contracts() + .weth + .approve(onchain.contracts().allowance, 5u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + order_validation: OrderValidationConfig { + same_tokens_policy: shared::order_validation::SameTokensPolicy::Allow, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }, + solver.clone(), + ) + .await; + + // Disable auto-mine so we don't accidentally mine a settlement + web3.provider + .evm_set_automine(false) + .await + .expect("Must be able to disable automine"); + + tracing::info!("Quoting"); + let quote_buy_amount = 1u64.eth(); + let weth_address = *onchain.contracts().weth.address(); + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: weth_address, + buy_token: BUY_ETH_ADDRESS, + side: OrderQuoteSide::Buy { + buy_amount_after_fee: NonZeroU256::try_from(quote_buy_amount).unwrap(), + }, + ..Default::default() + }; + let quote_response = services.submit_quote("e_request).await.unwrap(); + tracing::info!(?quote_response); + assert!(quote_response.id.is_some()); + assert!(quote_response.verified); + // For a Buy order the trader pays (sell_amount + fee) more than the + // `buy_amount` they receive. At a 1:1 WETH<->ETH price the bare `sell_amount` + // equals `buy_amount`; the cost difference is carried in `fee_amount`. + assert!(quote_response.quote.sell_amount + quote_response.quote.fee_amount > quote_buy_amount); + + // check that a different receiver does not affect the quoted amount + let quote_request_different_receiver = OrderQuoteRequest { + receiver: Some(Address::repeat_byte(0x01)), + ..quote_request + }; + let quote_response_different_receiver = services + .submit_quote("e_request_different_receiver) + .await + .unwrap(); + + tracing::info!(?quote_response_different_receiver); + assert!(quote_response_different_receiver.id.is_some()); + assert!(quote_response_different_receiver.verified); + assert!( + quote_response_different_receiver + .quote + .buy_amount + .is_approx_eq("e_response.quote.buy_amount, Some(0.0001)) + ); + assert!( + quote_response_different_receiver + .quote + .sell_amount + .is_approx_eq("e_response.quote.sell_amount, Some(0.0001)) + ); + + let quote_metadata = + crate::database::quote_metadata(services.db(), quote_response.id.unwrap()).await; + assert!(quote_metadata.is_some()); + tracing::debug!(?quote_metadata); + + tracing::info!("Placing order"); + let initial_balance = onchain + .contracts() + .weth + .balanceOf(trader.address()) + .call() + .await + .unwrap(); + assert_eq!(initial_balance, 5u64.eth()); + + let order = OrderCreation { + kind: OrderKind::Buy, + sell_token: weth_address, + buy_token: BUY_ETH_ADDRESS, + quote_id: quote_response.id, + // Sell and buy are the same asset priced 1:1, so the quoted `sell_amount` + // equals `buy_amount`; the fee is the only extra the trader pays. We sign + // `sell_amount + fee` (a (1 + fee):1 limit) so the solver has headroom to + // take its fee — without it the limit would be exactly 1:1 and no solution + // could cover the fee. + sell_amount: quote_response.quote.sell_amount + quote_response.quote.fee_amount, + buy_amount: quote_buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + assert!(services.create_order(&order).await.is_ok()); + + // Start tracking confirmed blocks so we can find the transaction later + let block_stream = web3 + .provider + .watch_blocks() + .await + .expect("must be able to create blocks filter") + .into_stream(); + + tracing::info!("Waiting for trade."); + onchain.mint_block().await; + + // Wait for settlement tx to appear in txpool + wait_for_condition(TIMEOUT, || async { + get_pending_tx(solver.address(), &web3).await.is_some() + }) + .await + .unwrap(); + + // Continue mining to confirm the settlement + web3.provider + .evm_set_automine(true) + .await + .expect("Must be able to enable automine"); + + // Wait for the settlement to be confirmed on chain + let tx = tokio::time::timeout( + Duration::from_secs(5), + get_confirmed_transaction(solver.address(), &web3, block_stream), + ) + .await + .unwrap(); + + // Verify the transaction is to the settlement contract (not a cancellation) + assert_eq!(tx.to, Some(*onchain.contracts().gp_settlement.address())); + + // Verify that the WETH balance decreased (sell happened on chain) + let trade_happened = || async { + let balance = onchain + .contracts() + .weth + .balanceOf(trader.address()) + .call() + .await + .unwrap(); + balance != initial_balance + }; + wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); + + let final_balance = onchain + .contracts() + .weth + .balanceOf(trader.address()) + .call() + .await + .unwrap(); + tracing::info!(?initial_balance, ?final_balance, "Trade completed"); + + assert!( + final_balance < initial_balance, + "Final WETH balance should be smaller than initial balance due to sell" + ); +} + +/// Use-case test for `SameTokensPolicy::Allow`: a trader submits a same-token +/// **Buy** order (sell token == buy token, here WETH -> WETH) whose real +/// purpose is not the swap — which is economically a no-op — but to get an +/// arbitrary **pre-hook** executed and paid for by the solver as part of the +/// settlement. +/// +/// The trader signs a small spread (`sell_amount` slightly above `buy_amount`) +/// which the solver keeps to cover the settlement gas, including the pre-hook. +/// We prove the hook actually ran by pointing it at a `Counter` contract and +/// asserting the counter advanced — the same approach used by the hook e2e +/// tests in `hooks.rs`. +async fn test_solver_pays_for_pre_hook_on_same_token_order(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + + // Same token on both sides of the order: WETH -> WETH. We fund the trader by + // wrapping ETH into WETH and approving the allowance manager. + let weth = onchain.contracts().weth.clone(); + weth.deposit() + .from(trader.address()) + .value(5u64.eth()) + .send_and_watch() + .await + .unwrap(); + weth.approve(onchain.contracts().allowance, 5u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + // Arbitrary on-chain action the trader wants executed (and paid for) by the + // solver. `Counter::incrementCounter` lets us prove afterwards that it ran. + let counter = contracts::test::Counter::Instance::deploy(web3.provider.clone()) + .await + .unwrap(); + let increment = counter.incrementCounter("pre".to_string()); + let pre_hook = Hook { + target: *counter.address(), + call_data: increment.calldata().to_vec(), + gas_limit: increment.estimate_gas().await.unwrap(), + }; + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + services + .start_protocol_with_args( + Configuration::test("test_solver", solver.address()), + configs::orderbook::Configuration { + order_validation: OrderValidationConfig { + same_tokens_policy: shared::order_validation::SameTokensPolicy::Allow, + ..Default::default() + }, + ..configs::orderbook::Configuration::test_default() + }, + solver.clone(), + ) + .await; + + // Disable auto-mine so we don't accidentally mine a settlement + web3.provider + .evm_set_automine(false) + .await + .expect("Must be able to disable automine"); + + assert_eq!( + counter.counters("pre".to_string()).call().await.unwrap(), + U256::ZERO, + "pre-hook must not have run before settlement" + ); + + let initial_balance = weth.balanceOf(trader.address()).call().await.unwrap(); + assert_eq!(initial_balance, 5u64.eth()); + + tracing::info!("Placing same-token buy order with a pre-hook"); + // Same token priced 1:1, so the bare cost equals `buy_amount`; the extra + // 1% spread is the headroom the solver keeps to pay for the settlement + // (gas + the pre-hook). Without it the limit would be exactly 1:1 and no + // solution could cover any cost. + let buy_amount = 1u64.eth(); + let sell_amount = buy_amount + buy_amount / U256::from(100); // buy_amount + 1% + let weth_address = *weth.address(); + let order = OrderCreation { + kind: OrderKind::Buy, + sell_token: weth_address, + sell_amount, + buy_token: weth_address, + buy_amount, + valid_to: model::time::now_in_epoch_seconds() + 300, + app_data: OrderCreationAppData::Full { + full: json!({ + "metadata": { + "hooks": { + "pre": [pre_hook], + "post": [], + }, + }, + }) + .to_string(), + }, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + services.create_order(&order).await.unwrap(); + + // Start tracking confirmed blocks so we can find the transaction later + let block_stream = web3 + .provider + .watch_blocks() + .await + .expect("must be able to create blocks filter") + .into_stream(); + + tracing::info!("Waiting for trade."); + onchain.mint_block().await; + + // Wait for settlement tx to appear in txpool + wait_for_condition(TIMEOUT, || async { + get_pending_tx(solver.address(), &web3).await.is_some() + }) + .await + .unwrap(); + + // Continue mining to confirm the settlement + web3.provider + .evm_set_automine(true) + .await + .expect("Must be able to enable automine"); + + // Wait for the settlement to be confirmed on chain + let tx = tokio::time::timeout( + Duration::from_secs(5), + get_confirmed_transaction(solver.address(), &web3, block_stream), + ) + .await + .unwrap(); + + // The solver settled the order (not a cancellation), so it bore the gas for + // the whole settlement — including the pre-hook. + assert_eq!(tx.to, Some(*onchain.contracts().gp_settlement.address())); + + // The pre-hook ran exactly once as part of that settlement, which is already + // mined at this point. + assert_eq!( + counter.counters("pre".to_string()).call().await.unwrap(), + U256::from(1), + "pre-hook must have run exactly once as part of the settlement" + ); + + // And the trader paid for the order (the spread the solver kept). + let final_balance = weth.balanceOf(trader.address()).call().await.unwrap(); + tracing::info!(?initial_balance, ?final_balance, "Trade completed"); + assert!( + final_balance < initial_balance, + "Trader balance should decrease by the amount paid for the same-token buy order" + ); +} + +async fn get_pending_tx(account: Address, web3: &Web3) -> Option { let txpool = web3 - .txpool() - .content() + .provider + .txpool_content() .await .expect("must be able to inspect mempool"); txpool.pending.get(&account)?.values().next().cloned() } async fn get_confirmed_transaction( - account: H160, + account: Address, web3: &Web3, - block_stream: impl Stream>, -) -> web3::types::Transaction { - let mut block_stream = Box::pin(block_stream); + block_hash_stream: PollerStream>, +) -> TransactionReceipt { + let mut block_hash_stream = Box::pin(block_hash_stream); loop { - let block_hash = block_stream.next().await.unwrap().unwrap(); - let block = web3 - .eth() - .block_with_txs(BlockId::Hash(block_hash)) - .await - .expect("must be able to get block by hash") - .expect("block not found"); - for tx in block.transactions { - if tx.from == Some(account) { - return tx; + let block_hashes = block_hash_stream.next().await.unwrap(); + for block_hash in block_hashes { + let transaction_senders = web3 + .provider + .get_block_receipts(block_hash.into()) + .await + .unwrap() + .into_iter() + .flatten(); + + for tx in transaction_senders { + if tx.from == account { + return tx; + } } } } diff --git a/crates/e2e/tests/e2e/token_metadata.rs b/crates/e2e/tests/e2e/token_metadata.rs new file mode 100644 index 0000000000..b04c5ccb9e --- /dev/null +++ b/crates/e2e/tests/e2e/token_metadata.rs @@ -0,0 +1,121 @@ +use { + bigdecimal::Zero, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, + model::{ + order::{OrderCreation, OrderKind}, + signature::EcdsaSigningScheme, + }, + number::units::EthUnit, + shared::web3::Web3, +}; + +#[tokio::test] +#[ignore] +async fn local_node_token_metadata() { + run_test(token_metadata).await; +} + +#[tokio::test] +#[ignore] +async fn local_node_token_metadata_no_trade() { + run_test(token_metadata_no_trade).await; +} + +/// Test that the token metadata endpoint returns correct metadata after a trade +async fn token_metadata(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + let [token_a, token_b] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + token_a.mint(trader.address(), 10u64.eth()).await; + + token_a + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + let order = OrderCreation { + sell_token: *token_a.address(), + sell_amount: 5u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let uid = services.create_order(&order).await.unwrap(); + + // Wait for order to be settled + onchain.mint_block().await; + let settlement_finished = || async { + let order = services.get_order(&uid).await.unwrap(); + !order.metadata.executed_buy_amount.is_zero() + }; + wait_for_condition(TIMEOUT, settlement_finished) + .await + .unwrap(); + + // Get metadata for token_a (which was traded) + let metadata = services + .get_token_metadata(token_a.address()) + .await + .unwrap(); + + // After a trade, the token should have metadata with valid values + let first_trade_block = metadata + .first_trade_block + .expect("Token should have first_trade_block after being traded"); + assert!( + first_trade_block > 0, + "First trade block should be greater than 0, got {first_trade_block}" + ); + + let native_price = metadata + .native_price + .expect("Token should have native_price after being traded"); + assert!( + !native_price.is_zero(), + "Native price should be non-zero after trading" + ); +} + +/// Test that the token metadata endpoint returns None values for tokens with no +/// trades +async fn token_metadata_no_trade(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + + // Deploy a token but don't trade it + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + // Get metadata for a token that has never been traded + let metadata = services.get_token_metadata(token.address()).await.unwrap(); + + // Token with no trades should have None for first_trade_block + assert!( + metadata.first_trade_block.is_none(), + "Token with no trades should have None for first_trade_block" + ); + // Native price might still exist from the pool + // So we don't assert on it +} diff --git a/crates/e2e/tests/e2e/tracking_insufficient_funds.rs b/crates/e2e/tests/e2e/tracking_insufficient_funds.rs index e0094a3f90..93bacc84df 100644 --- a/crates/e2e/tests/e2e/tracking_insufficient_funds.rs +++ b/crates/e2e/tests/e2e/tracking_insufficient_funds.rs @@ -1,17 +1,13 @@ use { database::order_events::{OrderEvent, OrderEventLabel}, e2e::setup::*, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -24,17 +20,17 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader_a, trader_b] = onchain.make_accounts(10u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader_a.address().into_alloy()) + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -42,16 +38,16 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_a.address().into_alloy()) - .value(eth(3)) + .from(trader_a.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader_b.address().into_alloy()) + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -59,8 +55,8 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_b.address().into_alloy()) - .value(eth(3)) + .from(trader_b.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); @@ -71,10 +67,10 @@ async fn test(web3: Web3) { tracing::info!("Placing order"); let order_a = OrderCreation { - sell_token: onchain.contracts().weth.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Buy, ..Default::default() @@ -82,13 +78,13 @@ async fn test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), + &trader_a.signer, ); let order_b = OrderCreation { - sell_token: onchain.contracts().weth.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Buy, ..Default::default() @@ -96,7 +92,7 @@ async fn test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()), + &trader_b.signer, ); let uid_a = services.create_order(&order_a).await.unwrap(); let uid_b = services.create_order(&order_b).await.unwrap(); @@ -105,16 +101,16 @@ async fn test(web3: Web3) { onchain .contracts() .weth - .withdraw(eth(3)) - .from(trader_a.address().into_alloy()) + .withdraw(3u64.eth()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); onchain .contracts() .weth - .withdraw(eth(3)) - .from(trader_b.address().into_alloy()) + .withdraw(3u64.eth()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -139,13 +135,13 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_a.address().into_alloy()) - .value(eth(3)) + .from(trader_a.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); - onchain.mint_block().await; let orders_updated = || async { + onchain.mint_block().await; let events_a = crate::database::events_of_order(services.db(), &uid_a).await; let events_b = crate::database::events_of_order(services.db(), &uid_b).await; let order_b_correct_events = events_b.into_iter().map(|e| e.label).collect::>() @@ -161,13 +157,13 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_b.address().into_alloy()) - .value(eth(3)) + .from(trader_b.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); - onchain.mint_block().await; let orders_updated = || async { + onchain.mint_block().await; let events_a = crate::database::events_of_order(services.db(), &uid_b).await; let events_b = crate::database::events_of_order(services.db(), &uid_b).await; events_a.last().map(|o| o.label) == Some(OrderEventLabel::Traded) diff --git a/crates/e2e/tests/e2e/trades_v2.rs b/crates/e2e/tests/e2e/trades_v2.rs new file mode 100644 index 0000000000..664157e4ec --- /dev/null +++ b/crates/e2e/tests/e2e/trades_v2.rs @@ -0,0 +1,165 @@ +use { + bigdecimal::Zero, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, + model::{ + order::{OrderCreation, OrderKind}, + signature::EcdsaSigningScheme, + }, + number::units::EthUnit, + shared::web3::Web3, +}; + +#[tokio::test] +#[ignore] +async fn local_node_trades_v2_endpoints() { + run_test(trades_v2_endpoints).await; +} + +/// Test all v2 trades endpoint features (by order UID, by owner, and +/// pagination) +async fn trades_v2_endpoints(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader1, trader2] = onchain.make_accounts(1u64.eth()).await; + let [token_a, token_b] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + // Mint tokens for both traders + token_a.mint(trader1.address(), 100u64.eth()).await; + token_a.mint(trader2.address(), 10u64.eth()).await; + + token_a + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader1.address()) + .send_and_watch() + .await + .unwrap(); + + token_a + .approve(onchain.contracts().allowance, 10u64.eth()) + .from(trader2.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + // Create 3 orders for trader1 (for pagination testing) + let mut trader1_uids = Vec::new(); + for i in 0..3 { + let order = OrderCreation { + sell_token: *token_a.address(), + sell_amount: (2u64 + i as u64).eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300 + i as u32, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader1.signer, + ); + + let uid = services.create_order(&order).await.unwrap(); + trader1_uids.push(uid); + } + + // Create 1 order for trader2 (for owner filtering testing) + let order2 = OrderCreation { + sell_token: *token_a.address(), + sell_amount: 3u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader2.signer, + ); + + let trader2_uid = services.create_order(&order2).await.unwrap(); + + // Wait for all orders to be settled + onchain.mint_block().await; + let settlement_finished = || async { + let order1 = services.get_order(&trader1_uids[0]).await.unwrap(); + let order2 = services.get_order(&trader2_uid).await.unwrap(); + !order1.metadata.executed_buy_amount.is_zero() + && !order2.metadata.executed_buy_amount.is_zero() + }; + wait_for_condition(TIMEOUT, settlement_finished) + .await + .unwrap(); + + // Test 1: Get trades by order UID + let trades_by_uid = services + .get_trades_v2(Some(&trader1_uids[0]), None, 0, 10) + .await + .unwrap(); + + assert_eq!(trades_by_uid.len(), 1, "Should have exactly 1 trade"); + assert_eq!( + trades_by_uid[0].order_uid, trader1_uids[0], + "Trade should match order UID" + ); + + // Test 2: Get trades by owner + let trader1_trades = services + .get_trades_v2(None, Some(&trader1.address()), 0, 100) + .await + .unwrap(); + + assert_eq!( + trader1_trades.len(), + 3, + "Trader1 should have exactly 3 trades" + ); + + let trader2_trades = services + .get_trades_v2(None, Some(&trader2.address()), 0, 10) + .await + .unwrap(); + + assert_eq!( + trader2_trades.len(), + 1, + "Trader2 should have exactly 1 trade" + ); + assert_eq!( + trader2_trades[0].order_uid, trader2_uid, + "Trade should match trader2's order" + ); + + // Test 3: Pagination + // Test with limit + let limited_trades = services + .get_trades_v2(None, Some(&trader1.address()), 0, 2) + .await + .unwrap(); + + assert_eq!( + limited_trades.len(), + 2, + "Should return exactly 2 trades with limit=2" + ); + + // Test with offset + let offset_trades = services + .get_trades_v2(None, Some(&trader1.address()), 1, 100) + .await + .unwrap(); + + assert_eq!( + offset_trades.len(), + 2, + "Offset should skip first trade, leaving 2" + ); +} diff --git a/crates/e2e/tests/e2e/uncovered_order.rs b/crates/e2e/tests/e2e/uncovered_order.rs index 97fb964011..127cab8c51 100644 --- a/crates/e2e/tests/e2e/uncovered_order.rs +++ b/crates/e2e/tests/e2e/uncovered_order.rs @@ -1,16 +1,12 @@ use { e2e::setup::*, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -19,6 +15,12 @@ async fn local_node_uncovered_order() { run_test(test).await; } +#[tokio::test] +#[ignore] +async fn local_node_full_balance_check() { + run_test(test_full_balance_check).await; +} + /// Tests that a user can already create an order if they only have /// 1 wei of the sell token and later fund their account to get the /// order executed. @@ -26,15 +28,15 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; let weth = &onchain.contracts().weth; - weth.approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + weth.approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -45,11 +47,11 @@ async fn test(web3: Web3) { tracing::info!("Placing order with 0 sell tokens"); let order = OrderCreation { - sell_token: weth.address().into_legacy(), - sell_amount: to_wei(2), - fee_amount: 0.into(), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *weth.address(), + sell_amount: 2u64.eth(), + fee_amount: ::alloy::primitives::U256::ZERO, + buy_token: *token.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, partially_fillable: false, @@ -58,7 +60,7 @@ async fn test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); // This order can't be created because we require the trader // to have at least 1 wei of sell tokens. @@ -66,7 +68,7 @@ async fn test(web3: Web3) { tracing::info!("Placing order with 1 wei of sell_tokens"); weth.deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(::alloy::primitives::U256::ONE) .send_and_watch() .await @@ -77,21 +79,129 @@ async fn test(web3: Web3) { tracing::info!("Deposit ETH to make order executable"); weth.deposit() - .from(trader.address().into_alloy()) - .value(eth(2)) + .from(trader.address()) + .value(2u64.eth()) .send_and_watch() .await .unwrap(); tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after = weth - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = weth.balanceOf(trader.address()).call().await.unwrap(); !balance_after.is_zero() }) .await .unwrap(); } + +/// Tests that when order is placed with full balance checks, it would not be +/// possible to place it, unless the account has both - sufficient allowance and +/// balance. +/// +/// It compares and asserts on the behaviour when the full balance check is +/// disabled and enabled. +async fn test_full_balance_check(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; + let [token] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + let weth = &onchain.contracts().weth; + + // Initial allowance is enough to pass basic checks, but not enough to execute + // the order + weth.approve(onchain.contracts().allowance, 1u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + // Initial balance is enough to pass basic checks, but not enough to execute the + // order + weth.deposit() + .from(trader.address()) + .value(1u64.eth()) + .send_and_watch() + .await + .unwrap(); + + tracing::info!("Starting services."); + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + let order = OrderCreation { + sell_token: *weth.address(), + sell_amount: 2u64.eth(), + fee_amount: ::alloy::primitives::U256::ZERO, + buy_token: *token.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + partially_fillable: false, + ..Default::default() + }; + let unchecked_order = order.clone().sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let order = OrderCreation { + full_balance_check: true, + // different valid_to for orders to be considered distinct + valid_to: model::time::now_in_epoch_seconds() + 301, + ..order + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + // This order can be created because full balance checks are not enabled. + // The account has 1 WEI of the token and allowance for this amount. + services.create_order(&unchecked_order).await.unwrap(); + + // This order can not be created, because despite the token being transferrable + // The account does not have enough sell token balance to cover the order. + assert!( + services + .create_order(&order) + .await + .unwrap_err() + .1 + .contains("InsufficientBalance") + ); + + // Add the missing balance for the balance checkE + weth.deposit() + .from(trader.address()) + .value(1u64.eth()) + .send_and_watch() + .await + .unwrap(); + + // This order can not be created, because the account does not have enough + // sell token allowance. + assert!( + services + .create_order(&order) + .await + .unwrap_err() + .1 + .contains("InsufficientAllowance") + ); + + // Set allowance to the full amount + weth.approve(onchain.contracts().allowance, 2u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + // This order can be created now, because account has correct balance and + // allowance + services.create_order(&order).await.unwrap(); +} diff --git a/crates/e2e/tests/e2e/univ2.rs b/crates/e2e/tests/e2e/univ2.rs index 27792283f4..f6bfc7a40f 100644 --- a/crates/e2e/tests/e2e/univ2.rs +++ b/crates/e2e/tests/e2e/univ2.rs @@ -1,19 +1,15 @@ use { ::alloy::primitives::U256, - contracts::alloy::GPv2Settlement, + contracts::GPv2Settlement, database::order_events::{OrderEvent, OrderEventLabel}, - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -26,17 +22,17 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(10u64.eth()).await; + let [trader] = onchain.make_accounts(10u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; onchain .contracts() .weth - .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 3u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -44,8 +40,8 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) - .value(eth(3)) + .from(trader.address()) + .value(3u64.eth()) .send_and_watch() .await .unwrap(); @@ -55,17 +51,13 @@ async fn test(web3: Web3) { services.start_protocol(solver.clone()).await; tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { - sell_token: onchain.contracts().weth.address().into_legacy(), - sell_amount: to_wei(2), - buy_token: token.address().into_legacy(), - buy_amount: to_wei(1), + sell_token: *onchain.contracts().weth.address(), + sell_amount: 2u64.eth(), + buy_token: *token.address(), + buy_amount: 1u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Buy, ..Default::default() @@ -73,7 +65,7 @@ async fn test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); let uid = services.create_order(&order).await.unwrap(); @@ -88,7 +80,7 @@ async fn test(web3: Web3) { Default::default(), [ vec![GPv2Settlement::GPv2Interaction::Data { - target: trader.address().into_alloy(), + target: trader.address(), value: U256::ZERO, callData: Default::default(), }], @@ -96,28 +88,24 @@ async fn test(web3: Web3) { Default::default(), ], ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); tracing::info!("Waiting for trade."); let trade_happened = || async { - token - .balanceOf(trader.address().into_alloy()) + !token + .balanceOf(trader.address()) .call() .await .unwrap() - != U256::ZERO + .is_zero() }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - assert_eq!(balance, eth(1)); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); + assert_eq!(balance, 1u64.eth()); let all_events_registered = || async { let events = crate::database::events_of_order(services.db(), &uid).await; diff --git a/crates/e2e/tests/e2e/user_surplus.rs b/crates/e2e/tests/e2e/user_surplus.rs new file mode 100644 index 0000000000..4023affeb6 --- /dev/null +++ b/crates/e2e/tests/e2e/user_surplus.rs @@ -0,0 +1,157 @@ +use { + ::alloy::primitives::U256, + bigdecimal::Zero, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, + model::{ + order::{OrderCreation, OrderKind}, + signature::EcdsaSigningScheme, + }, + number::units::EthUnit, + shared::web3::Web3, +}; + +#[tokio::test] +#[ignore] +async fn local_node_user_surplus_endpoint() { + run_test(user_surplus_endpoint).await; +} + +/// Test the user surplus endpoint with no trades, single trade, and multiple +/// trades +async fn user_surplus_endpoint(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; + let [token_a, token_b] = onchain + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) + .await; + + token_a.mint(trader.address(), 100u64.eth()).await; + + token_a + .approve(onchain.contracts().allowance, 100u64.eth()) + .from(trader.address()) + .send_and_watch() + .await + .unwrap(); + + let services = Services::new(&onchain).await; + services.start_protocol(solver).await; + + // Test 1: User with no trades should have zero surplus + let surplus_before = services + .get_user_total_surplus(&trader.address()) + .await + .unwrap(); + + assert_eq!( + surplus_before, + U256::ZERO, + "User with no trades should have zero surplus" + ); + + // Create and execute first order + let order1 = OrderCreation { + sell_token: *token_a.address(), + sell_amount: 5u64.eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let uid1 = services.create_order(&order1).await.unwrap(); + + // Wait for first order to be settled + onchain.mint_block().await; + let settlement_finished = || async { + let order = services.get_order(&uid1).await.unwrap(); + !order.metadata.executed_buy_amount.is_zero() + }; + wait_for_condition(TIMEOUT, settlement_finished) + .await + .unwrap(); + + // Wait for solver competition data to be indexed + let indexed_trades = || async { + match services.get_trades(&uid1).await.unwrap().first() { + Some(trade) => services + .get_solver_competition(trade.tx_hash.unwrap()) + .await + .is_ok(), + None => false, + } + }; + wait_for_condition(TIMEOUT, indexed_trades).await.unwrap(); + + // Test 2: User with one trade should have positive surplus + let surplus_after_one = services + .get_user_total_surplus(&trader.address()) + .await + .unwrap(); + + assert!( + surplus_after_one > U256::ZERO, + "Surplus should be positive after one trade, got {surplus_after_one}" + ); + + // Create and execute two more orders + for i in 1..3 { + let order = OrderCreation { + sell_token: *token_a.address(), + sell_amount: (5u64 + i as u64).eth(), + buy_token: *token_b.address(), + buy_amount: 1u64.eth(), + valid_to: model::time::now_in_epoch_seconds() + 300 + i as u32, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + &trader.signer, + ); + + let uid = services.create_order(&order).await.unwrap(); + + // Wait for order to be settled + onchain.mint_block().await; + let settlement_finished = || async { + let order = services.get_order(&uid).await.unwrap(); + !order.metadata.executed_buy_amount.is_zero() + }; + wait_for_condition(TIMEOUT, settlement_finished) + .await + .unwrap(); + + // Wait for solver competition data to be indexed + let indexed_trades = || async { + match services.get_trades(&uid).await.unwrap().first() { + Some(trade) => services + .get_solver_competition(trade.tx_hash.unwrap()) + .await + .is_ok(), + None => false, + } + }; + wait_for_condition(TIMEOUT, indexed_trades).await.unwrap(); + } + + // Test 3: User with multiple trades should have accumulated surplus + let surplus_after_three = services + .get_user_total_surplus(&trader.address()) + .await + .unwrap(); + + assert!( + surplus_after_three > surplus_after_one, + "Surplus should accumulate across trades: {surplus_after_one} -> {surplus_after_three}" + ); +} diff --git a/crates/e2e/tests/e2e/vault_balances.rs b/crates/e2e/tests/e2e/vault_balances.rs index 5491410586..d50fa3dff4 100644 --- a/crates/e2e/tests/e2e/vault_balances.rs +++ b/crates/e2e/tests/e2e/vault_balances.rs @@ -1,16 +1,12 @@ use { - e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + e2e::setup::*, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderKind, SellTokenSource}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + number::units::EthUnit, + shared::web3::Web3, }; #[tokio::test] @@ -22,31 +18,27 @@ async fn local_node_vault_balances() { async fn vault_balances(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(1u64.eth()).await; + let [trader] = onchain.make_accounts(1u64.eth()).await; let [token] = onchain - .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .deploy_tokens_with_weth_uni_v2_pools(1_000u64.eth(), 1_000u64.eth()) .await; - token.mint(trader.address(), to_wei(10)).await; + token.mint(trader.address(), 10u64.eth()).await; // Approve GPv2 for trading token - .approve(*onchain.contracts().balancer_vault.address(), eth(10)) - .from(trader.address().into_alloy()) + .approve(*onchain.contracts().balancer_vault.address(), 10u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); onchain .contracts() .balancer_vault - .setRelayerApproval( - trader.address().into_alloy(), - onchain.contracts().allowance.into_alloy(), - true, - ) - .from(trader.address().into_alloy()) + .setRelayerApproval(trader.address(), onchain.contracts().allowance, true) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -57,25 +49,25 @@ async fn vault_balances(web3: Web3) { // Place Orders let order = OrderCreation { kind: OrderKind::Sell, - sell_token: token.address().into_legacy(), - sell_amount: to_wei(10), + sell_token: *token.address(), + sell_amount: 10u64.eth(), sell_token_balance: SellTokenSource::External, - buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: to_wei(8), + buy_token: *onchain.contracts().weth.address(), + buy_amount: 8u64.eth(), valid_to: model::time::now_in_epoch_seconds() + 300, ..Default::default() } .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); services.create_order(&order).await.unwrap(); onchain.mint_block().await; let balance_before = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -84,7 +76,7 @@ async fn vault_balances(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { let token_balance = token - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .expect("Couldn't fetch token balance"); @@ -92,12 +84,12 @@ async fn vault_balances(web3: Web3) { let weth_balance_after = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); - token_balance.is_zero() && weth_balance_after.saturating_sub(balance_before) >= eth(8) + token_balance.is_zero() && weth_balance_after.saturating_sub(balance_before) >= 8u64.eth() }) .await .unwrap(); diff --git a/crates/e2e/tests/e2e/wrapper.rs b/crates/e2e/tests/e2e/wrapper.rs index 2d7c2b800a..deecd0377e 100644 --- a/crates/e2e/tests/e2e/wrapper.rs +++ b/crates/e2e/tests/e2e/wrapper.rs @@ -8,25 +8,21 @@ use { rpc::types::trace::geth::{CallConfig, GethDebugTracingOptions}, }, app_data::{AppDataHash, hash_full_app_data}, - contracts::alloy::ERC20, + contracts::ERC20, e2e::setup::*, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::CallBuilderExt, model::{ order::{OrderCreation, OrderCreationAppData, OrderKind}, quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, signature::EcdsaSigningScheme, }, - secp256k1::SecretKey, + number::units::EthUnit, serde_json::json, - shared::ethrpc::Web3, - web3::signing::SecretKeyRef, + shared::web3::Web3, }; /// The block number from which we will fetch state for the forked test. -const FORK_BLOCK_MAINNET: u64 = 23688436; +const FORK_BLOCK_MAINNET: u64 = 24843565; /// EmptyWrapper contract address deployed on mainnet. const EMPTY_WRAPPER_MAINNET: Address = address!("751871E9cA28B441Bb6d3b7C4255cf2B5873d56a"); @@ -48,17 +44,17 @@ async fn forked_node_mainnet_wrapper() { async fn forked_mainnet_wrapper_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers_forked(1u64.eth()).await; + let [trader] = onchain.make_accounts(2u64.eth()).await; let token_weth = onchain.contracts().weth.clone(); let token_usdc = ERC20::Instance::new( address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), - web3.alloy.clone(), + web3.provider.clone(), ); // Authorize the empty wrapper as a solver - web3.alloy + web3.provider .anvil_send_impersonated_transaction_with_config( onchain .contracts() @@ -75,7 +71,7 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { ) .into_transaction_request(), ImpersonateConfig { - fund_amount: Some(to_wei(1).into_alloy()), + fund_amount: Some(1u64.eth()), stop_impersonate: true, }, ) @@ -88,19 +84,16 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { // Trader deposits ETH to get WETH token_weth .deposit() - .value(to_wei(1).into_alloy()) - .from(trader.address().into_alloy()) + .value(1u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); // Approve GPv2 for trading token_weth - .approve( - onchain.contracts().allowance.into_alloy(), - to_wei(1).into_alloy(), - ) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance, 1u64.eth()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -136,11 +129,11 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { // Warm up co-located driver by quoting the order let _ = services .submit_quote(&OrderQuoteRequest { - sell_token: token_weth.address().into_legacy(), - buy_token: token_usdc.address().into_legacy(), + sell_token: *token_weth.address(), + buy_token: *token_usdc.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { - value: to_wei(1).try_into().unwrap(), + value: (1u64.eth()).try_into().unwrap(), }, }, app_data: OrderCreationAppData::Both { @@ -157,10 +150,10 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { full: app_data.clone(), expected: app_data_hash, }, - sell_token: token_weth.address().into_legacy(), - sell_amount: to_wei(1), - buy_token: token_usdc.address().into_legacy(), - buy_amount: 1.into(), + sell_token: *token_weth.address(), + sell_amount: 1u64.eth(), + buy_token: *token_usdc.address(), + buy_amount: ::alloy::primitives::U256::ONE, valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -168,19 +161,11 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { .sign( EcdsaSigningScheme::Eip712, &onchain.contracts().domain_separator, - SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + &trader.signer, ); - let sell_token_balance_before = token_weth - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_weth.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); // Create the order let order_uid = services.create_order(&order).await.unwrap(); @@ -203,16 +188,8 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { wait_for_condition(TIMEOUT, || async { onchain.mint_block().await; - let sell_token_balance_after = token_weth - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_after = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_after = token_weth.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_after = token_usdc.balanceOf(trader.address()).call().await.unwrap(); (sell_token_balance_before > sell_token_balance_after) && (buy_token_balance_after > buy_token_balance_before) @@ -237,7 +214,7 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { tracing::info!("Settlement transaction hash: {:?}", solve_tx_hash); let solve_tx = web3 - .alloy + .provider .get_transaction_by_hash(solve_tx_hash) .await .unwrap() @@ -268,7 +245,7 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { }; let trace = web3 - .alloy + .provider .debug_trace_transaction(solve_tx_hash, tracing_options) .await .unwrap(); @@ -326,9 +303,7 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { // Sometimes the API isnt ready to respond to the request immediately so we wait // a bit for success wait_for_condition(TIMEOUT, || async { - let auction_info = services - .get_solver_competition(solve_tx_hash.into_legacy()) - .await; + let auction_info = services.get_solver_competition(solve_tx_hash).await; if let Ok(a) = auction_info { tracing::info!("Pulled auction id {:?}", a.auction_id); diff --git a/crates/eth-domain-types/Cargo.toml b/crates/eth-domain-types/Cargo.toml new file mode 100644 index 0000000000..9b5e27952d --- /dev/null +++ b/crates/eth-domain-types/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "eth-domain-types" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-eips = { workspace = true } +alloy-primitives = { workspace = true } +alloy-rpc-types = { workspace = true } +derive_more = { workspace = true } +num = { workspace = true } +number = { workspace = true } diff --git a/crates/eth-domain-types/src/access_list.rs b/crates/eth-domain-types/src/access_list.rs new file mode 100644 index 0000000000..40925fe6be --- /dev/null +++ b/crates/eth-domain-types/src/access_list.rs @@ -0,0 +1,94 @@ +use { + alloy_primitives::{Address, B256}, + derive_more::{From, Into}, + std::collections::{HashMap, HashSet}, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Into, From)] +pub struct StorageKey(pub B256); + +/// An EIP-2930 access list. This type ensures that the addresses and storage +/// keys are not repeated, and that the ordering is deterministic. +/// +/// https://eips.ethereum.org/EIPS/eip-2930 +#[derive(Debug, Clone, Default)] +pub struct AccessList(HashMap>); + +impl AccessList { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl AccessList { + /// Merge two access lists together. + pub fn merge(mut self, other: Self) -> Self { + for (address, storage_keys) in other.0.into_iter() { + self.0.entry(address).or_default().extend(storage_keys); + } + self + } +} + +impl IntoIterator for AccessList { + type IntoIter = std::collections::hash_map::IntoIter>; + type Item = (Address, HashSet); + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl FromIterator<(Address, I)> for AccessList +where + I: IntoIterator, +{ + fn from_iter>(iter: T) -> Self { + Self( + iter.into_iter() + .map(|(address, i)| { + ( + address, + i.into_iter().map(StorageKey).collect::>(), + ) + }) + .collect(), + ) + } +} + +impl From for AccessList { + fn from(value: alloy_eips::eip2930::AccessList) -> Self { + Self( + value + .0 + .into_iter() + .map(|item| { + ( + item.address, + item.storage_keys + .into_iter() + .map(StorageKey) + .collect::>(), + ) + }) + .collect(), + ) + } +} + +impl From for alloy_eips::eip2930::AccessList { + fn from(value: AccessList) -> Self { + Self( + value + .into_iter() + .map( + |(address, storage_keys)| alloy_eips::eip2930::AccessListItem { + address, + storage_keys: storage_keys.into_iter().map(|k| k.0).collect(), + }, + ) + .collect(), + ) + } +} diff --git a/crates/driver/src/domain/eth/allowance.rs b/crates/eth-domain-types/src/allowance.rs similarity index 98% rename from crates/driver/src/domain/eth/allowance.rs rename to crates/eth-domain-types/src/allowance.rs index e56cac7544..91222566df 100644 --- a/crates/driver/src/domain/eth/allowance.rs +++ b/crates/eth-domain-types/src/allowance.rs @@ -1,6 +1,6 @@ use { super::{Address, TokenAddress}, - alloy::primitives::U256, + alloy_primitives::U256, derive_more::{From, Into}, }; diff --git a/crates/driver/src/domain/eth/eip712.rs b/crates/eth-domain-types/src/eip712.rs similarity index 100% rename from crates/driver/src/domain/eth/eip712.rs rename to crates/eth-domain-types/src/eip712.rs diff --git a/crates/eth-domain-types/src/ether.rs b/crates/eth-domain-types/src/ether.rs new file mode 100644 index 0000000000..7bf129f54b --- /dev/null +++ b/crates/eth-domain-types/src/ether.rs @@ -0,0 +1,66 @@ +use { + alloy_primitives::U256, + derive_more::derive::{Display, From, Into}, +}; + +/// An amount of native Ether tokens denominated in wei. +#[derive( + Clone, + Copy, + Debug, + Eq, + Ord, + PartialEq, + PartialOrd, + From, + Into, + Display, + Default, + derive_more::Add, + derive_more::Sub, +)] +pub struct Ether(pub U256); + +impl From for Ether { + fn from(value: i32) -> Self { + Self(U256::from(value)) + } +} + +impl From for num::BigInt { + fn from(value: Ether) -> Self { + num::BigUint::from_bytes_be(value.0.to_be_bytes::<32>().as_slice()).into() + } +} + +impl num::Saturating for Ether { + fn saturating_add(self, v: Self) -> Self { + Self(self.0.saturating_add(v.0)) + } + + fn saturating_sub(self, v: Self) -> Self { + Self(self.0.saturating_sub(v.0)) + } +} + +impl num::CheckedSub for Ether { + fn checked_sub(&self, v: &Self) -> Option { + self.0.checked_sub(v.0).map(Ether) + } +} + +impl num::Zero for Ether { + fn zero() -> Self { + Self(U256::ZERO) + } + + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +impl std::iter::Sum for Ether { + fn sum>(iter: I) -> Self { + iter.fold(num::Zero::zero(), std::ops::Add::add) + } +} diff --git a/crates/driver/src/domain/eth/gas.rs b/crates/eth-domain-types/src/gas.rs similarity index 68% rename from crates/driver/src/domain/eth/gas.rs rename to crates/eth-domain-types/src/gas.rs index 8c69e0dcbd..0b565c2a04 100644 --- a/crates/driver/src/domain/eth/gas.rs +++ b/crates/eth-domain-types/src/gas.rs @@ -1,7 +1,8 @@ use { - super::{Ether, U256}, + crate::Ether, + alloy_eips::eip1559::calc_effective_gas_price, + alloy_primitives::U256, derive_more::{Display, From, Into}, - std::{ops, ops::Add}, }; /// Gas amount in gas units. @@ -13,11 +14,11 @@ pub struct Gas(pub U256); impl From for Gas { fn from(value: u64) -> Self { - Self(value.into()) + Self(U256::from(value)) } } -impl Add for Gas { +impl std::ops::Add for Gas { type Output = Self; fn add(self, rhs: Self) -> Self::Output { @@ -37,15 +38,18 @@ pub struct GasPrice { tip: FeePerGas, /// The current base gas price that will be charged to all accounts on the /// next block. - base: FeePerGas, + base: u64, } impl GasPrice { /// Returns the estimated [`EffectiveGasPrice`] for the gas price estimate. pub fn effective(&self) -> EffectiveGasPrice { - U256::from(self.max) - .min(U256::from(self.base).saturating_add(self.tip.into())) - .into() + U256::from(calc_effective_gas_price( + u128::try_from(self.max.0.0).expect("max fee per gas should fit in a u128"), + u128::try_from(self.tip.0.0).expect("max priority fee per gas should fit in a u128"), + Some(self.base), + )) + .into() } pub fn max(&self) -> FeePerGas { @@ -56,25 +60,12 @@ impl GasPrice { self.tip } - pub fn base(&self) -> FeePerGas { + pub fn base(&self) -> u64 { self.base } - /// Creates a new instance limiting maxFeePerGas to a reasonable multiple of - /// the current base fee. - pub fn new(max: FeePerGas, tip: FeePerGas, base: FeePerGas) -> Self { - // We multiply a fixed factor of the current base fee per - // gas, which is chosen to be the maximum possible increase to the base - // fee (max 12.5% per block) over 12 blocks, also including the "tip". - const MAX_FEE_FACTOR: f64 = 4.2; - Self { - max: FeePerGas(std::cmp::min( - max.0, - base.mul_ceil(MAX_FEE_FACTOR).add(tip).0, - )), - tip, - base, - } + pub fn new(max: FeePerGas, tip: FeePerGas, base: u64) -> Self { + Self { max, tip, base } } } @@ -92,17 +83,6 @@ impl std::ops::Mul for GasPrice { } } -impl From for GasPrice { - fn from(value: EffectiveGasPrice) -> Self { - let value = value.0.0; - Self { - max: value.into(), - tip: value.into(), - base: value.into(), - } - } -} - /// The amount of ETH to pay as fees for a single unit of gas. This is /// `{max,max_priority,base}_fee_per_gas` as defined by EIP-1559. /// @@ -113,7 +93,7 @@ pub struct FeePerGas(pub Ether); impl FeePerGas { /// Multiplies this fee by the given floating point number, rounding up. fn mul_ceil(self, rhs: f64) -> Self { - U256::from_f64_lossy((self.0.0.to_f64_lossy() * rhs).ceil()).into() + U256::from((f64::from(self.0.0) * rhs).ceil()).into() } } @@ -123,7 +103,7 @@ impl From for FeePerGas { } } -impl ops::Add for FeePerGas { +impl std::ops::Add for FeePerGas { type Output = FeePerGas; fn add(self, rhs: FeePerGas) -> Self::Output { @@ -137,7 +117,7 @@ impl From for U256 { } } -impl ops::Mul for Gas { +impl std::ops::Mul for Gas { type Output = Ether; fn mul(self, rhs: FeePerGas) -> Self::Output { @@ -148,9 +128,15 @@ impl ops::Mul for Gas { /// The `effective_gas_price` as defined by EIP-1559. /// /// https://eips.ethereum.org/EIPS/eip-1559#specification -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Display, Default)] pub struct EffectiveGasPrice(pub Ether); +impl From for EffectiveGasPrice { + fn from(value: u128) -> Self { + Self(U256::from(value).into()) + } +} + impl From for EffectiveGasPrice { fn from(value: U256) -> Self { Self(value.into()) diff --git a/crates/eth-domain-types/src/lib.rs b/crates/eth-domain-types/src/lib.rs new file mode 100644 index 0000000000..9cff77aebd --- /dev/null +++ b/crates/eth-domain-types/src/lib.rs @@ -0,0 +1,151 @@ +pub use { + access_list::{AccessList, StorageKey}, + allowance::Allowance, + alloy_primitives::{Address, B256, U256, U512}, + eip712::DomainSeparator, + ether::Ether, + gas::{EffectiveGasPrice, FeePerGas, Gas, GasPrice}, + number::nonzero::NonZeroU256, + token_amount::{SellTokenAmount, SurplusTokenAmount, TokenAmount}, +}; +use { + alloy_primitives::Bytes, + alloy_rpc_types::TransactionRequest, + derive_more::{From, Into, derive::Deref}, +}; + +mod access_list; +pub mod allowance; +mod eip712; +mod ether; +mod gas; +mod token_amount; + +/// ERC20 token address for ETH. In reality, ETH is not an ERC20 token because +/// it does not implement the ERC20 interface, but this address is used by +/// convention across the Ethereum ecosystem whenever ETH is treated like an +/// ERC20 token. +pub const ETH_TOKEN: TokenAddress = TokenAddress(Address::repeat_byte(0xee)); + +// TODO This type should probably use Ethereum::is_contract to verify during +// construction that it does indeed point to a contract +/// A smart contract address. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deref)] +pub struct ContractAddress(Address); + +/// An ERC20 token address. +/// +/// https://eips.ethereum.org/EIPS/eip-20 +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deref)] +pub struct TokenAddress(Address); + +impl TokenAddress { + /// If the token is ETH, return WETH, thereby converting it to erc20. + pub fn as_erc20(self, weth: WrappedNativeToken) -> Self { + if self == ETH_TOKEN { *weth } else { self } + } +} + +/// ERC20 representation of the chain's native token (e.g. WETH on mainnet, +/// WXDAI on Gnosis Chain). +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deref)] +pub struct WrappedNativeToken(TokenAddress); + +impl From
for WrappedNativeToken { + fn from(value: Address) -> Self { + WrappedNativeToken(value.into()) + } +} + +impl From
for TokenAddress { + fn from(value: Address) -> Self { + Self(value) + } +} + +impl From
for ContractAddress { + fn from(value: Address) -> Self { + Self(value) + } +} + +impl From for Address { + fn from(value: TokenAddress) -> Self { + value.0 + } +} + +impl From for Address { + fn from(value: ContractAddress) -> Self { + value.0 + } +} + +/// An asset on the Ethereum blockchain. Represents a particular amount of a +/// particular token. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub struct Asset { + pub amount: TokenAmount, + pub token: TokenAddress, +} + +/// Block number. +#[derive(Debug, Copy, Clone, From, PartialEq, PartialOrd, Default)] +pub struct BlockNo(pub u64); + +impl std::fmt::Display for BlockNo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Adding blocks to a block number. +impl std::ops::Add for BlockNo { + type Output = BlockNo; + + fn add(self, rhs: u64) -> Self::Output { + Self(self.0 + rhs) + } +} + +impl num::Saturating for BlockNo { + fn saturating_add(self, v: Self) -> Self { + Self(self.0.saturating_add(v.0)) + } + + fn saturating_sub(self, v: Self) -> Self { + Self(self.0.saturating_sub(v.0)) + } +} + +/// A transaction ID, AKA transaction hash. +#[derive(Debug, Copy, Clone, From, Default)] +pub struct TxId(pub B256); + +/// An onchain transaction. +#[derive(derive_more::Debug, Clone)] +pub struct Tx { + pub from: Address, + pub to: Address, + pub value: Ether, + pub input: Bytes, + #[debug(ignore)] + pub access_list: AccessList, +} + +impl Tx { + pub fn set_access_list(&mut self, access_list: AccessList) { + self.access_list = access_list; + } +} + +impl From for TransactionRequest { + fn from(value: Tx) -> Self { + TransactionRequest::default() + .from(value.from) + .to(value.to) + .value(value.value.0) + .input(value.input.into()) + .access_list(value.access_list.into()) + } +} diff --git a/crates/eth-domain-types/src/token_amount.rs b/crates/eth-domain-types/src/token_amount.rs new file mode 100644 index 0000000000..b11a0edf49 --- /dev/null +++ b/crates/eth-domain-types/src/token_amount.rs @@ -0,0 +1,125 @@ +use { + alloy_primitives::U256, + derive_more::{From, Into}, + number::u256_ext::U256Ext, +}; + +/// An ERC20 token amount. +/// +/// https://eips.ethereum.org/EIPS/eip-20 +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] +pub struct TokenAmount(pub U256); + +impl TokenAmount { + /// Applies a factor to the token amount. + pub fn apply_factor(&self, factor: f64) -> Option { + Some(self.0.checked_mul_f64(factor)?.into()) + } +} + +/// A value denominated in an order's surplus token (buy token for +/// sell orders and sell token for buy orders). +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] +pub struct SurplusTokenAmount(pub U256); + +/// An ERC20 sell token amount. +/// +/// https://eips.ethereum.org/EIPS/eip-20 +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] +pub struct SellTokenAmount(pub U256); + +impl From for SellTokenAmount { + fn from(value: TokenAmount) -> Self { + Self(value.0) + } +} + +impl From for TokenAmount { + fn from(value: SellTokenAmount) -> Self { + Self(value.0) + } +} + +impl std::ops::Sub for TokenAmount { + type Output = TokenAmount; + + fn sub(self, rhs: Self) -> Self::Output { + self.0.sub(rhs.0).into() + } +} + +impl num::CheckedSub for TokenAmount { + fn checked_sub(&self, other: &Self) -> Option { + self.0.checked_sub(other.0).map(Into::into) + } +} + +impl std::ops::Mul for TokenAmount { + type Output = TokenAmount; + + fn mul(self, rhs: Self) -> Self::Output { + self.0.mul(rhs.0).into() + } +} + +impl num::CheckedMul for TokenAmount { + fn checked_mul(&self, other: &Self) -> Option { + self.0.checked_mul(other.0).map(Into::into) + } +} + +impl num::CheckedAdd for TokenAmount { + fn checked_add(&self, other: &Self) -> Option { + self.0.checked_add(other.0).map(Into::into) + } +} + +impl std::ops::Div for TokenAmount { + type Output = TokenAmount; + + fn div(self, rhs: Self) -> Self::Output { + self.0.div(rhs.0).into() + } +} + +impl num::CheckedDiv for TokenAmount { + fn checked_div(&self, other: &Self) -> Option { + self.0.checked_div(other.0).map(Into::into) + } +} + +impl From for TokenAmount { + fn from(value: u128) -> Self { + Self(U256::from(value)) + } +} + +impl std::ops::Add for TokenAmount { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl std::ops::AddAssign for TokenAmount { + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0; + } +} + +impl num::Zero for TokenAmount { + fn zero() -> Self { + Self(U256::ZERO) + } + + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +impl std::fmt::Display for TokenAmount { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} diff --git a/crates/ethrpc/Cargo.toml b/crates/ethrpc/Cargo.toml index 0d22f20865..92b21b3cf8 100644 --- a/crates/ethrpc/Cargo.toml +++ b/crates/ethrpc/Cargo.toml @@ -11,16 +11,24 @@ name = "ethrpc" path = "src/lib.rs" [dependencies] -alloy = { workspace = true, default-features = false, features = ["json-rpc", "providers", "rpc-client", "rpc-types", "transports", "transport-ws", "provider-ws", "reqwest", "signers", "signer-aws", "signer-local", "eips", "reqwest-default-tls", "pubsub", "contract"] } +alloy-consensus = { workspace = true } +alloy-contract = { workspace = true } +alloy-eips = { workspace = true } +alloy-json-rpc = { workspace = true } +alloy-network = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true, features = ["reqwest-default-tls", "reqwest", "ws"] } +alloy-rpc-client = { workspace = true, features = ["reqwest"] } +alloy-rpc-types = { workspace = true, features = ["eth"] } +alloy-signer = { workspace = true } +alloy-transport = { workspace = true } +alloy-transport-ws = { workspace = true } anyhow = { workspace = true } async-trait = { workspace = true } -ethcontract = { workspace = true } -futures = { workspace = true } const-hex = { workspace = true } -hex-literal = { workspace = true } +futures = { workspace = true } itertools = { workspace = true } observe = { workspace = true } -primitive-types = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } rand = { workspace = true } @@ -33,16 +41,9 @@ tokio-stream = { workspace = true } tower = { workspace = true } tracing = { workspace = true } url = { workspace = true } -web3 = { workspace = true } -mockall = { workspace = true, optional = true } - -[dev-dependencies] -mockall = { workspace = true } -maplit = { workspace = true } -testlib = { workspace = true } [features] -test-util = ["dep:mockall"] +test-util = [] [lints] workspace = true diff --git a/crates/ethrpc/src/alloy/buffering.rs b/crates/ethrpc/src/alloy/buffering.rs index 36a697c85c..dcff520a64 100644 --- a/crates/ethrpc/src/alloy/buffering.rs +++ b/crates/ethrpc/src/alloy/buffering.rs @@ -12,10 +12,8 @@ //! another channel. use { crate::Config, - alloy::{ - rpc::json_rpc::{RequestPacket, Response, ResponsePacket, SerializedRequest}, - transports::{RpcError, TransportError, TransportErrorKind}, - }, + alloy_json_rpc::{RequestPacket, Response, ResponsePacket, SerializedRequest}, + alloy_transport::{RpcError, TransportError, TransportErrorKind}, futures::{ channel::{mpsc, oneshot}, stream::StreamExt as _, diff --git a/crates/ethrpc/src/alloy/conversions.rs b/crates/ethrpc/src/alloy/conversions.rs deleted file mode 100644 index ff6d7ebc31..0000000000 --- a/crates/ethrpc/src/alloy/conversions.rs +++ /dev/null @@ -1,276 +0,0 @@ -use { - alloy::{network::TxSigner, signers::Signature}, - anyhow::Context, - std::collections::HashMap, -}; - -///////////////////////////////// -// Conversions to the alloy types -///////////////////////////////// - -pub trait IntoAlloy { - /// The corresponding Alloy type. - type To; - - /// Converts the legacy type to the corresponding Alloy type. - fn into_alloy(self) -> Self::To; -} - -impl IntoAlloy for ethcontract::I256 { - type To = alloy::primitives::I256; - - fn into_alloy(self) -> Self::To { - let mut buf = [0u8; 32]; - self.to_little_endian(&mut buf); - alloy::primitives::I256::from_le_bytes(buf) - } -} - -impl IntoAlloy for primitive_types::U256 { - type To = alloy::primitives::U256; - - fn into_alloy(self) -> Self::To { - let mut buf = [0u8; 32]; - self.to_little_endian(&mut buf); - alloy::primitives::U256::from_le_bytes(buf) - } -} - -impl IntoAlloy for primitive_types::U512 { - type To = alloy::primitives::U512; - - fn into_alloy(self) -> Self::To { - let mut buf = [0u8; 64]; - self.to_little_endian(&mut buf); - alloy::primitives::U512::from_le_bytes(buf) - } -} - -impl IntoAlloy for primitive_types::H160 { - type To = alloy::primitives::Address; - - fn into_alloy(self) -> Self::To { - alloy::primitives::Address(self.0.into()) - } -} - -impl IntoAlloy for primitive_types::H256 { - type To = alloy::primitives::aliases::B256; - - fn into_alloy(self) -> Self::To { - alloy::primitives::aliases::B256::new(self.0) - } -} - -impl IntoAlloy for web3::types::BlockNumber { - type To = alloy::eips::BlockNumberOrTag; - - fn into_alloy(self) -> Self::To { - match self { - web3::types::BlockNumber::Finalized => alloy::eips::BlockNumberOrTag::Finalized, - web3::types::BlockNumber::Safe => alloy::eips::BlockNumberOrTag::Safe, - web3::types::BlockNumber::Latest => alloy::eips::BlockNumberOrTag::Latest, - web3::types::BlockNumber::Earliest => alloy::eips::BlockNumberOrTag::Earliest, - web3::types::BlockNumber::Pending => alloy::eips::BlockNumberOrTag::Pending, - web3::types::BlockNumber::Number(number) => { - alloy::eips::BlockNumberOrTag::Number(number.as_u64()) - } - } - } -} - -impl IntoAlloy for web3::types::BlockId { - type To = alloy::eips::BlockId; - - fn into_alloy(self) -> Self::To { - match self { - web3::types::BlockId::Hash(hash) => { - alloy::eips::BlockId::Hash(alloy::eips::RpcBlockHash::from(hash.into_alloy())) - } - web3::types::BlockId::Number(number) => { - alloy::eips::BlockId::Number(number.into_alloy()) - } - } - } -} - -impl IntoAlloy for ethcontract::tokens::Bytes> { - type To = alloy::primitives::Bytes; - - fn into_alloy(self) -> Self::To { - alloy::primitives::Bytes::copy_from_slice(self.0.as_slice()) - } -} - -impl IntoAlloy for web3::types::Bytes { - type To = alloy::primitives::Bytes; - - fn into_alloy(self) -> Self::To { - alloy::primitives::Bytes::copy_from_slice(self.0.as_slice()) - } -} - -impl IntoAlloy for HashMap { - type To = HashMap< - alloy::primitives::B256, - alloy::primitives::B256, - alloy::primitives::map::FbBuildHasher<32>, - >; - - fn into_alloy(self) -> Self::To { - self.into_iter() - .map(|(k, v)| (k.into_alloy(), v.into_alloy())) - .collect() - } -} - -impl IntoAlloy for ethcontract::state_overrides::StateOverride { - type To = alloy::rpc::types::eth::state::AccountOverride; - - fn into_alloy(self) -> Self::To { - Self::To { - balance: self.balance.map(IntoAlloy::into_alloy), - nonce: self.nonce.map(|u| u.as_u64()), - code: self.code.map(IntoAlloy::into_alloy), - state: self.state.map(IntoAlloy::into_alloy), - state_diff: self.state_diff.map(IntoAlloy::into_alloy), - move_precompile_to: None, - } - } -} - -impl IntoAlloy for ethcontract::state_overrides::StateOverrides { - type To = alloy::rpc::types::eth::state::StateOverride; - - fn into_alloy(self) -> Self::To { - alloy::rpc::types::eth::state::StateOverridesBuilder::new( - self.into_iter() - .map(|(k, v)| (k.into_alloy(), v.into_alloy())) - .collect(), - ) - .build() - } -} - -pub enum Account { - Address(alloy::primitives::Address), - Signer(Box + Send + Sync + 'static>), -} - -#[async_trait::async_trait] -pub trait TryIntoAlloyAsync { - type Into; - - async fn try_into_alloy(self) -> anyhow::Result; -} - -#[async_trait::async_trait] -impl TryIntoAlloyAsync for ethcontract::Account { - type Into = Account; - - async fn try_into_alloy(self) -> anyhow::Result { - match self { - ethcontract::Account::Offline(pk, _) => { - let signer = - alloy::signers::local::PrivateKeySigner::from_slice(&pk.secret_bytes()) - .context("invalid private key bytes")?; - Ok(Account::Signer(Box::new(signer))) - } - ethcontract::Account::Kms(account, chain_id) => { - let signer = alloy::signers::aws::AwsSigner::new( - account.client().clone(), - account.key_id().to_string(), - chain_id, - ) - .await?; - Ok(Account::Signer(Box::new(signer))) - } - ethcontract::Account::Local(address, _) => Ok(Account::Address(address.into_alloy())), - ethcontract::Account::Locked(_, _, _) => { - anyhow::bail!("Locked accounts are not currently supported") - } - } - } -} - -////////////////////////////////// -// Conversions to the legacy types -////////////////////////////////// - -pub trait IntoLegacy { - /// The corresponding legacy type. - type To; - - /// Converts the alloy type to the corresponding legacy type. - fn into_legacy(self) -> Self::To; -} - -impl IntoLegacy for alloy::primitives::U256 { - type To = primitive_types::U256; - - fn into_legacy(self) -> Self::To { - primitive_types::U256(self.into_limbs()) - } -} - -impl IntoLegacy for alloy::primitives::U512 { - type To = primitive_types::U512; - - fn into_legacy(self) -> Self::To { - primitive_types::U512(self.into_limbs()) - } -} - -impl IntoLegacy for alloy::primitives::Address { - type To = primitive_types::H160; - - fn into_legacy(self) -> Self::To { - primitive_types::H160(self.into()) - } -} - -impl IntoLegacy for alloy::primitives::aliases::B256 { - type To = primitive_types::H256; - - fn into_legacy(self) -> Self::To { - primitive_types::H256(self.into()) - } -} - -impl IntoLegacy for alloy::primitives::Bytes { - type To = web3::types::Bytes; - - fn into_legacy(self) -> Self::To { - web3::types::Bytes(self.to_vec()) - } -} - -impl IntoLegacy - for HashMap< - alloy::primitives::B256, - alloy::primitives::B256, - alloy::primitives::map::FbBuildHasher<32>, - > -{ - type To = HashMap; - - fn into_legacy(self) -> Self::To { - self.into_iter() - .map(|(k, v)| (k.into_legacy(), v.into_legacy())) - .collect() - } -} - -impl IntoLegacy for alloy::rpc::types::eth::state::AccountOverride { - type To = ethcontract::state_overrides::StateOverride; - - fn into_legacy(self) -> Self::To { - Self::To { - balance: self.balance.map(IntoLegacy::into_legacy), - nonce: self.nonce.map(Into::into), - code: self.code.map(IntoLegacy::into_legacy), - state: self.state.map(IntoLegacy::into_legacy), - state_diff: self.state_diff.map(IntoLegacy::into_legacy), - } - } -} diff --git a/crates/ethrpc/src/alloy/errors.rs b/crates/ethrpc/src/alloy/errors.rs index e3f917196f..6b51c0042d 100644 --- a/crates/ethrpc/src/alloy/errors.rs +++ b/crates/ethrpc/src/alloy/errors.rs @@ -1,4 +1,4 @@ -use alloy::{contract::Error as ContractError, transports::RpcError}; +use {alloy_contract::Error as ContractError, alloy_transport::RpcError}; /// Bubbles up node errors, ignoring all other errors. pub fn ignore_non_node_error(result: Result) -> anyhow::Result> { @@ -16,6 +16,12 @@ pub trait ContractErrorExt { /// Returns whether a given error is a node error. fn is_node_error(&self) -> bool; + + /// Contract-level rejection of the call: an explicit revert (including + /// empty-data reverts from missing selectors, which [`is_contract_error`] + /// misses) or a `0x` response. Transport failures and caller-side bugs + /// return `false` so they keep bubbling up for retry. + fn is_contract_revert(&self) -> bool; } impl ContractErrorExt for ContractError { @@ -50,32 +56,75 @@ impl ContractErrorExt for ContractError { _ => false, } } + + fn is_contract_revert(&self) -> bool { + match self { + // Revert data, geth code 3, a "revert" message, or specifically + // the `INVALID`/0xFE opcode that older Solidity emits when no + // selector matches — all are deterministic contract-level + // rejections. Other EVM halts (e.g. `InvalidJump`) can stem from + // bad input rather than a contract-level rejection, so we don't + // lump them in here. Other ErrorResps (rate limits, bad params) + // are transport and must retry. + ContractError::TransportError(RpcError::ErrorResp(err)) => { + let message = err.message.to_lowercase(); + err.as_revert_data().is_some() + // https://github.com/ethereum/go-ethereum/blob/8e2107dc39dc9dab132150ec915e7ac299f9eb48/internal/ethapi/errors.go#L42-L46 + // https://github.com/alloy-rs/alloy/blob/b6753088241a50730c092bdba7036f52887c4c57/crates/rpc-types-eth/src/error.rs#L32 + || err.code == 3 + || message.contains("revert") + // anvil/revm surfaces halt reasons as + // `EVM error `. Match only the `INVALID` + // (0xFE) opcode here — older Solidity (e.g. Bancor BNT) + // emits it on a missing selector, which is a contract- + // level rejection. Other halts are intentionally excluded. + || message.contains("invalidfeopcode") + } + ContractError::ZeroData(..) + | ContractError::UnknownFunction(..) + | ContractError::UnknownSelector(..) => true, + _ => false, + } + } } /// Create an arbitrary alloy error that will convert into a "contract" error. /// Useful for testing. #[cfg(any(test, feature = "test-util"))] -pub fn testing_alloy_contract_error() -> alloy::contract::Error { - alloy::contract::Error::NotADeploymentTransaction +pub fn testing_alloy_contract_error() -> alloy_contract::Error { + alloy_contract::Error::NotADeploymentTransaction } /// Create an arbitrary alloy error that will convert into a "node" error. /// Useful for testing. #[cfg(any(test, feature = "test-util"))] -pub fn testing_alloy_node_error() -> alloy::contract::Error { - alloy::contract::Error::TransportError(alloy::transports::TransportError::ErrorResp( - alloy::rpc::json_rpc::ErrorPayload::internal_error(), +pub fn testing_alloy_node_error() -> alloy_contract::Error { + alloy_contract::Error::TransportError(alloy_transport::TransportError::ErrorResp( + alloy_json_rpc::ErrorPayload::internal_error(), )) } #[cfg(test)] mod tests { - use crate::alloy::errors::{ - ContractErrorExt, - testing_alloy_contract_error, - testing_alloy_node_error, + use { + crate::alloy::errors::{ + ContractErrorExt, + testing_alloy_contract_error, + testing_alloy_node_error, + }, + alloy_contract::Error as ContractError, + alloy_json_rpc::ErrorPayload, + alloy_transport::TransportError, }; + fn error_resp(code: i64, message: &'static str) -> ContractError { + ContractError::TransportError(TransportError::ErrorResp(ErrorPayload { + code, + message: message.into(), + data: None, + })) + } + #[test] fn test_contract_error() { assert!(testing_alloy_contract_error().is_contract_error()); @@ -87,4 +136,50 @@ mod tests { assert!(!testing_alloy_contract_error().is_node_error()); assert!(testing_alloy_node_error().is_node_error()); } + + #[test] + fn contract_revert_accepts_empty_data_reverts() { + // Geth-family "execution reverted" with no data — the USDC case. + assert!(error_resp(3, "execution reverted").is_contract_revert()); + // Non-standard code but unmistakable message. + assert!(error_resp(-32000, "execution reverted at pc=...").is_contract_revert()); + assert!(error_resp(-32000, "VM Exception: revert").is_contract_revert()); + // Case-insensitive: capitalized node messages still match. + assert!(error_resp(-32000, "Execution Reverted").is_contract_revert()); + } + + #[test] + fn contract_revert_accepts_invalid_fe_opcode_halt() { + // anvil surfaces the INVALID (0xFE) opcode as `EVM error InvalidFEOpcode` + // — older Solidity (e.g. Bancor BNT) emits it on a missing selector. + assert!(error_resp(-32603, "EVM error InvalidFEOpcode").is_contract_revert()); + // Case-insensitive match. + assert!(error_resp(-32603, "evm error invalidfeopcode").is_contract_revert()); + } + + #[test] + fn contract_revert_rejects_other_evm_halts() { + // Other halts (e.g. `InvalidJump`) can be triggered by bad input + // rather than a contract-level rejection, so they must keep bubbling + // up rather than being classified as reverts. + assert!(!error_resp(-32603, "EVM error InvalidJump").is_contract_revert()); + assert!(!error_resp(-32603, "EVM error OpcodeNotFound").is_contract_revert()); + assert!(!error_resp(-32603, "EVM error StackUnderflow").is_contract_revert()); + } + + #[test] + fn contract_revert_rejects_transport_failures() { + // Generic internal error without revert context — likely transport. + assert!(!testing_alloy_node_error().is_contract_revert()); + // Rate-limit-like codes without a revert message. + assert!(!error_resp(429, "too many requests").is_contract_revert()); + assert!(!error_resp(-32005, "daily request count exceeded").is_contract_revert()); + } + + #[test] + fn contract_revert_rejects_caller_usage_bugs() { + // `NotADeploymentTransaction` and siblings are local-usage errors, + // not contract behaviour — must not be classified as reverts. + assert!(!testing_alloy_contract_error().is_contract_revert()); + } } diff --git a/crates/ethrpc/src/alloy/evm_ext.rs b/crates/ethrpc/src/alloy/evm_ext.rs new file mode 100644 index 0000000000..e07ef24378 --- /dev/null +++ b/crates/ethrpc/src/alloy/evm_ext.rs @@ -0,0 +1,69 @@ +//! This module contains extensions specific to `evm_` RPC calls that alloy does +//! not provide (even though `anvil_` versions may exist). + +use { + alloy_primitives::BlockTimestamp, + alloy_provider::Provider, + alloy_transport::{RpcError, TransportErrorKind}, +}; + +/// Transport extensions based on the `evm_` namespace. +pub trait EvmProviderExt { + /// Set the automatic mining of new blocks with each new transaction + /// submitted to the network. + fn evm_set_automine( + &self, + automine: bool, + ) -> impl std::future::Future>> + Send; + + /// Sets the timestamp for the next block and increases the time + /// accordingly. + fn evm_set_next_block_timestamp( + &self, + timestamp: BlockTimestamp, + ) -> impl std::future::Future>> + Send; + + /// Enables (if `interval != 0`) or disables (if `interval == 0`) automatic + /// block mining with the given `interval` of milliseconds. + fn evm_set_interval_mining( + &self, + interval_ms: u64, + ) -> impl std::future::Future>> + Send; + + /// Sets the block gas limit for the following blocks. + fn evm_set_block_gas_limit( + &self, + gas_limit: u64, + ) -> impl std::future::Future>> + Send; +} + +impl EvmProviderExt for T { + async fn evm_set_automine(&self, automine: bool) -> Result<(), RpcError> { + self.raw_request("evm_setAutomine".into(), (automine,)) + .await + } + + async fn evm_set_next_block_timestamp( + &self, + timestamp: BlockTimestamp, + ) -> Result<(), RpcError> { + self.raw_request("evm_setNextBlockTimestamp".into(), (timestamp,)) + .await + } + + async fn evm_set_interval_mining( + &self, + interval_ms: u64, + ) -> Result<(), RpcError> { + self.raw_request("evm_setIntervalMining".into(), (interval_ms,)) + .await + } + + async fn evm_set_block_gas_limit( + &self, + gas_limit: u64, + ) -> Result> { + self.raw_request("evm_setBlockGasLimit".into(), (gas_limit,)) + .await + } +} diff --git a/crates/ethrpc/src/alloy/instrumentation.rs b/crates/ethrpc/src/alloy/instrumentation.rs index 38d0d8b36f..f7b8879dd2 100644 --- a/crates/ethrpc/src/alloy/instrumentation.rs +++ b/crates/ethrpc/src/alloy/instrumentation.rs @@ -9,15 +9,11 @@ //! trait to conveniently create a new `Provider` with an additional //! [`LabelingLayer`]. use { - crate::alloy::RpcClientRandomIdExt, - alloy::{ - providers::{DynProvider, Provider, ProviderBuilder}, - rpc::{ - client::RpcClient, - json_rpc::{RequestPacket, ResponsePacket, SerializedRequest}, - }, - transports::TransportError, - }, + crate::{Web3, alloy::RpcClientRandomIdExt}, + alloy_json_rpc::{RequestPacket, ResponsePacket, SerializedRequest}, + alloy_provider::{Provider, ProviderBuilder}, + alloy_rpc_client::RpcClient, + alloy_transport::TransportError, std::{ fmt::Debug, pin::Pin, @@ -151,16 +147,29 @@ where pub trait ProviderLabelingExt { /// Creates a new provider tagged with another label. - fn labeled(&self, label: String) -> Self; + fn labeled(&self, label: S) -> Self; } -impl ProviderLabelingExt for DynProvider { - fn labeled(&self, label: String) -> Self { - let is_local = self.client().is_local(); - let transport = self.client().transport().clone(); - let transport_with_label = LabelingLayer { label }.layer(transport); +impl ProviderLabelingExt for Web3 { + fn labeled(&self, label: S) -> Self { + let is_local = self.provider.client().is_local(); + let transport = self.provider.client().transport().clone(); + let transport_with_label = LabelingLayer { + label: label.to_string(), + } + .layer(transport); let client = RpcClient::with_random_id(transport_with_label, is_local); - ProviderBuilder::new().connect_client(client).erased() + let alloy = ProviderBuilder::new() + .wallet(self.wallet.clone()) + // TODO: eventually remove this and all the other simple nonce managers + .with_simple_nonce_management() + .connect_client(client) + .erased(); + + Self { + provider: alloy, + wallet: self.wallet.clone(), + } } } diff --git a/crates/ethrpc/src/alloy/mod.rs b/crates/ethrpc/src/alloy/mod.rs index 914e7e3251..f28fdd869d 100644 --- a/crates/ethrpc/src/alloy/mod.rs +++ b/crates/ethrpc/src/alloy/mod.rs @@ -1,34 +1,27 @@ mod buffering; -pub mod conversions; pub mod errors; +mod evm_ext; mod instrumentation; mod wallet; use { crate::{AlloyProvider, Config}, - alloy::{ - network::EthereumWallet, - providers::{Provider, ProviderBuilder}, - rpc::client::{ClientBuilder, RpcClient}, - }, + alloy_provider::{Provider, ProviderBuilder}, + alloy_rpc_client::{ClientBuilder, RpcClient}, buffering::BatchCallLayer, instrumentation::{InstrumentationLayer, LabelingLayer}, - std::time::Duration, }; -pub use {conversions::Account, instrumentation::ProviderLabelingExt, wallet::MutWallet}; +pub use {evm_ext::EvmProviderExt, instrumentation::ProviderLabelingExt, wallet::MutWallet}; /// Creates an [`RpcClient`] from the given URL with [`LabelingLayer`], /// [`InstrumentationLayer`] and [`BatchCallLayer`]. -fn rpc(url: &str) -> RpcClient { +fn rpc(url: &str, config: Config, label: Option<&str>) -> RpcClient { ClientBuilder::default() .layer(LabelingLayer { - label: "main".into(), + label: label.unwrap_or("main").into(), }) .layer(InstrumentationLayer) - .layer(BatchCallLayer::new(Config { - ethrpc_batch_delay: Duration::ZERO, - ..Default::default() - })) + .layer(BatchCallLayer::new(config)) .http(url.parse().unwrap()) } @@ -38,10 +31,10 @@ fn rpc(url: &str) -> RpcClient { /// /// This is useful for components that need to avoid batching (e.g., block /// stream polling on high-frequency chains). -fn unbuffered_rpc(url: &str) -> RpcClient { +fn unbuffered_rpc(url: &str, label: Option<&str>) -> RpcClient { ClientBuilder::default() .layer(LabelingLayer { - label: "main_unbuffered".into(), + label: label.unwrap_or("main_unbuffered").into(), }) .layer(InstrumentationLayer) .http(url.parse().unwrap()) @@ -53,8 +46,8 @@ fn unbuffered_rpc(url: &str) -> RpcClient { /// Useful for read-only operations like block polling. /// /// Returns a copy of the [`MutWallet`] so the caller can modify it later. -pub fn unbuffered_provider(url: &str) -> (AlloyProvider, MutWallet) { - let rpc = unbuffered_rpc(url); +pub fn unbuffered_provider(url: &str, label: Option<&str>) -> (AlloyProvider, MutWallet) { + let rpc = unbuffered_rpc(url, label); let wallet = MutWallet::default(); let provider = ProviderBuilder::new() .wallet(wallet.clone()) @@ -68,13 +61,13 @@ pub fn unbuffered_provider(url: &str) -> (AlloyProvider, MutWallet) { /// Creates a provider with the provided URL and an empty [`MutWallet`]. /// /// Returns a copy of the [`MutWallet`] so the caller can modify it later. -pub fn provider(url: &str) -> (AlloyProvider, MutWallet) { - let rpc = rpc(url); +pub fn provider(url: &str, config: Config, label: Option<&str>) -> (AlloyProvider, MutWallet) { + let rpc = rpc(url, config, label); let wallet = MutWallet::default(); let provider = ProviderBuilder::new() .wallet(wallet.clone()) // will query the node for the nonce every time that it is needed - // adds overhead but makes working with alloy/ethcontract at the same time much simpler + // adds overhead but makes working with alloy at the same time much simpler .with_simple_nonce_management() .connect_client(rpc) .erased(); @@ -102,9 +95,6 @@ impl RpcClientRandomIdExt for RpcClient { } pub trait ProviderSignerExt { - /// Creates a new provider with the given signer. - fn with_signer(&self, signer: Account) -> Self; - /// Creates a new provider without any signers. /// This is only ever useful if you configured /// anvil to impersonate some account and want @@ -114,24 +104,6 @@ pub trait ProviderSignerExt { } impl ProviderSignerExt for AlloyProvider { - fn with_signer(&self, signer: Account) -> Self { - let Account::Signer(signer) = signer else { - // Otherwise an unlocked account is used, not need to change anything. - return self.clone(); - }; - - let is_local = self.client().is_local(); - let transport = self.client().transport().clone(); - let wallet = EthereumWallet::new(signer); - let client = RpcClient::with_random_id(transport, is_local); - - ProviderBuilder::new() - .wallet(wallet) - .with_simple_nonce_management() - .connect_client(client) - .erased() - } - fn without_wallet(&self) -> Self { let is_local = self.client().is_local(); let transport = self.client().transport().clone(); @@ -148,12 +120,10 @@ impl ProviderSignerExt for AlloyProvider { mod test_util { use { super::*, - alloy::{ - contract::{CallBuilder, CallDecoder}, - primitives::TxHash, - providers::Network, - rpc::types::TransactionRequest, - }, + alloy_contract::{CallBuilder, CallDecoder}, + alloy_primitives::TxHash, + alloy_provider::Network, + alloy_rpc_types::TransactionRequest, std::time::Duration, tokio::time::timeout, }; @@ -197,6 +167,6 @@ mod test_util { } } -use alloy::{rpc::client::RpcClientInner, transports::IntoBoxTransport}; #[cfg(feature = "test-util")] pub use test_util::{CallBuilderExt, ProviderExt}; +use {alloy_rpc_client::RpcClientInner, alloy_transport::IntoBoxTransport}; diff --git a/crates/ethrpc/src/alloy/wallet.rs b/crates/ethrpc/src/alloy/wallet.rs index 69ee7a6d0c..054b55cb6e 100644 --- a/crates/ethrpc/src/alloy/wallet.rs +++ b/crates/ethrpc/src/alloy/wallet.rs @@ -1,11 +1,9 @@ use { - alloy::{ - consensus::{TxEnvelope, TypedTransaction}, - network::{Ethereum, EthereumWallet, Network, NetworkWallet, TxSigner}, - primitives::Address, - signers::Signature, - transports::impl_future, - }, + alloy_consensus::{TxEnvelope, TypedTransaction}, + alloy_network::{Ethereum, EthereumWallet, Network, NetworkWallet, TxSigner}, + alloy_primitives::Address, + alloy_signer::Signature, + alloy_transport::impl_future, std::{sync::Arc, thread}, tokio::sync::RwLock, }; @@ -126,7 +124,7 @@ where &self, sender: Address, tx: N::UnsignedTx, - ) -> impl_future!(>) { + ) -> impl_future!(>) { async move { let r_lock = self.0.read().await; >::sign_transaction_from(&r_lock, sender, tx).await diff --git a/crates/ethrpc/src/block_stream/mod.rs b/crates/ethrpc/src/block_stream.rs similarity index 56% rename from crates/ethrpc/src/block_stream/mod.rs rename to crates/ethrpc/src/block_stream.rs index 3d20fb25fb..f515bd2bb3 100644 --- a/crates/ethrpc/src/block_stream/mod.rs +++ b/crates/ethrpc/src/block_stream.rs @@ -1,20 +1,14 @@ use { - crate::{ - AlloyProvider, - alloy::{ProviderLabelingExt, conversions::IntoLegacy}, - }, - alloy::{ - eips::{BlockId, BlockNumberOrTag}, - providers::{Provider, ProviderBuilder}, - rpc::types::Block, - transports::ws::WsConnect, - }, - anyhow::{Context as _, Result, anyhow, ensure}, - futures::{StreamExt, TryStreamExt, stream::FuturesUnordered}, - primitive_types::{H256, U256}, + crate::AlloyProvider, + alloy_eips::{BlockId, BlockNumberOrTag}, + alloy_primitives::{B256, U256}, + alloy_provider::{Provider, ProviderBuilder}, + alloy_rpc_types::Block, + alloy_transport_ws::WsConnect, + anyhow::{Context as _, Result, anyhow}, + futures::StreamExt, std::{ fmt::Debug, - num::NonZeroU64, time::{Duration, Instant}, }, tokio::sync::watch, @@ -23,42 +17,18 @@ use { url::Url, }; -pub type BlockNumberHash = (u64, H256); - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RangeInclusive { - start: T, - end: T, -} - -impl RangeInclusive { - pub fn try_new(start: T, end: T) -> Result { - ensure!(end >= start, "end has to be bigger or equal to start"); - Ok(Self { start, end }) - } - - pub fn start(&self) -> &T { - &self.start - } - - pub fn end(&self) -> &T { - &self.end - } - - pub fn into_inner(self) -> (T, T) { - (self.start, self.end) - } -} +pub type BlockNumberHash = (u64, B256); /// Block information. #[derive(Clone, Copy, Debug, Eq)] pub struct BlockInfo { pub number: u64, - pub hash: H256, - pub parent_hash: H256, + pub hash: B256, + pub parent_hash: B256, pub timestamp: u64, pub gas_limit: U256, pub gas_price: U256, + pub base_fee: u64, /// When the system noticed the new block. pub observed_at: Instant, } @@ -72,6 +42,7 @@ impl Default for BlockInfo { timestamp: Default::default(), gas_limit: Default::default(), gas_price: Default::default(), + base_fee: Default::default(), observed_at: Instant::now(), } } @@ -92,36 +63,27 @@ impl TryFrom for BlockInfo { type Error = anyhow::Error; fn try_from(value: Block) -> std::result::Result { - Ok(Self { - number: value.header.number, - hash: value.header.hash.into_legacy(), - parent_hash: value.header.parent_hash.into_legacy(), - timestamp: value.header.timestamp, - gas_limit: primitive_types::U256::from(value.header.gas_limit), - gas_price: value - .header - .base_fee_per_gas - .map(primitive_types::U256::from) - .context("no gas price")?, - observed_at: Instant::now(), - }) + value.header.try_into() } } -impl TryFrom for BlockInfo { +impl TryFrom for BlockInfo { type Error = anyhow::Error; - fn try_from(value: alloy::rpc::types::Header) -> std::result::Result { + fn try_from(value: alloy_rpc_types::Header) -> std::result::Result { Ok(Self { number: value.number, - hash: value.hash.into_legacy(), - parent_hash: value.parent_hash.into_legacy(), + hash: value.hash, + parent_hash: value.parent_hash, timestamp: value.timestamp, - gas_limit: primitive_types::U256::from(value.gas_limit), + gas_limit: U256::from(value.gas_limit), gas_price: value .base_fee_per_gas - .map(primitive_types::U256::from) + .map(U256::from) .context("no gas price")?, + base_fee: value + .base_fee_per_gas + .ok_or_else(|| anyhow!("no base fee available"))?, observed_at: Instant::now(), }) } @@ -245,10 +207,10 @@ pub async fn current_block_stream( ) -> Result { // Build an alloy transport specifically for the current block stream to avoid // batching requests together on chains with a very high block frequency. - let (provider, _) = crate::alloy::unbuffered_provider(url.as_str()); - let provider = provider.labeled("base_currentBlockStream".into()); + let (provider, _) = + crate::alloy::unbuffered_provider(url.as_str(), Some("base_currentBlockStream")); - let first_block = provider.current_block().await?; + let first_block = get_block_at_id(&provider, BlockId::latest()).await?; tracing::debug!(number=%first_block.number, hash=?first_block.hash, "polled block"); let (sender, receiver) = watch::channel(first_block); @@ -256,7 +218,7 @@ pub async fn current_block_stream( let mut previous_block = first_block; loop { tokio::time::sleep(poll_interval).await; - let block = match provider.current_block().await { + let block = match get_block_at_id(&provider, BlockId::latest()).await { Ok(block) => block, Err(err) => { tracing::warn!("failed to get current block: {:?}", err); @@ -298,48 +260,6 @@ pub async fn current_block_stream( Ok(receiver) } -/// Returns a stream that is synchronized to the passed in stream by only yields -/// every nth update of the original stream. -pub fn throttle(blocks: CurrentBlockWatcher, updates_to_skip: NonZeroU64) -> CurrentBlockWatcher { - let first_block = *blocks.borrow(); - - // `receiver` yields `first_block` immediately. - let (sender, receiver) = watch::channel(first_block); - - let update_future = async move { - let mut skipped_updates = 0; - - // The `block_stream` would yield `first_block` immediately and since `receiver` - // is already guaranteed to yield that block by construction we skip 1 - // update right away to avoid yielding `first_block` twice from the - // throttled stream. - let mut block_stream = into_stream(blocks).skip(1); - - while let Some(block) = block_stream.next().await { - if skipped_updates == updates_to_skip.get() { - // reset counter - skipped_updates = 0; - } else { - // Don't update the throttled stream because we didn't skip enough updates yet. - skipped_updates += 1; - continue; - } - - if let Err(err) = sender.send(block) { - tracing::error!( - ?err, - "failed to send block to stream, aborting polling loop" - ); - panic!("polling loop terminated due to sender failure"); - } - } - }; - tokio::task::spawn( - update_future.instrument(tracing::info_span!("current_block_stream_throttled")), - ); - receiver -} - /// A method for creating a block stream with an initial value that never /// observes any new blocks. This is useful for testing and creating "mock" /// components. @@ -356,84 +276,13 @@ pub fn into_stream(receiver: CurrentBlockWatcher) -> WatchStream { WatchStream::new(receiver) } -/// Trait for abstracting the retrieval of the block information such as the -/// latest block number. -#[async_trait::async_trait] -pub trait BlockRetrieving: Debug + Send + Sync + 'static { - async fn current_block(&self) -> Result; - async fn block(&self, number: u64) -> Result; - async fn blocks(&self, range: RangeInclusive) -> Result>; -} - -#[async_trait::async_trait] -impl BlockRetrieving for AlloyProvider { - async fn current_block(&self) -> Result { - get_block_at_id(self, BlockId::latest()).await?.try_into() - } - - async fn block(&self, number: u64) -> Result { - let block = get_block_at_id(self, BlockId::number(number)).await?; - Ok((block.header.number, block.header.hash.into_legacy())) - } - - /// Gets all blocks requested in the range. For successful results it's - /// enforced that all the blocks are present, in the correct order and that - /// there are no reorgs in the block range. - async fn blocks(&self, range: RangeInclusive) -> Result> { - let (start, end) = range.into_inner(); - - // Uses FuturesUnordered instead of try_join_all, since the latter - // starts using FuturesOrdered once the number of futures exceeds 30, which - // doesn't support fail-fast behavior. - let futures = FuturesUnordered::new(); - for block_num in start..=end { - let block_id = BlockNumberOrTag::Number(block_num).into(); - let provider = self.clone(); - futures.push(async move { - provider - .get_block(block_id) - .await - .with_context(|| format!("failed to fetch block {block_num}"))? - .with_context(|| format!("missing block {block_num}")) - }); - } - - let mut blocks: Vec = futures.try_collect().await?; - - // Sort the same way as the requested range - blocks.sort_by_key(|block| block.number()); - - let mut prev_hash = None; - let mut result = Vec::with_capacity(blocks.len()); - - for block in blocks { - let current_hash: H256 = block.header.hash.into_legacy(); - if prev_hash.is_some_and(|prev| prev != block.header.parent_hash.into_legacy()) { - tracing::debug!( - start, - end, - ?prev_hash, - parent_hash = ?block.header.parent_hash, - block_number = ?block.number(), - "inconsistent parent in block range" - ); - return Err(anyhow!("inconsistent block range")); - } - prev_hash = Some(current_hash); - - result.push((block.number(), current_hash)); - } - - Ok(result) - } -} - -async fn get_block_at_id(provider: &AlloyProvider, id: BlockId) -> Result { +pub async fn get_block_at_id(provider: &AlloyProvider, id: BlockId) -> Result { let block = provider .get_block(id) .await .with_context(|| format!("failed to get block for {id:?}"))? - .with_context(|| format!("no block for {id:?}"))?; + .with_context(|| format!("no block for {id:?}"))? + .try_into()?; Ok(block) } @@ -466,8 +315,8 @@ pub async fn block_number_to_block_number_hash( let block = provider .get_block_by_number(block_number) .await? - .context("block should exists")?; - Ok((block.header.number, block.header.hash.into_legacy())) + .with_context(|| format!("failed to find block {}", block_number))?; + Ok((block.header.number, block.header.hash)) } #[derive(prometheus_metric_storage::MetricStorage)] @@ -532,11 +381,13 @@ mod tests { #[tokio::test] #[ignore] async fn mainnet() { - observe::tracing::initialize(&observe::Config::default().with_env_filter("shared=debug")); + observe::tracing::init::initialize( + &observe::Config::default().with_env_filter("shared=debug"), + ); let alloy_provider = Web3::new_from_env(); let ws_node = std::env::var("NODE_WS_URL").unwrap().parse().unwrap(); - let receiver = current_block_ws_stream(alloy_provider.alloy, ws_node) + let receiver = current_block_ws_stream(alloy_provider.provider, ws_node) .await .unwrap(); let mut stream = into_stream(receiver); @@ -546,85 +397,6 @@ mod tests { } } - #[tokio::test] - #[ignore] - async fn current_blocks_test() { - let web3 = Web3::new_from_env(); - - // single block - let range = RangeInclusive::try_new(5, 5).unwrap(); - let blocks = web3.alloy.blocks(range).await.unwrap(); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks.last().unwrap().0, 5); - - // multiple blocks - let range = RangeInclusive::try_new(5, 8).unwrap(); - let blocks = web3.alloy.blocks(range).await.unwrap(); - assert_eq!(blocks.len(), 4); - assert_eq!(blocks.last().unwrap().0, 8); - assert_eq!(blocks.first().unwrap().0, 5); - - // shortened blocks - let current_block_number = 5u64; - let length = 25u64; - let range = RangeInclusive::try_new( - current_block_number.saturating_sub(length), - current_block_number, - ) - .unwrap(); - let blocks = web3.alloy.blocks(range).await.unwrap(); - assert_eq!(blocks.len(), 6); - assert_eq!(blocks.last().unwrap().0, 5); - assert_eq!(blocks.first().unwrap().0, 0); - } - - // Tests that a throttled block stream indeed skips the configured - // number of updates. - // Always awaits the next block on a timer to not get the test stuck - // when we want to assert that no new block is coming. - #[tokio::test] - async fn throttled_skips_blocks_test() { - let (sender, receiver) = watch::channel(new_block(0)); - const TIMEOUT: Duration = Duration::from_millis(10); - - // stream that yields every other block - let throttled = throttle(receiver, 1.try_into().unwrap()); - let mut stream = into_stream(throttled); - - // Initial block of the original stream gets yielded immediately. - // which is consistent with an unthrottled stream. - let block = timeout(TIMEOUT, stream.next()).await.unwrap().unwrap(); - assert_eq!(block.number, 0); - - // Doesn't yield the first block twice - let block = timeout(TIMEOUT, stream.next()).await; - assert!(block.is_err()); - - sender.send(new_block(1)).unwrap(); - - // first update gets skipped - let block = timeout(TIMEOUT, stream.next()).await; - assert!(block.is_err()); - - sender.send(new_block(2)).unwrap(); - - // second update gets forwarded - let block = timeout(TIMEOUT, stream.next()).await.unwrap().unwrap(); - assert_eq!(block.number, 2); - - sender.send(new_block(3)).unwrap(); - - // third update getes skipped again - let block = timeout(TIMEOUT, stream.next()).await; - assert!(block.is_err()); - - sender.send(new_block(4)).unwrap(); - - // fourth update gets forwarded again - let block = timeout(TIMEOUT, stream.next()).await.unwrap().unwrap(); - assert_eq!(block.number, 4); - } - #[tokio::test] async fn test_next_block() { let (sender, receiver) = watch::channel(new_block(0)); diff --git a/crates/ethrpc/src/buffered.rs b/crates/ethrpc/src/buffered.rs deleted file mode 100644 index c942c4ef90..0000000000 --- a/crates/ethrpc/src/buffered.rs +++ /dev/null @@ -1,600 +0,0 @@ -//! A buffered `Transport` implementation that automatically groups JSON RPC -//! requests into batches. - -use { - super::MAX_BATCH_SIZE, - ethcontract::{ - jsonrpc::Call, - web3::{BatchTransport, Error as Web3Error, RequestId, Transport}, - }, - futures::{ - channel::{mpsc, oneshot}, - future::{self, BoxFuture, FutureExt as _}, - stream::{self, FusedStream, Stream, StreamExt as _}, - }, - serde_json::Value, - std::{ - collections::{BTreeMap, BTreeSet}, - fmt::Write, - future::Future, - num::NonZeroUsize, - sync::Arc, - time::Duration, - }, - tokio::task::JoinHandle, - tracing::Instrument as _, -}; - -/// Buffered transport configuration. -#[derive(Debug)] -pub struct Configuration { - /// The maximum amount of concurrent batches to send to the node. - /// - /// Specifying `None` means no limit on concurrency. - pub max_concurrent_requests: Option, - /// The maximum batch size. - pub max_batch_len: usize, - /// An additional minimum delay to wait for collecting requests. - /// - /// The delay starts counting after receiving the first request. - pub batch_delay: Duration, -} - -impl Default for Configuration { - fn default() -> Self { - // Default configuration behaves kind of like TCP Nagle. - Self { - max_concurrent_requests: NonZeroUsize::new(1), - max_batch_len: MAX_BATCH_SIZE, - batch_delay: Duration::default(), - } - } -} - -/// Buffered `Transport` implementation that implements automatic batching of -/// JSONRPC requests. -#[derive(Clone, Debug)] -pub struct BufferedTransport { - inner: Arc, - calls: mpsc::UnboundedSender, -} - -type RpcResult = Result; - -type CallContext = (RequestId, Call, Option, oneshot::Sender); - -impl BufferedTransport -where - Inner: BatchTransport + Send + Sync + 'static, - Inner::Out: Send, - Inner::Batch: Send, -{ - /// Create a new buffered transport with the default configuration. - pub fn new(inner: Inner) -> Self { - Self::with_config(inner, Default::default()) - } - - /// Creates a new buffered transport with the specified configuration. - pub fn with_config(inner: Inner, config: Configuration) -> Self { - let inner = Arc::new(inner); - let (calls, receiver) = mpsc::unbounded(); - Self::background_worker(inner.clone(), config, receiver); - - Self { inner, calls } - } - - /// Start a background worker for handling batched requests. - fn background_worker( - inner: Arc, - config: Configuration, - calls: mpsc::UnboundedReceiver, - ) -> JoinHandle<()> { - tokio::task::spawn(batched_for_each(config, calls, move |batch| { - let inner = inner.clone(); - async move { - let (mut requests, mut trace_ids, mut senders): (Vec<_>, Vec<_>, Vec<_>) = - itertools::multiunzip( - batch - .into_iter() - .filter(|(_, _, _, sender)| !sender.is_canceled()) - .map(|(id, request, trace_id, sender)| { - ((id, request), trace_id, sender) - }), - ); - match requests.len() { - 0 => (), - 1 => { - let ((id, request), trace_id, sender) = - (requests.remove(0), trace_ids.remove(0), senders.remove(0)); - let result = match (&request, trace_id) { - (Call::MethodCall(_), Some(trace_id)) => { - let span = - observe::distributed_tracing::request_id::info_span(trace_id); - inner.send(id, request).instrument(span).await - } - _ => inner.send(id, request).await, - }; - let _ = sender.send(result); - } - n => { - let results = match build_rpc_metadata(&requests, &trace_ids) { - Ok(metadata) => { - let span = - observe::distributed_tracing::request_id::info_span(metadata); - inner.send_batch(requests).instrument(span).await - } - Err(err) => { - tracing::error!( - ?err, - "failed to build metadata, sending RPC calls without the \ - metadata header" - ); - inner.send_batch(requests).await - } - } - .unwrap_or_else(|err| vec![Err(err); n]); - for (sender, result) in senders.into_iter().zip(results) { - let _ = sender.send(result); - } - } - } - } - })) - } - - /// Queue a call by sending it over calls channel to the background worker. - fn queue_call(&self, id: RequestId, request: Call) -> oneshot::Receiver { - let (sender, receiver) = oneshot::channel(); - let trace_id = observe::distributed_tracing::request_id::from_current_span(); - let context = (id, request, trace_id, sender); - self.calls - .unbounded_send(context) - .expect("worker task unexpectedly dropped"); - receiver - } - - /// Executes a call. - async fn execute_call(&self, id: RequestId, request: Call) -> RpcResult { - let method = match &request { - Call::MethodCall(call) => call.method.as_str(), - _ => "none", - }; - - tracing::trace!(%id, %method, "queueing call"); - - let response = self.queue_call(id, request); - let result = response.await.expect("worker task unexpectedly dropped"); - - tracing::trace!(%id, ok = %result.is_ok(), "received response"); - - result - } -} - -impl Transport for BufferedTransport -where - Inner: BatchTransport + Send + Sync + 'static, - Inner::Out: Send, - Inner::Batch: Send, -{ - type Out = BoxFuture<'static, RpcResult>; - - fn prepare(&self, method: &str, params: Vec) -> (RequestId, Call) { - self.inner.prepare(method, params) - } - - fn send(&self, id: RequestId, request: Call) -> Self::Out { - let this = self.clone(); - - async move { this.execute_call(id, request).await } - .in_current_span() - .boxed() - } -} - -impl BatchTransport for BufferedTransport -where - Inner: BatchTransport + Send + Sync + 'static, - Inner::Out: Send, - Inner::Batch: Send, -{ - type Batch = BoxFuture<'static, Result, Web3Error>>; - - fn send_batch(&self, requests: T) -> Self::Batch - where - T: IntoIterator, - { - let this = self.clone(); - let requests = requests.into_iter().collect::>(); - - async move { - let responses = requests - .into_iter() - .map(|(id, request)| this.execute_call(id, request)); - Ok(future::join_all(responses).await) - } - .in_current_span() - .boxed() - } -} - -/// Batches a stream into chunks. -/// -/// This is very similar to `futures::stream::StreamExt::ready_chunks` with the -/// difference that it allows configuring a minimum delay for a batch, so -/// waiting for a small amount of time to allow the stream to produce additional -/// items, thus decreasing the chance of batches of size 1. -fn batched_for_each( - config: Configuration, - items: St, - work: F, -) -> impl Future -where - St: Stream + FusedStream + Unpin, - F: Fn(Vec) -> Fut, - Fut: Future, -{ - let concurrency_limit = config.max_concurrent_requests.map(NonZeroUsize::get); - - let batches = stream::unfold(items, move |mut items| async move { - let mut chunk = vec![items.next().await?]; - - let delay = tokio::time::sleep(config.batch_delay).fuse(); - futures::pin_mut!(delay); - - while chunk.len() < config.max_batch_len { - futures::select_biased! { - item = items.next() => match item { - Some(item) => chunk.push(item), - None => break, - }, - _ = delay => break, - } - } - - Some((chunk, items)) - }); - - batches.for_each_concurrent(concurrency_limit, work) -} - -/// Builds a metadata string representation for RPC requests. -/// -/// This function takes an iterator of requests and their corresponding trace -/// IDs, and generates a metadata string that groups the requests by their trace -/// IDs and method names. The format of the output string is as follows: -/// -/// `trace_id:method_name(index1,index2,...),method_name(index1,index2,... -/// )|trace_id:...` -/// -/// Each trace ID is followed by a colon and a list of method names. Each method -/// name is followed by a list of indices (representing the position of the -/// request in the original vector) enclosed in parentheses. Different method -/// names are separated by commas. If there are multiple trace IDs, their -/// entries are separated by a pipe character. -/// -/// If a trace ID is `None`, it is represented as "null" in the output string. -/// All requests with absent trace IDs are grouped together under "null". -/// -/// # Arguments -/// -/// * `requests` - A vector of tuples, where each tuple contains a request ID -/// and a `Call` object representing the RPC request. -/// * `trace_ids` - A vector of optional strings representing the trace IDs of -/// the requests. The trace IDs correspond to the requests in the same -/// position in the `requests` vector. -/// -/// # Returns -/// -/// This function returns a string representing the metadata header. -fn build_rpc_metadata( - requests: &[(RequestId, Call)], - trace_ids: &[Option], -) -> anyhow::Result { - // Group the requests by trace ID(sorted) and method name(sorted) where values - // are sorted indices. - let mut grouped_metadata: BTreeMap>> = BTreeMap::new(); - for (idx, ((_, call), trace_id)) in requests.iter().zip(trace_ids).enumerate() { - if let Call::MethodCall(call) = call { - let trace_id = trace_id.clone().unwrap_or("null".to_string()); - grouped_metadata - .entry(trace_id) - .or_default() - .entry(call.method.clone()) - .or_default() - .insert(idx); - } - } - - let mut metadata_str = String::new(); - - let mut grouped_metadata_iter = grouped_metadata.into_iter().peekable(); - while let Some((trace_id, methods)) = grouped_metadata_iter.next() { - // New entry starts with the trace_id - write!(metadata_str, "{trace_id}:")?; - - // Followed by the method names and their indices - let mut methods_iter = methods.into_iter().peekable(); - while let Some((method, indices)) = methods_iter.next() { - write!(metadata_str, "{method}(")?; - - let indices_str = format_indices_as_ranges(indices)?; - write!(metadata_str, "{indices_str}")?; - - write!(metadata_str, ")")?; - - if methods_iter.peek().is_some() { - write!(metadata_str, ",")?; - } - } - - if grouped_metadata_iter.peek().is_some() { - write!(metadata_str, "|")?; - } - } - - Ok(metadata_str) -} - -/// Formats a set of indices as a string of ranges. -/// -/// This function takes a set of indices and formats them as a string where -/// consecutive indices are represented as ranges. For example, the set -/// `{1, 2, 3, 5, 6, 8}` would be formatted as the string `"1..3,5..6,8"`. -/// -/// # Arguments -/// -/// * `indices` - A set of indices to format. The indices should be unique and -/// sorted in ascending order. -/// -/// # Returns -/// -/// This function returns a string representing the indices as ranges. Each -/// range is formatted as `start..end`, and ranges are separated by commas. -/// Single indices (i.e., indices that are not part of a range) are represented -/// as themselves. -fn format_indices_as_ranges(indices: BTreeSet) -> anyhow::Result { - let mut result = String::new(); - let mut indices = indices.into_iter(); - // Initialize the start and last variables with the first index. - let mut start = match indices.next() { - Some(index) => index, - None => return Ok(result), - }; - let mut last = start; - - // Iterate over the rest of the indices - for index in indices { - // If the current index is the next consecutive number, update last index. - if index == last + 1 { - last = index; - // Otherwise, there is no need to accumulate the range anymore. Append - // the range to the result string. - } else { - append_sequence(&mut result, start, last)?; - write!(result, ",")?; - // Reset the start and last indices with the current value. - start = index; - last = index; - } - } - - // Append the remaining data. - append_sequence(&mut result, start, last)?; - - Ok(result) -} - -/// This function formats a range of integers into a condensed string -/// representation and appends it to the given buffer. The format varies based -/// on the relationship between `start` and `last`: -/// -/// - If `start` is equal to `last`, it indicates a single value, which is -/// appended as such. -/// - If `start` is one less than `last` (i.e., they are consecutive), both -/// numbers are appended separated by a comma. -/// - Otherwise, the numbers between `start` and `last` (inclusive) are -/// represented as a range using two dots (e.g., "start..last"). -fn append_sequence(buffer: &mut String, start: usize, last: usize) -> core::fmt::Result { - if start == last { - write!(buffer, "{start}") - } else if start == last - 1 { - write!(buffer, "{start},{last}") - } else { - write!(buffer, "{start}..{last}") - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::mock::MockTransport, - ethcontract::{ - U256, - Web3, - jsonrpc::{Id, MethodCall, Params}, - }, - mockall::predicate, - serde_json::json, - }; - - #[tokio::test] - async fn batches_calls_when_joining() { - let transport = MockTransport::new(); - transport - .mock() - .expect_execute_batch() - .with(predicate::eq(vec![ - ("foo".to_owned(), vec![json!(true), json!("stuff")]), - ("bar".to_owned(), vec![json!(42), json!("answer")]), - ])) - .returning(|_| Ok(vec![Ok(json!("hello")), Ok(json!("world"))])); - - let transport = BufferedTransport::new(transport); - - let (foo, bar) = futures::join!( - transport.execute("foo", vec![json!(true), json!("stuff")]), - transport.execute("bar", vec![json!(42), json!("answer")]), - ); - assert_eq!(foo.unwrap(), json!("hello")); - assert_eq!(bar.unwrap(), json!("world")); - } - - #[tokio::test] - async fn no_batching_with_only_one_request() { - let transport = MockTransport::new(); - transport - .mock() - .expect_execute() - .with( - predicate::eq("single".to_owned()), - predicate::eq(vec![json!("request")]), - ) - .returning(|_, _| Ok(json!(42))); - - let transport = BufferedTransport::new(transport); - - let response = transport - .execute("single", vec![json!("request")]) - .await - .unwrap(); - assert_eq!(response, json!(42)); - } - - #[tokio::test] - async fn batches_separate_web3_instances() { - let transport = MockTransport::new(); - transport - .mock() - .expect_execute_batch() - .with(predicate::eq(vec![ - ("eth_chainId".to_owned(), vec![]), - ("eth_chainId".to_owned(), vec![]), - ("eth_chainId".to_owned(), vec![]), - ])) - .returning(|_| { - Ok(vec![ - Ok(json!("0x2a")), - Ok(json!("0x2a")), - Ok(json!("0x2a")), - ]) - }); - - let web3 = Web3::new(BufferedTransport::new(transport)); - - let chain_ids = future::try_join_all(vec![ - web3.clone().eth().chain_id(), - web3.clone().eth().chain_id(), - web3.clone().eth().chain_id(), - ]) - .await - .unwrap(); - - assert_eq!(chain_ids, vec![U256::from(42); 3]); - } - - #[tokio::test] - async fn resolves_call_after_dropping_transport() { - let transport = MockTransport::new(); - transport - .mock() - .expect_execute() - .with(predicate::eq("used".to_owned()), predicate::eq(vec![])) - .returning(|_, _| Ok(json!(1337))); - - let transport = BufferedTransport::new(transport); - - let unused = transport.execute("unused", vec![]); - let unpolled = transport.execute("unpolled", vec![]); - let used = transport.execute("used", vec![]); - drop((unused, transport)); - - assert_eq!(used.await.unwrap(), json!(1337)); - drop(unpolled); - } - - #[test] - fn test_format_indices_as_ranges() { - // empty string - let indices = BTreeSet::new(); - assert_eq!(format_indices_as_ranges(indices).unwrap(), ""); - - // a single value - let indices = vec![2].into_iter().collect(); - assert_eq!(format_indices_as_ranges(indices).unwrap(), "2"); - - // only a range - let indices = vec![1, 2, 3, 4, 5].into_iter().collect(); - assert_eq!(format_indices_as_ranges(indices).unwrap(), "1..5"); - - // 2 subsequent values range - let indices = vec![2, 3].into_iter().collect(); - assert_eq!(format_indices_as_ranges(indices).unwrap(), "2,3"); - - // no ranges - let indices = vec![1, 3, 5, 7].into_iter().collect(); - assert_eq!(format_indices_as_ranges(indices).unwrap(), "1,3,5,7"); - - // ends with a non-range value - let indices = vec![1, 2, 3, 5, 7, 8, 9, 10, 20].into_iter().collect(); - assert_eq!( - format_indices_as_ranges(indices).unwrap(), - "1..3,5,7..10,20" - ); - - // ends with a range value - let indices = vec![1, 2, 3, 5, 6, 7, 8, 10, 11, 12].into_iter().collect(); - assert_eq!( - format_indices_as_ranges(indices).unwrap(), - "1..3,5..8,10..12" - ); - } - - fn method_call(method: &str) -> Call { - Call::MethodCall(MethodCall { - jsonrpc: None, - method: method.to_string(), - params: Params::None, - id: Id::Null, - }) - } - - #[test] - fn test_build_rpc_metadata_header() { - let requests = vec![ - (1001, method_call("eth_sendTransaction")), // 0 - (1001, method_call("eth_call")), // 1 - (1001, method_call("eth_sendTransaction")), // 2 - (1002, method_call("eth_call")), // 3 - (9999, method_call("eth_call")), // 4 - (1001, method_call("eth_sendTransaction")), // 5 - (1002, method_call("eth_call")), // 6 - (1002, method_call("eth_call")), // 7 - (1001, method_call("eth_sendTransaction")), // 8 - (9999, method_call("eth_sendTransaction")), // 9 - (9999, method_call("eth_sendTransaction")), // 10 - (9999, method_call("eth_sendTransaction")), // 11 - ]; - let trace_ids = vec![ - Some("1001".to_string()), // 0 - Some("1001".to_string()), // 1 - Some("1001".to_string()), // 2 - Some("1002".to_string()), // 3 - None, // 4 - Some("1001".to_string()), // 5 - Some("1002".to_string()), // 6 - Some("1002".to_string()), // 7 - Some("1001".to_string()), // 8 - None, // 9 - None, // 10 - None, // 11 - ]; - let metadata_header = build_rpc_metadata(&requests, &trace_ids).unwrap(); - assert_eq!( - metadata_header, - "1001:eth_call(1),eth_sendTransaction(0,2,5,8)|1002:eth_call(3,6,7)|null:eth_call(4),\ - eth_sendTransaction(9..11)" - ); - } -} diff --git a/crates/ethrpc/src/extensions.rs b/crates/ethrpc/src/extensions.rs deleted file mode 100644 index 6eac4944c7..0000000000 --- a/crates/ethrpc/src/extensions.rs +++ /dev/null @@ -1,157 +0,0 @@ -//! Module containing Ethereum RPC extension methods. - -use { - ethcontract::state_overrides::StateOverrides, - serde::Deserialize, - tracing::{Instrument, instrument::Instrumented}, - web3::{ - self, - Transport, - api::Namespace, - helpers::{self, CallFuture}, - types::{BlockId, Bytes, CallRequest, H256}, - }, -}; - -/// Web3 convenience extension trait. -pub trait EthExt -where - T: Transport, -{ - fn call_with_state_overrides( - &self, - call: CallRequest, - block: BlockId, - overrides: StateOverrides, - ) -> Instrumented>; -} - -impl EthExt for web3::api::Eth -where - T: Transport, -{ - fn call_with_state_overrides( - &self, - call: CallRequest, - block: BlockId, - overrides: StateOverrides, - ) -> Instrumented> { - let call = helpers::serialize(&call); - let block = helpers::serialize(&block); - let overrides = helpers::serialize(&overrides); - - CallFuture::new( - self.transport() - .execute("eth_call", vec![call, block, overrides]), - ) - .instrument(tracing::info_span!("eth_call")) - } -} - -/// Debug namespace extension trait. -pub trait DebugNamespace -where - T: Transport, -{ - fn debug(&self) -> Debug; -} - -impl DebugNamespace for web3::Web3 { - fn debug(&self) -> Debug { - self.api() - } -} - -/// `Debug` namespace -#[derive(Debug, Clone)] -pub struct Debug { - transport: T, -} - -impl Namespace for Debug { - fn new(transport: T) -> Self - where - Self: Sized, - { - Debug { transport } - } - - fn transport(&self) -> &T { - &self.transport - } -} - -impl Debug { - /// Returns all debug traces for callTracer type of tracer. - pub fn transaction(&self, hash: H256) -> CallFuture { - let hash = helpers::serialize(&hash); - let tracing_options = serde_json::json!({ "tracer": "callTracer" }); - CallFuture::new( - self.transport() - .execute("debug_traceTransaction", vec![hash, tracing_options]), - ) - } -} - -/// Taken from alloy::rpc::types::trace::geth::CallFrame -#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize)] -pub struct CallFrame { - /// The address of that initiated the call. - pub from: primitive_types::H160, - /// The address of the contract that was called. - #[serde(default)] - pub to: Option, - /// Calldata input. - pub input: Bytes, - /// Recorded child calls. - #[serde(default)] - pub calls: Vec, -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::Web3, - ethcontract::{H160, state_overrides::StateOverride}, - hex_literal::hex, - maplit::hashmap, - web3::types::BlockNumber, - }; - - #[ignore] - #[tokio::test] - async fn can_call_with_state_override() { - let web3 = Web3::new_from_env(); - - let address = H160(hex!("EeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")); - let output = web3 - .eth() - .call_with_state_overrides( - CallRequest { - to: Some(address), - ..Default::default() - }, - BlockNumber::Latest.into(), - hashmap! { - address => StateOverride { - // EVM program to just return 32 bytes from 0 to 31 - code: Some(hex!( - "7f 000102030405060708090a0b0c0d0e0f - 101112131415161718191a1b1c1d1e1f - 60 00 - 52 - 60 20 - 60 00 - f3" - ).into()), - ..Default::default() - }, - }, - ) - .await - .unwrap(); - - assert_eq!(output.0, (0..32).collect::>()); - } -} diff --git a/crates/ethrpc/src/http.rs b/crates/ethrpc/src/http.rs deleted file mode 100644 index 20f110b77f..0000000000 --- a/crates/ethrpc/src/http.rs +++ /dev/null @@ -1,306 +0,0 @@ -use { - ethcontract::jsonrpc as jsonrpc_core, - futures::{FutureExt, future::BoxFuture}, - jsonrpc_core::types::{Call, Output, Request, Value}, - observe::tracing::tracing_headers, - reqwest::{Client, Url, header}, - serde::{Deserialize, Serialize, de::DeserializeOwned}, - std::{ - collections::HashMap, - fmt::{Debug, Formatter}, - sync::{ - Arc, - atomic::{AtomicUsize, Ordering}, - }, - }, - web3::{ - BatchTransport, - RequestId, - Transport, - error::{Error as Web3Error, TransportError}, - helpers, - }, -}; - -#[derive(Clone)] -pub struct HttpTransport { - client: Client, - inner: Arc, -} - -struct Inner { - url: Url, - id: AtomicUsize, - /// Name of the transport used in logs to distinguish different transports. - name: String, -} - -impl HttpTransport { - pub fn new(client: Client, url: Url, name: String) -> Self { - Self { - client, - inner: Arc::new(Inner { - url, - id: AtomicUsize::new(0), - name, - }), - } - } - - fn next_id(&self) -> RequestId { - self.inner.id.fetch_add(1, Ordering::SeqCst) - } - - fn new_request(&self) -> (Client, Arc) { - (self.client.clone(), self.inner.clone()) - } -} - -impl Debug for HttpTransport { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("HttpTransport") - .field("url", &self.inner.url) - .finish() - } -} - -// Id is only used for logging. -async fn execute_rpc( - client: Client, - inner: Arc, - id: RequestId, - request: &Request, -) -> Result { - let body = serde_json::to_string(&request)?; - - let request_id = observe::distributed_tracing::request_id::from_current_span(); - - tracing::trace!(name = %inner.name, %id, %body, "executing request"); - let mut request_builder = client - .post(inner.url.clone()) - .header(header::CONTENT_TYPE, "application/json") - .header("X-RPC-REQUEST-ID", id.to_string()) - .headers(tracing_headers()) - .body(body); - match request { - Request::Single(Call::MethodCall(call)) => { - if let Some(metadata) = &request_id { - request_builder = request_builder.header("X-REQUEST-ID", metadata); - } - request_builder = request_builder.header("X-RPC-METHOD", call.method.clone()); - } - Request::Batch(_) => { - if let Some(ref metadata) = request_id { - request_builder = request_builder.header("X-RPC-BATCH-METADATA", metadata); - } - } - _ => {} - } - let response = request_builder - .send() - .await - .map_err(|err: reqwest::Error| { - tracing::warn!( - name = %inner.name, - rpc_request_id = %id, - request_id, - error = %err, - "failed to send request" - ); - Web3Error::Transport(TransportError::Message(err.to_string())) - })?; - let status = response.status(); - let text = response.text().await.map_err(|err: reqwest::Error| { - tracing::warn!( - name = %inner.name, - rpc_request_id = %id, - request_id, - error = %err, - "failed to get response body" - ); - Web3Error::Transport(TransportError::Message(err.to_string())) - })?; - // Log the raw text before decoding to get more information on responses that - // aren't valid json. Debug encoding so we don't get control characters like - // newlines in the output. - tracing::trace!(name = %inner.name, %id, body = %text.trim(), "received response"); - if !status.is_success() { - let error_msg = format!("HTTP error {status}"); - - return Err(Web3Error::Transport(TransportError::Message(error_msg))); - } - - let result = jsonrpc_core::serde_from_str(&text).map_err(|err| { - tracing::warn!( - name = %inner.name, - rpc_request_id = %id, - request_id, - error = %err, - raw_response = %text.trim(), - "failed to decode JSON response" - ); - Web3Error::Decoder(format!( - "{:?}, raw response: {}, rpc_request_id: {}, request_id: {:?}, {}", - err, - inner.name, - id, - request_id, - text.trim() - )) - })?; - Ok(result) -} - -type RpcResult = Result; - -impl Transport for HttpTransport { - type Out = BoxFuture<'static, RpcResult>; - - fn prepare(&self, method: &str, params: Vec) -> (RequestId, Call) { - let id = self.next_id(); - let request = helpers::build_request(id, method, params); - (id, request) - } - - fn send(&self, id: RequestId, call: Call) -> Self::Out { - let (client, inner) = self.new_request(); - - async move { - let output = execute_rpc(client, inner, id, &Request::Single(call)).await?; - helpers::to_result_from_output(output) - } - .boxed() - } -} - -impl BatchTransport for HttpTransport { - type Batch = BoxFuture<'static, Result, Web3Error>>; - - fn send_batch(&self, requests: T) -> Self::Batch - where - T: IntoIterator, - { - // Batch calls don't need an id but it helps associate the response log to the - // request log. - let id = self.next_id(); - let (client, inner) = self.new_request(); - let (ids, calls): (Vec<_>, Vec<_>) = requests.into_iter().unzip(); - - async move { - let outputs = execute_rpc(client, inner, id, &Request::Batch(calls)).await?; - handle_batch_response(&ids, outputs) - } - .boxed() - } -} - -/// Workaround for Erigon nodes, which encode each element of the Batch Response -/// as a String rather than a deserializable JSON object -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -enum OutputOrString { - String(String), - Output(Output), -} - -impl OutputOrString { - fn try_into_output(self) -> Result { - Ok(match self { - OutputOrString::String(string) => jsonrpc_core::serde_from_str(&string)?, - OutputOrString::Output(output) => output, - }) - } -} - -fn handle_batch_response( - ids: &[RequestId], - outputs: Vec, -) -> Result, Web3Error> { - if ids.len() != outputs.len() { - return Err(Web3Error::InvalidResponse( - "unexpected number of responses".to_string(), - )); - } - let mut outputs = outputs - .into_iter() - .map(|output_or_string| { - let output = output_or_string.try_into_output()?; - Ok(( - id_of_output(&output)?, - helpers::to_result_from_output(output), - )) - }) - .collect::, Web3Error>>()?; - ids.iter() - .map(|id| { - outputs.remove(id).ok_or_else(|| { - Web3Error::InvalidResponse(format!("batch response is missing id {id}")) - }) - }) - .collect() -} - -fn id_of_output(output: &Output) -> Result { - let id = match output { - Output::Success(success) => &success.id, - Output::Failure(failure) => &failure.id, - }; - match id { - jsonrpc_core::Id::Num(num) => Ok(*num as RequestId), - _ => Err(Web3Error::InvalidResponse( - "response id is not u64".to_string(), - )), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn handles_batch_response_being_in_different_order_than_input() { - let ids = vec![0, 1, 2]; - // This order is different from the ids. - let outputs = [1u64, 0, 2] - .iter() - .map(|&id| { - OutputOrString::Output(Output::Success(jsonrpc_core::Success { - jsonrpc: None, - result: id.into(), - id: jsonrpc_core::Id::Num(id), - })) - }) - .collect(); - let results = handle_batch_response(&ids, outputs) - .unwrap() - .into_iter() - .map(|result| result.unwrap().as_u64().unwrap() as usize) - .collect::>(); - // The order of the ids should have been restored. - assert_eq!(ids, results); - } - - #[test] - fn handles_batch_items_that_are_strings() { - let result = handle_batch_response( - &[1], - vec![OutputOrString::String("{\"result\": 1, \"id\": 1}".into())], - ) - .unwrap() - .into_iter() - .map(|result| result.unwrap().as_u64().unwrap() as usize) - .collect::>(); - assert_eq!(vec![1], result); - } - - #[test] - fn errors_on_invalid_string_batch_responses() { - assert!( - handle_batch_response( - &[1], - vec![OutputOrString::String("there is no spoon".into())], - ) - .is_err() - ); - } -} diff --git a/crates/ethrpc/src/instrumented.rs b/crates/ethrpc/src/instrumented.rs deleted file mode 100644 index 0cb9bf9ffb..0000000000 --- a/crates/ethrpc/src/instrumented.rs +++ /dev/null @@ -1,151 +0,0 @@ -use { - crate::alloy::ProviderLabelingExt, - ethcontract::{ - jsonrpc::types::{Call, Value}, - transport::DynTransport, - }, - futures::{FutureExt, future::BoxFuture}, - std::sync::Arc, - web3::{BatchTransport, RequestId, Transport, error::Error as Web3Error}, -}; - -#[derive(prometheus_metric_storage::MetricStorage, Clone, Debug)] -#[metric(subsystem = "rpc")] -struct Metrics { - /// Number of inflight RPC requests for ethereum node. - #[metric(labels("component", "method"))] - requests_inflight: prometheus::IntGaugeVec, - - /// Number of completed RPC requests for ethereum node. - #[metric(labels("component", "method"))] - requests_complete: prometheus::IntCounterVec, - - /// Execution time for each RPC request (batches are counted as one - /// request). - #[metric(labels("component", "method"))] - requests_duration_seconds: prometheus::HistogramVec, - - /// Number of RPC requests initiated within a batch request - #[metric(labels("component", "method"))] - inner_batch_requests_initiated: prometheus::IntCounterVec, -} - -impl Metrics { - #[must_use] - fn on_request_start(&self, label: &str, method: &str) -> impl Drop + use<> { - let requests_inflight = self.requests_inflight.with_label_values(&[label, method]); - let requests_complete = self.requests_complete.with_label_values(&[label, method]); - let requests_duration_seconds = self - .requests_duration_seconds - .with_label_values(&[label, method]); - - requests_inflight.inc(); - let timer = requests_duration_seconds.start_timer(); - - scopeguard::guard(timer, move |timer| { - requests_inflight.dec(); - requests_complete.inc(); - timer.stop_and_record(); - }) - } -} - -#[derive(Debug, Clone)] -pub struct InstrumentedTransport(Arc); - -impl InstrumentedTransport { - pub fn new(label: String, transport: DynTransport) -> Self { - Self(Arc::new(Inner { - metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), - transport, - label, - })) - } - - pub fn with_additional_label(&self, label: String) -> Self { - Self(Arc::new(Inner { - label: format!("{}_{label}", self.0.label), - transport: self.0.transport.clone(), - metrics: self.0.metrics, - })) - } -} - -/// Adds metrics for RPC requests using the provided label. -pub fn instrument_with_label(web3: &crate::Web3, label: String) -> crate::Web3 { - let transport = web3.transport().clone(); - let instrumented = match transport.downcast::() { - Some(instrumented) => instrumented.with_additional_label(label.clone()), - _ => InstrumentedTransport::new(label.clone(), transport), - }; - crate::Web3 { - legacy: web3::Web3::new(DynTransport::new(instrumented)), - alloy: web3.alloy.labeled(label), - wallet: web3.wallet.clone(), - } -} - -#[derive(Debug)] -struct Inner { - metrics: &'static Metrics, - transport: DynTransport, - label: String, -} - -type RpcResult = Result; - -impl Transport for InstrumentedTransport { - type Out = BoxFuture<'static, RpcResult>; - - fn prepare(&self, method: &str, params: Vec) -> (RequestId, Call) { - self.0.transport.prepare(method, params) - } - - fn send(&self, id: RequestId, call: Call) -> Self::Out { - let inner = self.0.clone(); - - async move { - let _guard = inner - .metrics - .on_request_start(&inner.label, method_name(&call)); - inner.transport.send(id, call).await - } - .boxed() - } -} - -impl BatchTransport for InstrumentedTransport { - type Batch = BoxFuture<'static, Result, Web3Error>>; - - fn send_batch(&self, requests: R) -> Self::Batch - where - R: IntoIterator, - { - let inner = self.0.clone(); - let requests: Vec<_> = requests.into_iter().collect(); - - async move { - let _guard = inner.metrics.on_request_start(&inner.label, "batch"); - let metrics = inner.metrics; - let label = &inner.label; - - let requests = requests.into_iter().inspect(move |(_id, call)| { - metrics - .inner_batch_requests_initiated - .with_label_values(&[label, method_name(call)]) - .inc() - }); - - inner.transport.send_batch(requests).await - } - .boxed() - } -} - -fn method_name(call: &Call) -> &str { - match call { - Call::MethodCall(method) => &method.method, - Call::Notification(notification) => ¬ification.method, - Call::Invalid { .. } => "invalid", - } -} diff --git a/crates/ethrpc/src/lib.rs b/crates/ethrpc/src/lib.rs index fe306109d0..b6c5f79f66 100644 --- a/crates/ethrpc/src/lib.rs +++ b/crates/ethrpc/src/lib.rs @@ -1,26 +1,12 @@ pub mod alloy; pub mod block_stream; -pub mod buffered; -pub mod extensions; -pub mod http; -pub mod instrumented; #[cfg(any(test, feature = "test-util"))] pub mod mock; -use { - self::{buffered::BufferedTransport, http::HttpTransport}, - crate::alloy::MutWallet, - ::alloy::providers::DynProvider, - ethcontract::{batch::CallBatch, transport::DynTransport}, - reqwest::{Client, Url}, - std::{num::NonZeroUsize, time::Duration}, - web3::Transport, -}; +use {crate::alloy::MutWallet, alloy_provider::DynProvider, reqwest::Url, std::time::Duration}; pub const MAX_BATCH_SIZE: usize = 100; -pub type Web3Transport = DynTransport; -pub type Web3CallBatch = CallBatch; pub type AlloyProvider = DynProvider; /// This is just a thin wrapper around providers (clients communicating @@ -30,21 +16,12 @@ pub type AlloyProvider = DynProvider; /// to convert each call site to use the new provider bit by bit instead of /// having to everything at once. #[derive(Debug, Clone)] -pub struct Web3 { - pub legacy: web3::Web3, - pub alloy: AlloyProvider, +pub struct Web3 { + pub provider: AlloyProvider, pub wallet: MutWallet, } -impl std::ops::Deref for Web3 { - type Target = web3::Web3; - - fn deref(&self) -> &Self::Target { - &self.legacy - } -} - -impl Web3 { +impl Web3 { // for tests pub fn new_from_env() -> Self { let url = &std::env::var("NODE_URL").unwrap(); @@ -52,12 +29,9 @@ impl Web3 { } pub fn new_from_url(url: &str) -> Self { - let legacy_transport = create_test_transport(url); - let web3 = web3::Web3::new(legacy_transport); - let (alloy, wallet) = crate::alloy::provider(url); + let (alloy, wallet) = crate::alloy::provider(url, Default::default(), None); Self { - legacy: web3, - alloy, + provider: alloy, wallet, } } @@ -78,76 +52,50 @@ pub struct Config { pub ethrpc_batch_delay: Duration, } -impl Config { - /// Returns the buffered transport configuration or `None` if batching is - /// disabled. - fn into_buffered_configuration(self) -> Option { - match ( - self.ethrpc_max_batch_size, - self.ethrpc_max_concurrent_requests, - ) { - (0 | 1, 0) => None, - _ => Some(buffered::Configuration { - max_concurrent_requests: NonZeroUsize::new(self.ethrpc_max_concurrent_requests), - max_batch_len: self.ethrpc_max_batch_size.max(1), - batch_delay: self.ethrpc_batch_delay, - }), - } - } -} - impl Default for Config { fn default() -> Self { Self { ethrpc_max_batch_size: 20, ethrpc_max_concurrent_requests: 10, - ethrpc_batch_delay: Duration::from_millis(5), + ethrpc_batch_delay: Duration::ZERO, } } } -/// Create a Web3 instance. -pub fn web3( - args: Config, - http_factory: reqwest::ClientBuilder, - url: &Url, - name: impl ToString, -) -> Web3 { - let http = http_factory.cookie_store(true).build().unwrap(); - let http = HttpTransport::new(http, url.clone(), name.to_string()); - let buffered_config = args.into_buffered_configuration(); - let (legacy, alloy, wallet) = match buffered_config { - Some(config) => { - let legacy = Web3Transport::new(BufferedTransport::with_config(http, config)); - let (alloy, wallet) = alloy::provider(url.as_str()); - (legacy, alloy, wallet) - } - None => { - let legacy = Web3Transport::new(http); - let (alloy, wallet) = alloy::unbuffered_provider(url.as_str()); - (legacy, alloy, wallet) - } +/// Create a Web3 instance with an optional label for observability. +pub fn web3(args: Config, url: &Url, label: Option<&str>) -> Web3 { + let (alloy, wallet) = match ( + args.ethrpc_max_batch_size, + args.ethrpc_max_concurrent_requests, + ) { + (0 | 1, 0) => alloy::unbuffered_provider(url.as_str(), label), + _ => alloy::provider(url.as_str(), args, label), }; - let instrumented = instrumented::InstrumentedTransport::new(name.to_string(), legacy); Web3 { - legacy: web3::Web3::new(Web3Transport::new(instrumented)), - alloy, + provider: alloy, wallet, } } -/// Convenience method to create a transport from a URL. -pub fn create_test_transport(url: &str) -> Web3Transport { - let http_transport = HttpTransport::new( - Client::builder() - .timeout(Duration::from_secs(10)) - .build() - .unwrap(), - url.try_into().unwrap(), - "test".into(), - ); - let dyn_transport = Web3Transport::new(http_transport); - let instrumented = instrumented::InstrumentedTransport::new("test".into(), dyn_transport); - Web3Transport::new(instrumented) +#[cfg(test)] +mod test { + use {crate::Web3, alloy_eips::BlockId, alloy_provider::Provider}; + + #[tokio::test] + async fn test_https() { + let provider = Web3::new_from_url("https://rpc.mevblocker.io"); + let response = provider.provider.get_block(BlockId::latest()).await; + + if let Err(err) = response { + // only fail the CI if we are sure the error is due to missing + // `https` support + if err.to_string().contains("scheme is not http") { + eprintln!("{err:?}"); + panic!("https support is not enabled"); + } else { + eprintln!("mevblocker error unrelated to https support: {err:?}"); + } + } + } } diff --git a/crates/ethrpc/src/mock.rs b/crates/ethrpc/src/mock.rs index 9a3c6c35a6..82d381b7c7 100644 --- a/crates/ethrpc/src/mock.rs +++ b/crates/ethrpc/src/mock.rs @@ -2,179 +2,28 @@ use { crate::{Web3, alloy::MutWallet}, - alloy::providers::{Provider, ProviderBuilder, mock::Asserter}, - ethcontract::{ - futures::future::{self, Ready}, - jsonrpc::{Call, Id, MethodCall, Params}, - web3::{self, BatchTransport, RequestId, Transport}, - }, - serde_json::Value, - std::{ - fmt::{self, Debug, Formatter}, - sync::{ - Arc, - Mutex, - MutexGuard, - atomic::{AtomicUsize, Ordering}, - }, - }, + alloy_provider::{Provider, ProviderBuilder, mock::Asserter}, }; -pub fn web3() -> Web3 { +impl Web3 { + pub fn with_asserter(asserter: Asserter) -> Self { + Web3 { + // this will not behave like the original mock transport but it's only used + // in one place so let's keep this for now and fix it when we switch to + // alloy in the 1 place that uses the mock provider. + provider: ProviderBuilder::new() + .connect_mocked_client(asserter) + .erased(), + wallet: MutWallet::default(), + } + } +} + +pub fn web3() -> Web3 { Web3 { - legacy: web3::Web3::new(MockTransport::new()), - // this will not behave like the original mock transport but it's only used - // in one place so let's keep this for now and fix it when we switch to - // alloy in the 1 place that uses the mock provider. - alloy: ProviderBuilder::new() + provider: ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), wallet: MutWallet::default(), } } - -/// An intermediate trait used for `mockall` to automatically generate a mock -/// transport for us. -#[mockall::automock] -pub trait MockableTransport { - fn execute(&self, method: String, params: Vec) -> web3::Result; - fn execute_batch( - &self, - requests: Vec<(String, Vec)>, - ) -> web3::Result>>; -} - -#[derive(Clone, Default)] -pub struct MockTransport(Arc); - -#[derive(Default)] -pub struct Inner { - inner: Mutex, - current_id: AtomicUsize, -} - -impl MockTransport { - pub fn new() -> Self { - Self::default() - } - - pub fn mock(&self) -> MutexGuard<'_, MockMockableTransport> { - self.0.inner.lock().unwrap() - } -} - -impl Debug for MockTransport { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct("MockTransport").finish() - } -} - -impl Transport for MockTransport { - type Out = Ready>; - - fn prepare(&self, method: &str, params: Vec) -> (RequestId, Call) { - let id = self.0.current_id.fetch_add(1, Ordering::SeqCst); - ( - id, - Call::MethodCall(MethodCall { - jsonrpc: None, - method: method.to_owned(), - params: Params::Array(params), - id: Id::Null, - }), - ) - } - - fn send(&self, _: RequestId, call: Call) -> Self::Out { - let (method, params) = extract_call(call); - let response = self.mock().execute(method, params); - future::ready(response) - } -} - -impl BatchTransport for MockTransport { - type Batch = Ready>>>; - - fn send_batch(&self, requests: T) -> Self::Batch - where - T: IntoIterator, - { - let batch = requests - .into_iter() - .map(|(_, call)| extract_call(call)) - .collect(); - let responses = self.mock().execute_batch(batch); - future::ready(responses) - } -} - -fn extract_call(call: Call) -> (String, Vec) { - match call { - Call::MethodCall(MethodCall { - method, - params: Params::Array(params), - .. - }) => (method, params), - _ => panic!("unexpected call {call:?}"), - } -} - -#[cfg(test)] -mod tests { - use {super::*, mockall::predicate::*, serde_json::json}; - - #[tokio::test] - async fn can_mock_single_requests() { - let transport = MockTransport::new(); - transport - .mock() - .expect_execute() - .with( - eq("foo_bar".to_owned()), - eq(vec![json!(true), json!("stuff")]), - ) - .returning(|_, _| Ok(json!("hello"))); - - assert_eq!( - transport - .execute("foo_bar", vec![json!(true), json!("stuff")]) - .await - .unwrap(), - json!("hello") - ); - } - - #[tokio::test] - async fn can_mock_batch_requests() { - let transport = MockTransport::new(); - transport - .mock() - .expect_execute_batch() - .with(eq(vec![ - ("foo_bar".to_owned(), vec![json!(true), json!("stuff")]), - ("do_thing".to_owned(), vec![]), - ("fail_thing".to_owned(), vec![json!(42)]), - ])) - .returning(|_| { - Ok(vec![ - Ok(json!("hello")), - Ok(json!("world")), - Err(web3::Error::Transport( - web3::error::TransportError::Message("bad".to_string()), - )), - ]) - }); - - let responses = transport - .send_batch(vec![ - transport.prepare("foo_bar", vec![json!(true), json!("stuff")]), - transport.prepare("do_thing", vec![]), - transport.prepare("fail_thing", vec![json!(42)]), - ]) - .await - .unwrap(); - assert_eq!(responses[0].as_ref().unwrap(), &json!("hello")); - assert_eq!(responses[1].as_ref().unwrap(), &json!("world")); - assert!(responses[2].is_err()); - } -} diff --git a/crates/event-indexing/Cargo.toml b/crates/event-indexing/Cargo.toml new file mode 100644 index 0000000000..a847906d9e --- /dev/null +++ b/crates/event-indexing/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "event-indexing" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-eips = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } +async-stream = { workspace = true } +async-trait = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +futures = { workspace = true } +observe = { workspace = true } +prometheus = { workspace = true } +prometheus-metric-storage = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +alloy-provider = { workspace = true } +contracts = { workspace = true } +mockall = { workspace = true } +tracing-subscriber = { workspace = true } + +[lints] +workspace = true diff --git a/crates/event-indexing/LICENSE-APACHE b/crates/event-indexing/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/event-indexing/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/event-indexing/LICENSE-MIT b/crates/event-indexing/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/event-indexing/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/event-indexing/src/block_retriever.rs b/crates/event-indexing/src/block_retriever.rs new file mode 100644 index 0000000000..8f46f76bfb --- /dev/null +++ b/crates/event-indexing/src/block_retriever.rs @@ -0,0 +1,189 @@ +use { + alloy_eips::{BlockId, BlockNumberOrTag}, + alloy_primitives::B256, + alloy_provider::Provider, + alloy_rpc_types::Block, + anyhow::{Context, Result, anyhow, ensure}, + ethrpc::{ + AlloyProvider, + block_stream::{BlockInfo, BlockNumberHash, get_block_at_id}, + }, + futures::{TryStreamExt, stream::FuturesUnordered}, + std::fmt::Debug, + tokio::sync::watch, + tracing::instrument, +}; + +/// Trait for abstracting the retrieval of the block information such as the +/// latest block number. +#[async_trait::async_trait] +pub trait BlockRetrieving: Debug + Send + Sync + 'static { + async fn current_block(&self) -> Result; + async fn finalized_block(&self) -> Result; + async fn block(&self, number: u64) -> Result; + async fn blocks(&self, range: RangeInclusive) -> Result>; +} + +#[async_trait::async_trait] +impl BlockRetrieving for AlloyProvider { + #[instrument(skip_all)] + async fn current_block(&self) -> Result { + get_block_at_id(&self, BlockId::latest()).await + } + + #[instrument(skip_all)] + async fn finalized_block(&self) -> Result { + get_block_at_id(&self, BlockId::finalized()).await + } + + #[instrument(skip_all)] + async fn block(&self, number: u64) -> Result { + let block = get_block_at_id(&self, BlockId::number(number)).await?; + Ok((block.number, block.hash)) + } + + /// Gets all blocks requested in the range. For successful results it's + /// enforced that all the blocks are present, in the correct order and that + /// there are no reorgs in the block range. + #[instrument(skip_all)] + async fn blocks(&self, range: RangeInclusive) -> Result> { + let (start, end) = range.into_inner(); + + // Uses FuturesUnordered instead of try_join_all, since the latter + // starts using FuturesOrdered once the number of futures exceeds 30, which + // doesn't support fail-fast behavior. + let futures = FuturesUnordered::new(); + for block_num in start..=end { + let block_id = BlockNumberOrTag::Number(block_num).into(); + let provider = self.clone(); + futures.push(async move { + provider + .get_block(block_id) + .await + .with_context(|| format!("failed to fetch block {block_num}"))? + .with_context(|| format!("missing block {block_num}")) + }); + } + + let mut blocks: Vec = futures.try_collect().await?; + + // Sort the same way as the requested range + blocks.sort_by_key(|block| block.number()); + + let mut prev_hash = None; + let mut result = Vec::with_capacity(blocks.len()); + + for block in blocks { + let current_hash: B256 = block.header.hash; + if prev_hash.is_some_and(|prev| prev != block.header.parent_hash) { + tracing::debug!( + start, + end, + ?prev_hash, + parent_hash = ?block.header.parent_hash, + block_number = ?block.number(), + "inconsistent parent in block range" + ); + return Err(anyhow!("inconsistent block range")); + } + prev_hash = Some(current_hash); + + result.push((block.number(), current_hash)); + } + + Ok(result) + } +} + +/// Version of [`BlockRetrieving`] that's optimized for the usage +/// in the event indexing logic. +#[derive(Debug, Clone)] +pub struct BlockRetriever { + pub provider: AlloyProvider, + pub block_stream: watch::Receiver, +} + +#[async_trait::async_trait] +impl BlockRetrieving for BlockRetriever { + #[instrument(skip_all)] + async fn current_block(&self) -> Result { + Ok(*self.block_stream.borrow()) + } + + #[instrument(skip_all)] + async fn finalized_block(&self) -> Result { + self.provider.finalized_block().await + } + + #[instrument(skip_all)] + async fn block(&self, number: u64) -> Result { + self.provider.block(number).await + } + + #[instrument(skip_all)] + async fn blocks(&self, range: RangeInclusive) -> Result> { + self.provider.blocks(range).await + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RangeInclusive { + start: T, + end: T, +} + +impl RangeInclusive { + pub fn try_new(start: T, end: T) -> Result { + ensure!(end >= start, "end has to be bigger or equal to start"); + Ok(Self { start, end }) + } + + pub fn start(&self) -> &T { + &self.start + } + + pub fn end(&self) -> &T { + &self.end + } + + pub fn into_inner(self) -> (T, T) { + (self.start, self.end) + } +} + +#[cfg(test)] +mod tests { + use {super::*, ethrpc::Web3}; + + #[tokio::test] + #[ignore] + async fn current_blocks_test() { + let web3 = Web3::new_from_env(); + + // single block + let range = RangeInclusive::try_new(5, 5).unwrap(); + let blocks = web3.provider.blocks(range).await.unwrap(); + assert_eq!(blocks.len(), 1); + assert_eq!(blocks.last().unwrap().0, 5); + + // multiple blocks + let range = RangeInclusive::try_new(5, 8).unwrap(); + let blocks = web3.provider.blocks(range).await.unwrap(); + assert_eq!(blocks.len(), 4); + assert_eq!(blocks.last().unwrap().0, 8); + assert_eq!(blocks.first().unwrap().0, 5); + + // shortened blocks + let current_block_number = 5u64; + let length = 25u64; + let range = RangeInclusive::try_new( + current_block_number.saturating_sub(length), + current_block_number, + ) + .unwrap(); + let blocks = web3.provider.blocks(range).await.unwrap(); + assert_eq!(blocks.len(), 6); + assert_eq!(blocks.last().unwrap().0, 5); + assert_eq!(blocks.first().unwrap().0, 0); + } +} diff --git a/crates/shared/src/event_handling.rs b/crates/event-indexing/src/event_handler.rs similarity index 80% rename from crates/shared/src/event_handling.rs rename to crates/event-indexing/src/event_handler.rs index 90b36fd622..b47bc70400 100644 --- a/crates/shared/src/event_handling.rs +++ b/crates/event-indexing/src/event_handler.rs @@ -1,22 +1,18 @@ use { - crate::maintenance::Maintaining, - alloy::{ - providers::{DynProvider, Provider}, - rpc::types::{Filter, Log}, - sol_types::SolEventInterface, + crate::{ + block_retriever::{BlockRetrieving, RangeInclusive}, + maintenance::Maintaining, }, + alloy_primitives::{Address, B256}, + alloy_provider::{DynProvider, Provider}, + alloy_rpc_types::{Filter, Log}, + alloy_sol_types::SolEventInterface, anyhow::{Context, Result}, - ethcontract::{EventMetadata, dyns::DynAllEventsBuilder}, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::{BlockNumberHash, BlockRetrieving, RangeInclusive}, - }, - futures::{Stream, StreamExt, TryStreamExt, future}, - primitive_types::H256, + ethrpc::block_stream::BlockNumberHash, + futures::{Stream, StreamExt}, std::{pin::Pin, sync::Arc}, tokio::sync::Mutex, - tracing::Instrument, - web3::types::Address, + tracing::{Instrument, instrument}, }; // We expect that there is never a reorg that changes more than the last n @@ -89,14 +85,6 @@ pub trait EventStoring: Send + Sync { pub type EventStream = Pin> + Send>>; -/// Defines an interface for retrieving events from a `ethcontract` crate -/// contract. Should be removed once fully migrated to alloy. -pub trait EthcontractEventRetrieving { - type Event: ethcontract::contract::ParseLog + 'static; - - fn get_events(&self) -> DynAllEventsBuilder; -} - pub trait AlloyEventRetrieving { type Event: SolEventInterface + Send + Sync + 'static; @@ -106,23 +94,19 @@ pub trait AlloyEventRetrieving { fn provider(&self) -> &DynProvider; } -/// A thin wrapper to avoid conflicts with EthcontractEventRetrieving -/// implementation. Will be dropped once fully migrated to alloy. -pub struct AlloyEventRetriever(pub T); - /// Common `alloy` crate-related event retrieval patterns are extracted to /// this trait to avoid code duplication in implementations. #[async_trait::async_trait] -impl EventRetrieving for AlloyEventRetriever +impl EventRetrieving for T where T: AlloyEventRetrieving + Send + Sync, { type Event = (T::Event, Log); - async fn get_events_by_block_hash(&self, block_hash: H256) -> Result> { - let filter = self.0.filter().at_block_hash(block_hash.into_alloy()); + #[instrument(skip_all)] + async fn get_events_by_block_hash(&self, block_hash: B256) -> Result> { + let filter = self.filter().at_block_hash(block_hash); let events = self - .0 .provider() .get_logs(&filter) .await @@ -147,8 +131,8 @@ where let start = *block_range.start(); let end = *block_range.end(); - let provider = self.0.provider().clone(); - let base_filter = self.0.filter(); + let provider = self.provider().clone(); + let base_filter = self.filter(); let stream = futures::stream::iter(start..=end) .chunks(CHUNK_SIZE) @@ -188,52 +172,7 @@ where } fn address(&self) -> Vec
{ - self.0 - .filter() - .address - .iter() - .copied() - .map(IntoLegacy::into_legacy) - .collect() - } -} - -/// Common `ethcontract` crate-related event retrieval patterns are extracted to -/// this trait to avoid code duplication and any dependencies on the -/// `ethcontract` crate in the main event handling traits. This will be removed -/// once fully migrated to alloy. -#[async_trait::async_trait] -impl EventRetrieving for T -where - T: EthcontractEventRetrieving + Send + Sync, -{ - type Event = ethcontract::Event; - - async fn get_events_by_block_hash( - &self, - block_hash: ethcontract::H256, - ) -> Result> { - Ok(self.get_events().block_hash(block_hash).query().await?) - } - - async fn get_events_by_block_range( - &self, - block_range: &RangeInclusive, - ) -> Result> { - let stream = self - .get_events() - .from_block((*block_range.start()).into()) - .to_block((*block_range.end()).into()) - .block_page_size(500) - .query_paginated() - .await? - .map_err(anyhow::Error::from); - - Ok(Box::pin(stream)) - } - - fn address(&self) -> Vec { - self.get_events().filter.address + self.filter().address.iter().copied().collect() } } @@ -241,10 +180,7 @@ where pub trait EventRetrieving { type Event; - async fn get_events_by_block_hash( - &self, - block_hash: ethcontract::H256, - ) -> Result>; + async fn get_events_by_block_hash(&self, block_hash: B256) -> Result>; async fn get_events_by_block_range( &self, @@ -327,17 +263,19 @@ where } /// Defines block range, for which events should be fetched + #[instrument(skip_all)] async fn event_block_range(&self) -> Result { let handled_blocks = if self.last_handled_blocks.is_empty() { let last_handled_block = self.store.last_event_block().await?; - self.block_retriever + &self + .block_retriever .blocks(RangeInclusive::try_new( last_handled_block, last_handled_block, )?) .await? } else { - self.last_handled_blocks.clone() + &self.last_handled_blocks }; let current_block = self.block_retriever.current_block().await?; @@ -426,7 +364,7 @@ where let (latest_blocks, is_reorg) = match history_range { Some(_) => (latest_blocks, true), None => { - let (latest_blocks, is_reorg) = detect_reorg_path(&handled_blocks, &latest_blocks); + let (latest_blocks, is_reorg) = detect_reorg_path(handled_blocks, &latest_blocks); (latest_blocks.to_vec(), is_reorg) } }; @@ -446,6 +384,7 @@ where } /// Get new events from the contract and insert them into the database. + #[instrument(skip_all)] pub async fn update_events(&mut self) -> Result<()> { let event_range = self.event_block_range().await?; @@ -462,6 +401,7 @@ where Ok(()) } + #[instrument(skip_all)] async fn update_events_from_old_blocks(&mut self, range: RangeInclusive) -> Result<()> { // first get the blocks needed to update `last_handled_blocks` because if it // fails, it's safer to fail at the beginning of the function before we @@ -532,6 +472,7 @@ where Ok(()) } + #[instrument(skip_all)] async fn update_events_from_latest_blocks( &mut self, latest_blocks: &[BlockNumberHash], @@ -568,41 +509,40 @@ where Ok(()) } + #[instrument(skip_all)] async fn past_events_by_block_hashes( &self, blocks: &[BlockNumberHash], ) -> (Vec, Vec) { let (mut blocks_filtered, mut events) = (vec![], vec![]); - for chunk in blocks.chunks(MAX_PARALLEL_RPC_CALLS) { - for (i, result) in future::join_all( - chunk - .iter() - .map(|block| self.contract.get_events_by_block_hash(block.1)), - ) - .await - .into_iter() - .enumerate() - { - match result { - Ok(e) => { - if !e.is_empty() { - tracing::debug!( - "events fetched for block: {:?}, events: {}", - blocks[i], - e.len(), - ); - } - blocks_filtered.push(blocks[i]); - events.extend(e); + let mut stream = futures::stream::iter(blocks.iter().cloned().enumerate().map( + async move |(index, block)| { + (index, self.contract.get_events_by_block_hash(block.1).await) + }, + )) + .buffered(MAX_PARALLEL_RPC_CALLS); + + while let Some((index, result)) = stream.next().await { + match result { + Ok(e) => { + if !e.is_empty() { + tracing::debug!( + "events fetched for block: {:?}, events: {}", + blocks[index], + e.len(), + ); } - Err(_) => return (blocks_filtered, events), + blocks_filtered.push(blocks[index]); + events.extend(e); } + Err(_) => return (blocks_filtered, events), } } (blocks_filtered, events) } + #[instrument(skip_all)] async fn past_events_by_block_number_range( &self, block_range: &RangeInclusive, @@ -610,6 +550,7 @@ where self.contract.get_events_by_block_range(block_range).await } + #[instrument(skip_all)] fn update_last_handled_blocks(&mut self, blocks: &[BlockNumberHash]) { tracing::debug!( "blocks to update into last_handled_blocks: {:?} - {:?}, last_handled_blocks: {:?} - \ @@ -632,7 +573,7 @@ where .last_handled_blocks .len() .saturating_sub(MAX_REORG_BLOCK_COUNT as usize); - self.last_handled_blocks = self.last_handled_blocks[start_index..].to_vec(); + self.last_handled_blocks.drain(..start_index); tracing::debug!( "last_handled_blocks after update: {:?} - {:?}", self.last_handled_blocks.first(), @@ -721,37 +662,6 @@ impl EventIndex { } } -impl From<&EventMetadata> for EventIndex { - fn from(meta: &EventMetadata) -> Self { - EventIndex { - block_number: meta.block_number, - log_index: meta.log_index as u64, - } - } -} - -#[macro_export] -macro_rules! impl_event_retrieving { - ($vis:vis $name:ident for $($contract_module:tt)*) => { - $vis struct $name($($contract_module)*::Contract); - - impl $name { - #[allow(dead_code)] - pub fn new(instance: $($contract_module)*::Contract) -> Self { - Self(instance) - } - } - - impl $crate::event_handling::EthcontractEventRetrieving for $name { - type Event = $($contract_module)*::Event; - - fn get_events(&self) -> ::ethcontract::dyns::DynAllEventsBuilder { - self.0.all_events() - } - } - }; -} - #[derive(prometheus_metric_storage::MetricStorage, Clone, Debug)] #[metric(subsystem = "event_handler")] struct Metrics { @@ -772,38 +682,37 @@ fn track_block_range(range: &str) { mod tests { use { super::*, - alloy::eips::BlockNumberOrTag, - contracts::alloy::{GPv2Settlement, InstanceExt}, - ethcontract::{BlockNumber, H256}, + alloy_eips::BlockNumberOrTag, + alloy_primitives::b256, + contracts::GPv2Settlement, ethrpc::{Web3, block_stream::block_number_to_block_number_hash}, - std::str::FromStr, }; impl AlloyEventRetrieving for GPv2Settlement::Instance { type Event = GPv2Settlement::GPv2Settlement::GPv2SettlementEvents; - fn filter(&self) -> alloy::rpc::types::Filter { + fn filter(&self) -> alloy_rpc_types::Filter { Filter::new().address(*self.address()) } - fn provider(&self) -> &contracts::alloy::Provider { + fn provider(&self) -> &alloy_provider::DynProvider { self.provider() } } /// Simple event storage for testing purposes of EventHandler struct EventStorage { - pub events: Vec<(T, alloy::rpc::types::Log)>, + pub events: Vec<(T, alloy_rpc_types::Log)>, } #[async_trait::async_trait] - impl EventStoring<(T, alloy::rpc::types::Log)> for EventStorage + impl EventStoring<(T, alloy_rpc_types::Log)> for EventStorage where T: Send + Sync, { async fn replace_events( &mut self, - events: Vec<(T, alloy::rpc::types::Log)>, + events: Vec<(T, alloy_rpc_types::Log)>, range: RangeInclusive, ) -> Result<()> { self.events @@ -812,7 +721,7 @@ mod tests { Ok(()) } - async fn append_events(&mut self, events: Vec<(T, alloy::rpc::types::Log)>) -> Result<()> { + async fn append_events(&mut self, events: Vec<(T, alloy_rpc_types::Log)>) -> Result<()> { self.events.extend(events); Ok(()) } @@ -843,7 +752,7 @@ mod tests { #[test] fn detect_reorg_path_test_handled_blocks_empty() { let handled_blocks = vec![]; - let latest_blocks = vec![(1, H256::from_low_u64_be(1))]; + let latest_blocks = vec![(1, B256::with_last_byte(1))]; let (replacement_blocks, is_reorg) = detect_reorg_path(&handled_blocks, &latest_blocks); assert_eq!(replacement_blocks, latest_blocks); assert!(!is_reorg); @@ -852,8 +761,8 @@ mod tests { #[test] fn detect_reorg_path_test_both_same() { // if the list are same, we return the common ancestor - let handled_blocks = vec![(1, H256::from_low_u64_be(1))]; - let latest_blocks = vec![(1, H256::from_low_u64_be(1))]; + let handled_blocks = vec![(1, B256::with_last_byte(1))]; + let latest_blocks = vec![(1, B256::with_last_byte(1))]; let (replacement_blocks, is_reorg) = detect_reorg_path(&handled_blocks, &latest_blocks); assert!(replacement_blocks.is_empty()); assert!(!is_reorg); @@ -861,12 +770,12 @@ mod tests { #[test] fn detect_reorg_path_test_common_case() { - let handled_blocks = vec![(1, H256::from_low_u64_be(1)), (2, H256::from_low_u64_be(2))]; + let handled_blocks = vec![(1, B256::with_last_byte(1)), (2, B256::with_last_byte(2))]; let latest_blocks = vec![ - (1, H256::from_low_u64_be(1)), - (2, H256::from_low_u64_be(2)), - (3, H256::from_low_u64_be(3)), - (4, H256::from_low_u64_be(4)), + (1, B256::with_last_byte(1)), + (2, B256::with_last_byte(2)), + (3, B256::with_last_byte(3)), + (4, B256::with_last_byte(4)), ]; let (replacement_blocks, is_reorg) = detect_reorg_path(&handled_blocks, &latest_blocks); assert_eq!(replacement_blocks, latest_blocks[2..].to_vec()); @@ -876,14 +785,14 @@ mod tests { #[test] fn detect_reorg_path_test_reorg_1() { let handled_blocks = vec![ - (1, H256::from_low_u64_be(1)), - (2, H256::from_low_u64_be(2)), - (3, H256::from_low_u64_be(3)), + (1, B256::with_last_byte(1)), + (2, B256::with_last_byte(2)), + (3, B256::with_last_byte(3)), ]; let latest_blocks = vec![ - (1, H256::from_low_u64_be(1)), - (2, H256::from_low_u64_be(2)), - (3, H256::from_low_u64_be(4)), + (1, B256::with_last_byte(1)), + (2, B256::with_last_byte(2)), + (3, B256::with_last_byte(4)), ]; let (replacement_blocks, is_reorg) = detect_reorg_path(&handled_blocks, &latest_blocks); assert_eq!(replacement_blocks, latest_blocks[2..].to_vec()); @@ -892,11 +801,11 @@ mod tests { #[test] fn detect_reorg_path_test_reorg_no_common_ancestor() { - let handled_blocks = vec![(2, H256::from_low_u64_be(20))]; + let handled_blocks = vec![(2, B256::with_last_byte(20))]; let latest_blocks = vec![ - (1, H256::from_low_u64_be(11)), - (2, H256::from_low_u64_be(21)), - (3, H256::from_low_u64_be(31)), + (1, B256::with_last_byte(11)), + (2, B256::with_last_byte(21)), + (3, B256::with_last_byte(31)), ]; let (replacement_blocks, is_reorg) = detect_reorg_path(&handled_blocks, &latest_blocks); assert_eq!(replacement_blocks, latest_blocks); @@ -939,46 +848,32 @@ mod tests { #[ignore] async fn past_events_by_block_hashes_test() { let web3 = Web3::new_from_env(); - let contract = GPv2Settlement::Instance::deployed(&web3.alloy) + let contract = GPv2Settlement::Instance::deployed(&web3.provider) .await .unwrap(); let storage = EventStorage { events: vec![] }; let blocks = vec![ ( 15575559, - H256::from_str( - "0xa21ba3de6ac42185aa2b21e37cd63ff1572b763adff7e828f86590df1d1be118", - ) - .unwrap(), + b256!("0xa21ba3de6ac42185aa2b21e37cd63ff1572b763adff7e828f86590df1d1be118"), ), ( 15575560, - H256::from_str( - "0x5a737331194081e99b73d7a8b7a2ccff84e0aff39fa0e39aca0b660f3d6694c4", - ) - .unwrap(), + b256!("0x5a737331194081e99b73d7a8b7a2ccff84e0aff39fa0e39aca0b660f3d6694c4"), ), ( 15575561, - H256::from_str( - "0xe91ec1a5a795c0739d99a60ac1df37cdf90b6c75c8150ace1cbad5b21f473b75", //WRONG HASH! - ) - .unwrap(), + b256!( + "0xe91ec1a5a795c0739d99a60ac1df37cdf90b6c75c8150ace1cbad5b21f473b75" /* WRONG HASH! */ + ), ), ( 15575562, - H256::from_str( - "0xac1ca15622f17c62004de1f746728d4051103d8b7e558d39fd9fcec4d3348937", - ) - .unwrap(), + b256!("0xac1ca15622f17c62004de1f746728d4051103d8b7e558d39fd9fcec4d3348937"), ), ]; - let event_handler = EventHandler::new( - Arc::new(web3.alloy.clone()), - AlloyEventRetriever(contract), - storage, - None, - ); + let event_handler = + EventHandler::new(Arc::new(web3.provider.clone()), contract, storage, None); let (replacement_blocks, _) = event_handler.past_events_by_block_hashes(&blocks).await; assert_eq!(replacement_blocks, blocks[..2]); } @@ -987,27 +882,25 @@ mod tests { #[ignore] async fn update_events_test() { let web3 = Web3::new_from_env(); - let contract = GPv2Settlement::Instance::deployed(&web3.alloy) + let contract = GPv2Settlement::Instance::deployed(&web3.provider) .await .unwrap(); let storage = EventStorage { events: vec![] }; - let current_block = web3.eth().block_number().await.unwrap(); + let current_block = web3.provider.get_block_number().await.unwrap(); const NUMBER_OF_BLOCKS: u64 = 300; //get block in history (current_block - NUMBER_OF_BLOCKS) let block = web3 - .eth() - .block( - BlockNumber::Number(current_block.saturating_sub(NUMBER_OF_BLOCKS.into())).into(), - ) + .provider + .get_block_by_number(current_block.saturating_sub(NUMBER_OF_BLOCKS).into()) .await .unwrap() .unwrap(); - let block = (block.number.unwrap().as_u64(), block.hash.unwrap()); + let block = (block.number(), block.hash()); let mut event_handler = EventHandler::new( - Arc::new(web3.alloy.clone()), - AlloyEventRetriever(contract), + Arc::new(web3.provider.clone()), + contract, storage, Some(block), ); @@ -1020,27 +913,26 @@ mod tests { async fn multiple_new_blocks_but_no_reorg_test() { tracing_subscriber::fmt::init(); let web3 = Web3::new_from_env(); - let contract = GPv2Settlement::Instance::deployed(&web3.alloy) + let contract = GPv2Settlement::Instance::deployed(&web3.provider) .await .unwrap(); - let storage = EventStorage { events: vec![] }; - let current_block = web3.eth().block_number().await.unwrap(); + let storage: EventStorage = + EventStorage { events: vec![] }; + let current_block = web3.provider.get_block_number().await.unwrap(); const NUMBER_OF_BLOCKS: u64 = 300; //get block in history (current_block - NUMBER_OF_BLOCKS) let block = web3 - .eth() - .block( - BlockNumber::Number(current_block.saturating_sub(NUMBER_OF_BLOCKS.into())).into(), - ) + .provider + .get_block_by_number(current_block.saturating_sub(NUMBER_OF_BLOCKS).into()) .await .unwrap() .unwrap(); - let block = (block.number.unwrap().as_u64(), block.hash.unwrap()); + let block = (block.number(), block.hash()); let mut event_handler = EventHandler::new( - Arc::new(web3.alloy.clone()), - AlloyEventRetriever(contract), + Arc::new(web3.provider.clone()), + contract, storage, Some(block), ); @@ -1054,22 +946,22 @@ mod tests { #[ignore] async fn optional_block_skipping() { let web3 = Web3::new_from_env(); - let contract = GPv2Settlement::Instance::deployed(&web3.alloy) + let contract = GPv2Settlement::Instance::deployed(&web3.provider) .await .unwrap(); - let current_block = web3.eth().block_number().await.unwrap(); + let current_block = web3.provider.get_block_number().await.unwrap(); // In this test we query for events multiple times. Newer events might be // included each time we query again for the same events, but we want to // disregard them. let remove_events_after_test_start = |v: Vec<( GPv2Settlement::GPv2Settlement::GPv2SettlementEvents, - alloy::rpc::types::Log, + alloy_rpc_types::Log, )>| { v.into_iter() .filter(|(_, log)| { // We make the test robust against reorgs by removing events that are too new - log.block_number.unwrap() <= (current_block - MAX_REORG_BLOCK_COUNT).as_u64() + log.block_number.unwrap() <= (current_block - MAX_REORG_BLOCK_COUNT) }) .collect::>() }; @@ -1080,14 +972,14 @@ mod tests { let storage_empty = EventStorage { events: vec![] }; let event_start = block_number_to_block_number_hash( - &web3.alloy, - BlockNumberOrTag::Number((current_block - RANGE_SIZE).as_u64()), + &web3.provider, + BlockNumberOrTag::Number(current_block - RANGE_SIZE), ) .await .unwrap(); let mut base_event_handler = EventHandler::new( - Arc::new(web3.alloy.clone()), - AlloyEventRetriever(contract.clone()), + Arc::new(web3.provider.clone()), + contract.clone(), storage_empty, Some(event_start), ); @@ -1102,14 +994,14 @@ mod tests { // date but using `new_skip_blocks_before` if there are no events let storage_empty = EventStorage { events: vec![] }; let event_start = block_number_to_block_number_hash( - &web3.alloy, - BlockNumberOrTag::Number((current_block - RANGE_SIZE).as_u64()), + &web3.provider, + BlockNumberOrTag::Number(current_block - RANGE_SIZE), ) .await .unwrap(); let mut base_block_skip_event_handler = EventHandler::new_skip_blocks_before( - Arc::new(web3.alloy.clone()), - AlloyEventRetriever(contract.clone()), + Arc::new(web3.provider.clone()), + contract.clone(), storage_empty, event_start, ) @@ -1146,8 +1038,8 @@ mod tests { events: vec![last_event.clone()], }; let mut nonempty_event_handler = EventHandler::new_skip_blocks_before( - Arc::new(web3.alloy.clone()), - AlloyEventRetriever(contract), + Arc::new(web3.provider.clone()), + contract, storage_nonempty, // Same event start as for the two previous event handlers. The test checks that this // is disregarded. diff --git a/crates/event-indexing/src/lib.rs b/crates/event-indexing/src/lib.rs new file mode 100644 index 0000000000..11793d1db6 --- /dev/null +++ b/crates/event-indexing/src/lib.rs @@ -0,0 +1,3 @@ +pub mod block_retriever; +pub mod event_handler; +pub mod maintenance; diff --git a/crates/shared/src/maintenance.rs b/crates/event-indexing/src/maintenance.rs similarity index 64% rename from crates/shared/src/maintenance.rs rename to crates/event-indexing/src/maintenance.rs index 5291f26467..1128cc0177 100644 --- a/crates/shared/src/maintenance.rs +++ b/crates/event-indexing/src/maintenance.rs @@ -2,22 +2,20 @@ use { anyhow::{Result, ensure}, ethrpc::block_stream::{self, BlockInfo, CurrentBlockWatcher}, futures::{Stream, StreamExt as _, future::join_all}, - std::{sync::Arc, time::Duration}, + std::{sync::Weak, time::Duration}, tokio::time, tracing::Instrument as _, }; -/// Collects all service components requiring maintenance on each new block +/// Collects all service components requiring maintenance on each new block. pub struct ServiceMaintenance { - maintainers: Vec>, + maintainers: Vec>, retry_delay: Duration, metrics: &'static Metrics, } -const SERVICE_MAINTENANCE_NAME: &str = "ServiceMaintenance"; - impl ServiceMaintenance { - pub fn new(maintainers: Vec>) -> Self { + pub fn new(maintainers: Vec>) -> Self { Self { maintainers, retry_delay: Duration::from_secs(1), @@ -25,15 +23,14 @@ impl ServiceMaintenance { } } - async fn run_maintenance_for_blocks(self, blocks: impl Stream) { - self.metrics - .runs - .with_label_values(&["success", SERVICE_MAINTENANCE_NAME]) - .reset(); - for maintainer in self.maintainers.iter().map(|maintainer| maintainer.name()) { + async fn run_maintenance_for_blocks( + mut self, + blocks: impl Stream, + ) -> Result<()> { + for maintainer in self.maintainers.iter().filter_map(Weak::upgrade) { self.metrics .runs - .with_label_values(&["failure", maintainer]) + .with_label_values(&["failure", maintainer.name()]) .reset(); } @@ -51,6 +48,12 @@ impl ServiceMaintenance { .unwrap_or(Some(block)), None => blocks.next().await, } { + self.maintainers.retain(|m| m.strong_count() > 0); + if self.maintainers.is_empty() { + tracing::debug!("no component needs maintenance anymore, terminating loop"); + return Ok(()); + } + tracing::debug!( ?block.number, ?block.hash, "running maintenance", @@ -77,42 +80,31 @@ impl ServiceMaintenance { self.metrics .last_updated_block .set(i64::try_from(block.number).unwrap_or(i64::MAX)); - self.metrics - .runs - .with_label_values(&["success", self.name()]) - .inc(); } + + Err(anyhow::anyhow!("block stream terminated unexpectedly")) } - pub async fn run_maintenance_on_new_block( - self, - current_block_stream: CurrentBlockWatcher, - ) -> ! { + pub async fn run_maintenance_on_new_block(self, current_block_stream: CurrentBlockWatcher) { self.run_maintenance_for_blocks(block_stream::into_stream(current_block_stream)) .instrument(tracing::info_span!("service_maintenance")) - .await; - panic!("block stream unexpectedly dropped"); + .await + .expect("maintenance task terminated with error"); } -} -#[cfg_attr(test, mockall::automock)] -#[async_trait::async_trait] -pub trait Maintaining: Send + Sync { - async fn run_maintenance(&self) -> Result<()>; - fn name(&self) -> &str; -} - -#[async_trait::async_trait] -impl Maintaining for ServiceMaintenance { async fn run_maintenance(&self) -> Result<()> { let mut no_error = true; - for (i, result) in join_all(self.maintainers.iter().map(|m| m.run_maintenance())) - .await - .into_iter() - .enumerate() + for (result, maintainer) in join_all( + self.maintainers + .iter() + .filter_map(Weak::upgrade) + .map(|m| async move { (m.run_maintenance().await, m) }), + ) + .await + .into_iter() { if let Err(err) = result { - let maintainer = self.maintainers[i].name(); + let maintainer = maintainer.name(); tracing::warn!( "Service Maintenance Error for maintainer {}: {:?}", maintainer, @@ -130,10 +122,13 @@ impl Maintaining for ServiceMaintenance { ensure!(no_error, "maintenance encounted one or more errors"); Ok(()) } +} - fn name(&self) -> &str { - SERVICE_MAINTENANCE_NAME - } +#[cfg_attr(test, mockall::automock)] +#[async_trait::async_trait] +pub trait Maintaining: Send + Sync { + async fn run_maintenance(&self) -> Result<()>; + fn name(&self) -> &str; } #[derive(prometheus_metric_storage::MetricStorage)] @@ -152,7 +147,7 @@ struct Metrics { #[cfg(test)] mod tests { - use {super::*, anyhow::bail, futures::stream, mockall::Sequence}; + use {super::*, anyhow::bail, futures::stream, mockall::Sequence, std::sync::Arc}; #[tokio::test] async fn run_maintenance_no_early_exit_on_error() { @@ -176,11 +171,15 @@ mod tests { .times(1) .returning(|| Ok(())); + let m1 = Arc::new(ok1_mock_maintenance) as Arc; + let m2 = Arc::new(err_mock_maintenance) as Arc; + let m3 = Arc::new(ok2_mock_maintenance) as Arc; + let service_maintenance = ServiceMaintenance { maintainers: vec![ - Arc::new(ok1_mock_maintenance), - Arc::new(err_mock_maintenance), - Arc::new(ok2_mock_maintenance), + Arc::downgrade(&m1), + Arc::downgrade(&m2), + Arc::downgrade(&m3), ], retry_delay: Duration::default(), metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), @@ -205,8 +204,9 @@ mod tests { .times(block_count) .returning(|| Ok(())); + let m1 = Arc::new(mock_maintenance) as Arc; let service_maintenance = ServiceMaintenance { - maintainers: vec![Arc::new(mock_maintenance)], + maintainers: vec![Arc::downgrade(&m1)], retry_delay: Duration::default(), metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), }; @@ -214,13 +214,14 @@ mod tests { let block_stream = stream::repeat(BlockInfo::default()).take(block_count); service_maintenance .run_maintenance_for_blocks(block_stream) - .await; + .await + .unwrap_err(); } #[tokio::test] async fn block_stream_retries_failed_blocks() { let obs_config = observe::Config::default().with_env_filter("debug"); - observe::tracing::initialize(&obs_config); + observe::tracing::init::initialize(&obs_config); let mut mock_maintenance = MockMaintaining::new(); let mut sequence = Sequence::new(); @@ -250,8 +251,9 @@ mod tests { .times(1) .in_sequence(&mut sequence); + let m1 = Arc::new(mock_maintenance) as Arc; let service_maintenance = ServiceMaintenance { - maintainers: vec![Arc::new(mock_maintenance)], + maintainers: vec![Arc::downgrade(&m1)], retry_delay: Duration::default(), metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), }; @@ -265,6 +267,58 @@ mod tests { }; service_maintenance .run_maintenance_for_blocks(block_stream) - .await; + .await + .unwrap_err(); + } + + /// Tests that the maintenance task terminates gracefully (`Ok(())`) when + /// all managed sub-tasks indicate they no longer need to run. + #[tokio::test] + async fn task_terminates_gracefully() { + let obs_config = observe::Config::default().with_env_filter("debug"); + observe::tracing::init::initialize(&obs_config); + + let mut m1 = MockMaintaining::new(); + m1.expect_name().return_const("test".to_string()); + m1.expect_run_maintenance().times(3).returning(|| Ok(())); + + let mut m2 = MockMaintaining::new(); + m2.expect_name().return_const("test".to_string()); + m2.expect_run_maintenance().times(7).returning(|| Ok(())); + + let m1 = Arc::new(m1) as Arc; + let m2 = Arc::new(m2) as Arc; + let service_maintenance = ServiceMaintenance { + maintainers: vec![Arc::downgrade(&m1), Arc::downgrade(&m2)], + retry_delay: Duration::default(), + metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), + }; + + let block_stream = async_stream::stream! { + let mut i = 0; + let mut m1 = Some(m1); + let mut m2 = Some(m2); + loop { + if i == 3 { + // first drop m1 to verify that m2 keeps getting maintained while + // m1 no longer runs + m1.take(); + } + if i == 7 { + // after m2 also gets dropped the whole service_maintenance terminates + // gracefully + m2.take(); + } + + yield BlockInfo::default(); + + time::sleep(Duration::from_millis(10)).await; + i += 1; + } + }; + service_maintenance + .run_maintenance_for_blocks(block_stream) + .await + .expect("task terminated with error despite all maintainers getting dropped"); } } diff --git a/crates/gas-price-estimation/Cargo.toml b/crates/gas-price-estimation/Cargo.toml new file mode 100644 index 0000000000..c4957e6c0c --- /dev/null +++ b/crates/gas-price-estimation/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "gas-price-estimation" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-eips = { workspace = true } +alloy-provider = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +configs = { workspace = true } +ethrpc = { workspace = true } +futures = { workspace = true } +observe = { workspace = true } +prometheus = { workspace = true } +prometheus-metric-storage = { workspace = true } +reqwest = { workspace = true, features = ["json"] } +tokio = { workspace = true } +tracing = { workspace = true } +url = { workspace = true } + +[dev-dependencies] +mockall = { workspace = true } + +[lints] +workspace = true diff --git a/crates/gas-price-estimation/LICENSE-APACHE b/crates/gas-price-estimation/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/gas-price-estimation/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/gas-price-estimation/LICENSE-MIT b/crates/gas-price-estimation/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/gas-price-estimation/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/gas-price-estimation/src/configurable_alloy.rs b/crates/gas-price-estimation/src/configurable_alloy.rs new file mode 100644 index 0000000000..aa51556c45 --- /dev/null +++ b/crates/gas-price-estimation/src/configurable_alloy.rs @@ -0,0 +1,89 @@ +//! Configurable EIP-1559 gas price estimator. +//! +//! Unlike alloy's default estimator which uses hardcoded values (10 blocks, +//! 20th percentile), this estimator allows configuring: +//! - Number of blocks to look back +//! - Reward percentile to use + +use { + crate::GasPriceEstimating, + alloy_eips::{BlockId, BlockNumberOrTag, eip1559::Eip1559Estimation}, + alloy_provider::{Provider, utils::eip1559_default_estimator}, + anyhow::{Context, Result}, + configs::gas_price_estimation::EstimatorConfig, + ethrpc::AlloyProvider, + tracing::instrument, +}; + +/// A configurable EIP-1559 gas price estimator. +/// +/// Uses alloy's default estimation algorithm but with configurable +/// `past_blocks` and `reward_percentile` parameters for the fee history query. +pub struct ConfigurableGasPriceEstimator { + provider: AlloyProvider, + config: EstimatorConfig, +} + +impl ConfigurableGasPriceEstimator { + pub fn new(provider: AlloyProvider, config: EstimatorConfig) -> Self { + Self { provider, config } + } +} + +#[async_trait::async_trait] +impl GasPriceEstimating for ConfigurableGasPriceEstimator { + async fn base_fee(&self) -> Result> { + Ok(self + .provider + .get_block(BlockId::latest()) + .await? + .and_then(|block| block.header.base_fee_per_gas)) + } + + #[instrument(skip(self), fields( + past_blocks = %self.config.past_blocks, + reward_percentile = %self.config.reward_percentile + ))] + async fn estimate(&self) -> Result { + // Fetch fee history with our configured parameters + let fee_history = self + .provider + .get_fee_history( + self.config.past_blocks, + BlockNumberOrTag::Latest, + &[self.config.reward_percentile], + ) + .await + .context("failed to fetch fee history")?; + + // Get base fee: use latest block's base fee, or fall back to fetching + // latest block directly if fee history is empty + let base_fee_per_gas = match fee_history.latest_block_base_fee() { + Some(base_fee) if base_fee != 0 => base_fee, + _ => { + // empty response, fetch basefee from latest block directly + let block = self + .provider + .get_block_by_number(BlockNumberOrTag::Latest) + .await + .context("failed to fetch latest block")? + .context("latest block not found")?; + u128::from( + block + .header + .base_fee_per_gas + .context("base_fee_per_gas not available (eip1559 not supported)")?, + ) + } + }; + + // Use alloy's default estimation algorithm + let estimation = + eip1559_default_estimator(base_fee_per_gas, &fee_history.reward.unwrap_or_default()); + + Ok(Eip1559Estimation { + max_fee_per_gas: estimation.max_fee_per_gas, + max_priority_fee_per_gas: estimation.max_priority_fee_per_gas, + }) + } +} diff --git a/crates/shared/src/gas_price_estimation/driver.rs b/crates/gas-price-estimation/src/driver.rs similarity index 60% rename from crates/shared/src/gas_price_estimation/driver.rs rename to crates/gas-price-estimation/src/driver.rs index 00cd114901..c470150a58 100644 --- a/crates/shared/src/gas_price_estimation/driver.rs +++ b/crates/gas-price-estimation/src/driver.rs @@ -1,11 +1,9 @@ use { - anyhow::{Context, Result}, - gas_estimation::{GasPrice1559, GasPriceEstimating}, - number::serialization::HexOrDecimalU256, - primitive_types::U256, + crate::GasPriceEstimating, + alloy_eips::{BlockId, eip1559::Eip1559Estimation}, + alloy_provider::{DynProvider, Provider}, + anyhow::{Context, Result, anyhow}, reqwest::Url, - serde::Deserialize, - serde_with::serde_as, std::{ sync::Arc, time::{Duration, Instant}, @@ -21,40 +19,29 @@ pub struct DriverGasEstimator { client: reqwest::Client, url: Url, cache: Arc>>, + provider: DynProvider, } #[derive(Debug, Clone)] struct CachedGasPrice { - price: GasPrice1559, + price: Eip1559Estimation, timestamp: Instant, } -#[serde_as] -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -/// Gas price components in EIP-1559 format. -struct GasPriceResponse { - #[serde_as(as = "HexOrDecimalU256")] - max_fee_per_gas: U256, - #[serde_as(as = "HexOrDecimalU256")] - max_priority_fee_per_gas: U256, - #[serde_as(as = "HexOrDecimalU256")] - base_fee_per_gas: U256, -} - const CACHE_DURATION: Duration = Duration::from_secs(5); impl DriverGasEstimator { - pub fn new(client: reqwest::Client, driver_url: Url) -> Self { + pub fn new(client: reqwest::Client, driver_url: Url, provider: DynProvider) -> Self { Self { client, url: driver_url, cache: Arc::new(Mutex::new(None)), + provider, } } #[instrument(skip(self))] - async fn fetch_gas_price(&self) -> Result { + async fn fetch_gas_price(&self) -> Result { let response = self .client .get(self.url.clone()) @@ -63,18 +50,21 @@ impl DriverGasEstimator { .context("failed to send request to driver")? .error_for_status() .context("driver returned error status")? - .json::() + .json::() .await .context("failed to parse driver response")?; - Ok(GasPrice1559 { - base_fee_per_gas: response.base_fee_per_gas.to_f64_lossy(), - max_fee_per_gas: response.max_fee_per_gas.to_f64_lossy(), - max_priority_fee_per_gas: response.max_priority_fee_per_gas.to_f64_lossy(), + Ok(Eip1559Estimation { + max_fee_per_gas: response.max_fee_per_gas, + max_priority_fee_per_gas: response.max_priority_fee_per_gas, }) } +} - async fn estimate(&self) -> Result { +#[async_trait::async_trait] +impl GasPriceEstimating for DriverGasEstimator { + #[instrument(skip(self))] + async fn estimate(&self) -> Result { // Lock cache for entire duration of this method to prevent concurrent network // requests let mut cache = self.cache.lock().await; @@ -94,16 +84,14 @@ impl DriverGasEstimator { Ok(price) } -} -#[async_trait::async_trait] -impl GasPriceEstimating for DriverGasEstimator { - #[instrument(skip(self))] - async fn estimate_with_limits( - &self, - _gas_limit: f64, - _time_limit: Duration, - ) -> Result { - self.estimate().await + async fn base_fee(&self) -> Result> { + Ok(self + .provider + .get_block(BlockId::latest()) + .await? + .ok_or_else(|| anyhow!("fecthed block does not have header"))? + .header + .base_fee_per_gas) } } diff --git a/crates/gas-price-estimation/src/eth_node.rs b/crates/gas-price-estimation/src/eth_node.rs new file mode 100644 index 0000000000..9fd26c2078 --- /dev/null +++ b/crates/gas-price-estimation/src/eth_node.rs @@ -0,0 +1,49 @@ +//! Node-based gas estimation approach, queries the node for the current gas +//! price. +//! +//! This approach is ported from the [`cowprotocol/gas-estimation`](https://github.com/cowprotocol/gas-estimation/tree/v0.7.3) crate's legacy estimation. + +use { + crate::GasPriceEstimating, + alloy_eips::{BlockId, eip1559::Eip1559Estimation}, + alloy_provider::Provider, + anyhow::{Context, Result, anyhow}, + ethrpc::AlloyProvider, +}; + +/// Gas estimator that queries the node current gas price using `eth_gasPrice`. +pub struct NodeGasPriceEstimator(AlloyProvider); + +impl NodeGasPriceEstimator { + pub fn new(provider: AlloyProvider) -> Self { + Self(provider) + } +} + +#[async_trait::async_trait] +impl GasPriceEstimating for NodeGasPriceEstimator { + /// Returns the result of calling the `eth_gasPrice` endpoint as the gas + /// estimation. + async fn estimate(&self) -> Result { + let legacy = self + .0 + .get_gas_price() + .await + .context("failed to get web3 gas price")?; + + Ok(Eip1559Estimation { + max_fee_per_gas: legacy, + max_priority_fee_per_gas: legacy, + }) + } + + async fn base_fee(&self) -> Result> { + Ok(self + .0 + .get_block(BlockId::latest()) + .await? + .ok_or_else(|| anyhow!("fecthed block does not have header"))? + .header + .base_fee_per_gas) + } +} diff --git a/crates/gas-price-estimation/src/fake.rs b/crates/gas-price-estimation/src/fake.rs new file mode 100644 index 0000000000..d4382e89fd --- /dev/null +++ b/crates/gas-price-estimation/src/fake.rs @@ -0,0 +1,29 @@ +use {crate::GasPriceEstimating, alloy_eips::eip1559::Eip1559Estimation, anyhow::Result}; + +pub struct FakeGasPriceEstimator(pub Eip1559Estimation); + +impl Default for FakeGasPriceEstimator { + fn default() -> Self { + Self(Eip1559Estimation { + max_fee_per_gas: Default::default(), + max_priority_fee_per_gas: Default::default(), + }) + } +} + +impl FakeGasPriceEstimator { + pub fn new(gas_price: Eip1559Estimation) -> Self { + Self(gas_price) + } +} + +#[async_trait::async_trait] +impl GasPriceEstimating for FakeGasPriceEstimator { + async fn estimate(&self) -> Result { + Ok(self.0) + } + + async fn base_fee(&self) -> Result> { + Ok(Default::default()) + } +} diff --git a/crates/gas-price-estimation/src/gas_price.rs b/crates/gas-price-estimation/src/gas_price.rs new file mode 100644 index 0000000000..fb8da8b5a6 --- /dev/null +++ b/crates/gas-price-estimation/src/gas_price.rs @@ -0,0 +1,69 @@ +//! Module defining an instrumented Ethereum gas price estimator. +//! +//! This allows us to keep track of historic gas prices in Grafana and do things +//! like alert when gas prices get too high as well as detect spikes and other +//! anomalies. + +use { + crate::GasPriceEstimating, + alloy_eips::eip1559::{Eip1559Estimation, calc_effective_gas_price}, + anyhow::Result, +}; + +/// An instrumented gas price estimator that wraps an inner one. +pub struct InstrumentedGasEstimator { + inner: T, + metrics: &'static Metrics, +} + +impl InstrumentedGasEstimator +where + T: GasPriceEstimating, +{ + pub fn new(inner: T) -> Self { + Self { + inner, + metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), + } + } +} + +#[async_trait::async_trait] +impl GasPriceEstimating for InstrumentedGasEstimator +where + T: GasPriceEstimating, +{ + async fn estimate(&self) -> Result { + self.inner.estimate().await + } + + async fn base_fee(&self) -> Result> { + self.inner.base_fee().await + } + + #[tracing::instrument(skip_all)] + async fn effective_gas_price(&self) -> Result { + let estimate = self.estimate().await?; + let base_fee = self.inner.base_fee().await?; + self.metrics + .base_fee + .set(base_fee.unwrap_or(0).cast_signed()); + + let effective_gas_price = calc_effective_gas_price( + estimate.max_fee_per_gas, + estimate.max_priority_fee_per_gas, + base_fee, + ); + + self.metrics.gas_price.set(effective_gas_price as f64 / 1e9); + Ok(effective_gas_price) + } +} + +#[derive(prometheus_metric_storage::MetricStorage)] +struct Metrics { + /// Last measured effective gas price in gwei + gas_price: prometheus::Gauge, + /// Last measured base fee + base_fee: prometheus::IntGauge, +} diff --git a/crates/gas-price-estimation/src/lib.rs b/crates/gas-price-estimation/src/lib.rs new file mode 100644 index 0000000000..a2491bc80f --- /dev/null +++ b/crates/gas-price-estimation/src/lib.rs @@ -0,0 +1,124 @@ +pub mod configurable_alloy; +pub mod driver; +pub mod eth_node; +pub mod fake; +pub mod gas_price; +pub mod priority; + +use { + crate::{ + configurable_alloy::ConfigurableGasPriceEstimator, + eth_node::NodeGasPriceEstimator, + priority::PriorityGasPriceEstimating, + }, + alloy_eips::eip1559::{Eip1559Estimation, calc_effective_gas_price}, + alloy_provider::Provider, + anyhow::Result, + configs::gas_price_estimation::{ + EstimatorConfig, + default_past_blocks, + default_reward_percentile, + }, + ethrpc::Web3, + tracing::instrument, + url::Url, +}; +pub use {driver::DriverGasEstimator, fake::FakeGasPriceEstimator}; + +#[cfg_attr(test, mockall::automock)] +#[async_trait::async_trait] +pub trait GasPriceEstimating: Send + Sync { + /// Estimate the gas price for a transaction to be mined "quickly". + async fn estimate(&self) -> Result; + + async fn base_fee(&self) -> Result>; + + async fn effective_gas_price(&self) -> Result { + let estimate = self.estimate().await?; + let base_fee = self.base_fee().await?; + Ok(calc_effective_gas_price( + estimate.max_fee_per_gas, + estimate.max_priority_fee_per_gas, + base_fee, + )) + } +} + +#[derive(Clone, Debug)] +pub enum GasEstimatorType { + Web3, + Driver(Url), + Alloy, +} + +#[instrument(skip_all)] +pub async fn create_priority_estimator( + http_client: reqwest::Client, + web3: &Web3, + estimator_types: &[GasEstimatorType], +) -> Result> { + let network_id = web3.provider.get_chain_id().await?.to_string(); + let mut estimators = Vec::>::new(); + + for estimator_type in estimator_types { + tracing::info!("estimator {estimator_type:?}, networkid {network_id}"); + match estimator_type { + GasEstimatorType::Driver(url) => { + estimators.push(Box::new(DriverGasEstimator::new( + http_client.clone(), + url.clone(), + web3.provider.clone(), + ))); + } + GasEstimatorType::Web3 => { + estimators.push(Box::new(NodeGasPriceEstimator::new(web3.provider.clone()))) + } + GasEstimatorType::Alloy => { + let estimator = ConfigurableGasPriceEstimator::new( + web3.provider.clone(), + EstimatorConfig { + past_blocks: default_past_blocks(), + reward_percentile: default_reward_percentile(), + }, + ); + estimators.push(Box::new(estimator)) + } + } + } + anyhow::ensure!( + !estimators.is_empty(), + "all gas estimators failed to initialize" + ); + Ok(PriorityGasPriceEstimating::new(estimators)) +} + +/// Extension trait for EIP-1559 gas price estimations. +pub trait Eip1559EstimationExt { + /// Calculates the effective gas price that will be paid given the base fee. + fn effective(self, base_fee: u64) -> u128; + + /// Scales fees by a multiplier in parts per thousand (e.g., 100 = +10%). + fn scaled_by_pml(self, pml: u64) -> Self; +} + +impl Eip1559EstimationExt for Eip1559Estimation { + fn effective(self, base_fee: u64) -> u128 { + calc_effective_gas_price( + self.max_fee_per_gas, + self.max_priority_fee_per_gas, + Some(base_fee), + ) + } + + fn scaled_by_pml(mut self, pml: u64) -> Self { + self.max_fee_per_gas = { + let n = self.max_fee_per_gas; + n * (1000 + pml as u128) / 1000 + }; + self.max_priority_fee_per_gas = { + let n = self.max_priority_fee_per_gas; + n * (1000 + pml as u128) / 1000 + }; + self + } +} diff --git a/crates/gas-price-estimation/src/priority.rs b/crates/gas-price-estimation/src/priority.rs new file mode 100644 index 0000000000..9df8664dca --- /dev/null +++ b/crates/gas-price-estimation/src/priority.rs @@ -0,0 +1,143 @@ +use { + crate::GasPriceEstimating, + alloy_eips::eip1559::Eip1559Estimation, + anyhow::{Result, anyhow}, + std::{ + future::Future, + sync::atomic::{AtomicUsize, Ordering}, + }, +}; + +// Errors of an individual estimator are logged as warnings until it has failed +// this many times in a row at which point they are logged as errors. +// This is useful to reduce alerts for estimators that sometimes fail individual +// requests while still getting them when the estimator really goes down. +const LOG_ERROR_AFTER_N_ERRORS: usize = 10; + +// Uses the first successful estimator. +pub struct PriorityGasPriceEstimating { + estimators: Vec, +} + +struct Estimator { + estimator: Box, + errors_in_a_row: AtomicUsize, +} + +impl PriorityGasPriceEstimating { + pub fn new(estimators: Vec>) -> Self { + let estimators = estimators + .into_iter() + .map(|estimator| Estimator { + estimator, + errors_in_a_row: AtomicUsize::new(0), + }) + .collect(); + Self { estimators } + } + + async fn prioritize<'a, T, F, O>(&'a self, operation: T) -> Result + where + T: Fn(&'a dyn GasPriceEstimating) -> F, + F: Future>, + { + for (i, estimator) in self.estimators.iter().enumerate() { + match operation(estimator.estimator.as_ref()).await { + Ok(result) => { + estimator.errors_in_a_row.store(0, Ordering::SeqCst); + return Ok(result); + } + Err(err) => { + let num_errors = estimator.errors_in_a_row.fetch_add(1, Ordering::SeqCst) + 1; + if num_errors < LOG_ERROR_AFTER_N_ERRORS { + tracing::warn!(?err, "gas estimator {} failed", i); + } else { + tracing::error!(?err, "gas estimator {} failed", i); + } + } + } + } + Err(anyhow!("all gas estimators failed")) + } +} + +#[async_trait::async_trait] +impl GasPriceEstimating for PriorityGasPriceEstimating { + async fn estimate(&self) -> Result { + self.prioritize(|estimator| estimator.estimate()).await + } + + async fn base_fee(&self) -> Result> { + self.prioritize(|estimator| estimator.base_fee()).await + } +} + +#[cfg(test)] +mod tests { + use { + crate::{GasPriceEstimating, MockGasPriceEstimating, priority::PriorityGasPriceEstimating}, + alloy_eips::eip1559::Eip1559Estimation, + anyhow::anyhow, + futures::future::FutureExt, + }; + + #[test] + fn prioritize_picks_first_if_first_succeeds() { + let mut estimator_0 = MockGasPriceEstimating::new(); + let estimator_1 = MockGasPriceEstimating::new(); + + estimator_0.expect_estimate().times(1).returning(|| { + Ok(Eip1559Estimation { + max_fee_per_gas: 10, + max_priority_fee_per_gas: 0, + }) + }); + + let priority = + PriorityGasPriceEstimating::new(vec![Box::new(estimator_0), Box::new(estimator_1)]); + // estimator_1 has no expectation so would panic if called + priority.estimate().now_or_never().unwrap().unwrap(); + } + + #[test] + fn prioritize_picks_second_if_first_fails() { + let mut estimator_0 = MockGasPriceEstimating::new(); + let mut estimator_1 = MockGasPriceEstimating::new(); + + estimator_0 + .expect_estimate() + .times(1) + .returning(|| Err(anyhow!(""))); + estimator_1.expect_estimate().times(1).returning(|| { + Ok(Eip1559Estimation { + max_fee_per_gas: 10, + max_priority_fee_per_gas: 0, + }) + }); + + let priority = + PriorityGasPriceEstimating::new(vec![Box::new(estimator_0), Box::new(estimator_1)]); + let result = priority.estimate().now_or_never().unwrap().unwrap(); + assert_eq!(result.max_fee_per_gas, 10); + } + + #[test] + fn prioritize_fails_if_all_fail() { + let mut estimator_0 = MockGasPriceEstimating::new(); + let mut estimator_1 = MockGasPriceEstimating::new(); + + estimator_0 + .expect_estimate() + .times(1) + .returning(|| Err(anyhow!(""))); + estimator_1 + .expect_estimate() + .times(1) + .returning(|| Err(anyhow!(""))); + + let priority = + PriorityGasPriceEstimating::new(vec![Box::new(estimator_0), Box::new(estimator_1)]); + let result = priority.estimate().now_or_never().unwrap(); + assert!(result.is_err()); + } +} diff --git a/crates/http-client/Cargo.toml b/crates/http-client/Cargo.toml new file mode 100644 index 0000000000..1c03aea2d2 --- /dev/null +++ b/crates/http-client/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "http-client" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "GPL-3.0-or-later" + +[dependencies] +clap = { workspace = true } +configs = { workspace = true } +humantime = { workspace = true } +reqwest = { workspace = true, features = ["cookies", "gzip", "json", "query"] } diff --git a/crates/shared/src/http_client.rs b/crates/http-client/src/lib.rs similarity index 63% rename from crates/shared/src/http_client.rs rename to crates/http-client/src/lib.rs index 630117cd69..1c8a086140 100644 --- a/crates/shared/src/http_client.rs +++ b/crates/http-client/src/lib.rs @@ -1,9 +1,6 @@ use { reqwest::{Client, ClientBuilder}, - std::{ - fmt::{self, Display, Formatter}, - time::Duration, - }, + std::time::Duration, }; const USER_AGENT: &str = "cowprotocol-services/2.0.0"; @@ -16,13 +13,13 @@ const USER_AGENT: &str = "cowprotocol-services/2.0.0"; /// different APIs. #[derive(Clone, Debug)] pub struct HttpClientFactory { - timeout: Duration, + pub timeout: Duration, } impl HttpClientFactory { - pub fn new(args: &Arguments) -> Self { + pub fn new(args: &configs::http_client::HttpClient) -> Self { Self { - timeout: args.http_timeout, + timeout: args.timeout, } } @@ -40,6 +37,7 @@ impl HttpClientFactory { pub fn builder(&self) -> ClientBuilder { ClientBuilder::new() .timeout(self.timeout) + .tcp_keepalive(Duration::from_secs(60)) .user_agent(USER_AGENT) } } @@ -52,24 +50,10 @@ impl Default for HttpClientFactory { } } -/// Command line arguments for the common HTTP factory. -#[derive(clap::Parser)] -#[group(skip)] -pub struct Arguments { - /// Default timeout in seconds for http requests. - #[clap( - long, - env, - default_value = "10s", - value_parser = humantime::parse_duration, - )] - pub http_timeout: Duration, -} - -impl Display for Arguments { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Self { http_timeout } = self; - - writeln!(f, "http_timeout: {http_timeout:?}") +impl From for HttpClientFactory { + fn from(value: configs::http_client::HttpClient) -> Self { + Self { + timeout: value.timeout, + } } } diff --git a/crates/liquidity-sources/Cargo.toml b/crates/liquidity-sources/Cargo.toml new file mode 100644 index 0000000000..f4b0b87547 --- /dev/null +++ b/crates/liquidity-sources/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "liquidity-sources" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy = { workspace = true, features = ["contract", "rand", "rpc-types"] } +anyhow = { workspace = true } +async-trait = { workspace = true } +bytes-hex = { workspace = true } +cached = { workspace = true } +chain = { workspace = true } +chrono = { workspace = true } +clap = { workspace = true } +const-hex = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +event-indexing = { workspace = true } +futures = { workspace = true } +hex-literal = { workspace = true } +itertools = { workspace = true } +mockall = { workspace = true, optional = true } +model = { workspace = true } +num = { workspace = true } +number = { workspace = true } +observe = { workspace = true } +prometheus = { workspace = true } +prometheus-metric-storage = { workspace = true } +request-sharing = { workspace = true } +reqwest = { workspace = true, features = ["json"] } +serde = { workspace = true } +serde_json = { workspace = true } +serde_with = { workspace = true } +strum = { workspace = true } +thiserror = { workspace = true } +token-info = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +ethrpc = { workspace = true, features = ["test-util"] } +maplit = { workspace = true } +mockall = { workspace = true } +regex = { workspace = true } +testlib = { workspace = true } +token-info = { workspace = true, features = ["test-util"] } + +[features] +test-util = ["dep:mockall"] + +[lints] +workspace = true diff --git a/crates/liquidity-sources/LICENSE-APACHE b/crates/liquidity-sources/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/liquidity-sources/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/liquidity-sources/LICENSE-MIT b/crates/liquidity-sources/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/liquidity-sources/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/shared/src/sources/balancer_v2/graph_api.rs b/crates/liquidity-sources/src/balancer_v2/graph_api.rs similarity index 82% rename from crates/shared/src/sources/balancer_v2/graph_api.rs rename to crates/liquidity-sources/src/balancer_v2/graph_api.rs index ae64119fea..45bc8601b1 100644 --- a/crates/shared/src/sources/balancer_v2/graph_api.rs +++ b/crates/liquidity-sources/src/balancer_v2/graph_api.rs @@ -10,9 +10,10 @@ use { super::swap::fixed_point::Bfp, - crate::{event_handling::MAX_REORG_BLOCK_COUNT, subgraph::SubgraphClient}, + crate::{json_map, subgraph::SubgraphClient}, + alloy::primitives::{Address, B256}, anyhow::Result, - ethcontract::{H160, H256}, + event_indexing::event_handler::MAX_REORG_BLOCK_COUNT, reqwest::{Client, Url}, serde::Deserialize, serde_json::json, @@ -49,7 +50,7 @@ impl BalancerSubgraphClient { let block_number = self.get_safe_block().await?; let mut pools = Vec::new(); - let mut last_id = H256::default(); + let mut last_id = B256::default(); // We do paging by last ID instead of using `skip`. This is the // suggested approach to paging best performance: @@ -124,7 +125,7 @@ impl RegisteredPools { } /// Groups registered pools by factory addresses. - pub fn group_by_factory(self) -> HashMap { + pub fn group_by_factory(self) -> HashMap { let fetched_block_number = self.fetched_block_number; self.pools .into_iter() @@ -147,9 +148,9 @@ impl RegisteredPools { #[serde(rename_all = "camelCase")] pub struct PoolData { pub pool_type: PoolType, - pub id: H256, - pub address: H160, - pub factory: H160, + pub id: B256, + pub address: Address, + pub factory: Address, pub swap_enabled: bool, pub tokens: Vec, } @@ -167,7 +168,7 @@ pub enum PoolType { #[serde_as] #[derive(Debug, Deserialize, Eq, PartialEq)] pub struct Token { - pub address: H160, + pub address: Address, pub decimals: u8, #[serde_as(as = "Option")] #[serde(default)] @@ -243,8 +244,8 @@ mod block_number_query { mod tests { use { super::*, - crate::sources::balancer_v2::swap::fixed_point::Bfp, - ethcontract::{H160, H256}, + crate::balancer_v2::swap::fixed_point::Bfp, + alloy::primitives::U256, maplit::hashmap, }; @@ -334,37 +335,41 @@ mod tests { pools: vec![ PoolData { pool_type: PoolType::Weighted, - id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + id: B256::repeat_byte(0x11), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, ], }, PoolData { pool_type: PoolType::Stable, - id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + id: B256::repeat_byte(0x11), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: None, }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, weight: None, }, @@ -372,37 +377,41 @@ mod tests { }, PoolData { pool_type: PoolType::LiquidityBootstrapping, - id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + id: B256::repeat_byte(0x11), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, ], }, PoolData { pool_type: PoolType::ComposableStable, - id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + id: B256::repeat_byte(0x11), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: None, }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, weight: None, }, @@ -436,8 +445,8 @@ mod tests { #[test] fn groups_pools_by_factory() { - let pool = |factory: H160, id: u8| PoolData { - id: H256([id; 32]), + let pool = |factory: Address, id: u8| PoolData { + id: B256::repeat_byte(id), factory, pool_type: PoolType::Weighted, address: Default::default(), @@ -447,9 +456,9 @@ mod tests { let registered_pools = RegisteredPools { pools: vec![ - pool(H160([1; 20]), 1), - pool(H160([1; 20]), 2), - pool(H160([2; 20]), 3), + pool(Address::repeat_byte(1), 1), + pool(Address::repeat_byte(1), 2), + pool(Address::repeat_byte(2), 3), ], fetched_block_number: 42, }; @@ -457,16 +466,16 @@ mod tests { assert_eq!( registered_pools.group_by_factory(), hashmap! { - H160([1; 20]) => RegisteredPools { + Address::repeat_byte(1) => RegisteredPools { pools: vec![ - pool(H160([1; 20]), 1), - pool(H160([1; 20]), 2), + pool(Address::repeat_byte(1), 1), + pool(Address::repeat_byte(1), 2), ], fetched_block_number: 42, }, - H160([2; 20]) => RegisteredPools { + Address::repeat_byte(2) => RegisteredPools { pools: vec![ - pool(H160([2; 20]), 3), + pool(Address::repeat_byte(2), 3), ], fetched_block_number: 42, }, diff --git a/crates/shared/src/sources/balancer_v2/mod.rs b/crates/liquidity-sources/src/balancer_v2/mod.rs similarity index 96% rename from crates/shared/src/sources/balancer_v2/mod.rs rename to crates/liquidity-sources/src/balancer_v2/mod.rs index 22b179b266..b9b4a9de5c 100644 --- a/crates/shared/src/sources/balancer_v2/mod.rs +++ b/crates/liquidity-sources/src/balancer_v2/mod.rs @@ -44,6 +44,6 @@ pub mod pools; pub mod swap; pub use self::{ - pool_fetching::{BalancerFactoryKind, BalancerPoolFetcher, BalancerPoolFetching}, + pool_fetching::{BalancerPoolFetcher, BalancerPoolFetching}, pools::{Pool, PoolKind}, }; diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/aggregate.rs b/crates/liquidity-sources/src/balancer_v2/pool_fetching/aggregate.rs similarity index 86% rename from crates/shared/src/sources/balancer_v2/pool_fetching/aggregate.rs rename to crates/liquidity-sources/src/balancer_v2/pool_fetching/aggregate.rs index 525ca54ec9..6e6f87d843 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/aggregate.rs +++ b/crates/liquidity-sources/src/balancer_v2/pool_fetching/aggregate.rs @@ -3,9 +3,9 @@ use { super::internal::InternalPoolFetching, - crate::{recent_block_cache::Block, sources::balancer_v2::pools::Pool}, + crate::{balancer_v2::pools::Pool, recent_block_cache::Block}, + alloy::primitives::B256, anyhow::Result, - ethcontract::H256, futures::future, model::TokenPair, std::collections::HashSet, @@ -25,7 +25,7 @@ impl Aggregate { #[async_trait::async_trait] impl InternalPoolFetching for Aggregate { - async fn pool_ids_for_token_pairs(&self, token_pairs: HashSet) -> HashSet { + async fn pool_ids_for_token_pairs(&self, token_pairs: HashSet) -> HashSet { future::join_all( self.fetchers .iter() @@ -37,7 +37,7 @@ impl InternalPoolFetching for Aggregate { .collect() } - async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result> { + async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result> { Ok(future::try_join_all( self.fetchers .iter() diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/cache.rs b/crates/liquidity-sources/src/balancer_v2/pool_fetching/cache.rs similarity index 83% rename from crates/shared/src/sources/balancer_v2/pool_fetching/cache.rs rename to crates/liquidity-sources/src/balancer_v2/pool_fetching/cache.rs index a79d6dd390..ef47caed83 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/cache.rs +++ b/crates/liquidity-sources/src/balancer_v2/pool_fetching/cache.rs @@ -6,17 +6,17 @@ use { super::internal::InternalPoolFetching, crate::{ + balancer_v2::pools::Pool, recent_block_cache::{Block, CacheConfig, CacheFetching, CacheKey, RecentBlockCache}, - sources::balancer_v2::pools::Pool, }, + alloy::primitives::B256, anyhow::Result, - ethcontract::H256, ethrpc::block_stream::CurrentBlockWatcher, std::{collections::HashSet, sync::Arc}, }; /// Internal type alias used for inner recent block cache. -type PoolCache = RecentBlockCache>; +type PoolCache = RecentBlockCache>; /// A cached pool fetcher that wraps an inner `InternalPoolFetching` /// implementation. @@ -52,18 +52,18 @@ where async fn pool_ids_for_token_pairs( &self, token_pairs: HashSet, - ) -> HashSet { + ) -> HashSet { self.inner.pool_ids_for_token_pairs(token_pairs).await } - async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result> { + async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result> { self.cache.fetch(pool_ids, block).await } } -impl CacheKey for H256 { +impl CacheKey for B256 { fn first_ord() -> Self { - H256::zero() + B256::ZERO } fn for_value(pool: &Pool) -> Self { @@ -79,11 +79,11 @@ impl CacheKey for H256 { struct CacheFetcher(Arc); #[async_trait::async_trait] -impl CacheFetching for CacheFetcher +impl CacheFetching for CacheFetcher where Inner: InternalPoolFetching, { - async fn fetch_values(&self, pool_ids: HashSet, at_block: Block) -> Result> { + async fn fetch_values(&self, pool_ids: HashSet, at_block: Block) -> Result> { self.0.pools_by_id(pool_ids, at_block).await } } diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/internal.rs b/crates/liquidity-sources/src/balancer_v2/pool_fetching/internal.rs similarity index 77% rename from crates/shared/src/sources/balancer_v2/pool_fetching/internal.rs rename to crates/liquidity-sources/src/balancer_v2/pool_fetching/internal.rs index 944fa00850..c0c6688dc9 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/internal.rs +++ b/crates/liquidity-sources/src/balancer_v2/pool_fetching/internal.rs @@ -2,9 +2,9 @@ //! strategies. use { - crate::{recent_block_cache::Block, sources::balancer_v2::pools::Pool}, + crate::{balancer_v2::pools::Pool, recent_block_cache::Block}, + alloy::primitives::B256, anyhow::Result, - ethcontract::H256, model::TokenPair, std::collections::HashSet, }; @@ -16,8 +16,8 @@ use { #[async_trait::async_trait] pub trait InternalPoolFetching: Send + Sync + 'static { /// Retrives all pool IDs that trade the specified pairs. - async fn pool_ids_for_token_pairs(&self, token_pairs: HashSet) -> HashSet; + async fn pool_ids_for_token_pairs(&self, token_pairs: HashSet) -> HashSet; /// Fetches current pool states for the specified IDs and block. - async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result>; + async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result>; } diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs b/crates/liquidity-sources/src/balancer_v2/pool_fetching/mod.rs similarity index 70% rename from crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs rename to crates/liquidity-sources/src/balancer_v2/pool_fetching/mod.rs index f245fa28c4..1dfdaab5d2 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs +++ b/crates/liquidity-sources/src/balancer_v2/pool_fetching/mod.rs @@ -25,15 +25,14 @@ use { }, swap::fixed_point::Bfp, }, - crate::{ - ethrpc::Web3, - recent_block_cache::{Block, CacheConfig}, - token_info::TokenInfoFetching, + crate::recent_block_cache::{Block, CacheConfig}, + alloy::{ + eips::BlockNumberOrTag, + primitives::{Address, B256}, + providers::{DynProvider, Provider}, }, - alloy::providers::DynProvider, anyhow::{Context, Result}, - clap::ValueEnum, - contracts::alloy::{ + contracts::{ BalancerV2ComposableStablePoolFactory, BalancerV2ComposableStablePoolFactoryV3, BalancerV2ComposableStablePoolFactoryV4, @@ -47,16 +46,16 @@ use { BalancerV2WeightedPoolFactory, BalancerV2WeightedPoolFactoryV3, BalancerV2WeightedPoolFactoryV4, - InstanceExt, }, - ethcontract::{BlockId, H160, H256}, - ethrpc::block_stream::{BlockRetrieving, CurrentBlockWatcher}, + ethrpc::{Web3, alloy::ProviderLabelingExt, block_stream::CurrentBlockWatcher}, + event_indexing::block_retriever::BlockRetrieving, model::TokenPair, reqwest::{Client, Url}, std::{ collections::{BTreeMap, HashSet}, sync::Arc, }, + token_info::TokenInfoFetching, tracing::instrument, }; pub use { @@ -77,8 +76,8 @@ pub trait BalancerPoolEvaluating { #[derive(Clone, Debug)] pub struct CommonPoolState { - pub id: H256, - pub address: H160, + pub id: B256, + pub address: Address, pub swap_fee: Bfp, pub paused: bool, } @@ -86,12 +85,12 @@ pub struct CommonPoolState { #[derive(Clone, Debug)] pub struct WeightedPool { pub common: CommonPoolState, - pub reserves: BTreeMap, + pub reserves: BTreeMap, pub version: WeightedPoolVersion, } impl WeightedPool { - pub fn new_unpaused(pool_id: H256, weighted_state: weighted::PoolState) -> Self { + pub fn new_unpaused(pool_id: B256, weighted_state: weighted::PoolState) -> Self { WeightedPool { common: CommonPoolState { id: pool_id, @@ -108,12 +107,12 @@ impl WeightedPool { #[derive(Clone, Debug)] pub struct StablePool { pub common: CommonPoolState, - pub reserves: BTreeMap, + pub reserves: BTreeMap, pub amplification_parameter: AmplificationParameter, } impl StablePool { - pub fn new_unpaused(pool_id: H256, stable_state: stable::PoolState) -> Self { + pub fn new_unpaused(pool_id: B256, stable_state: stable::PoolState) -> Self { StablePool { common: CommonPoolState { id: pool_id, @@ -134,7 +133,7 @@ pub struct FetchedBalancerPools { } impl FetchedBalancerPools { - pub fn relevant_tokens(&self) -> HashSet { + pub fn relevant_tokens(&self) -> HashSet
{ let mut tokens = HashSet::new(); tokens.extend( self.stable_pools @@ -166,25 +165,7 @@ pub struct BalancerPoolFetcher { // being problematic because their token balance becomes out of sync leading to simulation // failures. // https://forum.balancer.fi/t/medium-severity-bug-found/3161 - pool_id_deny_list: Vec, -} - -/// An enum containing all supported Balancer factory types. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)] -#[clap(rename_all = "verbatim")] -pub enum BalancerFactoryKind { - Weighted, - WeightedV3, - WeightedV4, - Weighted2Token, - StableV2, - LiquidityBootstrapping, - NoProtocolFeeLiquidityBootstrapping, - ComposableStable, - ComposableStableV3, - ComposableStableV4, - ComposableStableV5, - ComposableStableV6, + pool_id_deny_list: Vec, } pub enum BalancerFactoryInstance { @@ -244,128 +225,12 @@ impl BalancerFactoryInstance { } } -impl BalancerFactoryKind { - /// Returns a vector with supported factories for the specified chain ID. - pub fn for_chain(chain_id: u64) -> Vec { - match chain_id { - 1 => Self::value_variants().to_owned(), - 5 => vec![ - Self::Weighted, - Self::WeightedV3, - Self::WeightedV4, - Self::Weighted2Token, - Self::StableV2, - Self::ComposableStable, - Self::ComposableStableV3, - Self::ComposableStableV4, - Self::ComposableStableV5, - Self::ComposableStableV6, - ], - 100 => vec![ - Self::WeightedV3, - Self::WeightedV4, - Self::StableV2, - Self::ComposableStableV3, - Self::ComposableStableV4, - Self::ComposableStableV5, - Self::ComposableStableV6, - ], - 11155111 => vec![ - Self::WeightedV4, - Self::ComposableStableV4, - Self::ComposableStableV5, - Self::ComposableStableV6, - Self::NoProtocolFeeLiquidityBootstrapping, - ], - _ => Default::default(), - } - } -} - /// All balancer related contracts that we expect to exist. pub struct BalancerContracts { pub vault: BalancerV2Vault::Instance, pub factories: Vec, } -impl BalancerContracts { - pub async fn try_new(web3: &Web3, factory_kinds: Vec) -> Result { - let web3 = ethrpc::instrumented::instrument_with_label(web3, "balancerV2".into()); - let vault = BalancerV2Vault::Instance::deployed(&web3.alloy) - .await - .context("Cannot retrieve balancer vault")?; - - macro_rules! instance { - ($factory:ident) => {{ - $factory::Instance::deployed(&web3.alloy) - .await - .context(format!( - "Cannot retrieve Balancer factory {}", - stringify!($factory) - ))? - }}; - } - - let mut factories = Vec::new(); - for kind in factory_kinds { - let instance = match &kind { - BalancerFactoryKind::Weighted => { - BalancerFactoryInstance::Weighted(instance!(BalancerV2WeightedPoolFactory)) - } - BalancerFactoryKind::WeightedV3 => { - BalancerFactoryInstance::WeightedV3(instance!(BalancerV2WeightedPoolFactoryV3)) - } - BalancerFactoryKind::WeightedV4 => { - BalancerFactoryInstance::WeightedV4(instance!(BalancerV2WeightedPoolFactoryV4)) - } - BalancerFactoryKind::Weighted2Token => BalancerFactoryInstance::Weighted2Token( - instance!(BalancerV2WeightedPool2TokensFactory), - ), - BalancerFactoryKind::StableV2 => { - BalancerFactoryInstance::StableV2(instance!(BalancerV2StablePoolFactoryV2)) - } - BalancerFactoryKind::LiquidityBootstrapping => { - BalancerFactoryInstance::LiquidityBootstrapping(instance!( - BalancerV2LiquidityBootstrappingPoolFactory - )) - } - BalancerFactoryKind::NoProtocolFeeLiquidityBootstrapping => { - BalancerFactoryInstance::NoProtocolFeeLiquidityBootstrapping(instance!( - BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory - )) - } - BalancerFactoryKind::ComposableStable => BalancerFactoryInstance::ComposableStable( - instance!(BalancerV2ComposableStablePoolFactory), - ), - BalancerFactoryKind::ComposableStableV3 => { - BalancerFactoryInstance::ComposableStableV3(instance!( - BalancerV2ComposableStablePoolFactoryV3 - )) - } - BalancerFactoryKind::ComposableStableV4 => { - BalancerFactoryInstance::ComposableStableV4(instance!( - BalancerV2ComposableStablePoolFactoryV4 - )) - } - BalancerFactoryKind::ComposableStableV5 => { - BalancerFactoryInstance::ComposableStableV5(instance!( - BalancerV2ComposableStablePoolFactoryV5 - )) - } - BalancerFactoryKind::ComposableStableV6 => { - BalancerFactoryInstance::ComposableStableV6(instance!( - BalancerV2ComposableStablePoolFactoryV6 - )) - } - }; - - factories.push(instance); - } - - Ok(Self { vault, factories }) - } -} - impl BalancerPoolFetcher { #[expect(clippy::too_many_arguments)] pub async fn new( @@ -377,10 +242,10 @@ impl BalancerPoolFetcher { client: Client, web3: Web3, contracts: &BalancerContracts, - deny_listed_pool_ids: Vec, + deny_listed_pool_ids: Vec, ) -> Result { let pool_initializer = BalancerSubgraphClient::from_subgraph_url(subgraph_url, client)?; - let web3 = ethrpc::instrumented::instrument_with_label(&web3, "balancerV2".into()); + let web3 = web3.labeled("balancerV2"); let fetcher = Arc::new(Cache::new( create_aggregate_pool_fetcher( web3, @@ -459,18 +324,15 @@ async fn create_aggregate_pool_fetcher( let registered_pools = pool_initializer.initialize_pools().await?; let fetched_block_number = registered_pools.fetched_block_number; let fetched_block_hash = web3 - .eth() - .block(BlockId::Number(fetched_block_number.into())) + .provider + .get_block_by_number(BlockNumberOrTag::Number(fetched_block_number)) .await? .context("failed to get block by block number")? - .hash - .context("missing hash from block")?; + .hash(); let mut registered_pools_by_factory = registered_pools.group_by_factory(); macro_rules! registry { ($factory:ident, $instance:expr_2021) => {{ - use ethrpc::alloy::conversions::IntoLegacy; - create_internal_pool_fetcher( contracts.vault.clone(), $factory::Instance::new(*$instance.address(), $instance.provider().clone()), @@ -478,7 +340,7 @@ async fn create_aggregate_pool_fetcher( token_infos.clone(), $instance, registered_pools_by_factory - .remove(&(*$instance.address()).into_legacy()) + .remove(&(*$instance.address())) .unwrap_or_else(|| RegisteredPools::empty(fetched_block_number)), fetched_block_hash, )? @@ -557,7 +419,7 @@ fn create_internal_pool_fetcher( token_infos: Arc, factory_instance: &BalancerFactoryInstance, registered_pools: RegisteredPools, - fetched_block_hash: H256, + fetched_block_hash: B256, ) -> Result> where Factory: FactoryIndexing, @@ -584,23 +446,24 @@ where /// the pool. For example the GNO-BAL pool with ID /// `0x36128d5436d2d70cab39c9af9cce146c38554ff0000200000000000000000009`: /// -fn pool_address_from_id(pool_id: H256) -> H160 { - let mut address = H160::default(); - address.0.copy_from_slice(&pool_id.0[..20]); - address +fn pool_address_from_id(pool_id: B256) -> Address { + Address::from_slice(&pool_id.as_slice()[..20]) } #[cfg(test)] mod tests { - use {super::*, hex_literal::hex}; + use { + super::*, + alloy::primitives::{address, b256}, + }; #[test] fn can_extract_address_from_pool_id() { assert_eq!( - pool_address_from_id(H256(hex!( + pool_address_from_id(b256!( "36128d5436d2d70cab39c9af9cce146c38554ff0000200000000000000000009" - ))), - addr!("36128d5436d2d70cab39c9af9cce146c38554ff0"), + )), + address!("36128d5436d2d70cab39c9af9cce146c38554ff0"), ); } } diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/pool_storage.rs b/crates/liquidity-sources/src/balancer_v2/pool_fetching/pool_storage.rs similarity index 84% rename from crates/shared/src/sources/balancer_v2/pool_fetching/pool_storage.rs rename to crates/liquidity-sources/src/balancer_v2/pool_fetching/pool_storage.rs index f26737083b..835b622160 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/pool_storage.rs +++ b/crates/liquidity-sources/src/balancer_v2/pool_fetching/pool_storage.rs @@ -16,18 +16,17 @@ //! efficient lookup searching for pools based on token pairs. use { - crate::{ - event_handling::EventStoring, - sources::balancer_v2::pools::{FactoryIndexing, PoolIndexing, common}, + crate::balancer_v2::pools::{FactoryIndexing, PoolIndexing, common}, + alloy::{ + primitives::{Address, B256}, + rpc::types::Log, }, - alloy::rpc::types::Log, anyhow::{Context, Result}, - contracts::alloy::BalancerV2BasePoolFactory::BalancerV2BasePoolFactory::{ + contracts::BalancerV2BasePoolFactory::BalancerV2BasePoolFactory::{ BalancerV2BasePoolFactoryEvents, PoolCreated, }, - ethcontract::{H160, H256}, - ethrpc::{alloy::conversions::IntoLegacy, block_stream::RangeInclusive}, + event_indexing::{block_retriever::RangeInclusive, event_handler::EventStoring}, model::TokenPair, std::{ cmp, @@ -44,9 +43,9 @@ where /// Component used to fetch pool information. pool_info_fetcher: Arc>, /// Used for O(1) access to all pool_ids for a given token - pools_by_token: HashMap>, + pools_by_token: HashMap>, /// All indexed pool infos by ID. - pools: HashMap, + pools: HashMap, /// The block the initial pools were fetched on. This block is considered /// reorg-safe and events prior to this block do not get replaced. initial_fetched_block: u64, @@ -81,11 +80,11 @@ where fn pool_ids_for_token_pair( &self, token_pair: &TokenPair, - ) -> impl Iterator + '_ + use<'_, Factory> { + ) -> impl Iterator + '_ + use<'_, Factory> { let (token0, token1) = token_pair.get(); - let pools0 = self.pools_by_token.get(&token0.into_legacy()); - let pools1 = self.pools_by_token.get(&token1.into_legacy()); + let pools0 = self.pools_by_token.get(&token0); + let pools1 = self.pools_by_token.get(&token1); pools0 .zip(pools1) @@ -96,7 +95,7 @@ where /// Given a collection of `TokenPair`, returns all pools containing at least /// one of the pairs. - pub fn pool_ids_for_token_pairs(&self, token_pairs: &HashSet) -> HashSet { + pub fn pool_ids_for_token_pairs(&self, token_pairs: &HashSet) -> HashSet { token_pairs .iter() .flat_map(|pair| self.pool_ids_for_token_pair(pair)) @@ -104,12 +103,12 @@ where } /// Returns a pool by ID or none if no such pool exists. - pub fn pool_by_id(&self, pool_id: H256) -> Option<&Factory::PoolInfo> { + pub fn pool_by_id(&self, pool_id: B256) -> Option<&Factory::PoolInfo> { self.pools.get(&pool_id) } /// Returns all pool infos by their IDs. - pub fn pools_by_id(&self, pool_ids: &HashSet) -> Vec { + pub fn pools_by_id(&self, pool_ids: &HashSet) -> Vec { pool_ids .iter() .filter_map(|pool_id| self.pool_by_id(*pool_id)) @@ -135,7 +134,7 @@ where ) -> Result<()> { let pool = self .pool_info_fetcher - .fetch_pool_info(pool_creation.pool.into_legacy(), block_created) + .fetch_pool_info(pool_creation.pool, block_created) .await?; self.insert_pool(pool); @@ -229,38 +228,42 @@ where mod tests { use { super::*, - crate::sources::balancer_v2::{ + crate::balancer_v2::{ pools::{MockFactoryIndexing, common::MockPoolInfoFetching, weighted}, swap::fixed_point::Bfp, }, - ethrpc::alloy::conversions::IntoAlloy, + alloy::primitives::U256, maplit::{hashmap, hashset}, mockall::predicate::eq, }; pub type PoolInitData = ( - Vec, - Vec, - Vec, + Vec, + Vec
, + Vec
, Vec, Vec<(PoolCreated, u64)>, ); + // This can be made cleaner by making the start and end be u8's but the B256 + // doesn't support for a from(u8) so this needs to be reviewed upon migration fn pool_init_data(start: usize, end: usize) -> PoolInitData { - let pool_ids: Vec = (start..=end) - .map(|i| H256::from_low_u64_be(i as u64)) + let pool_ids: Vec = (start..=end) + .map(|i| B256::left_padding_from(&i.to_be_bytes())) .collect(); - let pool_addresses: Vec = (start..=end) - .map(|i| H160::from_low_u64_be(i as u64)) + let pool_addresses: Vec
= (start..=end) + .map(|i| Address::with_last_byte(i as u8)) .collect(); - let tokens: Vec = (start..=end + 1) - .map(|i| H160::from_low_u64_be(i as u64)) + let tokens: Vec
= (start..=end + 1) + .map(|i| Address::with_last_byte(i as u8)) + .collect(); + let weights: Vec = (start..=end + 1) + .map(|i| Bfp::from_wei(U256::from(i))) .collect(); - let weights: Vec = (start..=end + 1).map(|i| Bfp::from_wei(i.into())).collect(); let creation_events: Vec<(PoolCreated, u64)> = (start..=end) .map(|i| { ( PoolCreated { - pool: pool_addresses[i].into_alloy(), + pool: pool_addresses[i], }, i as u64, ) @@ -276,42 +279,46 @@ mod tests { vec![ weighted::PoolInfo { common: common::PoolInfo { - id: H256([1; 32]), - address: H160([1; 20]), - tokens: vec![H160([0x11; 20]), H160([0x22; 20])], + id: B256::repeat_byte(1), + address: Address::repeat_byte(1), + tokens: vec![Address::repeat_byte(0x11), Address::repeat_byte(0x22)], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0)], block_created: 0, }, weights: vec![ - Bfp::from_wei(500_000_000_000_000_000u128.into()), - Bfp::from_wei(500_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), ], }, weighted::PoolInfo { common: common::PoolInfo { - id: H256([2; 32]), - address: H160([2; 20]), - tokens: vec![H160([0x11; 20]), H160([0x33; 20]), H160([0x77; 20])], + id: B256::repeat_byte(2), + address: Address::repeat_byte(2), + tokens: vec![ + Address::repeat_byte(0x11), + Address::repeat_byte(0x33), + Address::repeat_byte(0x77), + ], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0)], block_created: 0, }, weights: vec![ - Bfp::from_wei(500_000_000_000_000_000u128.into()), - Bfp::from_wei(250_000_000_000_000_000u128.into()), - Bfp::from_wei(250_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(250_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(250_000_000_000_000_000_u128)), ], }, weighted::PoolInfo { common: common::PoolInfo { - id: H256([3; 32]), - address: H160([3; 20]), - tokens: vec![H160([0x11; 20]), H160([0x77; 20])], + id: B256::repeat_byte(3), + address: Address::repeat_byte(3), + tokens: vec![Address::repeat_byte(0x11), Address::repeat_byte(0x77)], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0)], block_created: 0, }, weights: vec![ - Bfp::from_wei(500_000_000_000_000_000u128.into()), - Bfp::from_wei(500_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), ], }, ], @@ -321,10 +328,10 @@ mod tests { assert_eq!( storage.pools_by_token, hashmap! { - H160([0x11; 20]) => hashset![H256([1; 32]), H256([2; 32]), H256([3; 32])], - H160([0x22; 20]) => hashset![H256([1; 32])], - H160([0x33; 20]) => hashset![H256([2; 32])], - H160([0x77; 20]) => hashset![H256([2; 32]), H256([3; 32])], + Address::repeat_byte(0x11) => hashset![B256::repeat_byte(1), B256::repeat_byte(2), B256::repeat_byte(3)], + Address::repeat_byte(0x22) => hashset![B256::repeat_byte(1)], + Address::repeat_byte(0x33) => hashset![B256::repeat_byte(2)], + Address::repeat_byte(0x77) => hashset![B256::repeat_byte(2), B256::repeat_byte(3)], } ); } @@ -433,16 +440,16 @@ mod tests { let new_pool = weighted::PoolInfo { common: common::PoolInfo { - id: H256::from_low_u64_be(43110), - address: H160::from_low_u64_be(42), - tokens: vec![H160::from_low_u64_be(808)], + id: B256::left_padding_from(&43110u64.to_be_bytes()), + address: Address::with_last_byte(42), + tokens: vec![Address::left_padding_from(808u64.to_be_bytes().as_slice())], scaling_factors: vec![Bfp::exp10(0)], block_created: 3, }, - weights: vec![Bfp::from_wei(1337.into())], + weights: vec![Bfp::from_wei(U256::from(1337))], }; let new_creation = PoolCreated { - pool: new_pool.common.address.into_alloy(), + pool: new_pool.common.address, }; mock_pool_fetcher @@ -534,9 +541,7 @@ mod tests { let n = 3; let (pool_ids, pool_addresses, tokens, _, _) = pool_init_data(0, n); let token_pairs: Vec = (0..n) - .map(|i| { - TokenPair::new(tokens[i].into_alloy(), tokens[(i + 1) % n].into_alloy()).unwrap() - }) + .map(|i| TokenPair::new(tokens[i], tokens[(i + 1) % n]).unwrap()) .collect(); let mut registry = PoolStorage::new( diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/registry.rs b/crates/liquidity-sources/src/balancer_v2/pool_fetching/registry.rs similarity index 80% rename from crates/shared/src/sources/balancer_v2/pool_fetching/registry.rs rename to crates/liquidity-sources/src/balancer_v2/pool_fetching/registry.rs index 78970a2701..9c2cbf7ee8 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/registry.rs +++ b/crates/liquidity-sources/src/balancer_v2/pool_fetching/registry.rs @@ -4,27 +4,27 @@ use { super::{internal::InternalPoolFetching, pool_storage::PoolStorage}, crate::{ - event_handling::{AlloyEventRetriever, AlloyEventRetrieving, EventHandler}, - maintenance::Maintaining, - recent_block_cache::Block, - sources::balancer_v2::{ + balancer_v2::{ pool_fetching::BalancerFactoryInstance, pools::{FactoryIndexing, Pool, PoolStatus, common::PoolInfoFetching}, }, + recent_block_cache::Block, }, BalancerV2BasePoolFactory::BalancerV2BasePoolFactory::BalancerV2BasePoolFactoryEvents, alloy::{ + primitives::B256, providers::DynProvider, rpc::types::{Filter, FilterSet, Log}, sol_types::SolEvent, }, anyhow::Result, - contracts::{ - alloy::BalancerV2BasePoolFactory::{self, BalancerV2BasePoolFactory::PoolCreated}, - errors::EthcontractErrorType, + contracts::BalancerV2BasePoolFactory::{self, BalancerV2BasePoolFactory::PoolCreated}, + ethrpc::{alloy::errors::ContractErrorExt, block_stream::BlockNumberHash}, + event_indexing::{ + block_retriever::BlockRetrieving, + event_handler::{AlloyEventRetrieving, EventHandler}, + maintenance::Maintaining, }, - ethcontract::{BlockId, H256, errors::MethodError}, - ethrpc::block_stream::{BlockNumberHash, BlockRetrieving}, futures::future, model::TokenPair, std::{collections::HashSet, sync::Arc}, @@ -51,7 +51,7 @@ impl AlloyEventRetrieving for BasePoolFactoryContract { /// Type alias for the internal event updater type. type PoolUpdater = Mutex< EventHandler< - AlloyEventRetriever, + BasePoolFactoryContract, PoolStorage, (BalancerV2BasePoolFactoryEvents, Log), >, @@ -85,7 +85,7 @@ where ) -> Self { let updater = Mutex::new(EventHandler::new( block_retreiver, - AlloyEventRetriever(BasePoolFactoryContract(base_pool_factory(factory_instance))), + BasePoolFactoryContract(base_pool_factory(factory_instance)), PoolStorage::new(initial_pools, fetcher.clone()), start_sync_at_block, )); @@ -98,7 +98,7 @@ impl InternalPoolFetching for Registry where Factory: FactoryIndexing, { - async fn pool_ids_for_token_pairs(&self, token_pairs: HashSet) -> HashSet { + async fn pool_ids_for_token_pairs(&self, token_pairs: HashSet) -> HashSet { self.updater .lock() .await @@ -106,13 +106,11 @@ where .pool_ids_for_token_pairs(&token_pairs) } - async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result> { - let block = BlockId::Number(block.into()); - + async fn pools_by_id(&self, pool_ids: HashSet, block: Block) -> Result> { let pool_infos = self.updater.lock().await.store().pools_by_id(&pool_ids); let pool_futures = pool_infos .into_iter() - .map(|pool_info| self.fetcher.fetch_pool(&pool_info, block)) + .map(|pool_info| self.fetcher.fetch_pool(&pool_info, block.into())) .collect::>(); let pools = future::join_all(pool_futures).await; @@ -148,29 +146,24 @@ fn collect_pool_results(pools: Vec>) -> Result> { .into_iter() .filter_map(|pool| match pool { Ok(pool) => Some(Ok(pool.active()?)), - Err(err) if is_contract_error(&err) => None, - Err(err) => Some(Err(err)), + // Error issued by the contract alloy contract calls + Err(err) => match err.downcast_ref::() { + Some(err) if err.is_contract_error() => None, + _ => Some(Err(err)), + }, }) .collect() } -fn is_contract_error(err: &anyhow::Error) -> bool { - matches!( - err.downcast_ref::() - .map(EthcontractErrorType::classify), - Some(EthcontractErrorType::Contract), - ) -} - #[cfg(test)] mod tests { use { super::*, - crate::sources::balancer_v2::{ + crate::balancer_v2::{ pools::{PoolKind, weighted}, swap::fixed_point::Bfp, }, - contracts::errors::{testing_contract_error, testing_node_error}, + ethrpc::alloy::errors::{testing_alloy_contract_error, testing_alloy_node_error}, }; #[tokio::test] @@ -185,14 +178,14 @@ mod tests { }), })), Ok(PoolStatus::Paused), - Err(testing_contract_error().into()), + Err(testing_alloy_contract_error().into()), ]; assert_eq!(collect_pool_results(results).unwrap().len(), 1); } #[tokio::test] async fn collecting_results_forwards_node_error() { - let node_err = Err(testing_node_error().into()); + let node_err = Err(testing_alloy_node_error().into()); assert!(collect_pool_results(vec![node_err]).is_err()); } } diff --git a/crates/shared/src/sources/balancer_v2/pool_init.rs b/crates/liquidity-sources/src/balancer_v2/pool_init.rs similarity index 100% rename from crates/shared/src/sources/balancer_v2/pool_init.rs rename to crates/liquidity-sources/src/balancer_v2/pool_init.rs diff --git a/crates/shared/src/sources/balancer_v2/pools/common.rs b/crates/liquidity-sources/src/balancer_v2/pools/common.rs similarity index 80% rename from crates/shared/src/sources/balancer_v2/pools/common.rs rename to crates/liquidity-sources/src/balancer_v2/pools/common.rs index cc657846d6..c9c6c831d3 100644 --- a/crates/shared/src/sources/balancer_v2/pools/common.rs +++ b/crates/liquidity-sources/src/balancer_v2/pools/common.rs @@ -2,19 +2,19 @@ use { super::{FactoryIndexing, Pool, PoolIndexing as _, PoolStatus}, - crate::{ - sources::balancer_v2::{ - graph_api::{PoolData, PoolType}, - swap::fixed_point::Bfp, - }, - token_info::TokenInfoFetching, + crate::balancer_v2::{ + graph_api::{PoolData, PoolType}, + swap::fixed_point::Bfp, + }, + alloy::{ + eips::BlockId, + primitives::{Address, B256, U256}, }, anyhow::{Context, Result, anyhow, ensure}, - contracts::alloy::{BalancerV2BasePool, BalancerV2Vault}, - ethcontract::{BlockId, H160, H256, U256}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + contracts::{BalancerV2BasePool, BalancerV2Vault}, futures::{FutureExt as _, future::BoxFuture}, std::{collections::BTreeMap, future::Future, sync::Arc}, + token_info::TokenInfoFetching, tokio::sync::oneshot, }; @@ -27,7 +27,7 @@ where { async fn fetch_pool_info( &self, - pool_address: H160, + pool_address: Address, block_created: u64, ) -> Result; @@ -60,13 +60,13 @@ impl PoolInfoFetcher { } /// Returns a Balancer base pool contract instance at the specified address. - fn base_pool_at(&self, pool_address: H160) -> BalancerV2BasePool::Instance { + fn base_pool_at(&self, pool_address: Address) -> BalancerV2BasePool::Instance { let provider = self.vault.provider().clone(); - BalancerV2BasePool::Instance::new(pool_address.into_alloy(), provider) + BalancerV2BasePool::Instance::new(pool_address, provider) } /// Retrieves the scaling exponents for the specified tokens. - async fn scaling_factors(&self, tokens: &[H160]) -> Result> { + async fn scaling_factors(&self, tokens: &[Address]) -> Result> { let token_infos = self.token_infos.get_token_infos(tokens).await; tokens .iter() @@ -83,21 +83,18 @@ impl PoolInfoFetcher { async fn fetch_common_pool_info( &self, - pool_address: H160, + pool_address: Address, block_created: u64, ) -> Result { let pool = self.base_pool_at(pool_address); - let pool_id = pool.getPoolId().call().await?.into_legacy(); + let pool_id = pool.getPoolId().call().await?; let tokens = self .vault .getPoolTokens(pool_id.0.into()) .call() .await? - .tokens - .into_iter() - .map(IntoLegacy::into_legacy) - .collect::>(); + .tokens; let scaling_factors = self.scaling_factors(&tokens).await?; Ok(PoolInfo { @@ -114,7 +111,6 @@ impl PoolInfoFetcher { pool: &PoolInfo, block: BlockId, ) -> BoxFuture<'static, Result> { - let block = block.into_alloy(); let pool_address = pool.address; let pool_id = pool.id; let vault = self.vault.clone(); @@ -152,21 +148,17 @@ impl PoolInfoFetcher { async move { let (paused, swap_fee, pool_tokens) = futures::try_join!(fetch_paused, fetch_swap_fee, pool_tokens)?; - let swap_fee = Bfp::from_wei(swap_fee.into_legacy()); + let swap_fee = Bfp::from_wei(swap_fee); let balances = pool_tokens.balances; - let tokens = pool_tokens - .tokens - .into_iter() - .map(IntoLegacy::into_legacy) - .collect::>(); + let tokens = pool_tokens.tokens.into_iter().collect::>(); ensure!(pool.tokens == tokens, "pool token mismatch"); let tokens = itertools::izip!(&pool.tokens, balances, &pool.scaling_factors) .map(|(&address, balance, &scaling_factor)| { ( address, TokenState { - balance: balance.into_legacy(), + balance, scaling_factor, }, ) @@ -190,7 +182,7 @@ where { async fn fetch_pool_info( &self, - pool_address: H160, + pool_address: Address, block_created: u64, ) -> Result { let common_pool_info = self @@ -233,9 +225,9 @@ where /// Common pool data shared across all Balancer pools. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct PoolInfo { - pub id: H256, - pub address: H160, - pub tokens: Vec, + pub id: B256, + pub address: Address, + pub tokens: Vec
, pub scaling_factors: Vec, pub block_created: u64, } @@ -276,7 +268,7 @@ impl PoolInfo { pub struct PoolState { pub paused: bool, pub swap_fee: Bfp, - pub tokens: BTreeMap, + pub tokens: BTreeMap, } /// Common pool token state information that is shared among all pool types. @@ -363,12 +355,12 @@ mod tests { use { super::*, crate::{ - sources::balancer_v2::{ + balancer_v2::{ PoolKind, graph_api::{PoolType, Token}, pools::{MockFactoryIndexing, weighted}, }, - token_info::{MockTokenInfoFetching, TokenInfo}, + bfp, }, alloy::{ providers::{Provider, ProviderBuilder}, @@ -376,34 +368,37 @@ mod tests { transports::mock::Asserter, }, anyhow::bail, - contracts::alloy::BalancerV2Vault, - ethcontract::U256, + contracts::BalancerV2Vault, maplit::{btreemap, hashmap}, mockall::predicate, std::future, - web3::types::BlockNumber, + token_info::{MockTokenInfoFetching, TokenInfo}, }; #[tokio::test] async fn fetch_common_pool_info() { let pool_id = alloy::primitives::FixedBytes([0x90; 32]); - let tokens = [H160([1; 20]), H160([2; 20]), H160([3; 20])]; + let tokens = [ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ]; let asserter = Asserter::new(); let provider = ProviderBuilder::new() .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); asserter.push_success(&pool_id); let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: tokens.iter().copied().map(|t| t.into_alloy()).collect(), + tokens: tokens.to_vec(), balances: vec![], - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -426,15 +421,15 @@ mod tests { token_infos: Arc::new(token_infos), }; let pool_info = pool_info_fetcher - .fetch_common_pool_info(pool.address().into_legacy(), 1337) + .fetch_common_pool_info(*pool.address(), 1337) .await .unwrap(); assert_eq!( pool_info, PoolInfo { - id: pool_id.into_legacy(), - address: pool.address().into_legacy(), + id: pool_id, + address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)], block_created: 1337, @@ -444,8 +439,12 @@ mod tests { #[tokio::test] async fn fetch_common_pool_state() { - let pool_id = H256([0x90; 32]); - let tokens = [H160([1; 20]), H160([2; 20]), H160([3; 20])]; + let pool_id = B256::repeat_byte(0x90); + let tokens = [ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ]; let balances = [bfp!("1000.0"), bfp!("10.0"), bfp!("15.0")]; let scaling_factors = [Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)]; @@ -454,33 +453,30 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &bfp!("0.003").as_uint256().into_alloy(), + &bfp!("0.003").as_uint256(), ); asserter.push_success(&get_swap_fee_percentage_response); let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: tokens.iter().copied().map(|t| t.into_alloy()).collect(), - balances: balances - .iter() - .map(|b| b.as_uint256().into_alloy()) - .collect(), - lastChangeBlock: U256::zero().into_alloy(), + tokens: tokens.to_vec(), + balances: balances.iter().map(|b| b.as_uint256()).collect(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -494,17 +490,15 @@ mod tests { }; let pool_info = PoolInfo { id: pool_id, - address: pool.address().into_legacy(), + address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: scaling_factors.to_vec(), block_created: 1337, }; let pool_state = { - let pool_state = pool_info_fetcher.fetch_common_pool_state( - &pool_info, - BlockId::Number(BlockNumber::Number(1.into())), - ); + let pool_state = + pool_info_fetcher.fetch_common_pool_state(&pool_info, BlockId::Number(1.into())); pool_state.await.unwrap() }; @@ -534,38 +528,42 @@ mod tests { #[tokio::test] async fn fetch_state_errors_on_token_mismatch() { - let tokens = [H160([1; 20]), H160([2; 20]), H160([3; 20])]; + let tokens = [ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ]; let asserter = Asserter::new(); let provider = ProviderBuilder::new() .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &U256::zero().into_alloy(), + &U256::ZERO, ); asserter.push_success(&get_swap_fee_percentage_response); let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: vec![H160([1; 20]).into_alloy(), H160([4; 20]).into_alloy()], - balances: vec![U256::zero().into_alloy(), U256::zero().into_alloy()], - lastChangeBlock: U256::zero().into_alloy(), + tokens: vec![Address::repeat_byte(1), Address::repeat_byte(4)], + balances: vec![U256::ZERO, U256::ZERO], + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -579,17 +577,15 @@ mod tests { }; let pool_info = PoolInfo { id: Default::default(), - address: pool.address().into_legacy(), + address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(0)], block_created: 1337, }; let pool_state = { - let pool_state = pool_info_fetcher.fetch_common_pool_state( - &pool_info, - BlockId::Number(BlockNumber::Number(1.into())), - ); + let pool_state = + pool_info_fetcher.fetch_common_pool_state(&pool_info, BlockId::Number(1.into())); pool_state.await }; @@ -606,29 +602,33 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &swap_fee.as_uint256().into_alloy(), + &swap_fee.as_uint256(), ); asserter.push_success(&get_swap_fee_percentage_response); let pool_info = weighted::PoolInfo { common: PoolInfo { - id: H256([0x90; 32]), - address: pool.address().into_legacy(), - tokens: vec![H160([1; 20]), H160([2; 20]), H160([3; 20])], + id: B256::repeat_byte(0x90), + address: *pool.address(), + tokens: vec![ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)], block_created: 1337, }, @@ -665,25 +665,19 @@ mod tests { let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: pool_info - .common - .tokens - .iter() - .copied() - .map(|t| t.into_alloy()) - .collect(), + tokens: pool_info.common.tokens.clone(), balances: pool_state .tokens .values() - .map(|token| token.common.balance.into_alloy()) + .map(|token| token.common.balance) .collect(), - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); let mut factory = MockFactoryIndexing::new(); - let block_id = BlockId::Number(BlockNumber::Number(1.into())); + let block_id = BlockId::Number(1.into()); factory .expect_fetch_pool_state() .with( @@ -723,22 +717,22 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: true, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &U256::zero().into_alloy(), + &U256::ZERO, ); asserter.push_success(&get_swap_fee_percentage_response); @@ -747,7 +741,7 @@ mod tests { &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { tokens: vec![], balances: vec![], - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -777,7 +771,7 @@ mod tests { let pool_info = weighted::PoolInfo { common: PoolInfo { id: Default::default(), - address: pool.address().into_legacy(), + address: *pool.address(), tokens: Default::default(), scaling_factors: Default::default(), block_created: Default::default(), @@ -787,7 +781,7 @@ mod tests { let pool_status = { pool_info_fetcher - .fetch_pool(&pool_info, BlockId::Number(BlockNumber::Number(1.into()))) + .fetch_pool(&pool_info, BlockId::Number(1.into())) .await .unwrap() }; @@ -802,22 +796,22 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &U256::zero().into_alloy(), + &U256::ZERO, ); asserter.push_success(&get_swap_fee_percentage_response); @@ -826,7 +820,7 @@ mod tests { &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { tokens: vec![], balances: vec![], - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -849,7 +843,7 @@ mod tests { let pool_info = weighted::PoolInfo { common: PoolInfo { id: Default::default(), - address: pool.address().into_legacy(), + address: *pool.address(), tokens: Default::default(), scaling_factors: Default::default(), block_created: Default::default(), @@ -859,7 +853,7 @@ mod tests { let pool_status = { pool_info_fetcher - .fetch_pool(&pool_info, BlockId::Number(BlockNumber::Number(1.into()))) + .fetch_pool(&pool_info, BlockId::Number(1.into())) .await .unwrap() }; @@ -876,15 +870,15 @@ mod tests { let pool_info_fetcher = PoolInfoFetcher { vault: BalancerV2Vault::Instance::new( - H160([0xba; 20]).into_alloy(), - ethrpc::mock::web3().alloy, + Address::repeat_byte(0xba), + ethrpc::mock::web3().provider, ), factory: MockFactoryIndexing::new(), token_infos: Arc::new(token_infos), }; assert!( pool_info_fetcher - .scaling_factors(&[H160([0xff; 20])]) + .scaling_factors(&[Address::repeat_byte(0xff)]) .await .is_err() ); @@ -892,7 +886,7 @@ mod tests { #[tokio::test] async fn scaling_factor_error_on_missing_decimals() { - let token = H160([0xff; 20]); + let token = Address::repeat_byte(0xff); let mut token_infos = MockTokenInfoFetching::new(); token_infos.expect_get_token_infos().returning(move |_| { hashmap! { @@ -902,8 +896,8 @@ mod tests { let pool_info_fetcher = PoolInfoFetcher { vault: BalancerV2Vault::Instance::new( - H160([0xba; 20]).into_alloy(), - ethrpc::mock::web3().alloy, + Address::repeat_byte(0xba), + ethrpc::mock::web3().provider, ), factory: MockFactoryIndexing::new(), token_infos: Arc::new(token_infos), @@ -915,18 +909,18 @@ mod tests { fn convert_graph_pool_to_common_pool_info() { let pool = PoolData { pool_type: PoolType::Stable, - id: H256([4; 32]), - address: H160([3; 20]), - factory: H160([0xfb; 20]), + id: B256::repeat_byte(4), + address: Address::repeat_byte(3), + factory: Address::repeat_byte(0xfb), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: None, }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 18, weight: None, }, @@ -936,9 +930,9 @@ mod tests { assert_eq!( PoolInfo::from_graph_data(&pool, 42).unwrap(), PoolInfo { - id: H256([4; 32]), - address: H160([3; 20]), - tokens: vec![H160([0x33; 20]), H160([0x44; 20])], + id: B256::repeat_byte(4), + address: Address::repeat_byte(3), + tokens: vec![Address::repeat_byte(0x33), Address::repeat_byte(0x44)], scaling_factors: vec![Bfp::exp10(15), Bfp::exp10(0)], block_created: 42, } @@ -949,12 +943,12 @@ mod tests { fn pool_conversion_insufficient_tokens() { let pool = PoolData { pool_type: PoolType::Weighted, - id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0; 20]), + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0), swap_enabled: true, tokens: vec![Token { - address: H160([2; 20]), + address: Address::repeat_byte(2), decimals: 18, weight: Some("1.337".parse().unwrap()), }], @@ -966,18 +960,18 @@ mod tests { fn pool_conversion_invalid_decimals() { let pool = PoolData { pool_type: PoolType::Weighted, - id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0; 20]), + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0), swap_enabled: true, tokens: vec![ Token { - address: H160([2; 20]), + address: Address::repeat_byte(2), decimals: 19, weight: Some("1.337".parse().unwrap()), }, Token { - address: H160([3; 20]), + address: Address::repeat_byte(3), decimals: 18, weight: Some("1.337".parse().unwrap()), }, diff --git a/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs b/crates/liquidity-sources/src/balancer_v2/pools/composable_stable.rs similarity index 83% rename from crates/shared/src/sources/balancer_v2/pools/composable_stable.rs rename to crates/liquidity-sources/src/balancer_v2/pools/composable_stable.rs index 258fbbdb2d..5f5164fa37 100644 --- a/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs +++ b/crates/liquidity-sources/src/balancer_v2/pools/composable_stable.rs @@ -2,14 +2,13 @@ use { super::{FactoryIndexing, PoolIndexing, common}, - crate::sources::balancer_v2::{ + crate::balancer_v2::{ graph_api::{PoolData, PoolType}, swap::fixed_point::Bfp, }, + alloy::eips::BlockId, anyhow::Result, - contracts::alloy::{BalancerV2ComposableStablePool, BalancerV2ComposableStablePoolFactory}, - ethcontract::BlockId, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + contracts::{BalancerV2ComposableStablePool, BalancerV2ComposableStablePoolFactory}, futures::{FutureExt as _, future::BoxFuture}, }; @@ -48,12 +47,12 @@ impl FactoryIndexing for BalancerV2ComposableStablePoolFactory::Instance { block: BlockId, ) -> BoxFuture<'static, Result>> { let pool_contract = BalancerV2ComposableStablePool::Instance::new( - pool_info.common.address.into_alloy(), + pool_info.common.address, self.provider().clone(), ); let fetch_common = common_pool_state.map(Result::Ok); - let scaling_factors_block = block.into_alloy(); + let scaling_factors_block = block; let amp_param_block = scaling_factors_block; let pool_contract_clone = pool_contract.clone(); let fetch_scaling_factors = async move { @@ -81,8 +80,8 @@ impl FactoryIndexing for BalancerV2ComposableStablePoolFactory::Instance { )?; let amplification_parameter = { AmplificationParameter::try_new( - amplification_parameter.value.into_legacy(), - amplification_parameter.precision.into_legacy(), + amplification_parameter.value, + amplification_parameter.precision, )? }; @@ -95,7 +94,7 @@ impl FactoryIndexing for BalancerV2ComposableStablePoolFactory::Instance { ( address, common::TokenState { - scaling_factor: Bfp::from_wei(scaling_factor.into_legacy()), + scaling_factor: Bfp::from_wei(scaling_factor), ..token }, ) @@ -113,26 +112,26 @@ impl FactoryIndexing for BalancerV2ComposableStablePoolFactory::Instance { mod tests { use { super::*, - crate::sources::balancer_v2::graph_api::Token, - ethcontract::{H160, H256}, + crate::balancer_v2::graph_api::Token, + alloy::primitives::{Address, B256}, }; #[test] fn errors_when_converting_wrong_pool_type() { let pool = PoolData { pool_type: PoolType::Stable, - id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: None, }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: None, }, diff --git a/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs b/crates/liquidity-sources/src/balancer_v2/pools/liquidity_bootstrapping.rs similarity index 86% rename from crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs rename to crates/liquidity-sources/src/balancer_v2/pools/liquidity_bootstrapping.rs index 8080ca3138..535cfdfef2 100644 --- a/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs +++ b/crates/liquidity-sources/src/balancer_v2/pools/liquidity_bootstrapping.rs @@ -2,17 +2,16 @@ use { super::{FactoryIndexing, PoolIndexing, common}, - crate::sources::balancer_v2::{ + crate::balancer_v2::{ graph_api::{PoolData, PoolType}, swap::fixed_point::Bfp, }, + alloy::eips::BlockId, anyhow::Result, - contracts::alloy::{ + contracts::{ BalancerV2LiquidityBootstrappingPool, BalancerV2LiquidityBootstrappingPoolFactory, }, - ethcontract::BlockId, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::{FutureExt as _, future::BoxFuture}, }; @@ -55,14 +54,14 @@ impl FactoryIndexing for BalancerV2LiquidityBootstrappingPoolFactory::Instance { block: BlockId, ) -> BoxFuture<'static, Result>> { let pool_contract = BalancerV2LiquidityBootstrappingPool::Instance::new( - pool_info.common.address.into_alloy(), + pool_info.common.address, self.provider().clone(), ); let fetch_common = common_pool_state.map(Result::Ok); // Liquidity bootstrapping pools use dynamic weights, meaning that we // need to fetch them every time. - let weights_block = block.into_alloy(); + let weights_block = block; let swap_block = weights_block; let pool_contract_clone = pool_contract.clone(); let fetch_weights = async move { @@ -98,7 +97,7 @@ impl FactoryIndexing for BalancerV2LiquidityBootstrappingPoolFactory::Instance { address, TokenState { common, - weight: Bfp::from_wei(weight.into_legacy()), + weight: Bfp::from_wei(weight), }, ) }) @@ -119,26 +118,26 @@ impl FactoryIndexing for BalancerV2LiquidityBootstrappingPoolFactory::Instance { mod tests { use { super::*, - crate::sources::balancer_v2::graph_api::Token, - ethcontract::{H160, H256}, + crate::balancer_v2::graph_api::Token, + alloy::primitives::{Address, B256}, }; #[test] fn errors_when_converting_wrong_pool_type() { let pool = PoolData { pool_type: PoolType::Weighted, - id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: None, }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: None, }, diff --git a/crates/shared/src/sources/balancer_v2/pools/mod.rs b/crates/liquidity-sources/src/balancer_v2/pools/mod.rs similarity index 98% rename from crates/shared/src/sources/balancer_v2/pools/mod.rs rename to crates/liquidity-sources/src/balancer_v2/pools/mod.rs index d35749c778..2d3138bd85 100644 --- a/crates/shared/src/sources/balancer_v2/pools/mod.rs +++ b/crates/liquidity-sources/src/balancer_v2/pools/mod.rs @@ -15,8 +15,8 @@ pub mod weighted; use { super::graph_api::PoolData, + alloy::{eips::BlockId, primitives::B256}, anyhow::Result, - ethcontract::{BlockId, H256}, futures::future::BoxFuture, }; @@ -24,7 +24,7 @@ use { #[derive(Clone, Debug, Eq, PartialEq)] pub struct Pool { /// The ID of the pool. - pub id: H256, + pub id: B256, /// The pool-specific kind and state. pub kind: PoolKind, } diff --git a/crates/shared/src/sources/balancer_v2/pools/stable.rs b/crates/liquidity-sources/src/balancer_v2/pools/stable.rs similarity index 75% rename from crates/shared/src/sources/balancer_v2/pools/stable.rs rename to crates/liquidity-sources/src/balancer_v2/pools/stable.rs index b60f8b96df..21ad5dd031 100644 --- a/crates/shared/src/sources/balancer_v2/pools/stable.rs +++ b/crates/liquidity-sources/src/balancer_v2/pools/stable.rs @@ -2,17 +2,16 @@ use { super::{FactoryIndexing, PoolIndexing, common}, - crate::{ - conversions::U256Ext as _, - sources::balancer_v2::{ - graph_api::{PoolData, PoolType}, - swap::fixed_point::Bfp, - }, + crate::balancer_v2::{ + graph_api::{PoolData, PoolType}, + swap::fixed_point::Bfp, + }, + alloy::{ + eips::BlockId, + primitives::{Address, U256}, }, anyhow::{Result, ensure}, - contracts::alloy::{BalancerV2StablePool, BalancerV2StablePoolFactoryV2}, - ethcontract::{BlockId, H160, U256}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + contracts::{BalancerV2StablePool, BalancerV2StablePoolFactoryV2}, futures::{FutureExt as _, future::BoxFuture}, num::BigRational, std::collections::BTreeMap, @@ -37,7 +36,7 @@ impl PoolIndexing for PoolInfo { #[derive(Clone, Debug, Eq, PartialEq)] pub struct PoolState { - pub tokens: BTreeMap, + pub tokens: BTreeMap, pub swap_fee: Bfp, pub amplification_parameter: AmplificationParameter, } @@ -66,7 +65,7 @@ impl AmplificationParameter { // don't allow modifications of `self.precision` such that it could // become 0. debug_assert!(!self.precision.is_zero()); - BigRational::new(self.factor.to_big_int(), self.precision.to_big_int()) + BigRational::new(self.factor.into(), self.precision.into()) } pub fn factor(&self) -> U256 { @@ -93,16 +92,14 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { common_pool_state: BoxFuture<'static, common::PoolState>, block: BlockId, ) -> BoxFuture<'static, Result>> { - let pool_contract = BalancerV2StablePool::Instance::new( - pool_info.common.address.into_alloy(), - self.provider().clone(), - ); + let pool_contract = + BalancerV2StablePool::Instance::new(pool_info.common.address, self.provider().clone()); let fetch_common = common_pool_state.map(Result::Ok); let fetch_amplification_parameter = async move { pool_contract .getAmplificationParameter() - .block(block.into_alloy()) + .block(block) .call() .await .map_err(anyhow::Error::from) @@ -113,8 +110,8 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { futures::try_join!(fetch_common, fetch_amplification_parameter)?; let amplification_parameter = { AmplificationParameter::try_new( - amplification_parameter.value.into_legacy(), - amplification_parameter.precision.into_legacy(), + amplification_parameter.value, + amplification_parameter.precision, )? }; @@ -130,28 +127,24 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { #[cfg(test)] mod tests { - use { - super::*, - crate::sources::balancer_v2::graph_api::Token, - ethcontract::{H160, H256}, - }; + use {super::*, crate::balancer_v2::graph_api::Token, alloy::primitives::B256}; #[test] fn errors_when_converting_wrong_pool_type() { let pool = PoolData { pool_type: PoolType::Weighted, - id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: None, }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: None, }, @@ -164,21 +157,21 @@ mod tests { #[test] fn amplification_parameter_conversions() { assert_eq!( - AmplificationParameter::try_new(2.into(), 3.into()) + AmplificationParameter::try_new(U256::from(2), U256::from(3)) .unwrap() - .with_base(1000.into()) + .with_base(U256::from(1000)) .unwrap(), - 666.into() + U256::from(666) ); assert_eq!( - AmplificationParameter::try_new(7.into(), 8.into()) + AmplificationParameter::try_new(U256::from(7), U256::from(8)) .unwrap() .as_big_rational(), BigRational::new(7.into(), 8.into()) ); assert_eq!( - AmplificationParameter::try_new(1.into(), 0.into()) + AmplificationParameter::try_new(U256::ONE, U256::ZERO) .unwrap_err() .to_string(), "Zero precision not allowed" diff --git a/crates/shared/src/sources/balancer_v2/pools/weighted.rs b/crates/liquidity-sources/src/balancer_v2/pools/weighted.rs similarity index 78% rename from crates/shared/src/sources/balancer_v2/pools/weighted.rs rename to crates/liquidity-sources/src/balancer_v2/pools/weighted.rs index ff1c34f42d..2e654de6a5 100644 --- a/crates/shared/src/sources/balancer_v2/pools/weighted.rs +++ b/crates/liquidity-sources/src/balancer_v2/pools/weighted.rs @@ -2,18 +2,17 @@ use { super::{FactoryIndexing, PoolIndexing, common}, - crate::sources::balancer_v2::{ + crate::balancer_v2::{ graph_api::{PoolData, PoolType}, swap::fixed_point::Bfp, }, + alloy::{eips::BlockId, primitives::Address}, anyhow::{Result, anyhow}, - contracts::alloy::{ + contracts::{ BalancerV2WeightedPool, BalancerV2WeightedPoolFactory, BalancerV2WeightedPoolFactoryV3, }, - ethcontract::{BlockId, H160}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::{FutureExt as _, future::BoxFuture}, std::collections::BTreeMap, }; @@ -26,7 +25,7 @@ pub struct PoolInfo { #[derive(Clone, Debug, Eq, PartialEq)] pub struct PoolState { - pub tokens: BTreeMap, + pub tokens: BTreeMap, pub swap_fee: Bfp, pub version: Version, } @@ -71,16 +70,14 @@ impl FactoryIndexing for BalancerV2WeightedPoolFactory::Instance { type PoolState = PoolState; async fn specialize_pool_info(&self, pool: common::PoolInfo) -> Result { - let pool_contract = BalancerV2WeightedPool::Instance::new( - pool.address.into_alloy(), - self.provider().clone(), - ); + let pool_contract = + BalancerV2WeightedPool::Instance::new(pool.address, self.provider().clone()); let weights = pool_contract .getNormalizedWeights() .call() .await? .into_iter() - .map(|weight| Bfp::from_wei(weight.into_legacy())) + .map(Bfp::from_wei) .collect(); Ok(PoolInfo { @@ -148,14 +145,13 @@ fn pool_state( mod tests { use { super::*, - crate::sources::balancer_v2::graph_api::Token, + crate::{balancer_v2::graph_api::Token, bfp}, alloy::{ - primitives::Address, + primitives::{Address, B256, U256}, providers::{Provider, ProviderBuilder, mock::Asserter}, sol_types::SolCall, }, - ethcontract::{H160, H256}, - ethcontract_mock::Mock, + ethrpc::Web3, futures::future, maplit::btreemap, }; @@ -164,18 +160,18 @@ mod tests { fn convert_graph_pool_to_weighted_pool_info() { let pool = PoolData { pool_type: PoolType::Weighted, - id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: Some(bfp!("1.337")), }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: Some(bfp!("4.2")), }, @@ -186,15 +182,15 @@ mod tests { PoolInfo::from_graph_data(&pool, 42).unwrap(), PoolInfo { common: common::PoolInfo { - id: H256([2; 32]), - address: H160([1; 20]), - tokens: vec![H160([0x11; 20]), H160([0x22; 20])], + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + tokens: vec![Address::repeat_byte(0x11), Address::repeat_byte(0x22)], scaling_factors: vec![Bfp::exp10(17), Bfp::exp10(16)], block_created: 42, }, weights: vec![ - Bfp::from_wei(1_337_000_000_000_000_000u128.into()), - Bfp::from_wei(4_200_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(1_337_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(4_200_000_000_000_000_000_u128)), ], }, ); @@ -204,18 +200,18 @@ mod tests { fn errors_when_converting_wrong_pool_type() { let pool = PoolData { pool_type: PoolType::Stable, - id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + id: B256::repeat_byte(2), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: Some(bfp!("1.337")), }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: Some(bfp!("4.2")), }, @@ -243,16 +239,20 @@ mod tests { let get_normalized_weights_response = BalancerV2WeightedPool::BalancerV2WeightedPool::getNormalizedWeightsCall::abi_encode_returns( &weights.iter() - .map(|w| w.as_uint256().into_alloy()) + .map(|w| w.as_uint256()) .collect() ); asserter.push_success(&get_normalized_weights_response); let pool = factory .specialize_pool_info(common::PoolInfo { - id: H256([0x90; 32]), - tokens: vec![H160([1; 20]), H160([2; 20]), H160([3; 20])], - address: pool.address().into_legacy(), + id: B256::repeat_byte(0x90), + tokens: vec![ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ], + address: *pool.address(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(0)], block_created: 42, }) @@ -265,29 +265,28 @@ mod tests { #[tokio::test] async fn fetch_pool_state() { let tokens = btreemap! { - H160([1; 20]) => common::TokenState { + Address::repeat_byte(1) => common::TokenState { balance: bfp!("1000.0").as_uint256(), scaling_factor: Bfp::exp10(0), }, - H160([2; 20]) => common::TokenState { - balance: 10_000_000.into(), + Address::repeat_byte(2) => common::TokenState { + balance: U256::from(10_000_000), scaling_factor: Bfp::exp10(12), }, }; let weights = [bfp!("0.8"), bfp!("0.2")]; let swap_fee = bfp!("0.003"); - let mock = Mock::new(42); - let web3 = mock.web3(); + let asserter = Asserter::new(); + asserter.push_success(&10); + let web3 = Web3::with_asserter(asserter); - let factory = BalancerV2WeightedPoolFactory::Instance::new( - Address::default(), - ethrpc::mock::web3().alloy, - ); + let factory = + BalancerV2WeightedPoolFactory::Instance::new(Address::default(), web3.provider.clone()); let pool_info = PoolInfo { common: common::PoolInfo { - id: H256([0x90; 32]), - address: H160([0x90; 20]), + id: B256::repeat_byte(0x90), + address: Address::repeat_byte(0x90), tokens: tokens.keys().copied().collect(), scaling_factors: tokens.values().map(|token| token.scaling_factor).collect(), block_created: 1337, @@ -301,7 +300,7 @@ mod tests { }; let pool_state = { - let block = web3.eth().block_number().await.unwrap(); + let block = web3.provider.get_block_number().await.unwrap(); let pool_state = factory.fetch_pool_state( &pool_info, diff --git a/crates/shared/src/sources/balancer_v2/swap/error.rs b/crates/liquidity-sources/src/balancer_v2/swap/error.rs similarity index 100% rename from crates/shared/src/sources/balancer_v2/swap/error.rs rename to crates/liquidity-sources/src/balancer_v2/swap/error.rs diff --git a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs b/crates/liquidity-sources/src/balancer_v2/swap/fixed_point.rs similarity index 82% rename from crates/shared/src/sources/balancer_v2/swap/fixed_point.rs rename to crates/liquidity-sources/src/balancer_v2/swap/fixed_point.rs index 44209a0be4..6687440307 100644 --- a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs +++ b/crates/liquidity-sources/src/balancer_v2/swap/fixed_point.rs @@ -5,8 +5,8 @@ use { super::error::Error, + alloy::primitives::U256, anyhow::{Context, Result, bail, ensure}, - ethcontract::U256, num::{BigInt, BigRational}, number::conversions::{big_int_to_u256, u256_to_big_int}, std::{ @@ -27,13 +27,17 @@ mod logexpmath; /// including error codes, from which the name (Balancer Fixed Point). pub struct Bfp(U256); -static ONE_18: LazyLock = LazyLock::new(|| U256::exp10(18)); +fn exp10(n: u8) -> U256 { + U256::from(10u64).pow(U256::from(n)) +} + +static ONE_18: LazyLock = LazyLock::new(|| exp10(18)); static ONE_18_BIGINT: LazyLock = LazyLock::new(|| u256_to_big_int(&ONE_18)); -static ZERO: LazyLock = LazyLock::new(|| Bfp(U256::zero())); +static ZERO: LazyLock = LazyLock::new(|| Bfp(U256::ZERO)); static ONE: LazyLock = LazyLock::new(|| Bfp(*ONE_18)); -static TWO: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * 2)); -static FOUR: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * 4)); -static MAX_POW_RELATIVE_ERROR: LazyLock = LazyLock::new(|| Bfp(10000_usize.into())); +static TWO: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * U256::from(2u64))); +static FOUR: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * U256::from(4u64))); +static MAX_POW_RELATIVE_ERROR: LazyLock = LazyLock::new(|| Bfp(U256::from(10000u64))); impl From for Bfp { fn from(num: usize) -> Self { @@ -72,9 +76,9 @@ impl FromStr for Bfp { if units.is_empty() || decimals.is_empty() || decimals.len() > 18 { bail!("Invalid decimal representation"); } - Ok(Bfp(U256::from_dec_str(&format!("{decimals:0<18}"))? + Ok(Bfp(U256::from_str_radix(&format!("{decimals:0<18}"), 10)? .checked_add( - U256::from_dec_str(units)? + U256::from_str_radix(units, 10)? .checked_mul(*ONE_18) .context("Too large number")?, ) @@ -88,7 +92,7 @@ impl Debug for Bfp { formatter, "{}.{:0>18}", self.0 / *ONE_18, - (self.0 % *ONE_18).as_u128() + u128::try_from(self.0 % *ONE_18).unwrap() ) } } @@ -96,7 +100,7 @@ impl Debug for Bfp { impl Bfp { #[cfg(test)] pub fn to_f64_lossy(self) -> f64 { - self.as_uint256().to_f64_lossy() / 1e18 + f64::from(self.as_uint256()) / 1e18 } pub fn as_uint256(self) -> U256 { @@ -121,7 +125,7 @@ impl Bfp { return Self::zero(); } - Self(U256::exp10(exp as _)) + Self(U256::from(10).pow(U256::from(exp))) } pub fn from_wei(num: U256) -> Self { @@ -154,7 +158,7 @@ impl Bfp { Ok(if product.is_zero() { Bfp::zero() } else { - Bfp(((product - 1) / *ONE_18) + 1) + Bfp(((product - U256::ONE) / *ONE_18) + U256::ONE) }) } @@ -177,7 +181,7 @@ impl Bfp { } else { let a_inflated = self.0.checked_mul(*ONE_18).ok_or(Error::DivInternal)?; - Ok(Self(((a_inflated - 1) / other.0) + 1)) + Ok(Self(((a_inflated - U256::ONE) / other.0) + U256::ONE)) } } @@ -191,7 +195,7 @@ impl Bfp { pub fn pow_up(self, exp: Self) -> Result { let raw = Bfp(logexpmath::pow(self.0, exp.0)?); - let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(1.into()))?; + let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(U256::ONE))?; raw.add(max_error) } @@ -206,7 +210,7 @@ impl Bfp { square.mul_up(square) } else { let raw = Bfp(logexpmath::pow(self.0, exp.0)?); - let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(1.into()))?; + let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(U256::ONE))?; raw.add(max_error) } @@ -220,22 +224,23 @@ mod tests { num::{BigInt, One, Zero}, }; - static EPSILON: LazyLock = LazyLock::new(|| Bfp(U256::one())); + static EPSILON: LazyLock = LazyLock::new(|| Bfp(U256::ONE)); + + fn test_exp10(n: u8) -> U256 { + U256::from(10u64).pow(U256::from(n)) + } #[test] fn parsing() { assert_eq!("1".parse::().unwrap(), Bfp::one()); - assert_eq!( - "0.1".parse::().unwrap(), - Bfp::from_wei(U256::exp10(17)) - ); + assert_eq!("0.1".parse::().unwrap(), Bfp::from_wei(test_exp10(17))); assert_eq!( "1.01".parse::().unwrap(), - Bfp::from_wei(U256::exp10(18) + U256::exp10(16)) + Bfp::from_wei(test_exp10(18) + test_exp10(16)) ); assert_eq!( "10.000000000000000001".parse::().unwrap(), - Bfp::from_wei(U256::exp10(19) + U256::one()) + Bfp::from_wei(test_exp10(19) + U256::ONE) ); assert!("10.0000000000000000001".parse::().is_err()); assert!("1.0.1".parse::().is_err()); @@ -246,7 +251,7 @@ mod tests { #[test] fn add() { - assert_eq!(Bfp::from(40).add(2.into()).unwrap(), 42.into()); + assert_eq!(Bfp::from(40).add(Bfp::from(2)).unwrap(), Bfp::from(42)); assert_eq!( Bfp(U256::MAX).add(*EPSILON).unwrap_err(), @@ -256,29 +261,27 @@ mod tests { #[test] fn sub() { - assert_eq!(Bfp::from(50).sub(8.into()).unwrap(), 42.into()); + assert_eq!(Bfp::from(50).sub(Bfp::from(8)).unwrap(), Bfp::from(42)); assert_eq!( - Bfp::one().sub(Bfp(*ONE_18 + 1)).unwrap_err(), + Bfp::one().sub(Bfp(*ONE_18 + U256::ONE)).unwrap_err(), Error::SubOverflow ); } macro_rules! test_mul { ($fn_name:ident) => { - assert_eq!(Bfp::from(6).$fn_name(7.into()).unwrap(), 42.into()); + assert_eq!(Bfp::from(6).$fn_name(Bfp::from(7)).unwrap(), Bfp::from(42)); assert_eq!(Bfp::zero().$fn_name(Bfp::one()).unwrap(), Bfp::zero()); assert_eq!(Bfp::one().$fn_name(Bfp::zero()).unwrap(), Bfp::zero()); assert_eq!( - Bfp::one() - .$fn_name(Bfp(U256::MAX / U256::exp10(18))) - .unwrap(), - Bfp(U256::MAX / U256::exp10(18)) + Bfp::one().$fn_name(Bfp(U256::MAX / *ONE_18)).unwrap(), + Bfp(U256::MAX / *ONE_18) ); assert_eq!( Bfp::one() - .$fn_name(Bfp(U256::MAX / U256::exp10(18) + 1)) + .$fn_name(Bfp(U256::MAX / *ONE_18 + U256::ONE)) .unwrap_err(), Error::MulOverflow, ); @@ -290,14 +293,14 @@ mod tests { test_mul!(mul_down); test_mul!(mul_up); - let one_half = Bfp((5 * 10_u128.pow(17)).into()); + let one_half = Bfp(U256::from(5 * 10_u128.pow(17))); assert_eq!(EPSILON.mul_down(one_half).unwrap(), Bfp::zero()); assert_eq!(EPSILON.mul_up(one_half).unwrap(), *EPSILON); // values used in proof: // shared/src/sources/balancer/swap/weighted_math.rs#L28-L33 - let max_in_ratio = Bfp::from_wei(U256::exp10(17).checked_mul(3_u32.into()).unwrap()); - let balance_in = Bfp::from_wei(U256::MAX / (U256::exp10(17) * U256::from(3))); + let max_in_ratio = Bfp::from_wei(test_exp10(17).checked_mul(U256::from(3u64)).unwrap()); + let balance_in = Bfp::from_wei(U256::MAX / (test_exp10(17) * U256::from(3u64))); assert!(balance_in.mul_down(max_in_ratio).is_ok()); assert!( (balance_in.add(Bfp::one())) @@ -309,15 +312,15 @@ mod tests { macro_rules! test_div { ($fn_name:ident) => { - assert_eq!(Bfp::from(42).div_down(7.into()).unwrap(), 6.into()); - assert_eq!(Bfp::zero().div_down(Bfp::one()).unwrap(), 0.into()); + assert_eq!(Bfp::from(42).div_down(Bfp::from(7)).unwrap(), Bfp::from(6)); + assert_eq!(Bfp::zero().div_down(Bfp::one()).unwrap(), Bfp::from(0)); assert_eq!( Bfp::one().$fn_name(Bfp::zero()).unwrap_err(), Error::ZeroDivision ); assert_eq!( - Bfp(U256::MAX / U256::exp10(18) + 1) + Bfp(U256::MAX / *ONE_18 + U256::ONE) .$fn_name(Bfp::one()) .unwrap_err(), Error::DivInternal, @@ -330,25 +333,22 @@ mod tests { test_div!(div_down); test_div!(div_up); - assert_eq!(EPSILON.div_down(2.into()).unwrap(), Bfp::zero()); - assert_eq!(EPSILON.div_up(2.into()).unwrap(), *EPSILON); - assert_eq!(Bfp::zero().div_up(1.into()).unwrap(), Bfp::zero()); + assert_eq!(EPSILON.div_down(Bfp::from(2)).unwrap(), Bfp::zero()); + assert_eq!(EPSILON.div_up(Bfp::from(2)).unwrap(), *EPSILON); + assert_eq!(Bfp::zero().div_up(Bfp::from(1)).unwrap(), Bfp::zero()); } #[test] fn pow_up() { assert_eq!( - Bfp::from(2).pow_up(3.into()).unwrap(), + Bfp::from(2).pow_up(Bfp::from(3)).unwrap(), Bfp(U256::from(8_000_000_000_000_079_990_u128)) ); // powDown: 7999999999999919988 assert_eq!( - Bfp::from(2).pow_up(0.into()).unwrap(), + Bfp::from(2).pow_up(Bfp::from(0)).unwrap(), Bfp(U256::from(1_000_000_000_000_010_001_u128)) ); // powDown: 999999999999989999 - assert_eq!( - Bfp::zero().pow_up(Bfp::one()).unwrap(), - Bfp(U256::from(1_u128)) - ); // powDown: 0 + assert_eq!(Bfp::zero().pow_up(Bfp::one()).unwrap(), Bfp(U256::ONE)); // powDown: 0 assert_eq!( Bfp(U256::MAX).pow_up(Bfp::one()).unwrap_err(), @@ -356,8 +356,9 @@ mod tests { ); // note: the values were chosen to get a large value from `pow` assert_eq!( - Bfp(U256::from_dec_str( - "287200000000000000000000000000000000000000000000000000000000000000000000000" + Bfp(U256::from_str_radix( + "287200000000000000000000000000000000000000000000000000000000000000000000000", + 10 ) .unwrap()) .pow_up(Bfp::one()) @@ -460,7 +461,7 @@ mod tests { ) .unwrap_err() .to_string(), - "the number is too large for the type" + "the value is too large to fit the target type" ); assert_eq!( Bfp::from_str( diff --git a/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs b/crates/liquidity-sources/src/balancer_v2/swap/fixed_point/logexpmath.rs similarity index 82% rename from crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs rename to crates/liquidity-sources/src/balancer_v2/swap/fixed_point/logexpmath.rs index 15375bca70..89f7137cf4 100644 --- a/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs +++ b/crates/liquidity-sources/src/balancer_v2/swap/fixed_point/logexpmath.rs @@ -4,7 +4,7 @@ use { super::super::error::Error, - ethcontract::{I256, U256}, + alloy::primitives::{I256, U256}, std::{convert::TryFrom, sync::LazyLock}, }; @@ -12,27 +12,44 @@ use { /// decimal digits. type Ufixed256x18 = U256; -static ONE_18: LazyLock = LazyLock::new(|| I256::exp10(18)); -static ONE_20: LazyLock = LazyLock::new(|| I256::exp10(20)); -static ONE_36: LazyLock = LazyLock::new(|| I256::exp10(36)); +fn i256_exp10(n: u8) -> I256 { + I256::try_from(U256::from(10u64).pow(U256::from(n))).expect("10^n for n <= 255 fits in I256") +} + +static ONE_18: LazyLock = LazyLock::new(|| i256_exp10(18)); +static ONE_20: LazyLock = LazyLock::new(|| i256_exp10(20)); +static ONE_36: LazyLock = LazyLock::new(|| i256_exp10(36)); static UFIXED256X18_ONE: LazyLock = - LazyLock::new(|| U256::try_from(*ONE_18).unwrap()); -static MAX_NATURAL_EXPONENT: LazyLock = - LazyLock::new(|| ONE_18.checked_mul(I256::from(130_i128)).unwrap()); -static MIN_NATURAL_EXPONENT: LazyLock = - LazyLock::new(|| ONE_18.checked_mul(I256::from(-41_i128)).unwrap()); -static LN_36_LOWER_BOUND: LazyLock = - LazyLock::new(|| ONE_18.checked_sub(I256::exp10(17)).unwrap()); -static LN_36_UPPER_BOUND: LazyLock = - LazyLock::new(|| ONE_18.checked_add(I256::exp10(17)).unwrap()); + LazyLock::new(|| U256::try_from(*ONE_18).expect("ONE_18 is positive and fits in U256")); +static MAX_NATURAL_EXPONENT: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_mul(I256::try_from(130i64).expect("130 fits in I256")) + .expect("ONE_18 * 130 does not overflow") +}); +static MIN_NATURAL_EXPONENT: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_mul(I256::try_from(-41i64).expect("-41 fits in I256")) + .expect("ONE_18 * -41 does not overflow") +}); +static LN_36_LOWER_BOUND: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_sub(i256_exp10(17)) + .expect("ONE_18 - 10^17 does not underflow") +}); +static LN_36_UPPER_BOUND: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_add(i256_exp10(17)) + .expect("ONE_18 + 10^17 does not overflow") +}); static MILD_EXPONENT_BOUND: LazyLock = LazyLock::new(|| { - (U256::one() << 254_u32) - .checked_div(U256::try_from(*ONE_20).unwrap()) - .unwrap() + let shifted: U256 = U256::from(1u64) << 254; + shifted + .checked_div(U256::try_from(*ONE_20).expect("ONE_20 is positive and fits in U256")) + .expect("division by non-zero ONE_20 does not fail") }); fn constant_x_20(i: u32) -> I256 { - match i { + I256::try_from(match i { 2 => 3_200_000_000_000_000_000_000_i128, 3 => 1_600_000_000_000_000_000_000_i128, 4 => 800_000_000_000_000_000_000_i128, @@ -44,19 +61,19 @@ fn constant_x_20(i: u32) -> I256 { 10 => 12_500_000_000_000_000_000_i128, 11 => 6_250_000_000_000_000_000_i128, _ => panic!("Constant not provided"), - } - .into() + }) + .expect("constant x_20 values fit in I256") } fn constant_x_18(i: u32) -> I256 { - match i { + I256::try_from(match i { 0 => 128_000_000_000_000_000_000_i128, 1 => 64_000_000_000_000_000_000_i128, _ => panic!("Constant not provided"), - } - .into() + }) + .expect("constant x_18 values fit in I256") } fn constant_a_20(i: u32) -> I256 { - match i { + I256::try_from(match i { 2 => 7_896_296_018_268_069_516_100_000_000_000_000_i128, 3 => 888_611_052_050_787_263_676_000_000_i128, 4 => 298_095_798_704_172_827_474_000_i128, @@ -68,25 +85,25 @@ fn constant_a_20(i: u32) -> I256 { 10 => 113_314_845_306_682_631_683_i128, 11 => 106_449_445_891_785_942_956_i128, _ => panic!("Constant not provided"), - } - .into() + }) + .expect("constant a_20 values fit in I256") } fn constant_a_18(i: u32) -> I256 { match i { - 0 => { - I256::from_dec_str("38877084059945950922200000000000000000000000000000000000").unwrap() - } - 1 => 6_235_149_080_811_616_882_910_000_000_i128.into(), + 0 => I256::from_dec_str("38877084059945950922200000000000000000000000000000000000") + .expect("constant a_18[0] is a valid decimal string that fits in I256"), + 1 => I256::try_from(6_235_149_080_811_616_882_910_000_000_i128) + .expect("constant a_18[1] fits in I256"), _ => panic!("Constant not provided"), } } pub fn pow(x: Ufixed256x18, y: Ufixed256x18) -> Result { - if y == U256::zero() { + if y.is_zero() { return Ok(*UFIXED256X18_ONE); } - if x == U256::zero() { - return Ok(U256::zero()); + if x.is_zero() { + return Ok(U256::ZERO); } let x_int256 = match I256::try_from(x) { @@ -95,7 +112,7 @@ pub fn pow(x: Ufixed256x18, y: Ufixed256x18) -> Result { }; let y_int256 = if y < *MILD_EXPONENT_BOUND { - I256::try_from(y).unwrap() + I256::try_from(y).expect("y < MILD_EXPONENT_BOUND guarantees it fits in I256") } else { return Err(Error::YOutOfBounds); }; @@ -120,7 +137,7 @@ fn exp(mut x: I256) -> Result { return Err(Error::InvalidExponent); } - if x < I256::zero() { + if x.is_negative() { return Ok((*ONE_18 * *ONE_18) / exp(-x)?); } @@ -132,10 +149,10 @@ fn exp(mut x: I256) -> Result { x -= constant_x_18(1); first_an = constant_a_18(1); } else { - first_an = 1.into(); + first_an = I256::ONE; } - x *= 100.into(); + x *= I256::try_from(100).expect("100 fits in I256"); let mut product = *ONE_20; for i in 2..=9 { @@ -150,11 +167,12 @@ fn exp(mut x: I256) -> Result { series_sum += term; for i in 2..=12 { - term = ((term * x) / *ONE_20) / i.into(); + term = ((term * x) / *ONE_20) / I256::try_from(i).expect("loop index fits in I256"); series_sum += term; } - Ok((((product * series_sum) / *ONE_20) * first_an) / 100.into()) + Ok((((product * series_sum) / *ONE_20) * first_an) + / I256::try_from(100).expect("100 fits in I256")) } fn _ln(mut a: I256) -> I256 { @@ -162,7 +180,7 @@ fn _ln(mut a: I256) -> I256 { return -_ln((*ONE_18 * *ONE_18) / a); } - let mut sum = I256::zero(); + let mut sum = I256::ZERO; for i in 0..=1 { if a >= constant_a_18(i) * *ONE_18 { a /= constant_a_18(i); @@ -170,8 +188,8 @@ fn _ln(mut a: I256) -> I256 { } } - sum *= 100.into(); - a *= 100.into(); + sum *= I256::try_from(100).expect("100 fits in I256"); + a *= I256::try_from(100).expect("100 fits in I256"); for i in 2..=11 { if a >= constant_a_20(i) { @@ -188,12 +206,12 @@ fn _ln(mut a: I256) -> I256 { for i in (3..=11).step_by(2) { num = (num * z_squared) / *ONE_20; - series_sum += num / i.into(); + series_sum += num / I256::try_from(i).expect("loop index fits in I256"); } - series_sum *= 2.into(); + series_sum *= I256::try_from(2).expect("2 fits in I256"); - (sum + series_sum) / 100.into() + (sum + series_sum) / I256::try_from(100).expect("100 fits in I256") } fn _ln_36(mut x: I256) -> I256 { @@ -207,10 +225,10 @@ fn _ln_36(mut x: I256) -> I256 { for i in (3..=15).step_by(2) { num = (num * z_squared) / *ONE_36; - series_sum += num / i.into(); + series_sum += num / I256::try_from(i).expect("loop index fits in I256"); } - series_sum * 2.into() + series_sum * I256::try_from(2).expect("2 fits in I256") } #[cfg(test)] @@ -465,8 +483,8 @@ mod tests { for (i, &o) in input.iter().zip(output.iter()) { assert_eq!( pow( - U256::from_dec_str(i[0]).unwrap(), - U256::from_dec_str(i[1]).unwrap() + U256::from_str_radix(i[0], 10).unwrap(), + U256::from_str_radix(i[1], 10).unwrap() ) .unwrap_err(), o.into() @@ -513,11 +531,11 @@ mod tests { for (i, &o) in input.iter().zip(output.iter()) { assert_eq!( pow( - U256::from_dec_str(i[0]).unwrap(), - U256::from_dec_str(i[1]).unwrap() + U256::from_str_radix(i[0], 10).unwrap(), + U256::from_str_radix(i[1], 10).unwrap() ) .unwrap(), - U256::from_dec_str(o).unwrap() + U256::from_str_radix(o, 10).unwrap() ); } } @@ -548,20 +566,13 @@ mod tests { #[test] fn pow_alternate_routes() { + assert_eq!(pow(U256::ZERO, U256::ZERO), Ok(*UFIXED256X18_ONE)); + assert_eq!(pow(U256::ZERO, U256::ONE), Ok(U256::ZERO)); + assert_eq!(pow(U256::ZERO, U256::ZERO), Ok(*UFIXED256X18_ONE)); + assert_eq!(pow(U256::ZERO, U256::ONE), Ok(U256::ZERO)); assert_eq!( - pow( - U256::from_dec_str("0").unwrap(), - U256::from_dec_str("0").unwrap() - ), + pow(U256::from(10u64).pow(U256::from(18u64)), U256::ONE), Ok(*UFIXED256X18_ONE) ); - assert_eq!( - pow( - U256::from_dec_str("0").unwrap(), - U256::from_dec_str("1").unwrap() - ), - Ok(U256::zero()) - ); - assert_eq!(pow(U256::exp10(18), U256::one()), Ok(*UFIXED256X18_ONE)); } } diff --git a/crates/shared/src/sources/balancer_v2/swap/math.rs b/crates/liquidity-sources/src/balancer_v2/swap/math.rs similarity index 87% rename from crates/shared/src/sources/balancer_v2/swap/math.rs rename to crates/liquidity-sources/src/balancer_v2/swap/math.rs index 5c8ee800d9..589bc16250 100644 --- a/crates/shared/src/sources/balancer_v2/swap/math.rs +++ b/crates/liquidity-sources/src/balancer_v2/swap/math.rs @@ -1,4 +1,4 @@ -use {super::error::Error, ethcontract::U256}; +use {super::error::Error, alloy::primitives::U256}; pub trait BalU256: Sized { fn bmul(self, other: Self) -> Result; @@ -33,9 +33,9 @@ impl BalU256 for U256 { return Err(Error::ZeroDivision); } if self.is_zero() { - return Ok(U256::zero()); + return Ok(U256::ZERO); } - let one = U256::one(); + let one = U256::ONE; Ok(one + (self - one) / other) } } @@ -46,8 +46,8 @@ mod tests { #[test] fn bmul_tests() { - let zero = U256::zero(); - let one = U256::one(); + let zero = U256::ZERO; + let one = U256::ONE; let max = U256::MAX; assert_eq!(zero.bmul(one).unwrap(), zero); assert_eq!(one.bmul(one).unwrap(), one); @@ -60,8 +60,8 @@ mod tests { #[test] fn badd_tests() { - let zero = U256::zero(); - let one = U256::one(); + let zero = U256::ZERO; + let one = U256::ONE; let two = U256::from(2); let max = U256::MAX; assert_eq!(zero.badd(one).unwrap(), one); @@ -75,8 +75,8 @@ mod tests { #[test] fn bsub_tests() { - let zero = U256::zero(); - let one = U256::one(); + let zero = U256::ZERO; + let one = U256::ONE; let two = U256::from(2); assert_eq!(two.bsub(zero).unwrap(), two); assert_eq!(two.bsub(one).unwrap(), one); @@ -89,8 +89,8 @@ mod tests { #[test] fn div_down_tests() { - let zero = U256::zero(); - let one = U256::one(); + let zero = U256::ZERO; + let one = U256::ONE; let two = U256::from(2); assert_eq!(zero.bdiv_down(one).unwrap(), zero); assert_eq!(two.bdiv_down(one).unwrap(), two); @@ -104,8 +104,8 @@ mod tests { #[test] fn div_up_tests() { - let zero = U256::zero(); - let one = U256::one(); + let zero = U256::ZERO; + let one = U256::ONE; let two = U256::from(2); assert_eq!(zero.bdiv_up(one).unwrap(), zero); assert_eq!(two.bdiv_up(one).unwrap(), two); diff --git a/crates/shared/src/sources/balancer_v2/swap/mod.rs b/crates/liquidity-sources/src/balancer_v2/swap/mod.rs similarity index 78% rename from crates/shared/src/sources/balancer_v2/swap/mod.rs rename to crates/liquidity-sources/src/balancer_v2/swap/mod.rs index a5db8727b0..8d5f107892 100644 --- a/crates/shared/src/sources/balancer_v2/swap/mod.rs +++ b/crates/liquidity-sources/src/balancer_v2/swap/mod.rs @@ -1,8 +1,6 @@ use { crate::{ - baseline_solver::BaselineSolvable, - conversions::U256Ext, - sources::balancer_v2::pool_fetching::{ + balancer_v2::pool_fetching::{ AmplificationParameter, StablePool, TokenState, @@ -10,10 +8,12 @@ use { WeightedPoolVersion, WeightedTokenState, }, + baseline_solvable::BaselineSolvable, }, + alloy::primitives::{Address, U256}, error::Error, - ethcontract::{H160, U256}, fixed_point::Bfp, + number::u256_ext::U256Ext, std::collections::BTreeMap, }; @@ -73,7 +73,7 @@ impl TokenState { /// amounts. #[derive(Debug)] pub struct WeightedPoolRef<'a> { - pub reserves: &'a BTreeMap, + pub reserves: &'a BTreeMap, pub swap_fee: Bfp, pub version: WeightedPoolVersion, } @@ -81,9 +81,9 @@ pub struct WeightedPoolRef<'a> { impl WeightedPoolRef<'_> { fn get_amount_out_inner( &self, - out_token: H160, + out_token: Address, in_amount: U256, - in_token: H160, + in_token: Address, ) -> Option { // Note that the output of this function does not depend on the pool // specialization. All contract branches compute this amount with: @@ -112,17 +112,17 @@ impl WeightedPoolRef<'_> { impl BaselineSolvable for WeightedPoolRef<'_> { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), - ) -> Option { + out_token: Address, + (in_amount, in_token): (alloy::primitives::U256, Address), + ) -> Option { self.get_amount_out_inner(out_token, in_amount, in_token) } async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), - ) -> Option { + in_token: Address, + (out_amount, out_token): (alloy::primitives::U256, Address), + ) -> Option { // Note that the output of this function does not depend on the pool // specialization. All contract branches compute this amount with: // https://github.com/balancer-labs/balancer-v2-monorepo/blob/6c9e24e22d0c46cca6dd15861d3d33da61a60b98/pkg/core/contracts/pools/BaseMinimalSwapInfoPool.sol#L75-L88 @@ -157,8 +157,8 @@ impl BaselineSolvable for WeightedPoolRef<'_> { /// Stable pool data as a reference used for computing input and output amounts. #[derive(Debug)] pub struct StablePoolRef<'a> { - pub address: H160, - pub reserves: &'a BTreeMap, + pub address: Address, + pub reserves: &'a BTreeMap, pub swap_fee: Bfp, pub amplification_parameter: AmplificationParameter, } @@ -180,7 +180,9 @@ impl<'a> StablePoolRef<'a> { /// swaps. /// /// - pub fn reserves_without_bpt(&self) -> impl Iterator + 'a + use<'a> { + pub fn reserves_without_bpt( + &self, + ) -> impl Iterator + 'a + use<'a> { let bpt = self.address; self.reserves .iter() @@ -190,8 +192,8 @@ impl<'a> StablePoolRef<'a> { fn upscale_balances_with_token_indices( &self, - in_token: &H160, - out_token: &H160, + in_token: &Address, + out_token: &Address, ) -> Result { let mut balances = vec![]; let (mut token_index_in, mut token_index_out) = (0, 0); @@ -221,8 +223,8 @@ impl<'a> StablePoolRef<'a> { /// https://etherscan.io/address/0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F#code#F2#L270 fn regular_swap_given_in( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { let in_reserves = self.reserves.get(&in_token)?; let out_reserves = self.reserves.get(&out_token)?; @@ -249,8 +251,8 @@ impl<'a> StablePoolRef<'a> { /// https://etherscan.io/address/0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F#code#F2#L270 fn regular_swap_given_out( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { let in_reserves = self.reserves.get(&in_token)?; let out_reserves = self.reserves.get(&out_token)?; @@ -275,7 +277,7 @@ impl<'a> StablePoolRef<'a> { /// Comes from `_swapWithBpt`: // https://etherscan.io/address/0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F#code#F2#L301 - fn swap_with_bpt(&self) -> Option { + fn swap_with_bpt(&self) -> Option { // TODO: We currently do not implement swapping with BPT for composable // stable pools. None @@ -285,10 +287,10 @@ impl<'a> StablePoolRef<'a> { impl StablePoolRef<'_> { fn get_amount_out_inner( &self, - out_token: H160, - in_amount: U256, - in_token: H160, - ) -> Option { + out_token: Address, + in_amount: alloy::primitives::U256, + in_token: Address, + ) -> Option { if in_token == self.address || out_token == self.address { self.swap_with_bpt() } else { @@ -300,17 +302,17 @@ impl StablePoolRef<'_> { impl BaselineSolvable for StablePoolRef<'_> { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), - ) -> Option { + out_token: Address, + (in_amount, in_token): (alloy::primitives::U256, Address), + ) -> Option { self.get_amount_out_inner(out_token, in_amount, in_token) } async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), - ) -> Option { + in_token: Address, + (out_amount, out_token): (alloy::primitives::U256, Address), + ) -> Option { if in_token == self.address || out_token == self.address { self.swap_with_bpt() } else { @@ -345,8 +347,8 @@ fn converge_in_amount( // trading price and multiply the amount to bump by 10 for each iteration. let mut bump = (exact_out_amount - out_amount) .checked_mul(in_amount)? - .ceil_div(&out_amount.max(U256::one())) - .max(U256::one()); + .ceil_div(&out_amount.max(U256::ONE)) + .max(U256::ONE); for _ in 0..6 { let bumped_in_amount = in_amount.checked_add(bump)?; @@ -355,7 +357,7 @@ fn converge_in_amount( return Some(bumped_in_amount); } - bump *= 10; + bump *= U256::from(10); } None @@ -372,11 +374,19 @@ impl WeightedPool { } impl BaselineSolvable for WeightedPool { - async fn get_amount_out(&self, out_token: H160, input: (U256, H160)) -> Option { + async fn get_amount_out( + &self, + out_token: Address, + input: (alloy::primitives::U256, Address), + ) -> Option { self.as_pool_ref().get_amount_out(out_token, input).await } - async fn get_amount_in(&self, in_token: H160, output: (U256, H160)) -> Option { + async fn get_amount_in( + &self, + in_token: Address, + output: (alloy::primitives::U256, Address), + ) -> Option { self.as_pool_ref().get_amount_in(in_token, output).await } @@ -396,17 +406,25 @@ impl StablePool { } /// See [`StablePoolRef::reserves_without_bpt`]. - pub fn reserves_without_bpt(&self) -> impl Iterator + '_ { + pub fn reserves_without_bpt(&self) -> impl Iterator + '_ { self.as_pool_ref().reserves_without_bpt() } } impl BaselineSolvable for StablePool { - async fn get_amount_out(&self, out_token: H160, input: (U256, H160)) -> Option { + async fn get_amount_out( + &self, + out_token: Address, + input: (alloy::primitives::U256, Address), + ) -> Option { self.as_pool_ref().get_amount_out(out_token, input).await } - async fn get_amount_in(&self, in_token: H160, output: (U256, H160)) -> Option { + async fn get_amount_in( + &self, + in_token: Address, + output: (alloy::primitives::U256, Address), + ) -> Option { self.as_pool_ref().get_amount_in(in_token, output).await } @@ -419,11 +437,15 @@ impl BaselineSolvable for StablePool { mod tests { use { super::*, - crate::sources::balancer_v2::pool_fetching::{AmplificationParameter, CommonPoolState}, + crate::{ + balancer_v2::pool_fetching::{AmplificationParameter, CommonPoolState}, + bfp, + }, + alloy::primitives::Address, }; fn create_weighted_pool_with( - tokens: Vec, + tokens: Vec
, balances: Vec, weights: Vec, scaling_factors: Vec, @@ -447,7 +469,7 @@ mod tests { WeightedPool { common: CommonPoolState { id: Default::default(), - address: H160::zero(), + address: Address::ZERO, swap_fee: Bfp::from_wei(swap_fee), paused: true, }, @@ -457,7 +479,7 @@ mod tests { } fn create_stable_pool_with( - tokens: Vec, + tokens: Vec
, balances: Vec, amplification_parameter: AmplificationParameter, scaling_factors: Vec, @@ -477,7 +499,7 @@ mod tests { StablePool { common: CommonPoolState { id: Default::default(), - address: H160::zero(), + address: Address::ZERO, swap_fee: Bfp::from_wei(swap_fee), paused: true, }, @@ -492,7 +514,7 @@ mod tests { balance: Default::default(), scaling_factor: Bfp::exp10(12), }; - let input = Bfp::from_wei(900_546_079_866_630_330_575_i128.into()); + let input = Bfp::from_wei(U256::from(900_546_079_866_630_330_575_u128)); assert_eq!( token_state.downscale_up(input).unwrap(), U256::from(900_546_080_u128) @@ -507,24 +529,30 @@ mod tests { async fn weighted_get_amount_out() { // Values obtained from this transaction: // https://dashboard.tenderly.co/tx/main/0xa9f571c9bfd4289bd4bd270465d73e1b7e010622ed089d54d81ec63a0365ec22/debugger - let crv = H160::repeat_byte(21); - let sdvecrv_dao = H160::repeat_byte(42); + let crv = Address::repeat_byte(21); + let sdvecrv_dao = Address::repeat_byte(42); let b = create_weighted_pool_with( vec![crv, sdvecrv_dao], vec![ - 1_850_304_144_768_426_873_445_489_i128.into(), - 95_671_347_892_391_047_965_654_i128.into(), + U256::from(1_850_304_144_768_426_873_445_489_u128), + U256::from(95_671_347_892_391_047_965_654_u128), ], vec![bfp!("0.9"), bfp!("0.1")], vec![Bfp::exp10(0), Bfp::exp10(0)], - 2_000_000_000_000_000_i128.into(), + U256::from(2_000_000_000_000_000_u128), ); assert_eq!( - b.get_amount_out(crv, (227_937_106_828_652_254_870_i128.into(), sdvecrv_dao)) - .await - .unwrap(), - 488_192_591_864_344_551_330_i128.into() + b.get_amount_out( + crv, + ( + alloy::primitives::U256::from(227_937_106_828_652_254_870_u128), + sdvecrv_dao + ) + ) + .await + .unwrap(), + alloy::primitives::U256::from(488_192_591_864_344_551_330_u128) ); } @@ -532,34 +560,37 @@ mod tests { async fn weighted_get_amount_in() { // Values obtained from this transaction: // https://dashboard.tenderly.co/tx/main/0xafc3dd6a636a85d9c1976dfa5aee33f78e6ee902f285c9d4cf80a0014aa2a052/debugger - let weth = H160::repeat_byte(21); - let tusd = H160::repeat_byte(42); + let weth = Address::repeat_byte(21); + let tusd = Address::repeat_byte(42); let b = create_weighted_pool_with( vec![weth, tusd], - vec![60_000_000_000_000_000_i128.into(), 250_000_000_i128.into()], + vec![ + U256::from(60_000_000_000_000_000_u128), + U256::from(250_000_000_u128), + ], vec![bfp!("0.5"), bfp!("0.5")], vec![Bfp::exp10(0), Bfp::exp10(12)], - 1_000_000_000_000_000_i128.into(), + U256::from(1_000_000_000_000_000_u128), ); assert_eq!( - b.get_amount_in(weth, (5_000_000_i128.into(), tusd)) + b.get_amount_in(weth, (alloy::primitives::U256::from(5_000_000_u128), tusd)) .await .unwrap(), - 1_225_715_511_430_411_i128.into() + alloy::primitives::U256::from(1_225_715_511_430_411_u128) ); } #[test] fn construct_balances_and_token_indices() { - let tokens: Vec<_> = (1..=3).map(H160::from_low_u64_be).collect(); - let balances = (1..=3).map(|n| n.into()).collect(); + let tokens: Vec<_> = (1..=3).map(Address::with_last_byte).collect(); + let balances = (1..=3).map(U256::from).collect(); let pool = create_stable_pool_with( tokens.clone(), balances, - AmplificationParameter::try_new(1.into(), 1.into()).unwrap(), + AmplificationParameter::try_new(U256::ONE, U256::ONE).unwrap(), vec![Bfp::exp10(18), Bfp::exp10(18), Bfp::exp10(18)], - 1.into(), + U256::ONE, ); for token_i in tokens.iter() { @@ -593,19 +624,19 @@ mod tests { // Test based on actual swap. // https://dashboard.tenderly.co/tx/main/0x75be93fff064ad46b423b9e20cee09b0ae7f741087f43e4187d4f4cf59f54229/debugger // Token addresses are irrelevant for computation. - let dai = H160::from_low_u64_be(1); - let usdc = H160::from_low_u64_be(2); - let tusd = H160::from_low_u64_be(3); + let dai = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); + let tusd = Address::with_last_byte(3); let tokens = vec![dai, usdc, tusd]; let scaling_exps = vec![Bfp::exp10(0), Bfp::exp10(12), Bfp::exp10(12)]; let amplification_parameter = - AmplificationParameter::try_new(570000.into(), 1000.into()).unwrap(); + AmplificationParameter::try_new(U256::from(570000), U256::from(1000)).unwrap(); let balances = vec![ - 40_927_687_702_846_622_465_144_342_i128.into(), - 59_448_574_675_062_i128.into(), - 55_199_308_926_456_i128.into(), + U256::from(40_927_687_702_846_622_465_144_342_u128), + U256::from(59_448_574_675_062_u128), + U256::from(55_199_308_926_456_u128), ]; - let swap_fee_percentage = 300_000_000_000_000u128.into(); + let swap_fee_percentage = U256::from(300_000_000_000_000_u128); let pool = create_stable_pool_with( tokens, balances, @@ -615,10 +646,10 @@ mod tests { ); // Etherscan for amount verification: // https://etherscan.io/tx/0x75be93fff064ad46b423b9e20cee09b0ae7f741087f43e4187d4f4cf59f54229 - let amount_in = 1_886_982_823_746_269_817_650_i128.into(); - let amount_out = 1_887_770_905_i128; + let amount_in = alloy::primitives::U256::from(1_886_982_823_746_269_817_650_u128); + let amount_out = U256::from(1_887_770_905_u128); let res_out = pool.get_amount_out(usdc, (amount_in, dai)).await; - assert_eq!(res_out.unwrap(), amount_out.into()); + assert_eq!(res_out.unwrap(), amount_out); } #[tokio::test] @@ -626,19 +657,19 @@ mod tests { // Test based on actual swap. // https://dashboard.tenderly.co/tx/main/0x38487122158eef6b63570b5d3754ddc223c63af5c049d7b80acacb9e8ca89a63/debugger // Token addresses are irrelevant for computation. - let dai = H160::from_low_u64_be(1); - let usdc = H160::from_low_u64_be(2); - let tusd = H160::from_low_u64_be(3); + let dai = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); + let tusd = Address::with_last_byte(3); let tokens = vec![dai, usdc, tusd]; let scaling_exps = vec![Bfp::exp10(0), Bfp::exp10(12), Bfp::exp10(12)]; let amplification_parameter = - AmplificationParameter::try_new(570000.into(), 1000.into()).unwrap(); + AmplificationParameter::try_new(U256::from(570000), U256::from(1000)).unwrap(); let balances = vec![ - 34_869_494_603_218_073_631_628_580_i128.into(), - 48_176_005_970_419_i128.into(), - 44_564_350_355_030_i128.into(), + U256::from(34_869_494_603_218_073_631_628_580_u128), + U256::from(48_176_005_970_419_u128), + U256::from(44_564_350_355_030_u128), ]; - let swap_fee_percentage = 300_000_000_000_000u128.into(); + let swap_fee_percentage = U256::from(300_000_000_000_000_u128); let pool = create_stable_pool_with( tokens, balances, @@ -648,9 +679,9 @@ mod tests { ); // Etherscan for amount verification: // https://etherscan.io/tx/0x38487122158eef6b63570b5d3754ddc223c63af5c049d7b80acacb9e8ca89a63 - let amount_in = 900_816_325_i128; - let amount_out = 900_000_000_000_000_000_000_u128.into(); + let amount_in = U256::from(900_816_325_u128); + let amount_out = alloy::primitives::U256::from(900_000_000_000_000_000_000_u128); let res_out = pool.get_amount_in(usdc, (amount_out, dai)).await; - assert_eq!(res_out.unwrap(), amount_in.into()); + assert_eq!(res_out.unwrap(), amount_in); } } diff --git a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs b/crates/liquidity-sources/src/balancer_v2/swap/stable_math.rs similarity index 92% rename from crates/shared/src/sources/balancer_v2/swap/stable_math.rs rename to crates/liquidity-sources/src/balancer_v2/swap/stable_math.rs index f1860b0459..3d18199851 100644 --- a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs +++ b/crates/liquidity-sources/src/balancer_v2/swap/stable_math.rs @@ -4,16 +4,16 @@ use { super::error::Error, - crate::sources::balancer_v2::swap::{fixed_point::Bfp, math::BalU256}, - ethcontract::U256, + crate::balancer_v2::swap::{fixed_point::Bfp, math::BalU256}, + alloy::primitives::U256, std::sync::LazyLock, }; -pub static AMP_PRECISION: LazyLock = LazyLock::new(|| U256::from(1000)); +pub static AMP_PRECISION: LazyLock = LazyLock::new(|| U256::from(1000u64)); /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/9eb7e44a4e9ebbadfe3c6242a086118298cadc9f/pkg/pool-stable-phantom/contracts/StableMath.sol#L57-L119 fn calculate_invariant(amplification_parameter: U256, balances: &[Bfp]) -> Result { - let mut sum = U256::zero(); + let mut sum = U256::ZERO; let num_tokens_usize = balances.len(); for balance_i in balances.iter() { sum = sum.badd(balance_i.as_uint256())?; @@ -48,7 +48,7 @@ fn calculate_invariant(amplification_parameter: U256, balances: &[Bfp]) -> Resul .bsub(*AMP_PRECISION)? .bmul(invariant)? .bdiv_down(*AMP_PRECISION)? - .badd(num_tokens.badd(1.into())?.bmul(d_p)?)?; + .badd(num_tokens.badd(U256::ONE)?.bmul(d_p)?)?; invariant = numerator.bdiv_down(denominator)?; match convergence_criteria(invariant, prev_invariant) { None => continue, @@ -89,7 +89,7 @@ pub fn calc_out_given_in( balances[token_index_out] .sub(final_balance_out)? - .sub(Bfp::from_wei(1.into())) + .sub(Bfp::from_wei(U256::ONE)) } /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/ad1442113b26ec22081c2047e2ec95355a7f12ba/pkg/pool-stable/contracts/StableMath.sol#L152-L190 @@ -124,7 +124,7 @@ pub fn calc_in_given_out( final_balance_in .sub(balances[token_index_in])? - .add(Bfp::from_wei(1.into())) + .add(Bfp::from_wei(U256::ONE)) } /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/ad1442113b26ec22081c2047e2ec95355a7f12ba/pkg/pool-stable/contracts/StableMath.sol#L465-L516 @@ -177,10 +177,12 @@ fn get_token_balance_given_invariant_and_all_other_balances( // Math.mul(tokenBalance, tokenBalance).add(c), // Math.mul(tokenBalance, 2).add(b).sub(invariant) // ); - token_balance = token_balance - .bmul(token_balance)? - .badd(c)? - .bdiv_up(token_balance.bmul(2.into())?.badd(b)?.bsub(invariant)?)?; + token_balance = token_balance.bmul(token_balance)?.badd(c)?.bdiv_up( + token_balance + .bmul(U256::from(2))? + .badd(b)? + .bsub(invariant)?, + )?; match convergence_criteria(token_balance, prev_token_balance) { None => continue, Some(token_balance) => return Ok(Bfp::from_wei(token_balance)), @@ -190,7 +192,7 @@ fn get_token_balance_given_invariant_and_all_other_balances( } fn convergence_criteria(curr_value: U256, prev_value: U256) -> Option { - let one = U256::one(); + let one = U256::ONE; if curr_value > prev_value { if curr_value .bsub(prev_value) @@ -219,12 +221,7 @@ fn convergence_criteria(curr_value: U256, prev_value: U256) -> Option { /// Cross-reference to the TS code: https://github.com/balancer-labs/balancer-v2-monorepo/blob/stable-deployment/pvt/helpers/src/models/pools/stable/math.ts #[cfg(test)] mod tests { - use { - super::*, - crate::sources::balancer_v2::swap::fixed_point::Bfp, - ethcontract::U256, - std::str::FromStr, - }; + use {super::*, crate::balancer_v2::swap::fixed_point::Bfp, std::str::FromStr}; // interpreted from // https://github.com/balancer-labs/balancer-v2-monorepo/blob/stable-deployment/pvt/helpers/src/models/pools/stable/math.ts#L53 @@ -341,7 +338,7 @@ mod tests { #[test] fn invariant_two_tokens_ok() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12)]; let max_relative_error = 0.001; let expected = calculate_analytic_invariant_two_tokens( @@ -351,7 +348,7 @@ mod tests { ); let result = calculate_invariant(amplification_parameter, &balances).unwrap(); assert!( - (result.to_f64_lossy() / 1e18 - expected) + (f64::from(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -364,13 +361,13 @@ mod tests { .iter() .map(|x| Bfp::from_str(x).unwrap()) .collect(); - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let result = calculate_invariant(amplification_parameter, balances.as_slice()).unwrap(); let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); let max_relative_error = 0.001; assert!( - (result.to_f64_lossy() / 1e18 - expected) + (f64::from(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -379,14 +376,14 @@ mod tests { #[test] fn invariant_three_tokens_ok() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); let max_relative_error = 0.001; let result = calculate_invariant(amplification_parameter, &balances).unwrap(); assert!( - (result.to_f64_lossy() / 1e18 - expected) + (f64::from(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -395,7 +392,7 @@ mod tests { #[test] fn in_given_out_two_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -427,7 +424,7 @@ mod tests { #[test] fn in_given_out_three_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -459,7 +456,7 @@ mod tests { #[test] fn out_given_in_two_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -491,7 +488,7 @@ mod tests { #[test] fn out_given_in_three_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; diff --git a/crates/shared/src/sources/balancer_v2/swap/weighted_math.rs b/crates/liquidity-sources/src/balancer_v2/swap/weighted_math.rs similarity index 80% rename from crates/shared/src/sources/balancer_v2/swap/weighted_math.rs rename to crates/liquidity-sources/src/balancer_v2/swap/weighted_math.rs index f978eab496..58aab4d830 100644 --- a/crates/shared/src/sources/balancer_v2/swap/weighted_math.rs +++ b/crates/liquidity-sources/src/balancer_v2/swap/weighted_math.rs @@ -4,15 +4,19 @@ use { super::{error::Error, fixed_point::Bfp}, - ethcontract::U256, + alloy::primitives::U256, std::sync::LazyLock, }; +fn exp10(n: u8) -> U256 { + U256::from(10u64).pow(U256::from(n)) +} + // https://github.com/balancer-labs/balancer-v2-monorepo/blob/6c9e24e22d0c46cca6dd15861d3d33da61a60b98/pkg/core/contracts/pools/weighted/WeightedMath.sol#L36-L37 static MAX_IN_RATIO: LazyLock = - LazyLock::new(|| Bfp::from_wei(U256::exp10(17).checked_mul(3_u32.into()).unwrap())); + LazyLock::new(|| Bfp::from_wei(exp10(17).checked_mul(U256::from(3u64)).unwrap())); static MAX_OUT_RATIO: LazyLock = - LazyLock::new(|| Bfp::from_wei(U256::exp10(17).checked_mul(3_u32.into()).unwrap())); + LazyLock::new(|| Bfp::from_wei(exp10(17).checked_mul(U256::from(3u64)).unwrap())); /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/6c9e24e22d0c46cca6dd15861d3d33da61a60b98/pkg/core/contracts/pools/weighted/WeightedMath.sol#L69-L100 /// It is not possible for the following addition balance_in.add(amount_in) to @@ -143,17 +147,17 @@ mod tests { fn calc_out_given_in_ok() { assert_eq!( calc_out_given_in( - Bfp::from_wei(100_000_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(300_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(700_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_u128.into()), + Bfp::from_wei(U256::from(100_000_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(300_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(700_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_u128)), ) .unwrap(), // (await weightedMath["_calcOutGivenIn"]("100000000000000000000000", // "300000000000000", "10000000000000000000", "700000000000000", // "10000000000000000")).toString() - Bfp::from_wei(428_571_297_950_u128.into()), + Bfp::from_wei(U256::from(428_571_297_950_u128)), ); } @@ -161,28 +165,28 @@ mod tests { fn calc_in_given_out_ok() { assert_eq!( calc_in_given_out( - Bfp::from_wei(100_000_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(300_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(700_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_u128.into()), + Bfp::from_wei(U256::from(100_000_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(300_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(700_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_u128)), ) .unwrap(), // (await weightedMath["_calcInGivenOut"]("100000000000000000000000", // "300000000000000", "10000000000000000000", "700000000000000", // "10000000000000000")).toString() - Bfp::from_wei(233_722_784_701_541_000_000_u128.into()), + Bfp::from_wei(U256::from(233_722_784_701_541_000_000_u128)), ); } #[test] fn calc_out_given_in_err() { - let zero = Bfp::from_wei(0.into()); - let one = Bfp::from_wei(1.into()); - let two = Bfp::from_wei(2.into()); + let zero = Bfp::from_wei(U256::ZERO); + let one = Bfp::from_wei(U256::ONE); + let two = Bfp::from_wei(U256::from(2)); let max_u256 = Bfp::from_wei(U256::MAX); - let max_balance_in = Bfp::from_wei(U256::MAX / (U256::exp10(17) * U256::from(3))); - let mid_u256 = Bfp::from_wei(u128::MAX.into()); + let max_balance_in = Bfp::from_wei(U256::MAX / (exp10(17) * U256::from(3))); + let mid_u256 = Bfp::from_wei(U256::from(u128::MAX)); assert_eq!( calc_out_given_in(max_u256, zero, zero, zero, two) .unwrap_err() @@ -234,12 +238,12 @@ mod tests { #[test] fn calc_in_given_out_err() { - let zero = Bfp::from_wei(0.into()); - let one = Bfp::from_wei(1.into()); - let two = Bfp::from_wei(2.into()); + let zero = Bfp::from_wei(U256::ZERO); + let one = Bfp::from_wei(U256::ONE); + let two = Bfp::from_wei(U256::from(2)); let max_u256 = Bfp::from_wei(U256::MAX); - let max_balance = Bfp::from_wei(U256::MAX / (U256::exp10(17) * U256::from(3))); - let mid_u256 = Bfp::from_wei(u128::MAX.into()); + let max_balance = Bfp::from_wei(U256::MAX / (exp10(17) * U256::from(3))); + let mid_u256 = Bfp::from_wei(U256::from(u128::MAX)); assert_eq!( calc_in_given_out(one, zero, max_u256, zero, two) .unwrap_err() @@ -299,10 +303,10 @@ mod tests { macro_rules! calc_with_default_pool { ($fn_name:ident, $amount: expr_2021) => { $fn_name( - Bfp::from_wei(deposit_in.into()), - Bfp::from_wei(500_000_000_000_000_u128.into()), - Bfp::from_wei(deposit_out.into()), - Bfp::from_wei(500_000_000_000_000_u128.into()), + Bfp::from_wei(U256::from(deposit_in)), + Bfp::from_wei(U256::from(500_000_000_000_000_u128)), + Bfp::from_wei(U256::from(deposit_out)), + Bfp::from_wei(U256::from(500_000_000_000_000_u128)), Bfp::from_wei($amount), ) }; @@ -314,26 +318,27 @@ mod tests { let largest_amount_in = deposit_in * 3 / 10; assert_eq!( - calc_with_default_pool!(calc_out_given_in, largest_amount_in.into()).unwrap(), + calc_with_default_pool!(calc_out_given_in, U256::from(largest_amount_in)).unwrap(), // > await calc_with_default_pool("_calcOutGivenIn", "6000000000000000000000") - Bfp::from_wei(2_307_692_307_692_230_750_000_u128.into()) + Bfp::from_wei(U256::from(2_307_692_307_692_230_750_000_u128)) ); assert_eq!( - calc_with_default_pool!(calc_out_given_in, (largest_amount_in + 1).into()).unwrap_err(), + calc_with_default_pool!(calc_out_given_in, U256::from(largest_amount_in + 1)) + .unwrap_err(), // > await calc_with_default_pool("_calcOutGivenIn", "6000000000000000000001") - "304".into() + Error::MaxInRatio ); let largest_amount_out = deposit_out * 3 / 10; assert_eq!( - calc_with_default_pool!(calc_in_given_out, largest_amount_out.into()).unwrap(), + calc_with_default_pool!(calc_in_given_out, U256::from(largest_amount_out)).unwrap(), // > await calc_with_default_pool("_calcInGivenOut", "3000000000000000000000") - Bfp::from_wei(8_571_428_571_428_857_160_000_u128.into()) + Bfp::from_wei(U256::from(8_571_428_571_428_857_160_000_u128)) ); assert_eq!( - calc_with_default_pool!(calc_in_given_out, (largest_amount_out + 1).into()) + calc_with_default_pool!(calc_in_given_out, U256::from(largest_amount_out + 1)) .unwrap_err(), // > await calc_with_default_pool("_calcInGivenOut", "3000000000000000000001") - "305".into() + Error::MaxOutRatio ); } } diff --git a/crates/liquidity-sources/src/base_tokens.rs b/crates/liquidity-sources/src/base_tokens.rs new file mode 100644 index 0000000000..6e1c66287e --- /dev/null +++ b/crates/liquidity-sources/src/base_tokens.rs @@ -0,0 +1,253 @@ +use {alloy::primitives::Address, model::TokenPair, std::collections::HashSet}; + +/// The maximum number of hops to use when trading with AMMs along a path. +const DEFAULT_MAX_HOPS: usize = 2; + +type PathCandidate = Vec
; + +pub struct BaseTokens { + /// The base tokens used to determine potential paths in the baseline + /// solver. + /// + /// Always includes the native token. + tokens: HashSet
, + /// All pairs of above. + pairs: HashSet, +} + +impl BaseTokens { + pub fn new(native_token: Address, base_tokens: &[Address]) -> Self { + let mut tokens = base_tokens.to_vec(); + tokens.push(native_token); + tokens.sort(); + tokens.dedup(); + let pairs = base_token_pairs(&tokens).collect(); + Self { + tokens: tokens.into_iter().collect(), + pairs, + } + } + + pub fn tokens(&self) -> &HashSet
{ + &self.tokens + } + + /// All pool token pairs that could be used along a path candidate for these + /// token pairs. + pub fn relevant_pairs(&self, pairs: impl Iterator) -> HashSet { + let mut result = HashSet::new(); + for pair in pairs { + result.insert(pair); + for token in pair { + result.extend( + self.tokens + .iter() + .filter_map(move |base_token| TokenPair::new(*base_token, token)), + ); + } + } + // Could be empty if the input pairs are empty. Just like path_candidates we + // return empty set in this case. + if !result.is_empty() { + result.extend(self.pairs.iter().copied()); + } + result + } + + // Returns possible paths from sell_token to buy token, given a list of + // potential intermediate base tokens and a maximum number of intermediate + // steps. Can contain token pairs between base tokens or a base token and + // the sell or buy token. + pub fn path_candidates( + &self, + sell_token: Address, + buy_token: Address, + ) -> HashSet { + self.path_candidates_with_hops(sell_token, buy_token, DEFAULT_MAX_HOPS) + } + + /// Returns possible path candidates with the specified number of maximum + /// hops. + pub fn path_candidates_with_hops( + &self, + sell_token: Address, + buy_token: Address, + max_hops: usize, + ) -> HashSet { + path_candidates(sell_token, buy_token, &self.tokens, max_hops) + } +} + +fn path_candidates( + sell_token: Address, + buy_token: Address, + base_tokens: &HashSet
, + max_hops: usize, +) -> HashSet { + if sell_token == buy_token { + return HashSet::new(); + } + + let mut candidates = HashSet::new(); + + // Start with just the sell token (yields the direct pair candidate in the 0th + // iteration) + let mut path_prefixes = vec![vec![sell_token]]; + for _ in 0..(max_hops + 1) { + let mut next_round_path_prefixes = vec![]; + for path_prefix in &path_prefixes { + // For this round, add the buy token and path to the candidates + let mut full_path = path_prefix.clone(); + full_path.push(buy_token); + candidates.insert(full_path); + + // For the next round, amend current prefix with all base tokens that are not + // yet on the path + for base_token in base_tokens { + if base_token != &buy_token && !path_prefix.contains(base_token) { + let mut next_round_path_prefix = path_prefix.clone(); + next_round_path_prefix.push(*base_token); + next_round_path_prefixes.push(next_round_path_prefix); + } + } + } + path_prefixes = next_round_path_prefixes; + } + candidates +} + +/// All token pairs between base tokens. +fn base_token_pairs(base_tokens: &[Address]) -> impl Iterator + '_ { + base_tokens + .iter() + .copied() + .enumerate() + .flat_map(move |(index, token)| { + base_tokens + .iter() + .copied() + .skip(index) + .filter_map(move |token_| TokenPair::new(token, token_)) + }) +} + +#[cfg(test)] +mod tests { + use {super::*, maplit::hashset, model::TokenPair}; + + #[test] + fn path_candidates_empty_when_same_token() { + let base = BaseTokens::new(Address::with_last_byte(0), &[Address::with_last_byte(1)]); + let sell_token = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(2); + + assert!(base.path_candidates(sell_token, buy_token).is_empty()); + } + + #[test] + fn test_path_candidates() { + let base_tokens = [ + Address::with_last_byte(0), + Address::with_last_byte(1), + Address::with_last_byte(2), + ]; + let base_token_set: HashSet
= base_tokens.iter().copied().collect(); + + let sell_token = Address::with_last_byte(4); + let buy_token = Address::with_last_byte(5); + + // 0 hops + assert_eq!( + path_candidates(sell_token, buy_token, &base_token_set, 0), + hashset! {vec![sell_token, buy_token]} + ); + + // 1 hop with all permutations + assert_eq!( + path_candidates(sell_token, buy_token, &base_token_set, 1), + hashset! { + vec![sell_token, buy_token], + vec![sell_token, base_tokens[0], buy_token], + vec![sell_token, base_tokens[1], buy_token], + vec![sell_token, base_tokens[2], buy_token], + + } + ); + + // 2 & 3 hops check count + assert_eq!( + path_candidates(sell_token, buy_token, &base_token_set, 2).len(), + 10 + ); + assert_eq!( + path_candidates(sell_token, buy_token, &base_token_set, 3).len(), + 16 + ); + + // 4 hops should not yield any more permutations since we used all base tokens + assert_eq!( + path_candidates(sell_token, buy_token, &base_token_set, 4).len(), + 16 + ); + + // Ignores base token if part of buy or sell + assert_eq!( + path_candidates(base_tokens[0], buy_token, &base_token_set, 1), + hashset! { + vec![base_tokens[0], buy_token], + vec![base_tokens[0], base_tokens[1], buy_token], + vec![base_tokens[0], base_tokens[2], buy_token], + + } + ); + assert_eq!( + path_candidates(sell_token, base_tokens[0], &base_token_set, 1), + hashset! { + vec![sell_token, base_tokens[0]], + vec![sell_token, base_tokens[1], base_tokens[0]], + vec![sell_token, base_tokens[2], base_tokens[0]], + + } + ); + } + + #[test] + fn base_token_pairs_() { + let base_tokens: Vec
= [0, 1, 2] + .iter() + .copied() + .map(Address::with_last_byte) + .collect(); + let pairs: Vec = base_token_pairs(&base_tokens).collect(); + assert_eq!(pairs.len(), 3); + assert!(pairs.contains(&TokenPair::new(base_tokens[0], base_tokens[1]).unwrap())); + assert!(pairs.contains(&TokenPair::new(base_tokens[0], base_tokens[2]).unwrap())); + assert!(pairs.contains(&TokenPair::new(base_tokens[1], base_tokens[2]).unwrap())); + } + + #[test] + fn relevant_pairs() { + let tokens: Vec
= [0, 1, 2, 3, 4] + .iter() + .copied() + .map(Address::with_last_byte) + .collect(); + let base = BaseTokens::new(tokens[0], &tokens[1..2]); + + let pairs = base.relevant_pairs(&mut std::iter::empty()); + assert!(pairs.is_empty()); + + let pairs = base.relevant_pairs(&mut TokenPair::new(tokens[0], tokens[1]).into_iter()); + assert_eq!(pairs.len(), 1); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[1]).unwrap())); + + let pairs = base.relevant_pairs(&mut TokenPair::new(tokens[3], tokens[4]).into_iter()); + assert_eq!(pairs.len(), 6); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[1]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[3]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[4]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[1], tokens[3]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[1], tokens[4]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[3], tokens[4]).unwrap())); + } +} diff --git a/crates/liquidity-sources/src/baseline_solvable.rs b/crates/liquidity-sources/src/baseline_solvable.rs new file mode 100644 index 0000000000..96ab390eb1 --- /dev/null +++ b/crates/liquidity-sources/src/baseline_solvable.rs @@ -0,0 +1,29 @@ +use alloy::primitives::{Address, U256}; + +/// Note that get_amount_out and get_amount_in are not always symmetrical. That +/// is for some AMMs it is possible that get_amount_out returns an amount for +/// which get_amount_in returns None when trying to go the reverse direction. Or +/// that the resulting amount is different from the original. This situation is +/// rare and resulting amounts should usually be identical or very close but it +/// can occur. +pub trait BaselineSolvable { + /// Given the desired output token, the amount and token input, return the + /// expected amount of output token. + fn get_amount_out( + &self, + out_token: Address, + input: (U256, Address), + ) -> impl Future> + Send; + + /// Given the input token, the amount and token we want output, return the + /// required amount of input token that needs to be provided. + fn get_amount_in( + &self, + in_token: Address, + out: (U256, Address), + ) -> impl Future> + Send; + + /// Returns the approximate amount of gas that using this piece of liquidity + /// would incur + fn gas_cost(&self) -> impl Future + Send; +} diff --git a/crates/shared/src/sources/mod.rs b/crates/liquidity-sources/src/lib.rs similarity index 58% rename from crates/shared/src/sources/mod.rs rename to crates/liquidity-sources/src/lib.rs index 4290a7c4f6..d6c106ff32 100644 --- a/crates/shared/src/sources/mod.rs +++ b/crates/liquidity-sources/src/lib.rs @@ -1,21 +1,18 @@ //! Top-level module organizing all baseline liquidity sources. pub mod balancer_v2; +pub mod base_tokens; +pub mod baseline_solvable; +mod macros; +pub mod recent_block_cache; +pub mod subgraph; pub mod swapr; pub mod uniswap_v2; pub mod uniswap_v3; pub mod uniswap_v3_pair_provider; +pub mod zeroex; -use { - self::uniswap_v2::pool_fetching::{Pool, PoolFetching}, - crate::recent_block_cache::Block, - anyhow::Result, - chain::Chain, - core::panic, - model::TokenPair, - std::{collections::HashSet, sync::Arc}, - tracing::instrument, -}; +use {chain::Chain, core::panic}; #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, clap::ValueEnum)] #[clap(rename_all = "verbatim")] @@ -42,16 +39,12 @@ pub fn defaults_for_network(chain: &Chain) -> Vec { BaselineSource::ZeroEx, BaselineSource::UniswapV3, ], - Chain::Goerli => vec![ - BaselineSource::UniswapV2, - BaselineSource::SushiSwap, - BaselineSource::BalancerV2, - ], Chain::Gnosis => vec![ BaselineSource::Honeyswap, BaselineSource::SushiSwap, BaselineSource::Baoswap, BaselineSource::Swapr, + BaselineSource::UniswapV3, ], Chain::ArbitrumOne => vec![ BaselineSource::UniswapV2, @@ -68,31 +61,10 @@ pub fn defaults_for_network(chain: &Chain) -> Vec { BaselineSource::ZeroEx, BaselineSource::UniswapV3, ], - Chain::Lens => vec![BaselineSource::UniswapV3], Chain::Linea => vec![BaselineSource::UniswapV3], - Chain::Plasma => vec![], + Chain::Plasma => vec![BaselineSource::UniswapV3], + Chain::Ink => vec![BaselineSource::UniswapV3], Chain::Sepolia => vec![BaselineSource::TestnetUniswapV2], Chain::Hardhat => panic!("unsupported baseline sources for Hardhat"), } } - -pub struct PoolAggregator { - pub pool_fetchers: Vec>, -} - -#[async_trait::async_trait] -impl PoolFetching for PoolAggregator { - #[instrument(skip_all)] - async fn fetch(&self, token_pairs: HashSet, at_block: Block) -> Result> { - // vk: Using try join means if any pool fetcher fails we fail too. Alternatively - // we could return the succeeding ones but I feel it is cleaner to - // forward the error. - let results = futures::future::try_join_all( - self.pool_fetchers - .iter() - .map(|pool_fetcher| pool_fetcher.fetch(token_pairs.clone(), at_block)), - ) - .await?; - Ok(results.into_iter().flatten().collect()) - } -} diff --git a/crates/liquidity-sources/src/macros.rs b/crates/liquidity-sources/src/macros.rs new file mode 100644 index 0000000000..c9fbf51f3a --- /dev/null +++ b/crates/liquidity-sources/src/macros.rs @@ -0,0 +1,20 @@ +#[macro_export] +macro_rules! bfp { + ($val:literal) => { + ($val) + .parse::<$crate::balancer_v2::swap::fixed_point::Bfp>() + .unwrap() + }; +} + +#[macro_export] +macro_rules! json_map { + ($($key:expr_2021 => $value:expr_2021),* $(,)?) => {{ + #[allow(unused_mut)] + let mut map = ::serde_json::Map::::new(); + $( + map.insert(($key).into(), ($value).into()); + )* + map + }} +} diff --git a/crates/shared/src/recent_block_cache.rs b/crates/liquidity-sources/src/recent_block_cache.rs similarity index 98% rename from crates/shared/src/recent_block_cache.rs rename to crates/liquidity-sources/src/recent_block_cache.rs index 9b6780b744..ba3dee67c7 100644 --- a/crates/shared/src/recent_block_cache.rs +++ b/crates/liquidity-sources/src/recent_block_cache.rs @@ -25,14 +25,14 @@ //! could simplify this module if it was only used by by the former. use { - crate::request_sharing::BoxRequestSharing, + alloy::eips::BlockId, anyhow::{Context, Result}, cached::{Cached, SizedCache}, - ethcontract::BlockNumber, ethrpc::block_stream::CurrentBlockWatcher, futures::{FutureExt, StreamExt}, itertools::Itertools, prometheus::IntCounterVec, + request_sharing::BoxRequestSharing, std::{ cmp, collections::{BTreeMap, HashMap, HashSet, hash_map::Entry}, @@ -74,12 +74,12 @@ pub enum Block { Finalized, } -impl From for BlockNumber { - fn from(val: Block) -> Self { - match val { - Block::Recent => BlockNumber::Latest, - Block::Number(number) => BlockNumber::Number(number.into()), - Block::Finalized => BlockNumber::Finalized, +impl From for BlockId { + fn from(value: Block) -> Self { + match value { + Block::Recent => BlockId::latest(), + Block::Number(n) => BlockId::number(n), + Block::Finalized => BlockId::finalized(), } } } @@ -265,7 +265,7 @@ where let retries = self.maximum_retries; let delay = self.delay_between_retries; let fetcher = self.fetcher.clone(); - let fut = self.requests.shared_or_else((key, block), |entry| { + let shared = self.requests.shared_or_else((key, block), |entry| { let (key, block) = entry.clone(); async move { for _ in 0..=retries { @@ -280,7 +280,7 @@ where } .boxed() }); - fut.await.context("could not fetch liquidity") + shared.await.context("could not fetch liquidity") } async fn fetch(&self, keys: impl IntoIterator, block: Block) -> Result> { diff --git a/crates/shared/src/subgraph.rs b/crates/liquidity-sources/src/subgraph.rs similarity index 99% rename from crates/shared/src/subgraph.rs rename to crates/liquidity-sources/src/subgraph.rs index afa43a5aa4..2c87b245b7 100644 --- a/crates/shared/src/subgraph.rs +++ b/crates/liquidity-sources/src/subgraph.rs @@ -1,6 +1,7 @@ //! A module implementing a client for querying subgraphs. use { + crate::json_map, anyhow::{Result, bail}, reqwest::{Client, Url}, serde::{Deserialize, Serialize, de::DeserializeOwned}, diff --git a/crates/shared/src/sources/swapr.rs b/crates/liquidity-sources/src/swapr.rs similarity index 80% rename from crates/shared/src/sources/swapr.rs rename to crates/liquidity-sources/src/swapr.rs index a9342e7242..476b9b841f 100644 --- a/crates/shared/src/sources/swapr.rs +++ b/crates/liquidity-sources/src/swapr.rs @@ -1,11 +1,11 @@ //! A pool state reading implementation specific to Swapr. use { - crate::sources::uniswap_v2::pool_fetching::{DefaultPoolReader, Pool, PoolReading}, + crate::uniswap_v2::pool_fetching::{DefaultPoolReader, Pool, PoolReading}, + alloy::eips::BlockId, anyhow::Result, - contracts::alloy::ISwaprPair, - ethcontract::BlockId, - ethrpc::alloy::{conversions::IntoAlloy, errors::ignore_non_node_error}, + contracts::ISwaprPair, + ethrpc::alloy::errors::ignore_non_node_error, futures::{FutureExt as _, future::BoxFuture}, model::TokenPair, num::rational::Ratio, @@ -27,8 +27,8 @@ impl PoolReading for SwaprPoolReader { async move { let pair_contract = - ISwaprPair::Instance::new(pair_address.into_alloy(), self.0.web3.alloy.clone()); - let fetch_fee = pair_contract.swapFee().block(block.into_alloy()); + ISwaprPair::Instance::new(pair_address, self.0.web3.provider.clone()); + let fetch_fee = pair_contract.swapFee().block(block); let (pool, fee) = futures::join!(fetch_pool, fetch_fee.call().into_future()); handle_results(pool, fee) @@ -54,14 +54,12 @@ fn handle_results( mod tests { use { super::*, - crate::{ - ethrpc::Web3, - recent_block_cache::Block, - sources::{BaselineSource, uniswap_v2}, + crate::{BaselineSource, recent_block_cache::Block, uniswap_v2}, + alloy::{ + primitives::{Address, address}, + providers::Provider, }, - alloy::primitives::{Address, address}, - ethcontract::H160, - ethrpc::alloy::errors::testing_alloy_contract_error, + ethrpc::{Web3, alloy::errors::testing_alloy_contract_error}, maplit::hashset, }; @@ -69,7 +67,7 @@ mod tests { fn sets_fee() { let tokens = TokenPair::new(Address::from_slice(&[1; 20]), Address::from_slice(&[2; 20])).unwrap(); - let address = H160::from_low_u64_be(1); + let address = Address::with_last_byte(1); assert_eq!( handle_results( Ok(Some(Pool { @@ -95,7 +93,7 @@ mod tests { fn ignores_contract_errors_when_reading_fee() { let tokens = TokenPair::new(Address::from_slice(&[1; 20]), Address::from_slice(&[2; 20])).unwrap(); - let address = H160::from_low_u64_be(1); + let address = Address::with_last_byte(1); assert!( handle_results( Ok(Some(Pool::uniswap(address, tokens, (0, 0)))), @@ -110,7 +108,7 @@ mod tests { #[ignore] async fn fetch_swapr_pool() { let web3 = Web3::new_from_env(); - let version = web3.eth().chain_id().await.unwrap().to_string(); + let version = web3.provider.get_chain_id().await.unwrap().to_string(); let pool_fetcher = uniswap_v2::UniV2BaselineSourceParameters::from_baseline_source( BaselineSource::Swapr, &version, diff --git a/crates/shared/src/sources/uniswap_v2/mod.rs b/crates/liquidity-sources/src/uniswap_v2/mod.rs similarity index 75% rename from crates/shared/src/sources/uniswap_v2/mod.rs rename to crates/liquidity-sources/src/uniswap_v2/mod.rs index ef0514ba11..5d934565de 100644 --- a/crates/shared/src/sources/uniswap_v2/mod.rs +++ b/crates/liquidity-sources/src/uniswap_v2/mod.rs @@ -9,14 +9,11 @@ use { pair_provider::PairProvider, pool_fetching::{DefaultPoolReader, PoolFetching, PoolReading}, }, - crate::{ - ethrpc::Web3, - sources::{BaselineSource, swapr::SwaprPoolReader}, - }, + crate::{BaselineSource, swapr::SwaprPoolReader}, + alloy::primitives::{Address, B256}, anyhow::{Context, Result}, - contracts::alloy::IUniswapLikeRouter, - ethcontract::{H160, H256}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + contracts::IUniswapLikeRouter, + ethrpc::{Web3, alloy::ProviderLabelingExt}, hex_literal::hex, std::{fmt::Display, str::FromStr, sync::Arc}, }; @@ -42,13 +39,6 @@ pub const SWAPR_INIT: [u8; 32] = pub const TESTNET_UNISWAP_INIT: [u8; 32] = hex!("0efd7612822d579e24a8851501d8c2ad854264a1050e3dfcee8afcca08f80a86"); -#[derive(Debug, Clone, Copy)] -pub struct UniV2BaselineSourceParameters { - router: H160, - init_code_digest: H256, - pool_reading: PoolReadingStyle, -} - #[derive(Clone, Copy, Debug, strum::EnumString, strum::Display)] enum PoolReadingStyle { Default, @@ -61,6 +51,13 @@ pub struct UniV2BaselineSource { pub pool_fetching: Arc, } +#[derive(Debug, Clone, Copy)] +pub struct UniV2BaselineSourceParameters { + router: Address, + init_code_digest: B256, + pool_reading: PoolReadingStyle, +} + impl UniV2BaselineSourceParameters { pub fn from_baseline_source(source: BaselineSource, chain: &str) -> Option { use BaselineSource as BS; @@ -70,38 +67,32 @@ impl UniV2BaselineSourceParameters { match source { BS::None | BS::BalancerV2 | BS::ZeroEx | BS::UniswapV3 => None, BS::UniswapV2 => Some(Self { - router: contracts::alloy::UniswapV2Router02::deployment_address(&chain_id) - .map(IntoLegacy::into_legacy)?, + router: contracts::UniswapV2Router02::deployment_address(&chain_id)?, init_code_digest: UNISWAP_INIT.into(), pool_reading: PoolReadingStyle::Default, }), BS::Honeyswap => Some(Self { - router: contracts::alloy::HoneyswapRouter::deployment_address(&chain_id) - .map(IntoLegacy::into_legacy)?, + router: contracts::HoneyswapRouter::deployment_address(&chain_id)?, init_code_digest: HONEYSWAP_INIT.into(), pool_reading: PoolReadingStyle::Default, }), BS::SushiSwap => Some(Self { - router: contracts::alloy::SushiSwapRouter::deployment_address(&chain_id) - .map(IntoLegacy::into_legacy)?, + router: contracts::SushiSwapRouter::deployment_address(&chain_id)?, init_code_digest: SUSHISWAP_INIT.into(), pool_reading: PoolReadingStyle::Default, }), BS::Swapr => Some(Self { - router: contracts::alloy::SwaprRouter::deployment_address(&chain_id) - .map(IntoLegacy::into_legacy)?, + router: contracts::SwaprRouter::deployment_address(&chain_id)?, init_code_digest: SWAPR_INIT.into(), pool_reading: PoolReadingStyle::Swapr, }), BS::TestnetUniswapV2 => Some(Self { - router: contracts::alloy::TestnetUniswapV2Router02::deployment_address(&chain_id) - .map(IntoLegacy::into_legacy)?, + router: contracts::TestnetUniswapV2Router02::deployment_address(&chain_id)?, init_code_digest: TESTNET_UNISWAP_INIT.into(), pool_reading: PoolReadingStyle::Default, }), BS::Baoswap => Some(Self { - router: contracts::alloy::BaoswapRouter::deployment_address(&chain_id) - .map(IntoLegacy::into_legacy)?, + router: contracts::BaoswapRouter::deployment_address(&chain_id)?, init_code_digest: BAOSWAP_INIT.into(), pool_reading: PoolReadingStyle::Default, }), @@ -109,14 +100,12 @@ impl UniV2BaselineSourceParameters { } pub async fn into_source(&self, web3: &Web3) -> Result { - let web3 = ethrpc::instrumented::instrument_with_label(web3, "uniswapV2".into()); - let router = contracts::alloy::IUniswapLikeRouter::Instance::new( - self.router.into_alloy(), - web3.alloy.clone(), - ); + let web3 = web3.labeled("uniswapV2"); + let router = + contracts::IUniswapLikeRouter::Instance::new(self.router, web3.provider.clone()); let factory = router.factory().call().await.context("factory")?; let pair_provider = pair_provider::PairProvider { - factory: factory.into_legacy(), + factory, init_code_digest: self.init_code_digest.0, }; let pool_reader = DefaultPoolReader::new(web3.clone(), pair_provider); @@ -149,12 +138,12 @@ impl FromStr for UniV2BaselineSourceParameters { fn from_str(s: &str) -> Result { let mut parts = s.split('|'); - let router: H160 = parts + let router: Address = parts .next() .context("no factory address")? .parse() .context("parse factory address")?; - let init_code_digest: H256 = parts + let init_code_digest: B256 = parts .next() .context("no init code digest")? .parse() @@ -178,10 +167,9 @@ mod tests { super::*, crate::recent_block_cache::Block, alloy::{ - primitives::{Address, address}, + primitives::{Address, B256, address}, providers::Provider, }, - ethrpc::alloy::conversions::IntoAlloy, maplit::hashset, model::TokenPair, }; @@ -190,8 +178,7 @@ mod tests { fn parse_address_init() { let arg = "0x0000000000000000000000000000000000000001|0x0000000000000000000000000000000000000000000000000000000000000002"; let parsed = UniV2BaselineSourceParameters::from_str(arg).unwrap(); - assert_eq!(parsed.router, H160::from_low_u64_be(1)); - assert_eq!(parsed.init_code_digest, H256::from_low_u64_be(2)); + assert_eq!(parsed.init_code_digest, B256::with_last_byte(2)); } #[test] @@ -213,18 +200,18 @@ mod tests { web3: &Web3, version: &str, source: BaselineSource, - token0: H160, - token1: H160, - expected_pool_address: H160, + token0: Address, + token1: Address, + expected_pool_address: Address, ) { - let version_ = web3.eth().chain_id().await.unwrap().to_string(); + let version_ = web3.provider.get_chain_id().await.unwrap().to_string(); assert_eq!(version_, version, "wrong node for test"); let source = UniV2BaselineSourceParameters::from_baseline_source(source, version) .unwrap() .into_source(web3) .await .unwrap(); - let pair = TokenPair::new(token0.into_alloy(), token1.into_alloy()).unwrap(); + let pair = TokenPair::new(token0, token1).unwrap(); let pool = source.pair_provider.pair_address(&pair); assert_eq!(pool, expected_pool_address); } @@ -233,7 +220,7 @@ mod tests { #[ignore] async fn baseline_mainnet() { let web3 = ethrpc::Web3::new_from_env(); - let version = web3.eth().chain_id().await.unwrap().to_string(); + let version = web3.provider.get_chain_id().await.unwrap().to_string(); assert_eq!(version, "1", "test must be run with mainnet node"); let test = |source, token0, token1, expected| { test_baseline_source(&web3, "1", source, token0, token1, expected) @@ -241,23 +228,23 @@ mod tests { test( BaselineSource::UniswapV2, - testlib::tokens::GNO.into_legacy(), - testlib::tokens::WETH.into_legacy(), - addr!("3e8468f66d30fc99f745481d4b383f89861702c6"), + testlib::tokens::GNO, + testlib::tokens::WETH, + address!("3e8468f66d30fc99f745481d4b383f89861702c6"), ) .await; test( BaselineSource::SushiSwap, - testlib::tokens::GNO.into_legacy(), - testlib::tokens::WETH.into_legacy(), - addr!("41328fdba556c8c969418ccccb077b7b8d932aa5"), + testlib::tokens::GNO, + testlib::tokens::WETH, + address!("41328fdba556c8c969418ccccb077b7b8d932aa5"), ) .await; test( BaselineSource::Swapr, - addr!("a1d65E8fB6e87b60FECCBc582F7f97804B725521"), - testlib::tokens::WETH.into_legacy(), - addr!("b0Dc4B36e0B4d2e3566D2328F6806EA0B76b4F13"), + address!("a1d65E8fB6e87b60FECCBc582F7f97804B725521"), + testlib::tokens::WETH, + address!("b0Dc4B36e0B4d2e3566D2328F6806EA0B76b4F13"), ) .await; } @@ -266,7 +253,7 @@ mod tests { #[ignore] async fn baseline_sepolia() { let web3 = ethrpc::Web3::new_from_env(); - let version = web3.eth().chain_id().await.unwrap().to_string(); + let version = web3.provider.get_chain_id().await.unwrap().to_string(); assert_eq!(version, "11155111", "test must be run with mainnet node"); let test = |source, token0, token1, expected| { test_baseline_source(&web3, "11155111", source, token0, token1, expected) @@ -275,9 +262,9 @@ mod tests { // https://sepolia.etherscan.io/tx/0x4d31daa9e74b96a5c9a780cf8839b115ac25127b17226ecb1ad6e7f244fd1c8f test( BaselineSource::TestnetUniswapV2, - addr!("fff9976782d46cc05630d1f6ebab18b2324d6b14"), - addr!("7c43482436624585c27cc9f804e53463d5a37aba"), - addr!("84A1CE0e56500D51a6a6e2559567007E26dc8a7C"), + address!("fff9976782d46cc05630d1f6ebab18b2324d6b14"), + address!("7c43482436624585c27cc9f804e53463d5a37aba"), + address!("84A1CE0e56500D51a6a6e2559567007E26dc8a7C"), ) .await; } @@ -286,7 +273,7 @@ mod tests { #[ignore] async fn baseline_xdai() { let web3 = ethrpc::Web3::new_from_env(); - let version = web3.eth().chain_id().await.unwrap().to_string(); + let version = web3.provider.get_chain_id().await.unwrap().to_string(); assert_eq!(version, "100", "test must be run with xdai node"); let test = |source, token0, token1, expected| { test_baseline_source(&web3, "100", source, token0, token1, expected) @@ -294,16 +281,16 @@ mod tests { test( BaselineSource::Baoswap, - addr!("7f7440c5098462f833e123b44b8a03e1d9785bab"), - addr!("e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"), - addr!("8746355882e10aae144d3709889dfaa39ff2a692"), + address!("7f7440c5098462f833e123b44b8a03e1d9785bab"), + address!("e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"), + address!("8746355882e10aae144d3709889dfaa39ff2a692"), ) .await; test( BaselineSource::Honeyswap, - addr!("71850b7e9ee3f13ab46d67167341e4bdc905eef9"), - addr!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), - addr!("4505b262dc053998c10685dc5f9098af8ae5c8ad"), + address!("71850b7e9ee3f13ab46d67167341e4bdc905eef9"), + address!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), + address!("4505b262dc053998c10685dc5f9098af8ae5c8ad"), ) .await; } @@ -315,7 +302,7 @@ mod tests { #[ignore] async fn fetch_baoswap_pool() { let web3 = Web3::new_from_env(); - let version = web3.alloy.get_chain_id().await.unwrap().to_string(); + let version = web3.provider.get_chain_id().await.unwrap().to_string(); let pool_fetcher = UniV2BaselineSourceParameters::from_baseline_source(BaselineSource::Baoswap, &version) .unwrap() @@ -342,7 +329,7 @@ mod tests { println!("WETH <> wxDAI pool: {pool:#?}"); assert_eq!( - pool.address.into_alloy(), + pool.address, address!("8c36f7ca02d50bf8e705f582328b873acbe9438d") ); } @@ -351,7 +338,7 @@ mod tests { #[ignore] async fn fetch_honeyswap_pool() { let web3 = Web3::new_from_env(); - let version = web3.alloy.get_chain_id().await.unwrap().to_string(); + let version = web3.provider.get_chain_id().await.unwrap().to_string(); let pool_fetcher = UniV2BaselineSourceParameters::from_baseline_source( BaselineSource::Honeyswap, &version, @@ -380,7 +367,7 @@ mod tests { println!("WETH <> wxDAI pool: {pool:#?}"); assert_eq!( - pool.address.into_alloy(), + pool.address, address!("7bea4af5d425f2d4485bdad1859c88617df31a67") ); } diff --git a/crates/shared/src/sources/uniswap_v2/pair_provider.rs b/crates/liquidity-sources/src/uniswap_v2/pair_provider.rs similarity index 65% rename from crates/shared/src/sources/uniswap_v2/pair_provider.rs rename to crates/liquidity-sources/src/uniswap_v2/pair_provider.rs index 747232e8f3..b82cb1e754 100644 --- a/crates/shared/src/sources/uniswap_v2/pair_provider.rs +++ b/crates/liquidity-sources/src/uniswap_v2/pair_provider.rs @@ -1,13 +1,16 @@ -use {ethcontract::H160, model::TokenPair, web3::signing::keccak256}; +use { + alloy::primitives::{Address, keccak256}, + model::TokenPair, +}; #[derive(Clone, Copy, Debug)] pub struct PairProvider { - pub factory: H160, + pub factory: Address, pub init_code_digest: [u8; 32], } impl PairProvider { - pub fn pair_address(&self, pair: &TokenPair) -> H160 { + pub fn pair_address(&self, pair: &TokenPair) -> Address { let (token0, token1) = pair.get(); // https://uniswap.org/docs/v2/javascript-SDK/getting-pair-addresses/ @@ -15,29 +18,33 @@ impl PairProvider { let mut buffer = [0u8; 40]; buffer[0..20].copy_from_slice(token0.as_slice()); buffer[20..40].copy_from_slice(token1.as_slice()); - keccak256(&buffer) + keccak256(buffer) }; create2_target_address(self.factory, &salt, &self.init_code_digest) } } -fn create2_target_address(creator: H160, salt: &[u8; 32], init_code_digest: &[u8; 32]) -> H160 { +fn create2_target_address( + creator: Address, + salt: &[u8; 32], + init_code_digest: &[u8; 32], +) -> Address { let mut preimage = [0xff; 85]; - preimage[1..21].copy_from_slice(creator.as_fixed_bytes()); + preimage[1..21].copy_from_slice(creator.as_slice()); preimage[21..53].copy_from_slice(salt); preimage[53..85].copy_from_slice(init_code_digest); - H160::from_slice(&keccak256(&preimage)[12..]) + Address::from_slice(&keccak256(preimage)[12..]) } #[cfg(test)] mod tests { - use {super::*, hex_literal::hex}; + use {super::*, alloy::primitives::address, hex_literal::hex}; #[test] fn test_create2_mainnet() { // https://info.uniswap.org/pair/0x3e8468f66d30fc99f745481d4b383f89861702c6 let provider = PairProvider { - factory: addr!("5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), + factory: address!("5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), init_code_digest: hex!( "96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" ), @@ -45,7 +52,7 @@ mod tests { let pair = TokenPair::new(testlib::tokens::GNO, testlib::tokens::WETH).unwrap(); assert_eq!( provider.pair_address(&pair), - addr!("3e8468f66d30fc99f745481d4b383f89861702c6") + address!("3e8468f66d30fc99f745481d4b383f89861702c6") ); } } diff --git a/crates/shared/src/sources/uniswap_v2/pool_cache.rs b/crates/liquidity-sources/src/uniswap_v2/pool_cache.rs similarity index 95% rename from crates/shared/src/sources/uniswap_v2/pool_cache.rs rename to crates/liquidity-sources/src/uniswap_v2/pool_cache.rs index 7f4257b5bb..5992425331 100644 --- a/crates/shared/src/sources/uniswap_v2/pool_cache.rs +++ b/crates/liquidity-sources/src/uniswap_v2/pool_cache.rs @@ -1,7 +1,7 @@ use { crate::{ recent_block_cache::{Block, CacheConfig, CacheFetching, CacheKey, RecentBlockCache}, - sources::uniswap_v2::pool_fetching::{Pool, PoolFetching}, + uniswap_v2::pool_fetching::{Pool, PoolFetching}, }, anyhow::Result, ethrpc::block_stream::CurrentBlockWatcher, diff --git a/crates/shared/src/sources/uniswap_v2/pool_fetching.rs b/crates/liquidity-sources/src/uniswap_v2/pool_fetching.rs similarity index 70% rename from crates/shared/src/sources/uniswap_v2/pool_fetching.rs rename to crates/liquidity-sources/src/uniswap_v2/pool_fetching.rs index caedfed96d..d9d323ad2a 100644 --- a/crates/shared/src/sources/uniswap_v2/pool_fetching.rs +++ b/crates/liquidity-sources/src/uniswap_v2/pool_fetching.rs @@ -1,20 +1,17 @@ use { super::pair_provider::PairProvider, - crate::{baseline_solver::BaselineSolvable, ethrpc::Web3, recent_block_cache::Block}, + crate::{baseline_solvable::BaselineSolvable, recent_block_cache::Block}, + alloy::{ + eips::BlockId, + primitives::{Address, U256}, + }, anyhow::Result, cached::{Cached, TimedCache}, contracts::{ - alloy::{ - ERC20, - IUniswapLikePair::{self, IUniswapLikePair::getReservesReturn}, - }, - errors::EthcontractErrorType, - }, - ethcontract::{BlockId, H160, U256, errors::MethodError}, - ethrpc::alloy::{ - conversions::{IntoAlloy, IntoLegacy}, - errors::ignore_non_node_error, + ERC20, + IUniswapLikePair::{self, IUniswapLikePair::getReservesReturn}, }, + ethrpc::{Web3, alloy::errors::ignore_non_node_error}, futures::{ FutureExt as _, future::{self, BoxFuture}, @@ -26,7 +23,6 @@ use { sync::{LazyLock, RwLock}, time::Duration, }, - tracing::instrument, }; const POOL_SWAP_GAS_COST: usize = 60_000; @@ -35,7 +31,7 @@ static POOL_MAX_RESERVES: LazyLock = LazyLock::new(|| U256::from((1u128 << /// This type denotes `(reserve_a, reserve_b, token_b)` where /// `reserve_a` refers to the reserve of the excluded token. -type RelativeReserves = (U256, U256, H160); +type RelativeReserves = (U256, U256, Address); #[async_trait::async_trait] pub trait PoolFetching: Send + Sync { @@ -56,14 +52,14 @@ impl PoolReading for Box { #[derive(Clone, Copy, Eq, Hash, PartialEq, Debug)] pub struct Pool { - pub address: H160, + pub address: Address, pub tokens: TokenPair, pub reserves: (u128, u128), pub fee: Ratio, } impl Pool { - pub fn uniswap(address: H160, tokens: TokenPair, reserves: (u128, u128)) -> Self { + pub fn uniswap(address: Address, tokens: TokenPair, reserves: (u128, u128)) -> Self { Self { address, tokens, @@ -75,7 +71,7 @@ impl Pool { /// Given an input amount and token, returns the maximum output amount and /// address of the other asset. Returns None if operation not possible /// due to arithmetic issues (e.g. over or underflow) - fn get_amount_out(&self, token_in: H160, amount_in: U256) -> Option<(U256, H160)> { + fn get_amount_out(&self, token_in: Address, amount_in: U256) -> Option<(U256, Address)> { let (reserve_in, reserve_out, token_out) = self.get_relative_reserves(token_in); Some(( self.amount_out(amount_in, reserve_in, reserve_out)?, @@ -86,7 +82,7 @@ impl Pool { /// Given an output amount and token, returns a required input amount and /// address of the other asset. Returns None if operation not possible /// due to arithmetic issues (e.g. over or underflow, reserve too small) - fn get_amount_in(&self, token_out: H160, amount_out: U256) -> Option<(U256, H160)> { + fn get_amount_in(&self, token_out: Address, amount_out: U256) -> Option<(U256, Address)> { let (reserve_out, reserve_in, token_in) = self.get_relative_reserves(token_out); Some(( self.amount_in(amount_out, reserve_in, reserve_out)?, @@ -101,24 +97,20 @@ impl Pool { /// - the reserve of the other token /// - the pool's other token This is essentially a helper method for /// shuffling values in `get_amount_in` and `get_amount_out` - fn get_relative_reserves(&self, token: H160) -> RelativeReserves { + fn get_relative_reserves(&self, token: Address) -> RelativeReserves { // https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol#L53 - if token == self.tokens.get().0.into_legacy() { + if token == self.tokens.get().0 { ( U256::from(self.reserves.0), U256::from(self.reserves.1), - self.tokens.get().1.into_legacy(), + self.tokens.get().1, ) } else { - assert_eq!( - token, - self.tokens.get().1.into_legacy(), - "Token not part of pool" - ); + assert_eq!(token, self.tokens.get().1, "Token not part of pool"); ( U256::from(self.reserves.1), U256::from(self.reserves.0), - self.tokens.get().0.into_legacy(), + self.tokens.get().0, ) } } @@ -151,7 +143,7 @@ impl Pool { let denominator = reserve_out .checked_sub(amount_out)? .checked_mul(U256::from(self.fee.denom().checked_sub(*self.fee.numer())?))?; - let amount_in = numerator.checked_div(denominator)?.checked_add(1.into())?; + let amount_in = numerator.checked_div(denominator)?.checked_add(U256::ONE)?; check_final_reserves(amount_in, amount_out, reserve_in, reserve_out)?; Some(amount_in) @@ -177,8 +169,8 @@ fn check_final_reserves( impl BaselineSolvable for Pool { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { self.get_amount_out(in_token, in_amount) .map(|(out_amount, token)| { @@ -189,8 +181,8 @@ impl BaselineSolvable for Pool { async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { self.get_amount_in(out_token, out_amount) .map(|(in_amount, token)| { @@ -225,17 +217,15 @@ impl PoolFetching for PoolFetcher where Reader: PoolReading, { - #[instrument(skip_all)] async fn fetch(&self, token_pairs: HashSet, at_block: Block) -> Result> { let mut token_pairs: Vec<_> = token_pairs.into_iter().collect(); { let mut non_existent_pools = self.non_existent_pools.write().unwrap(); token_pairs.retain(|pair| non_existent_pools.cache_get(pair).is_none()); } - let block = BlockId::Number(at_block.into()); let futures = token_pairs .iter() - .map(|pair| self.pool_reader.read_state(*pair, block)) + .map(|pair| self.pool_reader.read_state(*pair, at_block.into())) .collect::>(); let results = future::try_join_all(futures).await?; @@ -282,20 +272,16 @@ impl PoolReading for DefaultPoolReader { let pair_address = self.pair_provider.pair_address(&pair); // Fetch ERC20 token balances of the pools to sanity check with reserves - let token0 = ERC20::Instance::new(pair.get().0, self.web3.alloy.clone()); - let token1 = ERC20::Instance::new(pair.get().1, self.web3.alloy.clone()); + let token0 = ERC20::Instance::new(pair.get().0, self.web3.provider.clone()); + let token1 = ERC20::Instance::new(pair.get().1, self.web3.provider.clone()); async move { - let fetch_token0_balance = token0 - .balanceOf(pair_address.into_alloy()) - .block(block.into_alloy()); - let fetch_token1_balance = token1 - .balanceOf(pair_address.into_alloy()) - .block(block.into_alloy()); + let fetch_token0_balance = token0.balanceOf(pair_address).block(block); + let fetch_token1_balance = token1.balanceOf(pair_address).block(block); let pair_contract = - IUniswapLikePair::Instance::new(pair_address.into_alloy(), self.web3.alloy.clone()); - let fetch_reserves = pair_contract.getReserves().block(block.into_alloy()); + IUniswapLikePair::Instance::new(pair_address, self.web3.provider.clone()); + let fetch_reserves = pair_contract.getReserves().block(block); let (reserves, token0_balance, token1_balance) = futures::join!( fetch_reserves.call().into_future(), @@ -320,23 +306,11 @@ impl PoolReading for DefaultPoolReader { struct FetchedPool { pair: TokenPair, reserves: Result, - token0_balance: Result, - token1_balance: Result, + token0_balance: Result, + token1_balance: Result, } -// Node errors should be bubbled up but contract errors should lead to the pool -// being skipped. -pub fn handle_contract_error(result: Result) -> Result> { - match result { - Ok(t) => Ok(Some(t)), - Err(err) => match EthcontractErrorType::classify(&err) { - EthcontractErrorType::Node => Err(err.into()), - EthcontractErrorType::Contract => Ok(None), - }, - } -} - -fn handle_results(fetched_pool: FetchedPool, address: H160) -> Result> { +fn handle_results(fetched_pool: FetchedPool, address: Address) -> Result> { let reserves = ignore_non_node_error(fetched_pool.reserves)?; let token0_balance = ignore_non_node_error(fetched_pool.token0_balance)?; let token1_balance = ignore_non_node_error(fetched_pool.token1_balance)?; @@ -357,9 +331,7 @@ fn handle_results(fetched_pool: FetchedPool, address: H160) -> Result token0_balance? - || alloy::primitives::U256::from(r1) > token1_balance? - { + if U256::from(r0) > token0_balance? || U256::from(r1) > token1_balance? { return None; } // Errors here should never happen because reserves are uint<112, 2> @@ -403,130 +375,144 @@ mod tests { #[test] fn test_get_amounts_out() { - let sell_token = H160::from_low_u64_be(1); - let buy_token = H160::from_low_u64_be(2); + let sell_token = Address::with_last_byte(1); + let buy_token = Address::with_last_byte(2); // Even Pool let pool = Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(sell_token, buy_token).unwrap(), (100, 100), ); assert_eq!( - pool.get_amount_out(sell_token, 10.into()), - Some((9.into(), buy_token)) + pool.get_amount_out(sell_token, U256::from(10)), + Some((U256::from(9), buy_token)) ); assert_eq!( - pool.get_amount_out(sell_token, 100.into()), - Some((49.into(), buy_token)) + pool.get_amount_out(sell_token, U256::from(100)), + Some((U256::from(49), buy_token)) ); assert_eq!( - pool.get_amount_out(sell_token, 1000.into()), - Some((90.into(), buy_token)) + pool.get_amount_out(sell_token, U256::from(1000)), + Some((U256::from(90), buy_token)) ); //Uneven Pool let pool = Pool::uniswap( - H160::from_low_u64_be(2), - TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(), + Address::with_last_byte(2), + TokenPair::new(sell_token, buy_token).unwrap(), (200, 50), ); assert_eq!( - pool.get_amount_out(sell_token, 10.into()), - Some((2.into(), buy_token)) + pool.get_amount_out(sell_token, U256::from(10)), + Some((U256::from(2), buy_token)) ); assert_eq!( - pool.get_amount_out(sell_token, 100.into()), - Some((16.into(), buy_token)) + pool.get_amount_out(sell_token, U256::from(100)), + Some((U256::from(16), buy_token)) ); assert_eq!( - pool.get_amount_out(sell_token, 1000.into()), - Some((41.into(), buy_token)) + pool.get_amount_out(sell_token, U256::from(1000)), + Some((U256::from(41), buy_token)) ); // Large Numbers let pool = Pool::uniswap( - H160::from_low_u64_be(3), - TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(), + Address::with_last_byte(3), + TokenPair::new(sell_token, buy_token).unwrap(), (1u128 << 90, 1u128 << 90), ); assert_eq!( - pool.get_amount_out(sell_token, 10u128.pow(20).into()), - Some((99_699_991_970_459_889_807u128.into(), buy_token)) + pool.get_amount_out(sell_token, U256::from(10u128.pow(20))), + Some((U256::from(99_699_991_970_459_889_807u128), buy_token)) ); // Overflow - assert_eq!(pool.get_amount_out(sell_token, U256::max_value()), None); + assert_eq!(pool.get_amount_out(sell_token, U256::MAX), None); } #[test] fn test_get_amounts_in() { - let sell_token = H160::from_low_u64_be(1); - let buy_token = H160::from_low_u64_be(2); + let sell_token = Address::with_last_byte(1); + let buy_token = Address::with_last_byte(2); // Even Pool let pool = Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(sell_token, buy_token).unwrap(), (100, 100), ); assert_eq!( - pool.get_amount_in(buy_token, 10.into()), - Some((12.into(), sell_token)) + pool.get_amount_in(buy_token, U256::from(10)), + Some((U256::from(12), sell_token)) ); assert_eq!( - pool.get_amount_in(buy_token, 99.into()), - Some((9930.into(), sell_token)) + pool.get_amount_in(buy_token, U256::from(99)), + Some((U256::from(9930), sell_token)) ); // Buying more than possible - assert_eq!(pool.get_amount_in(buy_token, 100.into()), None); - assert_eq!(pool.get_amount_in(buy_token, 1000.into()), None); + assert_eq!(pool.get_amount_in(buy_token, U256::from(100)), None); + assert_eq!(pool.get_amount_in(buy_token, U256::from(1000)), None); //Uneven Pool let pool = Pool::uniswap( - H160::from_low_u64_be(2), - TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(), + Address::with_last_byte(2), + TokenPair::new(sell_token, buy_token).unwrap(), (200, 50), ); assert_eq!( - pool.get_amount_in(buy_token, 10.into()), - Some((51.into(), sell_token)) + pool.get_amount_in(buy_token, U256::from(10)), + Some((U256::from(51), sell_token)) ); assert_eq!( - pool.get_amount_in(buy_token, 49.into()), - Some((9830.into(), sell_token)) + pool.get_amount_in(buy_token, U256::from(49)), + Some((U256::from(9830), sell_token)) ); // Large Numbers let pool = Pool::uniswap( - H160::from_low_u64_be(3), - TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(), + Address::with_last_byte(3), + TokenPair::new(sell_token, buy_token).unwrap(), (1u128 << 90, 1u128 << 90), ); assert_eq!( - pool.get_amount_in(buy_token, 10u128.pow(20).into()), - Some((100_300_910_810_367_424_267u128.into(), sell_token)), + pool.get_amount_in(buy_token, U256::from(10u128.pow(20))), + Some((U256::from(100_300_910_810_367_424_267u128), sell_token)), ); } #[test] fn computes_final_reserves() { assert_eq!( - check_final_reserves(1.into(), 2.into(), 1_000_000.into(), 2_000_000.into(),).unwrap(), - (1_000_001.into(), 1_999_998.into()), + check_final_reserves( + U256::ONE, + U256::from(2), + U256::from(1_000_000), + U256::from(2_000_000), + ) + .unwrap(), + (U256::from(1_000_001), U256::from(1_999_998)), ); } #[test] fn check_final_reserve_limits() { // final out reserve too low - assert!(check_final_reserves(0.into(), 1.into(), 1_000_000.into(), 0.into()).is_none()); - // final in reserve too high assert!( - check_final_reserves(1.into(), 0.into(), *POOL_MAX_RESERVES, 1_000_000.into()) + check_final_reserves(U256::ZERO, U256::ONE, U256::from(1_000_000), U256::ZERO) .is_none() ); + // final in reserve too high + assert!( + check_final_reserves( + U256::ONE, + U256::ZERO, + *POOL_MAX_RESERVES, + U256::from(1_000_000) + ) + .is_none() + ); } #[test] @@ -534,8 +520,8 @@ mod tests { let fetched_pool = FetchedPool { reserves: Err(testing_alloy_node_error()), pair: Default::default(), - token0_balance: Ok(alloy::primitives::U256::from(1)), - token1_balance: Ok(alloy::primitives::U256::from(1)), + token0_balance: Ok(U256::ONE), + token1_balance: Ok(U256::ONE), }; let pool_address = Default::default(); assert!(handle_results(fetched_pool, pool_address).is_err()); @@ -546,8 +532,8 @@ mod tests { let fetched_pool = FetchedPool { reserves: Err(testing_alloy_contract_error()), pair: Default::default(), - token0_balance: Ok(alloy::primitives::U256::from(1)), - token1_balance: Ok(alloy::primitives::U256::from(1)), + token0_balance: Ok(U256::ONE), + token1_balance: Ok(U256::ONE), }; let pool_address = Default::default(); assert!( diff --git a/crates/shared/src/sources/uniswap_v3/event_fetching.rs b/crates/liquidity-sources/src/uniswap_v3/event_fetching.rs similarity index 98% rename from crates/shared/src/sources/uniswap_v3/event_fetching.rs rename to crates/liquidity-sources/src/uniswap_v3/event_fetching.rs index f7e4db3461..4aaf0c4e34 100644 --- a/crates/shared/src/sources/uniswap_v3/event_fetching.rs +++ b/crates/liquidity-sources/src/uniswap_v3/event_fetching.rs @@ -1,5 +1,4 @@ use { - crate::event_handling::{AlloyEventRetrieving, EventStoring}, UniswapV3Pool::UniswapV3Pool::UniswapV3PoolEvents as AlloyUniswapV3PoolEvents, alloy::{ primitives::Address, @@ -8,11 +7,14 @@ use { sol_types::SolEvent, }, anyhow::{Context, Result}, - contracts::alloy::{ + contracts::{ UniswapV3Pool, UniswapV3Pool::UniswapV3Pool::{Burn, Mint, Swap, UniswapV3PoolEvents}, }, - ethrpc::block_stream::RangeInclusive, + event_indexing::{ + block_retriever::RangeInclusive, + event_handler::{AlloyEventRetrieving, EventStoring}, + }, std::collections::BTreeMap, }; diff --git a/crates/shared/src/sources/uniswap_v3/graph_api.rs b/crates/liquidity-sources/src/uniswap_v3/graph_api.rs similarity index 75% rename from crates/shared/src/sources/uniswap_v3/graph_api.rs rename to crates/liquidity-sources/src/uniswap_v3/graph_api.rs index e785fc87c8..6e6194cf9d 100644 --- a/crates/shared/src/sources/uniswap_v3/graph_api.rs +++ b/crates/liquidity-sources/src/uniswap_v3/graph_api.rs @@ -3,11 +3,14 @@ use { crate::{ - event_handling::MAX_REORG_BLOCK_COUNT, + json_map, subgraph::{ContainsId, SubgraphClient}, + uniswap_v3::V3PoolDataSource, }, + alloy::primitives::{Address, U256}, anyhow::Result, - ethcontract::{H160, U256}, + async_trait::async_trait, + event_indexing::event_handler::MAX_REORG_BLOCK_COUNT, num::BigInt, number::serialization::HexOrDecimalU256, reqwest::{Client, Url}, @@ -106,27 +109,13 @@ impl UniV3SubgraphClient { .paginated_query(&query, variables) .await? .into_iter() - .filter(|pool: &PoolData| pool.liquidity > U256::zero()) + .filter(|pool: &PoolData| pool.liquidity > U256::ZERO) .collect()) } - /// Retrieves the pool data for all existing pools from the subgraph. - pub async fn get_registered_pools(&self) -> Result { - let block_number = self.get_safe_block().await?; - let variables = json_map! { - "block" => block_number, - }; - let query = Self::all_pools_query(self.use_liquidity_net_filter); - let pools = self.get_pools(query, variables).await?; - Ok(RegisteredPools { - fetched_block_number: block_number, - pools, - }) - } - async fn get_pools_by_pool_ids( &self, - pool_ids: &[H160], + pool_ids: &[Address], block_number: u64, ) -> Result> { let variables = json_map! { @@ -141,7 +130,7 @@ impl UniV3SubgraphClient { /// Retrieves the ticks data for pools with given pool ids async fn get_ticks_by_pools_ids( &self, - pool_ids: &[H160], + pool_ids: &[Address], block_number: u64, ) -> Result> { let mut all = Vec::new(); @@ -163,37 +152,6 @@ impl UniV3SubgraphClient { Ok(all) } - /// Retrieves the pool data and ticks data for pools with given pool ids - pub async fn get_pools_with_ticks_by_ids( - &self, - ids: &[H160], - block_number: u64, - ) -> Result> { - let (pools, ticks) = futures::try_join!( - self.get_pools_by_pool_ids(ids, block_number), - self.get_ticks_by_pools_ids(ids, block_number) - )?; - - // group ticks by pool ids - let mut ticks_mapped = HashMap::new(); - for tick in ticks { - ticks_mapped - .entry(tick.pool_address) - .or_insert_with(Vec::new) - .push(tick); - } - - Ok(pools - .into_iter() - .filter_map(|mut pool| { - ticks_mapped.get(&pool.id).map(|ticks| { - pool.ticks = Some(ticks.clone()); - pool - }) - }) - .collect()) - } - /// Retrieves a recent block number for which it is safe to assume no /// reorgs will happen. pub async fn get_safe_block(&self) -> Result { @@ -277,6 +235,62 @@ impl UniV3SubgraphClient { } } +#[async_trait] +impl V3PoolDataSource for UniV3SubgraphClient { + /// The subgraph supports historical queries, so every returned pool is + /// consistently anchored at `target_block`. + async fn get_registered_pools(&self, target_block: u64) -> Result { + let variables = json_map! { + "block" => target_block, + }; + let query = Self::all_pools_query(self.use_liquidity_net_filter); + let mut pools = self.get_pools(query, variables).await?; + for pool in &mut pools { + pool.block_number = target_block; + } + Ok(RegisteredPools { + fetched_block_number: target_block, + pools, + }) + } + + /// The subgraph supports historical queries, so the returned snapshot is + /// at exactly `target_block`. + async fn get_pools_with_ticks_by_ids( + &self, + ids: &[Address], + target_block: u64, + ) -> Result { + let (pools, ticks) = futures::try_join!( + self.get_pools_by_pool_ids(ids, target_block), + self.get_ticks_by_pools_ids(ids, target_block) + )?; + + let mut ticks_by_pool: HashMap> = HashMap::new(); + for tick in ticks { + ticks_by_pool + .entry(tick.pool_address) + .or_default() + .push(tick); + } + + let pools = pools + .into_iter() + .filter_map(|mut pool| { + ticks_by_pool.get(&pool.id).map(|ticks| { + pool.ticks = Some(ticks.clone()); + pool.block_number = target_block; + pool + }) + }) + .collect(); + Ok(PoolsWithTicks { + fetched_block_number: target_block, + pools, + }) + } +} + /// Result of the registered stable pool query. #[derive(Debug, Default, PartialEq)] pub struct RegisteredPools { @@ -286,12 +300,29 @@ pub struct RegisteredPools { pub pools: Vec, } -/// Pool data from the Uniswap V3 subgraph. +/// Result of fetching pool state + active ticks for a given set of pools. The +/// returned `fetched_block_number` is the actual snapshot block (which may be +/// later than the caller's `target_block` for indexer-backed sources). +#[derive(Debug, Default, PartialEq)] +pub struct PoolsWithTicks { + pub fetched_block_number: u64, + pub pools: Vec, +} + +/// Pool data from the Uniswap V3 subgraph or the pool-indexer service. +/// +/// `block_number` is the block at which the pool's authoritative state +/// (`liquidity` / `sqrt_price` / `tick`) was sampled. Sources stamp it +/// post-deserialization because the wire format doesn't carry a per-pool +/// block (the subgraph anchors at a single `target_block` for all pools; +/// the pool-indexer reports it per-response). Drivers can use this to +/// drive per-pool event replay rather than relying on a single global +/// anchor. #[serde_as] #[derive(Debug, Clone, Deserialize, Default, PartialEq)] #[serde(rename_all = "camelCase")] pub struct PoolData { - pub id: H160, + pub id: Address, pub token0: Token, pub token1: Token, #[serde_as(as = "HexOrDecimalU256")] @@ -303,11 +334,15 @@ pub struct PoolData { #[serde_as(as = "DisplayFromStr")] pub tick: BigInt, pub ticks: Option>, + /// Not serialised — sources populate this after deserialisation. See + /// the struct doc for why. + #[serde(default, skip_deserializing)] + pub block_number: u64, } impl ContainsId for PoolData { fn get_id(&self) -> String { - self.id.to_string() + format!("{:#x}", self.id) } } @@ -316,17 +351,19 @@ impl ContainsId for PoolData { #[derive(Debug, Clone, Deserialize, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct TickData { - pub id: String, #[serde_as(as = "DisplayFromStr")] pub tick_idx: BigInt, #[serde_as(as = "DisplayFromStr")] pub liquidity_net: BigInt, - pub pool_address: H160, + pub pool_address: Address, } impl ContainsId for TickData { + /// Recomputes the subgraph's `id` (`#`) on demand + /// rather than carrying it through the struct. Used by the subgraph + /// pagination cursor; the pool-indexer path doesn't paginate ticks. fn get_id(&self) -> String { - self.id.clone() + format!("{:#x}#{}", self.pool_address, self.tick_idx) } } @@ -334,7 +371,7 @@ impl ContainsId for TickData { #[derive(Debug, Clone, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct Token { - pub id: H160, + pub id: Address, #[serde_as(as = "DisplayFromStr")] pub decimals: u8, } @@ -367,7 +404,7 @@ mod block_number_query { #[cfg(test)] mod tests { - use {super::*, crate::subgraph::Data, serde_json::json, std::str::FromStr}; + use {super::*, crate::subgraph::Data, alloy::primitives::address, serde_json::json}; #[test] fn decode_pools_data() { @@ -414,40 +451,38 @@ mod tests { Data { inner: vec![ PoolData { - id: H160::from_str("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28").unwrap(), + id: address!("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28"), token0: Token { - id: H160::from_str("0xbef81556ef066ec840a540595c8d12f516b6378f") - .unwrap(), + id: address!("0xbef81556ef066ec840a540595c8d12f516b6378f"), decimals: 18, }, token1: Token { - id: H160::from_str("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") - .unwrap(), + id: address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), decimals: 18, }, - fee_tier: U256::from_dec_str("10000").unwrap(), - liquidity: U256::from_dec_str("303015134493562686441").unwrap(), - sqrt_price: U256::from_dec_str("792216481398733702759960397").unwrap(), + fee_tier: U256::from(10000), + liquidity: U256::from(303015134493562686441_u128), + sqrt_price: U256::from(792216481398733702759960397_u128), tick: BigInt::from(-92110), ticks: None, + block_number: 0, }, PoolData { - id: H160::from_str("0x0002e63328169d7feea121f1e32e4f620abf0352").unwrap(), + id: address!("0x0002e63328169d7feea121f1e32e4f620abf0352"), token0: Token { - id: H160::from_str("0x0d438f3b5175bebc262bf23753c1e53d03432bde") - .unwrap(), + id: address!("0x0d438f3b5175bebc262bf23753c1e53d03432bde"), decimals: 18, }, token1: Token { - id: H160::from_str("0x903bef1736cddf2a537176cf3c64579c3867a881") - .unwrap(), + id: address!("0x903bef1736cddf2a537176cf3c64579c3867a881"), decimals: 9, }, - fee_tier: U256::from_dec_str("3000").unwrap(), - liquidity: U256::from_dec_str("3125586395511534995").unwrap(), - sqrt_price: U256::from_dec_str("5986323062404391218190509").unwrap(), + fee_tier: U256::from(3000), + liquidity: U256::from(3125586395511534995_u128), + sqrt_price: U256::from(5986323062404391218190509_u128), tick: BigInt::from(-189822), ticks: None, + block_number: 0, }, ], } @@ -477,18 +512,14 @@ mod tests { Data { inner: vec![ TickData { - id: "0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28#0".to_string(), tick_idx: BigInt::from(0), liquidity_net: BigInt::from(-303015134493562686441i128), - pool_address: H160::from_str("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28") - .unwrap(), + pool_address: address!("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28") }, TickData { - id: "0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28#-92200".to_string(), tick_idx: BigInt::from(-92200), liquidity_net: BigInt::from(303015134493562686441i128), - pool_address: H160::from_str("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28") - .unwrap(), + pool_address: address!("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28") }, ], } diff --git a/crates/liquidity-sources/src/uniswap_v3/mod.rs b/crates/liquidity-sources/src/uniswap_v3/mod.rs new file mode 100644 index 0000000000..3559776950 --- /dev/null +++ b/crates/liquidity-sources/src/uniswap_v3/mod.rs @@ -0,0 +1,46 @@ +//! Uniswap V3 baseline liquidity source implementation. +pub mod event_fetching; +pub mod graph_api; +pub mod pool_fetching; +pub mod pool_indexer; + +use { + self::graph_api::{PoolsWithTicks, RegisteredPools}, + alloy::primitives::Address, + anyhow::Result, + async_trait::async_trait, +}; + +/// Abstracts over places we can pull Uniswap V3 pool state + ticks from. +/// Currently there are two backends: the Uniswap V3 subgraph (historical, +/// queryable by block) and our own pool-indexer service (at-head only, with a +/// `wait_until` barrier to bound staleness). +/// +/// Snapshot contract — both methods return data at a block *>=* `target_block`: +/// - Subgraph: honors `target_block` exactly via its `block: { number: ... }` +/// filter. +/// - Pool-indexer: blocks until its envelope's `block_number` has caught up to +/// `target_block`, then serves at-head data. +/// +/// Each response carries `fetched_block_number` — the *actual* snapshot block. +/// Callers must use that (not `target_block`) as the event-replay anchor, since +/// the indexer's actual block can be later than `target_block`. +#[async_trait] +pub trait V3PoolDataSource: Send + Sync + 'static { + /// Fetch the full set of pools the source knows about as of a block at or + /// after `target_block`. `PoolData::ticks` is always `None` here — callers + /// needing ticks must use [`Self::get_pools_with_ticks_by_ids`] separately. + /// The split lets a cheap "what pools exist?" lookup skip the expensive + /// tick fetch. + async fn get_registered_pools(&self, target_block: u64) -> Result; + + /// Fetch pools + their active ticks for the given pool addresses as of a + /// block at or after `target_block`. The returned `fetched_block_number` is + /// the actual snapshot block (`>= target_block`); callers should use it as + /// the event-replay anchor. + async fn get_pools_with_ticks_by_ids( + &self, + ids: &[Address], + target_block: u64, + ) -> Result; +} diff --git a/crates/shared/src/sources/uniswap_v3/pool_fetching.rs b/crates/liquidity-sources/src/uniswap_v3/pool_fetching.rs similarity index 78% rename from crates/shared/src/sources/uniswap_v3/pool_fetching.rs rename to crates/liquidity-sources/src/uniswap_v3/pool_fetching.rs index e5d464037b..8b95fd8f33 100644 --- a/crates/shared/src/sources/uniswap_v3/pool_fetching.rs +++ b/crates/liquidity-sources/src/uniswap_v3/pool_fetching.rs @@ -1,31 +1,28 @@ use { super::{ + V3PoolDataSource, event_fetching::{RecentEventsCache, UniswapV3PoolEventFetcher}, - graph_api::{PoolData, Token, UniV3SubgraphClient}, + graph_api::{PoolData, Token}, }, - crate::{ - event_handling::{AlloyEventRetriever, EventHandler, EventStoring, MAX_REORG_BLOCK_COUNT}, - maintenance::Maintaining, - recent_block_cache::Block, - sources::uniswap_v3::event_fetching::WithAddress, + crate::{recent_block_cache::Block, uniswap_v3::event_fetching::WithAddress}, + alloy::{ + primitives::{Address, U256}, + rpc::types::Log, }, - alloy::rpc::types::Log, anyhow::{Context, Result}, - contracts::alloy::UniswapV3Pool::UniswapV3Pool::{ + contracts::UniswapV3Pool::UniswapV3Pool::{ UniswapV3PoolEvents as AlloyUniswapV3PoolEvents, UniswapV3PoolEvents, }, - ethcontract::{H160, U256}, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::{BlockRetrieving, RangeInclusive}, + ethrpc::{Web3, alloy::ProviderLabelingExt}, + event_indexing::{ + block_retriever::{BlockRetrieving, RangeInclusive}, + event_handler::{EventHandler, EventStoring, MAX_REORG_BLOCK_COUNT}, + maintenance::Maintaining, }, - itertools::{Either, Itertools}, model::TokenPair, num::{BigInt, Zero, rational::Ratio}, number::serialization::HexOrDecimalU256, - reqwest::{Client, Url}, serde::Serialize, serde_with::{DisplayFromStr, serde_as}, std::{ @@ -42,7 +39,7 @@ pub trait PoolFetching: Send + Sync { &self, token_pairs: &HashSet, at_block: Block, - ) -> Result>; + ) -> Result>>; } /// Pool data in a format prepared for solvers. @@ -51,7 +48,7 @@ pub struct PoolInfo { /// Skip serializing address since it's redundant (already serialized /// outside of this struct) #[serde(skip_serializing)] - pub address: H160, + pub address: Address, pub tokens: Vec, pub state: PoolState, pub gas_stats: PoolStats, @@ -106,7 +103,7 @@ impl TryFrom for PoolInfo { } }) .collect(), - fee: Ratio::new(pool.fee_tier.as_u32(), 1_000_000u32), + fee: Ratio::new(u32::try_from(pool.fee_tier)?, 1_000_000u32), }, gas_stats: PoolStats { mean_gas: U256::from(108_163), // as estimated by https://dune.com/queries/1044812 @@ -118,47 +115,70 @@ impl TryFrom for PoolInfo { #[derive(Default)] struct PoolsCheckpoint { /// Pools state. - pools: HashMap, + pools: HashMap>, /// Block number for which `pools` field was populated. block_number: u64, /// Pools that don't exist in `pools` field, therefore need to be /// initialized and moved to `pools` in the next maintainance run - missing_pools: HashSet, + missing_pools: HashSet
, } struct PoolsCheckpointHandler { - graph_api: UniV3SubgraphClient, - /// H160 is pool id while TokenPair is a pair or tokens for each pool. - pools_by_token_pair: HashMap>, + source: Arc, + /// Address is pool id while TokenPair is a pair or tokens for each pool. + pools_by_token_pair: HashMap>, /// Pools state on a specific block number in history considered reorg safe pools_checkpoint: Mutex, } impl PoolsCheckpointHandler { /// Fetches the list of existing UniswapV3 pools and their metadata (without - /// state/ticks). Then fetches state/ticks for the most deepest pools - /// (subset of all existing pools) + /// state/ticks). Then fetches state/ticks for the deepest pools + /// (subset of all existing pools). + /// + /// `target_block` is the chain's finalized block so it matches the + /// pool-indexer source's anchor; both calls then return data at or + /// after that block. The event-replay anchor is taken from the *tick* + /// call's response (the later of the two). Otherwise there's a race + /// between the pool-list fetch and the tick fetch: an event landing + /// between them would show up in `ticks` but not `pools`, and replaying + /// it would apply that event twice. pub async fn new( - subgraph_url: &Url, - client: Client, + source: Arc, + block_retriever: Arc, max_pools_to_initialize_cache: usize, - max_pools_per_tick_query: usize, ) -> Result { - let graph_api = - UniV3SubgraphClient::from_subgraph_url(subgraph_url, client, max_pools_per_tick_query) - .await?; - let mut registered_pools = graph_api.get_registered_pools().await?; + let target_block = block_retriever + .finalized_block() + .await + .context("read finalized block for snapshot target_block")? + .number; + let mut registered_pools = source.get_registered_pools(target_block).await?; tracing::debug!( - block = %registered_pools.fetched_block_number, pools = %registered_pools.pools.len(), + target_block, + block = %registered_pools.fetched_block_number, + pools = %registered_pools.pools.len(), "initialized registered pools", ); - let mut pools_by_token_pair: HashMap> = HashMap::new(); - for pool in ®istered_pools.pools { - let pair = TokenPair::new(pool.token0.id.into_alloy(), pool.token1.id.into_alloy()) - .context("cant create pair")?; - pools_by_token_pair.entry(pair).or_default().insert(pool.id); - } + let pools_by_token_pair = { + // we store addresses in a `Vec` instead of a `HashSet` to save on memory but + // we still ensure there are no duplicated pools. + let mut pools_by_token_pair: HashMap> = HashMap::new(); + for pool in ®istered_pools.pools { + let pair = + TokenPair::new(pool.token0.id, pool.token1.id).context("cant create pair")?; + let pools = pools_by_token_pair.entry(pair).or_default(); + if !pools.contains(&pool.id) { + pools.push(pool.id); + } + } + pools_by_token_pair + .values_mut() + .for_each(|bucket| bucket.shrink_to_fit()); + pools_by_token_pair.shrink_to_fit(); + pools_by_token_pair + }; // can't fetch the state of all pools in constructor for performance reasons, // so let's fetch the top `max_pools_to_initialize_cache` pools with the highest @@ -174,20 +194,28 @@ impl PoolsCheckpointHandler { .rev() .take(max_pools_to_initialize_cache) .collect::>(); - let pools = graph_api + let pools_with_ticks = source .get_pools_with_ticks_by_ids(&pool_ids, registered_pools.fetched_block_number) - .await? + .await?; + let pools = pools_with_ticks + .pools .into_iter() - .filter_map(|pool| Some((pool.id, pool.try_into().ok()?))) + .filter_map(|pool| Some((pool.id, Arc::new(pool.try_into().ok()?)))) .collect::>(); + // Anchor the checkpoint at the *tick* call's snapshot block, which is + // `>= registered_pools.fetched_block_number`. For pool-indexer-backed + // sources this is later than the `get_registered_pools` call; using it + // (not the earlier block) prevents the driver's event replay from + // double-applying Mint/Burn events that the indexer already reflected + // by the time the tick fetch returned. let pools_checkpoint = Mutex::new(PoolsCheckpoint { pools, - block_number: registered_pools.fetched_block_number, + block_number: pools_with_ticks.fetched_block_number, ..Default::default() }); Ok(Self { - graph_api, + source, pools_by_token_pair, pools_checkpoint, }) @@ -196,7 +224,7 @@ impl PoolsCheckpointHandler { /// For a given list of token pairs, fetches the pools for the ones that /// exist in the checkpoint. For the ones that don't exist, flag as /// missing and expect to exist after the next maintenance run. - fn get(&self, token_pairs: &HashSet) -> (HashMap, u64) { + fn get(&self, token_pairs: &HashSet) -> (HashMap>, u64) { let mut pool_ids = token_pairs .iter() .filter_map(|pair| self.pools_by_token_pair.get(pair)) @@ -208,11 +236,17 @@ impl PoolsCheckpointHandler { match pool_ids.peek() { Some(_) => { let mut pools_checkpoint = self.pools_checkpoint.lock().unwrap(); - let (existing_pools, missing_pools): (HashMap, Vec) = - pool_ids.partition_map(|pool_id| match pools_checkpoint.pools.get(pool_id) { - Some(entry) => Either::Left((*pool_id, entry.clone())), - _ => Either::Right(pool_id), - }); + let mut existing_pools = HashMap::>::default(); + let missing_pools = pool_ids + .filter(|pool_id| match pools_checkpoint.pools.get(*pool_id) { + Some(entry) => { + existing_pools.insert(**pool_id, entry.clone()); + false + } + None => true, + }) + .collect::>(); + tracing::trace!( "cache hit: {:?}, cache miss: {:?}", existing_pools.keys(), @@ -239,21 +273,22 @@ impl PoolsCheckpointHandler { let pool_ids = missing_pools.into_iter().collect::>(); let start = std::time::Instant::now(); - let pools = self - .graph_api + let pools_with_ticks = self + .source .get_pools_with_ticks_by_ids(&pool_ids, block_number) .await; tracing::debug!( requested_pools = pool_ids.len(), time = ?start.elapsed(), - request_successful = pools.is_ok(), + request_successful = pools_with_ticks.is_ok(), "fetched pool ticks" ); + let pools_with_ticks = pools_with_ticks?; let mut checkpoint = self.pools_checkpoint.lock().unwrap(); - for pool in pools? { + for pool in pools_with_ticks.pools { checkpoint.missing_pools.remove(&pool.id); - checkpoint.pools.insert(pool.id, pool.try_into()?); + checkpoint.pools.insert(pool.id, Arc::new(pool.try_into()?)); } tracing::debug!("number of cached pools is {}", checkpoint.pools.len()); @@ -273,38 +308,28 @@ pub struct UniswapV3PoolFetcher { /// Recent events used on top of pools_checkpoint to get the `latest_block` /// pools state. events: tokio::sync::Mutex< - EventHandler< - AlloyEventRetriever, - RecentEventsCache, - (AlloyUniswapV3PoolEvents, Log), - >, + EventHandler, >, } impl UniswapV3PoolFetcher { pub async fn new( - subgraph_url: &Url, + source: Arc, web3: Web3, - client: Client, block_retriever: Arc, max_pools_to_initialize: usize, - max_pools_per_tick_query: usize, ) -> Result { - let web3 = ethrpc::instrumented::instrument_with_label(&web3, "uniswapV3".into()); - let checkpoint = PoolsCheckpointHandler::new( - subgraph_url, - client, - max_pools_to_initialize, - max_pools_per_tick_query, - ) - .await?; + let web3 = web3.labeled("uniswapV3"); + let checkpoint = + PoolsCheckpointHandler::new(source, block_retriever.clone(), max_pools_to_initialize) + .await?; let init_block = checkpoint.pools_checkpoint.lock().unwrap().block_number; let init_block = block_retriever.block(init_block).await?; let events = tokio::sync::Mutex::new(EventHandler::new( block_retriever, - AlloyEventRetriever(UniswapV3PoolEventFetcher(web3.alloy)), + UniswapV3PoolEventFetcher(web3.provider), RecentEventsCache::default(), Some(init_block), )); @@ -358,7 +383,7 @@ impl PoolFetching for UniswapV3PoolFetcher { &self, token_pairs: &HashSet, at_block: Block, - ) -> Result> { + ) -> Result>> { let block_number = match at_block { Block::Recent | Block::Finalized => self .events @@ -407,21 +432,19 @@ impl PoolFetching for UniswapV3PoolFetcher { // return only pools which current liquidity is positive Ok(checkpoint .into_values() - .filter(|pool| pool.state.liquidity > U256::zero()) + .filter(|pool| pool.state.liquidity > U256::ZERO) .collect()) } } /// For a given checkpoint, append events to get a new checkpoint fn append_events( - pools: &mut HashMap, + pools: &mut HashMap>, events: Vec>, ) { for event in events { - if let Some(pool) = pools - .get_mut(&event.address().into_legacy()) - .map(|pool| &mut pool.state) - { + if let Some(pool) = pools.get_mut(&event.address()).map(Arc::make_mut) { + let pool = &mut pool.state; match event.inner() { UniswapV3PoolEvents::Burn(burn) => { let tick_lower = BigInt::from(burn.tickLower.as_i32()); @@ -430,7 +453,7 @@ fn append_events( // liquidity tracks the liquidity on recent tick, // only need to update it if the new position includes the recent tick. if tick_lower <= pool.tick && pool.tick < tick_upper { - pool.liquidity -= burn.amount.into(); + pool.liquidity -= U256::from(burn.amount); } pool.liquidity_net @@ -459,7 +482,7 @@ fn append_events( // liquidity tracks the liquidity on recent tick, // only need to update it if the new position includes the recent tick. if tick_lower <= pool.tick && pool.tick < tick_upper { - pool.liquidity += mint.amount.into(); + pool.liquidity += U256::from(mint.amount); } pool.liquidity_net @@ -483,9 +506,8 @@ fn append_events( } UniswapV3PoolEvents::Swap(swap) => { pool.tick = BigInt::from(swap.tick.as_i32()); - pool.liquidity = swap.liquidity.into(); - pool.sqrt_price = - alloy::primitives::U256::from(swap.sqrtPriceX96).into_legacy(); + pool.liquidity = U256::from(swap.liquidity); + pool.sqrt_price = U256::from(swap.sqrtPriceX96); } _ => continue, } @@ -522,9 +544,8 @@ impl Maintaining for UniswapV3PoolFetcher { mod tests { use { super::*, - alloy::primitives::{U160, aliases::I24}, - contracts::alloy::UniswapV3Pool::UniswapV3Pool::{Burn, Mint, Swap}, - ethrpc::alloy::conversions::IntoAlloy, + alloy::primitives::{U160, address, aliases::I24}, + contracts::UniswapV3Pool::UniswapV3Pool::{Burn, Mint, Swap}, serde_json::json, std::str::FromStr, testlib::assert_json_matches, @@ -561,20 +582,20 @@ mod tests { }); let pool = PoolInfo { - address: H160::from_str("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28").unwrap(), + address: address!("0x0001fcbba8eb491c3ccfeddc5a5caba1a98c4c28"), tokens: vec![ Token { - id: H160::from_str("0xbef81556ef066ec840a540595c8d12f516b6378f").unwrap(), + id: address!("0xbef81556ef066ec840a540595c8d12f516b6378f"), decimals: 18, }, Token { - id: H160::from_str("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2").unwrap(), + id: address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), decimals: 18, }, ], state: PoolState { - sqrt_price: U256::from_dec_str("792216481398733702759960397").unwrap(), - liquidity: U256::from_dec_str("303015134493562686441").unwrap(), + sqrt_price: U256::from(792216481398733702759960397_u128), + liquidity: U256::from(303015134493562686441_u128), tick: BigInt::from_str("-92110").unwrap(), liquidity_net: BTreeMap::from([ ( @@ -603,7 +624,7 @@ mod tests { #[test] fn append_events_test_empty() { - let pools = HashMap::from([(H160::from_low_u64_be(1), Default::default())]); + let pools = HashMap::from([(Address::with_last_byte(1), Default::default())]); let mut new_pools = pools.clone(); let events = vec![]; append_events(&mut new_pools, events); @@ -612,11 +633,11 @@ mod tests { #[test] fn append_events_test_swap() { - let address = H160::from_low_u64_be(1); - let pool = PoolInfo { + let address = Address::with_last_byte(1); + let pool = Arc::new(PoolInfo { address, ..Default::default() - }; + }); let mut pools = HashMap::from([(address, pool)]); let event = WithAddress::new( @@ -629,7 +650,7 @@ mod tests { amount0: Default::default(), amount1: Default::default(), }), - address.into_alloy(), + address, ); append_events(&mut pools, vec![event]); @@ -640,11 +661,11 @@ mod tests { #[test] fn append_events_test_burn() { - let address = H160::from_low_u64_be(1); - let pool = PoolInfo { + let address = Address::with_last_byte(1); + let pool = Arc::new(PoolInfo { address, ..Default::default() - }; + }); let mut pools = HashMap::from([(address, pool)]); // add first burn event @@ -657,7 +678,7 @@ mod tests { amount0: Default::default(), amount1: Default::default(), }), - address.into_alloy(), + address, ); append_events(&mut pools, vec![event]); assert_eq!( @@ -678,7 +699,7 @@ mod tests { amount0: Default::default(), amount1: Default::default(), }), - address.into_alloy(), + address, ); append_events(&mut pools, vec![event]); assert_eq!( @@ -693,11 +714,11 @@ mod tests { #[test] fn append_events_test_mint() { - let address = H160::from_low_u64_be(1); - let pool = PoolInfo { + let address = Address::with_last_byte(1); + let pool = Arc::new(PoolInfo { address, ..Default::default() - }; + }); let mut pools = HashMap::from([(address, pool)]); // add first mint event @@ -711,7 +732,7 @@ mod tests { amount1: Default::default(), sender: Default::default(), }), - address.into_alloy(), + address, ); append_events(&mut pools, vec![event]); assert_eq!( @@ -733,7 +754,7 @@ mod tests { amount1: Default::default(), sender: Default::default(), }), - address.into_alloy(), + address, ); append_events(&mut pools, vec![event]); assert_eq!( diff --git a/crates/liquidity-sources/src/uniswap_v3/pool_indexer.rs b/crates/liquidity-sources/src/uniswap_v3/pool_indexer.rs new file mode 100644 index 0000000000..695193b84b --- /dev/null +++ b/crates/liquidity-sources/src/uniswap_v3/pool_indexer.rs @@ -0,0 +1,453 @@ +//! HTTP client for the Uniswap V3 pool-indexer service. Implements +//! [`V3PoolDataSource`] so the driver can swap this in place of the subgraph +//! client without touching anything else. +//! +//! The pool-indexer doesn't support historical queries; it always serves +//! at-head data. To give callers a consistent snapshot, each method takes a +//! `target_block` and blocks (via [`PoolIndexerClient::wait_until`]) until the +//! indexer's envelope reports a block at or after it. The actual snapshot +//! block — which can be later than `target_block` if the indexer advanced +//! during the call — is returned alongside the data so callers can anchor +//! their event-replay at the right place. + +use { + crate::uniswap_v3::{ + V3PoolDataSource, + graph_api::{PoolData, PoolsWithTicks, RegisteredPools, TickData, Token}, + }, + alloy::primitives::{Address, U256}, + anyhow::{Context, Result}, + async_trait::async_trait, + chain::Chain, + itertools::Itertools, + num::BigInt, + number::serialization::HexOrDecimalU256, + reqwest::{Client, Url}, + serde::{Deserialize, Deserializer, de}, + serde_with::{DisplayFromStr, serde_as}, + std::{collections::HashMap, time::Duration}, +}; + +/// Poll interval for [`PoolIndexerClient::wait_until`]. +const WAIT_UNTIL_POLL_INTERVAL: Duration = Duration::from_millis(500); + +/// Matches the server-side `MAX_POOL_IDS_PER_REQUEST`. +const POOL_IDS_PER_REQUEST: usize = 500; + +/// Matches the server-side `MAX_PAGE_LIMIT`. +const LIST_PAGE_SIZE: u64 = 5000; + +pub struct PoolIndexerClient { + base_url: Url, + http: Client, + /// Cap on a single `wait_until` call. Pick per network to exceed the + /// worst-case fresh-deploy seed time. + wait_until_timeout: Duration, +} + +impl PoolIndexerClient { + pub fn new(base_url: Url, chain: Chain, http: Client, wait_until_timeout: Duration) -> Self { + let prefix = format!("api/v1/{}/uniswap/v3/", chain.as_str()); + let base_url = url_join(&base_url, &prefix); + Self { + base_url, + http, + wait_until_timeout, + } + } + + fn path(&self, suffix: &str) -> Url { + url_join(&self.base_url, suffix) + } +} + +/// Joins `path` onto `url` with exactly one slash between them. Reusing +/// `Url::join` is unreliable here because a base URL without a trailing +/// slash drops its last path segment (RFC 3986 path resolution), and the +/// pool-indexer base URL comes from operator config which may or may not +/// have one. +fn url_join(url: &Url, mut path: &str) -> Url { + let mut url = url.to_string(); + while url.ends_with('/') { + url.pop(); + } + while path.starts_with('/') { + path = &path[1..]; + } + Url::parse(&format!("{url}/{path}")).expect("constructed URL is valid") +} + +#[derive(Deserialize)] +struct PoolsResponse { + block_number: u64, + pools: Vec, + #[serde(default)] + next_cursor: Option, +} + +#[serde_as] +#[derive(Deserialize)] +struct IndexerPool { + id: Address, + token0: IndexerToken, + token1: IndexerToken, + #[serde_as(as = "HexOrDecimalU256")] + fee_tier: U256, + #[serde_as(as = "HexOrDecimalU256")] + liquidity: U256, + #[serde_as(as = "HexOrDecimalU256")] + sqrt_price: U256, + tick: i32, +} + +#[derive(Deserialize)] +struct IndexerToken { + id: Address, + #[serde(default)] + decimals: Option, +} + +#[derive(Deserialize)] +struct BulkTicksResponse { + /// Block of the envelope. Compared against the paired `/pools/by-ids` + /// block in `fetch_batch_consistent` so the caller never mixes pool + /// state and tick state from different blocks. + block_number: u64, + /// Wire shape is `pools: [{ pool, ticks }, …]`; we re-index by pool + /// address. Duplicate pool keys fail deserialisation rather than + /// silently overwriting — the API contract is one entry per pool. + #[serde(deserialize_with = "deserialize_ticks_by_pool")] + pools: HashMap>, +} + +#[derive(Deserialize)] +struct IndexerPoolTicks { + pool: Address, + ticks: Vec, +} + +fn deserialize_ticks_by_pool<'de, D: Deserializer<'de>>( + de: D, +) -> Result>, D::Error> { + let entries = Vec::::deserialize(de)?; + let mut out = HashMap::with_capacity(entries.len()); + for IndexerPoolTicks { pool, ticks } in entries { + if out.insert(pool, ticks).is_some() { + return Err(de::Error::custom(format!( + "pool-indexer returned duplicate ticks for pool {pool:#x}", + ))); + } + } + Ok(out) +} + +#[serde_as] +#[derive(Clone, Deserialize)] +struct IndexerTick { + tick_idx: i32, + #[serde_as(as = "DisplayFromStr")] + liquidity_net: BigInt, +} + +/// Drops pools missing either token's `decimals`. Treating missing as `0` +/// would mis-scale prices, so we fail closed and wait for the indexer's +/// decimals backfill. +/// +/// On a fresh deploy the backfill can take minutes and each page may +/// carry hundreds of unfilled pools, so we log a single `debug!` summary +/// per call. Steady-state this should be a no-op. +fn drop_pools_missing_decimals(mut pools: Vec) -> Vec { + let total = pools.len(); + pools.retain(|p| p.token0.decimals.is_some() && p.token1.decimals.is_some()); + let dropped = total - pools.len(); + if dropped > 0 { + tracing::debug!( + dropped, + total, + "pool-indexer returned pools missing token decimals; filtered out", + ); + } + pools +} + +impl IndexerPool { + /// Stamps the envelope's `block_number` onto the pool so the driver + /// can anchor per-pool event replay. Bails if `decimals` is missing — + /// run [`drop_pools_missing_decimals`] first. + fn into_pool_data(self, block_number: u64) -> Result { + let token0_decimals = self + .token0 + .decimals + .context("BUG: missing token0 decimals after drop_pools_missing_decimals filter")?; + let token1_decimals = self + .token1 + .decimals + .context("BUG: missing token1 decimals after drop_pools_missing_decimals filter")?; + Ok(PoolData { + id: self.id, + token0: Token { + id: self.token0.id, + decimals: token0_decimals, + }, + token1: Token { + id: self.token1.id, + decimals: token1_decimals, + }, + fee_tier: self.fee_tier, + liquidity: self.liquidity, + sqrt_price: self.sqrt_price, + tick: BigInt::from(self.tick), + ticks: None, + block_number, + }) + } +} + +impl IndexerTick { + fn into_tick_data(self, pool_address: Address) -> TickData { + TickData { + tick_idx: BigInt::from(self.tick_idx), + liquidity_net: self.liquidity_net, + pool_address, + } + } +} + +impl PoolIndexerClient { + /// Polls `/pools?limit=1` every [`WAIT_UNTIL_POLL_INTERVAL`] until the + /// envelope reports `block_number >= target_block`. Returns + /// immediately if already there; bails after [`Self::wait_until_timeout`]. + /// + /// `503` is treated as "still bootstrapping" and the loop keeps + /// polling. Other non-2xx statuses propagate as errors. + async fn wait_until(&self, target_block: u64) -> Result<()> { + let deadline = std::time::Instant::now() + self.wait_until_timeout; + let mut last_observed: Option = None; + let mut interval = tokio::time::interval(WAIT_UNTIL_POLL_INTERVAL); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); + loop { + interval.tick().await; + match self.fetch_pools_page(1, None).await? { + None => tracing::debug!( + %target_block, + "pool-indexer not ready yet (503); waiting", + ), + Some(probe) => { + if probe.block_number >= target_block { + return Ok(()); + } + last_observed = Some(probe.block_number); + tracing::debug!( + indexer_block = probe.block_number, + %target_block, + "pool-indexer not yet at target block; waiting", + ); + } + } + if std::time::Instant::now() >= deadline { + anyhow::bail!( + "pool-indexer wait_until exceeded {:?} waiting for block {target_block}; last \ + observed indexer block: {last_observed:?}", + self.wait_until_timeout, + ); + } + } + } + + /// `GET /pools?limit=N[&after=cursor]`. `None` means 503 (still + /// bootstrapping) — the caller decides whether to retry or fail. + async fn fetch_pools_page( + &self, + limit: u64, + cursor: Option<&str>, + ) -> Result> { + let mut url = self.path("pools"); + url.query_pairs_mut() + .append_pair("limit", &limit.to_string()); + if let Some(c) = cursor { + url.query_pairs_mut().append_pair("after", c); + } + let resp = self.http.get(url).send().await.context("GET /pools")?; + if resp.status() == reqwest::StatusCode::SERVICE_UNAVAILABLE { + return Ok(None); + } + let page: PoolsResponse = resp + .error_for_status() + .context("/pools HTTP status")? + .json() + .await + .context("/pools body")?; + Ok(Some(page)) + } +} + +#[async_trait] +impl V3PoolDataSource for PoolIndexerClient { + async fn get_registered_pools(&self, target_block: u64) -> Result { + self.wait_until(target_block).await?; + // The indexer can advance between pages, so each pool carries the + // block of the page it arrived in. The envelope's + // `fetched_block_number` is the first page's block — a + // conservative lower bound for callers that only need a global + // "fresh as of" anchor. + let mut cursor: Option = None; + let mut pools: Vec = Vec::new(); + let mut fetched_block_number: Option = None; + loop { + let page = self + .fetch_pools_page(LIST_PAGE_SIZE, cursor.as_deref()) + .await? + .context("pool-indexer returned 503 after wait_until")?; + + let page_block = page.block_number; + fetched_block_number.get_or_insert(page_block); + // Drop zero-liquidity pools (matches the subgraph backend's + // filter, see `graph_api::get_pools`). + let mut liq_filtered = page.pools; + liq_filtered.retain(|p| !p.liquidity.is_zero()); + let filtered = drop_pools_missing_decimals(liq_filtered) + .into_iter() + .map(|p| p.into_pool_data(page_block)) + .collect::>>()?; + pools.extend(filtered); + match page.next_cursor { + Some(c) => cursor = Some(c), + None => break, + } + } + Ok(RegisteredPools { + fetched_block_number: fetched_block_number.context("pool-indexer returned no pages")?, + pools, + }) + } + + async fn get_pools_with_ticks_by_ids( + &self, + ids: &[Address], + target_block: u64, + ) -> Result { + self.wait_until(target_block).await?; + + if ids.is_empty() { + return Ok(PoolsWithTicks { + fetched_block_number: target_block, + pools: Vec::new(), + }); + } + + let mut out: Vec = Vec::with_capacity(ids.len()); + let mut fetched_block_number: Option = None; + for batch in ids.chunks(POOL_IDS_PER_REQUEST) { + let (pools_page, ticks_response) = self.fetch_batch_consistent(batch).await?; + + let batch_block = pools_page.block_number; + fetched_block_number.get_or_insert(batch_block); + for indexer_pool in pools_page.pools { + let pool_id = indexer_pool.id; + let mut pool = indexer_pool.into_pool_data(batch_block)?; + if let Some(ticks) = ticks_response.pools.get(&pool_id) { + pool.ticks = Some( + ticks + .iter() + .map(|t| t.clone().into_tick_data(pool_id)) + .collect(), + ); + } + out.push(pool); + } + } + Ok(PoolsWithTicks { + fetched_block_number: fetched_block_number.context( + "BUG: pool-indexer returned no batches for non-empty `ids` — empty short-circuits \ + above", + )?, + pools: out, + }) + } +} + +/// Capped at 3 — mismatches are rare and typically resolve on the next attempt. +const BATCH_CONSISTENCY_MAX_RETRIES: usize = 3; + +/// Wire-form `pools/by-ids` response. The caller stamps `block_number` +/// onto each `PoolData` during conversion. +struct PoolsByIdsPage { + block_number: u64, + pools: Vec, +} + +fn ids_param(ids: &[Address]) -> String { + ids.iter().map(const_hex::encode_prefixed).join(",") +} + +impl PoolIndexerClient { + /// Fetches pools + ticks for `ids` at a single indexer block. The two + /// HTTP endpoints can drift if a chunk commits between them; we retry + /// on mismatch up to [`BATCH_CONSISTENCY_MAX_RETRIES`]. On success + /// both responses share a `block_number`. + async fn fetch_batch_consistent( + &self, + ids: &[Address], + ) -> Result<(PoolsByIdsPage, BulkTicksResponse)> { + for attempt in 0..BATCH_CONSISTENCY_MAX_RETRIES { + let (pools_page, ticks_response) = futures::try_join!( + fetch_pools_by_ids(self, ids), + fetch_ticks_by_pool_ids(self, ids), + )?; + if pools_page.block_number == ticks_response.block_number { + return Ok((pools_page, ticks_response)); + } + tracing::warn!( + attempt, + pools_block = pools_page.block_number, + ticks_block = ticks_response.block_number, + "pool-indexer block mismatch between pools and ticks responses; retrying", + ); + } + anyhow::bail!( + "pool-indexer returned mismatched pools-vs-ticks blocks after \ + {BATCH_CONSISTENCY_MAX_RETRIES} retries" + ) + } +} + +async fn fetch_pools_by_ids(client: &PoolIndexerClient, ids: &[Address]) -> Result { + let mut url = client.path("pools/by-ids"); + url.query_pairs_mut() + .append_pair("pool_ids", &ids_param(ids)); + let resp: PoolsResponse = client + .http + .get(url) + .send() + .await + .with_context(|| format!("GET /pools/by-ids?pool_ids <{} ids>", ids.len()))? + .error_for_status() + .context("pools-by-ids HTTP status")? + .json() + .await + .context("pools-by-ids body")?; + Ok(PoolsByIdsPage { + block_number: resp.block_number, + pools: drop_pools_missing_decimals(resp.pools), + }) +} + +async fn fetch_ticks_by_pool_ids( + client: &PoolIndexerClient, + ids: &[Address], +) -> Result { + let mut url = client.path("pools/ticks"); + url.query_pairs_mut() + .append_pair("pool_ids", &ids_param(ids)); + client + .http + .get(url) + .send() + .await + .context("GET /pools/ticks")? + .error_for_status() + .context("bulk-ticks HTTP status")? + .json() + .await + .context("bulk-ticks body") +} diff --git a/crates/shared/src/sources/uniswap_v3_pair_provider.rs b/crates/liquidity-sources/src/uniswap_v3_pair_provider.rs similarity index 60% rename from crates/shared/src/sources/uniswap_v3_pair_provider.rs rename to crates/liquidity-sources/src/uniswap_v3_pair_provider.rs index 8568613bb5..4956d690ce 100644 --- a/crates/shared/src/sources/uniswap_v3_pair_provider.rs +++ b/crates/liquidity-sources/src/uniswap_v3_pair_provider.rs @@ -1,8 +1,12 @@ -use {ethcontract::H160, hex_literal::hex, model::TokenPair, web3::signing::keccak256}; +use { + alloy::primitives::{Address, keccak256}, + hex_literal::hex, + model::TokenPair, +}; /// Calculates deterministic Uniswapv3 pool address. /// https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/PoolAddress.sol -pub fn pair_address(factory: &H160, pair: &TokenPair, fee: u32) -> H160 { +pub fn pair_address(factory: &Address, pair: &TokenPair, fee: u32) -> Address { const INIT: [u8; 32] = hex!("e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"); let (token0, token1) = pair.get(); @@ -10,30 +14,30 @@ pub fn pair_address(factory: &H160, pair: &TokenPair, fee: u32) -> H160 { buffer[12..32].copy_from_slice(token0.as_slice()); buffer[44..64].copy_from_slice(token1.as_slice()); buffer[92..96].copy_from_slice(&fee.to_be_bytes()); - let hash = keccak256(&buffer); + let hash = keccak256(buffer); let mut buffer = [0u8; 1 + 20 + 32 + 32]; buffer[0] = 0xff; - buffer[1..21].copy_from_slice(&factory.0); - buffer[21..53].copy_from_slice(&hash); + buffer[1..21].copy_from_slice(factory.as_slice()); + buffer[21..53].copy_from_slice(hash.as_slice()); buffer[53..85].copy_from_slice(&INIT); - let hash = keccak256(&buffer); + let hash = keccak256(buffer); - H160::from_slice(&hash[12..]) + Address::from_slice(&hash[12..]) } #[cfg(test)] mod tests { - use super::*; + use {super::*, alloy::primitives::address}; #[test] fn mainnet_pool() { // https://v3.info.uniswap.org/home#/pools/0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8 let result = pair_address( - &addr!("1F98431c8aD98523631AE4a59f267346ea31F984"), + &address!("1F98431c8aD98523631AE4a59f267346ea31F984"), &TokenPair::new(testlib::tokens::WETH, testlib::tokens::USDC).unwrap(), 3000, ); - assert_eq!(result, addr!("8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8")); + assert_eq!(result, address!("8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8")); } } diff --git a/crates/shared/src/zeroex_api.rs b/crates/liquidity-sources/src/zeroex.rs similarity index 83% rename from crates/shared/src/zeroex_api.rs rename to crates/liquidity-sources/src/zeroex.rs index 139c05103f..663fe5baea 100644 --- a/crates/shared/src/zeroex_api.rs +++ b/crates/liquidity-sources/src/zeroex.rs @@ -5,13 +5,12 @@ //! use { + alloy::primitives::{Address, B256, U256, address}, anyhow::{Context, Result}, chrono::{DateTime, NaiveDateTime, TimeZone, Utc}, - derivative::Derivative, - ethcontract::{H160, H256, U256}, ethrpc::block_stream::{BlockInfo, CurrentBlockWatcher}, number::serialization::HexOrDecimalU256, - observe::tracing::tracing_headers, + observe::tracing::distributed::headers::tracing_headers, reqwest::{ Client, ClientBuilder, @@ -30,11 +29,16 @@ use { const ORDERS_MAX_PAGE_SIZE: usize = 1_000; -// The `Display` implementation for `H160` unfortunately does not print -// the full address ad instead uses ellipsis (e.g. "0xeeee…eeee"). This -// helper just works around that. -fn addr2str(addr: H160) -> String { - format!("{addr:#x}") +/// Join a path with a URL, ensuring that there is only one slash between them. +fn join_url(url: &Url, mut path: &str) -> Url { + let mut url = url.to_string(); + while url.ends_with('/') { + url.pop(); + } + while path.starts_with('/') { + path = &path[1..] + } + Url::parse(&format!("{url}/{path}")).unwrap() } /// 0x API orders query parameters. @@ -47,30 +51,31 @@ pub struct OrdersQuery { /// The address of the party that is allowed to fill the order. /// If set to a specific party, the order cannot be filled by anyone else. /// If left unspecified, anyone can fill the order. - pub taker: Option, + pub taker: Option
, /// Allows the maker to enforce that the order flow through some /// additional logic before it can be filled (e.g., a KYC whitelist). - pub sender: Option, + pub sender: Option
, /// Address of the contract where the transaction should be sent, /// usually this is the 0x exchange proxy contract. - pub verifying_contract: Option, + pub verifying_contract: Option
, } impl OrdersQuery { /// Encodes the orders query as a url with parameters. fn format_url(&self, base_url: &Url) -> Url { - let mut url = crate::url::join(base_url, "/orderbook/v1/orders"); + let mut url = join_url(base_url, "/orderbook/v1/orders"); if let Some(taker) = self.taker { - url.query_pairs_mut().append_pair("taker", &addr2str(taker)); + url.query_pairs_mut() + .append_pair("taker", &taker.to_string()); } if let Some(sender) = self.sender { url.query_pairs_mut() - .append_pair("sender", &addr2str(sender)); + .append_pair("sender", &sender.to_string()); } if let Some(verifying_contract) = self.verifying_contract { url.query_pairs_mut() - .append_pair("verifyingContract", &addr2str(verifying_contract)); + .append_pair("verifyingContract", &verifying_contract.to_string()); } url @@ -80,19 +85,17 @@ impl OrdersQuery { impl Default for OrdersQuery { fn default() -> Self { Self { - taker: Some(H160::zero()), - sender: Some(H160::zero()), + taker: Some(Address::ZERO), + sender: Some(Address::ZERO), verifying_contract: Some(DefaultZeroExApi::DEFAULT_VERIFICATION_CONTRACT), } } } #[serde_as] -#[derive(Debug, Derivative, Clone, Deserialize, Serialize, Eq, PartialEq)] -#[derivative(Default)] +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct OrderMetadata { - #[derivative(Default(value = "DateTime::::MIN_UTC"))] pub created_at: DateTime, #[serde(with = "bytes_hex")] pub order_hash: Vec, @@ -100,66 +103,96 @@ pub struct OrderMetadata { pub remaining_fillable_taker_amount: u128, } +impl Default for OrderMetadata { + fn default() -> Self { + Self { + created_at: DateTime::::MIN_UTC, + order_hash: Default::default(), + remaining_fillable_taker_amount: Default::default(), + } + } +} + #[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Default)] #[serde(rename_all = "camelCase")] pub struct ZeroExSignature { - pub r: H256, - pub s: H256, + pub r: B256, + pub s: B256, pub v: u8, pub signature_type: u8, } #[serde_as] -#[derive(Debug, Derivative, Clone, Deserialize, Serialize, Eq, PartialEq)] -#[derivative(Default)] +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Order { /// The ID of the Ethereum chain where the `verifying_contract` is located. pub chain_id: u64, /// Timestamp in seconds of when the order expires. Expired orders cannot be /// filled. - #[derivative(Default(value = "NaiveDateTime::MAX.and_utc().timestamp() as u64"))] #[serde_as(as = "DisplayFromStr")] pub expiry: u64, /// The address of the entity that will receive any fees stipulated by the /// order. This is typically used to incentivize off-chain order relay. - pub fee_recipient: H160, + pub fee_recipient: Address, /// The address of the party that creates the order. The maker is also one /// of the two parties that will be involved in the trade if the order /// gets filled. - pub maker: H160, + pub maker: Address, /// The amount of `maker_token` being sold by the maker. #[serde_as(as = "DisplayFromStr")] pub maker_amount: u128, /// The address of the ERC20 token the maker is selling to the taker. - pub maker_token: H160, + pub maker_token: Address, /// The staking pool to attribute the 0x protocol fee from this order. Set /// to zero to attribute to the default pool, not owned by anyone. - pub pool: H256, + pub pool: B256, /// A value that can be used to guarantee order uniqueness. Typically it is /// set to a random number. #[serde_as(as = "HexOrDecimalU256")] pub salt: U256, /// It allows the maker to enforce that the order flow through some /// additional logic before it can be filled (e.g., a KYC whitelist). - pub sender: H160, + pub sender: Address, /// The signature of the signed order. pub signature: ZeroExSignature, /// The address of the party that is allowed to fill the order. If set to a /// specific party, the order cannot be filled by anyone else. If left /// unspecified, anyone can fill the order. - pub taker: H160, + pub taker: Address, /// The amount of `taker_token` being sold by the taker. #[serde_as(as = "DisplayFromStr")] pub taker_amount: u128, /// The address of the ERC20 token the taker is selling to the maker. - pub taker_token: H160, + pub taker_token: Address, /// Amount of takerToken paid by the taker to the feeRecipient. #[serde_as(as = "DisplayFromStr")] pub taker_token_fee_amount: u128, /// Address of the contract where the transaction should be sent, usually /// this is the 0x exchange proxy contract. - pub verifying_contract: H160, + pub verifying_contract: Address, +} + +impl Default for Order { + fn default() -> Self { + Self { + chain_id: Default::default(), + expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, + fee_recipient: Default::default(), + maker: Default::default(), + maker_amount: Default::default(), + maker_token: Default::default(), + pool: Default::default(), + salt: Default::default(), + sender: Default::default(), + signature: Default::default(), + taker: Default::default(), + taker_amount: Default::default(), + taker_token: Default::default(), + taker_token_fee_amount: Default::default(), + verifying_contract: Default::default(), + } + } } #[derive(Debug, Default, Clone, Deserialize, Serialize, Eq, PartialEq)] @@ -199,7 +232,7 @@ impl OrderRecord { // `scaled_maker_amount` is at most as big as `maker_amount` which already fits // in an u128 - Ok(scaled_maker_amount.as_u128()) + Ok(u128::try_from(scaled_maker_amount)?) } } @@ -237,8 +270,8 @@ impl DefaultZeroExApi { pub const DEFAULT_URL: &'static str = "https://api.0x.org/"; /// Default 0x verifying contract. /// The currently latest 0x v4 contract. - pub const DEFAULT_VERIFICATION_CONTRACT: H160 = - addr!("Def1C0ded9bec7F1a1670819833240f027b25EfF"); + pub const DEFAULT_VERIFICATION_CONTRACT: Address = + address!("Def1C0ded9bec7F1a1670819833240f027b25EfF"); /// Create a new 0x HTTP API client with the specified base URL. pub fn new( @@ -395,7 +428,7 @@ impl DefaultZeroExApi { self.block_stream.borrow().hash.to_string(), ); }; - if let Some(id) = observe::distributed_tracing::request_id::from_current_span() { + if let Some(id) = observe::tracing::distributed::request_id::from_current_span() { request = request.header("X-REQUEST-ID", id); } @@ -456,7 +489,7 @@ impl Metrics { mod tests { use { super::*, - crate::addr, + alloy::primitives::{address, b256}, chrono::{DateTime, NaiveDate}, }; @@ -548,38 +581,42 @@ mod tests { Order { chain_id: 1u64, expiry: 1646463524u64, - fee_recipient: addr!("86003b044f70dac0abc80ac8957305b6370893ed"), - maker: addr!("683b2388d719e98874d1f9c16b42a7bb498efbeb"), + fee_recipient: address!("86003b044f70dac0abc80ac8957305b6370893ed"), + maker: address!("683b2388d719e98874d1f9c16b42a7bb498efbeb"), maker_amount: 500000000u128, - maker_token: addr!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), - pool: H256::zero(), - salt: 1645858724.into(), - sender: H160::zero(), + maker_token: address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), + pool: B256::ZERO, + salt: U256::from(1645858724), + sender: Address::ZERO, signature: ZeroExSignature { signature_type: 3, - r: H256::from_slice( - &const_hex::decode("db60e4fa2b4f2ee073d88eed3502149ba2231d699bc5d92d5627dcd21f915237") - .unwrap() + r: b256!( + "db60e4fa2b4f2ee073d88eed3502149ba2231d699bc5d92d5627dcd21f915237" ), - s: H256::from_slice( - &const_hex::decode("4cb1e9c15788b86d5187b99c0d929ad61d2654c242095c26f9ace17e64aca0fd") - .unwrap() + s: b256!( + "4cb1e9c15788b86d5187b99c0d929ad61d2654c242095c26f9ace17e64aca0fd" ), v: 28u8, }, - taker: H160::zero(), + taker: Address::ZERO, taker_amount: 262467000000000000u128, - taker_token: addr!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), + taker_token: address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), taker_token_fee_amount: 0u128, - verifying_contract: addr!("def1c0ded9bec7f1a1670819833240f027b25eff"), + verifying_contract: address!("def1c0ded9bec7f1a1670819833240f027b25eff"), }, OrderMetadata { - order_hash: - const_hex::decode( - "003427369d4c2a6b0aceeb7b315bb9a6086bc6fc4c887aa51efc73b662c9d127" - ).unwrap(), + order_hash: const_hex::decode( + "003427369d4c2a6b0aceeb7b315bb9a6086bc6fc4c887aa51efc73b662c9d127" + ) + .unwrap(), remaining_fillable_taker_amount: 262467000000000000u128, - created_at: DateTime::from_naive_utc_and_offset(NaiveDate::from_ymd_opt(2022, 2, 26).unwrap().and_hms_nano_opt(6, 59, 0, 440_000_000).unwrap(), Utc), + created_at: DateTime::from_naive_utc_and_offset( + NaiveDate::from_ymd_opt(2022, 2, 26) + .unwrap() + .and_hms_nano_opt(6, 59, 0, 440_000_000) + .unwrap(), + Utc + ), }, )], } diff --git a/crates/model/Cargo.toml b/crates/model/Cargo.toml index 298f574a45..11a18ef36c 100644 --- a/crates/model/Cargo.toml +++ b/crates/model/Cargo.toml @@ -9,24 +9,25 @@ license = "MIT OR Apache-2.0" doctest = false [dependencies] -alloy = { workspace = true } +alloy-primitives = { workspace = true, features = ["rand"] } +alloy-signer = { workspace = true } +alloy-signer-local = { workspace = true } +alloy-sol-types = { workspace = true } anyhow = { workspace = true } app-data = { workspace = true } bigdecimal = { workspace = true } bytes-hex = { workspace = true } -chrono = { workspace = true, features = ["serde", "clock"] } +chrono = { workspace = true, features = ["clock", "serde"] } const-hex = { workspace = true } derive_more = { workspace = true } hex-literal = { workspace = true } num = { workspace = true } number = { workspace = true } -primitive-types = { workspace = true } -secp256k1 = { workspace = true } serde = { workspace = true } +serde-ext = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } strum = { workspace = true } -web3 = { workspace = true, features = ["signing"] } [dev-dependencies] maplit = { workspace = true } diff --git a/crates/model/src/debug_report.rs b/crates/model/src/debug_report.rs new file mode 100644 index 0000000000..21c9cabd61 --- /dev/null +++ b/crates/model/src/debug_report.rs @@ -0,0 +1,148 @@ +use { + crate::order::{Order, OrderUid}, + alloy_primitives::{Address, B256}, + bigdecimal::BigDecimal, + chrono::{DateTime, Utc}, + serde::Serialize, + serde_with::{DisplayFromStr, serde_as}, + std::collections::HashMap, +}; + +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct DebugReport { + pub order_uid: OrderUid, + pub order: Order, + pub events: Vec, + pub auctions: Vec, + pub trades: Vec, +} + +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct Event { + pub label: String, + pub timestamp: DateTime, + #[serde(skip_serializing_if = "Option::is_none")] + pub reason: Option, +} + +#[serde_as] +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct Auction { + pub id: i64, + pub block: i64, + pub deadline: i64, + #[serde_as(as = "HashMap<_, DisplayFromStr>")] + pub native_prices: HashMap, + pub proposed_solutions: Vec, + pub executions: Vec, + pub settlement_attempts: Vec, + pub fee_policies: Vec, +} + +#[serde_as] +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct ProposedSolution { + pub solution_uid: i64, + pub ranking: i64, + pub solver: Address, + pub is_winner: bool, + pub filtered_out: bool, + #[serde_as(as = "DisplayFromStr")] + pub score: BigDecimal, + #[serde_as(as = "DisplayFromStr")] + pub executed_sell: BigDecimal, + #[serde_as(as = "DisplayFromStr")] + pub executed_buy: BigDecimal, +} + +#[serde_as] +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct Execution { + #[serde_as(as = "DisplayFromStr")] + pub executed_fee: BigDecimal, + pub executed_fee_token: Address, + pub block_number: i64, + pub protocol_fees: Vec, +} + +#[serde_as] +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct ProtocolFee { + pub token: Address, + #[serde_as(as = "DisplayFromStr")] + pub amount: BigDecimal, +} + +#[serde_as] +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct Trade { + pub block_number: i64, + pub log_index: i64, + #[serde_as(as = "DisplayFromStr")] + pub buy_amount: BigDecimal, + #[serde_as(as = "DisplayFromStr")] + pub sell_amount: BigDecimal, + #[serde_as(as = "DisplayFromStr")] + pub sell_amount_before_fees: BigDecimal, + #[serde(skip_serializing_if = "Option::is_none")] + pub tx_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub auction_id: Option, +} + +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct SettlementAttempt { + pub solver: Address, + pub solution_uid: i64, + pub start_timestamp: DateTime, + #[serde(skip_serializing_if = "Option::is_none")] + pub end_timestamp: Option>, + pub start_block: i64, + #[serde(skip_serializing_if = "Option::is_none")] + pub end_block: Option, + pub deadline_block: i64, + #[serde(skip_serializing_if = "Option::is_none")] + pub outcome: Option, +} + +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub struct FeePolicy { + pub kind: FeePolicyKind, + #[serde(skip_serializing_if = "Option::is_none")] + pub surplus_factor: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub surplus_max_volume_factor: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub volume_factor: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub price_improvement_factor: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub price_improvement_max_volume_factor: Option, +} + +#[derive(Debug, Serialize)] +#[cfg_attr(any(test, feature = "e2e"), derive(serde::Deserialize))] +#[serde(rename_all = "camelCase")] +pub enum FeePolicyKind { + Surplus, + Volume, + PriceImprovement, +} diff --git a/crates/model/src/fee_policy.rs b/crates/model/src/fee_policy.rs index 68f1f6fa45..72c5c5c1d5 100644 --- a/crates/model/src/fee_policy.rs +++ b/crates/model/src/fee_policy.rs @@ -1,5 +1,5 @@ use { - alloy::primitives::{Address, U256}, + alloy_primitives::{Address, U256}, number::serialization::HexOrDecimalU256, serde::Serialize, serde_with::serde_as, diff --git a/crates/model/src/interaction.rs b/crates/model/src/interaction.rs index 67a6d0f449..1cdbd7c021 100644 --- a/crates/model/src/interaction.rs +++ b/crates/model/src/interaction.rs @@ -1,5 +1,5 @@ use { - alloy::primitives::{Address, U256}, + alloy_primitives::{Address, U256}, number::serialization::HexOrDecimalU256, serde::{Deserialize, Serialize}, serde_with::serde_as, diff --git a/crates/model/src/lib.rs b/crates/model/src/lib.rs index 76dd42bc95..d62f1b9c67 100644 --- a/crates/model/src/lib.rs +++ b/crates/model/src/lib.rs @@ -1,5 +1,6 @@ //! Contains models that are shared between the orderbook and the solver. +pub mod debug_report; pub mod fee_policy; pub mod interaction; pub mod order; @@ -11,14 +12,10 @@ pub mod time; pub mod trade; use { - alloy::primitives::Address, + alloy_primitives::{Address, U256}, + alloy_sol_types::Eip712Domain, const_hex::{FromHex, FromHexError}, - primitive_types::H160, - std::{fmt, sync::LazyLock}, - web3::{ - ethabi::{Token, encode}, - signing, - }, + std::fmt, }; pub type AuctionId = i64; @@ -116,29 +113,16 @@ impl std::fmt::Debug for DomainSeparator { } impl DomainSeparator { - pub fn new(chain_id: u64, contract_address: H160) -> Self { - /// The EIP-712 domain name used for computing the domain separator. - static DOMAIN_NAME: LazyLock<[u8; 32]> = - LazyLock::new(|| signing::keccak256(b"Gnosis Protocol")); - - /// The EIP-712 domain version used for computing the domain separator. - static DOMAIN_VERSION: LazyLock<[u8; 32]> = LazyLock::new(|| signing::keccak256(b"v2")); - - /// The EIP-712 domain type used computing the domain separator. - static DOMAIN_TYPE_HASH: LazyLock<[u8; 32]> = LazyLock::new(|| { - signing::keccak256( - b"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)", - ) - }); - let abi_encode_string = encode(&[ - Token::Uint((*DOMAIN_TYPE_HASH).into()), - Token::Uint((*DOMAIN_NAME).into()), - Token::Uint((*DOMAIN_VERSION).into()), - Token::Uint(chain_id.into()), - Token::Address(contract_address), - ]); + pub fn new(chain_id: u64, contract_address: Address) -> Self { + let domain = Eip712Domain { + name: Some("Gnosis Protocol".into()), + version: Some("v2".into()), + chain_id: Some(U256::from(chain_id)), + verifying_contract: Some(contract_address), + salt: None, + }; - DomainSeparator(signing::keccak256(abi_encode_string.as_slice())) + DomainSeparator(domain.separator().into()) } } @@ -146,6 +130,7 @@ impl DomainSeparator { mod tests { use { super::*, + alloy_primitives::address, hex_literal::hex, std::{cmp::Ordering, str::FromStr}, }; @@ -162,7 +147,7 @@ mod tests { #[test] fn domain_separator_sepolia() { - let contract_address: H160 = hex!("9008D19f58AAbD9eD0D60971565AA8510560ab41").into(); // new deployment + let contract_address = address!("9008D19f58AAbD9eD0D60971565AA8510560ab41"); // new deployment let chain_id: u64 = 11155111; let domain_separator_sepolia = DomainSeparator::new(chain_id, contract_address); // domain separator is taken from Sepolia deployment at address diff --git a/crates/model/src/order.rs b/crates/model/src/order.rs index 6956711176..5243118a99 100644 --- a/crates/model/src/order.rs +++ b/crates/model/src/order.rs @@ -9,7 +9,8 @@ use { quote::QuoteId, signature::{self, EcdsaSignature, EcdsaSigningScheme, Signature}, }, - alloy::primitives::{Address, U512}, + alloy_primitives::{Address, B256, U256, U512, b256, keccak256}, + alloy_signer_local::PrivateKeySigner, anyhow::{Result, anyhow}, app_data::{AppDataHash, hash_full_app_data}, bigdecimal::BigDecimal, @@ -18,7 +19,6 @@ use { hex_literal::hex, num::BigUint, number::serialization::HexOrDecimalU256, - primitive_types::{H160, H256, U256}, serde::{Deserialize, Deserializer, Serialize, Serializer, de}, serde_with::{DisplayFromStr, serde_as}, std::{ @@ -27,12 +27,11 @@ use { str::FromStr, }, strum::{AsRefStr, EnumString, VariantNames}, - web3::signing::{self, Key, SecretKeyRef}, }; /// The flag denoting that an order is buying ETH (or the chain's native token). /// It is used in place of an actual buy token address in an order. -pub const BUY_ETH_ADDRESS: H160 = H160([0xee; 20]); +pub const BUY_ETH_ADDRESS: Address = Address::repeat_byte(0xee); #[derive(Eq, PartialEq, Clone, Debug, Default, Deserialize, Serialize)] pub struct Interactions { @@ -99,12 +98,12 @@ impl OrderBuilder { self } - pub fn with_sell_amount(mut self, sell_amount: alloy::primitives::U256) -> Self { + pub fn with_sell_amount(mut self, sell_amount: U256) -> Self { self.0.data.sell_amount = sell_amount; self } - pub fn with_buy_amount(mut self, buy_amount: alloy::primitives::U256) -> Self { + pub fn with_buy_amount(mut self, buy_amount: U256) -> Self { self.0.data.buy_amount = buy_amount; self } @@ -124,7 +123,7 @@ impl OrderBuilder { self } - pub fn with_fee_amount(mut self, fee_amount: alloy::primitives::U256) -> Self { + pub fn with_fee_amount(mut self, fee_amount: U256) -> Self { self.0.data.fee_amount = fee_amount; self } @@ -159,24 +158,25 @@ impl OrderBuilder { mut self, signing_scheme: EcdsaSigningScheme, domain: &DomainSeparator, - key: SecretKeyRef, + key: &PrivateKeySigner, ) -> Self { - self.0.metadata.owner = Address::new(key.address().0); - self.0.metadata.uid = self.0.data.uid(domain, &key.address()); + let owner = key.address(); + self.0.metadata.owner = owner; + self.0.metadata.uid = self.0.data.uid(domain, owner); self.0.signature = EcdsaSignature::sign(signing_scheme, domain, &self.0.data.hash_struct(), key) .to_signature(signing_scheme); self } - pub fn with_eip1271(mut self, owner: H160, signature: Vec) -> Self { - self.0.metadata.owner = Address::new(owner.0); + pub fn with_eip1271(mut self, owner: Address, signature: Vec) -> Self { + self.0.metadata.owner = owner; self.0.signature = Signature::Eip1271(signature); self } - pub fn with_presign(mut self, owner: H160) -> Self { - self.0.metadata.owner = Address::new(owner.0); + pub fn with_presign(mut self, owner: Address) -> Self { + self.0.metadata.owner = owner; self.0.signature = Signature::PreSign; self } @@ -204,9 +204,9 @@ pub struct OrderData { #[serde(default)] pub receiver: Option
, #[serde_as(as = "HexOrDecimalU256")] - pub sell_amount: alloy::primitives::U256, + pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] - pub buy_amount: alloy::primitives::U256, + pub buy_amount: U256, pub valid_to: u32, pub app_data: AppDataHash, /// Fees that will be taken in terms of `sell_token`. @@ -215,7 +215,7 @@ pub struct OrderData { /// and should not be settled on their own. /// This is 0 for limit orders as their fee gets taken from the surplus. #[serde_as(as = "HexOrDecimalU256")] - pub fee_amount: alloy::primitives::U256, + pub fee_amount: U256, pub kind: OrderKind, pub partially_fillable: bool, #[serde(default)] @@ -253,42 +253,26 @@ impl OrderData { hash_data[351] = self.partially_fillable as u8; hash_data[352..384].copy_from_slice(&self.sell_token_balance.as_bytes()); hash_data[384..416].copy_from_slice(&self.buy_token_balance.as_bytes()); - signing::keccak256(&hash_data) + *keccak256(hash_data) } pub fn token_pair(&self) -> Option { TokenPair::new(self.buy_token, self.sell_token) } - pub fn uid(&self, domain: &DomainSeparator, owner: &H160) -> OrderUid { + pub fn uid(&self, domain: &DomainSeparator, owner: Address) -> OrderUid { OrderUid::from_parts( - H256(super::signature::hashed_eip712_message( - domain, - &self.hash_struct(), - )), - *owner, + super::signature::hashed_eip712_message(domain, &self.hash_struct()), + owner, self.valid_to, ) } /// Checks if the order is a market order. pub fn within_market(&self, quote: QuoteAmounts) -> bool { - // Manual transformation because this crate doesn't have the conversiont trait - let mut buy_buffer = [0; 32]; - quote.buy.to_big_endian(&mut buy_buffer); - let quote_buy = alloy::primitives::U256::from_be_bytes(buy_buffer); - - let mut sell_buffer = [0; 32]; - quote.sell.to_big_endian(&mut sell_buffer); - let quote_sell = alloy::primitives::U256::from_be_bytes(sell_buffer); - - let mut fee_buffer = [0; 32]; - quote.fee.to_big_endian(&mut fee_buffer); - let quote_fee = alloy::primitives::U256::from_be_bytes(fee_buffer); - // Using let here because widening_mul isn't able to infer the result size - let lhs: U512 = (self.sell_amount + self.fee_amount).widening_mul(quote_buy); - let rhs: U512 = (quote_sell + quote_fee).widening_mul(self.buy_amount); + let lhs: U512 = (self.sell_amount + self.fee_amount).widening_mul(quote.buy); + let rhs: U512 = (quote.sell + quote.fee).widening_mul(self.buy_amount); lhs >= rhs } } @@ -309,13 +293,13 @@ pub struct QuoteAmounts { pub struct OrderCreation { // These fields are the same as in `OrderData`. /// The address of the token being sold. - pub sell_token: H160, + pub sell_token: Address, /// The address of the token being bought. - pub buy_token: H160, + pub buy_token: Address, /// The receiver of the `buy_token`. When this field is `None`, the receiver /// is the same as the owner. #[serde(default)] - pub receiver: Option, + pub receiver: Option
, /// The *maximum* amount of `sell_token`s that may be sold. #[serde_as(as = "HexOrDecimalU256")] pub sell_amount: U256, @@ -349,7 +333,7 @@ pub struct OrderCreation { /// /// In the EthFlow case, it will have the address of the EthFlow smart /// contract. - pub from: Option, + pub from: Option
, /// The owner's signature of the order's data. #[serde(flatten)] pub signature: Signature, @@ -358,30 +342,25 @@ pub struct OrderCreation { /// The order's AppData (can be an hash, the JSON body or both). #[serde(flatten)] pub app_data: OrderCreationAppData, + /// Should a transfer of the order's full balance be verified before + /// placement. + #[serde(default)] + pub full_balance_check: bool, } impl OrderCreation { /// Returns the order's data — i.e. the [`OrderCreation`] without /// the metadata: `signature`, `quote_id` and with the `app_data`'s hash. pub fn data(&self) -> OrderData { - let mut sell_amount_buffer = [0; 32]; - self.sell_amount.to_big_endian(&mut sell_amount_buffer); - - let mut buy_amount_buffer = [0; 32]; - self.buy_amount.to_big_endian(&mut buy_amount_buffer); - - let mut fee_amount_buffer = [0; 32]; - self.fee_amount.to_big_endian(&mut fee_amount_buffer); - OrderData { - sell_token: Address::new(self.sell_token.0), - buy_token: Address::new(self.buy_token.0), - receiver: self.receiver.map(|receiver| Address::new(receiver.0)), - sell_amount: alloy::primitives::U256::from_be_slice(&sell_amount_buffer), - buy_amount: alloy::primitives::U256::from_be_slice(&buy_amount_buffer), + sell_token: self.sell_token, + buy_token: self.buy_token, + receiver: self.receiver, + sell_amount: self.sell_amount, + buy_amount: self.buy_amount, valid_to: self.valid_to, app_data: self.app_data.hash(), - fee_amount: alloy::primitives::U256::from_be_slice(&fee_amount_buffer), + fee_amount: self.fee_amount, kind: self.kind, partially_fillable: self.partially_fillable, sell_token_balance: self.sell_token_balance, @@ -398,7 +377,7 @@ impl OrderCreation { mut self, signing_scheme: EcdsaSigningScheme, domain: &DomainSeparator, - key: SecretKeyRef, + key: &PrivateKeySigner, ) -> Self { self.signature = EcdsaSignature::sign(signing_scheme, domain, &self.data().hash_struct(), key) @@ -418,8 +397,8 @@ impl OrderCreation { pub fn verify_owner( &self, domain: &DomainSeparator, - app_data_signer: Option, - ) -> Result { + app_data_signer: Option
, + ) -> Result { let recovered = self .signature .recover(domain, &self.data().hash_struct()) @@ -509,8 +488,8 @@ impl OrderCreationAppData { #[derive(Debug)] pub struct AppdataFromMismatch { - pub from: H160, - pub app_data_signer: H160, + pub from: Address, + pub app_data_signer: Address, } #[derive(Debug)] @@ -537,15 +516,15 @@ impl OrderCancellations { pub fn hash_struct(&self) -> [u8; 32] { let mut encoded_uids = Vec::with_capacity(32 * self.order_uids.len()); for order_uid in &self.order_uids { - encoded_uids.extend_from_slice(&signing::keccak256(&order_uid.0)); + encoded_uids.extend_from_slice(keccak256(order_uid.0).as_slice()); } - let array_hash = signing::keccak256(&encoded_uids); + let array_hash = keccak256(&encoded_uids); let mut hash_data = [0u8; 64]; hash_data[0..32].copy_from_slice(&Self::TYPE_HASH); - hash_data[32..64].copy_from_slice(&array_hash); - signing::keccak256(&hash_data) + hash_data[32..64].copy_from_slice(array_hash.as_slice()); + *keccak256(hash_data) } } @@ -560,7 +539,7 @@ pub struct SignedOrderCancellations { } impl SignedOrderCancellations { - pub fn validate(&self, domain_separator: &DomainSeparator) -> Result { + pub fn validate(&self, domain_separator: &DomainSeparator) -> Result
{ Ok(self .signature .recover( @@ -585,12 +564,10 @@ impl Default for OrderCancellation { Self::for_order( OrderUid::default(), &DomainSeparator::default(), - SecretKeyRef::new( - &secp256k1::SecretKey::from_str( - "0000000000000000000000000000000000000000000000000000000000000001", - ) - .unwrap(), - ), + &PrivateKeySigner::from_bytes(&b256!( + "0000000000000000000000000000000000000000000000000000000000000001" + )) + .unwrap(), ) } } @@ -604,7 +581,7 @@ impl OrderCancellation { pub fn for_order( order_uid: OrderUid, domain_separator: &DomainSeparator, - key: SecretKeyRef, + key: &PrivateKeySigner, ) -> Self { let mut result = Self { order_uid, @@ -623,11 +600,11 @@ impl OrderCancellation { pub fn hash_struct(&self) -> [u8; 32] { let mut hash_data = [0u8; 64]; hash_data[0..32].copy_from_slice(&Self::TYPE_HASH); - hash_data[32..64].copy_from_slice(&signing::keccak256(&self.order_uid.0)); - signing::keccak256(&hash_data) + hash_data[32..64].copy_from_slice(keccak256(self.order_uid.0).as_slice()); + *keccak256(hash_data) } - pub fn validate(&self, domain_separator: &DomainSeparator) -> Result { + pub fn validate(&self, domain_separator: &DomainSeparator) -> Result
{ Ok(self .signature .recover(self.signing_scheme, domain_separator, &self.hash_struct())? @@ -647,7 +624,7 @@ pub struct CancellationPayload { #[serde(rename_all = "camelCase")] pub struct EthflowData { pub user_valid_to: i64, - pub refund_tx_hash: Option, + pub refund_tx_hash: Option, } // We still want to have the `is_refunded` field in the JSON response to stay @@ -663,7 +640,7 @@ impl ::serde::Serialize for EthflowData { #[serde(rename_all = "camelCase")] struct Extended { user_valid_to: i64, - refund_tx_hash: Option, + refund_tx_hash: Option, is_refunded: bool, } @@ -756,7 +733,12 @@ pub struct OrderMetadata { pub quote: Option, } -// uid as 56 bytes: 32 for orderDigest, 20 for ownerAddress and 4 for validTo +/// OrderUid is 56 bytes. When hex encoded as 0x prefixes Json string it is 116. +/// Chosen to be under the MAX_JSON_BODY_PAYLOAD size of 1024 * 16 +pub const ORDER_UID_LIMIT: usize = 128; + +/// Uid as 56 bytes: 32 for orderDigest, 20 for ownerAddress and 4 for validTo +/// Should be readable from prefixed and non-prefixed hex! #[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct OrderUid(pub [u8; 56]); @@ -769,20 +751,20 @@ impl OrderUid { } /// Create a UID from its parts. - pub fn from_parts(hash: H256, owner: H160, valid_to: u32) -> Self { + pub fn from_parts(hash: B256, owner: Address, valid_to: u32) -> Self { let mut uid = [0; 56]; - uid[0..32].copy_from_slice(hash.as_bytes()); - uid[32..52].copy_from_slice(owner.as_bytes()); + uid[0..32].copy_from_slice(hash.as_slice()); + uid[32..52].copy_from_slice(owner.as_slice()); uid[52..56].copy_from_slice(&valid_to.to_be_bytes()); Self(uid) } /// Splits an order UID into its parts. - pub fn parts(&self) -> (H256, H160, u32) { + pub fn parts(&self) -> (B256, Address, u32) { ( - H256::from_slice(&self.0[0..32]), - H160::from_slice(&self.0[32..52]), - u32::from_le_bytes(self.0[52..].try_into().unwrap()), + B256::from_slice(&self.0[0..32]), + Address::from_slice(&self.0[32..52]), + u32::from_be_bytes(self.0[52..].try_into().unwrap()), ) } } @@ -792,8 +774,7 @@ impl FromStr for OrderUid { fn from_str(s: &str) -> Result { let mut value = [0u8; 56]; - let s_without_prefix = s.strip_prefix("0x").unwrap_or(s); - const_hex::decode_to_slice(s_without_prefix, value.as_mut())?; + const_hex::decode_to_slice(s, value.as_mut())?; Ok(OrderUid(value)) } } @@ -848,11 +829,6 @@ impl<'de> Deserialize<'de> for OrderUid { where E: de::Error, { - let s = s.strip_prefix("0x").ok_or_else(|| { - de::Error::custom(format!( - "{s:?} can't be decoded as hex uid because it does not start with '0x'" - )) - })?; let mut value = [0u8; 56]; const_hex::decode_to_slice(s, value.as_mut()).map_err(|err| { de::Error::custom(format!("failed to decode {s:?} as hex uid: {err}")) @@ -1075,7 +1051,9 @@ pub struct OrderQuote { pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] pub buy_amount: U256, - pub solver: H160, + #[serde_as(as = "HexOrDecimalU256")] + pub fee_amount: U256, + pub solver: Address, pub verified: bool, pub metadata: serde_json::Value, } @@ -1085,19 +1063,19 @@ mod tests { use { super::*, crate::signature::{EcdsaSigningScheme, SigningScheme}, + alloy_primitives::{address, b256}, chrono::TimeZone, hex_literal::hex, maplit::hashset, - primitive_types::H256, - secp256k1::{PublicKey, Secp256k1, SecretKey}, serde_json::json, testlib::assert_json_matches, - web3::signing::keccak256, }; #[test] fn deserialization_and_back() { - let value = json!( + // Input JSON has v=0x01, which gets normalized to v=28 (0x1c) for Solidity + // ecrecover compatibility. Serialization then outputs v=0x1c. + let input_json = json!( { "creationDate": "1970-01-01T00:00:03Z", "owner": "0x0000000000000000000000000000000000000001", @@ -1134,6 +1112,7 @@ mod tests { }, "fullAppData": "123", }); + let signing_scheme = EcdsaSigningScheme::Eip712; let expected = Order { metadata: OrderMetadata { @@ -1144,9 +1123,9 @@ mod tests { available_balance: None, executed_buy_amount: BigUint::from_bytes_be(&[3]), executed_sell_amount: BigUint::from_bytes_be(&[5]), - executed_sell_amount_before_fees: 4.into(), - executed_fee_amount: 1.into(), - executed_fee: 1.into(), + executed_sell_amount_before_fees: U256::from(4), + executed_fee_amount: U256::from(1), + executed_fee: U256::from(1), executed_fee_token: Address::with_last_byte(10), invalidated: true, status: OrderStatus::Open, @@ -1158,101 +1137,183 @@ mod tests { sell_token: Address::with_last_byte(10), buy_token: Address::with_last_byte(9), receiver: Some(Address::with_last_byte(11)), - sell_amount: alloy::primitives::U256::ONE, - buy_amount: alloy::primitives::U256::ZERO, + sell_amount: U256::ONE, + buy_amount: U256::ZERO, valid_to: u32::MAX, app_data: AppDataHash(hex!( "6000000000000000000000000000000000000000000000000000000000000007" )), - fee_amount: alloy::primitives::U256::MAX, + fee_amount: U256::MAX, kind: OrderKind::Buy, partially_fillable: false, sell_token_balance: SellTokenSource::External, buy_token_balance: BuyTokenDestination::Internal, }, signature: EcdsaSignature { - v: 1, - r: H256::from_str( - "0200000000000000000000000000000000000000000000000000000000000003", - ) - .unwrap(), - s: H256::from_str( - "0400000000000000000000000000000000000000000000000000000000000005", - ) - .unwrap(), + // v=0x01 in input gets normalized to 28 for Solidity ecrecover compatibility + v: 28, + r: b256!("0200000000000000000000000000000000000000000000000000000000000003"), + s: b256!("0400000000000000000000000000000000000000000000000000000000000005"), } .to_signature(signing_scheme), interactions: Interactions::default(), }; - let deserialized: Order = serde_json::from_value(value.clone()).unwrap(); + + // After deserialization, v=0x01 becomes v=28 + let deserialized: Order = serde_json::from_value(input_json).unwrap(); assert_eq!(deserialized, expected); + + // Serialization outputs the normalized v=0x1c (28) + let expected_output_json = json!( + { + "creationDate": "1970-01-01T00:00:03Z", + "owner": "0x0000000000000000000000000000000000000001", + "uid": "0x1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + "availableBalance": null, + "executedBuyAmount": "3", + "executedSellAmount": "5", + "executedSellAmountBeforeFees": "4", + "executedFeeAmount": "1", + "invalidated": true, + "sellToken": "0x000000000000000000000000000000000000000a", + "buyToken": "0x0000000000000000000000000000000000000009", + "receiver": "0x000000000000000000000000000000000000000b", + "sellAmount": "1", + "buyAmount": "0", + "validTo": 4294967295u32, + "appData": "0x6000000000000000000000000000000000000000000000000000000000000007", + "feeAmount": "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "executedFee": "1", + "executedFeeToken": "0x000000000000000000000000000000000000000a", + "kind": "buy", + "class": "limit", + "partiallyFillable": false, + "signature": "0x02000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000005\ + 1c", + "signingScheme": "eip712", + "status": "open", + "settlementContract": "0x0000000000000000000000000000000000000002", + "sellTokenBalance": "external", + "buyTokenBalance": "internal", + "isLiquidityOrder": false, + "interactions": { + "pre": [], + "post": [], + }, + "fullAppData": "123", + }); let serialized = serde_json::to_value(expected).unwrap(); - assert_json_matches!(serialized, value); + assert_json_matches!(serialized, expected_output_json); } #[test] fn order_creation_serialization() { - let owner = H160([0xff; 20]); - for (signature, signing_scheme, from, signature_bytes) in [ - ( - Signature::default_with(SigningScheme::Eip712), - "eip712", - Some(owner), - "0x0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 00", - ), - ( - Signature::default_with(SigningScheme::EthSign), - "ethsign", - None, - "0x0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 00", - ), - (Signature::PreSign, "presign", Some(owner), "0x"), - ] { - let order = OrderCreation { - sell_token: H160([0x11; 20]), - buy_token: H160([0x22; 20]), - receiver: Some(H160([0x33; 20])), - sell_amount: 123.into(), - buy_amount: 456.into(), - valid_to: 1337, - app_data: OrderCreationAppData::Hash { - hash: AppDataHash([0x44; 32]), - }, - fee_amount: 789.into(), - kind: OrderKind::Sell, - partially_fillable: false, - sell_token_balance: SellTokenSource::Erc20, - buy_token_balance: BuyTokenDestination::Erc20, - from, - signature, - quote_id: Some(42), - }; - let order_json = json!({ - "sellToken": "0x1111111111111111111111111111111111111111", - "buyToken": "0x2222222222222222222222222222222222222222", - "receiver": "0x3333333333333333333333333333333333333333", - "sellAmount": "123", - "buyAmount": "456", - "validTo": 1337, - "appData": "0x4444444444444444444444444444444444444444444444444444444444444444", - "feeAmount": "789", - "kind": "sell", - "partiallyFillable": false, - "sellTokenBalance": "erc20", - "buyTokenBalance": "erc20", - "quoteId": 42, - "signingScheme": signing_scheme, - "signature": signature_bytes, - "from": from, - }); - - assert_json_matches!(json!(order), order_json); - assert_eq!(order, serde_json::from_value(order_json).unwrap()); - } + let owner = Address::repeat_byte(0xff); + + let template_order = OrderCreation { + sell_token: Address::repeat_byte(0x11), + buy_token: Address::repeat_byte(0x22), + receiver: Some(Address::repeat_byte(0x33)), + sell_amount: U256::from(123), + buy_amount: U256::from(456), + valid_to: 1337, + app_data: OrderCreationAppData::Hash { + hash: AppDataHash([0x44; 32]), + }, + fee_amount: U256::from(789), + kind: OrderKind::Sell, + partially_fillable: false, + sell_token_balance: SellTokenSource::Erc20, + buy_token_balance: BuyTokenDestination::Erc20, + from: Some(owner), + signature: Signature::PreSign, + quote_id: Some(42), + full_balance_check: false, + }; + + // Test PreSign round-trip (no signature normalization needed) + let presign_order = template_order.clone(); + let presign_json = json!({ + "sellToken": "0x1111111111111111111111111111111111111111", + "buyToken": "0x2222222222222222222222222222222222222222", + "receiver": "0x3333333333333333333333333333333333333333", + "sellAmount": "123", + "buyAmount": "456", + "validTo": 1337, + "appData": "0x4444444444444444444444444444444444444444444444444444444444444444", + "feeAmount": "789", + "kind": "sell", + "partiallyFillable": false, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "quoteId": 42, + "signingScheme": "presign", + "signature": "0x", + "from": owner, + "fullBalanceCheck": false + }); + assert_json_matches!(json!(presign_order), presign_json); + assert_eq!(presign_order, serde_json::from_value(presign_json).unwrap()); + + // Test ECDSA signature with v normalization. + // Input JSON has v=0x00, which normalizes to v=27 (0x1b). + let input_json_v0 = json!({ + "sellToken": "0x1111111111111111111111111111111111111111", + "buyToken": "0x2222222222222222222222222222222222222222", + "receiver": "0x3333333333333333333333333333333333333333", + "sellAmount": "123", + "buyAmount": "456", + "validTo": 1337, + "appData": "0x4444444444444444444444444444444444444444444444444444444444444444", + "feeAmount": "789", + "kind": "sell", + "partiallyFillable": false, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "quoteId": 42, + "signingScheme": "eip712", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 00", + "from": owner, + "fullBalanceCheck": false, + }); + let expected_order = OrderCreation { + signature: Signature::Eip712(EcdsaSignature { + r: B256::ZERO, + s: B256::ZERO, + v: 27, // normalized from v=0 + }), + ..template_order.clone() + }; + + // Deserialization normalizes v=0 to v=27 + let deserialized: OrderCreation = serde_json::from_value(input_json_v0).unwrap(); + assert_eq!(deserialized, expected_order); + + // Serialization outputs normalized v=0x1b + let output_json_v27 = json!({ + "sellToken": "0x1111111111111111111111111111111111111111", + "buyToken": "0x2222222222222222222222222222222222222222", + "receiver": "0x3333333333333333333333333333333333333333", + "sellAmount": "123", + "buyAmount": "456", + "validTo": 1337, + "appData": "0x4444444444444444444444444444444444444444444444444444444444444444", + "feeAmount": "789", + "kind": "sell", + "partiallyFillable": false, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "quoteId": 42, + "signingScheme": "eip712", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 1b", + "from": owner, + "fullBalanceCheck": false, + }); + assert_json_matches!(json!(expected_order), output_json_v27); } #[test] @@ -1306,7 +1367,7 @@ mod tests { let domain_separator = DomainSeparator(hex!( "74e0b11bd18120612556bae4578cfd3a254d7e2495f543c569a92ff5794d9b09" )); - let expected_owner = H160(hex!("70997970C51812dc3A010C7d01b50e0d17dc79C8")); + let expected_owner = address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"); for (signing_scheme, signature) in &[ ( @@ -1330,13 +1391,13 @@ mod tests { sell_token: hex!("0101010101010101010101010101010101010101").into(), buy_token: hex!("0202020202020202020202020202020202020202").into(), receiver: Some(hex!("0303030303030303030303030303030303030303").into()), - sell_amount: alloy::primitives::U256::from(0x0246ddf97976680000_u128), - buy_amount: alloy::primitives::U256::from(0xb98bc829a6f90000_u128), + sell_amount: U256::from(0x0246ddf97976680000_u128), + buy_amount: U256::from(0xb98bc829a6f90000_u128), valid_to: 0xffffffff, app_data: AppDataHash(hex!( "0000000000000000000000000000000000000000000000000000000000000000" )), - fee_amount: alloy::primitives::U256::from(0x0de0b6b3a7640000_u128), + fee_amount: U256::from(0x0de0b6b3a7640000_u128), kind: OrderKind::Sell, partially_fillable: false, sell_token_balance: SellTokenSource::Erc20, @@ -1359,18 +1420,18 @@ mod tests { let domain_separator = DomainSeparator(hex!( "74e0b11bd18120612556bae4578cfd3a254d7e2495f543c569a92ff5794d9b09" )); - let owner = hex!("70997970C51812dc3A010C7d01b50e0d17dc79C8").into(); + let owner = address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"); let order = OrderData { sell_token: hex!("0101010101010101010101010101010101010101").into(), buy_token: hex!("0202020202020202020202020202020202020202").into(), receiver: Some(hex!("0303030303030303030303030303030303030303").into()), - sell_amount: alloy::primitives::U256::from(0x0246ddf97976680000_u128), - buy_amount: alloy::primitives::U256::from(0xb98bc829a6f90000_u128), + sell_amount: U256::from(0x0246ddf97976680000_u128), + buy_amount: U256::from(0xb98bc829a6f90000_u128), valid_to: 0xffffffff, app_data: AppDataHash(hex!( "0000000000000000000000000000000000000000000000000000000000000000" )), - fee_amount: alloy::primitives::U256::from(0x0de0b6b3a7640000_u128), + fee_amount: U256::from(0x0de0b6b3a7640000_u128), kind: OrderKind::Sell, partially_fillable: false, sell_token_balance: SellTokenSource::Erc20, @@ -1378,7 +1439,7 @@ mod tests { }; assert_eq!( - order.uid(&domain_separator, &owner).0, + order.uid(&domain_separator, owner).0, hex!( "0e45d31fd31b28c26031cdd81b35a8938b2ccca2cc425fcf440fd3bfed1eede9 70997970c51812dc3a010c7d01b50e0d17dc79c8 @@ -1393,7 +1454,7 @@ mod tests { "f8a1143d44c67470a791201b239ff6b0ecc8910aa9682bebd08145f5fd84722b" )); - let expected_owner = H160(hex!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266")); + let expected_owner = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); let eip712_signature = hex!( "f2c69310a4dbcd78feabfd802df296ca4650681e01872f667251916ed3e9a2e14928382316607594a77c620e4bc4536e6fe145ee993a5ccc38fda929e86830231b" @@ -1410,7 +1471,7 @@ mod tests { order_uid: OrderUid(hex!( "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" )), - signature: EcdsaSignature::from_bytes(signature), + signature: EcdsaSignature::from_bytes(signature).unwrap(), signing_scheme: *signing_scheme, }; let owner = cancellation.validate(&domain_separator).unwrap(); @@ -1445,35 +1506,29 @@ mod tests { assert!(!order.contains_token_from(&hashset!(other_token))); } - pub fn h160_from_public_key(key: PublicKey) -> H160 { - let hash = keccak256(&key.serialize_uncompressed()[1..] /* cut '04' */); - H160::from_slice(&hash[12..]) - } - #[test] fn order_builder_signature_recovery() { - const PRIVATE_KEY: [u8; 32] = - hex!("0000000000000000000000000000000000000000000000000000000000000001"); - let sk = SecretKey::from_slice(&PRIVATE_KEY).unwrap(); - let public_key = PublicKey::from_secret_key(&Secp256k1::signing_only(), &sk); + const PRIVATE_KEY: B256 = B256::with_last_byte(1); + let signer = PrivateKeySigner::from_bytes(&PRIVATE_KEY).unwrap(); + let order = OrderBuilder::default() .with_sell_token(Address::ZERO) - .with_sell_amount(alloy::primitives::U256::from(100)) + .with_sell_amount(U256::from(100)) .with_buy_token(Address::ZERO) - .with_buy_amount(alloy::primitives::U256::from(80)) + .with_buy_amount(U256::from(80)) .with_valid_to(u32::MAX) .with_app_data([1u8; 32]) - .with_fee_amount(alloy::primitives::U256::from(1337)) + .with_fee_amount(U256::from(1337)) .with_partially_fillable(true) .with_sell_token_balance(SellTokenSource::External) .with_buy_token_balance(BuyTokenDestination::Internal) .with_creation_date(Utc.timestamp_opt(3, 0).unwrap()) - .with_presign(H160::from_low_u64_be(1)) + .with_presign(Address::with_last_byte(1)) .with_kind(OrderKind::Sell) .sign_with( EcdsaSigningScheme::Eip712, &DomainSeparator::default(), - SecretKeyRef::from(&sk), + &signer, ) .build(); @@ -1483,14 +1538,13 @@ mod tests { .unwrap() .unwrap(); - assert_eq!(recovered.signer, h160_from_public_key(public_key)); + assert_eq!(recovered.signer, signer.address()); } #[test] fn debug_order_data() { dbg!(Order::default()); } - #[test] fn order_cancellations_struct_hash() { // Generated with Ethers.js as a reference EIP-712 hashing impl. @@ -1508,4 +1562,25 @@ mod tests { assert_eq!(cancellations.hash_struct(), struct_hash); } } + + #[test] + fn order_uid_parts() { + let order_hash = B256::random(); + let user = Address::random(); + let valid_to = 12341234; + let uid = OrderUid::from_parts(order_hash, user, valid_to); + let parts = uid.parts(); + assert_eq!(order_hash, parts.0); + assert_eq!(user, parts.1); + assert_eq!(valid_to, parts.2); + + let uid = OrderUid::from_str("0x5668997bd3fb981d1b3ec44e8483e7c369756df47d10241c1c7a26fde4d1090e89984d17af2f18f8c54873c0de68a56cc5a23e0f695ba915").unwrap(); + let (order_hash, user, valid_to) = uid.parts(); + assert_eq!( + order_hash, + b256!("0x5668997bd3fb981d1b3ec44e8483e7c369756df47d10241c1c7a26fde4d1090e") + ); + assert_eq!(user, address!("0x89984d17af2f18f8c54873c0de68a56cc5a23e0f")); + assert_eq!(valid_to, 1767614741); + } } diff --git a/crates/model/src/quote.rs b/crates/model/src/quote.rs index 8e10f563c7..9d5f83e946 100644 --- a/crates/model/src/quote.rs +++ b/crates/model/src/quote.rs @@ -4,11 +4,12 @@ use { signature::SigningScheme, time, }, + alloy_primitives::{Address, U256}, anyhow::bail, app_data::AppDataHash, + bigdecimal::BigDecimal, chrono::{DateTime, Utc}, - number::{nonzero::U256 as NonZeroU256, serialization::HexOrDecimalU256}, - primitive_types::{H160, U256}, + number::{nonzero::NonZeroU256, serialization::HexOrDecimalU256}, serde::{ Deserialize, Deserializer, @@ -17,7 +18,7 @@ use { de, ser::{self, SerializeStruct as _}, }, - serde_with::serde_as, + serde_with::{DisplayFromStr, serde_as}, std::time::Duration, }; @@ -120,11 +121,11 @@ impl TryFrom for QuoteSigningScheme { #[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct OrderQuoteRequest { - pub from: H160, - pub sell_token: H160, - pub buy_token: H160, + pub from: Address, + pub sell_token: Address, + pub buy_token: Address, #[serde(skip_serializing_if = "Option::is_none")] - pub receiver: Option, + pub receiver: Option
, #[serde(flatten)] pub side: OrderQuoteSide, #[serde(flatten)] @@ -162,7 +163,7 @@ pub enum OrderQuoteSide { impl Default for OrderQuoteSide { fn default() -> Self { Self::Buy { - buy_amount_after_fee: NonZeroU256::one(), + buy_amount_after_fee: NonZeroU256::ONE, } } } @@ -300,12 +301,12 @@ pub enum SellAmount { /// The quoted order by the service. #[serde_as] -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct OrderQuote { - pub sell_token: H160, - pub buy_token: H160, - pub receiver: Option, + pub sell_token: Address, + pub buy_token: Address, + pub receiver: Option
, #[serde_as(as = "HexOrDecimalU256")] pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] @@ -315,6 +316,15 @@ pub struct OrderQuote { pub app_data: OrderCreationAppData, #[serde_as(as = "HexOrDecimalU256")] pub fee_amount: U256, + /// The estimated gas units required to execute the quoted trade. + #[serde_as(as = "DisplayFromStr")] + pub gas_amount: BigDecimal, + /// The estimated gas price at the time of quoting (in Wei). + #[serde_as(as = "DisplayFromStr")] + pub gas_price: BigDecimal, + /// The price of the sell token in native token (ETH/xDAI). + #[serde_as(as = "DisplayFromStr")] + pub sell_token_price: BigDecimal, pub kind: OrderKind, pub partially_fillable: bool, pub sell_token_balance: SellTokenSource, @@ -325,11 +335,11 @@ pub struct OrderQuote { pub type QuoteId = i64; #[serde_as] -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct OrderQuoteResponse { pub quote: OrderQuote, - pub from: H160, + pub from: Address, pub expiration: DateTime, pub id: Option, pub verified: bool, @@ -466,8 +476,8 @@ mod tests { }), ]; let expected_standard_response = OrderQuoteRequest { - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), ..Default::default() }; let modify_signing_scheme = |signing_scheme: QuoteSigningScheme| { diff --git a/crates/model/src/signature.rs b/crates/model/src/signature.rs index 7b8a875e42..b95db03916 100644 --- a/crates/model/src/signature.rs +++ b/crates/model/src/signature.rs @@ -1,16 +1,14 @@ use { crate::{DomainSeparator, quote::QuoteSigningScheme}, + alloy_primitives::{Address, B256, keccak256}, + alloy_signer::SignerSync, + alloy_signer_local::PrivateKeySigner, anyhow::{Context as _, Result, ensure}, - primitive_types::{H160, H256}, serde::{Deserialize, Serialize, de}, std::{ convert::TryInto as _, fmt::{self, Debug, Formatter}, }, - web3::{ - signing::{self, Key, SecretKeyRef}, - types::Recovery, - }, }; /// See [`Signature`]. @@ -119,12 +117,7 @@ impl Signature { let bytes: [u8; 65] = bytes .try_into() .context("ECDSA signature must be 65 bytes long")?; - EcdsaSignature { - r: H256::from_slice(&bytes[..32]), - s: H256::from_slice(&bytes[32..64]), - v: bytes[64], - } - .to_signature( + EcdsaSignature::from_bytes(&bytes)?.to_signature( scheme .try_to_ecdsa_scheme() .expect("scheme is an ecdsa scheme"), @@ -158,11 +151,11 @@ impl Signature { } } - pub fn encode_for_settlement(&self, owner: H160) -> Vec { + pub fn encode_for_settlement(&self, owner: Address) -> Vec { match self { Self::Eip712(signature) | Self::EthSign(signature) => signature.to_bytes().to_vec(), - Self::Eip1271(signature) => [owner.as_bytes(), signature].concat(), - Self::PreSign => owner.as_bytes().to_vec(), + Self::Eip1271(signature) => [owner.as_slice(), signature].concat(), + Self::PreSign => owner.to_vec(), } } @@ -173,7 +166,7 @@ impl Signature { signature: &[u8], domain_separator: &DomainSeparator, struct_hash: &[u8; 32], - ) -> Result { + ) -> Result
{ match self { Self::Eip712(_) | Self::EthSign(_) => { let recovered = self @@ -182,8 +175,8 @@ impl Signature { .context("unreachable?")?; Ok(recovered.signer) } - Self::Eip1271(_) => Ok(H160::from_slice(&signature[..20])), - Self::PreSign => Ok(H160::from_slice(signature)), + Self::Eip1271(_) => Ok(Address::from_slice(&signature[..20])), + Self::PreSign => Ok(Address::from_slice(signature)), } } } @@ -193,10 +186,10 @@ impl Signature { pub struct Recovered { /// The signing message that was used for recovery. The actual value of this /// message depends on the singing scheme used. - pub message: H256, + pub message: B256, /// The recovered signer address. - pub signer: H160, + pub signer: Address, } /// An internal type used for deriving `serde` implementations for the @@ -256,31 +249,39 @@ impl SigningScheme { } } -#[derive(Eq, PartialEq, Clone, Copy, Debug, Default, Hash)] +#[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)] pub struct EcdsaSignature { - pub r: H256, - pub s: H256, + pub r: B256, + pub s: B256, pub v: u8, } -pub fn hashed_eip712_message( - domain_separator: &DomainSeparator, - struct_hash: &[u8; 32], -) -> [u8; 32] { +impl Default for EcdsaSignature { + fn default() -> Self { + Self { + r: B256::ZERO, + s: B256::ZERO, + // Use normalized v value (equivalent to 0) for Solidity ecrecover compatibility + v: 27, + } + } +} + +pub fn hashed_eip712_message(domain_separator: &DomainSeparator, struct_hash: &[u8; 32]) -> B256 { let mut message = [0u8; 66]; // 0x19 0x01 are the magic prefix bytes for the domain separator // https://eips.ethereum.org/EIPS/eip-712#eth_signTypedData message[0..2].copy_from_slice(&[0x19, 0x01]); message[2..34].copy_from_slice(&domain_separator.0); message[34..66].copy_from_slice(struct_hash); - signing::keccak256(&message) + keccak256(message) } -fn hashed_ethsign_message(domain_separator: &DomainSeparator, struct_hash: &[u8; 32]) -> [u8; 32] { +fn hashed_ethsign_message(domain_separator: &DomainSeparator, struct_hash: &[u8; 32]) -> B256 { let mut message = [0u8; 60]; message[..28].copy_from_slice(b"\x19Ethereum Signed Message:\n32"); - message[28..].copy_from_slice(&hashed_eip712_message(domain_separator, struct_hash)); - signing::keccak256(&message) + message[28..].copy_from_slice(hashed_eip712_message(domain_separator, struct_hash).as_slice()); + keccak256(message) } /// Orders are always hashed into 32 bytes according to EIP-712. @@ -288,7 +289,7 @@ fn hashed_signing_message( signing_scheme: EcdsaSigningScheme, domain_separator: &DomainSeparator, struct_hash: &[u8; 32], -) -> [u8; 32] { +) -> B256 { match signing_scheme { EcdsaSigningScheme::Eip712 => hashed_eip712_message(domain_separator, struct_hash), EcdsaSigningScheme::EthSign => hashed_ethsign_message(domain_separator, struct_hash), @@ -306,18 +307,29 @@ impl EcdsaSignature { /// r + s + v pub fn to_bytes(self) -> [u8; 65] { let mut bytes = [0u8; 65]; - bytes[..32].copy_from_slice(self.r.as_bytes()); - bytes[32..64].copy_from_slice(self.s.as_bytes()); + bytes[..32].copy_from_slice(self.r.as_slice()); + bytes[32..64].copy_from_slice(self.s.as_slice()); bytes[64] = self.v; bytes } - pub fn from_bytes(bytes: &[u8; 65]) -> Self { - EcdsaSignature { - r: H256::from_slice(&bytes[..32]), - s: H256::from_slice(&bytes[32..64]), - v: bytes[64], - } + pub fn from_bytes(bytes: &[u8; 65]) -> Result { + let v = bytes[64]; + // Normalize v to legacy format (27/28) for Solidity ecrecover compatibility. + // Modern EIP-2 signatures use v = 0 or 1, but Solidity's ecrecover expects + // v = 27 or 28. Alloy normalizes internally for off-chain recovery, but + // on-chain ecrecover(hash, v=0, r, s) returns address(0) and fails. + // Only valid v values are 0, 1, 27, 28. + let normalized_v = match v { + 0 | 27 => 27, + 1 | 28 => 28, + _ => anyhow::bail!("invalid signature v value: {v}, expected 0, 1, 27, or 28"), + }; + Ok(EcdsaSignature { + r: B256::from_slice(&bytes[..32]), + s: B256::from_slice(&bytes[32..64]), + v: normalized_v, + }) } pub fn recover( @@ -327,40 +339,30 @@ impl EcdsaSignature { struct_hash: &[u8; 32], ) -> Result { let message = hashed_signing_message(signing_scheme, domain_separator, struct_hash); - let recovery = Recovery::new(message, self.v as u64, self.r, self.s); - let (signature, recovery_id) = recovery - .as_signature() - .context("unexpectedly invalid signature")?; - let signer = signing::recover(&message, &signature, recovery_id)?; - - Ok(Recovered { - message: H256(message), - signer, - }) + let signature = alloy_primitives::Signature::from_raw(&self.to_bytes())?; + let signer = signature.recover_address_from_prehash(&message)?; + + Ok(Recovered { message, signer }) } pub fn sign( signing_scheme: EcdsaSigningScheme, domain_separator: &DomainSeparator, struct_hash: &[u8; 32], - key: SecretKeyRef, + key: &PrivateKeySigner, ) -> Self { let message = hashed_signing_message(signing_scheme, domain_separator, struct_hash); // Unwrap because the only error is for invalid messages which we don't create. - let signature = key.sign(&message, None).unwrap(); - Self { - v: signature.v as u8, - r: signature.r, - s: signature.s, - } + let signature = key.sign_hash_sync(&message).unwrap(); + Self::from_bytes(&signature.as_bytes()).expect("signing produces valid v values") } /// Returns an arbitrary non-zero signature that can be used for recovery /// when you don't actually care about the owner. pub fn non_zero() -> Self { Self { - r: H256([1; 32]), - s: H256([2; 32]), + r: B256::repeat_byte(1), + s: B256::repeat_byte(2), v: 27, } } @@ -394,7 +396,7 @@ impl<'de> Deserialize<'de> for EcdsaSignature { write!( formatter, "the 65 ecdsa signature bytes as a hex encoded string, ordered as r, s, v, \ - where v is either 27 or 28" + where v is 0, 1, 27, or 28" ) } @@ -414,7 +416,7 @@ impl<'de> Deserialize<'de> for EcdsaSignature { "failed to decode {s:?} as hex ecdsa signature: {err}" )) })?; - Ok(EcdsaSignature::from_bytes(&bytes)) + EcdsaSignature::from_bytes(&bytes).map_err(de::Error::custom) } } @@ -424,7 +426,7 @@ impl<'de> Deserialize<'de> for EcdsaSignature { #[cfg(test)] mod tests { - use {super::*, serde_json::json, testlib::assert_json_matches}; + use {super::*, alloy_primitives::U256, serde_json::json, testlib::assert_json_matches}; #[test] fn onchain_signatures_cannot_recover_owners() { @@ -451,6 +453,7 @@ mod tests { assert!(Signature::from_bytes(SigningScheme::EthSign, &[0u8; 20]).is_err()); assert!(Signature::from_bytes(SigningScheme::PreSign, &[0u8; 32]).is_err()); + // Note: v=0 in input bytes gets normalized to v=27 for ecrecover compatibility assert_eq!( Signature::from_bytes(SigningScheme::Eip712, &[0u8; 65]).unwrap(), Signature::default_with(SigningScheme::Eip712) @@ -475,13 +478,17 @@ mod tests { #[test] fn signature_to_bytes() { + // Default ECDSA signatures have normalized v = 27 (equivalent to 0) + let mut expected_ecdsa = [0u8; 65]; + expected_ecdsa[64] = 27; + assert_eq!( Signature::default_with(SigningScheme::Eip712).to_bytes(), - [0u8; 65].to_vec() + expected_ecdsa.to_vec() ); assert_eq!( Signature::default_with(SigningScheme::EthSign).to_bytes(), - [0u8; 65].to_vec() + expected_ecdsa.to_vec() ); assert_eq!( Signature::default_with(SigningScheme::PreSign).to_bytes(), @@ -504,31 +511,8 @@ mod tests { #[test] fn deserialize_and_back() { + // Test round-trip for non-ECDSA signatures (no normalization needed) for (signature, json) in [ - ( - Signature::Eip712(Default::default()), - json!({ - "signingScheme": "eip712", - "signature": "0x\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 00", - }), - ), - ( - Signature::EthSign(EcdsaSignature { - r: H256([1; 32]), - s: H256([2; 32]), - v: 3, - }), - json!({ - "signingScheme": "ethsign", - "signature": "0x\ - 0101010101010101010101010101010101010101010101010101010101010101\ - 0202020202020202020202020202020202020202020202020202020202020202\ - 03", - }), - ), ( Signature::Eip1271(vec![1, 2, 3]), json!({ @@ -554,6 +538,57 @@ mod tests { assert_eq!(signature, serde_json::from_value(json.clone()).unwrap()); assert_json_matches!(json, json!(signature)); } + + // Test ECDSA signature deserialization with v normalization. + // Input v=0x00 normalizes to v=27, so serialization outputs v=0x1b. + let input_json = json!({ + "signingScheme": "eip712", + "signature": "0x\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 00", + }); + let expected_signature = Signature::Eip712(EcdsaSignature { + r: B256::ZERO, + s: B256::ZERO, + v: 27, // normalized from v=0 + }); + let expected_output_json = json!({ + "signingScheme": "eip712", + "signature": "0x\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 1b", + }); + + let deserialized: Signature = serde_json::from_value(input_json).unwrap(); + assert_eq!(deserialized, expected_signature); + assert_json_matches!(json!(deserialized), expected_output_json); + + // Test EthSign with v=1 normalizing to v=28 + let input_json = json!({ + "signingScheme": "ethsign", + "signature": "0x\ + 0101010101010101010101010101010101010101010101010101010101010101\ + 0202020202020202020202020202020202020202020202020202020202020202\ + 01", + }); + let expected_signature = Signature::EthSign(EcdsaSignature { + r: B256::repeat_byte(1), + s: B256::repeat_byte(2), + v: 28, // normalized from v=1 + }); + let expected_output_json = json!({ + "signingScheme": "ethsign", + "signature": "0x\ + 0101010101010101010101010101010101010101010101010101010101010101\ + 0202020202020202020202020202020202020202020202020202020202020202\ + 1c", + }); + + let deserialized: Signature = serde_json::from_value(input_json).unwrap(); + assert_eq!(deserialized, expected_signature); + assert_json_matches!(json!(deserialized), expected_output_json); } #[test] @@ -595,4 +630,132 @@ mod tests { .unwrap(), ); } + + #[test] + fn test_ecdsa_signature_recovery() { + let private_key = U256::from(1u64); + let signer = PrivateKeySigner::from_bytes(&private_key.to_be_bytes().into()).unwrap(); + let signer_address = signer.address(); + + let domain_separator = DomainSeparator(*B256::repeat_byte(0xde)); + let struct_hash = B256::repeat_byte(0xad); + + let eip712_ecdsa_signature = EcdsaSignature::sign( + EcdsaSigningScheme::Eip712, + &domain_separator, + &struct_hash, + &signer, + ); + let ethsign_ecdsa_signature = EcdsaSignature::sign( + EcdsaSigningScheme::EthSign, + &domain_separator, + &struct_hash, + &signer, + ); + + // Test Eip712 recovery + let eip712_signature = Signature::Eip712(eip712_ecdsa_signature); + let recovered_eip712 = eip712_signature + .recover(&domain_separator, &struct_hash) + .unwrap() + .unwrap(); + assert_eq!(recovered_eip712.signer, signer_address); + assert_eq!( + recovered_eip712.message, + hashed_eip712_message(&domain_separator, &struct_hash) + ); + + // Test EthSign recovery + let ethsign_signature = Signature::EthSign(ethsign_ecdsa_signature); + let recovered_ethsign = ethsign_signature + .recover(&domain_separator, &struct_hash) + .unwrap() + .unwrap(); + assert_eq!(recovered_ethsign.signer, signer_address); + assert_eq!( + recovered_ethsign.message, + hashed_ethsign_message(&domain_separator, &struct_hash) + ); + } + + #[test] + fn ecdsa_signature_v_normalization() { + // Modern EIP-2 signatures use v = 0 or 1, but Solidity's ecrecover expects + // v = 27 or 28. This test verifies that v values are normalized correctly. + + // v = 0 should be normalized to 27 + let mut bytes_v0 = [0u8; 65]; + bytes_v0[64] = 0; + let sig = EcdsaSignature::from_bytes(&bytes_v0).unwrap(); + assert_eq!(sig.v, 27); + assert_eq!(sig.to_bytes()[64], 27); + + // v = 1 should be normalized to 28 + let mut bytes_v1 = [0u8; 65]; + bytes_v1[64] = 1; + let sig = EcdsaSignature::from_bytes(&bytes_v1).unwrap(); + assert_eq!(sig.v, 28); + assert_eq!(sig.to_bytes()[64], 28); + + // v = 27 should stay 27 + let mut bytes_v27 = [0u8; 65]; + bytes_v27[64] = 27; + let sig = EcdsaSignature::from_bytes(&bytes_v27).unwrap(); + assert_eq!(sig.v, 27); + assert_eq!(sig.to_bytes()[64], 27); + + // v = 28 should stay 28 + let mut bytes_v28 = [0u8; 65]; + bytes_v28[64] = 28; + let sig = EcdsaSignature::from_bytes(&bytes_v28).unwrap(); + assert_eq!(sig.v, 28); + assert_eq!(sig.to_bytes()[64], 28); + + // Verify normalization also works through Signature::from_bytes + let sig = Signature::from_bytes(SigningScheme::Eip712, &bytes_v0).unwrap(); + assert_eq!(sig.to_bytes()[64], 27); + + let sig = Signature::from_bytes(SigningScheme::EthSign, &bytes_v1).unwrap(); + assert_eq!(sig.to_bytes()[64], 28); + } + + #[test] + fn ecdsa_signature_invalid_v_rejected() { + // Invalid v values should be rejected + for invalid_v in [2u8, 3, 26, 29, 30, 255] { + let mut bytes = [0u8; 65]; + bytes[64] = invalid_v; + + // EcdsaSignature::from_bytes should return an error + let result = EcdsaSignature::from_bytes(&bytes); + assert!( + result.is_err(), + "v={invalid_v} should be rejected but was accepted" + ); + + // Signature::from_bytes should also return an error + let result = Signature::from_bytes(SigningScheme::Eip712, &bytes); + assert!( + result.is_err(), + "v={invalid_v} should be rejected via Signature::from_bytes" + ); + + // Deserialization should also fail + let hex_sig = format!( + "0x{}{}{}", + const_hex::encode([0u8; 32]), + const_hex::encode([0u8; 32]), + const_hex::encode([invalid_v]) + ); + let json = json!({ + "signingScheme": "eip712", + "signature": hex_sig, + }); + let result: Result = serde_json::from_value(json); + assert!( + result.is_err(), + "v={invalid_v} should be rejected during deserialization" + ); + } + } } diff --git a/crates/model/src/solver_competition.rs b/crates/model/src/solver_competition.rs index 6c5d80c6e8..20b9dd934b 100644 --- a/crates/model/src/solver_competition.rs +++ b/crates/model/src/solver_competition.rs @@ -1,8 +1,7 @@ use { crate::{AuctionId, order::OrderUid}, - alloy::primitives::B256, + alloy_primitives::{Address, B256, U256}, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, @@ -36,7 +35,7 @@ pub struct SolverCompetitionAPI { pub struct CompetitionAuction { pub orders: Vec, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub prices: BTreeMap, + pub prices: BTreeMap, } #[serde_as] @@ -45,13 +44,13 @@ pub struct CompetitionAuction { pub struct SolverSettlement { pub solver: String, #[serde(default)] - pub solver_address: H160, + pub solver_address: Address, #[serde(flatten)] pub score: Option, #[serde(default)] pub ranking: usize, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub clearing_prices: BTreeMap, + pub clearing_prices: BTreeMap, pub orders: Vec, #[serde(default)] pub is_winner: bool, @@ -189,28 +188,28 @@ mod tests { OrderUid([0x33; 56]), ], prices: btreemap! { - H160([0x11; 20]) => 1000.into(), - H160([0x22; 20]) => 2000.into(), - H160([0x33; 20]) => 3000.into(), + Address::repeat_byte(0x11) => U256::from(1000), + Address::repeat_byte(0x22) => U256::from(2000), + Address::repeat_byte(0x33) => U256::from(3000), }, }, solutions: vec![SolverSettlement { solver: "2".to_string(), - solver_address: H160([0x22; 20]), - score: Some(Score::Solver(1.into())), + solver_address: Address::repeat_byte(0x22), + score: Some(Score::Solver(U256::ONE)), ranking: 1, clearing_prices: btreemap! { - H160([0x22; 20]) => 8.into(), + Address::repeat_byte(0x22) => U256::from(8), }, orders: vec![ Order::Colocated { id: OrderUid([0x33; 56]), - sell_amount: 12.into(), - buy_amount: 13.into(), + sell_amount: U256::from(12), + buy_amount: U256::from(13), }, Order::Legacy { id: OrderUid([0x44; 56]), - executed_amount: 14.into(), + executed_amount: U256::from(14), }, ], is_winner: true, diff --git a/crates/model/src/solver_competition_v2.rs b/crates/model/src/solver_competition_v2.rs index bb5d154db8..f36447f506 100644 --- a/crates/model/src/solver_competition_v2.rs +++ b/crates/model/src/solver_competition_v2.rs @@ -1,8 +1,7 @@ use { crate::{AuctionId, order::OrderUid}, - alloy::primitives::{Address, B256}, + alloy_primitives::{Address, B256, U256}, number::serialization::HexOrDecimalU256, - primitive_types::U256, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, @@ -14,6 +13,7 @@ use { pub struct Response { pub auction_id: AuctionId, pub auction_start_block: i64, + pub auction_deadline_block: i64, pub transaction_hashes: Vec, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] pub reference_scores: BTreeMap, @@ -74,6 +74,7 @@ mod tests { let correct = serde_json::json!({ "auctionId": 0, "auctionStartBlock": 13u64, + "auctionDeadlineBlock": 100, "transactionHashes": ["0x3333333333333333333333333333333333333333333333333333333333333333"], "referenceScores": { "0x2222222222222222222222222222222222222222": "0", @@ -119,34 +120,35 @@ mod tests { let orig = Response { auction_id: 0, auction_start_block: 13, + auction_deadline_block: 100, transaction_hashes: vec![tx], reference_scores: btreemap! { - solver => 0.into() + solver => U256::ZERO }, auction: Auction { orders: vec![OrderUid([0x11; 56])], prices: btreemap! { - Address::new([0x22; 20]) => 2000.into(), + Address::new([0x22; 20]) => U256::from(2000), }, }, solutions: vec![Solution { solver_address: solver, - score: 123.into(), + score: U256::from(123), ranking: 1, clearing_prices: btreemap! { - Address::new([0x22; 20]) => 8.into(), + Address::new([0x22; 20]) => U256::from(8), }, orders: vec![Order { id: OrderUid([0x11; 56]), - sell_amount: 12.into(), - buy_amount: 13.into(), + sell_amount: U256::from(12), + buy_amount: U256::from(13), buy_token: Address::new([0x22; 20]), sell_token: Address::new([0x22; 20]), }], is_winner: true, filtered_out: false, tx_hash: Some(tx), - reference_score: Some(10.into()), + reference_score: Some(U256::from(10)), }], }; diff --git a/crates/model/src/trade.rs b/crates/model/src/trade.rs index cba1d470a9..586c2afa74 100644 --- a/crates/model/src/trade.rs +++ b/crates/model/src/trade.rs @@ -3,7 +3,7 @@ use { crate::{fee_policy::ExecutedProtocolFee, order::OrderUid}, - alloy::primitives::{Address, B256}, + alloy_primitives::{Address, B256}, num::BigUint, serde::Serialize, serde_with::{DisplayFromStr, serde_as}, @@ -37,7 +37,7 @@ mod tests { use { super::*, crate::fee_policy::{FeePolicy, Quote}, - alloy::primitives::U256, + alloy_primitives::U256, serde_json::json, testlib::assert_json_matches, }; diff --git a/crates/number/Cargo.toml b/crates/number/Cargo.toml index ef84a0a375..1f2a11e921 100644 --- a/crates/number/Cargo.toml +++ b/crates/number/Cargo.toml @@ -6,13 +6,13 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] +alloy-primitives = { workspace = true, features = ["serde"] } anyhow = { workspace = true } -alloy = { workspace = true } bigdecimal = { workspace = true } num = { workspace = true } -primitive-types = { workspace = true } -serde_with = { workspace = true } +ruint = { workspace = true, features = ["num-bigint"] } serde = { workspace = true } +serde_with = { workspace = true } [lints] workspace = true diff --git a/crates/number/src/conversions.rs b/crates/number/src/conversions.rs index feae5770b4..b63e87226e 100644 --- a/crates/number/src/conversions.rs +++ b/crates/number/src/conversions.rs @@ -1,28 +1,48 @@ use { + alloy_primitives::{ + U256, + aliases::{I512, U160}, + }, anyhow::{Result, ensure}, bigdecimal::{BigDecimal, num_bigint::ToBigInt}, num::{BigInt, BigRational, BigUint, Zero, bigint::Sign, rational::Ratio}, - primitive_types::U256, }; -pub fn u256_to_big_uint(input: &U256) -> BigUint { - let mut bytes = [0; 32]; - input.to_big_endian(&mut bytes); - BigUint::from_bytes_be(&bytes) +pub fn big_decimal_to_big_uint(big_decimal: &BigDecimal) -> Option { + // TODO(vkgnosis): It would be nice to avoid copying the underlying BigInt when + // converting BigDecimal to anything else but the simple + // big_decimal.to_bigint makes a copy internally. + big_decimal.to_bigint()?.try_into().ok() } -pub fn u256_to_big_int(input: &U256) -> BigInt { - BigInt::from_biguint(Sign::Plus, u256_to_big_uint(input)) +pub fn rational_to_big_decimal(value: &Ratio) -> BigDecimal +where + T: Clone, + BigInt: From, +{ + let numer = BigInt::from(value.numer().clone()); + let denom = BigInt::from(value.denom().clone()); + BigDecimal::new(numer, 0) / BigDecimal::new(denom, 0) } -pub fn u256_to_big_rational(input: &U256) -> BigRational { - BigRational::new(u256_to_big_int(input), 1.into()) +pub fn big_decimal_to_big_rational(value: &BigDecimal) -> BigRational { + let (numer, scale) = value.as_bigint_and_exponent(); + let (adjusted_numer, denom) = match scale.cmp(&0) { + std::cmp::Ordering::Equal => (numer, BigInt::from(1)), + std::cmp::Ordering::Greater => (numer, BigInt::from(10).pow(scale as u32)), + std::cmp::Ordering::Less => ( + numer * BigInt::from(10).pow((-scale) as u32), + BigInt::from(1), + ), + }; + + BigRational::new(adjusted_numer, denom) } pub fn big_uint_to_u256(input: &BigUint) -> Result { let bytes = input.to_bytes_be(); ensure!(bytes.len() <= 32, "too large"); - Ok(U256::from_big_endian(&bytes)) + Ok(U256::from_be_slice(&bytes)) } pub fn big_int_to_u256(input: &BigInt) -> Result { @@ -30,24 +50,6 @@ pub fn big_int_to_u256(input: &BigInt) -> Result { big_uint_to_u256(input.magnitude()) } -pub fn big_rational_to_u256(ratio: &BigRational) -> Result { - ensure!(!ratio.denom().is_zero(), "zero denominator"); - big_int_to_u256(&(ratio.numer() / ratio.denom())) -} - -// TODO: It would be nice to avoid copying the underlying BigInt when converting -// BigDecimal to anything else but the simple big_decimal.to_bigint makes a copy -// internally. - -pub fn u256_to_big_decimal(u256: &U256) -> BigDecimal { - let big_uint = u256_to_big_uint(u256); - BigDecimal::from(BigInt::from(big_uint)) -} - -pub fn big_decimal_to_big_uint(big_decimal: &BigDecimal) -> Option { - big_decimal.to_bigint()?.try_into().ok() -} - pub fn big_decimal_to_u256(big_decimal: &BigDecimal) -> Option { if !big_decimal.is_integer() { return None; @@ -56,82 +58,81 @@ pub fn big_decimal_to_u256(big_decimal: &BigDecimal) -> Option { big_int_to_u256(&big_int).ok() } -pub mod alloy { - use { - alloy::primitives::U256, - anyhow::{Result, ensure}, - bigdecimal::{BigDecimal, num_bigint::ToBigInt}, - num::{BigInt, BigRational, BigUint, Zero, bigint::Sign}, - }; - pub fn big_uint_to_u256(input: &BigUint) -> Result { - let bytes = input.to_bytes_be(); - ensure!(bytes.len() <= 32, "too large"); - Ok(U256::from_be_slice(&bytes)) - } +pub fn big_rational_to_u256(ratio: &BigRational) -> Result { + ensure!(!ratio.denom().is_zero(), "zero denominator"); + big_int_to_u256(&(ratio.numer() / ratio.denom())) +} - pub fn big_int_to_u256(input: &BigInt) -> Result { - ensure!(input.sign() != Sign::Minus, "negative"); - big_uint_to_u256(input.magnitude()) - } +pub fn u256_to_big_uint(input: &U256) -> BigUint { + BigUint::from_bytes_be(&input.to_be_bytes::<32>()) +} - pub fn big_decimal_to_u256(big_decimal: &BigDecimal) -> Option { - if !big_decimal.is_integer() { - return None; - } - let big_int = big_decimal.to_bigint()?; - big_int_to_u256(&big_int).ok() - } +pub fn u256_to_big_int(input: &U256) -> BigInt { + BigInt::from_biguint(Sign::Plus, u256_to_big_uint(input)) +} - pub fn big_rational_to_u256(ratio: &BigRational) -> Result { - ensure!(!ratio.denom().is_zero(), "zero denominator"); - big_int_to_u256(&(ratio.numer() / ratio.denom())) - } +pub fn u256_to_big_rational(input: &U256) -> BigRational { + BigRational::new(u256_to_big_int(input), 1.into()) +} - pub fn u256_to_big_uint(input: &U256) -> BigUint { - BigUint::from_bytes_be(&input.to_be_bytes::<32>()) - } +pub fn u256_to_big_decimal(u256: &U256) -> BigDecimal { + let big_uint = u256_to_big_uint(u256); + BigDecimal::from(BigInt::from(big_uint)) +} - pub fn u256_to_big_int(input: &U256) -> BigInt { - BigInt::from_biguint(Sign::Plus, u256_to_big_uint(input)) - } +pub fn u160_to_big_decimal(u160: &U160) -> BigDecimal { + let big_uint = BigUint::from_bytes_be(&u160.to_be_bytes::<20>()); + BigDecimal::from(BigInt::from(big_uint)) +} - pub fn u256_to_big_rational(input: &U256) -> BigRational { - BigRational::new(u256_to_big_int(input), 1.into()) - } +pub fn big_decimal_to_u160(big_decimal: &BigDecimal) -> Option { + let big_uint = big_decimal_to_big_uint(big_decimal)?; + big_uint_to_u160(&big_uint).ok() +} - pub fn u256_to_big_decimal(u256: &U256) -> BigDecimal { - let big_uint = u256_to_big_uint(u256); - BigDecimal::from(BigInt::from(big_uint)) - } +pub fn big_uint_to_u160(input: &BigUint) -> Result { + let bytes = input.to_bytes_be(); + ensure!(bytes.len() <= 20, "too large for U160"); + let mut buf = [0u8; 20]; + buf[20 - bytes.len()..].copy_from_slice(&bytes); + Ok(U160::from_be_bytes(buf)) } -pub fn rational_to_big_decimal(value: &Ratio) -> BigDecimal -where - T: Clone, - BigInt: From, -{ - let numer = BigInt::from(value.numer().clone()); - let denom = BigInt::from(value.denom().clone()); - BigDecimal::new(numer, 0) / BigDecimal::new(denom, 0) +pub fn i512_to_big_int(i512: &I512) -> BigInt { + BigInt::from_bytes_be( + match i512.sign() { + alloy_primitives::Sign::Positive => Sign::Plus, + alloy_primitives::Sign::Negative => Sign::Minus, + }, + &i512.abs().to_be_bytes::<64>(), + ) } -pub fn big_decimal_to_big_rational(value: &BigDecimal) -> BigRational { - let (numer, scale) = value.as_bigint_and_exponent(); - let (adjusted_numer, denom) = match scale.cmp(&0) { - std::cmp::Ordering::Equal => (numer, BigInt::from(1)), - std::cmp::Ordering::Greater => (numer, BigInt::from(10).pow(scale as u32)), - std::cmp::Ordering::Less => ( - numer * BigInt::from(10).pow((-scale) as u32), - BigInt::from(1), - ), - }; +pub fn i512_to_big_rational(input: &I512) -> BigRational { + BigRational::new(i512_to_big_int(input), 1.into()) +} - BigRational::new(adjusted_numer, denom) +// TODO: Figure out a nicer way to convert I512 to U256, as a follow-up task +pub fn i512_to_u256(input: &I512) -> Result { + anyhow::ensure!(input >= &I512::ZERO, "Negative input value"); + anyhow::ensure!(input < &I512::from(U256::MAX), "Input exceeds U256::MAX"); + Ok(alloy_primitives::U256::from_be_slice( + &input.to_be_bytes::<64>()[32..], + )) } #[cfg(test)] mod tests { - use {super::*, num::One, std::str::FromStr}; + use { + super::*, + crate::conversions::{ + big_decimal_to_big_rational, + big_decimal_to_big_uint, + rational_to_big_decimal, + }, + num::{One, rational::Ratio}, + std::str::FromStr, + }; #[test] fn big_integer_to_u256() { @@ -189,8 +190,8 @@ mod tests { #[test] fn u256_to_big_uint_() { - assert_eq!(u256_to_big_uint(&U256::zero()), BigUint::zero()); - assert_eq!(u256_to_big_uint(&U256::one()), BigUint::one()); + assert_eq!(u256_to_big_uint(&U256::ZERO), BigUint::zero()); + assert_eq!(u256_to_big_uint(&U256::ONE), BigUint::one()); assert_eq!( u256_to_big_uint(&U256::MAX), BigUint::from_str( @@ -202,8 +203,8 @@ mod tests { #[test] fn bigint_to_u256_() { - assert_eq!(big_int_to_u256(&BigInt::zero()).unwrap(), U256::zero()); - assert_eq!(big_int_to_u256(&BigInt::one()).unwrap(), U256::one()); + assert_eq!(big_int_to_u256(&BigInt::zero()).unwrap(), U256::ZERO); + assert_eq!(big_int_to_u256(&BigInt::one()).unwrap(), U256::ONE); let max_u256_as_bigint = BigInt::from_str( "115792089237316195423570985008687907853269984665640564039457584007913129639935", ) @@ -215,8 +216,8 @@ mod tests { #[test] fn u256_to_big_decimal_() { - assert_eq!(u256_to_big_decimal(&U256::zero()), BigDecimal::zero()); - assert_eq!(u256_to_big_decimal(&U256::one()), BigDecimal::one()); + assert_eq!(u256_to_big_decimal(&U256::ZERO), BigDecimal::zero()); + assert_eq!(u256_to_big_decimal(&U256::ONE), BigDecimal::one()); assert_eq!( u256_to_big_decimal(&U256::MAX), BigDecimal::from_str( @@ -238,7 +239,8 @@ mod tests { ); assert!(big_decimal_to_big_uint( &BigDecimal::from_str( - "9115792089237316195423570985008687907853269984665640564039457584007913129639935" + +"9115792089237316195423570985008687907853269984665640564039457584007913129639935" ) .unwrap() ) @@ -250,8 +252,8 @@ mod tests { #[test] fn big_decimal_to_u256_() { - assert_eq!(big_decimal_to_u256(&BigDecimal::zero()), Some(U256::zero())); - assert_eq!(big_decimal_to_u256(&BigDecimal::one()), Some(U256::one())); + assert_eq!(big_decimal_to_u256(&BigDecimal::zero()), Some(U256::ZERO)); + assert_eq!(big_decimal_to_u256(&BigDecimal::one()), Some(U256::ONE)); assert!(big_decimal_to_u256(&BigDecimal::from(-1)).is_none()); assert!(big_decimal_to_u256(&BigDecimal::from_str("0.5").unwrap()).is_none()); let max_u256_as_big_decimal = BigDecimal::from_str( diff --git a/crates/number/src/lib.rs b/crates/number/src/lib.rs index 5d277018a1..983f0a933e 100644 --- a/crates/number/src/lib.rs +++ b/crates/number/src/lib.rs @@ -1,3 +1,7 @@ pub mod conversions; pub mod nonzero; +pub mod ratio_ext; pub mod serialization; +pub mod testing; +pub mod u256_ext; +pub mod units; diff --git a/crates/number/src/nonzero.rs b/crates/number/src/nonzero.rs index 36408f3a58..da0ce46f0b 100644 --- a/crates/number/src/nonzero.rs +++ b/crates/number/src/nonzero.rs @@ -1,36 +1,35 @@ use { + alloy_primitives::U256, anyhow::Context, - primitive_types::U256 as ZeroU256, serde::{Deserialize, Deserializer, Serialize, Serializer}, std::fmt::{self, Display, Formatter}, }; #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] -pub struct U256(ZeroU256); +pub struct NonZeroU256(U256); -impl U256 { - pub fn new(value: ZeroU256) -> Option { - (!value.is_zero()).then_some(Self(value)) - } +impl NonZeroU256 { + pub const MAX: Self = NonZeroU256(U256::MAX); + pub const ONE: Self = NonZeroU256(U256::ONE); - pub fn one() -> Self { - Self(ZeroU256::one()) + pub fn new(value: U256) -> Option { + (!value.is_zero()).then_some(Self(value)) } - pub fn get(&self) -> ZeroU256 { + pub fn get(self) -> U256 { self.0 } } -impl TryFrom for U256 { +impl TryFrom for NonZeroU256 { type Error = anyhow::Error; - fn try_from(value: ZeroU256) -> Result { + fn try_from(value: U256) -> Result { Self::new(value).context("Value cannot be zero!") } } -impl Serialize for U256 { +impl Serialize for NonZeroU256 { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -39,38 +38,37 @@ impl Serialize for U256 { } } -impl<'de> Deserialize<'de> for U256 { +impl<'de> Deserialize<'de> for NonZeroU256 { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - let s = String::deserialize(deserializer)?; - let u256_val = ZeroU256::from_dec_str(&s).map_err(serde::de::Error::custom)?; - U256::try_from(u256_val).map_err(serde::de::Error::custom) + let u256 = U256::deserialize(deserializer)?; + NonZeroU256::try_from(u256).map_err(serde::de::Error::custom) } } -impl TryFrom for U256 { +impl TryFrom for NonZeroU256 { type Error = anyhow::Error; fn try_from(value: u128) -> Result { - U256::try_from(ZeroU256::from(value)) + NonZeroU256::try_from(U256::from(value)) } } -impl Default for U256 { +impl Default for NonZeroU256 { fn default() -> Self { - Self(ZeroU256::one()) + Self::ONE } } -impl From for ZeroU256 { - fn from(val: U256) -> Self { +impl From for U256 { + fn from(val: NonZeroU256) -> Self { val.0 } } -impl Display for U256 { +impl Display for NonZeroU256 { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Display::fmt(&self.0, f) } diff --git a/crates/number/src/ratio_ext.rs b/crates/number/src/ratio_ext.rs new file mode 100644 index 0000000000..aa70c2faec --- /dev/null +++ b/crates/number/src/ratio_ext.rs @@ -0,0 +1,38 @@ +use { + alloy_primitives::{U256, U512, ruint::UintTryFrom}, + num::rational::Ratio, +}; + +pub trait RatioExt { + const ZERO: Ratio; + const ONE: Ratio; + + /// Multiplies a ratio by a scalar, returning `None` if the result or any + /// intermediate operation would overflow a `U256`. + fn scalar_mul(&self, scalar: N) -> Option; + + /// Multiplies a ratio by a scalar, returning `None` only if the result + /// would overflow a `U256`, but intermediate operations are allowed to + /// overflow. + fn full_scalar_mul(&self, scalar: N) -> Option; +} + +impl RatioExt for Ratio { + const ONE: Ratio = Ratio::new_raw(U256::ONE, U256::ONE); + const ZERO: Ratio = Ratio::new_raw(U256::ZERO, U256::ONE); + + fn scalar_mul(&self, scalar: U256) -> Option { + scalar + .checked_mul(*self.numer())? + .checked_div(*self.denom()) + } + + fn full_scalar_mul(&self, scalar: U256) -> Option { + U256::uint_try_from( + scalar + .widening_mul(*self.numer()) + .checked_div(U512::from(*self.denom()))?, + ) + .ok() + } +} diff --git a/crates/number/src/serialization.rs b/crates/number/src/serialization.rs index b30a9107e1..801e1e8ad0 100644 --- a/crates/number/src/serialization.rs +++ b/crates/number/src/serialization.rs @@ -1,140 +1,28 @@ use { - primitive_types::U256, - serde::{Deserializer, Serializer, de}, + alloy_primitives::U256, + serde::{Deserialize, Deserializer, Serializer}, serde_with::{DeserializeAs, SerializeAs}, - std::fmt, }; /// (De)serialization structure able to deserialize decimal and hexadecimal /// numbers, serializes as decimal. pub struct HexOrDecimalU256; -impl<'de> DeserializeAs<'de, alloy::primitives::U256> for HexOrDecimalU256 { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Visitor {} - impl de::Visitor<'_> for Visitor { - type Value = alloy::primitives::U256; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!( - formatter, - "a u256 encoded either as 0x hex prefixed or decimal encoded string" - ) - } - - fn visit_str(self, s: &str) -> Result - where - E: de::Error, - { - if s.trim().starts_with("0x") { - alloy::primitives::U256::from_str_radix(s, 16).map_err(|err| { - de::Error::custom(format!("failed to decode {s:?} as hex u256: {err}")) - }) - } else { - alloy::primitives::U256::from_str_radix(s, 10).map_err(|err| { - de::Error::custom(format!("failed to decode {s:?} as decimal u256: {err}")) - }) - } - } - } - - deserializer.deserialize_str(Visitor {}) - } -} - -impl SerializeAs for HexOrDecimalU256 { - fn serialize_as(source: &U256, serializer: S) -> Result - where - S: Serializer, - { - serialize(source, serializer) - } -} - impl<'de> DeserializeAs<'de, U256> for HexOrDecimalU256 { fn deserialize_as(deserializer: D) -> Result where D: Deserializer<'de>, { - deserialize(deserializer) + U256::deserialize(deserializer) } } -impl SerializeAs for HexOrDecimalU256 { - fn serialize_as(source: &alloy::primitives::U256, serializer: S) -> Result +impl SerializeAs for HexOrDecimalU256 { + fn serialize_as(source: &U256, serializer: S) -> Result where S: Serializer, { + // alloy_primitives::U256 serializes as hex, this gives us decimals instead serializer.serialize_str(&source.to_string()) } } - -pub fn serialize(value: &U256, serializer: S) -> Result -where - S: Serializer, -{ - // `primitive_types::U256::to_string()` is so slow that - // it's still faster to first convert to alloy's U256 - // and convert that to string... - let mut buf = [0u8; 32]; - value.to_big_endian(&mut buf); - let value = alloy::primitives::U256::from_be_bytes(buf); - serializer.serialize_str(&value.to_string()) -} - -pub fn deserialize<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - struct Visitor {} - impl de::Visitor<'_> for Visitor { - type Value = U256; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!( - formatter, - "a u256 encoded either as 0x hex prefixed or decimal encoded string" - ) - } - - fn visit_str(self, s: &str) -> Result - where - E: de::Error, - { - if s.trim().starts_with("0x") { - U256::from_str_radix(s, 16).map_err(|err| { - de::Error::custom(format!("failed to decode {s:?} as hex u256: {err}")) - }) - } else { - U256::from_dec_str(s).map_err(|err| { - de::Error::custom(format!("failed to decode {s:?} as decimal u256: {err}")) - }) - } - } - } - - deserializer.deserialize_str(Visitor {}) -} - -#[cfg(test)] -mod tests { - use { - super::*, - serde::de::{ - IntoDeserializer, - value::{Error as ValueError, StrDeserializer}, - }, - }; - - #[test] - fn test_deserialization() { - let deserializer: StrDeserializer = "0x10".into_deserializer(); - assert_eq!(deserialize(deserializer), Ok(16.into())); - - let deserializer: StrDeserializer = "10".into_deserializer(); - assert_eq!(deserialize(deserializer), Ok(10.into())); - } -} diff --git a/crates/number/src/testing.rs b/crates/number/src/testing.rs new file mode 100644 index 0000000000..17c71853ba --- /dev/null +++ b/crates/number/src/testing.rs @@ -0,0 +1,197 @@ +use { + bigdecimal::Signed, + num::{BigInt, BigRational, FromPrimitive}, +}; + +/// Trait for approximate equality comparisons, useful for tests with rounding +/// errors. +pub trait ApproxEq { + /// Checks if two values are approximately equal within a relative error + /// threshold. + /// + /// # Examples + /// + /// ```ignore + /// assert!(100.is_approx_eq(101, Some(0.02))); // 1% diff, within 2% threshold + /// assert!(!100.is_approx_eq(150, Some(0.02))); // 50% diff, exceeds threshold + /// assert!(100.is_approx_eq(100, None)); // Default 1e-9 threshold + /// ``` + fn is_approx_eq(&self, other: &Self, delta: Option) -> bool; +} + +impl ApproxEq for T +where + Self: Copy, + T: Into, +{ + fn is_approx_eq(&self, other: &Self, delta: Option) -> bool { + let self_: BigInt = (*self).into(); + let self_ = BigRational::from_integer(self_); + + let other: BigInt = (*other).into(); + let other = BigRational::from_integer(other); + + // Early equality check prevents division by zero when both values are 0 + if self_ == other { + return true; + } + + // Default to 1e-9 (0.0000001%) relative error threshold + let expected_delta = BigRational::from_f64(delta.unwrap_or(0.000000001)) + .expect("delta should be representable using BigRational"); + + // We can't use num::Unsigned due to ruint::U256 not implementing it + // (due to limitations on const generics) + // Calculate relative error: |actual - expected| / |expected| + // Ensures correct behavior with negative numbers + let diff = (self_.clone() - other.clone()).abs(); + let calculated_delta = diff / other.abs(); + + calculated_delta <= expected_delta + } +} + +#[cfg(test)] +mod test { + use {super::*, alloy_primitives::U256}; + + #[test] + fn u64_identical_values() { + let a: u64 = 100; + let b: u64 = 100; + assert!(a.is_approx_eq(&b, None)); + } + + #[test] + fn u64_within_threshold() { + // 1000000000 and 1000000001 differ by 1e-9 (exactly at threshold) + let a: u64 = 1_000_000_000; + let b: u64 = 1_000_000_001; + assert!(a.is_approx_eq(&b, None)); + assert!(b.is_approx_eq(&a, None)); + } + + #[test] + fn u64_exceeds_threshold() { + // 100 and 101 differ by 1% which exceeds the 1e-9 threshold + let a: u64 = 100; + let b: u64 = 101; + assert!(!a.is_approx_eq(&b, None)); + assert!(!b.is_approx_eq(&a, None)); + } + + #[test] + fn u64_zero_values() { + let a: u64 = 0; + let b: u64 = 0; + assert!(a.is_approx_eq(&b, None)); + } + + #[test] + fn u64_custom_delta() { + // 100 and 105 differ by ~5%, which is within a 10% threshold + // Note: 100.is_approx_eq(&105) uses |100-105|/105 = 4.76% + // 105.is_approx_eq(&100) uses |105-100|/100 = 5% + let a: u64 = 100; + let b: u64 = 105; + assert!(!a.is_approx_eq(&b, None)); // Not within default threshold + assert!(!b.is_approx_eq(&a, None)); // Not within default threshold + assert!(a.is_approx_eq(&b, Some(0.1))); // Within 10% threshold + assert!(b.is_approx_eq(&a, Some(0.1))); // Within 10% threshold + } + + #[test] + fn u128_identical_values() { + let a: u128 = 123456789012345678; + let b: u128 = 123456789012345678; + assert!(a.is_approx_eq(&b, None)); + } + + #[test] + fn u128_within_threshold() { + // Large values with tiny relative difference + let a: u128 = 1_000_000_000_000_000_000; + let b: u128 = 1_000_000_000_000_000_001; + assert!(a.is_approx_eq(&b, None)); + assert!(b.is_approx_eq(&a, None)); + } + + #[test] + fn u128_exceeds_threshold() { + let a: u128 = 1_000_000; + let b: u128 = 1_001_000; // 0.1% difference, exceeds threshold + assert!(!a.is_approx_eq(&b, None)); + assert!(!b.is_approx_eq(&a, None)); + } + + #[test] + fn u128_zero_values() { + let a: u128 = 0; + let b: u128 = 0; + assert!(a.is_approx_eq(&b, None)); + } + + #[test] + fn u128_custom_delta() { + // 1000 and 1050 differ by ~5%, which is within a 10% threshold + // Note: 1000.is_approx_eq(&1050) uses |1000-1050|/1050 = 4.76% + // 1050.is_approx_eq(&1000) uses |1050-1000|/1000 = 5% + let a: u128 = 1000; + let b: u128 = 1050; + assert!(!a.is_approx_eq(&b, None)); + assert!(!b.is_approx_eq(&a, None)); + assert!(a.is_approx_eq(&b, Some(0.1))); // Within 10% threshold + assert!(b.is_approx_eq(&a, Some(0.1))); // Within 10% threshold + } + + #[test] + fn u256_identical_values() { + let a = U256::from(999999999u64); + let b = U256::from(999999999u64); + assert!(a.is_approx_eq(&b, None)); + } + + #[test] + fn u256_within_threshold() { + // Very large values with tiny relative difference + let a = U256::from(1_000_000_000_000_000_000u64); + let b = U256::from(1_000_000_000_000_000_001u64); + assert!(a.is_approx_eq(&b, None)); + assert!(b.is_approx_eq(&a, None)); + } + + #[test] + fn u256_exceeds_threshold() { + let a = U256::from(1_000_000u64); + let b = U256::from(1_001_000u64); // 0.1% difference + assert!(!a.is_approx_eq(&b, None)); + assert!(!b.is_approx_eq(&a, None)); + } + + #[test] + fn u256_zero_values() { + let a = U256::ZERO; + let b = U256::ZERO; + assert!(a.is_approx_eq(&b, None)); + } + + #[test] + fn u256_custom_delta() { + // 10000 and 10500 differ by ~5%, which is within a 10% threshold + // Note: 10000.is_approx_eq(&10500) uses |10000-10500|/10500 = 4.76% + // 10500.is_approx_eq(&10000) uses |10500-10000|/10000 = 5% + let a = U256::from(10000u64); + let b = U256::from(10500u64); + assert!(!a.is_approx_eq(&b, None)); + assert!(!b.is_approx_eq(&a, None)); + assert!(a.is_approx_eq(&b, Some(0.1))); // Within 10% threshold + assert!(b.is_approx_eq(&a, Some(0.1))); // Within 10% threshold + } + + #[test] + fn u256_max_values() { + let a = U256::MAX; + let b = U256::MAX; + assert!(a.is_approx_eq(&b, None)); + } +} diff --git a/crates/number/src/u256_ext.rs b/crates/number/src/u256_ext.rs new file mode 100644 index 0000000000..f54b072b7f --- /dev/null +++ b/crates/number/src/u256_ext.rs @@ -0,0 +1,215 @@ +//! Extension trait for U256 arithmetic operations. + +use { + alloy_primitives::U256, + num::{BigInt, BigRational, BigUint, One}, +}; + +/// Extension trait for U256 to add utility methods. +pub trait U256Ext: Sized { + /// Ceiling division: (self + other - 1) / other + fn checked_ceil_div(&self, other: &Self) -> Option; + + /// Ceiling division that panics on error. + fn ceil_div(&self, other: &Self) -> Self { + self.checked_ceil_div(other) + .expect("ceiling division arithmetic error") + } + + /// Multiply U256 by f64 factor using a conversion factor approach. + /// + /// This method converts the factor to a scaled integer by multiplying it by + /// 10^18, then performs integer arithmetic: `(self * scaled_factor) / + /// 10^18`. + /// + /// This approach preserves precision for factors that, when multiplied by + /// 10^18, result in values that can be accurately represented in f64 + /// (up to ~9e15). + /// + /// We avoid BigRational here because it preserves binary-f64 semantics + /// and diverges from decimal-intent inputs (e.g., config values). + /// + /// Returns `None` if: + /// - The factor is negative, NaN, or infinity + /// - The intermediate multiplication would overflow U256 + fn checked_mul_f64(&self, factor: f64) -> Option; + + /// Convert to BigRational. + fn to_big_rational(&self) -> BigRational; + + /// Create from BigInt. + fn from_big_int(input: &BigInt) -> Option; + + /// Create from BigRational. + fn from_big_rational(value: &BigRational) -> Option { + use num::Zero; + if value.denom().is_zero() { + return None; + } + Self::from_big_int(&(value.numer() / value.denom())) + } +} + +impl U256Ext for U256 { + fn checked_ceil_div(&self, other: &Self) -> Option { + (!other.is_zero()).then(|| self.div_ceil(*other)) + } + + fn checked_mul_f64(&self, factor: f64) -> Option { + if !factor.is_finite() || factor.is_sign_negative() { + return None; + } + + // Special case: multiplication by 1.0 is identity + // This avoids intermediate overflow when multiplying large values + if factor.is_one() { + return Some(*self); + } + + // Scale factor to preserve precision: factor * 10^18 + const SCALE_F64: f64 = 1_000_000_000_000_000_000.0; + const SCALE_U128: u128 = 1_000_000_000_000_000_000; + let scaled_factor = factor * SCALE_F64; + + // Convert scaled factor to U256 + let scaled_factor_u256 = if scaled_factor <= u128::MAX as f64 { + // For values that fit in u128, convert directly + U256::from(scaled_factor) + } else { + // For larger values, use BigUint's f64 conversion + use num::FromPrimitive; + let scaled_factor_big = BigUint::from_f64(scaled_factor)?; + U256::try_from(&scaled_factor_big).ok()? + }; + + // Perform: (self * scaled_factor_u256) / SCALE + let result = self.checked_mul(scaled_factor_u256)?; + result.checked_div(U256::from(SCALE_U128)) + } + + fn to_big_rational(&self) -> BigRational { + BigRational::new(self.into(), 1.into()) + } + + fn from_big_int(input: &BigInt) -> Option { + U256::try_from(input).ok() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_checked_ceil_div() { + // Exact division + assert_eq!( + U256::from(10u64).checked_ceil_div(&U256::from(2u64)), + Some(U256::from(5u64)) + ); + + // Ceiling needed: 10 / 3 = 3.33... -> 4 + assert_eq!( + U256::from(10u64).checked_ceil_div(&U256::from(3u64)), + Some(U256::from(4u64)) + ); + + // Ceiling needed: 7 / 2 = 3.5 -> 4 + assert_eq!( + U256::from(7u64).checked_ceil_div(&U256::from(2u64)), + Some(U256::from(4u64)) + ); + + // 1 / 2 = 0.5 -> 1 + assert_eq!( + U256::from(1u64).checked_ceil_div(&U256::from(2u64)), + Some(U256::from(1u64)) + ); + + // Division by 1 + assert_eq!( + U256::from(42u64).checked_ceil_div(&U256::from(1u64)), + Some(U256::from(42u64)) + ); + + // Zero divided by anything (non-zero) + assert_eq!( + U256::from(0u64).checked_ceil_div(&U256::from(5u64)), + Some(U256::from(0u64)) + ); + + // Division by zero returns None + assert_eq!(U256::from(10u64).checked_ceil_div(&U256::ZERO), None); + + // Large number division + let large = U256::from(1_000_000_000_000_000_000u64); // 1e18 + let divisor = U256::from(3u64); + // 1e18 / 3 = 333,333,333,333,333,333.33... -> 333,333,333,333,333,334 + assert_eq!( + large.checked_ceil_div(&divisor), + Some(U256::from(333_333_333_333_333_334u64)) + ); + } + + #[test] + fn test_checked_mul_f64() { + // Realistic enough values + let value = U256::from(25_000_000_000_000_000_000u128); // 25 ether + let result = value.checked_mul_f64(0.2).unwrap(); + assert_eq!( + result, + U256::from(5_000_000_000_000_000_000u128), + "25 ether * 0.2 must be exact" + ); + + // Basic functionality + assert_eq!( + U256::from(100u64).checked_mul_f64(0.5), + Some(U256::from(50u64)) + ); + + // Multiply by 1.0 + assert_eq!( + U256::from(12345u64).checked_mul_f64(1.0), + Some(U256::from(12345u64)) + ); + + // Multiply by 0.0 + assert_eq!(U256::from(12345u64).checked_mul_f64(0.0), Some(U256::ZERO)); + + // Zero multiplied by any factor + assert_eq!(U256::ZERO.checked_mul_f64(123.456), Some(U256::ZERO)); + + // Negative factor returns None + assert_eq!(U256::from(100u64).checked_mul_f64(-1.0), None); + + // NaN returns None + assert_eq!(U256::from(100u64).checked_mul_f64(f64::NAN), None); + + // Infinity returns None + assert_eq!(U256::from(100u64).checked_mul_f64(f64::INFINITY), None); + assert_eq!(U256::from(100u64).checked_mul_f64(f64::NEG_INFINITY), None); + + // Test with exact f64 representation: 0.125 = 1/8 + let value = U256::from(1_000_000_000u64); // 1 billion + let result = value.checked_mul_f64(0.125).unwrap(); + // 1_000_000_000 * 0.125 = 125_000_000 + assert_eq!(result, U256::from(125_000_000u64)); + + // Test with 0.25 = 1/4 + let value = U256::from(8_888_888u64); + let result = value.checked_mul_f64(0.25).unwrap(); + // 8_888_888 * 0.25 = 2_222_222 + assert_eq!(result, U256::from(2_222_222u64)); + + // Test with very small exact value + let value = U256::from(1_000_000_000_000_000_000u64); // 1e18 + let result = value.checked_mul_f64(0.00390625).unwrap(); // 1/256 + // 1e18 / 256 = 3906250000000000 + assert_eq!(result, U256::from(3_906_250_000_000_000u64)); + + // Multiplying a large U256 by a large factor should overflow and return None + let max_u256 = U256::MAX; + assert_eq!(max_u256.checked_mul_f64(1.1), None); + } +} diff --git a/crates/number/src/units.rs b/crates/number/src/units.rs new file mode 100644 index 0000000000..ed9e6c7a2f --- /dev/null +++ b/crates/number/src/units.rs @@ -0,0 +1,42 @@ +use alloy_primitives::{U256, utils::Unit}; + +pub trait EthUnit: std::marker::Sized { + /// Converts this value to wei. + fn atom(self) -> U256; + + /// Converts this value from Mwei to wei (multiplies by 1e6). + fn matom(self) -> U256 { + self.atom() * U256::from(10).pow(U256::from(6)) + } + + /// Converts this value from Gwei to wei (multiplies by 1e9). + fn gatom(self) -> U256 { + self.atom() * U256::from(10).pow(U256::from(9)) + } + + /// Converts this value from Eth to wei (multiplies by 1e18). + fn eth(self) -> U256 { + self.atom() * Unit::ETHER.wei() + } +} + +impl EthUnit for u64 { + fn atom(self) -> U256 { + U256::from(self) + } +} + +impl EthUnit for u128 { + fn atom(self) -> U256 { + U256::from(self) + } +} +impl EthUnit for f64 { + fn atom(self) -> U256 { + U256::from(self as u128) + } + + fn eth(self) -> U256 { + U256::from((self * 1e18) as u128) + } +} diff --git a/crates/observe/Cargo.toml b/crates/observe/Cargo.toml index 0448d9ec3e..997b740ab2 100644 --- a/crates/observe/Cargo.toml +++ b/crates/observe/Cargo.toml @@ -6,13 +6,17 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] -axum = { workspace = true, optional = true } -atty = { workspace = true } +async-nats = { workspace = true } async-trait = { workspace = true } +axum = { workspace = true } +backtrace = { workspace = true, features = ["std"] } +bytes = { workspace = true } chrono = { workspace = true, features = ["now"] } -console-subscriber = { workspace = true } +console-subscriber = { workspace = true, optional = true } futures = { workspace = true } +jemalloc_pprof = { workspace = true } opentelemetry = { workspace = true } +opentelemetry-http = { workspace = true } opentelemetry-otlp = { workspace = true, features = ["grpc-tonic"] } opentelemetry_sdk = { workspace = true } pin-project-lite = { workspace = true } @@ -25,13 +29,16 @@ time = { workspace = true, features = ["macros"] } tokio = { workspace = true, features = ["fs"] } tracing = { workspace = true } tracing-opentelemetry = { workspace = true } -tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "time"] } -warp = { workspace = true } tracing-serde = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "time"] } +url = { workspace = true } -[lints] -workspace = true +[dev-dependencies] +tokio = { workspace = true, features = ["rt-multi-thread"] } [features] default = [] -axum-tracing = ["axum"] +tokio-console = ["dep:console-subscriber"] + +[lints] +workspace = true diff --git a/crates/observe/build.rs b/crates/observe/build.rs index b0ce3de9b9..9c0b1f64be 100644 --- a/crates/observe/build.rs +++ b/crates/observe/build.rs @@ -1,4 +1,6 @@ fn main() { // Make build system aware of custom config flags to avoid clippy warnings + // tokio_unstable is only used when explicitly compiled with --cfg + // tokio_unstable (e.g., in the playground environment) println!("cargo::rustc-check-cfg=cfg(tokio_unstable)"); } diff --git a/crates/observe/src/config.rs b/crates/observe/src/config.rs index cc061390e0..7bcbdbeca8 100644 --- a/crates/observe/src/config.rs +++ b/crates/observe/src/config.rs @@ -1,4 +1,4 @@ -use {core::time::Duration, tracing::Level}; +use {core::time::Duration, tracing::Level, url::Url}; #[derive(Debug, Clone)] pub struct Config { @@ -88,3 +88,15 @@ impl TracingConfig { } } } + +/// Configures a backend wide event bus events can be posted to. +pub struct EventBusConfig { + /// Url of the event bus service + pub url: Url, + /// Name of the channel to post events to + pub stream_name: String, + /// Which chain this service operates on. The service-level `chain-id` + /// must be set when the event bus is configured; this is checked at + /// config validation time, so callers can pass it through directly. + pub chain_id: u64, +} diff --git a/crates/observe/src/distributed_tracing/mod.rs b/crates/observe/src/distributed_tracing/mod.rs deleted file mode 100644 index aeff1c5b30..0000000000 --- a/crates/observe/src/distributed_tracing/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod request_id; -pub mod trace_id_format; -#[cfg(feature = "axum-tracing")] -pub mod tracing_axum; -pub mod tracing_warp; diff --git a/crates/observe/src/distributed_tracing/tracing_warp.rs b/crates/observe/src/distributed_tracing/tracing_warp.rs deleted file mode 100644 index 1828dccbbb..0000000000 --- a/crates/observe/src/distributed_tracing/tracing_warp.rs +++ /dev/null @@ -1,23 +0,0 @@ -use { - crate::{request_id::request_id, tracing::HeaderExtractor}, - opentelemetry::global, - tracing::info, - tracing_opentelemetry::OpenTelemetrySpanExt, - warp::http::HeaderMap, -}; - -pub fn make_span(info: warp::trace::Info) -> tracing::Span { - let headers: &HeaderMap = info.request_headers(); - - // Extract OTEL context from headers - let parent_cx = global::get_text_map_propagator(|prop| prop.extract(&HeaderExtractor(headers))); - - let span = tracing::info_span!("http_request", request_id = %request_id(headers)); - span.set_parent(parent_cx); // sets parent context for distributed trace - { - let _span = span.enter(); - info!(method = %info.method(), path = %info.path(), "HTTP request"); - } - - span -} diff --git a/crates/observe/src/event_bus/mod.rs b/crates/observe/src/event_bus/mod.rs new file mode 100644 index 0000000000..26b98e168c --- /dev/null +++ b/crates/observe/src/event_bus/mod.rs @@ -0,0 +1,299 @@ +//! Implements a simple globally available way to publish events to an event +//! bus. Under the hood it's using NATS. To support publishing events from +//! synchronous contexts we use a channel as an in-memory buffer. +//! Whenever a message gets posted to this channel a background task wakes +//! up and forwards it to the NATS service running in a different process. +//! Messages always get serialized as JSON so you can publish anything that +//! can be serialized to JSON as well. +use { + crate::config::EventBusConfig, + async_nats::jetstream::Context as JetstreamClient, + bytes::Bytes, + chrono::Utc, + futures::stream::{FuturesUnordered, StreamExt}, + serde::Serialize, + tokio::sync::{ + OnceCell, + mpsc::{Receiver, Sender, channel}, + }, +}; + +/// Wire format version of the JSON envelope sent on every event. Bump +/// alongside any breaking change to [`Envelope`]. +const ENVELOPE_VERSION: &str = "v1"; + +/// JSON envelope wrapping every event published to the bus. Consumers can +/// rely on `version` to evolve their parsers, on `timestamp` for ordering, +/// and on `requestId` to correlate events to a single inbound request. +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct Envelope { + version: &'static str, + timestamp: String, + #[serde(skip_serializing_if = "Option::is_none")] + request_id: Option, + body: T, +} + +impl Envelope { + fn new(request_id: Option, body: T) -> Self { + Self { + version: ENVELOPE_VERSION, + timestamp: Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true), + request_id, + body, + } + } +} + +struct EventBusConnector { + /// Channel to decouple issuing events from actually sending them to the + /// event bus service. + message_queue: Sender, + /// Subject prefix to disambiguate messages in globally shared event bus + /// service. + subject_prefix: String, +} + +struct Message { + subject: String, + data: Bytes, +} + +/// Singleton event bus connection to allow publishing events +/// conveniently from everywhere. +static BUS: OnceCell = OnceCell::const_new(); + +/// Initializes the event bus. Connection failures are logged but do not +/// abort startup: the event bus is purely observational, so a misconfigured +/// or unreachable NATS must not take the binary down. When init fails the +/// global `BUS` stays uninitialized and [`publish`] becomes a no-op. +/// +/// Safe to call multiple times: once a previous call has succeeded the +/// subsequent ones short-circuit. A failed call leaves the bus uninitialized +/// so the next call gets another chance. +pub async fn init(config: EventBusConfig) { + if BUS.initialized() { + return; + } + let result = BUS + .get_or_try_init(|| async { connect(&config).await }) + .await; + match result { + Ok(_) => { + tracing::info!( + channel = %config.stream_name, + chain_id = config.chain_id, + "event bus connected", + ); + } + Err(err) => { + tracing::error!( + ?err, + url = %config.url, + channel = %config.stream_name, + "failed to initialize event bus; events will be dropped", + ); + } + } +} + +async fn connect(config: &EventBusConfig) -> Result { + // We prefix every subject with `event` so consumers can subscribe to all + // events (e.g. `event.>`) without also seeing NATS internal events. The + // trailing dot is significant: see [`publish`] for how it's concatenated + // with the per-event subject suffix. + let subject_prefix = format!("event.{}.", config.chain_id); + + let client = async_nats::connect(config.url.as_str()).await?; + let jetstream = async_nats::jetstream::new(client); + // Make sure the stream exists up-front; otherwise every publish would fail + // server-side and we'd only find out at runtime. + jetstream.get_stream(&config.stream_name).await?; + + // JetStream publish completes in two stages: the call to `publish()` + // returns once the client has buffered the message, the returned + // PubAck future resolves once the server has stored it. + let (message_tx, message_rx) = channel(EVENT_BUS_SIZE); + let (ack_tx, ack_rx) = channel(EVENT_BUS_SIZE); + tokio::task::spawn(publish_messages(message_rx, jetstream, ack_tx)); + tokio::task::spawn(await_acks(ack_rx)); + + Ok(EventBusConnector { + message_queue: message_tx, + subject_prefix, + }) +} + +const EVENT_BUS_SIZE: usize = 1_000; + +/// In-flight handle returned by JetStream's `publish` call, passed from the +/// publisher task to the ack-handling task. +type PendingAck = (String, async_nats::jetstream::context::PublishAckFuture); + +/// Reads messages off the in-memory queue and hands the publish ack future +/// off to [`await_acks`]. +async fn publish_messages( + mut messages: Receiver, + client: JetstreamClient, + acks: Sender, +) { + while let Some(message) = messages.recv().await { + let subject = message.subject; + let ack_fut = match client.publish(subject.clone(), message.data).await { + Ok(fut) => fut, + Err(err) => { + tracing::warn!(?err, %subject, "failed to enqueue event with NATS client"); + record_dropped(DropReason::Publish); + continue; + } + }; + if acks.send((subject, ack_fut)).await.is_err() { + tracing::warn!("ack task was shut down; returning"); + return; + } + } +} + +/// Awaits JetStream publish acks concurrently and logs any failures. Runs +/// until the publisher task drops its sender and all in-flight acks have +/// resolved, so server-side rejections are still observed during shutdown. +async fn await_acks(mut acks: Receiver) { + let mut pending = FuturesUnordered::new(); + loop { + tokio::select! { + biased; + // Drain pending acks alongside new ones so failures are logged + // promptly and the set doesn't grow without bound. + Some(()) = pending.next(), if !pending.is_empty() => {} + next = acks.recv() => { + let Some((subject, ack_fut)) = next else { break }; + pending.push(log_ack(subject, ack_fut)); + } + } + } + // Only reached on publisher panic (steady state keeps both tasks alive). + // Drain pending futures so `log_ack` still runs for any in-flight publish + // — otherwise dropping them unpolled silently loses the log + metric. + while pending.next().await.is_some() {} +} + +async fn log_ack(subject: String, ack_fut: async_nats::jetstream::context::PublishAckFuture) { + if let Err(err) = ack_fut.await { + tracing::warn!(?err, %subject, "NATS did not acknowledge event"); + record_dropped(DropReason::Ack); + } +} + +/// Enqueues the event to be sent to the event bus in a background task. +pub fn publish(subject: &str, data: impl Serialize) { + let Some(bus) = BUS.get() else { + tracing::warn!("attempting to publish events without initializing the event bus"); + return; + }; + + let envelope = Envelope::new( + crate::tracing::distributed::request_id::from_current_span(), + data, + ); + let body = match serde_json::to_vec(&envelope) { + Ok(body) => body, + Err(err) => { + tracing::error!(?err, "failed to serialize event"); + record_dropped(DropReason::Serialize); + return; + } + }; + + let message = Message { + subject: format!("{}{}", bus.subject_prefix, subject), + data: body.into(), + }; + + if let Err(err) = bus.message_queue.try_send(message) { + tracing::error!(?err, "failed to enqueue message"); + record_dropped(DropReason::ChannelFull); + } +} + +/// Why an event was not delivered to the event bus. Used as a Prometheus +/// label so the failure modes can be alerted on independently. +#[derive(Copy, Clone, Debug)] +enum DropReason { + /// In-memory queue between [`publish`] and the background forwarder was + /// saturated. + ChannelFull, + /// The payload could not be encoded as JSON. + Serialize, + /// The NATS client rejected the publish locally (e.g. disconnected). + Publish, + /// JetStream did not acknowledge the publish. + Ack, +} + +impl DropReason { + fn as_label(self) -> &'static str { + match self { + DropReason::ChannelFull => "channel_full", + DropReason::Serialize => "serialize", + DropReason::Publish => "publish", + DropReason::Ack => "ack", + } + } +} + +#[derive(prometheus_metric_storage::MetricStorage)] +#[metric(subsystem = "event_bus")] +struct Metrics { + /// Events that were not delivered to the event bus, by failure mode. + /// See [`DropReason`] for the meaning of each label value. + #[metric(labels("reason"))] + dropped_events: prometheus::IntCounterVec, +} + +fn record_dropped(reason: DropReason) { + let Ok(metrics) = Metrics::instance(crate::metrics::get_storage_registry()) else { + return; + }; + metrics + .dropped_events + .with_label_values(&[reason.as_label()]) + .inc(); +} + +#[cfg(test)] +mod tests { + use {super::*, serde_json::json}; + + #[test] + fn envelope_matches_wire_format() { + let envelope = Envelope { + version: ENVELOPE_VERSION, + timestamp: "2026-05-22T12:00:00.000Z".to_string(), + request_id: Some("req-1".to_string()), + body: json!({"outAmount": 1234}), + }; + let serialized: serde_json::Value = serde_json::to_value(&envelope).unwrap(); + assert_eq!( + serialized, + json!({ + "version": "v1", + "timestamp": "2026-05-22T12:00:00.000Z", + "requestId": "req-1", + "body": {"outAmount": 1234}, + }) + ); + } + + #[test] + fn envelope_omits_missing_request_id() { + let envelope = Envelope { + version: ENVELOPE_VERSION, + timestamp: "2026-05-22T12:00:00.000Z".to_string(), + request_id: None, + body: json!({}), + }; + let serialized: serde_json::Value = serde_json::to_value(&envelope).unwrap(); + assert!(serialized.get("requestId").is_none()); + } +} diff --git a/crates/observe/src/heap_dump_handler.rs b/crates/observe/src/heap_dump_handler.rs new file mode 100644 index 0000000000..7ddceca046 --- /dev/null +++ b/crates/observe/src/heap_dump_handler.rs @@ -0,0 +1,169 @@ +use { + std::time::Duration, + tokio::{ + io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, + net::{UnixListener, UnixStream}, + }, +}; + +/// Spawns a new async task that listens for connections to a UNIX socket +/// at "/tmp/heap_dump_.sock". +/// When "dump" command is sent, it generates a heap profile using +/// jemalloc_pprof and streams the binary protobuf data back through the socket. +/// +/// Profiling is enabled at runtime via the MALLOC_CONF environment variable. +/// Set MALLOC_CONF=prof:true to enable heap profiling. +/// +/// Usage: +/// ```bash +/// # From your local machine (one-liner): +/// kubectl exec -n -- sh -c "echo dump | nc -U /tmp/heap_dump_.sock" > heap.pprof +/// +/// # Analyze with pprof: +/// go tool pprof -http=:8080 heap.pprof +/// ``` +pub fn spawn_heap_dump_handler() { + // Check if jemalloc profiling is available at runtime + // This depends on whether MALLOC_CONF=prof:true was set + let profiling_available = + std::panic::catch_unwind(|| jemalloc_pprof::PROF_CTL.as_ref().is_some()).unwrap_or(false); + + if !profiling_available { + // Profiling is disabled - do nothing + return; + } + + tracing::info!("jemalloc heap profiling is active"); + + tokio::spawn(async move { + let name = binary_name().unwrap_or("unknown".to_string()); + let socket_path = format!("/tmp/heap_dump_{name}.sock"); + + tracing::info!(socket = socket_path, "heap dump handler started"); + + let _ = tokio::fs::remove_file(&socket_path).await; + let listener = match UnixListener::bind(&socket_path) { + Ok(listener) => listener, + Err(err) => { + tracing::error!( + ?err, + socket = socket_path, + "failed to bind heap dump socket" + ); + return; + } + }; + let handle = SocketHandle { + listener, + socket_path, + }; + + loop { + // Accept connection in main loop, then spawn task for each connection + // Sequential processing prevents multiple simultaneous expensive heap dumps + match handle.listener.accept().await { + Ok((socket, _addr)) => { + let mut handle = tokio::spawn(async move { + handle_connection_with_socket(socket).await; + }); + + // 1-minute timeout to prevent stuck dumps from blocking future requests + match tokio::time::timeout(Duration::from_secs(60), &mut handle).await { + Ok(Ok(())) => { + // Task completed successfully + } + Ok(Err(err)) => { + tracing::error!(?err, "panic in heap dump connection handler"); + } + Err(elapsed) => { + handle.abort(); + tracing::error!(?elapsed, "heap dump request timed out"); + } + } + } + Err(err) => { + tracing::debug!(?err, "failed to accept connection"); + } + } + } + }); +} + +struct SocketHandle { + socket_path: String, + listener: UnixListener, +} + +impl Drop for SocketHandle { + fn drop(&mut self) { + let _ = std::fs::remove_file(&self.socket_path); + } +} + +fn binary_name() -> Option { + Some( + std::env::current_exe() + .ok()? + .file_name()? + .to_str()? + .to_string(), + ) +} + +async fn handle_connection_with_socket(mut socket: UnixStream) { + let message = read_line(&mut socket).await; + match message.as_deref() { + Some("dump") => { + generate_and_stream_dump(&mut socket).await; + } + Some("") => { + tracing::debug!("client disconnected"); + } + None => { + tracing::debug!("failed to read message"); + } + Some(unknown) => { + tracing::debug!(command = unknown, "unknown command"); + } + } +} + +async fn generate_and_stream_dump(socket: &mut UnixStream) { + tracing::info!("generating heap dump"); + + // PROF_CTL was already verified to be available in spawn_heap_dump_handler + // so we can safely unwrap here. If this panics, it means there's a serious bug. + let prof_ctl = jemalloc_pprof::PROF_CTL + .as_ref() + .expect("PROF_CTL should be available - checked at handler spawn"); + + let pprof_data = { + let mut lock = prof_ctl.lock().await; + let pprof_data = lock.dump_pprof(); + // While assembling the heap dump a global symbol cache gets filled with + // the resolved identifiers. As that is quite large and does not get freed + // automatically we do it explicitly here. + backtrace::clear_symbol_cache(); + pprof_data + }; + + match pprof_data { + Ok(pprof_data) => { + tracing::info!(size_bytes = pprof_data.len(), "heap dump generated"); + + if let Err(err) = socket.write_all(&pprof_data).await { + tracing::warn!(?err, "failed to write heap dump to socket"); + } + } + Err(err) => { + tracing::error!(?err, "failed to generate heap dump"); + } + } +} + +async fn read_line(socket: &mut UnixStream) -> Option { + let mut reader = BufReader::new(socket); + let mut buffer = String::new(); + reader.read_line(&mut buffer).await.ok()?; + Some(buffer.trim().to_owned()) +} diff --git a/crates/observe/src/lib.rs b/crates/observe/src/lib.rs index 290f3a2ceb..d847d75193 100644 --- a/crates/observe/src/lib.rs +++ b/crates/observe/src/lib.rs @@ -2,15 +2,15 @@ //! improve the observability of a system. That includes initialization logic //! for metrics and logging as well as logging helper functions. pub mod config; -pub mod distributed_tracing; +pub mod event_bus; pub mod future; +#[cfg(unix)] +pub mod heap_dump_handler; pub mod metrics; pub mod panic_hook; pub mod tracing; -#[cfg(unix)] -mod tracing_reload_handler; pub use { + crate::tracing::distributed::request_id, config::{Config, TracingConfig}, - distributed_tracing::request_id, }; diff --git a/crates/observe/src/metrics.rs b/crates/observe/src/metrics.rs index ac53fdfc71..9b427e6312 100644 --- a/crates/observe/src/metrics.rs +++ b/crates/observe/src/metrics.rs @@ -1,11 +1,16 @@ use { + axum::{ + Router, + http::StatusCode, + response::{IntoResponse, Response}, + routing::get, + }, prometheus::{ Encoder, core::{AtomicF64, AtomicU64, GenericCounterVec}, }, std::{ collections::HashMap, - convert::Infallible, net::SocketAddr, sync::{ Arc, @@ -14,8 +19,7 @@ use { }, time::Instant, }, - tokio::task::{self, JoinHandle}, - warp::{Filter, Rejection, Reply}, + tokio::task::JoinHandle, }; /// Global metrics registry used by all components. @@ -84,86 +88,87 @@ pub trait LivenessChecking: Send + Sync { async fn is_alive(&self) -> bool; } +#[derive(Clone)] +struct AppState { + liveness: Arc, + readiness: Arc>, + startup: Arc>, +} + +/// Serves metrics on a dedicated server at the given address. +/// Spawns a background task and returns its handle. pub fn serve_metrics( liveness: Arc, address: SocketAddr, readiness: Arc>, startup: Arc>, ) -> JoinHandle<()> { - let filter = handle_metrics() - .or(handle_liveness_probe(liveness)) - .or(handle_readiness_probe(readiness)) - .or(handle_startup_probe(startup)); + let app = Router::new() + .route("/metrics", get(handle_metrics)) + .route("/liveness", get(handle_liveness_probe)) + .route("/ready", get(handle_readiness_probe)) + .route("/startup", get(handle_startup_probe)) + .with_state(AppState { + liveness, + readiness, + startup, + }); + tracing::info!(%address, "serving metrics"); - task::spawn(warp::serve(filter).bind(address)) + tokio::spawn(async move { + let listener = tokio::net::TcpListener::bind(address) + .await + .expect("failed to bind metrics server"); + axum::serve(listener, app) + .await + .expect("failed to serve metrics") + }) } // `/metrics` route exposing encoded prometheus data to monitoring system -pub fn handle_metrics() -> impl Filter + Clone { - let registry = get_registry(); - warp::path("metrics").map(move || encode(registry)) +async fn handle_metrics() -> String { + encode(get_registry()) } -fn handle_liveness_probe( - liveness_checker: Arc, -) -> impl Filter + Clone { - warp::path("liveness").and_then(move || { - let liveness_checker = liveness_checker.clone(); - async move { - let status = if liveness_checker.is_alive().await { - warp::http::StatusCode::OK - } else { - warp::http::StatusCode::SERVICE_UNAVAILABLE - }; - Result::<_, Infallible>::Ok(warp::reply::with_status(warp::reply(), status)) - } - }) +async fn handle_liveness_probe( + axum::extract::State(state): axum::extract::State, +) -> Response { + let status = if state.liveness.is_alive().await { + StatusCode::OK + } else { + StatusCode::SERVICE_UNAVAILABLE + }; + status.into_response() } -fn handle_readiness_probe( - readiness: Arc>, -) -> impl Filter + Clone { - warp::path("ready").and_then(move || { - let readiness = readiness.clone(); - async move { - let Some(ref readiness) = *readiness else { - // if readiness is not configured we're ready right away - return Result::<_, Infallible>::Ok(warp::reply::with_status( - warp::reply(), - warp::http::StatusCode::OK, - )); - }; - let status = if readiness.load(Ordering::Acquire) { - warp::http::StatusCode::OK - } else { - warp::http::StatusCode::SERVICE_UNAVAILABLE - }; - Result::<_, Infallible>::Ok(warp::reply::with_status(warp::reply(), status)) - } - }) +async fn handle_readiness_probe( + axum::extract::State(state): axum::extract::State, +) -> Response { + let Some(ref readiness) = *state.readiness else { + // if readiness is not configured we're ready right away + return StatusCode::OK.into_response(); + }; + let status = if readiness.load(Ordering::Acquire) { + StatusCode::OK + } else { + StatusCode::SERVICE_UNAVAILABLE + }; + status.into_response() } -fn handle_startup_probe( - startup: Arc>, -) -> impl Filter + Clone { - warp::path("startup").and_then(move || { - let startup = startup.clone(); - async move { - let Some(ref startup) = *startup else { - // if startup is not configured we're started right away - return Result::<_, Infallible>::Ok(warp::reply::with_status( - warp::reply(), - warp::http::StatusCode::OK, - )); - }; - let status = if startup.load(Ordering::Acquire) { - warp::http::StatusCode::OK - } else { - warp::http::StatusCode::SERVICE_UNAVAILABLE - }; - Result::<_, Infallible>::Ok(warp::reply::with_status(warp::reply(), status)) - } - }) +async fn handle_startup_probe( + axum::extract::State(state): axum::extract::State, +) -> Response { + let Some(ref startup) = *state.startup else { + // if startup is not configured we're started right away + return StatusCode::OK.into_response(); + }; + let status = if startup.load(Ordering::Acquire) { + StatusCode::OK + } else { + StatusCode::SERVICE_UNAVAILABLE + }; + status.into_response() } /// Metrics shared by potentially all processes. diff --git a/crates/observe/src/panic_hook.rs b/crates/observe/src/panic_hook.rs index 1a592c2bd2..63f4d4bd53 100644 --- a/crates/observe/src/panic_hook.rs +++ b/crates/observe/src/panic_hook.rs @@ -38,7 +38,7 @@ mod tests { #[ignore] fn manual_thread() { let obs_config = Config::new("info", None, false, None); - crate::tracing::initialize(&obs_config); + crate::tracing::init::initialize(&obs_config); // Should print panic trace log but not kill the process. let handle = std::thread::spawn(|| panic!("you should see this message")); @@ -57,7 +57,7 @@ mod tests { #[ignore] async fn manual_tokio() { let obs_config = Config::new("info", None, false, None); - crate::tracing::initialize(&obs_config); + crate::tracing::init::initialize(&obs_config); let handle = tokio::task::spawn(async { panic!("you should see this message") }); assert!(handle.await.is_err()); diff --git a/crates/observe/src/distributed_tracing/tracing_axum.rs b/crates/observe/src/tracing/distributed/axum.rs similarity index 84% rename from crates/observe/src/distributed_tracing/tracing_axum.rs rename to crates/observe/src/tracing/distributed/axum.rs index d26fabcaec..61f11ece9e 100644 --- a/crates/observe/src/distributed_tracing/tracing_axum.rs +++ b/crates/observe/src/tracing/distributed/axum.rs @@ -1,7 +1,8 @@ use { - crate::{request_id::request_id, tracing::HeaderExtractor}, + crate::request_id::request_id, axum::http::Request, opentelemetry::{global, trace::TraceContextExt}, + opentelemetry_http::HeaderExtractor, tracing::{Span, field, info, info_span}, tracing_opentelemetry::OpenTelemetrySpanExt, }; @@ -25,7 +26,9 @@ pub fn make_span(request: &Request) -> Span { let request_id = request_id(request.headers()); let span = info_span!("http_request", ?request_id, trace_id = field::Empty); - span.set_parent(parent_context); + if let Err(err) = span.set_parent(parent_context) { + tracing::debug!(?err, "failed to set request parent span"); + } { let _span = span.enter(); info!(uri = %request.uri(), method = %request.method(), "HTTP request"); diff --git a/crates/observe/src/tracing/distributed/headers.rs b/crates/observe/src/tracing/distributed/headers.rs new file mode 100644 index 0000000000..5d6a8fab7f --- /dev/null +++ b/crates/observe/src/tracing/distributed/headers.rs @@ -0,0 +1,20 @@ +use { + axum::http::HeaderMap, + opentelemetry::{Context, global}, + opentelemetry_http::HeaderInjector, + tracing::Span, + tracing_opentelemetry::OpenTelemetrySpanExt, +}; + +pub fn tracing_headers() -> HeaderMap { + let mut headers = HeaderMap::new(); + + Context::current(); + let span = Span::current(); + let cx = span.context(); + global::get_text_map_propagator(|propagator| { + propagator.inject_context(&cx, &mut HeaderInjector(&mut headers)) + }); + + headers +} diff --git a/crates/observe/src/tracing/distributed/mod.rs b/crates/observe/src/tracing/distributed/mod.rs new file mode 100644 index 0000000000..f1d3955317 --- /dev/null +++ b/crates/observe/src/tracing/distributed/mod.rs @@ -0,0 +1,7 @@ +//! Module containing all the necessary pieces to trace logs across +//! multiple services by passing open telemetry information via HTTP headers. + +pub mod axum; +pub mod headers; +pub mod request_id; +pub mod trace_id_format; diff --git a/crates/observe/src/distributed_tracing/request_id.rs b/crates/observe/src/tracing/distributed/request_id.rs similarity index 87% rename from crates/observe/src/distributed_tracing/request_id.rs rename to crates/observe/src/tracing/distributed/request_id.rs index 56ae75af27..48a1b926ed 100644 --- a/crates/observe/src/distributed_tracing/request_id.rs +++ b/crates/observe/src/tracing/distributed/request_id.rs @@ -18,6 +18,7 @@ //! request. use { + axum::http::{HeaderMap, HeaderValue}, std::{ fmt, sync::{OnceLock, atomic::AtomicUsize}, @@ -30,7 +31,6 @@ use { span::Attributes, }, tracing_subscriber::{Layer, Registry, layer::Context, registry::LookupSpan}, - warp::http::{HeaderMap, HeaderValue}, }; pub(crate) fn request_id(headers: &HeaderMap) -> String { @@ -95,7 +95,7 @@ impl LookupSpan<'lookup>> Layer for RequestIdLay let Some(span) = ctx.span(id) else { return; }; - if span.name() != crate::distributed_tracing::request_id::SPAN_NAME { + if span.name() != SPAN_NAME { return; } @@ -126,17 +126,14 @@ mod test { fn init_tracing(env_filter: &str) { let obs_config = Config::new(env_filter, tracing::Level::ERROR.into(), false, None); - crate::tracing::initialize_reentrant(&obs_config); + crate::tracing::init::initialize_reentrant(&obs_config); } #[tokio::test] async fn request_id_from_current_span() { init_tracing("error"); async { - assert_eq!( - Some("test".to_string()), - crate::distributed_tracing::request_id::from_current_span() - ); + assert_eq!(Some("test".to_string()), from_current_span()); } .instrument(info_span("test".to_string())) .await @@ -146,10 +143,7 @@ mod test { async fn request_id_not_set() { init_tracing("debug"); async { - assert_eq!( - None, - crate::distributed_tracing::request_id::from_current_span() - ); + assert_eq!(None, from_current_span()); } .await } @@ -161,10 +155,7 @@ mod test { async { async { // we traverse the span hierarchy until we find a span with the request id - assert_eq!( - Some("test".to_string()), - crate::distributed_tracing::request_id::from_current_span() - ); + assert_eq!(Some("test".to_string()), from_current_span()); } .instrument(tracing::info_span!("wrap2", value = "value2")) .await @@ -183,10 +174,7 @@ mod test { async { async { // if multiple ancestors have a request id we take the closest one - assert_eq!( - Some("test_inner".to_string()), - crate::distributed_tracing::request_id::from_current_span() - ); + assert_eq!(Some("test_inner".to_string()), from_current_span()); } .instrument(tracing::info_span!("wrap", value = "value")) .await @@ -206,10 +194,7 @@ mod test { async { // we can spawn a new task and still find the request id if the spawned task // was instrumented with a span that contains the request id - assert_eq!( - Some("test".to_string()), - crate::distributed_tracing::request_id::from_current_span() - ); + assert_eq!(Some("test".to_string()), from_current_span()); } .instrument(Span::current()), ) diff --git a/crates/observe/src/distributed_tracing/trace_id_format.rs b/crates/observe/src/tracing/distributed/trace_id_format.rs similarity index 67% rename from crates/observe/src/distributed_tracing/trace_id_format.rs rename to crates/observe/src/tracing/distributed/trace_id_format.rs index dc2766a31d..2d11f16e38 100644 --- a/crates/observe/src/distributed_tracing/trace_id_format.rs +++ b/crates/observe/src/tracing/distributed/trace_id_format.rs @@ -2,7 +2,11 @@ use { chrono::Utc, opentelemetry::trace::{TraceContextExt, TraceId}, serde::ser::{SerializeMap, Serializer as _}, - std::{fmt, io}, + std::{ + collections::{HashMap, hash_map::Entry}, + fmt, + io, + }, tracing::{Event, Span, Subscriber}, tracing_opentelemetry::OpenTelemetrySpanExt, tracing_serde::{AsSerde, fields::AsMap}, @@ -11,6 +15,7 @@ use { FmtContext, FormatEvent, FormatFields, + FormattedFields, format::{Format, Full, Writer}, time::FormatTime, }, @@ -40,7 +45,13 @@ use { /// "status": 200 /// }, /// "target": "warp::filters::trace", -/// "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736" +/// "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", +/// "spans": { +/// "spanName1": { +/// "field1": 123, +/// "field2": "abc" +/// } +/// } /// } /// ``` pub struct TraceIdJsonFormat; @@ -52,7 +63,7 @@ where { fn format_event( &self, - _ctx: &FmtContext<'_, S, N>, + ctx: &FmtContext<'_, S, N>, mut writer: Writer<'_>, event: &Event<'_>, ) -> std::fmt::Result @@ -79,6 +90,44 @@ where serializer.serialize_entry("trace_id", &trace_id.to_string())?; } + // serialize all parent span names and their fields + if let Some(scope) = ctx.event_scope() { + let mut parent_spans = HashMap::::new(); + + for span in scope.from_root() { + let current_span_fields: serde_json::Map = span + .extensions() + .get::>() + .and_then(|fields| serde_json::from_str(fields.as_str()).ok()) + .unwrap_or_default(); + + match parent_spans.entry(span.name().to_string()) { + Entry::Vacant(entry) => { + entry.insert(serde_json::Value::Object(current_span_fields)); + } + Entry::Occupied(mut entry) => { + // the desired format does not preserve the hierarchy of spans + // so theoretically there could be nested spans with the same + // name so we merge the fields of all spans with the same name + // + // if there are duplicated fields the value of the span closest + // to the processed event wins + // + // also theoretically we could detect fields getting overwritten + // but we couldn't log that without causing a stack overflow so we + // don't + entry + .get_mut() + .as_object_mut() + .expect("fields get initialized with an object") + .extend(current_span_fields) + } + } + } + + serializer.serialize_entry("spans", &parent_spans)?; + } + serializer.end() }; diff --git a/crates/observe/src/tracing.rs b/crates/observe/src/tracing/init.rs similarity index 61% rename from crates/observe/src/tracing.rs rename to crates/observe/src/tracing/init.rs index eb9ae0f316..0647ecfb55 100644 --- a/crates/observe/src/tracing.rs +++ b/crates/observe/src/tracing/init.rs @@ -1,19 +1,15 @@ use { crate::{ config::Config, - distributed_tracing::{ - request_id::RequestIdLayer, - trace_id_format::{TraceIdFmt, TraceIdJsonFormat}, + tracing::{ + distributed::{ + request_id::RequestIdLayer, + trace_id_format::{TraceIdFmt, TraceIdJsonFormat}, + }, + reload_handler::spawn_reload_handler, }, - tracing_reload_handler::spawn_reload_handler, - }, - opentelemetry::{ - Context, - KeyValue, - global, - propagation::{Extractor, Injector}, - trace::TracerProvider, }, + opentelemetry::{KeyValue, global, trace::TracerProvider}, opentelemetry_otlp::WithExportConfig, opentelemetry_sdk::{ Resource, @@ -22,8 +18,7 @@ use { }, std::{panic::PanicHookInfo, sync::Once}, time::macros::format_description, - tracing::{Span, level_filters::LevelFilter}, - tracing_opentelemetry::OpenTelemetrySpanExt, + tracing::level_filters::LevelFilter, tracing_subscriber::{ EnvFilter, Layer, @@ -31,7 +26,6 @@ use { prelude::*, util::SubscriberInitExt, }, - warp::{http, http::HeaderMap}, }; /// Initializes tracing setup that is shared between the binaries. @@ -59,19 +53,7 @@ pub fn initialize_reentrant(config: &Config) { fn set_tracing_subscriber(config: &Config) { let initial_filter = config.env_filter.to_string(); - // The `tracing` APIs are heavily generic to enable zero overhead. Unfortunately - // this leads to very annoying type constraints which can only be satisfied - // by literally copy and pasting the code so the compiler doesn't try to - // infer types that satisfy both the tokio-console and the regular case. - // It's tempting to resolve this mess by first configuring the `fmt_layer` and - // only then the `console_subscriber`. However, this setup was the only way - // I found that: - // 1. actually makes `tokio-console` work - // 2. prints logs if `tokio-console` is disabled - // 3. does NOT skip the next log following a `tracing::event!()`. These calls - // happen for example under the hood in `sqlx`. I don't understand what's - // actually causing that but at this point I'm just happy if all the features - // work correctly. + // The `tracing` APIs are heavily generic to enable zero overhead. macro_rules! fmt_layer { ($env_filter:expr_2021, $stderr_threshold:expr_2021, $use_json_format:expr_2021) => {{ @@ -91,16 +73,19 @@ fn set_tracing_subscriber(config: &Config) { if config.use_json_format { // structured logging tracing_subscriber::fmt::layer() + .with_ansi(false) + .fmt_fields(tracing_subscriber::fmt::format::JsonFields::default()) .event_format(TraceIdJsonFormat) .with_writer(writer) .with_filter($env_filter) .boxed() } else { + let is_terminal = std::io::IsTerminal::is_terminal(&std::io::stdout()); tracing_subscriber::fmt::layer() .with_timer(timer) - .with_ansi(atty::is(atty::Stream::Stdout)) + .with_ansi(is_terminal) .map_event_format(|formatter| TraceIdFmt { - inner: formatter.with_ansi(atty::is(atty::Stream::Stdout)), + inner: formatter.with_ansi(is_terminal), }) .with_writer(writer) .with_filter($env_filter) @@ -109,11 +94,6 @@ fn set_tracing_subscriber(config: &Config) { }}; } - let enable_tokio_console: bool = std::env::var("TOKIO_CONSOLE") - .unwrap_or("false".to_string()) - .parse() - .unwrap(); - let (env_filter, reload_handle) = tracing_subscriber::reload::Layer::new(EnvFilter::new(&initial_filter)); @@ -161,13 +141,33 @@ fn set_tracing_subscriber(config: &Config) { )) .with(tracing_layer); - if cfg!(tokio_unstable) && enable_tokio_console { - subscriber.with(console_subscriber::spawn()).init(); - tracing::info!("started program with support for tokio-console"); - } else { + #[cfg(all(tokio_unstable, feature = "tokio-console"))] + { + let enable_tokio_console: bool = std::env::var("TOKIO_CONSOLE") + .unwrap_or("false".to_string()) + .parse() + .unwrap(); + + if enable_tokio_console { + subscriber.with(console_subscriber::spawn()).init(); + tracing::info!("started program with support for tokio-console"); + } else { + subscriber.init(); + tracing::info!( + "started program without support for tokio-console (TOKIO_CONSOLE=false)" + ); + } + } + + #[cfg(not(all(tokio_unstable, feature = "tokio-console")))] + { subscriber.init(); - tracing::info!("started program without support for tokio-console"); + tracing::info!( + "started program without support for tokio-console (not compiled with tokio_unstable \ + cfg and tokio-console feature)" + ); } + if cfg!(unix) { spawn_reload_handler(initial_filter, reload_handle); } @@ -183,51 +183,3 @@ fn tracing_panic_hook(panic: &PanicHookInfo) { let backtrace = std::backtrace::Backtrace::force_capture(); tracing::error!("thread '{name}' {panic}\nstack backtrace:\n{backtrace}"); } - -pub struct HeaderExtractor<'a>(pub &'a HeaderMap); - -// Copied from https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-http/src/lib.rs -// because that crate is using `http` crate v1 while warp is on v0.2 -impl Extractor for HeaderExtractor<'_> { - /// Get a value for a key from the HeaderMap. If the value is not valid - /// ASCII, returns None. - fn get(&self, key: &str) -> Option<&str> { - self.0.get(key).and_then(|value| value.to_str().ok()) - } - - /// Collect all the keys from the HeaderMap. - fn keys(&self) -> Vec<&str> { - self.0 - .keys() - .map(|value| value.as_str()) - .collect::>() - } -} - -pub struct HeaderInjector<'a>(pub &'a mut http::HeaderMap); - -impl Injector for HeaderInjector<'_> { - /// Set a key and value in the HeaderMap. Does nothing if the key or value - /// are not valid inputs. - fn set(&mut self, key: &str, value: String) { - if let (Ok(name), Ok(val)) = ( - http::header::HeaderName::from_bytes(key.as_bytes()), - http::header::HeaderValue::from_str(&value), - ) { - self.0.insert(name, val); - } - } -} - -pub fn tracing_headers() -> HeaderMap { - let mut headers = HeaderMap::new(); - - Context::current(); - let span = Span::current(); - let cx = span.context(); - global::get_text_map_propagator(|propagator| { - propagator.inject_context(&cx, &mut HeaderInjector(&mut headers)) - }); - - headers -} diff --git a/crates/observe/src/tracing/lazy.rs b/crates/observe/src/tracing/lazy.rs new file mode 100644 index 0000000000..0641cd1f63 --- /dev/null +++ b/crates/observe/src/tracing/lazy.rs @@ -0,0 +1,53 @@ +/// Helper struct to lazily evaluate an expression if a log is actually active. +/// Sometimes you need to compute a value for logs. This expression gets +/// evaluated eagerly in the `tracing` log macros. In order to only evaluate the +/// expression when the log is actually enabled wrap the expression in a closure +/// and wrap that in a [`Lazy`]. +pub struct Lazy(pub T); + +impl std::fmt::Debug for Lazy +where + T: Fn() -> D, + D: std::fmt::Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", (self.0)()) + } +} + +impl std::fmt::Display for Lazy +where + T: Fn() -> D, + D: std::fmt::Display, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", (self.0)()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lazy_eval() { + let lazy = Lazy(|| "abc".to_string()); + + let display = format!("{}", lazy); + assert_eq!(display, "abc"); + + let debug = format!("{:?}", lazy); + assert_eq!(debug, "\"abc\""); + } + + #[test] + fn lazy_in_macro() { + tracing::debug!( + miep = ?Lazy(|| { + panic!("this panic should not happen because we evaluate lazily"); + #[expect(unreachable_code)] + "abc" + }) + ) + } +} diff --git a/crates/observe/src/tracing/mod.rs b/crates/observe/src/tracing/mod.rs new file mode 100644 index 0000000000..bf4846c17c --- /dev/null +++ b/crates/observe/src/tracing/mod.rs @@ -0,0 +1,5 @@ +pub mod distributed; +pub mod init; +pub mod lazy; +#[cfg(unix)] +mod reload_handler; diff --git a/crates/observe/src/tracing_reload_handler.rs b/crates/observe/src/tracing/reload_handler.rs similarity index 100% rename from crates/observe/src/tracing_reload_handler.rs rename to crates/observe/src/tracing/reload_handler.rs diff --git a/crates/order-validation/Cargo.toml b/crates/order-validation/Cargo.toml index 88196cfdd0..fbef47a169 100644 --- a/crates/order-validation/Cargo.toml +++ b/crates/order-validation/Cargo.toml @@ -6,13 +6,20 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] -alloy = { workspace = true } +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +async-trait = { workspace = true } +const-hex = { workspace = true } contracts = { workspace = true } +futures = { workspace = true } +hmac = { workspace = true } moka = { workspace = true, features = ["sync"] } +reqwest = { workspace = true, features = ["json"] } +sha2 = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } -futures = {workspace = true } +url = { workspace = true } [lints] workspace = true diff --git a/crates/order-validation/src/banned.rs b/crates/order-validation/src/banned.rs deleted file mode 100644 index f7c27eb8d7..0000000000 --- a/crates/order-validation/src/banned.rs +++ /dev/null @@ -1,233 +0,0 @@ -//! Banned user detection for order validation. -//! -//! Checks if addresses are banned using a hardcoded list and optionally the -//! Chainalysis Oracle on-chain registry. On-chain results are cached (1-hour -//! expiry, LRU eviction) with background refresh every 60 seconds. - -use { - alloy::primitives::Address, - contracts::alloy::ChainalysisOracle, - futures::future::join_all, - moka::sync::Cache, - std::{ - collections::HashSet, - sync::Arc, - time::{Duration, Instant}, - }, -}; - -/// A list of banned users and an optional registry that can be checked onchain. -pub struct Users { - list: HashSet
, - onchain: Option>, -} - -#[derive(Clone)] -struct UserMetadata { - is_banned: bool, - last_updated: Instant, -} - -/// Onchain banned user checker using Chainalysis Oracle with caching and -/// background refresh. Maintains a size-bounded LRU cache with periodic -/// maintenance to refresh expired entries. -struct Onchain { - contract: ChainalysisOracle::Instance, - cache: Cache, -} - -impl Onchain { - pub fn new(contract: ChainalysisOracle::Instance, cache_max_size: u64) -> Arc { - let onchain = Arc::new(Self { - contract, - cache: Cache::builder().max_capacity(cache_max_size).build(), - }); - - onchain.clone().spawn_maintenance_task(); - - onchain - } - - /// Spawns a background task that periodically checks the cache for expired - /// entries and re-run checks for them. - fn spawn_maintenance_task(self: Arc) { - let cache_expiry = Duration::from_secs(60 * 60); - let maintenance_timeout = Duration::from_secs(60); - let detector = Arc::clone(&self); - - tokio::task::spawn(async move { - loop { - let start = Instant::now(); - - let expired_data: Vec<_> = detector - .cache - .iter() - .filter_map(|(address, metadata)| { - let expired = start - .checked_duration_since(metadata.last_updated) - .unwrap_or_default() - >= cache_expiry - maintenance_timeout; - - expired.then_some((address, metadata)) - }) - .collect(); - - let results = join_all(expired_data.into_iter().map(|(address, metadata)| { - let detector = detector.clone(); - async move { - match detector.fetch(*address).await { - Ok(result) => Some(( - *address, - UserMetadata { - is_banned: result, - ..metadata - }, - )), - Err(err) => { - tracing::warn!( - address = ?*address, - ?err, - "unable to determine banned status in the background task" - ); - None - } - } - } - })) - .await - .into_iter() - .flatten(); - - detector.insert_many_into_cache(results); - - let remaining_sleep = maintenance_timeout - .checked_sub(start.elapsed()) - .unwrap_or_default(); - tokio::time::sleep(remaining_sleep).await; - } - }); - } - - fn insert_many_into_cache(&self, addresses: impl Iterator) { - let now = Instant::now(); - for (address, metadata) in addresses { - self.cache.insert( - address, - UserMetadata { - last_updated: now, - ..metadata - }, - ); - } - } -} - -impl Users { - /// Creates a new `Users` instance that checks the hardcoded list and uses - /// the given `web3` instance to determine whether an onchain registry of - /// banned addresses is available. - pub fn new( - contract: Option, - banned_users: Vec
, - cache_max_size: u64, - ) -> Self { - Self { - list: HashSet::from_iter(banned_users), - onchain: contract.map(|instance| Onchain::new(instance, cache_max_size)), - } - } - - /// Creates a new `Users` instance that passes all addresses. - pub fn none() -> Self { - Self { - list: HashSet::new(), - onchain: None, - } - } - - /// Creates a new `Users` instance that passes all addresses except for the - /// ones in `list`. - pub fn from_set(list: HashSet
) -> Self { - Self { - list, - onchain: None, - } - } - - /// Returns a subset of addresses from the input iterator which are banned. - /// - /// On cache-misses, it will use the Chainalysis oracle to fetch the users. - pub async fn banned(&self, addresses: impl IntoIterator) -> HashSet
{ - let mut banned = HashSet::new(); - - let need_lookup = addresses - .into_iter() - .filter(|address| { - if self.list.contains(address) { - banned.insert(*address); - false - } else { - true - } - }) - // Need to collect here to make sure filter gets executed and we insert addresses - .collect::>(); - - let Some(onchain) = &self.onchain else { - return banned; - }; - let need_lookup: Vec<_> = { - let mut filtered = Vec::new(); - for address in need_lookup { - match onchain.cache.get(&address) { - Some(metadata) => { - metadata.is_banned.then(|| banned.insert(address)); - } - None => { - filtered.push(address); - } - } - } - filtered - }; - - let to_cache = join_all( - need_lookup - .into_iter() - .map(|address| async move { (address, onchain.fetch(address).await) }), - ) - .await; - - let now = Instant::now(); - for (address, result) in to_cache { - match result { - Ok(is_banned) => { - onchain.cache.insert( - address, - UserMetadata { - is_banned, - last_updated: now, - }, - ); - is_banned.then(|| banned.insert(address)); - } - Err(err) => { - tracing::warn!(?err, ?address, "failed to fetch banned status"); - } - } - } - banned - } -} - -impl Onchain { - async fn fetch(&self, address: Address) -> Result { - Ok(self.contract.isSanctioned(address).call().await?) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("failed to fetch banned users from onchain")] - Onchain(#[from] alloy::contract::Error), -} diff --git a/crates/order-validation/src/banned/cached.rs b/crates/order-validation/src/banned/cached.rs new file mode 100644 index 0000000000..2ac6e66dda --- /dev/null +++ b/crates/order-validation/src/banned/cached.rs @@ -0,0 +1,188 @@ +//! Shared cache fronting every configured banned-user backend. Stores one +//! entry per address (not per address × backend) since callers only ask +//! "banned by anyone?"; backends stay as pure fetchers. + +use { + alloy_primitives::Address, + async_trait::async_trait, + futures::{StreamExt, future::join_all, stream}, + moka::sync::Cache, + std::{ + collections::HashSet, + sync::{Arc, Weak}, + time::{Duration, Instant}, + }, +}; + +/// Caps in-flight fetches so a large miss batch can't burst the backends. +const MAX_CONCURRENT_LOOKUPS: usize = 10; +const CACHE_EXPIRY: Duration = Duration::from_secs(60 * 60); +const MAINTENANCE_TIMEOUT: Duration = Duration::from_secs(60); + +#[derive(Clone)] +struct Entry { + is_banned: bool, + last_updated: Instant, +} + +#[derive(Debug, thiserror::Error)] +pub(super) enum BackendError { + #[error("chainalysis lookup failed")] + Chainalysis(#[from] alloy_contract::Error), + + #[error("hermod lookup failed")] + Hermod(#[from] super::hermod::Error), +} + +/// Pure banned-address fetcher; caching and refresh live in [`Cached`]. +#[async_trait] +pub(super) trait Backend: Send + Sync + 'static { + async fn fetch(&self, address: Address) -> Result; + + fn name(&self) -> &'static str; +} + +/// Single cache fronting every configured backend. A miss fans out to every +/// backend in parallel and stores the OR of the results. +pub(super) struct Cached { + backends: Vec>, + cache: Cache, +} + +impl Cached { + /// Returns `None` when no backends are configured. + pub(super) fn new(backends: Vec>, max_capacity: u64) -> Option> { + if backends.is_empty() { + return None; + } + let cached = Arc::new(Self { + backends, + cache: Cache::builder().max_capacity(max_capacity).build(), + }); + cached.spawn_maintenance_task(); + Some(cached) + } + + /// Returns the subset reported as banned by any backend. Misses fan out + /// to backends concurrently. + pub(super) async fn check(&self, addresses: &HashSet
) -> HashSet
{ + let mut banned = HashSet::new(); + let mut need_lookup = Vec::new(); + for address in addresses { + match self.cache.get(address) { + Some(entry) => { + entry.is_banned.then(|| banned.insert(*address)); + } + None => need_lookup.push(*address), + } + } + + let fetched: Vec<_> = stream::iter(need_lookup) + .map(|address| async move { (address, self.fetch_all(address).await) }) + .buffer_unordered(MAX_CONCURRENT_LOOKUPS) + .collect() + .await; + + let now = Instant::now(); + for (address, is_banned) in fetched { + let Some(is_banned) = is_banned else { continue }; + self.cache.insert( + address, + Entry { + is_banned, + last_updated: now, + }, + ); + if is_banned { + banned.insert(address); + } + } + + banned + } + + /// `Some(true)` as soon as any backend confirms a ban — a failure + /// elsewhere must not mask a positive hit. `None` means no confirmation + /// and at least one failure, so the caller skips caching. + async fn fetch_all(&self, address: Address) -> Option { + let results = join_all(self.backends.iter().map(|b| fetch_one(b.as_ref(), address))).await; + if results.iter().any(|r| matches!(r, Some(true))) { + Some(true) + } else if results.iter().any(Option::is_none) { + None + } else { + Some(false) + } + } + + /// Collects cache entries close enough to expiry that the next maintenance + /// tick may miss the window. + fn expired(&self, now: Instant) -> Vec> { + self.cache + .iter() + .filter_map(|(address, entry)| { + let due = now + .checked_duration_since(entry.last_updated) + .unwrap_or_default() + >= CACHE_EXPIRY - MAINTENANCE_TIMEOUT; + due.then_some(address) + }) + .collect() + } + + /// `None` (existing entry preserved) when `fetch_all` is uncertain — no + /// positive confirmation and at least one backend failed. + async fn refresh(&self, address: Address) -> Option<(Address, Entry)> { + let is_banned = self.fetch_all(address).await?; + Some(( + address, + Entry { + is_banned, + last_updated: Instant::now(), + }, + )) + } + + /// Spawns a background task that periodically refreshes near-expiry cache + /// entries so callers rarely observe a cold miss. Holds a [`Weak`] handle + /// so the task exits once the last external [`Arc`] is dropped. + fn spawn_maintenance_task(self: &Arc) { + let weak: Weak = Arc::downgrade(self); + tokio::task::spawn(async move { + let mut interval = tokio::time::interval(MAINTENANCE_TIMEOUT); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); + loop { + interval.tick().await; + let Some(this) = weak.upgrade() else { return }; + let now = Instant::now(); + let expired = this.expired(now); + + let refreshed: Vec<_> = stream::iter(expired) + .map(|address| this.refresh(*address)) + .buffer_unordered(MAX_CONCURRENT_LOOKUPS) + .collect() + .await; + + for (address, entry) in refreshed.into_iter().flatten() { + this.cache.insert(address, entry); + } + } + }); + } +} + +/// Logs and swallows backend errors so callers can OR successful results. +async fn fetch_one(backend: &dyn Backend, address: Address) -> Option { + match backend.fetch(address).await { + Ok(banned) => Some(banned), + Err(err) => { + tracing::warn!( + backend = backend.name(), + ?address, + ?err, + "failed to fetch banned status", + ); + None + } + } +} diff --git a/crates/order-validation/src/banned/hermod.rs b/crates/order-validation/src/banned/hermod.rs new file mode 100644 index 0000000000..7de194385c --- /dev/null +++ b/crates/order-validation/src/banned/hermod.rs @@ -0,0 +1,134 @@ +//! Hermod (zeroShadow) sanctioned-address fetcher. Queries are +//! HMAC-SHA256-signed; hit = HTTP 200, miss = HTTP 404. + +use { + super::cached::{Backend, BackendError}, + alloy_primitives::Address, + async_trait::async_trait, + hmac::{Hmac, Mac}, + sha2::Sha256, + std::time::Duration, + url::Url, +}; + +const REQUEST_TIMEOUT: Duration = Duration::from_secs(5); + +/// Configuration for the Hermod (zeroShadow) sanctioned-address checker. +#[derive(Debug, Clone)] +pub struct Config { + /// Base URL of the Hermod agent (e.g. `http://hermod:3000`). + pub url: Url, + /// Per-customer HMAC key used to obfuscate addresses before sending. + pub hmac_key: String, + /// Optional API key sent as a Bearer token. + pub api_key: Option, +} + +#[derive(Debug, thiserror::Error)] +pub(super) enum Error { + #[error("request failed")] + Request(#[from] reqwest::Error), + #[error("unexpected status code: {0}")] + UnexpectedStatus(reqwest::StatusCode), +} + +pub(super) struct Client { + client: reqwest::Client, + url: Url, + hmac_key: Vec, + api_key: Option, +} + +impl Client { + pub(super) fn new(config: Config) -> Self { + // Make sure the URL ends with a slash so joining `addresses/` + // appends rather than replaces the last path segment. + let mut url = config.url; + if !url.path().ends_with('/') { + let with_slash = format!("{}/", url.path()); + url.set_path(&with_slash); + } + Self { + client: reqwest::Client::builder() + .timeout(REQUEST_TIMEOUT) + .build() + .expect("reqwest client builder with default TLS settings is infallible"), + url, + hmac_key: config.hmac_key.into_bytes(), + api_key: config.api_key, + } + } + + /// HMAC-SHA256 of the address textual payload, encoded as lowercase hex. + fn sign(&self, address: Address) -> String { + // Hermod expects the lowercase `0x`-prefixed address (42 chars). + let payload = const_hex::encode_prefixed(address); + let mut mac = Hmac::::new_from_slice(&self.hmac_key) + .expect("HMAC accepts keys of any length"); + mac.update(payload.as_bytes()); + const_hex::encode(mac.finalize().into_bytes()) + } + + async fn fetch_status(&self, address: Address) -> Result { + let signature = self.sign(address); + let endpoint = self + .url + .join(&format!("addresses/{signature}")) + .expect("base url is valid and signature is hex"); + + let mut request = self.client.get(endpoint); + if let Some(api_key) = &self.api_key { + request = request.bearer_auth(api_key); + } + let response = request.send().await?; + match response.status() { + reqwest::StatusCode::OK => Ok(true), + reqwest::StatusCode::NOT_FOUND => Ok(false), + status => Err(Error::UnexpectedStatus(status)), + } + } +} + +#[async_trait] +impl Backend for Client { + async fn fetch(&self, address: Address) -> Result { + Ok(self.fetch_status(address).await?) + } + + fn name(&self) -> &'static str { + "hermod" + } +} + +#[cfg(test)] +mod tests { + use {super::*, alloy_primitives::address}; + + fn backend() -> Client { + Client::new(Config { + url: "http://hermod:3000".parse().unwrap(), + hmac_key: "key".to_string(), + api_key: None, + }) + } + + #[tokio::test] + async fn hmac_signature_is_deterministic() { + let hermod = backend(); + let addr = address!("dead000000000000000000000000000000000000"); + assert_eq!(hermod.sign(addr), hermod.sign(addr)); + assert_eq!(hermod.sign(addr).len(), 64); + } + + #[tokio::test] + async fn base_url_without_trailing_slash_is_normalised() { + let hermod = Client::new(Config { + url: "http://hermod:3000/v1".parse().unwrap(), + hmac_key: "key".to_string(), + api_key: None, + }); + assert!(hermod.url.as_str().ends_with('/')); + let joined = hermod.url.join("addresses/abc").unwrap(); + assert_eq!(joined.as_str(), "http://hermod:3000/v1/addresses/abc"); + } +} diff --git a/crates/order-validation/src/banned/mod.rs b/crates/order-validation/src/banned/mod.rs new file mode 100644 index 0000000000..af9a78eb49 --- /dev/null +++ b/crates/order-validation/src/banned/mod.rs @@ -0,0 +1,85 @@ +//! Banned user detection: hardcoded list + optional Chainalysis Oracle +//! and/or Hermod (zeroShadow). Remote sources share one cache layer. + +mod cached; +mod hermod; +mod onchain; + +pub use hermod::Config as HermodConfig; +use { + self::{ + cached::{Backend, Cached}, + hermod::Client as Hermod, + onchain::Onchain, + }, + alloy_primitives::Address, + contracts::ChainalysisOracle, + std::{collections::HashSet, sync::Arc}, +}; + +/// A list of banned users and optional registries that can be checked. +pub struct Users { + list: HashSet
, + remote: Option>, +} + +impl Users { + /// Builds the validator from a hardcoded list and optional remote backends. + pub fn new( + contract: Option, + hermod: Option, + banned_users: Vec
, + cache_max_size: u64, + ) -> Self { + let mut backends: Vec> = Vec::new(); + if let Some(contract) = contract { + backends.push(Box::new(Onchain::new(contract))); + } + if let Some(config) = hermod { + backends.push(Box::new(Hermod::new(config))); + } + Self { + list: HashSet::from_iter(banned_users), + remote: Cached::new(backends, cache_max_size), + } + } + + /// Creates a new `Users` instance that passes all addresses. + pub fn none() -> Self { + Self { + list: HashSet::new(), + remote: None, + } + } + + /// Creates a new `Users` instance that passes all addresses except for the + /// ones in `list`. + pub fn from_set(list: HashSet
) -> Self { + Self { list, remote: None } + } + + /// Returns the subset of `addresses` that are banned. Cache misses hit + /// the configured remote sources. + pub async fn banned(&self, addresses: impl IntoIterator) -> HashSet
{ + let mut banned = HashSet::new(); + + let need_lookup = addresses + .into_iter() + .filter(|address| { + if self.list.contains(address) { + banned.insert(*address); + false + } else { + true + } + }) + // Need to collect here to make sure filter gets executed and we insert addresses + .collect::>(); + + if let Some(remote) = &self.remote { + banned.extend(remote.check(&need_lookup).await); + } + + banned + } +} diff --git a/crates/order-validation/src/banned/onchain.rs b/crates/order-validation/src/banned/onchain.rs new file mode 100644 index 0000000000..54d3d322ab --- /dev/null +++ b/crates/order-validation/src/banned/onchain.rs @@ -0,0 +1,32 @@ +//! Chainalysis Oracle-backed sanctioned-address fetcher. +//! +//! Queries the on-chain `isSanctioned` view. Pure fetcher — caching and +//! background refresh are provided by the [`super::cached::Cached`] wrapper. + +use { + super::cached::{Backend, BackendError}, + alloy_primitives::Address, + async_trait::async_trait, + contracts::ChainalysisOracle, +}; + +pub(super) struct Onchain { + contract: ChainalysisOracle::Instance, +} + +impl Onchain { + pub(super) fn new(contract: ChainalysisOracle::Instance) -> Self { + Self { contract } + } +} + +#[async_trait] +impl Backend for Onchain { + async fn fetch(&self, address: Address) -> Result { + Ok(self.contract.isSanctioned(address).call().await?) + } + + fn name(&self) -> &'static str { + "chainalysis" + } +} diff --git a/crates/orderbook/Cargo.toml b/crates/orderbook/Cargo.toml index 10411832f4..22737e4cb4 100644 --- a/crates/orderbook/Cargo.toml +++ b/crates/orderbook/Cargo.toml @@ -7,41 +7,48 @@ license = "GPL-3.0-or-later" build = "build.rs" [lib] +doctest = false name = "orderbook" path = "src/lib.rs" -doctest = false [[bin]] name = "orderbook" path = "src/main.rs" [dependencies] +account-balances = { workspace = true } alloy = { workspace = true } anyhow = { workspace = true } app-data = { workspace = true } async-trait = { workspace = true } +axum = { workspace = true } +bad-tokens = { workspace = true } +balance-overrides = { workspace = true } bigdecimal = { workspace = true } cached = { workspace = true } chain = { workspace = true } chrono = { workspace = true, features = ["clock"] } clap = { workspace = true } +configs = { workspace = true } +const-hex = { workspace = true } contracts = { workspace = true } database = { workspace = true } -ethcontract = { workspace = true } +eth-domain-types = { workspace = true } ethrpc = { workspace = true } futures = { workspace = true } -const-hex = { workspace = true } +gas-price-estimation = { workspace = true } hex-literal = { workspace = true } +http-client = { workspace = true } humantime = { workspace = true } -hyper = { workspace = true } -mimalloc = { workspace = true } +humantime-serde = { workspace = true } +mimalloc = { workspace = true, optional = true } model = { workspace = true } multibase = { workspace = true } num = { workspace = true } number = { workspace = true } -order-validation = { workspace = true } observe = { workspace = true } -primitive-types = { workspace = true } +order-validation = { workspace = true } +price-estimation = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } reqwest = { workspace = true, features = ["json"] } @@ -49,25 +56,37 @@ serde = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } shared = { workspace = true } -strum = { workspace = true } +signature-validator = { workspace = true } +simulator = { workspace = true } sqlx = { workspace = true } +strum = { workspace = true } +tempfile = { workspace = true, optional = true } thiserror = { workspace = true } +tikv-jemallocator = { workspace = true } +token-info = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "sync", "time"] } +toml = { workspace = true } +tower = { workspace = true } +tower-http = { workspace = true, features = ["cors", "trace"] } tracing = { workspace = true } url = { workspace = true } -warp = { workspace = true } [dev-dependencies] +configs = { workspace = true, features = ["test-util"] } mockall = { workspace = true } -tokio = { workspace = true, features = ["test-util"] } shared = { workspace = true, features = ["test-util"] } +tempfile = { workspace = true } +tokio = { workspace = true, features = ["test-util"] } [build-dependencies] anyhow = { workspace = true } vergen = { workspace = true, features = ["git", "gitcl"] } -[lints] -workspace = true - [features] e2e = [] +mimalloc-allocator = ["dep:mimalloc"] +test-util = ["dep:tempfile", "shared/test-util"] +tokio-console = ["observe/tokio-console"] + +[lints] +workspace = true diff --git a/crates/orderbook/openapi.yml b/crates/orderbook/openapi.yml index a8f58c67c7..4e07465519 100644 --- a/crates/orderbook/openapi.yml +++ b/crates/orderbook/openapi.yml @@ -27,14 +27,22 @@ servers: url: "https://api.cow.fi/polygon" - description: Polygon (Staging) url: "https://barn.api.cow.fi/polygon" - - description: Lens (Prod) - url: "https://api.cow.fi/lens" - - description: Lens (Staging) - url: "https://barn.api.cow.fi/lens" + - description: Linea (Prod) + url: "https://api.cow.fi/linea" + - description: Linea (Staging) + url: "https://barn.api.cow.fi/linea" - description: BNB (Prod) url: "https://api.cow.fi/bnb" - description: BNB (Staging) url: "https://barn.api.cow.fi/bnb" + - description: Plasma (Prod) + url: "https://api.cow.fi/plasma" + - description: Plasma (Staging) + url: "https://barn.api.cow.fi/plasma" + - description: Ink (Prod) + url: "https://api.cow.fi/ink" + - description: Ink (Staging) + url: "https://barn.api.cow.fi/ink" - description: Sepolia (Prod) url: "https://api.cow.fi/sepolia" - description: Sepolia (Staging) @@ -73,6 +81,8 @@ paths: description: "Forbidden, your account is deny-listed." "404": description: No route was found quoting the order. + "422": + description: Unable to parse request body as valid JSON. "429": description: Too many order placements. "500": @@ -113,6 +123,62 @@ paths: description: Invalid signature. "404": description: One or more orders were not found and no orders were cancelled. + "422": + description: Unable to parse request body as valid JSON. + "/api/v1/orders/by_uids": + post: + operationId: getOrders + summary: Get existing orders from the list of UIDs. + description: | + Returns an array where each element is an object with either + an "order" key containing the full order, or an "error" key + containing the UID and a description of what went wrong. + requestBody: + description: The list of up to 128 order uids to fetch + required: true + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/UID" + responses: + "200": + description: | + The resulting full order data based on the request. Each element of the array is + an object of the following format: + - `{"order": }` for successfully fetched orders + - `{"error": {"uid": "", "description": ""}}` for orders that failed conversion + The result ordering is not guaranteed and might differ from the order of requested UIDs. + Orders that do not exist in the database will be missing from the response. + content: + application/json: + schema: + oneOf: + - type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + - type: object + properties: + error: + type: object + properties: + uid: + $ref: "#/components/schemas/UID" + description: + type: string + required: + - uid + - description + required: + - error + "400": + description: Request array size larger than 128 or unable to parse request body as valid JSON. + "422": + description: Could not decode array values as order UID. "/api/v1/orders/{UID}": get: operationId: getOrder @@ -130,6 +196,8 @@ paths: application/json: schema: $ref: "#/components/schemas/Order" + "400": + description: Invalid order UID. "404": description: Order was not found. delete: @@ -169,6 +237,8 @@ paths: description: Invalid signature. "404": description: Order was not found. + "422": + description: Unable to parse request body as valid JSON. "/api/v1/orders/{UID}/status": get: operationId: getOrderStatus @@ -188,6 +258,8 @@ paths: application/json: schema: $ref: "#/components/schemas/CompetitionOrderStatus" + "400": + description: Invalid order UID. "/api/v1/transactions/{txHash}/orders": get: operationId: getOrdersByTxHash @@ -207,12 +279,62 @@ paths: type: array items: $ref: "#/components/schemas/Order" + "400": + description: Invalid transaction hash. /api/v1/trades: get: operationId: getTrades - summary: Get existing trades. + summary: Get existing trades (unpaginated). + deprecated: true + description: | + **Deprecated:** This endpoint is deprecated and will be removed in the future. Please use `/api/v2/trades` instead, which provides pagination support. + + Exactly one of `owner` or `orderUid` must be set. + + Results are sorted by block number and log index descending (newest trades first). + + **Note:** This endpoint returns all matching trades without pagination. For paginated results, use `/api/v2/trades`. + parameters: + - name: owner + in: query + schema: + $ref: "#/components/schemas/Address" + required: false + - name: orderUid + in: query + schema: + $ref: "#/components/schemas/UID" + required: false + responses: + "200": + description: |- + ### If `owner` is specified: + + Return all trades related to that `owner`. + + ### If `orderUid` is specified: + + Return all trades related to that `orderUid`. Given that an order + may be partially fillable, it is possible that an individual order + may have *multiple* trades. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Trade" + /api/v2/trades: + get: + operationId: getTradesV2 + summary: Get existing trades (paginated). description: | Exactly one of `owner` or `orderUid` must be set. + + Results are paginated and sorted by block number and log index descending (newest trades first). + + To enumerate all trades start with `offset` 0 and keep increasing the + `offset` by the total number of returned results. When a response + contains less than `limit` the last page has been reached. parameters: - name: owner in: query @@ -224,6 +346,22 @@ paths: schema: $ref: "#/components/schemas/UID" required: false + - name: offset + in: query + description: | + The pagination offset. Defaults to 0. + schema: + type: integer + required: false + - name: limit + in: query + description: | + The maximum number of trades to return. Defaults to 10. Must be between 1 and 1000. + schema: + type: integer + minimum: 1 + maximum: 1000 + required: false responses: "200": description: |- @@ -363,73 +501,33 @@ paths: application/json: schema: $ref: "#/components/schemas/PriceEstimationError" - "404": - description: No route was found for the specified order. - "429": - description: Too many order quotes. - "500": - description: Unexpected error quoting an order. - "/api/v1/solver_competition/{auction_id}": - get: - operationId: getSolverCompetitionByAuctionId - deprecated: true - summary: Get information about a solver competition. - description: | - Returns the competition information by `auction_id`. - parameters: - - name: auction_id - in: path - required: true - schema: - type: integer - responses: - "200": - description: Competition + "403": + description: >- + Forbidden, the order owner is deny-listed (`errorType`: + `Forbidden`). content: application/json: schema: - $ref: "#/components/schemas/SolverCompetitionResponse" + $ref: "#/components/schemas/PriceEstimationError" "404": - description: No competition information available for this auction id. - "/api/v1/solver_competition/by_tx_hash/{tx_hash}": - get: - operationId: getSolverCompetitionByTxHash - deprecated: true - summary: Get information about solver competition. - description: | - Returns the competition information by `tx_hash`. - parameters: - - name: tx_hash - description: Transaction hash in which the competition was settled. - in: path - required: true - schema: - $ref: "#/components/schemas/TransactionHash" - responses: - "200": - description: Competition + description: >- + No route was found for the specified order (`errorType`: + `NoLiquidity`). content: application/json: schema: - $ref: "#/components/schemas/SolverCompetitionResponse" - "404": - description: No competition information available for this `tx_hash`. - /api/v1/solver_competition/latest: - get: - operationId: getSolverCompetitionLatest - deprecated: true - summary: Get information about the most recent solver competition. - description: | - Returns the competition information for the last seen auction_id. - responses: - "200": - description: Competition + $ref: "#/components/schemas/PriceEstimationError" + "422": + description: Unable to parse request body as valid JSON. + "429": + description: Too many order quotes. + "500": + description: >- + Unexpected error (`errorType`: `InternalServerError`). content: application/json: schema: - $ref: "#/components/schemas/SolverCompetitionResponse" - "404": - description: No competition information available. + $ref: "#/components/schemas/PriceEstimationError" "/api/v2/solver_competition/{auction_id}": get: operationId: getSolverCompetitionByAuctionIdV2 @@ -449,6 +547,8 @@ paths: application/json: schema: $ref: "#/components/schemas/SolverCompetitionResponse" + "400": + description: Invalid auction ID. "404": description: No competition information available for this auction id. "/api/v2/solver_competition/by_tx_hash/{tx_hash}": @@ -471,6 +571,8 @@ paths: application/json: schema: $ref: "#/components/schemas/SolverCompetitionResponse" + "400": + description: Invalid transaction hash. "404": description: No competition information available for this `tx_hash`. /api/v2/solver_competition/latest: @@ -517,6 +619,8 @@ paths: application/json: schema: $ref: "#/components/schemas/AppDataObject" + "400": + description: Invalid app data hash. "404": description: No full `appData` stored for this hash. put: @@ -554,6 +658,8 @@ paths: $ref: "#/components/schemas/AppDataHash" "400": description: Error validating full `appData` + "422": + description: Unable to parse request body as valid JSON. "500": description: Error storing the full `appData` /api/v1/app_data: @@ -585,6 +691,8 @@ paths: $ref: "#/components/schemas/AppDataHash" "400": description: Error validating full `appData` + "422": + description: Unable to parse request body as valid JSON. "500": description: Error storing the full `appData` "/api/v1/users/{address}/total_surplus": @@ -609,6 +717,106 @@ paths: application/json: schema: $ref: "#/components/schemas/TotalSurplus" + "400": + description: Invalid address. + "/restricted/api/v1/debug/simulation": + post: + operationId: debugSimulationPost + summary: Simulate an arbitrary order. + description: > + Simulates an arbitrary order specified in the request body and returns + the Tenderly simulation request, along with any simulation error if + applicable. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/SimulationRequest" + responses: + "200": + description: Simulation request returned. + content: + application/json: + schema: + $ref: "#/components/schemas/OrderSimulation" + "400": + description: > + Invalid JSON body, or `appData` is not valid JSON. + "405": + description: Order simulation endpoint is not enabled. + "422": + description: > + Request body failed schema validation: missing required field, + wrong field type, zero `sellAmount`, or unrecognised `kind` value. + "500": + description: Internal error. + "/restricted/api/v1/debug/simulation/{uid}": + get: + operationId: debugSimulation + summary: Get Tenderly simulation request for an order. + description: > + Returns the Tenderly simulation request that would be used to simulate + the given order, along with any simulation error if applicable. + parameters: + - in: path + name: uid + schema: + $ref: "#/components/schemas/UID" + required: true + - in: query + name: block_number + schema: + type: integer + format: int64 + required: false + description: > + Block number to simulate the order at. If not specified, the + simulation uses the latest block. + responses: + "200": + description: Simulation request returned. + content: + application/json: + schema: + $ref: "#/components/schemas/OrderSimulation" + "400": + description: > + Malformed path parameter (invalid order UID format) or invalid + `block_number` query parameter. + "404": + description: Order not found. + "405": + description: Order simulation endpoint is not enabled. + "500": + description: Internal error. + "/restricted/api/v1/debug/order/{uid}": + get: + operationId: debugOrder + summary: Debug an order's lifecycle. + description: > + Returns a comprehensive debug report for the given order, including + order details, lifecycle events, auction participation, proposed + solutions, executions, trades, and settlement attempts. + parameters: + - in: path + name: uid + schema: + $ref: "#/components/schemas/UID" + required: true + responses: + "200": + description: Debug report returned. + content: + application/json: + schema: + $ref: "#/components/schemas/DebugOrderResponse" + "400": + description: Invalid order UID (malformed hex or wrong length). + "404": + description: Order not found. + "500": + description: Internal error. components: schemas: TransactionHash: @@ -781,11 +989,45 @@ components: description: Unix timestamp (`uint32`) until which the order is valid. type: integer appData: - $ref: "#/components/schemas/AppDataHash" + description: > + The app data associated with the order. In quote responses, this can be + either the full app data JSON string or the app data hash, depending on + what was provided in the quote request. + oneOf: + - $ref: "#/components/schemas/AppData" + - $ref: "#/components/schemas/AppDataHash" + appDataHash: + description: > + The hash of the app data. Only present when the full app data is also + provided in the `appData` field. + allOf: + - $ref: "#/components/schemas/AppDataHash" feeAmount: - description: sellAmount in atoms to cover network fees. Needs to be zero (and incorporated into the limit price) when placing the order + description: | + The fee amount in sell token atoms. For quote responses, this represents + the estimated network fee, calculated as: + `feeAmount = ceil((gasAmount * gasPrice) / sellTokenPrice)`. + + When creating an order, this should be set to zero as fees are now + computed dynamically by solvers. allOf: - $ref: "#/components/schemas/TokenAmount" + gasAmount: + description: | + The estimated gas units required to execute the quoted trade. + type: string + example: "150000" + gasPrice: + description: | + The estimated gas price at the time of quoting, measured in Wei per gas unit. + type: string + example: "15000000000" + sellTokenPrice: + description: | + Represents how much one atomic unit of the sell token is worth + in the network's native token (in Wei or the equivalent atom). + type: string + example: "0.0004" kind: description: The kind is either a buy or sell order. allOf: @@ -794,14 +1036,23 @@ components: description: Is the order fill-or-kill or partially fillable? type: boolean sellTokenBalance: + description: > + Where the sell token should be drawn from. Defaults to `erc20` for + standard ERC-20 token transfers. allOf: - $ref: "#/components/schemas/SellTokenSource" default: erc20 buyTokenBalance: + description: > + Where the buy token should be transferred to. Defaults to `erc20` for + standard ERC-20 token transfers. allOf: - $ref: "#/components/schemas/BuyTokenDestination" default: erc20 signingScheme: + description: > + The signing scheme to use for the order. Defaults to `eip712` for + standard typed data signing. allOf: - $ref: "#/components/schemas/SigningScheme" default: eip712 @@ -813,6 +1064,9 @@ components: - validTo - appData - feeAmount + - gasAmount + - gasPrice + - sellTokenPrice - kind - partiallyFillable OrderCreation: @@ -943,6 +1197,14 @@ components: allOf: - $ref: "#/components/schemas/AppDataHash" nullable: true + fullBalanceCheck: + description: > + If set to true, full sell amount will be checked during allowance and balance checking. + This will ensure the account has correct allowance and available balance for the order + to be created. + + type: boolean + default: false required: - sellToken - buyToken @@ -966,11 +1228,24 @@ components: type: string example: "2020-12-03T18:35:18.814523Z" class: - $ref: "#/components/schemas/OrderClass" + description: > + The class of the order (market, limit, or liquidity). Determines + how fees are handled. + allOf: + - $ref: "#/components/schemas/OrderClass" owner: - $ref: "#/components/schemas/Address" + description: > + The address that signed the order and owns it. For regular orders, + this is the trader. For EIP 1271 orders, it's the respective contract + (see `onchainUser` for the actual trader). + allOf: + - $ref: "#/components/schemas/Address" uid: - $ref: "#/components/schemas/UID" + description: > + Unique identifier of the order. Computed as the EIP-712 hash of the + order data combined with the owner address and valid_to timestamp. + allOf: + - $ref: "#/components/schemas/UID" availableBalance: description: > Unused field that is currently always set to `null` and will be @@ -1027,6 +1302,10 @@ components: traded otherwise and should not expect to get surplus. type: boolean ethflowData: + description: > + Additional data specific to ethflow orders. Only present for orders + placed through the EthFlow contract, which allows trading native ETH + directly without wrapping to WETH first. allOf: - $ref: "#/components/schemas/EthflowData" onchainUser: @@ -1063,6 +1342,22 @@ components: `OrderCreation` for more information. type: string nullable: true + settlementContract: + description: > + The address of the CoW Protocol settlement contract that this order + is valid for. Orders are only valid on the settlement contract they + were signed for. + allOf: + - $ref: "#/components/schemas/Address" + quote: + description: > + If the order was created with a quote, this field contains the original + quote data for reference. Includes gas estimation and pricing information + captured at the time of quoting, which can be used to analyze order + execution and calculate fees. + allOf: + - $ref: "#/components/schemas/StoredOrderQuote" + nullable: true required: - creationDate - class @@ -1074,10 +1369,37 @@ components: - executedFeeAmount - invalidated - status + - settlementContract Order: + description: > + An order as returned by the API. Combines the order creation data, + order metadata, and any associated interactions. allOf: - $ref: "#/components/schemas/OrderCreation" - $ref: "#/components/schemas/OrderMetaData" + - type: object + properties: + interactions: + description: > + Optional pre and post interactions associated with the order. + Pre-interactions are executed before the order's trade, and + post-interactions are executed after. + type: object + properties: + pre: + description: > + Interactions to be executed before the order's trade. + These can be used for setup operations like token approvals. + type: array + items: + $ref: "#/components/schemas/InteractionData" + post: + description: > + Interactions to be executed after the order's trade. + These can be used for cleanup or follow-up operations. + type: array + items: + $ref: "#/components/schemas/InteractionData" AuctionOrder: description: > A solvable order included in the current batch auction. Contains the @@ -1298,7 +1620,7 @@ components: properties: orderUids: type: array - description: UIDs of orders to cancel. + description: Up to 128 UIDs of orders to cancel. items: $ref: "#/components/schemas/UID" signature: @@ -1465,7 +1787,9 @@ components: - UnsupportedToken - InvalidAppData - AppDataHashMismatch + - AppDataMismatch - AppdataFromMismatch + - MetadataSerializationFailed - OldOrderActivelyBidOn description: type: string @@ -1491,17 +1815,51 @@ components: - errorType - description PriceEstimationError: + description: | + Error quoting an order. + + Possible `errorType` values per HTTP status: + * 400: `AppDataHashMismatch`, `CustomSolverError`, `ExcessiveValidTo`, + `InsufficientLiquidity`, `InsufficientValidTo`, `InvalidAppData`, + `InvalidNativeSellToken`, `QuoteNotVerified`, `SameBuyAndSellToken`, + `SellAmountDoesNotCoverFee`, `TokenTemporarilySuspended`, + `TradingOutsideAllowedWindow`, `UnsupportedBuyTokenDestination`, + `UnsupportedOrderType`, `UnsupportedSellTokenSource`, + `UnsupportedToken` + * 403: `Forbidden` + * 404: `NoLiquidity` + * 500: `InternalServerError` type: object properties: errorType: type: string enum: + - AppDataHashMismatch + - CustomSolverError + - ExcessiveValidTo + - Forbidden + - InsufficientLiquidity + - InsufficientValidTo + - InternalServerError + - InvalidAppData + - InvalidNativeSellToken + - NoLiquidity - QuoteNotVerified - - UnsupportedToken - - ZeroAmount + - SameBuyAndSellToken + - SellAmountDoesNotCoverFee + - TokenTemporarilySuspended + - TradingOutsideAllowedWindow + - UnsupportedBuyTokenDestination - UnsupportedOrderType + - UnsupportedSellTokenSource + - UnsupportedToken description: type: string + data: + type: object + description: >- + Optional error-specific payload: `SellAmountDoesNotCoverFee` + returns an object with `fee_amount`. required: - errorType - description @@ -1647,11 +2005,11 @@ components: timeout: type: integer description: > - User provided timeout in milliseconds. Can only be used to reduce - the response time for quote requests if the default is too slow - as values greater than the default will be capped to the default. + User provided timeout in milliseconds. If no value is provided + the systems default quote timeout will be used. Values get capped + at a generous maximum timeout. Note that reducing the timeout can result in worse quotes because - the reduced timeout might be too slow for some price estimators. + it might be too short for some price estimators. required: - sellToken - buyToken @@ -1663,9 +2021,16 @@ components: type: object properties: quote: - $ref: "#/components/schemas/OrderParameters" + description: > + The quoted order parameters. These values can be used directly to + create and sign an order. + allOf: + - $ref: "#/components/schemas/OrderParameters" from: - $ref: "#/components/schemas/Address" + description: > + The address of the trader for whom the quote was requested. + allOf: + - $ref: "#/components/schemas/Address" expiration: description: | Expiration date of the offered fee. Order service might not accept @@ -1685,17 +2050,9 @@ components: protocolFeeBps: description: > Protocol fee in basis points (e.g., "2" for 0.02%). This represents - the volume-based fee policy. Only present when configured. + the volume-based fee policy. Only present when a volume fee is configured. type: string example: "2" - protocolFeeSellAmount: - description: > - Protocol fee amount in sell token. For SELL orders, this amount is - already included in the returned sellAmount. For BUY orders, this - amount is applied before network fees are added to sellAmount. Only - present when a volume fee is configured. - allOf: - - $ref: "#/components/schemas/TokenAmount" required: - quote - expiration @@ -1713,6 +2070,9 @@ components: auctionStartBlock: type: integer description: Block that the auction started on. + auctionDeadlineBlock: + type: integer + description: Block deadline by which the auction must be settled. transactionHashes: type: array description: | @@ -1765,11 +2125,18 @@ components: Transaction in which the solution was executed onchain (if available). nullable: true clearingPrices: + deprecated: true type: object additionalProperties: $ref: "#/components/schemas/BigUint" description: > - The prices of tokens for settled user orders as passed to the + Deprecated. The autopilot no longer persists per-solution uniform + clearing prices, so this field will be empty for solutions of + auctions produced by recent autopilots. Solutions stored before + this change keep their original values. + + + The prices of tokens for settled user orders as passed to the settlement contract. orders: type: array @@ -1806,20 +2173,116 @@ components: type: string description: The total surplus. InteractionData: + description: > + Represents a smart contract interaction that can be executed as part of + an order's pre or post hooks. type: object properties: target: - $ref: "#/components/schemas/Address" + description: The address of the contract to call. + allOf: + - $ref: "#/components/schemas/Address" value: - $ref: "#/components/schemas/TokenAmount" - call_data: - type: array - items: - $ref: "#/components/schemas/CallData" - description: The call data to be used for the interaction. + description: > + The amount of native token (ETH, xDAI, etc.) in Wei to send with the + interaction call. + allOf: + - $ref: "#/components/schemas/TokenAmount" + callData: + description: > + The calldata to be sent to the target contract. Encoded as a hex + string with `0x` prefix. + allOf: + - $ref: "#/components/schemas/CallData" + required: + - target + - value + - callData + StoredOrderQuote: + description: | + Quote data stored with an order. This represents the original quote used to + create the order, containing gas estimation and pricing information captured + at the time of quoting. + + Note: This is different from `OrderQuoteResponse` which is returned by the + `POST /api/v1/quote` endpoint and contains order parameters to sign. + type: object + properties: + gasAmount: + description: | + The estimated gas units required to execute the quoted trade. + Measured in gas units (not Wei). Used together with `gasPrice` and + `sellTokenPrice` to calculate the network fee in sell token atoms. + type: string + example: "150000" + gasPrice: + description: | + The estimated gas price at the time of quoting, measured in Wei per gas unit. + The network fee in Wei can be calculated as: `feeInWei = gasAmount * gasPrice`. + type: string + example: "15000000000" + sellTokenPrice: + description: | + The price of the sell token expressed in native token atoms per sell token atom. + + Units: `native token atoms / sell token atoms` + + **Example calculation (Mainnet, selling USDC):** + - Sell token: USDC (6 decimals) + - Native token: ETH (18 decimals) + - Market price: 1 ETH = 1000 USDC + + `sellTokenPrice = 1 × 10^18 wei / (1000 × 10^6 USDC atoms) = 10^9` + + This value is used to convert network fees (in native token) to sell token amounts. + type: string + example: "1000000000" + sellAmount: + description: The quoted sell amount in atoms of the sell token. + allOf: + - $ref: "#/components/schemas/TokenAmount" + buyAmount: + description: The quoted buy amount in atoms of the buy token. + allOf: + - $ref: "#/components/schemas/TokenAmount" + feeAmount: + description: | + The fee amount in atoms of the sell token, calculated from the gas parameters + at the time of quoting. + + Computed as: `ceil((gasAmount * gasPrice) / sellTokenPrice)`. + + This represents the network fee that was estimated when the quote was created. + allOf: + - $ref: "#/components/schemas/TokenAmount" + solver: + description: The address of the solver that provided this quote. + allOf: + - $ref: "#/components/schemas/Address" + verified: + description: | + Whether the quote was verified through simulation. A verified quote + provides higher confidence that the trade will execute successfully. + type: boolean + metadata: + description: | + Additional metadata about the quote execution plan (e.g., the route taken). + This field is only populated for orders that are no longer fillable + (filled, cancelled, or expired) to prevent solvers from copying + execution strategies for active orders. + type: object + required: + - gasAmount + - gasPrice + - sellTokenPrice + - sellAmount + - buyAmount + - feeAmount + - solver + - verified Quote: description: | - A calculated order quote. + A calculated order quote used in solver auctions. type: object properties: sellAmount: @@ -1887,11 +2350,27 @@ components: - maxVolumeFactor - quote FeePolicy: - description: Defines the ways to calculate the protocol fee. + description: > + Defines the ways to calculate the protocol fee. oneOf: - - $ref: "#/components/schemas/Surplus" - - $ref: "#/components/schemas/Volume" - - $ref: "#/components/schemas/PriceImprovement" + - type: object + properties: + surplus: + $ref: "#/components/schemas/Surplus" + required: + - surplus + - type: object + properties: + volume: + $ref: "#/components/schemas/Volume" + required: + - volume + - type: object + properties: + priceImprovement: + $ref: "#/components/schemas/PriceImprovement" + required: + - priceImprovement ExecutedProtocolFee: type: object properties: @@ -1905,3 +2384,419 @@ components: allOf: - description: The token in which the fee is taken - $ref: "#/components/schemas/Address" + DebugOrderResponse: + type: object + required: + - orderUid + - order + - events + - auctions + - trades + properties: + orderUid: + description: The UID of the order being debugged. + allOf: + - $ref: "#/components/schemas/UID" + order: + $ref: "#/components/schemas/Order" + events: + type: array + items: + $ref: "#/components/schemas/DebugEvent" + auctions: + description: > + Auctions this order participated in, sorted by ID. Each auction + groups all related data: native prices, proposed solutions, + executions, settlement attempts, and fee policies. + type: array + items: + $ref: "#/components/schemas/DebugAuction" + trades: + type: array + items: + $ref: "#/components/schemas/DebugTrade" + DebugEvent: + type: object + required: + - label + - timestamp + properties: + label: + type: string + description: Event type (e.g. created, ready, filtered, traded). + timestamp: + type: string + format: date-time + reason: + type: string + nullable: true + description: > + Why the order was filtered or marked invalid. Only present for + "filtered" and "invalid" events. + DebugAuction: + type: object + required: + - id + - block + - deadline + - nativePrices + - proposedSolutions + - executions + - settlementAttempts + - feePolicies + properties: + id: + type: integer + description: Auction ID. + block: + type: integer + description: Block number of the auction. + deadline: + type: integer + description: Deadline block for the auction. + nativePrices: + type: object + additionalProperties: + type: string + description: > + Native prices for the order's sell and buy tokens in this auction. + Keys are hex-encoded token addresses, values are decimal price + strings. + proposedSolutions: + type: array + items: + $ref: "#/components/schemas/DebugProposedSolution" + executions: + type: array + items: + $ref: "#/components/schemas/DebugExecution" + settlementAttempts: + type: array + items: + $ref: "#/components/schemas/DebugSettlementAttempt" + feePolicies: + type: array + items: + $ref: "#/components/schemas/DebugFeePolicy" + DebugProposedSolution: + type: object + required: + - solutionUid + - ranking + - solver + - isWinner + - filteredOut + - score + - executedSell + - executedBuy + properties: + solutionUid: + type: integer + ranking: + type: integer + solver: + $ref: "#/components/schemas/Address" + isWinner: + type: boolean + filteredOut: + type: boolean + score: + type: string + description: Decimal-encoded score. + executedSell: + $ref: "#/components/schemas/TokenAmount" + executedBuy: + $ref: "#/components/schemas/TokenAmount" + DebugExecution: + type: object + required: + - executedFee + - executedFeeToken + - blockNumber + - protocolFees + properties: + executedFee: + $ref: "#/components/schemas/TokenAmount" + executedFeeToken: + $ref: "#/components/schemas/Address" + blockNumber: + type: integer + protocolFees: + type: array + items: + $ref: "#/components/schemas/DebugProtocolFee" + DebugProtocolFee: + type: object + required: + - token + - amount + properties: + token: + $ref: "#/components/schemas/Address" + amount: + $ref: "#/components/schemas/TokenAmount" + DebugTrade: + type: object + required: + - blockNumber + - logIndex + - buyAmount + - sellAmount + - sellAmountBeforeFees + properties: + blockNumber: + type: integer + logIndex: + type: integer + buyAmount: + $ref: "#/components/schemas/TokenAmount" + sellAmount: + $ref: "#/components/schemas/TokenAmount" + sellAmountBeforeFees: + $ref: "#/components/schemas/TokenAmount" + txHash: + $ref: "#/components/schemas/TransactionHash" + auctionId: + type: integer + DebugSettlementAttempt: + type: object + required: + - solver + - solutionUid + - startTimestamp + - startBlock + - deadlineBlock + properties: + solver: + $ref: "#/components/schemas/Address" + solutionUid: + type: integer + startTimestamp: + type: string + format: date-time + endTimestamp: + type: string + format: date-time + startBlock: + type: integer + endBlock: + type: integer + deadlineBlock: + type: integer + outcome: + type: string + description: Settlement outcome (e.g. "success", "revert"). + DebugFeePolicy: + type: object + description: Fee policy applied to this order in this auction. + required: + - kind + properties: + kind: + type: string + enum: [surplus, volume, priceImprovement] + surplusFactor: + type: number + surplusMaxVolumeFactor: + type: number + volumeFactor: + type: number + priceImprovementFactor: + type: number + priceImprovementMaxVolumeFactor: + type: number + SimulationType: + description: The kind of Tenderly simulation to run. + type: string + enum: + - full + - quick + AccessListItem: + type: object + properties: + address: + $ref: "#/components/schemas/Address" + storage_keys: + type: array + items: + description: 32 byte storage key encoded as hex with `0x` prefix. + type: string + example: "0x0000000000000000000000000000000000000000000000000000000000000000" + required: + - address + - storage_keys + StateObject: + description: State overrides for a given account before simulation. + type: object + properties: + balance: + description: Fake balance to set for the account (decimal-encoded uint256). + type: string + example: "1000000000000000000" + code: + description: Fake EVM bytecode to inject into the account (hex with `0x` prefix). + type: string + example: "0x6080604052" + storage: + description: > + Fake key-value mapping to override individual storage slots. + Keys and values are 32-byte hex strings with `0x` prefix. + type: object + additionalProperties: + type: string + TenderlyRequest: + description: A Tenderly transaction simulation request. + type: object + properties: + network_id: + description: The network identifier (e.g. "1" for mainnet). + type: string + example: "1" + block_number: + description: Block number to simulate the transaction at. + type: integer + transaction_index: + description: Transaction index within the block. + type: integer + from: + $ref: "#/components/schemas/Address" + to: + $ref: "#/components/schemas/Address" + input: + allOf: + - $ref: "#/components/schemas/CallData" + description: Transaction calldata encoded as hex with `0x` prefix. + gas: + description: Gas limit for the transaction. + type: integer + gas_price: + description: Gas price in Wei. + type: integer + value: + description: ETH value to send with the transaction (decimal-encoded uint256). + type: string + example: "0" + simulation_type: + $ref: "#/components/schemas/SimulationType" + save: + description: Whether to save the simulation on Tenderly. + type: boolean + save_if_fails: + description: Whether to save the simulation only if it fails. + type: boolean + generate_access_list: + description: Whether to generate an access list for the transaction. + type: boolean + state_objects: + description: > + State overrides applied before simulation. Keys are account + addresses (hex with `0x` prefix). + type: object + additionalProperties: + $ref: "#/components/schemas/StateObject" + access_list: + description: EIP-2930 access list for the transaction. + type: array + items: + $ref: "#/components/schemas/AccessListItem" + required: + - network_id + - from + - to + - input + SimulationRequest: + description: > + Request body for simulating an arbitrary order without it being stored + in the orderbook. + type: object + properties: + sellToken: + description: The token being sold. + allOf: + - $ref: "#/components/schemas/Address" + buyToken: + description: The token being bought. + allOf: + - $ref: "#/components/schemas/Address" + sellAmount: + description: > + Amount of sell token (hex- or decimal-encoded uint256). Must be + greater than zero. + allOf: + - $ref: "#/components/schemas/TokenAmount" + buyAmount: + description: Amount of buy token (hex- or decimal-encoded uint256). + allOf: + - $ref: "#/components/schemas/TokenAmount" + kind: + description: Whether this is a sell or buy order. + allOf: + - $ref: "#/components/schemas/OrderKind" + owner: + description: The address of the order owner. + allOf: + - $ref: "#/components/schemas/Address" + receiver: + description: > + The address that will receive the buy tokens. Defaults to the owner + if omitted. + allOf: + - $ref: "#/components/schemas/Address" + sellTokenBalance: + description: Where the sell token should be drawn from. + allOf: + - $ref: "#/components/schemas/SellTokenSource" + buyTokenBalance: + description: Where the buy token should be transferred to. + allOf: + - $ref: "#/components/schemas/BuyTokenDestination" + appData: + description: > + Full app data JSON string. + type: string + blockNumber: + type: integer + nullable: true + signingScheme: + $ref: "#/components/schemas/SigningScheme" + signature: + $ref: "#/components/schemas/Signature" + feeAmount: + description: > + The fee amount in sell token atoms. Expected to be 0; only present + because it must be part of the signed order data. + allOf: + - $ref: "#/components/schemas/TokenAmount" + validTo: + description: Unix timestamp (`uint32`) until which the order is valid. + type: integer + partiallyFillable: + description: Whether the order can be partially filled or must be filled all at once. + type: boolean + required: + - sellToken + - buyToken + - sellAmount + - buyAmount + - kind + - owner + - signingScheme + - signature + - feeAmount + - validTo + - partiallyFillable + - appData + OrderSimulation: + description: > + The Tenderly simulation request for an order, along with any + simulation error. + type: object + properties: + tenderly_request: + $ref: "#/components/schemas/TenderlyRequest" + error: + description: Simulation error message, if the simulation failed. + type: string + nullable: true + required: + - tenderly_request diff --git a/crates/orderbook/src/api.rs b/crates/orderbook/src/api.rs index 649767c4fa..66a5a6d2ce 100644 --- a/crates/orderbook/src/api.rs +++ b/crates/orderbook/src/api.rs @@ -1,162 +1,352 @@ use { - crate::{app_data, database::Postgres, orderbook::Orderbook, quoter::QuoteHandler}, - anyhow::Result, - observe::distributed_tracing::tracing_warp::make_span, - serde::{Serialize, de::DeserializeOwned}, - shared::price_estimation::{PriceEstimationError, native::NativePriceEstimating}, + crate::{ + app_data, + database::Postgres, + orderbook::Orderbook, + quoter::QuoteHandler, + solver_competition::LoadSolverCompetitionError, + }, + axum::{ + Router, + extract::DefaultBodyLimit, + http::{Request, StatusCode, header::USER_AGENT}, + middleware::{self, Next}, + response::{IntoResponse, Json, Response}, + routing::{delete, get, post, put}, + }, + ethrpc::block_stream::CurrentBlockWatcher, + observe::tracing::distributed::axum::{make_span, record_trace_id}, + price_estimation::{PriceEstimationError, native::NativePriceEstimating}, + serde::{Deserialize, Serialize}, std::{ - convert::Infallible, + borrow::Cow, fmt::Debug, sync::Arc, time::{Duration, Instant}, }, - warp::{ - Filter, - Rejection, - Reply, - filters::BoxedFilter, - hyper::StatusCode, - reply::{Json, WithStatus, json, with_status}, - }, + tower::ServiceBuilder, + tower_http::{cors::CorsLayer, trace::TraceLayer}, }; mod cancel_order; mod cancel_orders; +mod debug_order; +mod debug_simulation; mod get_app_data; mod get_auction; mod get_native_price; mod get_order_by_uid; mod get_order_status; mod get_orders_by_tx; -mod get_solver_competition; +mod get_orders_by_uid; mod get_solver_competition_v2; mod get_token_metadata; mod get_total_surplus; mod get_trades; +mod get_trades_v2; mod get_user_orders; mod post_order; mod post_quote; mod put_app_data; +mod ready; mod version; +const ALLOWED_METHODS: &[axum::http::Method] = &[ + axum::http::Method::GET, + axum::http::Method::POST, + axum::http::Method::DELETE, + axum::http::Method::OPTIONS, + axum::http::Method::PUT, + axum::http::Method::PATCH, + axum::http::Method::HEAD, +]; + +/// Centralized application state shared across all API handlers +pub struct AppState { + pub database_write: Postgres, + pub database_read: Postgres, + pub orderbook: Arc, + pub quotes: QuoteHandler, + pub app_data: Arc, + pub native_price_estimator: Arc, + pub quote_timeout: Duration, + pub current_block_stream: CurrentBlockWatcher, + pub hide_competition_before_deadline: bool, +} + +impl AppState { + /// When the feature is enabled, returns the current block number so DB + /// queries can hide competition data whose deadline hasn't passed yet. + /// Returns `None` when the feature is off (no filtering). + pub(crate) fn hide_competition_before_block(&self) -> Option { + self.hide_competition_before_deadline + .then(|| self.current_block_stream.borrow().number.cast_signed()) + } +} + +async fn summarize_request(req: Request, next: Next) -> Response { + let method = req.method().to_string(); + let uri = req.uri().to_string(); + + let user_agent = req + .headers() + .get(USER_AGENT) + .map(|user_agent| user_agent.to_str().unwrap_or("invalid (non-ASCII)")) + .unwrap_or("unset") + .to_string(); + + let timer = Instant::now(); + let response = next.run(req).await; + let status = response.status().as_u16(); + + tracing::info!( + method, + uri, + user_agent, + status, + elapsed = ?timer.elapsed(), + "request_summary", + ); + + response +} + +/// Middleware that automatically tracks metrics using Axum's MatchedPath +async fn with_matched_path_metric(req: Request, next: Next) -> Response { + let metrics = ApiMetrics::instance(observe::metrics::get_storage_registry()).unwrap(); + + let http_method = req.method().as_str(); + let matched_path = req + .extensions() + .get::() + .map(|path| path.as_str()) + .unwrap_or("unknown"); + let method_with_path = format!("{http_method} {matched_path}"); + + let response = { + let _timer = metrics + .requests_duration_seconds + .with_label_values(&[&method_with_path]) + .start_timer(); + next.run(req).await + }; + let status = response.status(); + + // Track completed requests + metrics + .requests_complete + .with_label_values(&[method_with_path.as_str(), status.as_str()]) + .inc(); + + // Track rejected requests (4xx and 5xx status codes) + if status.is_client_error() || status.is_server_error() { + metrics + .requests_rejected + .with_label_values(&[status.as_str()]) + .inc(); + } + + response +} + +const MAX_JSON_BODY_PAYLOAD: u64 = 1024 * 16; + +#[expect(clippy::too_many_arguments)] pub fn handle_all_routes( database_write: Postgres, database_read: Postgres, orderbook: Arc, - quotes: Arc, + quotes: QuoteHandler, app_data: Arc, native_price_estimator: Arc, quote_timeout: Duration, -) -> impl Filter + Clone { - // Note that we add a string with endpoint's name to all responses. - // This string will be used later to report metrics. - // It is not used to form the actual server response. - - let routes = vec![ + current_block_stream: CurrentBlockWatcher, + hide_competition_before_deadline: bool, +) -> Router { + let app_data_size_limit = app_data.size_limit(); + + let state = Arc::new(AppState { + database_write, + database_read, + orderbook, + quotes, + app_data, + native_price_estimator, + quote_timeout, + current_block_stream, + hide_competition_before_deadline, + }); + + let routes = [ + // V1 routes + ( + "GET", + "/api/v1/account/{owner}/orders", + get(get_user_orders::get_user_orders_handler), + ), + ( + "PUT", + "/api/v1/app_data", + put(put_app_data::put_app_data_without_hash) + .layer(DefaultBodyLimit::max(app_data_size_limit)), + ), + ( + "GET", + "/api/v1/app_data/{hash}", + get(get_app_data::get_app_data_handler), + ), ( - "v1/create_order", - box_filter(post_order::post_order(orderbook.clone())), + "PUT", + "/api/v1/app_data/{hash}", + put(put_app_data::put_app_data_with_hash) + .layer(DefaultBodyLimit::max(app_data_size_limit)), ), ( - "v1/get_order", - box_filter(get_order_by_uid::get_order_by_uid(orderbook.clone())), + "GET", + "/api/v1/auction", + get(get_auction::get_auction_handler), ), ( - "v1/get_order_status", - box_filter(get_order_status::get_status(orderbook.clone())), + "POST", + "/api/v1/orders", + post(post_order::post_order_handler), ), ( - "v1/get_trades", - box_filter(get_trades::get_trades(database_read.clone())), + "POST", + "/api/v1/orders/by_uids", + post(get_orders_by_uid::get_orders_by_uid_handler), ), ( - "v1/cancel_order", - box_filter(cancel_order::cancel_order(orderbook.clone())), + "DELETE", + "/api/v1/orders", + delete(cancel_orders::cancel_orders_handler), ), ( - "v1/cancel_orders", - box_filter(cancel_orders::filter(orderbook.clone())), + "GET", + "/api/v1/orders/{uid}", + get(get_order_by_uid::get_order_by_uid_handler), ), ( - "v1/get_user_orders", - box_filter(get_user_orders::get_user_orders(orderbook.clone())), + "DELETE", + "/api/v1/orders/{uid}", + delete(cancel_order::cancel_order_handler), ), ( - "v1/get_orders_by_tx", - box_filter(get_orders_by_tx::get_orders_by_tx(orderbook.clone())), + "GET", + "/api/v1/orders/{uid}/status", + get(get_order_status::get_status_handler), ), - ("v1/post_quote", box_filter(post_quote::post_quote(quotes))), ( - "v1/auction", - box_filter(get_auction::get_auction(orderbook.clone())), + "POST", + "/api/v1/quote", + post(post_quote::post_quote_handler), ), ( - "v1/solver_competition", - box_filter(get_solver_competition::get(Arc::new( - database_write.clone(), - ))), + "GET", + "/api/v1/token/{token}/metadata", + get(get_token_metadata::get_token_metadata_handler), ), ( - "v2/solver_competition", - box_filter(get_solver_competition_v2::get(database_write.clone())), + "GET", + "/api/v1/token/{token}/native_price", + get(get_native_price::get_native_price_handler), ), + ("GET", "/api/v1/trades", get(get_trades::get_trades_handler)), ( - "v1/solver_competition/latest", - box_filter(get_solver_competition::get_latest(Arc::new( - database_write.clone(), - ))), + "GET", + "/api/v1/transactions/{hash}/orders", + get(get_orders_by_tx::get_orders_by_tx_handler), ), ( - "v2/solver_competition/latest", - box_filter(get_solver_competition_v2::get_latest( - database_write.clone(), - )), + "GET", + "/api/v1/users/{user}/total_surplus", + get(get_total_surplus::get_total_surplus_handler), ), - ("v1/version", box_filter(version::version())), + ("GET", "/api/v1/version", get(version::version_handler)), + ("GET", "/api/v1/ready", get(ready::get_ready_handler)), + // Routes under `/restricted/api/` are not exposed publicly. WAF and + // infra rules restrict access to authenticated partners. + // New internal-only endpoints MUST use this prefix. ( - "v1/get_native_price", - box_filter(get_native_price::get_native_price( - native_price_estimator, - quote_timeout, - )), + "GET", + "/restricted/api/v1/debug/order/{uid}", + get(debug_order::debug_order_handler), ), ( - "v1/get_app_data", - get_app_data::get(database_read.clone()).boxed(), + "GET", + "/restricted/api/v1/debug/simulation/{uid}", + get(debug_simulation::debug_simulation_handler), ), ( - "v1/put_app_data", - box_filter(put_app_data::filter(app_data)), + "POST", + "/restricted/api/v1/debug/simulation", + post(debug_simulation::debug_simulation_post_handler), ), + // V2 routes + // /solver_competition routes (specific before parameterized) ( - "v1/get_total_surplus", - box_filter(get_total_surplus::get(database_read.clone())), + "GET", + "/api/v2/solver_competition/latest", + get(get_solver_competition_v2::get_solver_competition_latest_handler), ), ( - "v1/get_token_metadata", - box_filter(get_token_metadata::get_token_metadata(database_read)), + "GET", + "/api/v2/solver_competition/by_tx_hash/{tx_hash}", + get(get_solver_competition_v2::get_solver_competition_by_hash_handler), + ), + ( + "GET", + "/api/v2/solver_competition/{auction_id}", + get(get_solver_competition_v2::get_solver_competition_by_id_handler), + ), + ( + "GET", + "/api/v2/trades", + get(get_trades_v2::get_trades_handler), + ), + ( + "GET", + "/restricted/api/v2/solver_competition/{auction_id}", + get(get_solver_competition_v2::get_solver_competition_by_id_unfiltered_handler), ), ]; - finalize_router(routes, "orderbook::api::request_summary") -} - -pub type ApiReply = WithStatus; - -// We turn Rejection into Reply to workaround warp not setting CORS headers on -// rejections. -async fn handle_rejection(err: Rejection) -> Result { - let response = err.default_response(); - + // Initialize metrics let metrics = ApiMetrics::instance(observe::metrics::get_storage_registry()).unwrap(); - metrics - .requests_rejected - .with_label_values(&[response.status().as_str()]) - .inc(); + metrics.reset_requests_rejected(); - Ok(response) + let mut api_router = Router::new(); + for (method, path, method_router) in routes { + metrics.reset_requests_complete(method, path); + api_router = api_router.route(path, method_router); + } + let api_router = api_router.with_state(state); + + let cors = CorsLayer::new() + .allow_origin(tower_http::cors::Any) + .allow_methods(ALLOWED_METHODS.to_vec()) + .allow_headers(vec![ + axum::http::header::ORIGIN, + axum::http::header::CONTENT_TYPE, + // Must be lower case due to the HTTP-2 spec + axum::http::HeaderName::from_static("x-auth-token"), + axum::http::HeaderName::from_static("x-appid"), + ]); + + api_router + .layer(DefaultBodyLimit::max(MAX_JSON_BODY_PAYLOAD as usize)) + .layer(cors) + .layer(middleware::from_fn(summarize_request)) + .layer(middleware::from_fn(with_matched_path_metric)) + .layer( + ServiceBuilder::new() + .layer(TraceLayer::new_for_http().make_span_with(make_span)) + .map_request(record_trace_id), + ) } +// NOTE(jmg-duarte): method is actually the request path, to avoid breaking +// dashboards, the http_method was added #[derive(prometheus_metric_storage::MetricStorage, Clone, Debug)] #[metric(subsystem = "api")] struct ApiMetrics { @@ -195,43 +385,39 @@ impl ApiMetrics { } } - fn reset_requests_complete(&self, method: &str) { + fn reset_requests_complete(&self, method: &str, path: &str) { + let method_with_path = format!("{method} {path}"); for status in Self::INITIAL_STATUSES { self.requests_complete - .with_label_values(&[method, status.as_str()]) + .with_label_values(&[method_with_path.as_str(), status.as_str()]) .reset(); } } - - fn on_request_completed(&self, method: &str, status: StatusCode, timer: Instant) { - self.requests_complete - .with_label_values(&[method, status.as_str()]) - .inc(); - self.requests_duration_seconds - .with_label_values(&[method]) - .observe(timer.elapsed().as_secs_f64()); - } } -#[derive(Serialize)] +#[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -struct Error<'a> { - error_type: &'a str, - description: &'a str, +pub struct Error { + pub error_type: Cow<'static, str>, + pub description: Cow<'static, str>, /// Additional arbitrary data that can be attached to an API error. #[serde(skip_serializing_if = "Option::is_none")] - data: Option, + pub data: Option, } -pub fn error(error_type: &str, description: impl AsRef) -> Json { - json(&Error { - error_type, - description: description.as_ref(), +pub fn error(error_type: &'static str, description: impl AsRef) -> Json { + Json(Error { + error_type: error_type.into(), + description: Cow::Owned(description.as_ref().to_owned()), data: None, }) } -pub fn rich_error(error_type: &str, description: impl AsRef, data: impl Serialize) -> Json { +pub fn rich_error( + error_type: &'static str, + description: impl AsRef, + data: impl Serialize, +) -> Json { let data = match serde_json::to_value(&data) { Ok(value) => Some(value), Err(err) => { @@ -240,144 +426,70 @@ pub fn rich_error(error_type: &str, description: impl AsRef, data: impl Ser } }; - json(&Error { - error_type, - description: description.as_ref(), + Json(Error { + error_type: error_type.into(), + description: Cow::Owned(description.as_ref().to_owned()), data, }) } -pub fn internal_error_reply() -> ApiReply { - with_status( - error("InternalServerError", ""), +pub fn internal_error_reply() -> Response { + ( StatusCode::INTERNAL_SERVER_ERROR, + error("InternalServerError", ""), ) + .into_response() } -pub fn convert_json_response(result: Result) -> WithStatus -where - T: Serialize, - E: IntoWarpReply + Debug, -{ - match result { - Ok(response) => with_status(warp::reply::json(&response), StatusCode::OK), - Err(err) => err.into_warp_reply(), - } -} +// Newtype wrapper for PriceEstimationError to allow IntoResponse implementation +// (orphan rules prevent implementing IntoResponse directly on external types) +pub(crate) struct PriceEstimationErrorWrapper(pub(crate) PriceEstimationError); -pub trait IntoWarpReply { - fn into_warp_reply(self) -> ApiReply; -} - -pub async fn response_body(response: warp::hyper::Response) -> Vec { - let mut body = response.into_body(); - let mut result = Vec::new(); - while let Some(bytes) = futures::StreamExt::next(&mut body).await { - result.extend_from_slice(bytes.unwrap().as_ref()); - } - result -} - -const MAX_JSON_BODY_PAYLOAD: u64 = 1024 * 16; - -pub fn extract_payload() --> impl Filter + Clone { - // (rejecting huge payloads)... - extract_payload_with_max_size(MAX_JSON_BODY_PAYLOAD) -} - -pub fn extract_payload_with_max_size( - max_size: u64, -) -> impl Filter + Clone { - warp::body::content_length_limit(max_size).and(warp::body::json()) -} - -pub type BoxedRoute = BoxedFilter<(Box,)>; - -pub fn box_filter(filter: Filter_) -> BoxedFilter<(Box,)> -where - Filter_: Filter + Send + Sync + 'static, - Reply_: Reply + Send + 'static, -{ - filter.map(|a| Box::new(a) as Box).boxed() -} - -/// Sets up basic metrics, cors and proper log tracing for all routes. -/// -/// # Panics -/// -/// This method panics if `routes` is empty. -pub fn finalize_router( - routes: Vec<(&'static str, BoxedRoute)>, - log_prefix: &'static str, -) -> impl Filter + Clone { - let metrics = ApiMetrics::instance(observe::metrics::get_storage_registry()).unwrap(); - metrics.reset_requests_rejected(); - for (method, _) in &routes { - metrics.reset_requests_complete(method); - } - - let router = routes - .into_iter() - .fold( - Option::)>>::None, - |router, (method, route)| { - let route = route.map(move |result| (method, result)).untuple_one(); - let next = match router { - Some(router) => router.or(route).unify().boxed(), - None => route.boxed(), - }; - Some(next) - }, - ) - .expect("routes cannot be empty"); - - let instrumented = - warp::any() - .map(Instant::now) - .and(router) - .map(|timer, method, reply: Box| { - let response = reply.into_response(); - metrics.on_request_completed(method, response.status(), timer); - response - }); - - // Final setup - let cors = warp::cors() - .allow_any_origin() - .allow_methods(vec!["GET", "POST", "DELETE", "OPTIONS", "PUT", "PATCH"]) - .allow_headers(vec!["Origin", "Content-Type", "X-Auth-Token", "X-AppId"]); - - warp::path!("api" / ..) - .and(instrumented) - .recover(handle_rejection) - .with(cors) - .with(warp::log::log(log_prefix)) - .with(warp::trace::trace(make_span)) -} - -impl IntoWarpReply for PriceEstimationError { - fn into_warp_reply(self) -> WithStatus { - match self { - Self::UnsupportedToken { token, reason } => with_status( +impl IntoResponse for PriceEstimationErrorWrapper { + fn into_response(self) -> Response { + match self.0 { + PriceEstimationError::UnsupportedToken { token, reason } => ( + StatusCode::BAD_REQUEST, error( "UnsupportedToken", format!("Token {token:?} is unsupported: {reason:}"), ), + ) + .into_response(), + PriceEstimationError::UnsupportedOrderType(order_type) => ( StatusCode::BAD_REQUEST, - ), - Self::UnsupportedOrderType(order_type) => with_status( error( "UnsupportedOrderType", format!("{order_type} not supported"), ), - StatusCode::BAD_REQUEST, - ), - Self::NoLiquidity | Self::RateLimited | Self::EstimatorInternal(_) => with_status( - error("NoLiquidity", "no route found"), + ) + .into_response(), + PriceEstimationError::NoLiquidity + | PriceEstimationError::RateLimited + | PriceEstimationError::EstimatorInternal(_) => ( StatusCode::NOT_FOUND, - ), - Self::ProtocolInternal(err) => { + error("NoLiquidity", "no route found"), + ) + .into_response(), + PriceEstimationError::TradingOutsideAllowedWindow { message } => ( + StatusCode::BAD_REQUEST, + error("TradingOutsideAllowedWindow", message), + ) + .into_response(), + PriceEstimationError::TokenTemporarilySuspended { message } => ( + StatusCode::BAD_REQUEST, + error("TokenTemporarilySuspended", message), + ) + .into_response(), + PriceEstimationError::InsufficientLiquidity { message } => ( + StatusCode::BAD_REQUEST, + error("InsufficientLiquidity", message), + ) + .into_response(), + PriceEstimationError::CustomSolverError { message } => { + (StatusCode::BAD_REQUEST, error("CustomSolverError", message)).into_response() + } + PriceEstimationError::ProtocolInternal(err) => { tracing::error!(?err, "PriceEstimationError::Other"); internal_error_reply() } @@ -385,16 +497,56 @@ impl IntoWarpReply for PriceEstimationError { } } +impl IntoResponse for LoadSolverCompetitionError { + fn into_response(self) -> Response { + match self { + err @ LoadSolverCompetitionError::NotFound => { + (StatusCode::NOT_FOUND, error("NotFound", err.to_string())).into_response() + } + LoadSolverCompetitionError::Other(err) => { + tracing::error!(?err, "failed to load solver competition"); + internal_error_reply() + } + } + } +} + +#[cfg(test)] +pub async fn response_body(response: axum::http::Response) -> Vec { + // SAFETY: usize::MAX is ok here because it's a test + axum::body::to_bytes(response.into_body(), usize::MAX) + .await + .unwrap() + .to_vec() +} + #[cfg(test)] mod tests { - use {super::*, serde::ser, serde_json::json}; + use { + crate::api::{Error, PriceEstimationErrorWrapper, rich_error}, + alloy::primitives::{Address, B256}, + app_data::AppDataHash, + axum::{ + Router, + body::Body, + extract::{Path, Query}, + http::{Request, StatusCode}, + response::IntoResponse, + routing::get, + }, + model::order::OrderUid, + price_estimation::PriceEstimationError, + serde::{Deserialize, Serialize, ser}, + serde_json::json, + tower::ServiceExt as _, + }; #[test] fn rich_errors_skip_unset_data_field() { assert_eq!( serde_json::to_value(&Error { - error_type: "foo", - description: "bar", + error_type: "foo".into(), + description: "bar".into(), data: None, }) .unwrap(), @@ -405,8 +557,8 @@ mod tests { ); assert_eq!( serde_json::to_value(Error { - error_type: "foo", - description: "bar", + error_type: "foo".into(), + description: "bar".into(), data: Some(json!(42)), }) .unwrap(), @@ -430,20 +582,431 @@ mod tests { } } - let body = warp::hyper::body::to_bytes( - rich_error("foo", "bar", AlwaysErrors) - .into_response() - .into_body(), - ) - .await - .unwrap(); + let response = rich_error("foo", "bar", AlwaysErrors).into_response(); + // SAFETY: usize::MAX is ok here because it's a test + let bytes = axum::body::to_bytes(response.into_body(), usize::MAX) + .await + .unwrap(); assert_eq!( - serde_json::from_slice::(&body).unwrap(), + serde_json::from_slice::(&bytes).unwrap(), json!({ "errorType": "foo", "description": "bar", }) ); } + + #[tokio::test] + async fn maps_custom_price_estimation_errors_to_bad_request_responses() { + let cases = [ + ( + PriceEstimationError::TradingOutsideAllowedWindow { + message: "window closed".to_string(), + }, + "TradingOutsideAllowedWindow", + "window closed", + ), + ( + PriceEstimationError::TokenTemporarilySuspended { + message: "token suspended".to_string(), + }, + "TokenTemporarilySuspended", + "token suspended", + ), + ( + PriceEstimationError::InsufficientLiquidity { + message: "insufficient liquidity".to_string(), + }, + "InsufficientLiquidity", + "insufficient liquidity", + ), + ( + PriceEstimationError::CustomSolverError { + message: "custom solver reason".to_string(), + }, + "CustomSolverError", + "custom solver reason", + ), + ]; + + for (err, expected_type, expected_description) in cases { + let response = PriceEstimationErrorWrapper(err).into_response(); + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + let bytes = axum::body::to_bytes(response.into_body(), usize::MAX) + .await + .unwrap(); + let body: Error = serde_json::from_slice(&bytes).unwrap(); + + assert_eq!(body.error_type, expected_type); + assert_eq!(body.description.as_ref(), expected_description); + } + } + + // Tests for Axum extractor type parsing. + // + // Since the parsing behavior depends on the type, not the endpoint, + // we test each type once here rather than duplicating across handlers. + + async fn get_request(router: Router, path: &str) -> axum::response::Response { + router + .oneshot(Request::get(path).body(Body::empty()).unwrap()) + .await + .unwrap() + } + + mod path_order_uid { + use super::*; + + async fn handler(Path(_uid): Path) -> StatusCode { + StatusCode::OK + } + + fn router() -> Router { + Router::new().route("/orders/{uid}", get(handler)) + } + + async fn request(uid: &str) -> axum::response::Response { + get_request(router(), &format!("/orders/{uid}")).await + } + + #[tokio::test] + async fn with_0x_prefix() { + let uid = format!("0x{}", "01".repeat(56)); + assert_eq!(request(&uid).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn without_0x_prefix() { + let uid = "01".repeat(56); + assert_eq!(request(&uid).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn odd_hex_chars_with_0x() { + let uid = format!("0x{}", "01".repeat(56).strip_suffix('1').unwrap()); + assert_eq!(request(&uid).await.status(), StatusCode::BAD_REQUEST); + } + + #[tokio::test] + async fn odd_hex_chars_without_0x() { + let uid = "01".repeat(56); + let uid = uid.strip_suffix('1').unwrap(); + assert_eq!(request(uid).await.status(), StatusCode::BAD_REQUEST); + } + } + + mod path_address { + use super::*; + + async fn handler(Path(_addr): Path
) -> StatusCode { + StatusCode::OK + } + + fn router() -> Router { + Router::new().route("/token/{addr}", get(handler)) + } + + async fn request(addr: &str) -> axum::response::Response { + get_request(router(), &format!("/token/{addr}")).await + } + + #[tokio::test] + async fn with_0x_prefix() { + let addr = format!("0x{}", "01".repeat(20)); + assert_eq!(request(&addr).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn without_0x_prefix() { + let addr = "01".repeat(20); + assert_eq!(request(&addr).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn odd_hex_chars_with_0x() { + let addr = format!("0x{}", "01".repeat(20).strip_suffix('1').unwrap()); + assert_eq!(request(&addr).await.status(), StatusCode::BAD_REQUEST); + } + + #[tokio::test] + async fn odd_hex_chars_without_0x() { + let addr = "01".repeat(20); + let addr = addr.strip_suffix('1').unwrap(); + assert_eq!(request(addr).await.status(), StatusCode::BAD_REQUEST); + } + + #[tokio::test] + async fn too_short() { + assert_eq!(request("0x0101").await.status(), StatusCode::BAD_REQUEST); + } + + #[tokio::test] + async fn invalid_hex_chars() { + let addr = format!("0x{}", "GG".repeat(20)); + assert_eq!(request(&addr).await.status(), StatusCode::BAD_REQUEST); + } + } + + mod path_b256 { + use super::*; + + async fn handler(Path(_hash): Path) -> StatusCode { + StatusCode::OK + } + + fn router() -> Router { + Router::new().route("/tx/{hash}", get(handler)) + } + + async fn request(hash: &str) -> axum::response::Response { + get_request(router(), &format!("/tx/{hash}")).await + } + + #[tokio::test] + async fn with_0x_prefix() { + let hash = format!("0x{}", "01".repeat(32)); + assert_eq!(request(&hash).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn without_0x_prefix() { + let hash = "01".repeat(32); + assert_eq!(request(&hash).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn odd_hex_chars_with_0x() { + let hash = format!("0x{}", "01".repeat(32).strip_suffix('1').unwrap()); + assert_eq!(request(&hash).await.status(), StatusCode::BAD_REQUEST); + } + + #[tokio::test] + async fn odd_hex_chars_without_0x() { + let hash = "01".repeat(32); + let hash = hash.strip_suffix('1').unwrap(); + assert_eq!(request(hash).await.status(), StatusCode::BAD_REQUEST); + } + } + + mod path_app_data_hash { + use super::*; + + async fn handler(Path(_hash): Path) -> StatusCode { + StatusCode::OK + } + + fn router() -> Router { + Router::new().route("/app_data/{hash}", get(handler)) + } + + async fn request(hash: &str) -> axum::response::Response { + get_request(router(), &format!("/app_data/{hash}")).await + } + + #[tokio::test] + async fn with_0x_prefix() { + let hash = format!("0x{}", "01".repeat(32)); + assert_eq!(request(&hash).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn without_0x_prefix() { + let hash = "01".repeat(32); + assert_eq!(request(&hash).await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn odd_hex_chars_with_0x() { + let hash = format!("0x{}", "01".repeat(32).strip_suffix('1').unwrap()); + assert_eq!(request(&hash).await.status(), StatusCode::BAD_REQUEST); + } + + #[tokio::test] + async fn odd_hex_chars_without_0x() { + let hash = "01".repeat(32); + let hash = hash.strip_suffix('1').unwrap(); + assert_eq!(request(hash).await.status(), StatusCode::BAD_REQUEST); + } + } + + mod path_u64 { + use super::*; + + async fn handler(Path(_id): Path) -> StatusCode { + StatusCode::OK + } + + fn router() -> Router { + Router::new().route("/resource/{id}", get(handler)) + } + + async fn request(path: &str) -> axum::response::Response { + get_request(router(), path).await + } + + #[tokio::test] + async fn valid() { + assert_eq!(request("/resource/123").await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn invalid_string() { + assert_eq!( + request("/resource/abc").await.status(), + StatusCode::BAD_REQUEST + ); + } + + #[tokio::test] + async fn negative() { + assert_eq!( + request("/resource/-1").await.status(), + StatusCode::BAD_REQUEST + ); + } + } + + mod query_hex_types { + use super::*; + + #[derive(Deserialize)] + #[serde(rename_all = "camelCase")] + struct Params { + #[allow(unused)] + order_uid: Option, + #[allow(unused)] + owner: Option
, + } + + async fn handler(Query(_q): Query) -> StatusCode { + StatusCode::OK + } + + fn router() -> Router { + Router::new().route("/trades", get(handler)) + } + + async fn request(query: &str) -> axum::response::Response { + get_request(router(), &format!("/trades?{query}")).await + } + + #[tokio::test] + async fn order_uid_with_0x_prefix() { + let uid = format!("0x{}", "01".repeat(56)); + assert_eq!( + request(&format!("orderUid={uid}")).await.status(), + StatusCode::OK + ); + } + + #[tokio::test] + async fn order_uid_without_0x_prefix() { + let uid = "01".repeat(56); + assert_eq!( + request(&format!("orderUid={uid}")).await.status(), + StatusCode::OK + ); + } + + #[tokio::test] + async fn order_uid_odd_hex_chars() { + let uid = format!("0x{}", "01".repeat(56).strip_suffix('1').unwrap()); + assert_eq!( + request(&format!("orderUid={uid}")).await.status(), + StatusCode::BAD_REQUEST + ); + } + + #[tokio::test] + async fn owner_with_0x_prefix() { + let owner = format!("0x{}", "01".repeat(20)); + assert_eq!( + request(&format!("owner={owner}")).await.status(), + StatusCode::OK + ); + } + + #[tokio::test] + async fn owner_without_0x_prefix() { + let owner = "01".repeat(20); + assert_eq!( + request(&format!("owner={owner}")).await.status(), + StatusCode::OK + ); + } + + #[tokio::test] + async fn owner_odd_hex_chars() { + let owner = format!("0x{}", "01".repeat(20).strip_suffix('1').unwrap()); + assert_eq!( + request(&format!("owner={owner}")).await.status(), + StatusCode::BAD_REQUEST + ); + } + } + + mod query_numeric_types { + use super::*; + + #[derive(Deserialize)] + struct Params { + #[allow(unused)] + offset: Option, + #[allow(unused)] + limit: Option, + } + + async fn handler(Query(_q): Query) -> StatusCode { + StatusCode::OK + } + + fn router() -> Router { + Router::new().route("/items", get(handler)) + } + + async fn request(path: &str) -> axum::response::Response { + get_request(router(), path).await + } + + #[tokio::test] + async fn no_params() { + assert_eq!(request("/items").await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn only_offset() { + assert_eq!(request("/items?offset=5").await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn only_limit() { + assert_eq!(request("/items?limit=20").await.status(), StatusCode::OK); + } + + #[tokio::test] + async fn both_params() { + assert_eq!( + request("/items?offset=5&limit=20").await.status(), + StatusCode::OK + ); + } + + #[tokio::test] + async fn invalid_offset() { + assert_eq!( + request("/items?offset=abc").await.status(), + StatusCode::BAD_REQUEST + ); + } + + #[tokio::test] + async fn invalid_limit() { + assert_eq!( + request("/items?limit=abc").await.status(), + StatusCode::BAD_REQUEST + ); + } + } } diff --git a/crates/orderbook/src/api/cancel_order.rs b/crates/orderbook/src/api/cancel_order.rs index 25a6484952..db82862d11 100644 --- a/crates/orderbook/src/api/cancel_order.rs +++ b/crates/orderbook/src/api/cancel_order.rs @@ -1,60 +1,74 @@ use { - crate::{ - api::{IntoWarpReply, convert_json_response, extract_payload}, - orderbook::{OrderCancellationError, Orderbook}, + crate::{api::AppState, orderbook::OrderCancellationError}, + axum::{ + Json, + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Response}, }, - anyhow::Result, model::order::{CancellationPayload, OrderCancellation, OrderUid}, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection, hyper::StatusCode, reply::with_status}, + std::sync::Arc, }; -pub fn cancel_order_request() --> impl Filter + Clone { - warp::path!("v1" / "orders" / OrderUid) - .and(warp::delete()) - .and(extract_payload()) - .map(|uid, payload: CancellationPayload| OrderCancellation { - order_uid: uid, - signature: payload.signature, - signing_scheme: payload.signing_scheme, - }) +pub async fn cancel_order_handler( + State(state): State>, + Path(uid): Path, + Json(payload): Json, +) -> Response { + let order_cancellation = OrderCancellation { + order_uid: uid, + signature: payload.signature, + signing_scheme: payload.signing_scheme, + }; + state + .orderbook + .cancel_order(order_cancellation) + .await + .map(|_| Json("Cancelled")) + .into_response() } -impl IntoWarpReply for OrderCancellationError { - fn into_warp_reply(self) -> super::ApiReply { +impl IntoResponse for OrderCancellationError { + fn into_response(self) -> Response { match self { - Self::InvalidSignature => with_status( + Self::InvalidSignature => ( + StatusCode::BAD_REQUEST, super::error("InvalidSignature", "Malformed signature"), + ) + .into_response(), + Self::AlreadyCancelled => ( StatusCode::BAD_REQUEST, - ), - Self::AlreadyCancelled => with_status( super::error("AlreadyCancelled", "Order is already cancelled"), + ) + .into_response(), + Self::OrderFullyExecuted => ( StatusCode::BAD_REQUEST, - ), - Self::OrderFullyExecuted => with_status( super::error("OrderFullyExecuted", "Order is fully executed"), + ) + .into_response(), + Self::OrderExpired => ( StatusCode::BAD_REQUEST, - ), - Self::OrderExpired => with_status( super::error("OrderExpired", "Order is expired"), - StatusCode::BAD_REQUEST, - ), - Self::OrderNotFound => with_status( - super::error("OrderNotFound", "Order not located in database"), + ) + .into_response(), + Self::OrderNotFound => ( StatusCode::NOT_FOUND, - ), - Self::WrongOwner => with_status( + super::error("OrderNotFound", "Order not located in database"), + ) + .into_response(), + Self::WrongOwner => ( + StatusCode::UNAUTHORIZED, super::error( "WrongOwner", "Signature recovery's owner doesn't match order's", ), - StatusCode::UNAUTHORIZED, - ), - Self::OnChainOrder => with_status( - super::error("OnChainOrder", "On-chain orders must be cancelled on-chain"), + ) + .into_response(), + Self::OnChainOrder => ( StatusCode::BAD_REQUEST, - ), + super::error("OnChainOrder", "On-chain orders must be cancelled on-chain"), + ) + .into_response(), Self::Other(err) => { tracing::error!(?err, "cancel_order"); crate::api::internal_error_reply() @@ -63,33 +77,17 @@ impl IntoWarpReply for OrderCancellationError { } } -pub fn cancel_order_response(result: Result<(), OrderCancellationError>) -> super::ApiReply { - convert_json_response(result.map(|_| "Cancelled")) -} - -pub fn cancel_order( - orderbook: Arc, -) -> impl Filter + Clone { - cancel_order_request().and_then(move |order| { - let orderbook = orderbook.clone(); - async move { - let result = orderbook.cancel_order(order).await; - Result::<_, Infallible>::Ok(cancel_order_response(result)) - } - }) -} - #[cfg(test)] mod tests { use { super::*, - ethcontract::H256, - hex_literal::hex, + alloy::primitives::b256, model::signature::{EcdsaSignature, EcdsaSigningScheme}, serde_json::json, - warp::{Reply, test::request}, }; + type Result = std::result::Result, OrderCancellationError>; + #[test] fn cancellation_payload_deserialization() { assert_eq!( @@ -103,12 +101,8 @@ mod tests { .unwrap(), CancellationPayload { signature: EcdsaSignature { - r: H256(hex!( - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" - )), - s: H256(hex!( - "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" - )), + r: b256!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + s: b256!("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), v: 27, }, signing_scheme: EcdsaSigningScheme::Eip712, @@ -116,57 +110,34 @@ mod tests { ); } - #[tokio::test] - async fn cancel_order_request_ok() { - let filter = cancel_order_request(); - let cancellation = OrderCancellation::default(); - - let request = request() - .path(&format!("/v1/orders/{}", cancellation.order_uid)) - .method("DELETE") - .header("content-type", "application/json") - .json(&CancellationPayload { - signature: cancellation.signature, - signing_scheme: cancellation.signing_scheme, - }); - let result = request.filter(&filter).await.unwrap(); - assert_eq!(result, cancellation); - } - #[test] fn cancel_order_response_ok() { - let response = cancel_order_response(Ok(())).into_response(); + let response = (Result::Ok(Json("Cancelled"))).into_response(); assert_eq!(response.status(), StatusCode::OK); } #[test] fn cancel_order_response_err() { - let response = - cancel_order_response(Err(OrderCancellationError::InvalidSignature)).into_response(); + let response = Result::Err(OrderCancellationError::InvalidSignature).into_response(); assert_eq!(response.status(), StatusCode::BAD_REQUEST); - let response = - cancel_order_response(Err(OrderCancellationError::OrderFullyExecuted)).into_response(); + let response = Result::Err(OrderCancellationError::OrderFullyExecuted).into_response(); assert_eq!(response.status(), StatusCode::BAD_REQUEST); - let response = - cancel_order_response(Err(OrderCancellationError::AlreadyCancelled)).into_response(); + let response = Result::Err(OrderCancellationError::AlreadyCancelled).into_response(); assert_eq!(response.status(), StatusCode::BAD_REQUEST); - let response = - cancel_order_response(Err(OrderCancellationError::OrderExpired)).into_response(); + let response = Result::Err(OrderCancellationError::OrderExpired).into_response(); assert_eq!(response.status(), StatusCode::BAD_REQUEST); - let response = - cancel_order_response(Err(OrderCancellationError::WrongOwner)).into_response(); + let response = Result::Err(OrderCancellationError::WrongOwner).into_response(); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); - let response = - cancel_order_response(Err(OrderCancellationError::OrderNotFound)).into_response(); + let response = Result::Err(OrderCancellationError::OrderNotFound).into_response(); assert_eq!(response.status(), StatusCode::NOT_FOUND); - let response = cancel_order_response(Err(OrderCancellationError::Other( - anyhow::Error::msg("test error"), + let response = Result::Err(OrderCancellationError::Other(anyhow::Error::msg( + "test error", ))) .into_response(); assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR); diff --git a/crates/orderbook/src/api/cancel_orders.rs b/crates/orderbook/src/api/cancel_orders.rs index b252fd8dae..a44ae215de 100644 --- a/crates/orderbook/src/api/cancel_orders.rs +++ b/crates/orderbook/src/api/cancel_orders.rs @@ -1,32 +1,41 @@ use { - crate::{ - api::{convert_json_response, extract_payload}, - orderbook::{OrderCancellationError, Orderbook}, + crate::{api::AppState, orderbook::OrderCancellationError}, + anyhow::anyhow, + axum::{ + Json, + body, + extract::State, + http::StatusCode, + response::{IntoResponse, Response}, }, - anyhow::Result, - model::order::SignedOrderCancellations, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection}, + model::order::{ORDER_UID_LIMIT, SignedOrderCancellations}, + std::sync::Arc, }; -pub fn request() -> impl Filter + Clone { - warp::path!("v1" / "orders") - .and(warp::delete()) - .and(extract_payload()) -} +pub async fn cancel_orders_handler( + State(state): State>, + body: body::Bytes, +) -> Response { + // TODO: remove after all downstream callers have been notified of the status + // code changes + let Ok(cancellations) = serde_json::from_slice::(&body) else { + return StatusCode::BAD_REQUEST.into_response(); + }; -pub fn response(result: Result<(), OrderCancellationError>) -> super::ApiReply { - convert_json_response(result.map(|_| "Cancelled")) -} + // Explicitly limit the number of orders cancelled in a batch as the request + // size limit *does not* provide a proper bound for this + if cancellations.data.order_uids.len() > ORDER_UID_LIMIT { + return Err::<&'static str, _>(OrderCancellationError::Other(anyhow!( + "too many orders ({} > 1024)", + cancellations.data.order_uids.len() + ))) + .into_response(); + } -pub fn filter( - orderbook: Arc, -) -> impl Filter + Clone { - request().and_then(move |cancellations| { - let orderbook = orderbook.clone(); - async move { - let result = orderbook.cancel_orders(cancellations).await; - Result::<_, Infallible>::Ok(response(result)) - } - }) + state + .orderbook + .cancel_orders(cancellations) + .await + .map(|_| Json("Cancelled")) + .into_response() } diff --git a/crates/orderbook/src/api/debug_order.rs b/crates/orderbook/src/api/debug_order.rs new file mode 100644 index 0000000000..bcae471f99 --- /dev/null +++ b/crates/orderbook/src/api/debug_order.rs @@ -0,0 +1,28 @@ +use { + crate::api::AppState, + axum::{ + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, + model::order::OrderUid, + std::sync::Arc, +}; + +pub async fn debug_order_handler( + State(state): State>, + Path(uid): Path, +) -> Response { + match state.database_read.fetch_debug_report(&uid).await { + Ok(Some(report)) => (StatusCode::OK, Json(report)).into_response(), + Ok(None) => ( + StatusCode::NOT_FOUND, + super::error("NotFound", "order not found"), + ) + .into_response(), + Err(err) => { + tracing::error!(?err, "failed to fetch debug report"); + crate::api::internal_error_reply() + } + } +} diff --git a/crates/orderbook/src/api/debug_simulation.rs b/crates/orderbook/src/api/debug_simulation.rs new file mode 100644 index 0000000000..7937a58751 --- /dev/null +++ b/crates/orderbook/src/api/debug_simulation.rs @@ -0,0 +1,74 @@ +use { + crate::{api::AppState, dto::OrderSimulationRequest, orderbook::OrderSimulationError}, + axum::{ + Json, + extract::{Path, Query, State}, + http::StatusCode, + response::{IntoResponse, Response}, + }, + model::order::OrderUid, + serde::Deserialize, + std::sync::Arc, +}; + +#[derive(Deserialize)] +pub struct SimulationQuery { + pub block_number: Option, +} + +pub async fn debug_simulation_handler( + State(state): State>, + Path(uid): Path, + Query(params): Query, +) -> Response { + match state + .orderbook + .simulate_order(&uid, params.block_number) + .await + { + Ok(Some(result)) => (StatusCode::OK, Json(result)).into_response(), + Ok(None) => ( + StatusCode::NOT_FOUND, + super::error("NotFound", "order not found"), + ) + .into_response(), + Err(err) => err.into_response(), + } +} + +pub async fn debug_simulation_post_handler( + State(state): State>, + Json(request): Json, +) -> Response { + match state.orderbook.simulate_custom_order(request).await { + Ok(result) => (StatusCode::OK, Json(result)).into_response(), + Err(err) => err.into_response(), + } +} + +impl IntoResponse for OrderSimulationError { + fn into_response(self) -> Response { + match self { + OrderSimulationError::NotEnabled => ( + StatusCode::METHOD_NOT_ALLOWED, + super::error( + "MethodNotAllowed", + "order simulation endpoint is not enabled", + ), + ) + .into_response(), + OrderSimulationError::MalformedInput(err) => { + tracing::warn!(?err, "failed to parse order simulation input"); + ( + StatusCode::BAD_REQUEST, + super::error("BadRequest", format!("malformed input: {err}")), + ) + .into_response() + } + OrderSimulationError::Other(err) => { + tracing::error!(?err, "failed to create simulation for order"); + crate::api::internal_error_reply() + } + } + } +} diff --git a/crates/orderbook/src/api/get_app_data.rs b/crates/orderbook/src/api/get_app_data.rs index 21c3a099e2..6b4f9f3a96 100644 --- a/crates/orderbook/src/api/get_app_data.rs +++ b/crates/orderbook/src/api/get_app_data.rs @@ -1,42 +1,34 @@ use { - crate::database::Postgres, - anyhow::Result, + crate::api::AppState, app_data::{AppDataDocument, AppDataHash}, - reqwest::StatusCode, - std::convert::Infallible, - warp::{Filter, Rejection, Reply, reply}, + axum::{ + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, + std::sync::Arc, }; -pub fn request() -> impl Filter + Clone { - warp::path!("v1" / "app_data" / AppDataHash).and(warp::get()) -} - -pub fn get( - database: Postgres, -) -> impl Filter,), Error = Rejection> + Clone { - request().and_then(move |contract_app_data: AppDataHash| { - let database = database.clone(); - async move { - let result = database.get_full_app_data(&contract_app_data).await; - Result::<_, Infallible>::Ok(match result { - Ok(Some(response)) => { - let response = reply::with_status( - reply::json(&AppDataDocument { - full_app_data: response, - }), - StatusCode::OK, - ); - Box::new(response) as Box - } - Ok(None) => Box::new(reply::with_status( - "full app data not found", - StatusCode::NOT_FOUND, - )), - Err(err) => { - tracing::error!(?err, "get_app_data_by_hash"); - Box::new(crate::api::internal_error_reply()) - } - }) +pub async fn get_app_data_handler( + State(state): State>, + Path(contract_app_data): Path, +) -> Response { + let result = state + .database_read + .get_full_app_data(&contract_app_data) + .await; + match result { + Ok(Some(response)) => ( + StatusCode::OK, + Json(AppDataDocument { + full_app_data: response, + }), + ) + .into_response(), + Ok(None) => (StatusCode::NOT_FOUND, "full app data not found").into_response(), + Err(err) => { + tracing::error!(?err, "get_app_data_by_hash"); + crate::api::internal_error_reply() } - }) + } } diff --git a/crates/orderbook/src/api/get_auction.rs b/crates/orderbook/src/api/get_auction.rs index cfe169f8a7..1577fdc363 100644 --- a/crates/orderbook/src/api/get_auction.rs +++ b/crates/orderbook/src/api/get_auction.rs @@ -1,34 +1,25 @@ use { - crate::{api::ApiReply, orderbook::Orderbook}, - anyhow::Result, - reqwest::StatusCode, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection, reply::with_status}, + crate::api::AppState, + axum::{ + extract::State, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, + std::sync::Arc, }; -fn get_auction_request() -> impl Filter + Clone { - warp::path!("v1" / "auction").and(warp::get()) -} - -pub fn get_auction( - orderbook: Arc, -) -> impl Filter + Clone { - get_auction_request().and_then(move || { - let orderbook = orderbook.clone(); - async move { - let result = orderbook.get_auction().await; - let reply = match result { - Ok(Some(auction)) => with_status(warp::reply::json(&auction), StatusCode::OK), - Ok(None) => with_status( - super::error("NotFound", "There is no active auction"), - StatusCode::NOT_FOUND, - ), - Err(err) => { - tracing::error!(?err, "/api/v1/get_auction"); - crate::api::internal_error_reply() - } - }; - Result::<_, Infallible>::Ok(reply) +pub async fn get_auction_handler(State(state): State>) -> Response { + let result = state.orderbook.get_auction().await; + match result { + Ok(Some(auction)) => Json(auction).into_response(), + Ok(None) => ( + StatusCode::NOT_FOUND, + super::error("NotFound", "There is no active auction"), + ) + .into_response(), + Err(err) => { + tracing::error!(?err, "/api/v1/get_auction"); + crate::api::internal_error_reply() } - }) + } } diff --git a/crates/orderbook/src/api/get_native_price.rs b/crates/orderbook/src/api/get_native_price.rs index b2c027ebce..52c490aeb4 100644 --- a/crates/orderbook/src/api/get_native_price.rs +++ b/crates/orderbook/src/api/get_native_price.rs @@ -1,50 +1,23 @@ use { - crate::api::{ApiReply, IntoWarpReply}, + crate::api::{AppState, PriceEstimationErrorWrapper}, alloy::primitives::Address, - anyhow::Result, + axum::{ + extract::{Path, State}, + response::{IntoResponse, Json, Response}, + }, model::quote::NativeTokenPrice, - shared::price_estimation::native::NativePriceEstimating, - std::{convert::Infallible, sync::Arc, time::Duration}, - warp::{Filter, Rejection, hyper::StatusCode, reply::with_status}, + std::sync::Arc, }; -fn get_native_prices_request() -> impl Filter + Clone { - warp::path!("v1" / "token" / Address / "native_price").and(warp::get()) -} - -pub fn get_native_price( - estimator: Arc, - quote_timeout: Duration, -) -> impl Filter + Clone { - get_native_prices_request().and_then(move |token: Address| { - let estimator = estimator.clone(); - async move { - let result = estimator.estimate_native_price(token, quote_timeout).await; - let reply = match result { - Ok(price) => with_status( - warp::reply::json(&NativeTokenPrice { price }), - StatusCode::OK, - ), - Err(err) => err.into_warp_reply(), - }; - Result::<_, Infallible>::Ok(reply) - } - }) -} - -#[cfg(test)] -mod tests { - use {super::*, alloy::primitives::address, futures::FutureExt, warp::test::request}; - - #[test] - fn native_prices_query() { - let path = "/v1/token/0xdac17f958d2ee523a2206206994597c13d831ec7/native_price"; - let request = request().path(path).method("GET"); - let result = request - .filter(&get_native_prices_request()) - .now_or_never() - .unwrap() - .unwrap(); - assert_eq!(result, address!("dac17f958d2ee523a2206206994597c13d831ec7")); - } +pub async fn get_native_price_handler( + State(state): State>, + Path(token): Path
, +) -> Response { + state + .native_price_estimator + .estimate_native_price(token, state.quote_timeout) + .await + .map(|price| Json(NativeTokenPrice { price })) + .map_err(PriceEstimationErrorWrapper) + .into_response() } diff --git a/crates/orderbook/src/api/get_order_by_uid.rs b/crates/orderbook/src/api/get_order_by_uid.rs index 9a579eacaf..7cc11721e3 100644 --- a/crates/orderbook/src/api/get_order_by_uid.rs +++ b/crates/orderbook/src/api/get_order_by_uid.rs @@ -1,16 +1,24 @@ use { - crate::orderbook::Orderbook, + crate::api::AppState, anyhow::Result, + axum::{ + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, model::order::{Order, OrderUid}, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection, hyper::StatusCode, reply}, + std::sync::Arc, }; -pub fn get_order_by_uid_request() -> impl Filter + Clone { - warp::path!("v1" / "orders" / OrderUid).and(warp::get()) +pub async fn get_order_by_uid_handler( + State(state): State>, + Path(uid): Path, +) -> Response { + let result = state.orderbook.get_order(&uid).await; + get_order_by_uid_response(result) } -pub fn get_order_by_uid_response(result: Result>) -> super::ApiReply { +pub fn get_order_by_uid_response(result: Result>) -> Response { let order = match result { Ok(order) => order, Err(err) => { @@ -19,47 +27,23 @@ pub fn get_order_by_uid_response(result: Result>) -> super::ApiRep } }; match order { - Some(order) => reply::with_status(reply::json(&order), StatusCode::OK), - None => reply::with_status( - super::error("NotFound", "Order was not found"), + Some(order) => (StatusCode::OK, Json(order)).into_response(), + None => ( StatusCode::NOT_FOUND, - ), + super::error("NotFound", "Order was not found"), + ) + .into_response(), } } -pub fn get_order_by_uid( - orderbook: Arc, -) -> impl Filter + Clone { - get_order_by_uid_request().and_then(move |uid| { - let orderbook = orderbook.clone(); - async move { - let result = orderbook.get_order(&uid).await; - Result::<_, Infallible>::Ok(get_order_by_uid_response(result)) - } - }) -} - #[cfg(test)] mod tests { - use { - super::*, - crate::api::response_body, - warp::{Reply, test::request}, - }; - - #[tokio::test] - async fn get_order_by_uid_request_ok() { - let uid = OrderUid::default(); - let request = request().path(&format!("/v1/orders/{uid}")).method("GET"); - let filter = get_order_by_uid_request(); - let result = request.filter(&filter).await.unwrap(); - assert_eq!(result, uid); - } + use {super::*, crate::api::response_body}; #[tokio::test] async fn get_order_by_uid_response_ok() { let order = Order::default(); - let response = get_order_by_uid_response(Ok(Some(order.clone()))).into_response(); + let response = get_order_by_uid_response(Ok(Some(order.clone()))); assert_eq!(response.status(), StatusCode::OK); let body = response_body(response).await; let response_order: Order = serde_json::from_slice(body.as_slice()).unwrap(); @@ -68,7 +52,7 @@ mod tests { #[tokio::test] async fn get_order_by_uid_response_non_existent() { - let response = get_order_by_uid_response(Ok(None)).into_response(); + let response = get_order_by_uid_response(Ok(None)); assert_eq!(response.status(), StatusCode::NOT_FOUND); } } diff --git a/crates/orderbook/src/api/get_order_status.rs b/crates/orderbook/src/api/get_order_status.rs index 90f0d5336e..40d92c9292 100644 --- a/crates/orderbook/src/api/get_order_status.rs +++ b/crates/orderbook/src/api/get_order_status.rs @@ -1,36 +1,29 @@ use { - crate::{ - api::ApiReply, - orderbook::{OrderStatusError, Orderbook}, + crate::{api::AppState, orderbook::OrderStatusError}, + axum::{ + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, }, - anyhow::Result, model::order::OrderUid, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection, hyper::StatusCode, reply}, + std::sync::Arc, }; -fn get_status_request() -> impl Filter + Clone { - warp::path!("v1" / "orders" / OrderUid / "status").and(warp::get()) -} - -pub fn get_status( - orderbook: Arc, -) -> impl Filter + Clone { - get_status_request().and_then(move |uid| { - let orderbook = orderbook.clone(); - async move { - let status = orderbook.get_order_status(&uid).await; - Result::<_, Infallible>::Ok(match status { - Ok(status) => warp::reply::with_status(warp::reply::json(&status), StatusCode::OK), - Err(OrderStatusError::NotFound) => reply::with_status( - super::error("NotFound", "Order status was not found"), - StatusCode::NOT_FOUND, - ), - Err(err) => { - tracing::error!(?err, "get_order_status"); - *Box::new(crate::api::internal_error_reply()) - } - }) +pub async fn get_status_handler( + State(state): State>, + Path(uid): Path, +) -> Response { + let status = state.orderbook.get_order_status(&uid).await; + match status { + Ok(status) => Json(status).into_response(), + Err(err @ OrderStatusError::NotFound) => ( + StatusCode::NOT_FOUND, + super::error("NotFound", err.to_string()), + ) + .into_response(), + Err(err) => { + tracing::error!(?err, "get_order_status"); + crate::api::internal_error_reply() } - }) + } } diff --git a/crates/orderbook/src/api/get_orders_by_tx.rs b/crates/orderbook/src/api/get_orders_by_tx.rs index dc357227de..a50c2dd43d 100644 --- a/crates/orderbook/src/api/get_orders_by_tx.rs +++ b/crates/orderbook/src/api/get_orders_by_tx.rs @@ -1,47 +1,23 @@ use { - crate::{api::ApiReply, orderbook::Orderbook}, + crate::api::AppState, alloy::primitives::B256, - anyhow::Result, - reqwest::StatusCode, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection, reply::with_status}, + axum::{ + extract::{Path, State}, + response::{IntoResponse, Json, Response}, + }, + std::sync::Arc, }; -pub fn get_orders_by_tx_request() -> impl Filter + Clone { - warp::path!("v1" / "transactions" / B256 / "orders").and(warp::get()) -} - -pub fn get_orders_by_tx( - orderbook: Arc, -) -> impl Filter + Clone { - get_orders_by_tx_request().and_then(move |hash: B256| { - let orderbook = orderbook.clone(); - async move { - let result = orderbook.get_orders_for_tx(&hash).await; - Result::<_, Infallible>::Ok(match result { - Ok(response) => with_status(warp::reply::json(&response), StatusCode::OK), - Err(err) => { - tracing::error!(?err, "get_orders_by_tx"); - crate::api::internal_error_reply() - } - }) +pub async fn get_orders_by_tx_handler( + State(state): State>, + Path(hash): Path, +) -> Response { + let result = state.orderbook.get_orders_for_tx(&hash).await; + match result { + Ok(response) => Json(response).into_response(), + Err(err) => { + tracing::error!(?err, "get_orders_by_tx"); + crate::api::internal_error_reply() } - }) -} - -#[cfg(test)] -mod tests { - use {super::*, std::str::FromStr}; - - #[tokio::test] - async fn request_ok() { - let hash_str = "0x0191dbb560e936bd3320d5a505c9c05580a0ebb7e12fe117551ac26e484f295e"; - let result = warp::test::request() - .path(&format!("/v1/transactions/{hash_str}/orders")) - .method("GET") - .filter(&get_orders_by_tx_request()) - .await - .unwrap(); - assert_eq!(result.0, B256::from_str(hash_str).unwrap().0); } } diff --git a/crates/orderbook/src/api/get_orders_by_uid.rs b/crates/orderbook/src/api/get_orders_by_uid.rs new file mode 100644 index 0000000000..fd0831ec97 --- /dev/null +++ b/crates/orderbook/src/api/get_orders_by_uid.rs @@ -0,0 +1,122 @@ +use { + crate::api::AppState, + anyhow::Result, + axum::{ + extract::State, + http::StatusCode, + response::{IntoResponse, Response}, + }, + model::order::{ORDER_UID_LIMIT, Order, OrderUid}, + serde::Serialize, + std::sync::Arc, +}; + +#[expect(clippy::large_enum_variant)] +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +enum OrderResultEntry { + Order(Order), + Error(OrderError), +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct OrderError { + uid: OrderUid, + description: String, +} + +pub async fn get_orders_by_uid_handler( + State(state): State>, + axum::Json(orders): axum::Json>, +) -> Response { + if orders.len() > ORDER_UID_LIMIT { + return ( + StatusCode::BAD_REQUEST, + format!("Request exceeds maximum number of order UIDs of {ORDER_UID_LIMIT}"), + ) + .into_response(); + } + + get_orders_by_uid_response(state.orderbook.get_orders(&orders).await) +} + +fn get_orders_by_uid_response(result: Result)>>) -> Response { + match result { + Ok(orders) => axum::Json( + orders + .into_iter() + .map(|(uid, order)| match order { + Ok(order) => OrderResultEntry::Order(order), + Err(err) => { + tracing::warn!(?err, "Error converting into model order"); + OrderResultEntry::Error(OrderError { + uid, + description: "Internal server error encountered when retrieving the \ + order" + .to_string(), + }) + } + }) + .collect::>(), + ) + .into_response(), + Err(err) => { + tracing::error!(?err, "get_orders_by_uid_response"); + crate::api::internal_error_reply() + } + } +} + +#[cfg(test)] +mod tests { + use {super::*, crate::api::response_body}; + + #[tokio::test] + async fn get_orders_by_uid_ok() { + let order = Order::default(); + let uid = order.metadata.uid; + let result = vec![(uid, Ok(order.clone()))]; + let response = get_orders_by_uid_response(Ok(result)); + assert_eq!(response.status(), StatusCode::OK); + + let body = response_body(response).await; + let entries: Vec = serde_json::from_slice(&body).unwrap(); + assert_eq!(entries.len(), 1); + + let order_entry: Order = + serde_json::from_value(entries[0].get("order").expect("key order exists").clone()) + .expect("value is a correct Order"); + assert_eq!(order_entry, order); + } + + #[tokio::test] + async fn get_orders_by_uid_conversion_error() { + let uid = OrderUid([1u8; 56]); + let result = vec![(uid, Err(anyhow::anyhow!("bad data")))]; + let response = get_orders_by_uid_response(Ok(result)); + assert_eq!(response.status(), StatusCode::OK); + + let body = response_body(response).await; + let entries: Vec = serde_json::from_slice(&body).unwrap(); + assert_eq!(entries.len(), 1); + + let error = entries[0].get("error").expect("error key exists"); + let error_uid: OrderUid = error.get("uid").unwrap().as_str().unwrap().parse().unwrap(); + assert_eq!(error_uid, uid); + assert_eq!( + error + .get("description") + .expect("key description exists") + .as_str() + .expect("description is a string"), + "Internal server error encountered when retrieving the order" + ); + } + + #[tokio::test] + async fn get_orders_by_uid_err() { + let response = get_orders_by_uid_response(Err(anyhow::anyhow!("error"))); + assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR); + } +} diff --git a/crates/orderbook/src/api/get_solver_competition.rs b/crates/orderbook/src/api/get_solver_competition.rs deleted file mode 100644 index 26e7a38390..0000000000 --- a/crates/orderbook/src/api/get_solver_competition.rs +++ /dev/null @@ -1,114 +0,0 @@ -use { - crate::solver_competition::{Identifier, LoadSolverCompetitionError, SolverCompetitionStoring}, - alloy::primitives::B256, - anyhow::Result, - model::{AuctionId, solver_competition::SolverCompetitionAPI}, - reqwest::StatusCode, - std::{convert::Infallible, sync::Arc}, - warp::{ - Filter, - Rejection, - reply::{Json, WithStatus, with_status}, - }, -}; - -fn request_id() -> impl Filter + Clone { - warp::path!("v1" / "solver_competition" / AuctionId) - .and(warp::get()) - .map(Identifier::Id) -} - -fn request_hash() -> impl Filter + Clone { - warp::path!("v1" / "solver_competition" / "by_tx_hash" / B256) - .and(warp::get()) - .map(Identifier::Transaction) -} - -fn request_latest() -> impl Filter + Clone { - warp::path!("v1" / "solver_competition" / "latest").and(warp::get()) -} -pub fn get( - handler: Arc, -) -> impl Filter + Clone { - request_id() - .or(request_hash()) - .unify() - .and_then(move |identifier: Identifier| { - let handler = handler.clone(); - async move { - let result = handler.load_competition(identifier).await; - Result::<_, Infallible>::Ok(response(result)) - } - }) -} - -pub fn get_latest( - handler: Arc, -) -> impl Filter + Clone { - request_latest().and_then(move || { - let handler = handler.clone(); - async move { - let result = handler.load_latest_competition().await; - Result::<_, Infallible>::Ok(response(result)) - } - }) -} - -fn response( - result: Result, -) -> WithStatus { - match result { - Ok(response) => with_status(warp::reply::json(&response), StatusCode::OK), - Err(LoadSolverCompetitionError::NotFound) => with_status( - super::error("NotFound", "no competition found"), - StatusCode::NOT_FOUND, - ), - Err(LoadSolverCompetitionError::Other(err)) => { - tracing::error!(?err, "load solver competition"); - crate::api::internal_error_reply() - } - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::solver_competition::MockSolverCompetitionStoring, - warp::{Reply, test::request}, - }; - - #[tokio::test] - async fn test() { - let mut storage = MockSolverCompetitionStoring::new(); - storage - .expect_load_competition() - .times(2) - .returning(|_| Ok(Default::default())); - storage - .expect_load_competition() - .times(1) - .return_once(|_| Err(LoadSolverCompetitionError::NotFound)); - let filter = get(Arc::new(storage)); - - let request_ = request().path("/v1/solver_competition/0").method("GET"); - let response = request_.filter(&filter).await.unwrap().into_response(); - dbg!(&response); - assert_eq!(response.status(), StatusCode::OK); - - let request_ = request() - .path( - "/v1/solver_competition/by_tx_hash/\ - 0xd51f28edffcaaa76be4a22f6375ad289272c037f3cc072345676e88d92ced8b5", - ) - .method("GET"); - let response = request_.filter(&filter).await.unwrap().into_response(); - dbg!(&response); - assert_eq!(response.status(), StatusCode::OK); - - let request_ = request().path("/v1/solver_competition/1337").method("GET"); - let response = request_.filter(&filter).await.unwrap().into_response(); - dbg!(&response); - assert_eq!(response.status(), StatusCode::NOT_FOUND); - } -} diff --git a/crates/orderbook/src/api/get_solver_competition_v2.rs b/crates/orderbook/src/api/get_solver_competition_v2.rs index 85850a8ec9..66db3216b9 100644 --- a/crates/orderbook/src/api/get_solver_competition_v2.rs +++ b/crates/orderbook/src/api/get_solver_competition_v2.rs @@ -1,76 +1,77 @@ use { - crate::{ - database::Postgres, - solver_competition::{Identifier, LoadSolverCompetitionError}, - }, + crate::{api::AppState, database::Postgres, solver_competition::LoadSolverCompetitionError}, alloy::primitives::B256, - anyhow::Result, - model::{AuctionId, solver_competition_v2::Response}, - reqwest::StatusCode, - std::convert::Infallible, - warp::{ - Filter, - Rejection, - reply::{Json, WithStatus, with_status}, + axum::{ + extract::{Path, State}, + response::{IntoResponse, Json, Response}, }, + model::{AuctionId, solver_competition_v2::Response as CompetitionResponse}, + std::sync::Arc, }; -fn request_id() -> impl Filter + Clone { - warp::path!("v2" / "solver_competition" / AuctionId) - .and(warp::get()) - .map(Identifier::Id) -} +pub async fn get_solver_competition_by_id_handler( + State(state): State>, + Path(auction_id): Path, +) -> Response { + // We use u64 to ensure that negative numbers are returned as BAD_REQUEST + // however, there's a gap between u64::MAX and i64::MAX, numbers beyond i64::MAX + // will be marked as NOT_FOUND as they're positive (and as such, valid) but + // they are not covered by our system + if auction_id > AuctionId::MAX.cast_unsigned() { + return LoadSolverCompetitionError::NotFound.into_response(); + } -fn request_hash() -> impl Filter + Clone { - warp::path!("v2" / "solver_competition" / "by_tx_hash" / B256) - .and(warp::get()) - .map(Identifier::Transaction) + db(&state) + .load_competition_by_id( + auction_id.cast_signed(), + state.hide_competition_before_block(), + ) + .await + .map(Json) + .into_response() } -fn request_latest() -> impl Filter + Clone { - warp::path!("v2" / "solver_competition" / "latest").and(warp::get()) +pub async fn get_solver_competition_by_hash_handler( + State(state): State>, + Path(tx_hash): Path, +) -> Response { + db(&state) + .load_competition_by_tx_hash(tx_hash, state.hide_competition_before_block()) + .await + .map(Json) + .into_response() } -pub fn get(db: Postgres) -> impl Filter + Clone { - request_id() - .or(request_hash()) - .unify() - .and_then(move |identifier: Identifier| { - let db = db.clone(); - async move { - let result = match identifier { - Identifier::Id(id) => db.load_competition_by_id(id).await, - Identifier::Transaction(hash) => db.load_competition_by_tx_hash(hash).await, - }; - Result::<_, Infallible>::Ok(response(result)) - } - }) +pub async fn get_solver_competition_latest_handler( + State(state): State>, +) -> Result, LoadSolverCompetitionError> { + db(&state) + .load_latest_competition(state.hide_competition_before_block()) + .await + .map(Json) } -pub fn get_latest( - db: Postgres, -) -> impl Filter + Clone { - request_latest().and_then(move || { - let db = db.clone(); - async move { - let result = db.load_latest_competition().await; - Result::<_, Infallible>::Ok(response(result)) - } - }) +/// Internal endpoint that skips deadline filtering (access restricted on +/// infra level). +pub async fn get_solver_competition_by_id_unfiltered_handler( + State(state): State>, + Path(auction_id): Path, +) -> Response { + if auction_id > AuctionId::MAX.cast_unsigned() { + return LoadSolverCompetitionError::NotFound.into_response(); + } + + db(&state) + .load_competition_by_id(auction_id.cast_signed(), None) + .await + .map(Json) + .into_response() } -fn response( - result: Result, -) -> WithStatus { - match result { - Ok(response) => with_status(warp::reply::json(&response), StatusCode::OK), - Err(LoadSolverCompetitionError::NotFound) => with_status( - super::error("NotFound", "no competition found"), - StatusCode::NOT_FOUND, - ), - Err(LoadSolverCompetitionError::Other(err)) => { - tracing::error!(?err, "load solver competition"); - crate::api::internal_error_reply() - } - } +fn db(state: &AppState) -> &Postgres { + // While these queries actually don't write to the DB + // the latency incurred by the DB replication process + // is not acceptable in some cases (e.g. when the circuit + // breaker needs to decide whether an tx was out of competition). + &state.database_write } diff --git a/crates/orderbook/src/api/get_token_metadata.rs b/crates/orderbook/src/api/get_token_metadata.rs index d8f0631564..06782b4dd4 100644 --- a/crates/orderbook/src/api/get_token_metadata.rs +++ b/crates/orderbook/src/api/get_token_metadata.rs @@ -1,31 +1,23 @@ use { - crate::database::Postgres, + crate::api::AppState, alloy::primitives::Address, - hyper::StatusCode, - std::convert::Infallible, - warp::{Filter, Rejection, reply}, + axum::{ + extract::{Path, State}, + response::{IntoResponse, Json, Response}, + }, + std::sync::Arc, }; -fn get_native_prices_request() -> impl Filter + Clone { - warp::path!("v1" / "token" / Address / "metadata").and(warp::get()) -} - -pub fn get_token_metadata( - db: Postgres, -) -> impl Filter + Clone { - get_native_prices_request().and_then(move |token: Address| { - let db = db.clone(); - async move { - let result = db.token_metadata(&token).await; - let response = match result { - Ok(metadata) => reply::with_status(reply::json(&metadata), StatusCode::OK), - Err(err) => { - tracing::error!(?err, ?token, "Failed to fetch token's first trade block"); - crate::api::internal_error_reply() - } - }; - - Result::<_, Infallible>::Ok(response) +pub async fn get_token_metadata_handler( + State(state): State>, + Path(token): Path
, +) -> Response { + let result = state.database_read.token_metadata(&token).await; + match result { + Ok(metadata) => Json(metadata).into_response(), + Err(err) => { + tracing::error!(?err, ?token, "Failed to fetch token's first trade block"); + crate::api::internal_error_reply() } - }) + } } diff --git a/crates/orderbook/src/api/get_total_surplus.rs b/crates/orderbook/src/api/get_total_surplus.rs index afdbc07b93..04d5434f2f 100644 --- a/crates/orderbook/src/api/get_total_surplus.rs +++ b/crates/orderbook/src/api/get_total_surplus.rs @@ -1,30 +1,31 @@ use { - crate::database::Postgres, + crate::api::AppState, alloy::primitives::Address, + axum::{ + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, serde_json::json, - std::convert::Infallible, - warp::{Filter, Rejection, http::StatusCode, reply::with_status}, + std::sync::Arc, }; -pub fn get(db: Postgres) -> impl Filter + Clone { - warp::path!("v1" / "users" / Address / "total_surplus") - .and(warp::get()) - .and_then(move |user| { - let db = db.clone(); - async move { - let surplus = db.total_surplus(&user).await; - Result::<_, Infallible>::Ok(match surplus { - Ok(surplus) => with_status( - warp::reply::json(&json!({ - "totalSurplus": surplus.to_string() - })), - StatusCode::OK, - ), - Err(err) => { - tracing::error!(?err, ?user, "failed to compute total surplus"); - crate::api::internal_error_reply() - } - }) - } - }) +pub async fn get_total_surplus_handler( + State(state): State>, + Path(user): Path
, +) -> Response { + let surplus = state.database_read.total_surplus(&user).await; + match surplus { + Ok(surplus) => ( + StatusCode::OK, + Json(json!({ + "totalSurplus": surplus.to_string() + })), + ) + .into_response(), + Err(err) => { + tracing::error!(?err, ?user, "failed to compute total surplus"); + crate::api::internal_error_reply() + } + } } diff --git a/crates/orderbook/src/api/get_trades.rs b/crates/orderbook/src/api/get_trades.rs index a104c7cb55..fd8dcaf907 100644 --- a/crates/orderbook/src/api/get_trades.rs +++ b/crates/orderbook/src/api/get_trades.rs @@ -1,22 +1,23 @@ use { crate::{ - api::{ApiReply, error}, - database::{ - Postgres, - trades::{TradeFilter, TradeRetrieving}, - }, + api::{AppState, error}, + database::trades::{TradeFilter, TradeRetrieving}, }, alloy::primitives::Address, - anyhow::{Context, Result}, + anyhow::Context, + axum::{ + extract::{Query, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, model::order::OrderUid, serde::Deserialize, - std::convert::Infallible, - warp::{Filter, Rejection, hyper::StatusCode, reply::with_status}, + std::sync::Arc, }; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct Query { +pub(crate) struct QueryParams { pub order_uid: Option, pub owner: Option
, } @@ -26,7 +27,7 @@ enum TradeFilterError { InvalidFilter(String), } -impl Query { +impl QueryParams { fn trade_filter(&self) -> TradeFilter { TradeFilter { order_uid: self.order_uid, @@ -44,87 +45,71 @@ impl Query { } } -fn get_trades_request() --> impl Filter,), Error = Rejection> + Clone { - warp::path!("v1" / "trades") - .and(warp::get()) - .and(warp::query::()) - .map(|query: Query| query.validate()) -} +pub async fn get_trades_handler( + State(state): State>, + Query(query): Query, +) -> Response { + let trade_filter = match query.validate() { + Ok(trade_filter) => trade_filter, + Err(TradeFilterError::InvalidFilter(msg)) => { + let err = error("InvalidTradeFilter", msg); + return (StatusCode::BAD_REQUEST, err).into_response(); + } + }; -pub fn get_trades(db: Postgres) -> impl Filter + Clone { - get_trades_request().and_then(move |request_result| { - let database = db.clone(); - async move { - Result::<_, Infallible>::Ok(match request_result { - Ok(trade_filter) => { - let result = database.trades(&trade_filter).await.context("get_trades"); - match result { - Ok(reply) => with_status(warp::reply::json(&reply), StatusCode::OK), - Err(err) => { - tracing::error!(?err, "get_trades"); - crate::api::internal_error_reply() - } - } - } - Err(TradeFilterError::InvalidFilter(msg)) => { - let err = error("InvalidTradeFilter", msg); - with_status(err, StatusCode::BAD_REQUEST) - } - }) + let result = state + .database_read + .trades(&trade_filter) + .await + .context("get_trades"); + match result { + Ok(reply) => Json(reply).into_response(), + Err(err) => { + tracing::error!(?err, "get_trades"); + crate::api::internal_error_reply() } - }) + } } #[cfg(test)] mod tests { - use { - super::*, - warp::test::{RequestBuilder, request}, - }; - - #[tokio::test] - async fn get_trades_request_ok() { - let trade_filter = |request: RequestBuilder| async move { - let filter = get_trades_request(); - request.method("GET").filter(&filter).await - }; + use {super::*, alloy::primitives::Address, model::order::OrderUid}; + #[test] + fn query_validation_ok() { let owner = Address::with_last_byte(1); - let owner_path = format!("/v1/trades?owner=0x{owner:x}"); - let result = trade_filter(request().path(owner_path.as_str())) - .await - .unwrap() - .unwrap(); + let query = QueryParams { + owner: Some(owner), + order_uid: None, + }; + let result = query.validate().unwrap(); assert_eq!(result.owner, Some(owner)); assert_eq!(result.order_uid, None); let uid = OrderUid([1u8; 56]); - let order_uid_path = format!("/v1/trades?orderUid={uid}"); - let result = trade_filter(request().path(order_uid_path.as_str())) - .await - .unwrap() - .unwrap(); + let query = QueryParams { + owner: None, + order_uid: Some(uid), + }; + let result = query.validate().unwrap(); assert_eq!(result.owner, None); assert_eq!(result.order_uid, Some(uid)); } - #[tokio::test] - async fn get_trades_request_err() { - let trade_filter = |request: RequestBuilder| async move { - let filter = get_trades_request(); - request.method("GET").filter(&filter).await - }; - + #[test] + fn query_validation_err() { let owner = Address::with_last_byte(1); let uid = OrderUid([1u8; 56]); - let path = format!("/v1/trades?owner=0x{owner:x}&orderUid={uid}"); - - let result = trade_filter(request().path(path.as_str())).await.unwrap(); - assert!(result.is_err()); + let query = QueryParams { + owner: Some(owner), + order_uid: Some(uid), + }; + assert!(query.validate().is_err()); - let path = "/v1/trades"; - let result = trade_filter(request().path(path)).await.unwrap(); - assert!(result.is_err()); + let query = QueryParams { + owner: None, + order_uid: None, + }; + assert!(query.validate().is_err()); } } diff --git a/crates/orderbook/src/api/get_trades_v2.rs b/crates/orderbook/src/api/get_trades_v2.rs new file mode 100644 index 0000000000..b3c1073849 --- /dev/null +++ b/crates/orderbook/src/api/get_trades_v2.rs @@ -0,0 +1,188 @@ +use { + crate::{ + api::{AppState, error}, + database::trades::{PaginatedTradeFilter, TradeRetrievingPaginated}, + }, + alloy::primitives::Address, + anyhow::Context, + axum::{ + extract::{Query, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, + model::order::OrderUid, + serde::Deserialize, + std::sync::Arc, +}; + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct QueryParams { + pub order_uid: Option, + pub owner: Option
, + pub offset: Option, + pub limit: Option, +} + +const DEFAULT_OFFSET: u64 = 0; +const DEFAULT_LIMIT: u64 = 10; +const MIN_LIMIT: u64 = 1; +const MAX_LIMIT: u64 = 1000; + +#[derive(Debug, Eq, PartialEq)] +enum TradeFilterError { + InvalidFilter(String), + InvalidLimit(u64, u64), +} + +impl QueryParams { + fn trade_filter(&self, offset: u64, limit: u64) -> PaginatedTradeFilter { + PaginatedTradeFilter { + order_uid: self.order_uid, + owner: self.owner, + offset, + limit, + } + } + + fn validate(&self) -> Result { + match (self.order_uid.as_ref(), self.owner.as_ref()) { + (Some(_), None) | (None, Some(_)) => { + let offset = self.offset.unwrap_or(DEFAULT_OFFSET); + let limit = self.limit.unwrap_or(DEFAULT_LIMIT); + + if !(MIN_LIMIT..=MAX_LIMIT).contains(&limit) { + return Err(TradeFilterError::InvalidLimit(MIN_LIMIT, MAX_LIMIT)); + } + + Ok(self.trade_filter(offset, limit)) + } + _ => Err(TradeFilterError::InvalidFilter( + "Must specify exactly one of owner or orderUid.".to_owned(), + )), + } + } +} + +pub async fn get_trades_handler( + State(state): State>, + Query(query): Query, +) -> Response { + let trade_filter = match query.validate() { + Ok(trade_filter) => trade_filter, + Err(TradeFilterError::InvalidFilter(msg)) => { + let err = error("InvalidTradeFilter", msg); + return (StatusCode::BAD_REQUEST, err).into_response(); + } + Err(TradeFilterError::InvalidLimit(min, max)) => { + let err = error( + "InvalidLimit", + format!("limit must be between {min} and {max}"), + ); + return (StatusCode::BAD_REQUEST, err).into_response(); + } + }; + + let result = state + .database_read + .trades_paginated(&trade_filter) + .await + .context("get_trades_v2"); + match result { + Ok(reply) => (StatusCode::OK, Json(reply)).into_response(), + Err(err) => { + tracing::error!(?err, "get_trades_v2"); + crate::api::internal_error_reply() + } + } +} + +#[cfg(test)] +mod tests { + use {super::*, alloy::primitives::Address, model::order::OrderUid}; + + #[test] + fn query_validation_ok() { + let owner = Address::with_last_byte(1); + let query = QueryParams { + owner: Some(owner), + order_uid: None, + offset: None, + limit: None, + }; + let result = query.validate().unwrap(); + assert_eq!(result.owner, Some(owner)); + assert_eq!(result.order_uid, None); + assert_eq!(result.offset, DEFAULT_OFFSET); + assert_eq!(result.limit, DEFAULT_LIMIT); + + let uid = OrderUid([1u8; 56]); + let query = QueryParams { + owner: None, + order_uid: Some(uid), + offset: None, + limit: None, + }; + let result = query.validate().unwrap(); + assert_eq!(result.owner, None); + assert_eq!(result.order_uid, Some(uid)); + assert_eq!(result.offset, DEFAULT_OFFSET); + assert_eq!(result.limit, DEFAULT_LIMIT); + + // Test with custom offset and limit + let query = QueryParams { + owner: Some(owner), + order_uid: None, + offset: Some(10), + limit: Some(50), + }; + let result = query.validate().unwrap(); + assert_eq!(result.owner, Some(owner)); + assert_eq!(result.offset, 10); + assert_eq!(result.limit, 50); + } + + #[test] + fn query_validation_err() { + let owner = Address::with_last_byte(1); + let uid = OrderUid([1u8; 56]); + let query = QueryParams { + owner: Some(owner), + order_uid: Some(uid), + offset: None, + limit: None, + }; + assert!(query.validate().is_err()); + + let query = QueryParams { + owner: None, + order_uid: None, + offset: None, + limit: None, + }; + assert!(query.validate().is_err()); + + // Test limit validation + let query = QueryParams { + owner: Some(owner), + order_uid: None, + offset: None, + limit: Some(0), + }; + assert!(matches!( + query.validate(), + Err(TradeFilterError::InvalidLimit(MIN_LIMIT, MAX_LIMIT)) + )); + + let query = QueryParams { + owner: Some(owner), + order_uid: None, + offset: None, + limit: Some(1001), + }; + assert!(matches!( + query.validate(), + Err(TradeFilterError::InvalidLimit(MIN_LIMIT, MAX_LIMIT)) + )); + } +} diff --git a/crates/orderbook/src/api/get_user_orders.rs b/crates/orderbook/src/api/get_user_orders.rs index 77783b29bf..8330a72313 100644 --- a/crates/orderbook/src/api/get_user_orders.rs +++ b/crates/orderbook/src/api/get_user_orders.rs @@ -1,82 +1,51 @@ use { - crate::{api::ApiReply, orderbook::Orderbook}, + crate::api::AppState, alloy::primitives::Address, - anyhow::Result, + axum::{ + extract::{Path, Query, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, serde::Deserialize, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection, hyper::StatusCode, reply::with_status}, + std::sync::Arc, }; #[derive(Clone, Copy, Debug, Deserialize)] -struct Query { +pub(crate) struct QueryParams { offset: Option, limit: Option, } -fn request() -> impl Filter + Clone { - warp::path!("v1" / "account" / Address / "orders") - .and(warp::get()) - .and(warp::query::()) -} - -pub fn get_user_orders( - orderbook: Arc, -) -> impl Filter + Clone { - request().and_then(move |owner: Address, query: Query| { - let orderbook = orderbook.clone(); - async move { - const DEFAULT_OFFSET: u64 = 0; - const DEFAULT_LIMIT: u64 = 10; - const MIN_LIMIT: u64 = 1; - const MAX_LIMIT: u64 = 1000; - let offset = query.offset.unwrap_or(DEFAULT_OFFSET); - let limit = query.limit.unwrap_or(DEFAULT_LIMIT); - if !(MIN_LIMIT..=MAX_LIMIT).contains(&limit) { - return Ok(with_status( - super::error( - "LIMIT_OUT_OF_BOUNDS", - format!("The pagination limit is [{MIN_LIMIT},{MAX_LIMIT}]."), - ), - StatusCode::BAD_REQUEST, - )); - } - let result = orderbook.get_user_orders(&owner, offset, limit).await; - Result::<_, Infallible>::Ok(match result { - Ok(reply) => with_status(warp::reply::json(&reply), StatusCode::OK), - Err(err) => { - tracing::error!(?err, "get_user_orders"); - crate::api::internal_error_reply() - } - }) - } - }) -} +pub async fn get_user_orders_handler( + State(state): State>, + Path(owner): Path
, + Query(query): Query, +) -> Response { + const DEFAULT_OFFSET: u64 = 0; + const DEFAULT_LIMIT: u64 = 10; + const MIN_LIMIT: u64 = 1; + const MAX_LIMIT: u64 = 1000; -#[cfg(test)] -mod tests { - use super::*; + let offset = query.offset.unwrap_or(DEFAULT_OFFSET); + let limit = query.limit.unwrap_or(DEFAULT_LIMIT); - #[tokio::test] - async fn request_() { - let path = "/v1/account/0x0000000000000000000000000000000000000001/orders"; - let result = warp::test::request() - .path(path) - .method("GET") - .filter(&request()) - .await - .unwrap(); - assert_eq!(result.0, Address::with_last_byte(1)); - assert_eq!(result.1.offset, None); - assert_eq!(result.1.limit, None); + if !(MIN_LIMIT..=MAX_LIMIT).contains(&limit) { + return ( + StatusCode::BAD_REQUEST, + super::error( + "LIMIT_OUT_OF_BOUNDS", + format!("The pagination limit is [{MIN_LIMIT},{MAX_LIMIT}]."), + ), + ) + .into_response(); + } - let path = "/v1/account/0x0000000000000000000000000000000000000001/orders?offset=1&limit=2"; - let result = warp::test::request() - .path(path) - .method("GET") - .filter(&request()) - .await - .unwrap(); - assert_eq!(result.1.offset, Some(1)); - assert_eq!(result.1.limit, Some(2)); + let result = state.orderbook.get_user_orders(&owner, offset, limit).await; + match result { + Ok(reply) => (StatusCode::OK, Json(reply)).into_response(), + Err(err) => { + tracing::error!(?err, "get_user_orders"); + crate::api::internal_error_reply() + } } } diff --git a/crates/orderbook/src/api/post_order.rs b/crates/orderbook/src/api/post_order.rs index 7a57ac4ed4..9db253913b 100644 --- a/crates/orderbook/src/api/post_order.rs +++ b/crates/orderbook/src/api/post_order.rs @@ -1,12 +1,16 @@ use { crate::{ - api::{ApiReply, IntoWarpReply, error, extract_payload}, - orderbook::{AddOrderError, OrderReplacementError, Orderbook}, + api::{AppState, error}, + orderbook::{AddOrderError, OrderReplacementError}, + }, + axum::{ + Json, + extract::State, + http::StatusCode, + response::{IntoResponse, Response}, }, - anyhow::Result, model::{ - order::{AppdataFromMismatch, OrderCreation, OrderUid}, - quote::QuoteId, + order::{AppdataFromMismatch, OrderCreation}, signature, }, shared::order_validation::{ @@ -15,77 +19,93 @@ use { PartialValidationError, ValidationError, }, - std::{convert::Infallible, sync::Arc}, - warp::{ - Filter, - Rejection, - hyper::StatusCode, - reply::{self, with_status}, - }, + std::sync::Arc, }; -pub fn create_order_request() -> impl Filter + Clone -{ - warp::path!("v1" / "orders") - .and(warp::post()) - .and(extract_payload()) +pub async fn post_order_handler( + State(state): State>, + Json(order): Json, +) -> Response { + state + .orderbook + .add_order(order.clone()) + .await + .map(|(order_uid, quote_metadata)| { + let quote_id = quote_metadata.as_ref().and_then(|q| q.id); + let quote_solver = quote_metadata.as_ref().map(|q| q.solver); + tracing::debug!(%order_uid, ?quote_id, ?quote_solver, "order created"); + (StatusCode::CREATED, Json(order_uid)) + }) + .inspect_err(|err| { + tracing::debug!(?order, ?err, "error creating order"); + }) + .into_response() } pub struct PartialValidationErrorWrapper(pub PartialValidationError); -impl IntoWarpReply for PartialValidationErrorWrapper { - fn into_warp_reply(self) -> ApiReply { +impl IntoResponse for PartialValidationErrorWrapper { + fn into_response(self) -> Response { match self.0 { - PartialValidationError::UnsupportedBuyTokenDestination(dest) => with_status( + PartialValidationError::UnsupportedBuyTokenDestination(dest) => ( + StatusCode::BAD_REQUEST, error("UnsupportedBuyTokenDestination", format!("Type {dest:?}")), + ) + .into_response(), + PartialValidationError::UnsupportedSellTokenSource(src) => ( StatusCode::BAD_REQUEST, - ), - PartialValidationError::UnsupportedSellTokenSource(src) => with_status( error("UnsupportedSellTokenSource", format!("Type {src:?}")), + ) + .into_response(), + PartialValidationError::UnsupportedOrderType => ( StatusCode::BAD_REQUEST, - ), - PartialValidationError::UnsupportedOrderType => with_status( error( "UnsupportedOrderType", "This order type is currently not supported", ), - StatusCode::BAD_REQUEST, - ), - PartialValidationError::Forbidden => with_status( - error("Forbidden", "Forbidden, your account is deny-listed"), + ) + .into_response(), + PartialValidationError::Forbidden => ( StatusCode::FORBIDDEN, - ), - PartialValidationError::ValidTo(OrderValidToError::Insufficient) => with_status( + error("Forbidden", "Forbidden, your account is deny-listed"), + ) + .into_response(), + PartialValidationError::ValidTo(OrderValidToError::Insufficient) => ( + StatusCode::BAD_REQUEST, error( "InsufficientValidTo", "validTo is not far enough in the future", ), + ) + .into_response(), + PartialValidationError::ValidTo(OrderValidToError::Excessive) => ( StatusCode::BAD_REQUEST, - ), - PartialValidationError::ValidTo(OrderValidToError::Excessive) => with_status( error("ExcessiveValidTo", "validTo is too far into the future"), + ) + .into_response(), + PartialValidationError::InvalidNativeSellToken => ( StatusCode::BAD_REQUEST, - ), - PartialValidationError::InvalidNativeSellToken => with_status( error( "InvalidNativeSellToken", "The chain's native token (Ether/xDai) cannot be used as the sell token", ), + ) + .into_response(), + PartialValidationError::SameBuyAndSellToken => ( StatusCode::BAD_REQUEST, - ), - PartialValidationError::SameBuyAndSellToken => with_status( error( "SameBuyAndSellToken", "Buy token is the same as the sell token.", ), + ) + .into_response(), + PartialValidationError::UnsupportedToken { token, reason } => ( StatusCode::BAD_REQUEST, - ), - PartialValidationError::UnsupportedToken { token, reason } => with_status( error( "UnsupportedToken", format!("Token {token:?} is unsupported: {reason}"), ), - StatusCode::BAD_REQUEST, - ), + ) + .into_response(), PartialValidationError::Other(err) => { tracing::error!(?err, "PartialValidatonError"); crate::api::internal_error_reply() @@ -95,14 +115,16 @@ impl IntoWarpReply for PartialValidationErrorWrapper { } pub struct AppDataValidationErrorWrapper(pub AppDataValidationError); -impl IntoWarpReply for AppDataValidationErrorWrapper { - fn into_warp_reply(self) -> ApiReply { +impl IntoResponse for AppDataValidationErrorWrapper { + fn into_response(self) -> Response { match self.0 { - AppDataValidationError::Invalid(err) => with_status( + AppDataValidationError::Invalid(err) => ( + StatusCode::BAD_REQUEST, error("InvalidAppData", format!("{err:?}")), + ) + .into_response(), + AppDataValidationError::Mismatch { provided, actual } => ( StatusCode::BAD_REQUEST, - ), - AppDataValidationError::Mismatch { provided, actual } => with_status( error( "AppDataHashMismatch", format!( @@ -110,30 +132,34 @@ impl IntoWarpReply for AppDataValidationErrorWrapper { {provided:?}", ), ), - StatusCode::BAD_REQUEST, - ), + ) + .into_response(), } } } pub struct ValidationErrorWrapper(ValidationError); -impl IntoWarpReply for ValidationErrorWrapper { - fn into_warp_reply(self) -> ApiReply { +impl IntoResponse for ValidationErrorWrapper { + fn into_response(self) -> Response { match self.0 { - ValidationError::Partial(pre) => PartialValidationErrorWrapper(pre).into_warp_reply(), - ValidationError::AppData(err) => AppDataValidationErrorWrapper(err).into_warp_reply(), - ValidationError::PriceForQuote(err) => err.into_warp_reply(), - ValidationError::MissingFrom => with_status( + ValidationError::Partial(pre) => PartialValidationErrorWrapper(pre).into_response(), + ValidationError::AppData(err) => AppDataValidationErrorWrapper(err).into_response(), + ValidationError::PriceForQuote(err) => { + super::PriceEstimationErrorWrapper(err).into_response() + } + ValidationError::MissingFrom => ( + StatusCode::BAD_REQUEST, error( "MissingFrom", "From address must be specified for on-chain signature", ), - StatusCode::BAD_REQUEST, - ), + ) + .into_response(), ValidationError::AppdataFromMismatch(AppdataFromMismatch { from, app_data_signer, - }) => with_status( + }) => ( + StatusCode::BAD_REQUEST, error( "AppdataFromMismatch", format!( @@ -141,9 +167,10 @@ impl IntoWarpReply for ValidationErrorWrapper { {app_data_signer:?} specified in the app data" ), ), + ) + .into_response(), + ValidationError::WrongOwner(signature::Recovered { message, signer }) => ( StatusCode::BAD_REQUEST, - ), - ValidationError::WrongOwner(signature::Recovered { message, signer }) => with_status( error( "WrongOwner", format!( @@ -151,78 +178,97 @@ impl IntoWarpReply for ValidationErrorWrapper { from address" ), ), + ) + .into_response(), + ValidationError::InvalidEip1271Signature(hash) => ( StatusCode::BAD_REQUEST, - ), - ValidationError::InvalidEip1271Signature(hash) => with_status( error( "InvalidEip1271Signature", format!("signature for computed order hash {hash:?} is not valid"), ), + ) + .into_response(), + ValidationError::InsufficientBalance => ( StatusCode::BAD_REQUEST, - ), - ValidationError::InsufficientBalance => with_status( error( "InsufficientBalance", "order owner must have funds worth at least x in his account", ), + ) + .into_response(), + ValidationError::InsufficientAllowance => ( StatusCode::BAD_REQUEST, - ), - ValidationError::InsufficientAllowance => with_status( error( "InsufficientAllowance", "order owner must give allowance to VaultRelayer", ), + ) + .into_response(), + ValidationError::InvalidSignature => ( StatusCode::BAD_REQUEST, - ), - ValidationError::InvalidSignature => with_status( error("InvalidSignature", "invalid signature"), + ) + .into_response(), + ValidationError::NonZeroFee => ( StatusCode::BAD_REQUEST, - ), - ValidationError::NonZeroFee => with_status( error("NonZeroFee", "Fee must be zero"), - StatusCode::BAD_REQUEST, - ), - ValidationError::SellAmountOverflow => with_status( + ) + .into_response(), + ValidationError::SellAmountOverflow => ( + StatusCode::INTERNAL_SERVER_ERROR, error( "SellAmountOverflow", "Sell amount + fee amount must fit in U256", ), - StatusCode::INTERNAL_SERVER_ERROR, - ), - ValidationError::TransferSimulationFailed => with_status( - error( - "TransferSimulationFailed", - "sell token cannot be transferred", - ), + ) + .into_response(), + ValidationError::TransferSimulationFailed(revert_data) => { + let description = if revert_data.is_empty() { + "sell token cannot be transferred".to_string() + } else { + format!( + "sell token cannot be transferred, token reverted with: 0x{}", + const_hex::encode(&revert_data), + ) + }; + ( + StatusCode::BAD_REQUEST, + error("TransferSimulationFailed", description), + ) + } + .into_response(), + ValidationError::QuoteNotVerified => ( StatusCode::BAD_REQUEST, - ), - ValidationError::QuoteNotVerified => with_status( error( "QuoteNotVerified", "No quote for this trade could be verified to be accurate. Aborting the order \ creation since it will likely not be executed.", ), + ) + .into_response(), + ValidationError::ZeroAmount => ( StatusCode::BAD_REQUEST, - ), - ValidationError::ZeroAmount => with_status( error("ZeroAmount", "Buy or sell amount is zero."), + ) + .into_response(), + ValidationError::IncompatibleSigningScheme => ( StatusCode::BAD_REQUEST, - ), - ValidationError::IncompatibleSigningScheme => with_status( error( "IncompatibleSigningScheme", "Signing scheme is not compatible with order placement method.", ), + ) + .into_response(), + ValidationError::TooManyLimitOrders => ( StatusCode::BAD_REQUEST, - ), - ValidationError::TooManyLimitOrders => with_status( error("TooManyLimitOrders", "Too many limit orders"), + ) + .into_response(), + ValidationError::TooMuchGas => ( StatusCode::BAD_REQUEST, - ), - ValidationError::TooMuchGas => with_status( error("TooMuchGas", "Executing order requires too many gas units"), - StatusCode::BAD_REQUEST, - ), + ) + .into_response(), ValidationError::Other(err) => { tracing::error!(?err, "ValidationErrorWrapper"); @@ -232,14 +278,15 @@ impl IntoWarpReply for ValidationErrorWrapper { } } -impl IntoWarpReply for AddOrderError { - fn into_warp_reply(self) -> ApiReply { +impl IntoResponse for AddOrderError { + fn into_response(self) -> Response { match self { - Self::OrderValidation(err) => ValidationErrorWrapper(err).into_warp_reply(), - Self::DuplicatedOrder => with_status( - error("DuplicatedOrder", "order already exists"), + Self::OrderValidation(err) => ValidationErrorWrapper(err).into_response(), + Self::DuplicatedOrder => ( StatusCode::BAD_REQUEST, - ), + error("DuplicatedOrder", "order already exists"), + ) + .into_response(), Self::Database(err) => { tracing::error!(?err, "AddOrderError"); crate::api::internal_error_reply() @@ -253,38 +300,43 @@ impl IntoWarpReply for AddOrderError { ); crate::api::internal_error_reply() } - AddOrderError::OrderNotFound(err) => err.into_warp_reply(), - AddOrderError::InvalidAppData(err) => reply::with_status( - super::error("InvalidAppData", err.to_string()), + AddOrderError::OrderNotFound(err) => err.into_response(), + AddOrderError::InvalidAppData(err) => ( StatusCode::BAD_REQUEST, - ), - AddOrderError::InvalidReplacement(err) => err.into_warp_reply(), - AddOrderError::MetadataSerializationFailed(err) => reply::with_status( - super::error("MetadataSerializationFailed", err.to_string()), + super::error("InvalidAppData", err.to_string()), + ) + .into_response(), + AddOrderError::InvalidReplacement(err) => err.into_response(), + AddOrderError::MetadataSerializationFailed(err) => ( StatusCode::INTERNAL_SERVER_ERROR, - ), + super::error("MetadataSerializationFailed", err.to_string()), + ) + .into_response(), } } } -impl IntoWarpReply for OrderReplacementError { - fn into_warp_reply(self) -> super::ApiReply { +impl IntoResponse for OrderReplacementError { + fn into_response(self) -> Response { match self { - OrderReplacementError::InvalidSignature => with_status( - super::error("InvalidSignature", "Malformed signature"), + OrderReplacementError::InvalidSignature => ( StatusCode::BAD_REQUEST, - ), - OrderReplacementError::WrongOwner => with_status( - super::error("WrongOwner", "Old and new orders have different signers"), + super::error("InvalidSignature", "Malformed signature"), + ) + .into_response(), + OrderReplacementError::WrongOwner => ( StatusCode::UNAUTHORIZED, - ), - OrderReplacementError::OldOrderActivelyBidOn => with_status( + super::error("WrongOwner", "Old and new orders have different signers"), + ) + .into_response(), + OrderReplacementError::OldOrderActivelyBidOn => ( + StatusCode::BAD_REQUEST, super::error( "OldOrderActivelyBidOn", "The old order is actively beign bid on in recent auctions", ), - StatusCode::BAD_REQUEST, - ), + ) + .into_response(), OrderReplacementError::Other(err) => { tracing::error!(?err, "replace_order"); crate::api::internal_error_reply() @@ -293,70 +345,20 @@ impl IntoWarpReply for OrderReplacementError { } } -pub fn create_order_response( - result: Result<(OrderUid, Option), AddOrderError>, -) -> ApiReply { - match result { - Ok((uid, _)) => with_status(warp::reply::json(&uid), StatusCode::CREATED), - Err(err) => err.into_warp_reply(), - } -} - -pub fn post_order( - orderbook: Arc, -) -> impl Filter + Clone { - create_order_request().and_then(move |order: OrderCreation| { - let orderbook = orderbook.clone(); - async move { - let result = orderbook - .add_order(order.clone()) - .await - .map(|(order_uid, quote_metadata)| { - let quote_id = quote_metadata.as_ref().and_then(|q| q.id); - let quote_solver = quote_metadata.as_ref().map(|q| q.solver); - tracing::debug!(%order_uid, ?quote_id, ?quote_solver, "order created"); - (order_uid, quote_metadata.and_then(|quote| quote.id)) - }) - .inspect_err(|err| { - tracing::debug!(?order, ?err, "error creating order"); - }); - - Result::<_, Infallible>::Ok(create_order_response(result)) - } - }) -} - #[cfg(test)] mod tests { - use { - super::*, - crate::api::response_body, - model::order::{OrderCreation, OrderUid}, - serde_json::json, - warp::{Reply, test::request}, - }; + use {super::*, crate::api::response_body, model::order::OrderUid, serde_json::json}; - #[tokio::test] - async fn create_order_request_ok() { - let filter = create_order_request(); - let order_payload = OrderCreation::default(); - let request = request() - .path("/v1/orders") - .method("POST") - .header("content-type", "application/json") - .json(&order_payload); - let result = request.filter(&filter).await.unwrap(); - assert_eq!(result, order_payload); - } + type Result = std::result::Result<(StatusCode, Json), AddOrderError>; #[tokio::test] async fn create_order_response_created() { let uid = OrderUid([1u8; 56]); - let response = create_order_response(Ok((uid, Some(42)))).into_response(); + let response = Result::Ok((StatusCode::CREATED, Json(uid))).into_response(); assert_eq!(response.status(), StatusCode::CREATED); let body = response_body(response).await; let body: serde_json::Value = serde_json::from_slice(body.as_slice()).unwrap(); - let expected= json!( + let expected = json!( "0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" ); assert_eq!(body, expected); @@ -364,7 +366,7 @@ mod tests { #[tokio::test] async fn create_order_response_duplicate() { - let response = create_order_response(Err(AddOrderError::DuplicatedOrder)).into_response(); + let response = Result::Err(AddOrderError::DuplicatedOrder).into_response(); assert_eq!(response.status(), StatusCode::BAD_REQUEST); let body = response_body(response).await; let body: serde_json::Value = serde_json::from_slice(body.as_slice()).unwrap(); diff --git a/crates/orderbook/src/api/post_quote.rs b/crates/orderbook/src/api/post_quote.rs index 9d087ef787..4981e6cc64 100644 --- a/crates/orderbook/src/api/post_quote.rs +++ b/crates/orderbook/src/api/post_quote.rs @@ -1,80 +1,68 @@ use { super::post_order::{AppDataValidationErrorWrapper, PartialValidationErrorWrapper}, crate::{ - api::{self, ApiReply, IntoWarpReply, convert_json_response, error, rich_error}, - quoter::{OrderQuoteError, QuoteHandler}, + api::{AppState, error, rich_error}, + quoter::OrderQuoteError, + }, + axum::{ + Json, + extract::State, + response::{IntoResponse, Response}, }, - anyhow::Result, model::quote::OrderQuoteRequest, reqwest::StatusCode, shared::order_quoting::CalculateQuoteError, - std::{convert::Infallible, sync::Arc}, - thiserror::Error, - warp::{Filter, Rejection}, + std::sync::Arc, }; -fn post_quote_request() -> impl Filter + Clone { - warp::path!("v1" / "quote") - .and(warp::post()) - .and(api::extract_payload()) +pub async fn post_quote_handler( + State(state): State>, + Json(request): Json, +) -> Response { + state + .quotes + .calculate_quote(&request) + .await + .map(Json) + .inspect_err(|err| tracing::warn!(%err, ?request, "post_quote error")) + .into_response() } -pub fn post_quote( - quotes: Arc, -) -> impl Filter + Clone { - post_quote_request().and_then(move |request: OrderQuoteRequest| { - let quotes = quotes.clone(); - async move { - let result = quotes - .calculate_quote(&request) - .await - .map_err(OrderQuoteErrorWrapper); - if let Err(err) = &result { - tracing::warn!(%err, ?request, "post_quote error"); - } - Result::<_, Infallible>::Ok(convert_json_response(result)) - } - }) -} - -#[derive(Debug, Error)] -#[error(transparent)] -pub struct OrderQuoteErrorWrapper(pub OrderQuoteError); -impl IntoWarpReply for OrderQuoteErrorWrapper { - fn into_warp_reply(self) -> ApiReply { - match self.0 { - OrderQuoteError::AppData(err) => AppDataValidationErrorWrapper(err).into_warp_reply(), - OrderQuoteError::Order(err) => PartialValidationErrorWrapper(err).into_warp_reply(), - OrderQuoteError::CalculateQuote(err) => { - CalculateQuoteErrorWrapper(err).into_warp_reply() - } +impl IntoResponse for OrderQuoteError { + fn into_response(self) -> Response { + match self { + OrderQuoteError::AppData(err) => AppDataValidationErrorWrapper(err).into_response(), + OrderQuoteError::Order(err) => PartialValidationErrorWrapper(err).into_response(), + OrderQuoteError::CalculateQuote(err) => CalculateQuoteErrorWrapper(err).into_response(), } } } pub struct CalculateQuoteErrorWrapper(CalculateQuoteError); -impl IntoWarpReply for CalculateQuoteErrorWrapper { - fn into_warp_reply(self) -> ApiReply { +impl IntoResponse for CalculateQuoteErrorWrapper { + fn into_response(self) -> Response { match self.0 { - CalculateQuoteError::Price { source, .. } => source.into_warp_reply(), - CalculateQuoteError::SellAmountDoesNotCoverFee { fee_amount } => { - warp::reply::with_status( - rich_error( - "SellAmountDoesNotCoverFee", - "The sell amount for the sell order is lower than the fee.", - serde_json::json!({ "fee_amount": fee_amount }), - ), - StatusCode::BAD_REQUEST, - ) + CalculateQuoteError::Price { source, .. } => { + super::PriceEstimationErrorWrapper(source).into_response() } - CalculateQuoteError::QuoteNotVerified => warp::reply::with_status( + CalculateQuoteError::SellAmountDoesNotCoverFee { fee_amount } => ( + StatusCode::BAD_REQUEST, + rich_error( + "SellAmountDoesNotCoverFee", + "The sell amount for the sell order is lower than the fee.", + serde_json::json!({ "fee_amount": fee_amount }), + ), + ) + .into_response(), + CalculateQuoteError::QuoteNotVerified => ( + StatusCode::BAD_REQUEST, error( "QuoteNotVerified", "No quote for this trade could be verified to be accurate. Orders for this \ trade will likely not be executed.", ), - StatusCode::BAD_REQUEST, - ), + ) + .into_response(), CalculateQuoteError::Other(err) => { tracing::error!(?err, "CalculateQuoteErrorWrapper"); crate::api::internal_error_reply() @@ -88,10 +76,11 @@ mod tests { use { super::*, crate::api::response_body, + alloy::primitives::Address, anyhow::anyhow, app_data::AppDataHash, + bigdecimal::BigDecimal, chrono::{TimeZone, Utc}, - ethcontract::H160, model::{ order::{BuyTokenDestination, SellTokenSource}, quote::{ @@ -104,12 +93,11 @@ mod tests { Validity, }, }, - number::nonzero::U256 as NonZeroU256, + number::nonzero::NonZeroU256, reqwest::StatusCode, serde_json::json, shared::order_quoting::CalculateQuoteError, - std::time::Duration, - warp::{Reply, test::request}, + std::{str::FromStr, time::Duration}, }; #[test] @@ -130,9 +118,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), receiver: None, side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { @@ -169,9 +157,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), receiver: None, side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { @@ -203,10 +191,10 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), - receiver: Some(H160([0x04; 20])), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), + receiver: Some(Address::repeat_byte(0x04)), side: OrderQuoteSide::Buy { buy_amount_after_fee: NonZeroU256::try_from(1337).unwrap(), }, @@ -229,9 +217,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(1337).unwrap() @@ -255,9 +243,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(1337).unwrap() @@ -269,32 +257,6 @@ mod tests { ); } - #[tokio::test] - async fn post_quote_request_ok() { - let filter = post_quote_request(); - let request_payload = OrderQuoteRequest::default(); - let request = request() - .path("/v1/quote") - .method("POST") - .header("content-type", "application/json") - .json(&request_payload); - let result = request.filter(&filter).await.unwrap(); - assert_eq!(result, request_payload); - } - - #[tokio::test] - async fn post_quote_request_err() { - let filter = post_quote_request(); - let request_payload = OrderQuoteRequest::default(); - // Path is wrong! - let request = request() - .path("/v1/fee_quote") - .method("POST") - .header("content-type", "application/json") - .json(&request_payload); - assert!(request.filter(&filter).await.is_err()); - } - #[tokio::test] async fn post_quote_response_ok() { let quote = OrderQuote { @@ -306,6 +268,9 @@ mod tests { valid_to: 0, app_data: Default::default(), fee_amount: Default::default(), + gas_amount: BigDecimal::from_str("100000").unwrap(), + gas_price: BigDecimal::from_str("10000000000").unwrap(), + sell_token_price: BigDecimal::from_str("0.0004").unwrap(), kind: Default::default(), partially_fillable: false, sell_token_balance: Default::default(), @@ -314,16 +279,13 @@ mod tests { }; let order_quote_response = OrderQuoteResponse { quote, - from: H160::zero(), + from: Address::ZERO, expiration: Utc.timestamp_millis_opt(0).unwrap(), id: Some(0), verified: false, protocol_fee_bps: Some("2".to_string()), }; - let response = convert_json_response::(Ok( - order_quote_response.clone(), - )) - .into_response(); + let response = (StatusCode::OK, Json(order_quote_response.clone())).into_response(); assert_eq!(response.status(), StatusCode::OK); let body = response_body(response).await; let body: serde_json::Value = serde_json::from_slice(body.as_slice()).unwrap(); @@ -333,12 +295,9 @@ mod tests { #[tokio::test] async fn post_quote_response_err() { - let response = convert_json_response::(Err( - OrderQuoteErrorWrapper(OrderQuoteError::CalculateQuote(CalculateQuoteError::Other( - anyhow!("Uh oh - error"), - ))), - )) - .into_response(); + let response = + OrderQuoteError::CalculateQuote(CalculateQuoteError::Other(anyhow!("Uh oh - error"))) + .into_response(); assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR); let body = response_body(response).await; let body: serde_json::Value = serde_json::from_slice(body.as_slice()).unwrap(); diff --git a/crates/orderbook/src/api/put_app_data.rs b/crates/orderbook/src/api/put_app_data.rs index 4bf9e417d2..a1b5be2876 100644 --- a/crates/orderbook/src/api/put_app_data.rs +++ b/crates/orderbook/src/api/put_app_data.rs @@ -1,69 +1,65 @@ use { - crate::api::{IntoWarpReply, internal_error_reply}, - anyhow::Result, + crate::api::{AppState, internal_error_reply}, app_data::{AppDataDocument, AppDataHash}, - reqwest::StatusCode, - std::{convert::Infallible, sync::Arc}, - warp::{Filter, Rejection, body, reply}, + axum::{ + extract::{Path, State}, + http::StatusCode, + response::{IntoResponse, Json, Response}, + }, + std::sync::Arc, }; -fn request( - max_size: usize, -) -> impl Filter, AppDataDocument), Error = Rejection> + Clone { - let opt = warp::path::param::() - .map(Some) - .or_else(|_| async { Ok::<(Option,), std::convert::Infallible>((None,)) }); - warp::path!("v1" / "app_data" / ..) - .and(opt) - .and(warp::put()) - .and(body::content_length_limit(max_size as _)) - .and(body::json()) +pub async fn put_app_data_without_hash( + State(state): State>, + Json(document): Json, +) -> Response { + state + .app_data + .register(None, document.full_app_data.as_bytes()) + .await + .into_response() } -fn response( - result: Result<(crate::app_data::Registered, AppDataHash), crate::app_data::RegisterError>, -) -> super::ApiReply { - match result { - Ok((registered, hash)) => { - let status = match registered { - crate::app_data::Registered::New => StatusCode::CREATED, - crate::app_data::Registered::AlreadyExisted => StatusCode::OK, - }; - reply::with_status(reply::json(&hash), status) - } - Err(err) => err.into_warp_reply(), - } +pub async fn put_app_data_with_hash( + State(state): State>, + Path(hash): Path, + Json(document): Json, +) -> Response { + state + .app_data + .register(Some(hash), document.full_app_data.as_bytes()) + .await + .into_response() } -pub fn filter( - registry: Arc, -) -> impl Filter + Clone { - request(registry.size_limit()).and_then(move |hash, document: AppDataDocument| { - let registry = registry.clone(); - async move { - let result = registry - .register(hash, document.full_app_data.as_bytes()) - .await; - Result::<_, Infallible>::Ok(response(result)) - } - }) +impl IntoResponse for crate::app_data::Register { + fn into_response(self) -> Response { + let status = match self.status { + crate::app_data::RegistrationStatus::New => StatusCode::CREATED, + crate::app_data::RegistrationStatus::AlreadyExisted => StatusCode::OK, + }; + (status, Json(self.hash)).into_response() + } } -impl IntoWarpReply for crate::app_data::RegisterError { - fn into_warp_reply(self) -> super::ApiReply { +impl IntoResponse for crate::app_data::RegisterError { + fn into_response(self) -> Response { match self { - Self::Invalid(err) => reply::with_status( + Self::Invalid(err) => ( + StatusCode::BAD_REQUEST, super::error("AppDataInvalid", err.to_string()), + ) + .into_response(), + err @ Self::HashMismatch { .. } => ( StatusCode::BAD_REQUEST, - ), - err @ Self::HashMismatch { .. } => reply::with_status( super::error("AppDataHashMismatch", err.to_string()), + ) + .into_response(), + err @ Self::DataMismatch { .. } => ( StatusCode::BAD_REQUEST, - ), - err @ Self::DataMismatch { .. } => reply::with_status( super::error("AppDataMismatch", err.to_string()), - StatusCode::BAD_REQUEST, - ), + ) + .into_response(), Self::Other(err) => { tracing::error!(?err, "app_data::SaveError::Other"); internal_error_reply() diff --git a/crates/orderbook/src/api/ready.rs b/crates/orderbook/src/api/ready.rs new file mode 100644 index 0000000000..e5d4790b27 --- /dev/null +++ b/crates/orderbook/src/api/ready.rs @@ -0,0 +1,19 @@ +use { + crate::api::AppState, + axum::{ + extract::State, + http::StatusCode, + response::{IntoResponse, Response}, + }, + std::sync::Arc, +}; + +pub async fn get_ready_handler(State(state): State>) -> Response { + match state.database_write.last_used_auction_id().await { + Ok(_maybe_id) => StatusCode::OK.into_response(), + Err(err) => { + tracing::error!(?err, "/api/v1/ready"); + crate::api::internal_error_reply() + } + } +} diff --git a/crates/orderbook/src/api/version.rs b/crates/orderbook/src/api/version.rs index 04b5c698c5..20489608b7 100644 --- a/crates/orderbook/src/api/version.rs +++ b/crates/orderbook/src/api/version.rs @@ -1,16 +1,3 @@ -use { - reqwest::StatusCode, - std::convert::Infallible, - warp::{Filter, Rejection, Reply, reply::with_status}, -}; - -pub fn version() -> impl Filter,), Error = Rejection> + Clone { - warp::path!("v1" / "version") - .and(warp::get()) - .and_then(|| async { - Result::<_, Infallible>::Ok(Box::new(with_status( - env!("VERGEN_GIT_DESCRIBE"), - StatusCode::OK, - )) as Box) - }) +pub async fn version_handler() -> &'static str { + env!("VERGEN_GIT_DESCRIBE") } diff --git a/crates/orderbook/src/app_data.rs b/crates/orderbook/src/app_data.rs index 9844df4bac..bd6326f174 100644 --- a/crates/orderbook/src/app_data.rs +++ b/crates/orderbook/src/app_data.rs @@ -43,7 +43,7 @@ impl Registry { &self, hash: Option, document: &[u8], - ) -> Result<(Registered, AppDataHash), RegisterError> { + ) -> Result { let validated = self .validator .validate(document) @@ -60,8 +60,14 @@ impl Registry { .insert_full_app_data(&validated.hash, &validated.document) .await { - Ok(()) => Ok((Registered::New, validated.hash)), - Err(InsertError::Duplicate) => Ok((Registered::AlreadyExisted, validated.hash)), + Ok(()) => Ok(Register { + status: RegistrationStatus::New, + hash: validated.hash, + }), + Err(InsertError::Duplicate) => Ok(Register { + status: RegistrationStatus::AlreadyExisted, + hash: validated.hash, + }), Err(InsertError::Mismatch(existing)) => Err(RegisterError::DataMismatch { existing }), Err(InsertError::Other(err)) => Err(RegisterError::Other(err)), } @@ -95,13 +101,18 @@ impl Registry { } #[derive(Debug)] -pub enum Registered { +pub enum RegistrationStatus { /// The app data was newly added to the registry. New, /// An identical app data was already registered. AlreadyExisted, } +pub struct Register { + pub status: RegistrationStatus, + pub hash: AppDataHash, +} + #[derive(Debug, thiserror::Error)] pub enum RegisterError { #[error("appData is invalid: {0}")] diff --git a/crates/orderbook/src/arguments.rs b/crates/orderbook/src/arguments.rs index e47ba3eb6d..868697a4cd 100644 --- a/crates/orderbook/src/arguments.rs +++ b/crates/orderbook/src/arguments.rs @@ -1,293 +1,17 @@ -use { - alloy::primitives::Address, - chrono::{DateTime, Utc}, - reqwest::Url, - shared::{ - arguments::{display_option, display_secret_option}, - bad_token::token_owner_finder, - http_client, - price_estimation::{self, NativePriceEstimators}, - }, - std::{net::SocketAddr, num::NonZeroUsize, str::FromStr, time::Duration}, -}; +use std::path::PathBuf; #[derive(clap::Parser)] pub struct Arguments { - #[clap(flatten)] - pub shared: shared::arguments::Arguments, - - #[clap(flatten)] - pub order_quoting: shared::arguments::OrderQuotingArguments, - - #[clap(flatten)] - pub http_client: http_client::Arguments, - - #[clap(flatten)] - pub token_owner_finder: token_owner_finder::Arguments, - - #[clap(flatten)] - pub price_estimation: price_estimation::Arguments, - - /// A tracing Ethereum node URL to connect to, allowing a separate node URL - /// to be used exclusively for tracing calls. - #[clap(long, env)] - pub tracing_node_url: Option, - - #[clap(long, env, default_value = "0.0.0.0:8080")] - pub bind_address: SocketAddr, - - /// Url of the Postgres database. By default connects to locally running - /// postgres. - #[clap(long, env, default_value = "postgresql://")] - pub db_write_url: Url, - - /// Url of the Postgres database replica. By default it's the same as - /// db_write_url - #[clap(long, env)] - pub db_read_url: Option, - - /// The minimum amount of time in seconds an order has to be valid for. - #[clap( - long, - env, - default_value = "1m", - value_parser = humantime::parse_duration, - )] - pub min_order_validity_period: Duration, - - /// The maximum amount of time in seconds an order can be valid for. - /// Defaults to 3 hours. This restriction does not apply to liquidity - /// owner orders or presign orders. - #[clap( - long, - env, - default_value = "3h", - value_parser = humantime::parse_duration, - )] - pub max_order_validity_period: Duration, - - /// The maximum amount of time in seconds a limit order can be valid for. - /// Defaults to 1 year. - #[clap( - long, - env, - default_value = "1y", - value_parser = humantime::parse_duration, - )] - pub max_limit_order_validity_period: Duration, - - /// List of token addresses to be ignored throughout service - #[clap(long, env, use_value_delimiter = true)] - pub unsupported_tokens: Vec
, - - /// List of account addresses to be denied from order creation - #[clap(long, env, use_value_delimiter = true)] - pub banned_users: Vec
, - - /// Maximum number of entries to keep in the banned users cache. - #[clap(long, env, default_value = "100")] - pub banned_users_max_cache_size: NonZeroUsize, - - /// Which estimators to use to estimate token prices in terms of the chain's - /// native token. - #[clap(long, env)] - pub native_price_estimators: NativePriceEstimators, - - /// How many successful price estimates for each order will cause a fast - /// or native price estimation to return its result early. - /// The bigger the value the more the fast price estimation performs like - /// the optimal price estimation. - /// It's possible to pass values greater than the total number of enabled - /// estimators but that will not have any further effect. - #[clap(long, env, default_value = "2")] - pub fast_price_estimation_results_required: NonZeroUsize, - - /// List of token addresses that should be allowed regardless of whether the - /// bad token detector thinks they are bad. Base tokens are - /// automatically allowed. - #[clap(long, env, use_value_delimiter = true)] - pub allowed_tokens: Vec
, - - /// Skip EIP-1271 order signature validation on creation. - #[clap(long, env, action = clap::ArgAction::Set, default_value = "false")] - pub eip1271_skip_creation_validation: bool, - - /// If solvable orders haven't been successfully updated in this many blocks - /// attempting to get them errors and our liveness check fails. - #[clap(long, env, default_value = "24")] - pub solvable_orders_max_update_age_blocks: u64, - - /// Max number of limit orders per user. - #[clap(long, env, default_value = "10")] - pub max_limit_orders_per_user: u64, - - /// If set, the orderbook will use this IPFS gateway to fetch full app data - /// for orders that only specify the contract app data hash. - #[clap(long, env)] - pub ipfs_gateway: Option, - - /// Authentication key for Pinata IPFS gateway. + /// Path to the TOML configuration file. #[clap(long, env)] - pub ipfs_pinata_auth: Option, - - /// Set the maximum size in bytes of order app data. - #[clap(long, env, default_value = "8192")] - pub app_data_size_limit: usize, - - /// The maximum gas amount a single order can use for getting settled. - #[clap(long, env, default_value = "8000000")] - pub max_gas_per_order: u64, - - /// The number of past solver competitions to look back at to determine - /// whether an order is actively being bid on. - #[clap(long, env, default_value = "5")] - pub active_order_competition_threshold: u32, - - #[clap(flatten)] - pub volume_fee_config: Option, -} - -/// Volume-based protocol fee factor to be applied to quotes. -#[derive(clap::Parser, Debug, Clone)] -pub struct VolumeFeeConfig { - /// This is a decimal value (e.g., 0.0002 for 0.02% or 2 basis points). - /// The fee is applied to the surplus token (buy token for sell orders, - /// sell token for buy orders). - #[clap( - id = "volume_fee_factor", - long = "volume-fee-factor", - env = "VOLUME_FEE_FACTOR" - )] - pub factor: Option, - - /// The timestamp from which the volume fee becomes effective. - #[clap( - long = "volume-fee-effective-timestamp", - env = "VOLUME_FEE_EFFECTIVE_TIMESTAMP" - )] - pub effective_from_timestamp: Option>, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct FeeFactor(f64); - -impl FeeFactor { - /// Number of basis points that make up 100%. - pub const MAX_BPS: u32 = 10_000; - - /// Converts the fee factor to basis points (BPS). - /// For example, 0.0002 -> 2 BPS - pub fn to_bps(&self) -> u64 { - (self.0 * f64::from(Self::MAX_BPS)).round() as u64 - } -} - -/// TryFrom implementation for the cases we want to enforce the constraint [0, -/// 1) -impl TryFrom for FeeFactor { - type Error = anyhow::Error; - - fn try_from(value: f64) -> Result { - anyhow::ensure!( - (0.0..1.0).contains(&value), - "Factor must be in the range [0, 1)" - ); - Ok(FeeFactor(value)) - } -} - -impl FromStr for FeeFactor { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - s.parse::().map(FeeFactor::try_from)? - } + pub config: PathBuf, } impl std::fmt::Display for Arguments { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let Arguments { - shared, - order_quoting, - http_client, - token_owner_finder, - price_estimation, - tracing_node_url, - bind_address, - min_order_validity_period, - max_order_validity_period, - max_limit_order_validity_period, - unsupported_tokens, - banned_users, - banned_users_max_cache_size, - allowed_tokens, - eip1271_skip_creation_validation, - solvable_orders_max_update_age_blocks, - native_price_estimators, - fast_price_estimation_results_required, - max_limit_orders_per_user, - ipfs_gateway, - ipfs_pinata_auth, - app_data_size_limit, - db_write_url: db_url, - db_read_url, - max_gas_per_order, - active_order_competition_threshold, - volume_fee_config, - } = self; + let Arguments { config } = self; - write!(f, "{shared}")?; - write!(f, "{order_quoting}")?; - write!(f, "{http_client}")?; - write!(f, "{token_owner_finder}")?; - write!(f, "{price_estimation}")?; - display_option(f, "tracing_node_url", tracing_node_url)?; - writeln!(f, "bind_address: {bind_address}")?; - let _intentionally_ignored = db_url; - writeln!(f, "db_url: SECRET")?; - display_secret_option(f, "db_read_url", db_read_url.as_ref())?; - writeln!( - f, - "min_order_validity_period: {min_order_validity_period:?}" - )?; - writeln!( - f, - "max_order_validity_period: {max_order_validity_period:?}" - )?; - writeln!( - f, - "max_limit_order_validity_period: {max_limit_order_validity_period:?}" - )?; - writeln!(f, "unsupported_tokens: {unsupported_tokens:?}")?; - writeln!(f, "banned_users: {banned_users:?}")?; - writeln!( - f, - "banned_users_max_cache_size: {banned_users_max_cache_size:?}" - )?; - writeln!(f, "allowed_tokens: {allowed_tokens:?}")?; - writeln!( - f, - "eip1271_skip_creation_validation: {eip1271_skip_creation_validation}" - )?; - writeln!( - f, - "solvable_orders_max_update_age_blocks: {solvable_orders_max_update_age_blocks}", - )?; - writeln!(f, "native_price_estimators: {native_price_estimators}")?; - writeln!( - f, - "fast_price_estimation_results_required: {fast_price_estimation_results_required}" - )?; - writeln!(f, "max_limit_orders_per_user: {max_limit_orders_per_user}")?; - writeln!(f, "ipfs_gateway: {ipfs_gateway:?}")?; - display_secret_option(f, "ipfs_pinata_auth", ipfs_pinata_auth.as_ref())?; - writeln!(f, "app_data_size_limit: {app_data_size_limit}")?; - writeln!(f, "max_gas_per_order: {max_gas_per_order}")?; - writeln!( - f, - "active_order_competition_threshold: {active_order_competition_threshold}" - )?; - writeln!(f, "volume_fee_config: {volume_fee_config:?}")?; + writeln!(f, "config: {}", config.display())?; Ok(()) } diff --git a/crates/orderbook/src/database/auctions.rs b/crates/orderbook/src/database/auctions.rs index 99445f95c2..3028d92054 100644 --- a/crates/orderbook/src/database/auctions.rs +++ b/crates/orderbook/src/database/auctions.rs @@ -1,4 +1,7 @@ -use {crate::dto, anyhow::Result}; +use { + crate::dto, + anyhow::{Context, Result}, +}; impl super::Postgres { pub async fn most_recent_auction(&self) -> Result> { @@ -16,4 +19,16 @@ impl super::Postgres { let auction = dto::AuctionWithId { id, auction }; Ok(Some(auction)) } + + pub async fn last_used_auction_id(&self) -> Result> { + let _timer = super::Metrics::get() + .database_queries + .with_label_values(&["last_used_auction_id"]) + .start_timer(); + + let mut ex = self.pool.acquire().await?; + database::auction::last_used_auction_id(&mut ex) + .await + .context("could not fetch last used auction_id") + } } diff --git a/crates/orderbook/src/database/debug_report.rs b/crates/orderbook/src/database/debug_report.rs new file mode 100644 index 0000000000..797bedf275 --- /dev/null +++ b/crates/orderbook/src/database/debug_report.rs @@ -0,0 +1,238 @@ +use { + super::Postgres, + crate::database::orders::OrderStoring, + alloy::primitives::{Address, B256}, + anyhow::{Context, Result}, + database::{ + auction::{self, Auction as DbAuction, AuctionId}, + byte_array::ByteArray, + fee_policies::{self, FeePolicy as DbFeePolicy, FeePolicyKind as DbFeePolicyKind}, + order_events, + order_execution::{self, OrderExecution as DbOrderExecution}, + settlement_executions::{self, SettlementExecution as DbSettlementExecution}, + solver_competition_v2::{self, OrderProposedSolution as DbProposedSolution}, + trades::{self, TradesQueryRow as DbTradesQueryRow}, + }, + model::{ + debug_report::{ + Auction, + DebugReport, + Event, + Execution, + FeePolicy, + FeePolicyKind, + ProposedSolution, + ProtocolFee, + SettlementAttempt, + Trade, + }, + order::OrderUid, + }, + std::collections::HashMap, +}; + +impl Postgres { + pub async fn fetch_debug_report(&self, uid: &OrderUid) -> Result> { + let _timer = super::Metrics::get() + .database_queries + .with_label_values(&["fetch_debug_report"]) + .start_timer(); + + let db_uid = ByteArray(uid.0); + let order = match self.single_order(uid).await? { + Some(order) => order, + None => return Ok(None), + }; + + let mut conn = self.pool.acquire().await?; + + let events: Vec = order_events::get_all(&mut conn, &db_uid) + .await? + .into_iter() + .map(|e| Event { + label: format!("{:?}", e.label).to_lowercase(), + timestamp: e.timestamp, + reason: e.reason.map(|r| r.to_string()), + }) + .collect(); + + let proposed_solutions = + solver_competition_v2::find_solutions_for_order(&mut conn, &db_uid).await?; + let executions = order_execution::read_by_order_uid(&mut conn, &db_uid).await?; + let trades: Vec = trades::trades(&mut conn, None, Some(&db_uid), 0, 100) + .into_inner() + .await + .context("failed to fetch trades")?; + + let auction_ids: Vec = + auction::fetch_auction_ids_by_order_uid(&mut conn, &db_uid).await?; + + let db_auctions = auction::fetch_multiple(&mut conn, &auction_ids).await?; + let settlement_execs = + settlement_executions::read_by_auction_ids(&mut conn, &auction_ids).await?; + let fee_policies = fee_policies::fetch_by_order_uid(&mut conn, &db_uid).await?; + + let sell_token = order.data.sell_token; + let buy_token = order.data.buy_token; + let auctions = build_auctions( + db_auctions, + proposed_solutions, + executions, + settlement_execs, + fee_policies, + sell_token, + buy_token, + ); + + Ok(Some(DebugReport { + order_uid: *uid, + order, + events, + auctions, + trades: trades.into_iter().map(convert_trade).collect(), + })) + } +} + +fn build_auctions( + db_auctions: Vec, + db_solutions: Vec, + db_executions: Vec, + db_settlements: Vec, + db_fees: Vec, + sell_token: Address, + buy_token: Address, +) -> Vec { + let sell = ByteArray(sell_token.0.0); + let buy = ByteArray(buy_token.0.0); + + let mut solutions_by_auction: HashMap> = HashMap::new(); + for s in db_solutions { + solutions_by_auction + .entry(s.auction_id) + .or_default() + .push(convert_solution(s)); + } + + let mut executions_by_auction: HashMap> = HashMap::new(); + for e in db_executions { + executions_by_auction + .entry(e.auction_id) + .or_default() + .push(convert_execution(e)); + } + + let mut settlements_by_auction: HashMap> = HashMap::new(); + for s in db_settlements { + settlements_by_auction + .entry(s.auction_id) + .or_default() + .push(convert_settlement(s)); + } + + let mut fees_by_auction: HashMap> = HashMap::new(); + for f in db_fees { + fees_by_auction + .entry(f.auction_id) + .or_default() + .push(convert_fee_policy(f)); + } + + let mut auctions: Vec = db_auctions + .into_iter() + .map(|a| { + let native_prices = a + .price_tokens + .iter() + .zip(&a.price_values) + .filter(|(token, _)| **token == sell || **token == buy) + .map(|(token, price)| (Address::from(token.0), price.clone())) + .collect(); + let id = a.id; + Auction { + id, + block: a.block, + deadline: a.deadline, + native_prices, + proposed_solutions: solutions_by_auction.remove(&id).unwrap_or_default(), + executions: executions_by_auction.remove(&id).unwrap_or_default(), + settlement_attempts: settlements_by_auction.remove(&id).unwrap_or_default(), + fee_policies: fees_by_auction.remove(&id).unwrap_or_default(), + } + }) + .collect(); + + auctions.sort_by_key(|a| a.id); + auctions +} + +fn convert_solution(s: DbProposedSolution) -> ProposedSolution { + ProposedSolution { + solution_uid: s.solution_uid, + ranking: s.solution_uid + 1, + solver: Address::from(s.solver.0), + is_winner: s.is_winner, + filtered_out: s.filtered_out, + score: s.score, + executed_sell: s.executed_sell, + executed_buy: s.executed_buy, + } +} + +fn convert_execution(e: DbOrderExecution) -> Execution { + let protocol_fees = e + .protocol_fee_tokens + .iter() + .zip(e.protocol_fee_amounts.iter()) + .map(|(token, amount)| ProtocolFee { + token: Address::from(token.0), + amount: amount.clone(), + }) + .collect(); + Execution { + executed_fee: e.executed_fee, + executed_fee_token: Address::from(e.executed_fee_token.0), + block_number: e.block_number, + protocol_fees, + } +} + +fn convert_trade(t: DbTradesQueryRow) -> Trade { + Trade { + block_number: t.block_number, + log_index: t.log_index, + buy_amount: t.buy_amount, + sell_amount: t.sell_amount, + sell_amount_before_fees: t.sell_amount_before_fees, + tx_hash: t.tx_hash.map(|h| B256::from(h.0)), + auction_id: t.auction_id, + } +} + +fn convert_settlement(s: DbSettlementExecution) -> SettlementAttempt { + SettlementAttempt { + solver: Address::from(s.solver.0), + solution_uid: s.solution_uid, + start_timestamp: s.start_timestamp, + end_timestamp: s.end_timestamp, + start_block: s.start_block, + end_block: s.end_block, + deadline_block: s.deadline_block, + outcome: s.outcome, + } +} + +fn convert_fee_policy(f: DbFeePolicy) -> FeePolicy { + FeePolicy { + kind: match f.kind { + DbFeePolicyKind::Surplus => FeePolicyKind::Surplus, + DbFeePolicyKind::Volume => FeePolicyKind::Volume, + DbFeePolicyKind::PriceImprovement => FeePolicyKind::PriceImprovement, + }, + surplus_factor: f.surplus_factor, + surplus_max_volume_factor: f.surplus_max_volume_factor, + volume_factor: f.volume_factor, + price_improvement_factor: f.price_improvement_factor, + price_improvement_max_volume_factor: f.price_improvement_max_volume_factor, + } +} diff --git a/crates/orderbook/src/database/fee_policies.rs b/crates/orderbook/src/database/fee_policies.rs index 2991e0fc8f..7da7fa40bd 100644 --- a/crates/orderbook/src/database/fee_policies.rs +++ b/crates/orderbook/src/database/fee_policies.rs @@ -8,7 +8,7 @@ use { database::{OrderUid, auction::AuctionId}, model::fee_policy::{ExecutedProtocolFee, FeePolicy, Quote}, num::BigRational, - number::conversions::alloy::{big_decimal_to_u256, big_rational_to_u256}, + number::conversions::{big_decimal_to_u256, big_rational_to_u256}, std::collections::HashMap, }; diff --git a/crates/orderbook/src/database/mod.rs b/crates/orderbook/src/database/mod.rs index fa6f1092df..b42bacdc11 100644 --- a/crates/orderbook/src/database/mod.rs +++ b/crates/orderbook/src/database/mod.rs @@ -1,6 +1,7 @@ pub mod app_data; pub mod auction_prices; pub mod auctions; +pub mod debug_report; mod fee_policies; pub mod orders; pub mod quotes; @@ -14,26 +15,72 @@ use { anyhow::Result, database::byte_array::ByteArray, model::order::Order, - sqlx::{PgConnection, PgPool}, + shared::arguments::DB_MAX_CONNECTIONS_DEFAULT, + sqlx::{Executor, PgConnection, PgPool, postgres::PgPoolOptions}, + std::time::Duration, }; // TODO: There is remaining optimization potential by implementing sqlx encoding // and decoding for U256 directly instead of going through BigDecimal. This is // not very important as this is fast enough anyway. +#[derive(Debug, Clone)] +pub struct Config { + pub max_pool_size: u32, + /// Maps directly to Postgres' `statement_timeout` parameter, applied on a + /// per-connection basis, but *only* if the pool was created using + /// [`Postgres::try_new_with_timeout`]. + pub statement_timeout: Duration, +} + +impl Default for Config { + fn default() -> Self { + Self { + // Match SQLx default pool size + max_pool_size: DB_MAX_CONNECTIONS_DEFAULT.get(), + statement_timeout: Duration::from_secs(30), + } + } +} + // The pool uses an Arc internally. #[derive(Clone)] pub struct Postgres { pub pool: PgPool, + pub config: Config, } // The implementation is split up into several modules which contain more public // methods. impl Postgres { - pub fn try_new(uri: &str) -> Result { + pub fn try_new(uri: &str, config: Config) -> Result { Ok(Self { - pool: PgPool::connect_lazy(uri)?, + pool: PgPoolOptions::new() + .max_connections(config.max_pool_size) + .connect_lazy(uri)?, + config, + }) + } + + /// Creates a Postgres connection pool, but applies the [`Config`]'s + /// `statement_timeout` to all queries. + pub fn try_new_with_timeout(uri: &str, config: Config) -> Result { + let read_query_timeout = config.statement_timeout; + + Ok(Self { + pool: PgPoolOptions::new() + .max_connections(config.max_pool_size) + .after_connect(move |conn, _meta| { + Box::pin(async move { + let timeout_ms = read_query_timeout.as_millis(); + conn.execute(format!("SET statement_timeout = {timeout_ms}").as_str()) + .await?; + Ok(()) + }) + }) + .connect_lazy(uri)?, + config, }) } @@ -67,3 +114,30 @@ impl Metrics { Metrics::instance(observe::metrics::get_storage_registry()).unwrap() } } + +#[cfg(test)] +mod tests { + use {super::*, sqlx::Executor}; + + #[tokio::test] + #[ignore] + async fn postgres_statement_timeout_cancels_slow_query() { + let config = Config { + statement_timeout: Duration::from_millis(100), + ..Default::default() + }; + let db = Postgres::try_new_with_timeout("postgresql://", config).unwrap(); + let mut conn = db.pool.acquire().await.unwrap(); + + // A fast query should succeed. + conn.execute("SELECT 1").await.unwrap(); + + // A query exceeding the timeout should fail. + let err = conn + .execute("SELECT pg_sleep(5)") + .await + .expect_err("should have timed out"); + let db_err = err.as_database_error().expect("should be a database error"); + assert_eq!(db_err.code().as_deref(), Some("57014")); // query_canceled + } +} diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index bbc424b2b6..081336e3ed 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -1,7 +1,7 @@ use { super::Postgres, crate::dto::TokenMetadata, - alloy::primitives::{Address, B256}, + alloy::primitives::{Address, B256, map::HashSet}, anyhow::{Context as _, Result}, app_data::AppDataHash, async_trait::async_trait, @@ -12,9 +12,7 @@ use { order_events::{OrderEvent, OrderEventLabel, insert_order_event}, orders::{self, FullOrder, OrderKind as DbOrderKind}, }, - ethcontract::H256, - ethrpc::alloy::conversions::IntoLegacy, - futures::{FutureExt, StreamExt, stream::TryStreamExt}, + futures::{FutureExt, StreamExt, stream::TryStreamExt, try_join}, model::{ order::{ EthflowData, @@ -31,16 +29,7 @@ use { time::now_in_epoch_seconds, }, num::Zero, - number::conversions::{ - alloy::{ - big_decimal_to_u256 as alloy_big_decimal_to_u256, - u256_to_big_decimal as alloy_u256_to_big_decimal, - }, - big_decimal_to_big_uint, - big_decimal_to_u256, - u256_to_big_decimal, - }, - primitive_types::{H160, U256}, + number::conversions::{big_decimal_to_big_uint, big_decimal_to_u256, u256_to_big_decimal}, shared::{ db_order_conversions::{ buy_token_destination_from, @@ -86,6 +75,7 @@ pub trait OrderStoring: Send + Sync { ) -> Result>; async fn latest_order_event(&self, order_uid: &OrderUid) -> Result>; async fn single_order(&self, uid: &OrderUid) -> Result>; + async fn many_orders(&self, uids: &[OrderUid]) -> Result)>>; } #[derive(Debug)] @@ -116,6 +106,7 @@ async fn cancel_order( order_uid: uid, timestamp: now, label: OrderEventLabel::Cancelled, + reason: None, }, ) .await?; @@ -131,6 +122,7 @@ async fn insert_order(order: &Order, ex: &mut PgConnection) -> Result<(), Insert order_uid, timestamp: Utc::now(), label: OrderEventLabel::Created, + reason: None, }, ) .await?; @@ -153,7 +145,7 @@ async fn insert_order(order: &Order, ex: &mut PgConnection) -> Result<(), Insert .map( |(index, (interaction, execution))| database::orders::Interaction { target: ByteArray(*interaction.target.0), - value: u256_to_big_decimal(&interaction.value.into_legacy()), + value: u256_to_big_decimal(&interaction.value), data: interaction.call_data.clone(), index: index .try_into() @@ -170,11 +162,11 @@ async fn insert_order(order: &Order, ex: &mut PgConnection) -> Result<(), Insert sell_token: ByteArray(order.data.sell_token.0.0), buy_token: ByteArray(order.data.buy_token.0.0), receiver: order.data.receiver.map(|addr| ByteArray(addr.0.0)), - sell_amount: alloy_u256_to_big_decimal(&order.data.sell_amount), - buy_amount: alloy_u256_to_big_decimal(&order.data.buy_amount), + sell_amount: u256_to_big_decimal(&order.data.sell_amount), + buy_amount: u256_to_big_decimal(&order.data.buy_amount), valid_to: order.data.valid_to as i64, app_data: ByteArray(order.data.app_data.0), - fee_amount: alloy_u256_to_big_decimal(&order.data.fee_amount), + fee_amount: u256_to_big_decimal(&order.data.fee_amount), kind: order_kind_into(order.data.kind), class: order_class_into(&order.metadata.class), partially_fillable: order.data.partially_fillable, @@ -208,7 +200,7 @@ async fn insert_order(order: &Order, ex: &mut PgConnection) -> Result<(), Insert sell_token_price: quote.sell_token_price.to_f64().unwrap(), sell_amount: u256_to_big_decimal("e.sell_amount), buy_amount: u256_to_big_decimal("e.buy_amount), - solver: ByteArray(quote.solver.0), + solver: ByteArray(quote.solver.0.0), verified: quote.verified, metadata: quote.metadata.clone(), }; @@ -228,12 +220,11 @@ impl OrderStoring for Postgres { .with_label_values(&["insert_order"]) .start_timer(); - let order = order.clone(); let mut connection = self.pool.acquire().await?; let mut ex = connection.begin().await?; - insert_order(&order, &mut ex).await?; - Self::insert_order_app_data(&order, &mut ex).await?; + insert_order(order, &mut ex).await?; + Self::insert_order_app_data(order, &mut ex).await?; ex.commit().await?; Ok(()) @@ -324,6 +315,50 @@ impl OrderStoring for Postgres { .transpose() } + async fn many_orders(&self, uids: &[OrderUid]) -> Result)>> { + let _timer = super::Metrics::get() + .database_queries + .with_label_values(&["many_orders"]) + .start_timer(); + // Deduplicate order UIDs + let uids = uids + .iter() + .map(|uid| ByteArray(uid.0)) + .collect::>() + .into_iter() + .collect::>(); + let mut ex_orders = self.pool.acquire().await?; + let mut ex_jit_orders = self.pool.acquire().await?; + + let (orders, jit_orders) = try_join!( + database::orders::many_full_orders_with_quotes(&mut ex_orders, &uids), + // JIT orders are fetched without quotes as they are created by solvers at settlement + // time + database::jit_orders::get_many_by_uid(&mut ex_jit_orders, &uids) + )?; + Ok(orders + .into_iter() + .map(|order| { + let (order, quote) = order.into_order_and_quote(); + let uid = OrderUid(order.uid.0); + let result = + full_order_with_quote_into_model_order(order, quote.as_ref()).map_err(|err| { + tracing::warn!(?err, "Error converting into model order"); + err.context("Error converting into model order") + }); + (uid, result) + }) + .chain(jit_orders.into_iter().map(|order| { + let uid = OrderUid(order.uid.0); + let result = full_order_into_model_order(order).map_err(|err| { + tracing::warn!(?err, "Error converting Jit order into model order"); + err.context("Error converting Jit order into model order") + }); + (uid, result) + })) + .collect()) + } + async fn orders_for_tx(&self, tx_hash: &B256) -> Result> { tokio::try_join!( self.user_order_for_tx(tx_hash), @@ -408,7 +443,7 @@ impl Postgres { } pub async fn token_metadata(&self, token: &Address) -> Result { - let (first_trade_block, native_price): (Option, Option) = tokio::try_join!( + let (first_trade_block, native_price): (Option, Option) = tokio::try_join!( self.execute_instrumented("token_first_trade_block", async { let mut ex = self.pool.acquire().await?; database::trades::token_first_trade_block(&mut ex, ByteArray(token.0.0)) @@ -455,7 +490,7 @@ impl Postgres { #[async_trait] impl LimitOrderCounting for Postgres { - async fn count(&self, owner: H160) -> Result { + async fn count(&self, owner: Address) -> Result { let _timer = super::Metrics::get() .database_queries .with_label_values(&["count_limit_orders_by_owner"]) @@ -465,7 +500,7 @@ impl LimitOrderCounting for Postgres { Ok(database::orders::user_orders_with_quote( &mut ex, now_in_epoch_seconds().into(), - &ByteArray(owner.0), + &ByteArray(owner.0.0), ) .await? .into_iter() @@ -474,7 +509,7 @@ impl LimitOrderCounting for Postgres { &Amounts { sell: big_decimal_to_u256(&order_with_quote.order_sell_amount).unwrap(), buy: big_decimal_to_u256(&order_with_quote.order_buy_amount).unwrap(), - fee: 0.into(), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: big_decimal_to_u256(&order_with_quote.quote_sell_amount).unwrap(), @@ -538,7 +573,7 @@ fn full_order_with_quote_into_model_order( let ethflow_data = if let Some((refund_tx, user_valid_to)) = order.ethflow_data { Some(EthflowData { user_valid_to, - refund_tx_hash: refund_tx.map(|hash| H256(hash.0)), + refund_tx_hash: refund_tx.map(|hash| B256::new(hash.0)), }) } else { None @@ -595,14 +630,11 @@ fn full_order_with_quote_into_model_order( sell_token: Address::new(order.sell_token.0), buy_token: Address::new(order.buy_token.0), receiver: order.receiver.map(|address| Address::new(address.0)), - sell_amount: alloy_big_decimal_to_u256(&order.sell_amount) - .context("sell_amount is not U256")?, - buy_amount: alloy_big_decimal_to_u256(&order.buy_amount) - .context("buy_amount is not U256")?, + sell_amount: big_decimal_to_u256(&order.sell_amount).context("sell_amount is not U256")?, + buy_amount: big_decimal_to_u256(&order.buy_amount).context("buy_amount is not U256")?, valid_to: order.valid_to.try_into().context("valid_to is not u32")?, app_data: AppDataHash(order.app_data.0), - fee_amount: alloy_big_decimal_to_u256(&order.fee_amount) - .context("fee_amount is not U256")?, + fee_amount: big_decimal_to_u256(&order.fee_amount).context("fee_amount is not U256")?, kind: order_kind_from(order.kind), partially_fillable: order.partially_fillable, sell_token_balance: sell_token_source_from(order.sell_token_balance), @@ -659,7 +691,6 @@ mod tests { order::{Order, OrderData, OrderMetadata, OrderStatus, OrderUid}, signature::{Signature, SigningScheme}, }, - primitive_types::U256, shared::order_quoting::{Quote, QuoteData, QuoteMetadataV1}, std::sync::atomic::{AtomicI64, Ordering}, }; @@ -882,7 +913,7 @@ mod tests { async fn postgres_replace_order() { let owner = Address::repeat_byte(0x77); - let db = Postgres::try_new("postgresql://").unwrap(); + let db = Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&db.pool).await.unwrap(); let old_order = Order { @@ -948,7 +979,7 @@ mod tests { async fn postgres_replace_order_no_cancellation_on_error() { let owner = Address::repeat_byte(0x77); - let db = Postgres::try_new("postgresql://").unwrap(); + let db = Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&db.pool).await.unwrap(); let old_order = Order { @@ -992,7 +1023,7 @@ mod tests { #[tokio::test] #[ignore] async fn postgres_presignature_status() { - let db = Postgres::try_new("postgresql://").unwrap(); + let db = Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&db.pool).await.unwrap(); let uid = OrderUid([0u8; 56]); let order = Order { @@ -1065,7 +1096,7 @@ mod tests { #[tokio::test] #[ignore] async fn postgres_cancel_orders() { - let db = Postgres::try_new("postgresql://").unwrap(); + let db = Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&db.pool).await.unwrap(); // Define some helper closures to make the test easier to read. @@ -1114,7 +1145,7 @@ mod tests { #[tokio::test] #[ignore] async fn postgres_insert_orders_with_interactions() { - let db = Postgres::try_new("postgresql://").unwrap(); + let db = Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&db.pool).await.unwrap(); let interaction = |byte: u8| InteractionData { @@ -1123,19 +1154,20 @@ mod tests { call_data: vec![byte; byte as _], }; + let fee_parameters = FeeParameters { + sell_token_price: 2.5, + gas_amount: 0.01, + gas_price: 0.003, + }; let quote = Quote { id: Some(5), - sell_amount: U256::from(1), - buy_amount: U256::from(2), + sell_amount: alloy::primitives::U256::from(1), + buy_amount: alloy::primitives::U256::from(2), + fee_amount: fee_parameters.fee(), data: QuoteData { - fee_parameters: FeeParameters { - sell_token_price: 2.5, - gas_amount: 0.01, - gas_price: 0.003, - }, + fee_parameters, ..Default::default() }, - ..Default::default() }; let uid = OrderUid([0x42; 56]); @@ -1170,13 +1202,13 @@ mod tests { #[tokio::test] #[ignore] async fn postgres_insert_orders_with_interactions_and_verified() { - let db = Postgres::try_new("postgresql://").unwrap(); + let db = Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&db.pool).await.unwrap(); let quote = Quote { id: Some(5), - sell_amount: U256::from(1), - buy_amount: U256::from(2), + sell_amount: alloy::primitives::U256::from(1), + buy_amount: alloy::primitives::U256::from(2), data: QuoteData { verified: true, metadata: QuoteMetadataV1 { diff --git a/crates/orderbook/src/database/solver_competition.rs b/crates/orderbook/src/database/solver_competition.rs index 8aba3a057d..e812883364 100644 --- a/crates/orderbook/src/database/solver_competition.rs +++ b/crates/orderbook/src/database/solver_competition.rs @@ -30,6 +30,7 @@ impl SolverCompetitionStoring for Postgres { async fn load_competition( &self, id: Identifier, + after_block: Option, ) -> Result { let _timer = super::Metrics::get() .database_queries @@ -38,20 +39,10 @@ impl SolverCompetitionStoring for Postgres { let mut ex = self.pool.acquire().await.map_err(anyhow::Error::from)?; match id { - Identifier::Id(id) => database::solver_competition::load_by_id(&mut ex, id) - .await - .context("solver_competition::load_by_id")? - .map(|row| { - deserialize_solver_competition( - row.json, - row.id, - row.tx_hashes.iter().map(|hash| B256::new(hash.0)).collect(), - ) - }), - Identifier::Transaction(hash) => { - database::solver_competition::load_by_tx_hash(&mut ex, &ByteArray(hash.0)) + Identifier::Id(id) => { + database::solver_competition::load_by_id(&mut ex, id, after_block) .await - .context("solver_competition::load_by_tx_hash")? + .context("solver_competition::load_by_id")? .map(|row| { deserialize_solver_competition( row.json, @@ -60,12 +51,27 @@ impl SolverCompetitionStoring for Postgres { ) }) } + Identifier::Transaction(hash) => database::solver_competition::load_by_tx_hash( + &mut ex, + &ByteArray(hash.0), + after_block, + ) + .await + .context("solver_competition::load_by_tx_hash")? + .map(|row| { + deserialize_solver_competition( + row.json, + row.id, + row.tx_hashes.iter().map(|hash| B256::new(hash.0)).collect(), + ) + }), } .ok_or(LoadSolverCompetitionError::NotFound)? } async fn load_latest_competition( &self, + after_block: Option, ) -> Result { let _timer = super::Metrics::get() .database_queries @@ -73,7 +79,7 @@ impl SolverCompetitionStoring for Postgres { .start_timer(); let mut ex = self.pool.acquire().await.map_err(anyhow::Error::from)?; - database::solver_competition::load_latest_competition(&mut ex) + database::solver_competition::load_latest_competition(&mut ex, after_block) .await .context("solver_competition::load_latest_competition")? .map(|row| { @@ -100,6 +106,7 @@ impl SolverCompetitionStoring for Postgres { let latest_competitions = database::solver_competition::load_latest_competitions( &mut ex, latest_competitions_count, + None, ) .await .context("solver_competition::load_latest_competitions")? @@ -124,11 +131,11 @@ mod tests { #[tokio::test] #[ignore] async fn not_found_error() { - let db = Postgres::try_new("postgresql://").unwrap(); + let db = Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&db.pool).await.unwrap(); let result = db - .load_competition(Identifier::Transaction(Default::default())) + .load_competition(Identifier::Transaction(Default::default()), None) .await .unwrap_err(); assert!(matches!(result, LoadSolverCompetitionError::NotFound)); diff --git a/crates/orderbook/src/database/solver_competition_v2.rs b/crates/orderbook/src/database/solver_competition_v2.rs index 71d735e089..6a22438723 100644 --- a/crates/orderbook/src/database/solver_competition_v2.rs +++ b/crates/orderbook/src/database/solver_competition_v2.rs @@ -16,6 +16,7 @@ impl Postgres { pub async fn load_competition_by_id( &self, auction_id: i64, + current_block: Option, ) -> Result { let _timer = super::Metrics::get() .database_queries @@ -23,7 +24,7 @@ impl Postgres { .start_timer(); let mut ex = self.pool.acquire().await.map_err(anyhow::Error::from)?; - database::solver_competition_v2::load_by_id(&mut ex, auction_id) + database::solver_competition_v2::load_by_id(&mut ex, auction_id, current_block) .await .context("solver_competition_v2::load_by_id")? .map(try_into_dto) @@ -33,6 +34,7 @@ impl Postgres { pub async fn load_competition_by_tx_hash( &self, tx_hash: B256, + current_block: Option, ) -> Result { let _timer = super::Metrics::get() .database_queries @@ -40,21 +42,28 @@ impl Postgres { .start_timer(); let mut ex = self.pool.acquire().await.map_err(anyhow::Error::from)?; - database::solver_competition_v2::load_by_tx_hash(&mut ex, ByteArray(tx_hash.0)) - .await - .context("solver_competition_v2::load_by_tx_hash")? - .map(try_into_dto) - .ok_or(LoadSolverCompetitionError::NotFound)? + database::solver_competition_v2::load_by_tx_hash( + &mut ex, + ByteArray(tx_hash.0), + current_block, + ) + .await + .context("solver_competition_v2::load_by_tx_hash")? + .map(try_into_dto) + .ok_or(LoadSolverCompetitionError::NotFound)? } - pub async fn load_latest_competition(&self) -> Result { + pub async fn load_latest_competition( + &self, + current_block: Option, + ) -> Result { let _timer = super::Metrics::get() .database_queries .with_label_values(&["load_latest_solver_competition_v2"]) .start_timer(); let mut ex = self.pool.acquire().await.map_err(anyhow::Error::from)?; - database::solver_competition_v2::load_latest(&mut ex) + database::solver_competition_v2::load_latest(&mut ex, current_block) .await .context("solver_competition_v2::load_latest")? .map(try_into_dto) @@ -153,6 +162,7 @@ fn try_into_dto(value: DbResponse) -> Result Result { const TOTAL_SURPLUS_QUERY: &str = r#" -WITH regular_orders AS ( - SELECT ARRAY_AGG(uid) AS ids FROM orders WHERE owner = $1 -), -onchain_orders AS ( - SELECT ARRAY_AGG(uid) AS ids FROM onchain_placed_orders WHERE sender = $1 -), -trade_components AS ( +WITH trade_components AS ( SELECT - CASE kind - -- so much was actually bought - WHEN 'sell' THEN t.buy_amount - -- so much was actually converted to buy tokens - WHEN 'buy' THEN t.sell_amount - t.fee_amount - END AS trade_amount, - CASE kind - -- so much had to be bought at least (given exeucted amount and limit price) - WHEN 'sell' THEN (t.sell_amount - t.fee_amount) * o.buy_amount / o.sell_amount - -- so much could be converted to buy_token at most (given executed amount and limit price) - WHEN 'buy' THEN t.buy_amount * o.sell_amount / o.buy_amount - END AS limit_amount, - o.kind, - CASE kind - WHEN 'sell' THEN (SELECT price FROM auction_prices ap WHERE ap.token = o.buy_token AND ap.auction_id = oe.auction_id) - WHEN 'buy' THEN (SELECT price FROM auction_prices ap WHERE ap.token = o.sell_token AND ap.auction_id = oe.auction_id) - END AS surplus_token_native_price + o.uid, + CASE o.kind + WHEN 'sell' THEN t.buy_amount + WHEN 'buy' THEN t.sell_amount - t.fee_amount + END AS trade_amount, + CASE o.kind + WHEN 'sell' THEN (t.sell_amount - t.fee_amount) * o.buy_amount / o.sell_amount + WHEN 'buy' THEN t.buy_amount * o.sell_amount / o.buy_amount + END AS limit_amount, + o.kind, + ap.price AS surplus_token_native_price FROM orders o - JOIN trades t ON o.uid = t.order_uid - JOIN order_execution oe ON o.uid = oe.order_uid - -- use this weird construction instead of `where owner=address or sender=address` to help postgres make efficient use of indices - WHERE uid = ANY(ARRAY_CAT((SELECT ids FROM regular_orders), (SELECT ids FROM onchain_orders))) + JOIN trades t ON t.order_uid = o.uid + JOIN order_execution oe ON oe.order_uid = t.order_uid + LEFT JOIN auction_prices ap + ON ap.auction_id = oe.auction_id + AND ap.token = CASE o.kind WHEN 'sell' THEN o.buy_token ELSE o.sell_token END + WHERE o.owner = $1 + + UNION ALL + + SELECT + o.uid, + CASE o.kind + -- so much was actually bought + WHEN 'sell' THEN t.buy_amount + -- so much was actually converted to buy tokens + WHEN 'buy' THEN t.sell_amount - t.fee_amount + END AS trade_amount, + CASE o.kind + -- so much had to be bought at least (given executed amount and limit price) + WHEN 'sell' THEN (t.sell_amount - t.fee_amount) * o.buy_amount / o.sell_amount + -- so much could be converted to buy_token at most (given executed amount and limit price) + WHEN 'buy' THEN t.buy_amount * o.sell_amount / o.buy_amount + END AS limit_amount, + o.kind, + ap.price AS surplus_token_native_price + FROM onchain_placed_orders opo + JOIN orders o ON o.uid = opo.uid AND o.owner != $1 + JOIN trades t ON t.order_uid = o.uid + JOIN order_execution oe ON oe.order_uid = t.order_uid + LEFT JOIN auction_prices ap + ON ap.auction_id = oe.auction_id + AND ap.token = CASE o.kind WHEN 'sell' THEN o.buy_token ELSE o.sell_token END + WHERE opo.sender = $1 UNION ALL -- Additional query for jit_orders SELECT - CASE j.kind - WHEN 'sell' THEN t.buy_amount - WHEN 'buy' THEN t.sell_amount - t.fee_amount - END AS trade_amount, - CASE j.kind - WHEN 'sell' THEN (t.sell_amount - t.fee_amount) * j.buy_amount / j.sell_amount - WHEN 'buy' THEN t.buy_amount * j.sell_amount / j.buy_amount - END AS limit_amount, - j.kind, - CASE j.kind - WHEN 'sell' THEN (SELECT price FROM auction_prices ap WHERE ap.token = j.buy_token AND ap.auction_id = oe.auction_id) - WHEN 'buy' THEN (SELECT price FROM auction_prices ap WHERE ap.token = j.sell_token AND ap.auction_id = oe.auction_id) - END AS surplus_token_native_price + j.uid, + CASE j.kind + WHEN 'sell' THEN t.buy_amount + WHEN 'buy' THEN t.sell_amount - t.fee_amount + END AS trade_amount, + CASE j.kind + WHEN 'sell' THEN (t.sell_amount - t.fee_amount) * j.buy_amount / j.sell_amount + WHEN 'buy' THEN t.buy_amount * j.sell_amount / j.buy_amount + END AS limit_amount, + j.kind, + ap.price AS surplus_token_native_price FROM jit_orders j JOIN trades t ON j.uid = t.order_uid - JOIN order_execution oe ON j.uid = oe.order_uid - WHERE j.owner = $1 AND NOT EXISTS ( + JOIN order_execution oe ON t.order_uid = oe.order_uid + LEFT JOIN auction_prices ap + ON ap.auction_id = oe.auction_id + AND ap.token = CASE j.kind WHEN 'sell' THEN j.buy_token ELSE j.sell_token END + WHERE j.owner = $1 + AND NOT EXISTS ( SELECT 1 FROM orders o WHERE o.uid = j.uid ) -), -trade_surplus AS ( +) +SELECT + COALESCE(SUM(surplus_in_wei ORDER BY uid), 0) AS total_surplus_in_wei +FROM ( SELECT + uid, CASE kind - -- amounts refer to tokens bought; more is better WHEN 'sell' THEN (trade_amount - limit_amount) * surplus_token_native_price - -- amounts refer to tokens sold; less is better WHEN 'buy' THEN (limit_amount - trade_amount) * surplus_token_native_price END / POWER(10, 18) AS surplus_in_wei FROM trade_components -) -SELECT - COALESCE(SUM(surplus_in_wei), 0) AS total_surplus_in_wei -FROM trade_surplus +) ts; "#; sqlx::query_scalar(TOTAL_SURPLUS_QUERY) diff --git a/crates/orderbook/src/database/trades.rs b/crates/orderbook/src/database/trades.rs index 6430ffb2f6..0b2bf5bd08 100644 --- a/crates/orderbook/src/database/trades.rs +++ b/crates/orderbook/src/database/trades.rs @@ -3,7 +3,6 @@ use { alloy::primitives::{Address, B256}, anyhow::{Context, Result}, database::{byte_array::ByteArray, trades::TradesQueryRow}, - futures::stream::TryStreamExt, model::{fee_policy::ExecutedProtocolFee, order::OrderUid, trade::Trade}, number::conversions::big_decimal_to_big_uint, std::convert::TryInto, @@ -14,6 +13,11 @@ pub trait TradeRetrieving: Send + Sync { async fn trades(&self, filter: &TradeFilter) -> Result>; } +#[async_trait::async_trait] +pub trait TradeRetrievingPaginated: Send + Sync { + async fn trades_paginated(&self, filter: &PaginatedTradeFilter) -> Result>; +} + /// Any default value means that this field is unfiltered. #[derive(Debug, Default, Eq, PartialEq)] pub struct TradeFilter { @@ -21,6 +25,15 @@ pub struct TradeFilter { pub order_uid: Option, } +/// Trade filter with pagination support (for v2 API). +#[derive(Debug, Default, Eq, PartialEq)] +pub struct PaginatedTradeFilter { + pub owner: Option
, + pub order_uid: Option, + pub offset: u64, + pub limit: u64, +} + #[async_trait::async_trait] impl TradeRetrieving for Postgres { async fn trades(&self, filter: &TradeFilter) -> Result> { @@ -29,16 +42,78 @@ impl TradeRetrieving for Postgres { .with_label_values(&["trades"]) .start_timer(); + let mut ex = self.pool.acquire().await?; + // For v1 API, return all results without pagination (use large default values) + let trades = database::trades::trades( + &mut ex, + filter.owner.map(|owner| ByteArray(owner.0.0)).as_ref(), + filter.order_uid.map(|uid| ByteArray(uid.0)).as_ref(), + 0, + i64::MAX, + ) + .into_inner() + .await + .map_err(anyhow::Error::from)?; + timer.stop_and_record(); + + let auction_order_uids = trades + .iter() + .filter_map(|t| t.auction_id.map(|auction_id| (auction_id, t.order_uid))) + .collect::>(); + + if auction_order_uids.len() >= u16::MAX as usize { + // We use these ids as arguments for an SQL query and sqlx only allows + // u16::MAX arguments. To avoid a panic later on we return an error here. + anyhow::bail!("query response too large"); + } + + let executed_protocol_fees = self + .executed_protocol_fees(auction_order_uids.as_slice()) + .await?; + + trades + .into_iter() + .map(|trade| { + let executed_protocol_fees = trade + .auction_id + .map(|auction_id| { + executed_protocol_fees + .get(&(auction_id, trade.order_uid)) + .cloned() + .unwrap_or_default() + }) + .unwrap_or_default(); + trade_from(trade, executed_protocol_fees) + }) + .collect::>>() + } +} + +#[async_trait::async_trait] +impl TradeRetrievingPaginated for Postgres { + async fn trades_paginated(&self, filter: &PaginatedTradeFilter) -> Result> { + let timer = super::Metrics::get() + .database_queries + .with_label_values(&["trades_paginated"]) + .start_timer(); + let mut ex = self.pool.acquire().await?; let trades = database::trades::trades( &mut ex, filter.owner.map(|owner| ByteArray(owner.0.0)).as_ref(), filter.order_uid.map(|uid| ByteArray(uid.0)).as_ref(), + filter + .offset + .try_into() + .context("offset too large for database")?, + filter + .limit + .try_into() + .context("limit too large for database")?, ) .into_inner() - .map_err(anyhow::Error::from) - .try_collect::>() - .await?; + .await + .map_err(anyhow::Error::from)?; timer.stop_and_record(); let auction_order_uids = trades diff --git a/crates/orderbook/src/dto/auction.rs b/crates/orderbook/src/dto/auction.rs index fe3d237fbf..54268c0ad9 100644 --- a/crates/orderbook/src/dto/auction.rs +++ b/crates/orderbook/src/dto/auction.rs @@ -1,13 +1,14 @@ use { super::order::Order, + alloy::primitives::{Address, U256}, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, }; /// Replicates [`crate::model::Auction`]. +// NOTE: as of 25/11/2025 this is only used for liveness checking. #[serde_as] #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -15,9 +16,9 @@ pub struct Auction { pub block: u64, pub orders: Vec, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub prices: BTreeMap, + pub prices: BTreeMap, #[serde(default)] - pub surplus_capturing_jit_order_owners: Vec, + pub surplus_capturing_jit_order_owners: Vec
, } pub type AuctionId = i64; diff --git a/crates/orderbook/src/dto/mod.rs b/crates/orderbook/src/dto/mod.rs index 1fd8284dbf..cb5cf0b26a 100644 --- a/crates/orderbook/src/dto/mod.rs +++ b/crates/orderbook/src/dto/mod.rs @@ -1,19 +1,89 @@ pub mod auction; pub mod order; -pub use { - auction::{Auction, AuctionId, AuctionWithId}, - order::Order, -}; use { + alloy::primitives::U256, + eth_domain_types::{Address, NonZeroU256}, + model::{ + order::{BuyTokenDestination, OrderKind, SellTokenSource}, + signature::Signature, + }, number::serialization::HexOrDecimalU256, - primitive_types::U256, - serde::Serialize, + serde::{Deserialize, Serialize}, serde_with::serde_as, + simulator::tenderly, +}; +pub use { + auction::{Auction, AuctionId, AuctionWithId}, + order::Order, }; +/// Request body for the POST /restricted/api/v1/debug/simulation endpoint. +#[serde_as] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OrderSimulationRequest { + /// The address of the token being sold. + pub sell_token: Address, + /// The address of the token being bought. + pub buy_token: Address, + /// The amount of `sell_token`s that may be sold. + pub sell_amount: NonZeroU256, + /// The amount of `buy_token`s that should be bought. + #[serde_as(as = "HexOrDecimalU256")] + pub buy_amount: U256, + /// The kind of order (i.e. sell or buy). + pub kind: OrderKind, + /// The address of the order's owner + pub owner: Address, + /// The receiver of the `buy_token`. When this field is `None`, the receiver + /// is the same as the owner. + #[serde(default)] + pub receiver: Option
, + /// Sell token's source — ERC20, internal vault or external vault (at the + /// time of writing). + #[serde(default)] + pub sell_token_balance: SellTokenSource, + /// Defines how tokens are transferred back to the user, either as an ERC-20 + /// token transfer or internal Balancer Vault transfer. + #[serde(default)] + pub buy_token_balance: BuyTokenDestination, + /// Full app data JSON. + pub app_data: String, + /// The block number at which the simulation should happen + pub block_number: Option, + /// The order signature (signing scheme + bytes). Required to pass + /// signature verification in the settlement contract during simulation. + #[serde(flatten)] + pub signature: Signature, + /// The fee amount signed by the user. This field is expected to be 0 and + /// only still there because it needs to be signed by the user. + pub fee_amount: U256, + /// UNIX timestamp when the order will expire. + pub valid_to: u32, + /// Whether the order needs to be filled all at once or allows to be filled + /// over multiple partial executions. + pub partially_fillable: bool, +} + +/// The result of Order simulation, contains the error (if any) +/// and full Tenderly API request that can be used to resimulate +/// and debug using Tenderly +#[derive(Clone, Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct OrderSimulationResult { + /// Full request object that can be used directly with the Tenderly API + pub tenderly_request: tenderly::dto::Request, + /// Shared Tenderly simulation URL for debugging in the dashboard + #[serde(skip_serializing_if = "Option::is_none")] + pub tenderly_url: Option, + /// Any error that might have been reported during order simulation + pub error: Option, +} + #[serde_as] #[derive(Serialize)] +#[cfg_attr(feature = "e2e", derive(serde::Deserialize))] #[serde(rename_all = "camelCase")] pub struct TokenMetadata { pub first_trade_block: Option, diff --git a/crates/orderbook/src/dto/order.rs b/crates/orderbook/src/dto/order.rs index 0e08967081..99b309a32f 100644 --- a/crates/orderbook/src/dto/order.rs +++ b/crates/orderbook/src/dto/order.rs @@ -1,4 +1,5 @@ use { + alloy::primitives::Address, app_data::AppDataHash, model::{ interaction::InteractionData, @@ -6,7 +7,6 @@ use { signature::Signature, }, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, serde::{Deserialize, Serialize}, serde_with::serde_as, }; @@ -16,21 +16,21 @@ use { #[serde(rename_all = "camelCase")] pub struct Order { pub uid: OrderUid, - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, #[serde_as(as = "HexOrDecimalU256")] - pub sell_amount: U256, + pub sell_amount: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub buy_amount: U256, + pub buy_amount: alloy::primitives::U256, pub protocol_fees: Vec, pub created: u32, pub valid_to: u32, pub kind: OrderKind, - pub receiver: Option, - pub owner: H160, + pub receiver: Option
, + pub owner: Address, pub partially_fillable: bool, #[serde_as(as = "HexOrDecimalU256")] - pub executed: U256, + pub executed: alloy::primitives::U256, pub pre_interactions: Vec, pub post_interactions: Vec, pub sell_token_balance: SellTokenSource, @@ -48,12 +48,12 @@ pub struct Order { #[serde(rename_all = "camelCase")] pub struct Quote { #[serde_as(as = "HexOrDecimalU256")] - pub sell_amount: U256, + pub sell_amount: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub buy_amount: U256, + pub buy_amount: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub fee: U256, - pub solver: H160, + pub fee: alloy::primitives::U256, + pub solver: Address, } #[serde_as] @@ -78,9 +78,9 @@ pub enum FeePolicy { #[serde(rename_all = "camelCase")] pub struct ExecutedAmounts { #[serde_as(as = "HexOrDecimalU256")] - pub sell: U256, + pub sell: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub buy: U256, + pub buy: alloy::primitives::U256, } /// Indicates that a solver has provided a solution, with `executed_amounts` diff --git a/crates/orderbook/src/ipfs.rs b/crates/orderbook/src/ipfs.rs index ff0a873a45..fbc2d8cc65 100644 --- a/crates/orderbook/src/ipfs.rs +++ b/crates/orderbook/src/ipfs.rs @@ -89,7 +89,7 @@ mod tests { #[tokio::test] #[ignore] async fn not_found() { - observe::tracing::initialize( + observe::tracing::init::initialize( &observe::Config::default().with_env_filter("orderbook::ipfs=trace"), ); let ipfs = Ipfs::new(Default::default(), "https://ipfs.io".parse().unwrap(), None); diff --git a/crates/orderbook/src/main.rs b/crates/orderbook/src/main.rs index b2f14d5ff2..89606ccc81 100644 --- a/crates/orderbook/src/main.rs +++ b/crates/orderbook/src/main.rs @@ -1,6 +1,11 @@ +#[cfg(feature = "mimalloc-allocator")] #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +#[cfg(not(feature = "mimalloc-allocator"))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + #[tokio::main] async fn main() { orderbook::start(std::env::args()).await; diff --git a/crates/orderbook/src/orderbook.rs b/crates/orderbook/src/orderbook.rs index 6d33bf29e0..23e901ebf2 100644 --- a/crates/orderbook/src/orderbook.rs +++ b/crates/orderbook/src/orderbook.rs @@ -4,16 +4,15 @@ use { orders::{InsertionError, OrderStoring}, trades::{TradeFilter, TradeRetrieving}, }, - dto, + dto::{self, OrderSimulationRequest, OrderSimulationResult}, solver_competition::{Identifier, LoadSolverCompetitionError, SolverCompetitionStoring}, }, - alloy::primitives::{Address, B256}, - anyhow::{Context, Result}, + alloy::primitives::{Address, B256, keccak256}, + anyhow::{Context, Result, anyhow}, app_data::{AppDataHash, Validator}, bigdecimal::ToPrimitive, chrono::Utc, database::order_events::OrderEventLabel, - ethrpc::alloy::conversions::IntoLegacy, model::{ DomainSeparator, order::{ @@ -21,6 +20,7 @@ use { OrderCancellation, OrderCreation, OrderCreationAppData, + OrderData, OrderStatus, OrderUid, SignedOrderCancellations, @@ -29,7 +29,6 @@ use { solver_competition::{self, SolverCompetitionAPI}, }, observe::metrics::LivenessChecking, - primitive_types::H160, shared::{ fee::FeeParameters, order_quoting::Quote, @@ -40,6 +39,7 @@ use { is_order_outside_market_price, }, }, + simulator::simulation_builder::{self, SettlementSimulator}, std::{borrow::Cow, sync::Arc}, strum::Display, thiserror::Error, @@ -79,9 +79,9 @@ impl Metrics { // Check if the order at the submission time was "in market" !is_order_outside_market_price( &Amounts { - sell: order.data.sell_amount.into_legacy(), - buy: order.data.buy_amount.into_legacy(), - fee: order.data.fee_amount.into_legacy(), + sell: order.data.sell_amount, + buy: order.data.buy_amount, + fee: order.data.fee_amount, }, &Amounts { sell: quote.sell_amount, @@ -217,7 +217,7 @@ pub enum OrderReplacementError { #[derive(Debug)] pub struct QuoteMetadata { pub id: Option, - pub solver: H160, + pub solver: Address, } impl From<&Quote> for QuoteMetadata { @@ -231,23 +231,26 @@ impl From<&Quote> for QuoteMetadata { pub struct Orderbook { domain_separator: DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, database: crate::database::Postgres, database_replica: crate::database::Postgres, order_validator: Arc, app_data: Arc, active_order_competition_threshold: u32, + order_simulator: Option, } impl Orderbook { + #[expect(clippy::too_many_arguments)] pub fn new( domain_separator: DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, database: crate::database::Postgres, database_replica: crate::database::Postgres, order_validator: Arc, app_data: Arc, active_order_competition_threshold: u32, + order_simulator: Option, ) -> Self { Metrics::initialize(); Self { @@ -258,6 +261,7 @@ impl Orderbook { order_validator, app_data, active_order_competition_threshold, + order_simulator, } } @@ -349,10 +353,7 @@ impl Orderbook { let signer = cancellation .validate(&self.domain_separator) .map_err(|_| OrderCancellationError::InvalidSignature)?; - if orders - .iter() - .any(|order| signer != order.metadata.owner.into_legacy()) - { + if orders.iter().any(|order| signer != order.metadata.owner) { return Err(OrderCancellationError::WrongOwner); }; @@ -382,7 +383,7 @@ impl Orderbook { let signer = cancellation .validate(&self.domain_separator) .map_err(|_| OrderCancellationError::InvalidSignature)?; - if signer != order.metadata.owner.into_legacy() { + if signer != order.metadata.owner { return Err(OrderCancellationError::WrongOwner); }; @@ -499,6 +500,10 @@ impl Orderbook { self.database_replica.single_order(uid).await } + pub async fn get_orders(&self, uids: &[OrderUid]) -> Result)>> { + self.database_replica.many_orders(uids).await + } + pub async fn get_orders_for_tx(&self, hash: &B256) -> Result> { self.database_replica.orders_for_tx(hash).await } @@ -556,9 +561,10 @@ impl Orderbook { }; let latest_competition = async { - let competition = SolverCompetitionStoring::load_latest_competition(&self.database) - .await - .map_err(Into::::into)?; + let competition = + SolverCompetitionStoring::load_latest_competition(&self.database, None) + .await + .map_err(Into::::into)?; Ok::<_, OrderStatusError>(solutions(competition)) }; @@ -579,7 +585,7 @@ impl Orderbook { Some(Some(tx_hash)) => { let competition = self .database - .load_competition(Identifier::Transaction(tx_hash)) + .load_competition(Identifier::Transaction(tx_hash), None) .await?; return Ok(dto::order::Status::Traded(solutions(competition))); } @@ -604,6 +610,135 @@ impl Orderbook { }; Ok(status) } + + /// Simulates an order based on its Uid using the OrderSimulator. + /// + /// The returned value contains the simulation result and tenderly API + /// request object that can be used to debug it. + pub async fn simulate_order( + &self, + uid: &OrderUid, + block_number: Option, + ) -> Result, OrderSimulationError> { + let Some(order_simulator) = &self.order_simulator else { + return Err(OrderSimulationError::NotEnabled); + }; + let Some(order) = self + .get_order(uid) + .await + .map_err(OrderSimulationError::Other)? + else { + return Ok(None); + }; + + let full_app_data = order.metadata.full_app_data.clone().ok_or_else(|| { + OrderSimulationError::Other(anyhow!( + "can't find the full app data for this order in the database, can't simulate the \ + order correctly without that" + )) + })?; + + let sim = order_simulator + .new_simulation_builder() + .with_orders([simulation_builder::Order::new(order.data) + .with_signature(order.metadata.owner, order.signature) + .fill_at( + simulation_builder::ExecutionAmount::Remaining, + simulation_builder::PriceEncoding::LimitPrice, + )]) + .parameters_from_app_data(&full_app_data) + .map_err(|err| { + OrderSimulationError::MalformedInput(anyhow!("app_data `{}`: {err}", full_app_data)) + })? + .at_block( + block_number + .map(simulation_builder::Block::Number) + .unwrap_or(simulation_builder::Block::Latest), + ) + .provide_sufficient_buy_tokens() + .from_solver(simulation_builder::Solver::Fake(None)) + .build() + .await + .context("failed to finalize simulation") + .map_err(OrderSimulationError::Other)?; + + let simulation_result = sim + .simulate_with_tenderly_report() + .await + .context("failed to execute simulation") + .map_err(OrderSimulationError::Other)?; + + Ok(Some(OrderSimulationResult { + tenderly_url: simulation_result.tenderly_url, + tenderly_request: simulation_result.tenderly_request, + error: simulation_result.error, + })) + } + + /// Simulates an arbitrary order without requiring it to exist in the + /// database. + pub async fn simulate_custom_order( + &self, + request: OrderSimulationRequest, + ) -> Result { + let Some(order_simulator) = &self.order_simulator else { + return Err(OrderSimulationError::NotEnabled); + }; + let app_data_hash = keccak256(&request.app_data); + + let sim = order_simulator + .new_simulation_builder() + .with_orders([simulation_builder::Order::new(OrderData { + sell_token: request.sell_token, + buy_token: request.buy_token, + sell_amount: request.sell_amount.into(), + buy_amount: request.buy_amount, + kind: request.kind, + receiver: request.receiver, + sell_token_balance: request.sell_token_balance, + buy_token_balance: request.buy_token_balance, + fee_amount: request.fee_amount, + valid_to: request.valid_to, + app_data: AppDataHash(app_data_hash.into()), + partially_fillable: request.partially_fillable, + }) + .with_signature(request.owner, request.signature) + .fill_at( + simulation_builder::ExecutionAmount::Full, + simulation_builder::PriceEncoding::LimitPrice, + )]) + .parameters_from_app_data(&request.app_data) + .map_err(|err| { + OrderSimulationError::MalformedInput(anyhow!( + "app_data `{}`: {err}", + request.app_data + )) + })? + .at_block( + request + .block_number + .map(simulation_builder::Block::Number) + .unwrap_or(simulation_builder::Block::Latest), + ) + .provide_sufficient_buy_tokens() + .from_solver(simulation_builder::Solver::Fake(None)) + .build() + .await + .context("failed to finalize simulation") + .map_err(OrderSimulationError::Other)?; + + let simulation_result = sim + .simulate_with_tenderly_report() + .await + .context("failed to execute simulation") + .map_err(OrderSimulationError::Other)?; + + Ok(OrderSimulationResult { + tenderly_url: simulation_result.tenderly_url, + tenderly_request: simulation_result.tenderly_request, + error: simulation_result.error, + }) + } } #[derive(Error, Debug)] @@ -623,6 +758,16 @@ impl From for OrderStatusError { } } +#[derive(Error, Debug)] +pub enum OrderSimulationError { + #[error("order simulation is not enabled")] + NotEnabled, + #[error("malformed input")] + MalformedInput(anyhow::Error), + #[error("simulation could not be created for order")] + Other(anyhow::Error), +} + #[async_trait::async_trait] impl LivenessChecking for Orderbook { async fn is_alive(&self) -> bool { @@ -635,8 +780,6 @@ mod tests { use { super::*, crate::database::orders::MockOrderStoring, - ethcontract::H160, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, mockall::predicate::eq, model::{ order::{OrderData, OrderMetadata}, @@ -679,7 +822,7 @@ mod tests { Ok(( Order { metadata: OrderMetadata { - owner: creation.from.unwrap().into_alloy(), + owner: creation.from.unwrap(), uid: new_order_uid, ..Default::default() }, @@ -691,7 +834,8 @@ mod tests { )) }); - let database = crate::database::Postgres::try_new("postgresql://").unwrap(); + let database = + crate::database::Postgres::try_new("postgresql://", Default::default()).unwrap(); database::clear_DANGER(&database.pool).await.unwrap(); database.insert_order(&old_order).await.unwrap(); @@ -706,16 +850,17 @@ mod tests { database_replica, order_validator: Arc::new(order_validator), domain_separator: Default::default(), - settlement_contract: H160([0xba; 20]), + settlement_contract: Address::repeat_byte(0xba), app_data, active_order_competition_threshold: Default::default(), + order_simulator: None, }; // Different owner assert!(matches!( orderbook .add_order(OrderCreation { - from: Some(H160([2; 20])), + from: Some(Address::repeat_byte(2)), signature: Signature::Eip712(Default::default()), app_data: OrderCreationAppData::Full { full: format!( @@ -735,7 +880,7 @@ mod tests { assert!(matches!( orderbook .add_order(OrderCreation { - from: Some(H160([2; 20])), + from: Some(Address::repeat_byte(2)), signature: Signature::Eip712(Default::default()), app_data: OrderCreationAppData::Full { full: format!( @@ -755,7 +900,7 @@ mod tests { assert!(matches!( orderbook .add_order(OrderCreation { - from: Some(old_order.metadata.owner.into_legacy()), + from: Some(old_order.metadata.owner), signature: Signature::PreSign, app_data: OrderCreationAppData::Full { full: format!( @@ -774,7 +919,7 @@ mod tests { // Stars align... let (order_id, _) = orderbook .add_order(OrderCreation { - from: Some(old_order.metadata.owner.into_legacy()), + from: Some(old_order.metadata.owner), signature: Signature::Eip712(Default::default()), app_data: OrderCreationAppData::Full { full: format!( diff --git a/crates/orderbook/src/quoter.rs b/crates/orderbook/src/quoter.rs index 489ad669f6..8c9db9993d 100644 --- a/crates/orderbook/src/quoter.rs +++ b/crates/orderbook/src/quoter.rs @@ -1,15 +1,17 @@ use { - crate::{ - app_data, - arguments::{FeeFactor, VolumeFeeConfig}, - }, + crate::app_data, + alloy::primitives::{U256, U512, Uint, ruint::UintTryFrom}, + bigdecimal::{BigDecimal, FromPrimitive}, chrono::{TimeZone, Utc}, + configs::{fee_factor::FeeFactor, orderbook::VolumeFeeConfig}, model::{ order::OrderCreationAppData, quote::{OrderQuote, OrderQuoteRequest, OrderQuoteResponse, OrderQuoteSide, PriceQuality}, }, - primitive_types::U256, + price_estimation::Verification, shared::{ + arguments::TokenBucketFeeOverride, + fee::VolumeFeePolicy, order_quoting::{CalculateQuoteError, OrderQuoting, Quote, QuoteParameters}, order_validation::{ AppDataValidationError, @@ -17,11 +19,11 @@ use { PartialValidationError, PreOrderData, }, - price_estimation::Verification, - trade_finding, }, std::sync::Arc, thiserror::Error, + token_info::TokenInfoFetching, + tokio::join, tracing::instrument, }; @@ -36,6 +38,15 @@ struct AdjustedQuoteData { protocol_fee_bps: Option, } +impl AdjustedQuoteData { + pub fn unchanged(quote: &Quote) -> Self { + AdjustedQuoteData { + sell_amount: quote.sell_amount, + buy_amount: quote.buy_amount, + protocol_fee_bps: None, + } + } +} /// A high-level interface for handling API quote requests. pub struct QuoteHandler { order_validator: Arc, @@ -43,6 +54,8 @@ pub struct QuoteHandler { fast_quoter: Arc, app_data: Arc, volume_fee: Option, + volume_fee_policy: VolumeFeePolicy, + token_info_fetcher: Arc, } impl QuoteHandler { @@ -51,13 +64,23 @@ impl QuoteHandler { quoter: Arc, app_data: Arc, volume_fee: Option, + volume_fee_bucket_overrides: Vec, + enable_sell_equals_buy_volume_fee: bool, + token_info_fetcher: Arc, ) -> Self { + let volume_fee_policy = VolumeFeePolicy::new( + volume_fee_bucket_overrides, + volume_fee.as_ref().and_then(|config| config.factor), + enable_sell_equals_buy_volume_fee, + ); Self { order_validator, optimal_quoter: quoter.clone(), fast_quoter: quoter, app_data, volume_fee, + volume_fee_policy, + token_info_fetcher, } } @@ -73,7 +96,18 @@ impl QuoteHandler { &self, request: &OrderQuoteRequest, ) -> Result { - tracing::debug!(?request, "calculating quote"); + let (sell_token_info, buy_token_info) = join!( + self.token_info_fetcher.get_token_info(request.sell_token), + self.token_info_fetcher.get_token_info(request.buy_token), + ); + let sell_token_symbol = sell_token_info.ok().and_then(|info| info.symbol); + let buy_token_symbol = buy_token_info.ok().and_then(|info| info.symbol); + tracing::debug!( + ?request, + ?sell_token_symbol, + ?buy_token_symbol, + "calculating quote" + ); let full_app_data_override = match request.app_data { OrderCreationAppData::Hash { hash } => self.app_data.find(&hash).await.unwrap_or(None), @@ -95,10 +129,7 @@ impl QuoteHandler { verification: Verification { from: request.from, receiver: request.receiver.unwrap_or(request.from), - sell_token_source: request.sell_token_balance, - buy_token_destination: request.buy_token_balance, - pre_interactions: trade_finding::map_interactions(&app_data.interactions.pre), - post_interactions: trade_finding::map_interactions(&app_data.interactions.post), + app_data: Arc::new(app_data.inner.document.clone()), }, signing_scheme: request.signing_scheme, additional_gas: app_data.inner.protocol.hooks.gas_limit(), @@ -123,9 +154,15 @@ impl QuoteHandler { } }; - let adjusted_quote = - get_adjusted_quote_data("e, self.volume_fee.as_ref(), &request.side) - .map_err(|err| OrderQuoteError::CalculateQuote(err.into()))?; + let adjusted_quote = get_vol_fee_adjusted_quote_data( + "e, + &request.side, + self.volume_fee.as_ref(), + &self.volume_fee_policy, + request.buy_token, + request.sell_token, + ) + .map_err(|err| OrderQuoteError::CalculateQuote(err.into()))?; let response = OrderQuoteResponse { quote: OrderQuote { sell_token: request.sell_token, @@ -142,6 +179,20 @@ impl QuoteHandler { app_data => app_data.clone(), }, fee_amount: quote.fee_amount, + gas_amount: BigDecimal::from_f64(quote.data.fee_parameters.gas_amount).ok_or( + OrderQuoteError::CalculateQuote( + anyhow::anyhow!("gas_amount is not a valid BigDecimal").into(), + ), + )?, + gas_price: BigDecimal::from_f64(quote.data.fee_parameters.gas_price).ok_or( + OrderQuoteError::CalculateQuote( + anyhow::anyhow!("gas_price is not a valid BigDecimal").into(), + ), + )?, + sell_token_price: BigDecimal::from_f64(quote.data.fee_parameters.sell_token_price) + .ok_or(OrderQuoteError::CalculateQuote( + anyhow::anyhow!("sell_token_price is not a valid BigDecimal").into(), + ))?, kind: quote.data.kind, partially_fillable: false, sell_token_balance: request.sell_token_balance, @@ -160,17 +211,27 @@ impl QuoteHandler { } } -/// Calculates the protocol fee based on volume fee and adjusts quote amounts. -fn get_adjusted_quote_data( +/// Calculates the protocol fee based on volume fee and adjusts quote +/// amounts. +fn get_vol_fee_adjusted_quote_data( quote: &Quote, - volume_fee: Option<&VolumeFeeConfig>, side: &OrderQuoteSide, + volume_fee: Option<&VolumeFeeConfig>, + volume_fee_policy: &VolumeFeePolicy, + buy_token: alloy::primitives::Address, + sell_token: alloy::primitives::Address, ) -> anyhow::Result { - let Some(factor) = volume_fee + let Some(_) = volume_fee.as_ref() // Only apply volume fee if effective timestamp has come .filter(|config| config.effective_from_timestamp.is_none_or(|ts| ts <= Utc::now())) - .and_then(|config| config.factor) else { + return Ok(AdjustedQuoteData::unchanged(quote)); + }; + + // Determine applicable fee factor considering same-token config and overrides + let factor = volume_fee_policy.get_applicable_volume_fee_factor(buy_token, sell_token, None); + + let Some(factor) = factor else { return Ok(AdjustedQuoteData { sell_amount: quote.sell_amount, buy_amount: quote.buy_amount, @@ -180,16 +241,21 @@ fn get_adjusted_quote_data( // Calculate the volume (surplus token amount) to apply fee to // Following driver's logic in // crates/driver/src/domain/competition/solution/fee.rs:189-202: + // Use high precision scaling to support sub-basis-point fee factors (e.g., 0.3 + // BPS) + let scaled_factor = U256::from(factor.to_high_precision()); + let scale = U512::from(FeeFactor::HIGH_PRECISION_SCALE); let (adjusted_sell_amount, adjusted_buy_amount) = match side { OrderQuoteSide::Sell { .. } => { // For SELL orders, fee is calculated on buy amount - let protocol_fee = quote - .buy_amount - .full_mul(U256::from(factor.to_bps())) - .checked_div(U256::from(FeeFactor::MAX_BPS).into()) - .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))? - .try_into() - .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; + let protocol_fee = U256::uint_try_from( + quote + .buy_amount + .widening_mul(scaled_factor) + .checked_div(scale) + .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))?, + ) + .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; // Reduce buy amount by protocol fee let adjusted_buy = quote.buy_amount.saturating_sub(protocol_fee); @@ -200,12 +266,13 @@ fn get_adjusted_quote_data( // For BUY orders, fee is calculated on sell amount + network fee. // Network fee is already in sell token, so it is added to get the total volume. let total_sell_volume = quote.sell_amount.saturating_add(quote.fee_amount); - let protocol_fee = total_sell_volume - .full_mul(U256::from(factor.to_bps())) - .checked_div(U256::from(FeeFactor::MAX_BPS).into()) - .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))? - .try_into() - .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; + let volume_scaled: Uint<512, 8> = total_sell_volume.widening_mul(scaled_factor); + let protocol_fee = U256::uint_try_from( + volume_scaled + .checked_div(scale) + .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))?, + ) + .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; // Increase sell amount by protocol fee let adjusted_sell = quote.sell_amount.saturating_add(protocol_fee); @@ -217,7 +284,7 @@ fn get_adjusted_quote_data( Ok(AdjustedQuoteData { sell_amount: adjusted_sell_amount, buy_amount: adjusted_buy_amount, - protocol_fee_bps: Some(factor.to_bps().to_string()), + protocol_fee_bps: Some(factor.to_bps_str()), }) } @@ -250,22 +317,27 @@ impl From for OrderQuoteError { mod tests { use { super::*, - crate::arguments::FeeFactor, + alloy::primitives::U256, + configs::fee_factor::FeeFactor, model::quote::OrderQuoteSide, - primitive_types::U256, - shared::order_quoting::{Quote, QuoteData}, + number::units::EthUnit, + shared::{ + fee::VolumeFeePolicy, + order_quoting::{Quote, QuoteData}, + }, }; - fn to_wei(base: u32) -> U256 { - U256::from(base) * U256::from(10).pow(U256::from(18)) - } + const TEST_SELL_TOKEN: alloy::primitives::Address = + alloy::primitives::address!("0000000000000000000000000000000000000001"); + const TEST_BUY_TOKEN: alloy::primitives::Address = + alloy::primitives::address!("0000000000000000000000000000000000000002"); fn create_test_quote(sell_amount: U256, buy_amount: U256) -> Quote { Quote { id: None, data: QuoteData { - sell_token: Default::default(), - buy_token: Default::default(), + sell_token: TEST_SELL_TOKEN, + buy_token: TEST_BUY_TOKEN, quoted_sell_amount: sell_amount, quoted_buy_amount: buy_amount, fee_parameters: Default::default(), @@ -278,7 +350,7 @@ mod tests { }, sell_amount, buy_amount, - fee_amount: U256::zero(), + fee_amount: U256::ZERO, } } @@ -289,27 +361,36 @@ mod tests { factor: Some(volume_fee), effective_from_timestamp: None, }; + let volume_fee_policy = VolumeFeePolicy::new(vec![], Some(volume_fee), false); // Selling 100 tokens, expecting to buy 100 tokens - let quote = create_test_quote(to_wei(100), to_wei(100)); + let quote = create_test_quote(100u64.eth(), 100u64.eth()); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::NonZeroU256::try_from(100u64.eth()).unwrap(), }, }; - let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); + let result = get_vol_fee_adjusted_quote_data( + "e, + &side, + Some(&volume_fee_config), + &volume_fee_policy, + TEST_BUY_TOKEN, + TEST_SELL_TOKEN, + ) + .unwrap(); // For SELL orders: // - sell_amount stays the same // - buy_amount is reduced by 0.02% of original buy_amount // - protocol_fee_bps = "2" - assert_eq!(result.sell_amount, to_wei(100)); + assert_eq!(result.sell_amount, 100u64.eth()); assert_eq!(result.protocol_fee_bps, Some("2".to_string())); // buy_amount should be reduced by 0.02% // Expected: 100 - (100 * 0.0002) = 100 - 0.02 = 99.98 - let expected_buy = to_wei(100) - (to_wei(100) / U256::from(5000)); // 0.02% = 1/5000 + let expected_buy = 100u64.eth() - (100u64.eth() / U256::from(5000)); // 0.02% = 1/5000 assert_eq!(result.buy_amount, expected_buy); } @@ -322,25 +403,34 @@ mod tests { // Effective date in the past to ensure fee is applied effective_from_timestamp: Some(past_timestamp), }; + let volume_fee_policy = VolumeFeePolicy::new(vec![], Some(volume_fee), false); // Buying 100 tokens, expecting to sell 100 tokens, with no network fee - let quote = create_test_quote(to_wei(100), to_wei(100)); + let quote = create_test_quote(100u64.eth(), 100u64.eth()); let side = OrderQuoteSide::Buy { - buy_amount_after_fee: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + buy_amount_after_fee: number::nonzero::NonZeroU256::try_from(100u64.eth()).unwrap(), }; - let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); + let result = get_vol_fee_adjusted_quote_data( + "e, + &side, + Some(&volume_fee_config), + &volume_fee_policy, + TEST_BUY_TOKEN, + TEST_SELL_TOKEN, + ) + .unwrap(); // For BUY orders with no network fee: // - buy_amount stays the same // - sell_amount is increased by 0.02% of original sell_amount // - protocol_fee_bps = "2" - assert_eq!(result.buy_amount, to_wei(100)); + assert_eq!(result.buy_amount, 100u64.eth()); assert_eq!(result.protocol_fee_bps, Some("2".to_string())); // sell_amount should be increased by 0.02% of sell_amount (no network fee) // Expected: 100 + (100 * 0.0002) = 100 + 0.02 = 100.02 - let expected_sell = to_wei(100) + (to_wei(100) / U256::from(5000)); // 0.02% = 1/5000 + let expected_sell = 100u64.eth() + (100u64.eth() / U256::from(5000)); // 0.02% = 1/5000 assert_eq!(result.sell_amount, expected_sell); } @@ -351,30 +441,39 @@ mod tests { factor: Some(volume_fee), effective_from_timestamp: None, }; + let volume_fee_policy = VolumeFeePolicy::new(vec![], Some(volume_fee), false); // Buying 100 tokens, expecting to sell 100 tokens, with 5 token network fee - let mut quote = create_test_quote(to_wei(100), to_wei(100)); - quote.fee_amount = to_wei(5); // Network fee in sell token + let mut quote = create_test_quote(100u64.eth(), 100u64.eth()); + quote.fee_amount = 5u64.eth(); // Network fee in sell token let side = OrderQuoteSide::Buy { - buy_amount_after_fee: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + buy_amount_after_fee: number::nonzero::NonZeroU256::try_from(100u64.eth()).unwrap(), }; - let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); + let result = get_vol_fee_adjusted_quote_data( + "e, + &side, + Some(&volume_fee_config), + &volume_fee_policy, + TEST_BUY_TOKEN, + TEST_SELL_TOKEN, + ) + .unwrap(); // For BUY orders with network fee: // - buy_amount stays the same // - protocol fee is calculated on (sell_amount + network_fee) // - sell_amount is increased by protocol fee - assert_eq!(result.buy_amount, to_wei(100)); + assert_eq!(result.buy_amount, 100u64.eth()); assert_eq!(result.protocol_fee_bps, Some("2".to_string())); // Total volume = sell_amount + network_fee = 100 + 5 = 105 // Protocol fee = 105 * 0.0002 = 0.021 // sell_amount should be increased by protocol fee // Expected: 100 + 0.021 = 100.021 - let total_volume = to_wei(100) + to_wei(5); // 105 + let total_volume = 100u64.eth() + 5u64.eth(); // 105 let expected_protocol_fee = total_volume / U256::from(5000); // 0.021 - let expected_sell = to_wei(100) + expected_protocol_fee; // 100.021 + let expected_sell = 100u64.eth() + expected_protocol_fee; // 100.021 assert_eq!(result.sell_amount, expected_sell); } @@ -385,22 +484,31 @@ mod tests { factor: Some(volume_fee), effective_from_timestamp: None, }; + let volume_fee_policy = VolumeFeePolicy::new(vec![], Some(volume_fee), false); // Selling 100 tokens, expecting to buy 200 tokens (2:1 price ratio) - let quote = create_test_quote(to_wei(100), to_wei(200)); + let quote = create_test_quote(100u64.eth(), 200u64.eth()); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::NonZeroU256::try_from(100u64.eth()).unwrap(), }, }; - let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); + let result = get_vol_fee_adjusted_quote_data( + "e, + &side, + Some(&volume_fee_config), + &volume_fee_policy, + TEST_BUY_TOKEN, + TEST_SELL_TOKEN, + ) + .unwrap(); assert_eq!(result.protocol_fee_bps, Some("10".to_string())); - assert_eq!(result.sell_amount, to_wei(100)); + assert_eq!(result.sell_amount, 100u64.eth()); // buy_amount reduced by 0.1% of 200 = 0.2 tokens - let expected_buy = to_wei(200) - (to_wei(200) / U256::from(1000)); + let expected_buy = 200u64.eth() - (200u64.eth() / U256::from(1000)); assert_eq!(result.buy_amount, expected_buy); } @@ -420,15 +528,24 @@ mod tests { factor: Some(volume_fee), effective_from_timestamp: None, }; + let volume_fee_policy = VolumeFeePolicy::new(vec![], Some(volume_fee), false); - let quote = create_test_quote(to_wei(100), to_wei(100)); + let quote = create_test_quote(100u64.eth(), 100u64.eth()); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::NonZeroU256::try_from(100u64.eth()).unwrap(), }, }; - let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); + let result = get_vol_fee_adjusted_quote_data( + "e, + &side, + Some(&volume_fee_config), + &volume_fee_policy, + TEST_BUY_TOKEN, + TEST_SELL_TOKEN, + ) + .unwrap(); assert_eq!(result.protocol_fee_bps, Some(expected_bps.to_string())); } @@ -442,20 +559,70 @@ mod tests { factor: Some(volume_fee), effective_from_timestamp: Some(future_timestamp), }; + let volume_fee_policy = VolumeFeePolicy::new(vec![], Some(volume_fee), false); // Selling 100 tokens, expecting to buy 100 tokens - let quote = create_test_quote(to_wei(100), to_wei(100)); + let quote = create_test_quote(100u64.eth(), 100u64.eth()); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::NonZeroU256::try_from(100u64.eth()).unwrap(), }, }; - let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); + let result = get_vol_fee_adjusted_quote_data( + "e, + &side, + Some(&volume_fee_config), + &volume_fee_policy, + TEST_BUY_TOKEN, + TEST_SELL_TOKEN, + ) + .unwrap(); // Since the effective date is in the future, no volume fee should be applied - assert_eq!(result.sell_amount, to_wei(100)); - assert_eq!(result.buy_amount, to_wei(100)); + assert_eq!(result.sell_amount, 100u64.eth()); + assert_eq!(result.buy_amount, 100u64.eth()); assert_eq!(result.protocol_fee_bps, None); } + + #[test] + fn test_volume_fee_sub_basis_point_precision() { + // Test sub-BPS precision: 0.00003 = 0.3 BPS + let volume_fee = FeeFactor::try_from(0.00003).unwrap(); + let volume_fee_config = VolumeFeeConfig { + factor: Some(volume_fee), + effective_from_timestamp: None, + }; + let volume_fee_policy = VolumeFeePolicy::new(vec![], Some(volume_fee), false); + + // Large amount to make the sub-BPS fee visible + let sell_amount = 1_000_000u64.eth(); + let buy_amount = 1_000_000u64.eth(); + let quote = create_test_quote(sell_amount, buy_amount); + let side = OrderQuoteSide::Sell { + sell_amount: model::quote::SellAmount::BeforeFee { + value: number::nonzero::NonZeroU256::try_from(sell_amount).unwrap(), + }, + }; + + let result = get_vol_fee_adjusted_quote_data( + "e, + &side, + Some(&volume_fee_config), + &volume_fee_policy, + TEST_BUY_TOKEN, + TEST_SELL_TOKEN, + ) + .unwrap(); + + // Protocol fee = 0.3 BPS + assert_eq!(result.protocol_fee_bps, Some("0.3".to_string())); + assert_eq!(result.sell_amount, sell_amount); + + // Expected fee: 1_000_000 * 0.00003 = 30 tokens + // buy_amount should be reduced by 30 tokens + let expected_fee = 30u64.eth(); + let expected_buy = buy_amount - expected_fee; + assert_eq!(result.buy_amount, expected_buy); + } } diff --git a/crates/orderbook/src/run.rs b/crates/orderbook/src/run.rs index cff280fe87..dd8767b7c1 100644 --- a/crates/orderbook/src/run.rs +++ b/crates/orderbook/src/run.rs @@ -8,108 +8,125 @@ use { orderbook::Orderbook, quoter::QuoteHandler, }, + account_balances::{self, BalanceSimulator}, alloy::providers::Provider, anyhow::{Context, Result, anyhow}, app_data::Validator, + bad_tokens::list_based::DenyListedTokens, chain::Chain, clap::Parser, - contracts::alloy::{ + configs::orderbook::Configuration, + contracts::{ BalancerV2Vault, ChainalysisOracle, + FlashLoanRouter, GPv2Settlement, HooksTrampoline, - IUniswapV3Factory, - InstanceExt, WETH9, support::Balances, }, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - futures::{FutureExt, StreamExt}, - model::{DomainSeparator, order::BUY_ETH_ADDRESS}, + gas_price_estimation::gas_price::InstrumentedGasEstimator, + http_client::HttpClientFactory, + model::DomainSeparator, num::ToPrimitive, - observe::metrics::{DEFAULT_METRICS_PORT, serve_metrics}, + observe::{ + config::EventBusConfig, + metrics::{DEFAULT_METRICS_PORT, serve_metrics}, + }, order_validation, + price_estimation::{ + PriceEstimating, + config::price_estimation::BalanceOverridesConfigExt, + factory::{self, PriceEstimatorFactory}, + native::{FallbackNativePriceEstimator, NativePriceEstimating}, + }, shared::{ - account_balances::{self, BalanceSimulator}, - arguments::tracing_config, - bad_token::{ - cache::CachingDetector, - instrumented::InstrumentedBadTokenDetectorExt, - list_based::{ListBasedDetector, UnknownTokenStrategy}, - token_owner_finder, - trace_call::TraceCallDetector, - }, - baseline_solver::BaseTokens, - code_fetching::CachedCodeFetcher, - gas_price::InstrumentedGasEstimator, - http_client::HttpClientFactory, order_quoting::{self, OrderQuoter}, - order_validation::{OrderValidPeriodConfiguration, OrderValidator}, - price_estimation::{ - PriceEstimating, - QuoteVerificationMode, - factory::{self, PriceEstimatorFactory}, - native::NativePriceEstimating, - }, - signature_validator, - sources::{self, BaselineSource, uniswap_v2::UniV2BaselineSourceParameters}, - token_info::{CachedTokenInfoFetcher, TokenInfoFetcher}, + order_validation::{OrderSimulator, OrderValidPeriodConfiguration, OrderValidator}, }, - std::{convert::Infallible, future::Future, net::SocketAddr, sync::Arc, time::Duration}, + std::{future::Future, net::SocketAddr, sync::Arc, time::Duration}, + token_info::{CachedTokenInfoFetcher, TokenInfoFetcher}, tokio::task::{self, JoinHandle}, - warp::Filter, }; pub async fn start(args: impl Iterator) { let args = Arguments::parse_from(args); + let config = Configuration::from_path(&args.config) + .await + .expect("failed to load configuration file") + .validate() + .expect("failed to validate configuration file"); + let tracing_config = config + .shared + .tracing + .collector_endpoint + .as_ref() + .map(|endpoint| { + observe::TracingConfig::new( + endpoint.clone(), + "orderbook".into(), + config.shared.tracing.exporter_timeout, + config.shared.tracing.level, + ) + }); let obs_config = observe::Config::new( - args.shared.logging.log_filter.as_str(), - args.shared.logging.log_stderr_threshold, - args.shared.logging.use_json_logs, - tracing_config(&args.shared.tracing, "orderbook".into()), + config.shared.logging.filter.as_str(), + config.shared.logging.stderr_threshold, + config.shared.logging.use_json, + tracing_config, ); - observe::tracing::initialize(&obs_config); + observe::tracing::init::initialize(&obs_config); tracing::info!("running order book with validated arguments:\n{}", args); observe::panic_hook::install(); observe::metrics::setup_registry(Some("gp_v2_api".into()), None); - run(args).await; + if let Some(event_bus) = &config.shared.event_bus { + observe::event_bus::init(EventBusConfig { + url: event_bus.url.clone(), + stream_name: event_bus.channel.clone(), + // Presence of `chain-id` alongside `event_bus` is enforced by + // `SharedConfig::validate` at startup. + chain_id: config.shared.chain_id.unwrap(), + }) + .await; + } + #[cfg(unix)] + observe::heap_dump_handler::spawn_heap_dump_handler(); + tracing::info!("file configuration:\n{:#?}", config); + run(config).await; } -pub async fn run(args: Arguments) { - let http_factory = HttpClientFactory::new(&args.http_client); +pub async fn run(config: Configuration) { + let http_factory = HttpClientFactory::from(config.http_client); - let web3 = shared::ethrpc::web3( - &args.shared.ethrpc, - &http_factory, - &args.shared.node_url, - "base", - ); - let simulation_web3 = args.shared.simulation_node_url.as_ref().map(|node_url| { - shared::ethrpc::web3(&args.shared.ethrpc, &http_factory, node_url, "simulation") - }); + let ethrpc_args = shared::web3::Arguments::from(&config.shared.ethrpc); + let web3 = shared::web3::web3(ðrpc_args, &config.shared.node_url, "base"); + let simulation_web3 = config + .shared + .simulation_node_url + .as_ref() + .map(|node_url| shared::web3::web3(ðrpc_args, node_url, "simulation")); let chain_id = web3 - .eth() - .chain_id() + .provider + .get_chain_id() .await - .expect("Could not get chainId") - .as_u64(); - if let Some(expected_chain_id) = args.shared.chain_id { + .expect("Could not get chainId"); + if let Some(expected_chain_id) = config.shared.chain_id { assert_eq!( chain_id, expected_chain_id, "connected to node with incorrect chain ID", ); } - let settlement_contract = match args.shared.settlement_contract_address { - Some(address) => GPv2Settlement::Instance::new(address.into_alloy(), web3.alloy.clone()), - None => GPv2Settlement::Instance::deployed(&web3.alloy) + let settlement_contract = match config.shared.contracts.settlement { + Some(address) => GPv2Settlement::Instance::new(address, web3.provider.clone()), + None => GPv2Settlement::Instance::deployed(&web3.provider) .await .expect("load settlement contract"), }; - let balances_contract = match args.shared.balances_contract_address { - Some(address) => Balances::Instance::new(address, web3.alloy.clone()), - None => Balances::Instance::deployed(&web3.alloy.clone()) + let balances_contract = match config.shared.contracts.balances { + Some(address) => Balances::Instance::new(address, web3.provider.clone()), + None => Balances::Instance::deployed(&web3.provider.clone()) .await .expect("load balances contract"), }; @@ -118,36 +135,35 @@ pub async fn run(args: Arguments) { .call() .await .expect("Couldn't get vault relayer address"); - let signatures_contract = match args.shared.signatures_contract_address { - Some(address) => contracts::alloy::support::Signatures::Instance::new( - address.into_alloy(), - web3.alloy.clone(), - ), - None => contracts::alloy::support::Signatures::Instance::deployed(&web3.alloy) + let signatures_contract = match config.shared.contracts.signatures { + Some(address) => { + contracts::support::Signatures::Instance::new(address, web3.provider.clone()) + } + None => contracts::support::Signatures::Instance::deployed(&web3.provider) .await .expect("load signatures contract"), }; - let native_token = match args.shared.native_token_address { - Some(address) => WETH9::Instance::new(address, web3.alloy.clone()), - None => WETH9::Instance::deployed(&web3.alloy) + let native_token = match config.shared.contracts.native_token { + Some(address) => WETH9::Instance::new(address, web3.provider.clone()), + None => WETH9::Instance::deployed(&web3.provider) .await .expect("load native token contract"), }; let chain = Chain::try_from(chain_id).expect("incorrect chain ID"); - let balance_overrider = args.price_estimation.balance_overrides.init(web3.clone()); + let balance_overrider = config.price_estimation.balance_overrides.init(web3.clone()); let signature_validator = signature_validator::validator( &web3, signature_validator::Contracts { settlement: settlement_contract.clone(), signatures: signatures_contract, - vault_relayer: vault_relayer.into_legacy(), + vault_relayer, }, balance_overrider.clone(), ); - let vault_address = args.shared.balancer_v2_vault_address.or_else(|| { + let vault_address = config.shared.contracts.balancer_v2_vault.or_else(|| { let chain_id = chain.id(); match BalancerV2Vault::deployment_address(&chain_id) { addr @ Some(_) => addr, @@ -160,28 +176,38 @@ pub async fn run(args: Arguments) { } } }); - let vault = - vault_address.map(|address| BalancerV2Vault::Instance::new(address, web3.alloy.clone())); - let hooks_contract = match args.shared.hooks_contract_address { - Some(address) => HooksTrampoline::Instance::new(address.into_alloy(), web3.alloy.clone()), - None => HooksTrampoline::Instance::deployed(&web3.alloy) + let hooks_contract = match config.shared.contracts.hooks { + Some(address) => HooksTrampoline::Instance::new(address, web3.provider.clone()), + None => HooksTrampoline::Instance::deployed(&web3.provider) .await .expect("load hooks trampoline contract"), }; + let hooks_trampoline_address = *hooks_contract.address(); + + let flashloan_router_address = config + .shared + .contracts + .flashloan_router + .or_else(|| FlashLoanRouter::deployment_address(&chain_id)) + .expect("no flashloan router deployment for this chain"); verify_deployed_contract_constants(&settlement_contract, chain_id) .await .expect("Deployed contract constants don't match the ones in this binary"); - let domain_separator = - DomainSeparator::new(chain_id, settlement_contract.address().into_legacy()); - let postgres_write = - Postgres::try_new(args.db_write_url.as_str()).expect("failed to create database"); + let domain_separator = DomainSeparator::new(chain_id, *settlement_contract.address()); + let db_config = crate::database::Config { + max_pool_size: config.database.max_connections.get(), + statement_timeout: config.database.statement_timeout, + }; + let postgres_write = Postgres::try_new(config.database.write_url.as_str(), db_config.clone()) + .expect("failed to create database"); - let postgres_read = if let Some(db_read_url) = args.db_read_url - && args.db_write_url != db_read_url + let postgres_read = if let Some(db_read_url) = config.database.read_url + && config.database.write_url != db_read_url { - Postgres::try_new(db_read_url.as_str()).expect("failed to create read replica databaseR") + Postgres::try_new_with_timeout(db_read_url.as_str(), db_config) + .expect("failed to create read replica database") } else { postgres_write.clone() }; @@ -191,101 +217,33 @@ pub async fn run(args: Arguments) { BalanceSimulator::new( settlement_contract.clone(), balances_contract.clone(), - vault_relayer.into_legacy(), - vault_address.map(IntoLegacy::into_legacy), - balance_overrider, + vault_relayer, + vault_address, + balance_overrider.clone(), ), ); + let gas_estimators: Vec = config + .shared + .gas_estimators + .iter() + .map(shared::arguments::gas_estimator_type_from_config) + .collect(); let gas_price_estimator = Arc::new(InstrumentedGasEstimator::new( - shared::gas_price_estimation::create_priority_estimator( - &http_factory, + gas_price_estimation::create_priority_estimator( + http_factory.create(), &web3, - args.shared.gas_estimators.as_slice(), + &gas_estimators, ) .await .expect("failed to create gas price estimator"), )); - let baseline_sources = args - .shared - .baseline_sources - .clone() - .unwrap_or_else(|| sources::defaults_for_network(&chain)); - tracing::info!(?baseline_sources, "using baseline sources"); - let univ2_sources = baseline_sources - .iter() - .filter_map(|source: &BaselineSource| { - UniV2BaselineSourceParameters::from_baseline_source(*source, &chain_id.to_string()) - }) - .chain(args.shared.custom_univ2_baseline_sources.iter().copied()); - let pair_providers: Vec<_> = futures::stream::iter(univ2_sources) - .then(|source: UniV2BaselineSourceParameters| { - let web3 = &web3; - async move { source.into_source(web3).await.unwrap().pair_provider } - }) - .collect() - .await; - - let base_tokens = Arc::new(BaseTokens::new( - native_token.address().into_legacy(), - &args.shared.base_tokens, - )); - let mut allowed_tokens = args.allowed_tokens.clone(); - allowed_tokens.extend(base_tokens.tokens().iter().map(|t| t.into_alloy())); - allowed_tokens.push(BUY_ETH_ADDRESS.into_alloy()); - let unsupported_tokens = args.unsupported_tokens.clone(); - - let uniswapv3_factory = IUniswapV3Factory::Instance::deployed(&web3.alloy) - .await - .inspect_err(|err| tracing::warn!(%err, "error while fetching IUniswapV3Factory instance")) - .ok(); - - let finder = token_owner_finder::init( - &args.token_owner_finder, - web3.clone(), - &chain, - &http_factory, - &pair_providers, - vault.as_ref(), - uniswapv3_factory.as_ref(), - &base_tokens, - settlement_contract.address().into_legacy(), - ) - .await - .expect("failed to initialize token owner finders"); - - let trace_call_detector = args.tracing_node_url.as_ref().map(|tracing_node_url| { - CachingDetector::new( - Box::new(TraceCallDetector::new( - shared::ethrpc::web3( - &args.shared.ethrpc, - &http_factory, - tracing_node_url, - "trace", - ), - settlement_contract.address().into_legacy(), - finder, - )), - args.shared.token_quality_cache_expiry, - args.shared.token_quality_cache_prefetch_time, - ) - }); - let bad_token_detector = Arc::new( - ListBasedDetector::new( - allowed_tokens, - unsupported_tokens, - trace_call_detector - .map(|detector| UnknownTokenStrategy::Forward(detector)) - .unwrap_or(UnknownTokenStrategy::Allow), - ) - .instrumented(), - ); + let deny_listed_tokens = DenyListedTokens::new(config.unsupported_tokens); - let current_block_stream = args - .shared - .current_block - .stream(args.shared.node_url.clone(), web3.alloy.clone()) + let current_block_args = shared::current_block::Arguments::from(&config.shared.current_block); + let current_block_stream = current_block_args + .stream(config.shared.node_url.clone(), web3.provider.clone()) .await .unwrap(); @@ -293,60 +251,82 @@ pub async fn run(args: Arguments) { web3: web3.clone(), }))); - let code_fetcher = Arc::new(CachedCodeFetcher::new(Arc::new(web3.clone()))); - let mut price_estimator_factory = PriceEstimatorFactory::new( - &args.price_estimation, - &args.shared, + &config.price_estimation, + &config.native_price_estimation.shared, factory::Network { web3: web3.clone(), simulation_web3, chain, - settlement: settlement_contract.address().into_legacy(), - native_token: native_token.address().into_legacy(), + settlement: *settlement_contract.address(), + native_token: *native_token.address(), authenticator: settlement_contract .authenticator() .call() .await - .expect("failed to query solver authenticator address") - .into_legacy(), - base_tokens: base_tokens.clone(), + .expect("failed to query solver authenticator address"), block_stream: current_block_stream.clone(), + flash_loan_router: flashloan_router_address, + hooks_trampoline: hooks_trampoline_address, }, factory::Components { - http_factory: http_factory.clone(), - bad_token_detector: bad_token_detector.clone(), + http_factory: http_client::HttpClientFactory::new(&configs::http_client::HttpClient { + timeout: http_factory.timeout, + }), + deny_listed_tokens: deny_listed_tokens.clone(), tokens: token_info_fetcher.clone(), - code_fetcher: code_fetcher.clone(), }, ) .await .expect("failed to initialize price estimator factory"); - let native_price_estimator = price_estimator_factory + let prices = postgres_write.fetch_latest_prices().await.unwrap(); + let cache = price_estimation::native_price_cache::Cache::new( + config.native_price_estimation.shared.cache.max_age, + prices, + ); + let primary = price_estimator_factory .native_price_estimator( - args.native_price_estimators.as_slice(), - args.fast_price_estimation_results_required, - native_token.clone(), + config.native_price_estimation.estimators.as_slice(), + config.native_price_estimation.shared.results_required, + &native_token, ) .await - .unwrap(); - let prices = postgres_write - .fetch_latest_prices() - .await - .unwrap() - .into_iter() - .map(|(k, v)| (k.into_legacy(), v)) - .collect(); - native_price_estimator.initialize_cache(prices); + .expect("failed to build primary native price estimator"); + + let inner: Box = + if let Some(ref fallback_config) = config.native_price_estimation.fallback_estimators { + let fallback = price_estimator_factory + .native_price_estimator( + fallback_config.as_slice(), + config.native_price_estimation.shared.results_required, + &native_token, + ) + .await + .expect("failed to build fallback native price estimator"); + Box::new(FallbackNativePriceEstimator::new(primary, fallback)) + } else { + primary + }; + + let native_price_estimator: Arc = Arc::new( + price_estimator_factory + .caching_native_price_estimator_from_inner(inner, cache) + .await, + ); let price_estimator = price_estimator_factory .price_estimator( - &args + &config .order_quoting .price_estimation_drivers .iter() - .map(|price_estimator| price_estimator.clone().into()) + .map( + |price_estimator_driver| configs::native_price_estimators::ExternalSolver { + name: price_estimator_driver.name.clone(), + url: price_estimator_driver.url.clone(), + }, + ) .collect::>(), native_price_estimator.clone(), gas_price_estimator.clone(), @@ -354,26 +334,30 @@ pub async fn run(args: Arguments) { .unwrap(); let fast_price_estimator = price_estimator_factory .fast_price_estimator( - &args + &config .order_quoting .price_estimation_drivers .iter() - .map(|price_estimator| price_estimator.clone().into()) + .map( + |price_estimator_driver| configs::native_price_estimators::ExternalSolver { + name: price_estimator_driver.name.clone(), + url: price_estimator_driver.url.clone(), + }, + ) .collect::>(), - args.fast_price_estimation_results_required, + config.native_price_estimation.shared.results_required, native_price_estimator.clone(), gas_price_estimator.clone(), ) .unwrap(); let validity_configuration = OrderValidPeriodConfiguration { - min: args.min_order_validity_period, - max_market: args.max_order_validity_period, - max_limit: args.max_limit_order_validity_period, + min: config.order_validation.min_order_validity_period, + max_market: config.order_validation.max_order_validity_period, + max_limit: config.order_validation.max_limit_order_validity_period, }; - let create_quoter = |price_estimator: Arc, - verification: QuoteVerificationMode| { + let create_quoter = |price_estimator: Arc| { Arc::new(OrderQuoter::new( price_estimator, native_price_estimator.clone(), @@ -381,63 +365,81 @@ pub async fn run(args: Arguments) { Arc::new(postgres_write.clone()), order_quoting::Validity { eip1271_onchain_quote: chrono::Duration::from_std( - args.order_quoting.eip1271_onchain_quote_validity, + config.order_quoting.eip1271_onchain_quote_validity, ) .unwrap(), presign_onchain_quote: chrono::Duration::from_std( - args.order_quoting.presign_onchain_quote_validity, + config.order_quoting.presign_onchain_quote_validity, ) .unwrap(), standard_quote: chrono::Duration::from_std( - args.order_quoting.standard_offchain_quote_validity, + config.order_quoting.standard_offchain_quote_validity, ) .unwrap(), }, - balance_fetcher.clone(), - verification, - args.price_estimation.quote_timeout, + config.price_estimation.quote_timeout, + config.price_estimation.max_quote_timeout, )) }; - let optimal_quoter = create_quoter(price_estimator, args.price_estimation.quote_verification); + let optimal_quoter = create_quoter(price_estimator); // Fast quoting is able to return early and if none of the produced quotes are // verifiable we are left with no quote at all. Since fast estimates don't // make any promises on correctness we can just skip quote verification for // them. - let fast_quoter = create_quoter(fast_price_estimator, QuoteVerificationMode::Unverified); + let fast_quoter = create_quoter(fast_price_estimator); - let app_data_validator = Validator::new(args.app_data_size_limit); - let chainalysis_oracle = ChainalysisOracle::Instance::deployed(&web3.alloy) + let app_data_validator = Validator::new(config.app_data_size_limit); + let chainalysis_oracle = ChainalysisOracle::Instance::deployed(&web3.provider) .await .ok(); + + let order_simulator = price_estimator_factory.settlement_simulator().cloned(); + + let validator_simulator = order_simulator.clone().map(|settlement_simulator| { + let simulator: Arc = Arc::new( + shared::order_creation_simulation::OrderCreationSimulator::new(settlement_simulator), + ); + OrderSimulator { + simulator, + timeout: config.order_simulation_timeout, + } + }); + let order_validator = Arc::new(OrderValidator::new( native_token.clone(), Arc::new(order_validation::banned::Users::new( chainalysis_oracle, - args.banned_users, - args.banned_users_max_cache_size.get().to_u64().unwrap(), + config.banned_users.hermod.clone().map(|hermod| { + order_validation::banned::HermodConfig { + url: hermod.url, + hmac_key: hermod.hmac_key, + api_key: hermod.api_key, + } + }), + config.banned_users.addresses, + config.banned_users.max_cache_size.get().to_u64().unwrap(), )), validity_configuration, - args.eip1271_skip_creation_validation, - bad_token_detector.clone(), + config.eip1271_skip_creation_validation, + deny_listed_tokens.clone(), hooks_contract, optimal_quoter.clone(), balance_fetcher, signature_validator, + validator_simulator, Arc::new(postgres_write.clone()), - args.max_limit_orders_per_user, - code_fetcher, + config.order_validation.max_limit_orders_per_user, app_data_validator.clone(), - args.max_gas_per_order, + config.order_validation.max_gas_per_order, + config.order_validation.same_tokens_policy, )); - let ipfs = args - .ipfs_gateway - .map(|url| { - Ipfs::new( - http_factory.builder(), - url, - args.ipfs_pinata_auth - .map(|auth| format!("pinataGatewayToken={auth}")), - ) + let ipfs = config + .ipfs + .map(|ipfs| { + let pinata_query = ipfs + .auth_token + .map(|auth| format!("pinataGatewayToken={auth}")); + Ipfs::new(http_factory.builder(), ipfs.gateway, pinata_query) }) .map(IpfsAppData::new); let app_data = Arc::new(crate::app_data::Registry::new( @@ -445,26 +447,35 @@ pub async fn run(args: Arguments) { postgres_write.clone(), ipfs, )); + let orderbook = Arc::new(Orderbook::new( domain_separator, - settlement_contract.address().into_legacy(), + *settlement_contract.address(), postgres_write.clone(), postgres_read.clone(), order_validator.clone(), app_data.clone(), - args.active_order_competition_threshold, + config.active_order_competition_threshold, + order_simulator, )); check_database_connection(orderbook.as_ref()).await; - let quotes = Arc::new( - QuoteHandler::new( - order_validator, - optimal_quoter, - app_data.clone(), - args.volume_fee_config, - ) - .with_fast_quoter(fast_quoter), - ); + let volume_fee_bucket_overrides: Vec = config + .shared + .volume_fee_bucket_overrides + .iter() + .map(Into::into) + .collect(); + let quotes = QuoteHandler::new( + order_validator, + optimal_quoter, + app_data.clone(), + config.volume_fee, + volume_fee_bucket_overrides, + config.shared.enable_sell_equals_buy_volume_fee, + token_info_fetcher.clone(), + ) + .with_fast_quoter(fast_quoter); let (shutdown_sender, shutdown_receiver) = tokio::sync::oneshot::channel(); let serve_api = serve_api( @@ -473,15 +484,17 @@ pub async fn run(args: Arguments) { orderbook.clone(), quotes, app_data, - args.bind_address, + config.bind_address, async { let _ = shutdown_receiver.await; }, native_price_estimator, - args.price_estimation.quote_timeout, + config.price_estimation.quote_timeout, + current_block_stream, + config.hide_competition_before_deadline, ); - let mut metrics_address = args.bind_address; + let mut metrics_address = config.bind_address; metrics_address.set_port(DEFAULT_METRICS_PORT); tracing::info!(%metrics_address, "serving metrics"); let metrics_task = serve_metrics( @@ -545,14 +558,16 @@ fn serve_api( database: Postgres, database_replica: Postgres, orderbook: Arc, - quotes: Arc, + quotes: QuoteHandler, app_data: Arc, address: SocketAddr, shutdown_receiver: impl Future + Send + 'static, native_price_estimator: Arc, quote_timeout: Duration, + current_block_stream: ethrpc::block_stream::CurrentBlockWatcher, + hide_competition_before_deadline: bool, ) -> JoinHandle<()> { - let filter = api::handle_all_routes( + let app = api::handle_all_routes( database, database_replica, orderbook, @@ -560,19 +575,26 @@ fn serve_api( app_data, native_price_estimator, quote_timeout, - ) - .boxed(); + current_block_stream, + hide_competition_before_deadline, + ); tracing::info!(%address, "serving order book"); - let warp_svc = warp::service(filter); - let make_svc = hyper::service::make_service_fn(move |_| { - let svc = warp_svc.clone(); - async move { Ok::<_, Infallible>(svc) } - }); - let server = hyper::Server::bind(&address) - .serve(make_svc) - .with_graceful_shutdown(shutdown_receiver) - .map(|_| ()); - task::spawn(server) + + task::spawn(async move { + let listener = match tokio::net::TcpListener::bind(address).await { + Ok(listener) => listener, + Err(err) => { + tracing::error!(?err, "failed to bind server"); + return; + } + }; + if let Err(err) = axum::serve(listener, app) + .with_graceful_shutdown(shutdown_receiver) + .await + { + tracing::error!(?err, "server error"); + } + }) } /// Check that important constants such as the EIP 712 Domain Separator and @@ -592,7 +614,7 @@ async fn verify_deployed_contract_constants( .0, ); - let domain_separator = DomainSeparator::new(chain_id, contract.address().into_legacy()); + let domain_separator = DomainSeparator::new(chain_id, *contract.address()); if !bytecode.contains(&const_hex::encode(domain_separator.0)) { return Err(anyhow!("Bytecode did not contain domain separator")); } diff --git a/crates/orderbook/src/solver_competition.rs b/crates/orderbook/src/solver_competition.rs index 9cd1c2c2e0..5ca19dc995 100644 --- a/crates/orderbook/src/solver_competition.rs +++ b/crates/orderbook/src/solver_competition.rs @@ -21,16 +21,22 @@ pub trait SolverCompetitionStoring: Send + Sync { /// /// Returns a `NotFound` error if no solver competition with that ID could /// be found. + /// When `after_block` is `Some`, competitions whose deadline hasn't + /// passed are treated as not found. async fn load_competition( &self, identifier: Identifier, - ) -> Result; + after_block: Option, + ) -> Result; /// Retrieves the solver competition for the most recent auction. /// /// Returns a `NotFound` error if no solver competition could be found. + /// When `after_block` is `Some`, only auctions whose deadline has passed + /// are considered. async fn load_latest_competition( &self, + after_block: Option, ) -> Result; /// Retrieves the solver competitions for the most recent auctions. diff --git a/crates/pool-indexer/Cargo.toml b/crates/pool-indexer/Cargo.toml new file mode 100644 index 0000000000..2beb71e383 --- /dev/null +++ b/crates/pool-indexer/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "pool-indexer" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "GPL-3.0-or-later" + +[lib] +doctest = false +name = "pool_indexer" +path = "src/lib.rs" + +[[bin]] +name = "pool-indexer" +path = "src/main.rs" + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true, features = ["serde", "std"] } +alloy-provider = { workspace = true } +alloy-rpc-types-eth = { workspace = true } +alloy-sol-types = { workspace = true } +alloy-transport = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +axum = { workspace = true } +bigdecimal = { workspace = true } +clap = { workspace = true } +configs = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +futures = { workspace = true } +itertools = { workspace = true } +mimalloc = { workspace = true, optional = true } +num = { workspace = true } +number = { workspace = true } +observe = { workspace = true } +prometheus = { workspace = true } +prometheus-metric-storage = { workspace = true } +reqwest = { workspace = true, features = ["json"] } +scopeguard = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +shared = { workspace = true } +sqlx = { workspace = true } +tikv-jemallocator = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "sync", "time"] } +toml = { workspace = true } +tower = { workspace = true } +tower-http = { workspace = true, features = ["trace"] } +tracing = { workspace = true } +url = { workspace = true } + +[features] +mimalloc-allocator = ["dep:mimalloc"] +tokio-console = ["observe/tokio-console"] + +[lints] +workspace = true diff --git a/crates/pool-indexer/README.md b/crates/pool-indexer/README.md new file mode 100644 index 0000000000..c5f6ad583c --- /dev/null +++ b/crates/pool-indexer/README.md @@ -0,0 +1,28 @@ +# pool-indexer + +Indexes Uniswap V3 pools, ticks, and pool state into Postgres and serves +the data over HTTP. The driver consumes this API in place of a +third-party Uniswap V3 subgraph. + +For each (chain, factory) pair, the indexer seeds its DB from a subgraph +at a fixed block, catches up to the chain tip via RPC events, then stays +live by polling new blocks. Drivers consume it via the `pool-indexer-url` +field in their Uniswap V3 liquidity config. + +## Running locally + +Create `crates/pool-indexer/config.local.toml` first (schema = the +`Configuration` struct in `src/config.rs`): a `[database]` section, one +`[network]` block with a single factory, and optional `[api]` / `[metrics]` +sections. String fields accept `%ENV_VAR` so secrets can come from the +environment instead of being written into the file. + +Then, from the repository root, reset the local stack and start the indexer: + +```bash +# wipes the local DB — dev machines only +docker compose down --volumes +docker compose up -d db +docker compose run --rm migrations +cargo run --release -p pool-indexer -- --config crates/pool-indexer/config.local.toml +``` diff --git a/crates/pool-indexer/src/api/mod.rs b/crates/pool-indexer/src/api/mod.rs new file mode 100644 index 0000000000..7bd0c5cb91 --- /dev/null +++ b/crates/pool-indexer/src/api/mod.rs @@ -0,0 +1,64 @@ +pub mod routes; +pub mod uniswap_v3; + +pub use routes::router; +use { + crate::config::NetworkName, + axum::{ + http::StatusCode, + response::{IntoResponse, Response}, + }, + sqlx::PgPool, +}; + +#[derive(Clone)] +pub struct AppState { + pub db: PgPool, + /// The network this process indexes. Requests whose `{network}` path + /// segment doesn't match get a 404. + pub network: NetworkName, +} + +impl AppState { + pub fn is_network_configured(&self, name: &str) -> bool { + self.network.as_str() == name + } +} + +/// Errors a handler can return. Input-shape errors (bad addresses, cursors, +/// too many ids) get rejected by the serde extractors and come back as +/// axum's default 400s before any handler runs. +#[derive(Debug)] +pub enum ApiError { + /// `{network}` path segment doesn't match this process's network. + NetworkNotFound, + /// No checkpoint yet — indexer is still bootstrapping. 503 so clients + /// retry instead of caching an empty response. + NotReady, + Internal(anyhow::Error), +} + +impl IntoResponse for ApiError { + fn into_response(self) -> Response { + match self { + Self::NetworkNotFound => StatusCode::NOT_FOUND.into_response(), + Self::NotReady => StatusCode::SERVICE_UNAVAILABLE.into_response(), + Self::Internal(err) => { + tracing::error!(?err, "internal error"); + StatusCode::INTERNAL_SERVER_ERROR.into_response() + } + } + } +} + +impl From for ApiError { + fn from(err: anyhow::Error) -> Self { + Self::Internal(err) + } +} + +pub(super) async fn latest_indexed_block(state: &AppState) -> Result { + crate::db::uniswap_v3::get_latest_indexed_block(&state.db) + .await? + .ok_or(ApiError::NotReady) +} diff --git a/crates/pool-indexer/src/api/routes.rs b/crates/pool-indexer/src/api/routes.rs new file mode 100644 index 0000000000..8e95733e20 --- /dev/null +++ b/crates/pool-indexer/src/api/routes.rs @@ -0,0 +1,80 @@ +//! HTTP routing for the pool-indexer API. + +use { + super::{ApiError, AppState, uniswap_v3}, + axum::{ + Router, + extract::{MatchedPath, Path, Request, State}, + http::StatusCode, + middleware::{self, Next}, + response::{IntoResponse, Response}, + routing::get, + }, + observe::tracing::distributed::axum::{make_span, record_trace_id}, + std::{collections::HashMap, sync::Arc}, + tower::ServiceBuilder, + tower_http::trace::TraceLayer, +}; + +/// Builds the axum `Router` for the pool-indexer API, and mounts +/// the routes and the metrics middleware. +pub fn router(state: Arc) -> Router { + let v3_routes = Router::new() + .route("/pools", get(uniswap_v3::get_pools)) + .route("/pools/by-ids", get(uniswap_v3::get_pools_by_ids)) + .route("/pools/ticks", get(uniswap_v3::get_ticks_bulk)) + .route("/pools/{pool_address}/ticks", get(uniswap_v3::get_ticks)) + .route_layer(middleware::from_fn_with_state(state.clone(), network_guard)); + + Router::new() + .route("/health", get(health)) + .nest("/api/v1/{network}/uniswap/v3", v3_routes) + .with_state(state) + .layer(middleware::from_fn(record_request_metrics)) + .layer( + ServiceBuilder::new() + .layer(TraceLayer::new_for_http().make_span_with(make_span)) + .map_request(record_trace_id), + ) +} + +async fn health() -> impl IntoResponse { + StatusCode::OK +} + +/// 404s requests whose `{network}` segment doesn't match this process. +async fn network_guard( + State(state): State>, + Path(params): Path>, + req: Request, + next: Next, +) -> Result { + let network = params.get("network").ok_or(ApiError::NetworkNotFound)?; + if !state.is_network_configured(network) { + return Err(ApiError::NetworkNotFound); + } + Ok(next.run(req).await) +} + +/// Per-request count + latency metrics, labelled by the route template +/// (`/api/v1/{network}/.../{pool_address}/ticks`) so cardinality stays +/// bounded under address-parameterised routes. +async fn record_request_metrics(req: Request, next: Next) -> Response { + use crate::metrics::HistogramVecExt; + + let route = req + .extensions() + .get::() + .map(|p| p.as_str().to_owned()) + .unwrap_or_else(|| "unmatched".to_owned()); + let metrics = crate::metrics::Metrics::get(); + let labels = [route.as_str()]; + let _timer = metrics.api_request_seconds.timer(&labels); + let response = next.run(req).await; + let status = response.status().as_u16().to_string(); + metrics + .api_requests + .with_label_values(&[route.as_str(), status.as_str()]) + .inc(); + response +} diff --git a/crates/pool-indexer/src/api/uniswap_v3/bulk_ticks.rs b/crates/pool-indexer/src/api/uniswap_v3/bulk_ticks.rs new file mode 100644 index 0000000000..aaeb8539e3 --- /dev/null +++ b/crates/pool-indexer/src/api/uniswap_v3/bulk_ticks.rs @@ -0,0 +1,70 @@ +//! `GET /api/v1/{network}/uniswap/v3/pools/ticks?pool_ids=…` + +use { + super::{PoolIds, TickEntry}, + crate::{ + api::{ApiError, AppState, latest_indexed_block}, + db::uniswap_v3 as db, + }, + alloy_primitives::Address, + axum::{ + extract::{Query, State}, + response::{IntoResponse, Json, Response}, + }, + serde::{Deserialize, Serialize}, + std::{collections::HashMap, sync::Arc}, +}; + +#[derive(Deserialize)] +pub struct BulkTicksQuery { + /// Comma-separated pool addresses. Capped at + /// [`super::MAX_POOL_IDS_PER_REQUEST`]. + pub pool_ids: PoolIds, +} + +#[derive(Serialize)] +pub struct PoolTicks { + pub pool: Address, + pub ticks: Vec, +} + +/// Pools with no non-zero ticks are omitted from `pools` — callers should +/// treat an address missing from the response as "no active ticks", not +/// "unknown pool". +#[derive(Serialize)] +pub struct BulkTicksResponse { + pub block_number: u64, + pub pools: Vec, +} + +/// Ticks per pool are sorted by `tick_idx` (the DB query orders by +/// `(pool_address, tick_idx)`). +pub async fn get_ticks_bulk( + State(state): State>, + Query(BulkTicksQuery { pool_ids }): Query, +) -> Result { + let (block, ticks) = tokio::join!( + latest_indexed_block(&state), + db::get_ticks_for_pools(&state.db, &pool_ids.0), + ); + + Ok(Json(BulkTicksResponse { + block_number: block?, + pools: group_ticks_by_pool(ticks?), + }) + .into_response()) +} + +fn group_ticks_by_pool(rows: Vec) -> Vec { + let mut groups: HashMap> = HashMap::with_capacity(rows.len()); + for row in rows { + groups.entry(row.pool_address).or_default().push(TickEntry { + tick_idx: row.tick_idx, + liquidity_net: row.liquidity_net, + }); + } + groups + .into_iter() + .map(|(pool, ticks)| PoolTicks { pool, ticks }) + .collect() +} diff --git a/crates/pool-indexer/src/api/uniswap_v3/mod.rs b/crates/pool-indexer/src/api/uniswap_v3/mod.rs new file mode 100644 index 0000000000..ceae25a54f --- /dev/null +++ b/crates/pool-indexer/src/api/uniswap_v3/mod.rs @@ -0,0 +1,209 @@ +pub mod bulk_ticks; +pub mod pool_ticks; +pub mod pools_by_ids; +pub mod pools_list; + +use { + crate::db::uniswap_v3 as db, + alloy_primitives::Address, + axum::{ + Json, + response::{IntoResponse, Response}, + }, + bigdecimal::{BigDecimal, num_bigint::ToBigInt}, + serde::{Deserialize, Deserializer, Serialize}, +}; +pub use { + bulk_ticks::get_ticks_bulk, + pool_ticks::get_ticks, + pools_by_ids::get_pools_by_ids, + pools_list::get_pools, +}; + +/// Max pool addresses per bulk lookup. Keeps URLs under proxy limits and +/// caps the DB query size. +pub(super) const MAX_POOL_IDS_PER_REQUEST: usize = 500; + +/// Deserializes `?pool_ids=0x…,0x…` into typed addresses. Parsing and the +/// cap happen at the extractor so handlers see a `Vec
`. +pub(crate) struct PoolIds(pub Vec
); + +impl<'de> Deserialize<'de> for PoolIds { + fn deserialize>(de: D) -> Result { + let raw = String::deserialize(de)?; + let out: Vec
= raw + .split(',') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(|entry| { + entry + .parse::
() + .map_err(|_| serde::de::Error::custom("invalid pool id")) + }) + .collect::>()?; + if out.len() > MAX_POOL_IDS_PER_REQUEST { + return Err(serde::de::Error::custom(format!( + "too many pool ids; max {MAX_POOL_IDS_PER_REQUEST}" + ))); + } + Ok(PoolIds(out)) + } +} + +/// One tick with its net liquidity delta. Used by both tick endpoints +/// and embedded in [`PoolResponse`] when ticks are requested inline. +#[derive(Serialize)] +pub struct TickEntry { + pub tick_idx: i32, + #[serde(serialize_with = "serialize_integer")] + pub liquidity_net: BigDecimal, +} + +impl From for TickEntry { + fn from(tick: db::TickRow) -> Self { + Self { + tick_idx: tick.tick_idx, + liquidity_net: tick.liquidity_net, + } + } +} + +/// ERC-20 token metadata embedded in pool responses. +#[derive(Serialize)] +pub struct TokenInfo { + pub id: Address, + #[serde(skip_serializing_if = "Option::is_none")] + pub decimals: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol: Option, +} + +/// A single Uniswap v3 pool. +#[derive(Serialize)] +pub struct PoolResponse { + pub id: Address, + pub token0: TokenInfo, + pub token1: TokenInfo, + /// Fee tier in hundredths of a basis point (e.g. 3000 = 0.3%). + #[serde(serialize_with = "serialize_display")] + pub fee_tier: u32, + #[serde(serialize_with = "serialize_integer")] + pub liquidity: BigDecimal, + #[serde(serialize_with = "serialize_integer")] + pub sqrt_price: BigDecimal, + pub tick: i32, + /// Set only when ticks are requested inline. + pub ticks: Option>, +} + +#[derive(Serialize)] +pub struct PoolsResponse { + /// Latest fully-indexed block. + pub block_number: u64, + pub pools: Vec, + /// Pass as `after=` to fetch the next page; `null` on the last page. + pub next_cursor: Option, +} + +impl From<&db::PoolRow> for PoolResponse { + fn from(r: &db::PoolRow) -> Self { + Self { + id: r.address, + token0: TokenInfo { + id: r.token0, + decimals: r.token0_decimals, + symbol: non_empty(r.token0_symbol.as_deref()), + }, + token1: TokenInfo { + id: r.token1, + decimals: r.token1_decimals, + symbol: non_empty(r.token1_symbol.as_deref()), + }, + fee_tier: r.fee, + liquidity: r.liquidity.clone(), + sqrt_price: r.sqrt_price_x96.clone(), + tick: r.tick, + ticks: None, + } + } +} + +/// The symbol backfill writes `""` as a "tried and failed" sentinel. +/// Surface that as missing instead of as an empty string. +pub(super) fn non_empty(s: Option<&str>) -> Option { + s.filter(|s| !s.is_empty()).map(str::to_owned) +} + +/// Shared `PoolsResponse` builder for the listing endpoints. +pub(super) fn pools_response( + block_number: u64, + rows: &[db::PoolRow], + next_cursor: Option, +) -> Response { + Json(PoolsResponse { + block_number, + pools: rows.iter().map(PoolResponse::from).collect(), + next_cursor, + }) + .into_response() +} + +pub(super) fn serialize_display( + value: &T, + serializer: S, +) -> Result { + serializer.serialize_str(&value.to_string()) +} + +/// Emits a `BigDecimal` as plain digits. `Display` falls back to `Ne+M` +/// notation for some magnitudes, which `alloy::U256::from_str` rejects. +/// All columns we serialize this way (`sqrt_price_x96`, `liquidity`, +/// `liquidity_net`) hold integers, so the `to_bigint` round-trip is lossless. +pub(super) fn serialize_integer( + value: &BigDecimal, + serializer: S, +) -> Result { + // `to_bigint` truncates fractional values; round-trip-check so we don't + // silently drop precision. + match value.to_bigint() { + Some(bi) if BigDecimal::from(bi.clone()) == *value => { + serializer.serialize_str(&bi.to_string()) + } + _ => Err(serde::ser::Error::custom(format!( + "expected integer, got {value}" + ))), + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + bigdecimal::{BigDecimal, num_bigint::BigInt}, + serde::Serialize, + std::str::FromStr, + }; + + /// Postgres NUMERIC compresses trailing zeros into a negative + /// `BigDecimal` scale, which `Display` renders as `Ne+M`. Verify the + /// serializer emits plain digits so `U256::from_str` can parse the + /// response on the driver side. + #[test] + fn serialize_integer_handles_negative_scale_bigdecimal() { + let mantissa = BigInt::from_str("79228162514264337593543950336").unwrap(); + let v = BigDecimal::new(mantissa, -30); + + assert_eq!(v.to_string(), "79228162514264337593543950336e+30"); + + #[derive(Serialize)] + struct Wrapper { + #[serde(serialize_with = "serialize_integer")] + v: BigDecimal, + } + let json = serde_json::to_string(&Wrapper { v }).unwrap(); + assert_eq!( + json, + "{\"v\":\"79228162514264337593543950336000000000000000000000000000000\"}" + ); + } +} diff --git a/crates/pool-indexer/src/api/uniswap_v3/pool_ticks.rs b/crates/pool-indexer/src/api/uniswap_v3/pool_ticks.rs new file mode 100644 index 0000000000..bc2ebe97a8 --- /dev/null +++ b/crates/pool-indexer/src/api/uniswap_v3/pool_ticks.rs @@ -0,0 +1,41 @@ +//! `GET /api/v1/{network}/uniswap/v3/pools/{pool}/ticks` + +use { + super::TickEntry, + crate::{ + api::{ApiError, AppState, latest_indexed_block}, + db::uniswap_v3 as db, + }, + alloy_primitives::Address, + axum::{ + extract::{Path, State}, + response::{IntoResponse, Json, Response}, + }, + serde::Serialize, + std::sync::Arc, +}; + +#[derive(Serialize)] +pub struct TicksResponse { + pub block_number: u64, + pub pool: Address, + pub ticks: Vec, +} + +/// All non-zero ticks for one pool, sorted by `tick_idx`. +pub async fn get_ticks( + State(state): State>, + Path((_network, pool)): Path<(String, Address)>, +) -> Result { + let (block, ticks) = tokio::join!( + latest_indexed_block(&state), + db::get_ticks(&state.db, &pool), + ); + + Ok(Json(TicksResponse { + block_number: block?, + pool, + ticks: ticks?.into_iter().map(TickEntry::from).collect(), + }) + .into_response()) +} diff --git a/crates/pool-indexer/src/api/uniswap_v3/pools_by_ids.rs b/crates/pool-indexer/src/api/uniswap_v3/pools_by_ids.rs new file mode 100644 index 0000000000..079418d31e --- /dev/null +++ b/crates/pool-indexer/src/api/uniswap_v3/pools_by_ids.rs @@ -0,0 +1,37 @@ +//! `GET /api/v1/{network}/uniswap/v3/pools/by-ids?pool_ids=…` + +use { + super::{PoolIds, pools_response}, + crate::{ + api::{ApiError, AppState, latest_indexed_block}, + db::uniswap_v3 as db, + }, + axum::{ + extract::{Query, State}, + response::Response, + }, + serde::Deserialize, + std::sync::Arc, +}; + +#[derive(Deserialize)] +pub struct BulkLookupQuery { + /// Comma-separated pool addresses. Capped at + /// [`super::MAX_POOL_IDS_PER_REQUEST`]; clients with more should chunk. + pub pool_ids: PoolIds, +} + +/// Pools matching `pool_ids`, sorted by address. Unknown addresses are +/// skipped silently — treat a partial response as "these are the ones I +/// have", not "the others don't exist". +/// +/// `block_number` is read first so the envelope is never *newer* than the +/// row data (the indexer can advance between the two reads, never regress). +pub async fn get_pools_by_ids( + State(state): State>, + Query(BulkLookupQuery { pool_ids }): Query, +) -> Result { + let block = latest_indexed_block(&state).await?; + let pools = db::get_pools_by_ids(&state.db, &pool_ids.0).await?; + Ok(pools_response(block, &pools, None)) +} diff --git a/crates/pool-indexer/src/api/uniswap_v3/pools_list.rs b/crates/pool-indexer/src/api/uniswap_v3/pools_list.rs new file mode 100644 index 0000000000..4b4aa3f5ec --- /dev/null +++ b/crates/pool-indexer/src/api/uniswap_v3/pools_list.rs @@ -0,0 +1,58 @@ +//! `GET /api/v1/{network}/uniswap/v3/pools` — cursor-paginated pool list. + +use { + super::pools_response, + crate::{ + api::{ApiError, AppState, latest_indexed_block}, + db::uniswap_v3 as db, + }, + alloy_primitives::Address, + axum::{ + extract::{Query, State}, + response::Response, + }, + serde::Deserialize, + std::sync::Arc, +}; + +const DEFAULT_PAGE_LIMIT: u64 = 1_000; + +/// Hard server-side cap on `limit`. Applied even if the client asks for more. +const MAX_PAGE_LIMIT: u64 = 5_000; + +#[derive(Deserialize)] +pub struct ListPoolsQuery { + /// Cursor from the previous page (the last-seen pool address); omit to + /// start from the beginning. + pub after: Option
, + /// Clamped to `[1, MAX_PAGE_LIMIT]`; defaults to `DEFAULT_PAGE_LIMIT`. + pub limit: Option, +} + +impl ListPoolsQuery { + fn page_limit(&self) -> u64 { + self.limit + .unwrap_or(DEFAULT_PAGE_LIMIT) + .clamp(1, MAX_PAGE_LIMIT) + } +} + +/// All indexed pools, sorted by address. +pub async fn get_pools( + State(state): State>, + Query(query): Query, +) -> Result { + let block_number = latest_indexed_block(&state).await?; + let limit = query.page_limit(); + let cursor = query.after.map(|addr| addr.as_slice().to_vec()); + + let mut rows = db::get_pools(&state.db, cursor, limit + 1).await?; + + let has_next = rows.len() > limit as usize; + rows.truncate(limit as usize); + let next_cursor = has_next + .then(|| rows.last().map(|row| format!("{:#x}", row.address))) + .flatten(); + + Ok(pools_response(block_number, &rows, next_cursor)) +} diff --git a/crates/pool-indexer/src/arguments.rs b/crates/pool-indexer/src/arguments.rs new file mode 100644 index 0000000000..ce5085cf1f --- /dev/null +++ b/crates/pool-indexer/src/arguments.rs @@ -0,0 +1,12 @@ +use {shared::logging_args_with_default_filter, std::path::PathBuf}; + +logging_args_with_default_filter!(LoggingArguments, "warn,pool_indexer=debug,shared=debug"); + +#[derive(clap::Parser)] +pub struct Arguments { + #[clap(long, env)] + pub config: PathBuf, + + #[clap(flatten)] + pub logging: LoggingArguments, +} diff --git a/crates/pool-indexer/src/config.rs b/crates/pool-indexer/src/config.rs new file mode 100644 index 0000000000..0580dd74c9 --- /dev/null +++ b/crates/pool-indexer/src/config.rs @@ -0,0 +1,210 @@ +use { + alloy_primitives::Address, + anyhow::{Context, Result}, + serde::Deserialize, + std::{ + fmt, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + num::NonZeroU32, + path::Path, + time::Duration, + }, + url::Url, +}; + +const fn default_max_connections() -> NonZeroU32 { + NonZeroU32::new(10).expect("non-zero literal") +} + +const fn default_chunk_size() -> u64 { + 500 +} + +const fn default_poll_interval_secs() -> u64 { + 3 +} + +const fn default_fetch_concurrency() -> usize { + 8 +} + +const fn default_prefetch_concurrency() -> usize { + 50 +} + +const fn default_bind_address() -> SocketAddr { + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 7777)) +} + +const fn default_metrics_address() -> SocketAddr { + SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::UNSPECIFIED, + observe::metrics::DEFAULT_METRICS_PORT, + )) +} + +/// Network slug used in API routes (e.g. "mainnet", "arbitrum-one"). +#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)] +#[serde(transparent)] +pub struct NetworkName(String); + +impl NetworkName { + pub fn new(name: impl Into) -> Self { + Self(name.into()) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl fmt::Display for NetworkName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.0) + } +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct DatabaseConfig { + /// Postgres connection URL. Accepts `%ENV_VAR` to pull from the + /// environment. + #[serde(deserialize_with = "configs::deserialize_env::deserialize_url_from_env")] + pub url: Url, + #[serde(default = "default_max_connections")] + pub max_connections: NonZeroU32, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct NetworkConfig { + pub name: NetworkName, + pub chain_id: u64, + #[serde(deserialize_with = "configs::deserialize_env::deserialize_url_from_env")] + pub rpc_url: Url, + /// Uniswap V3 factories to index. Exactly one is allowed in this release + /// (see [`NetworkConfig::validate`]); multi-factory is a follow-up. + pub factories: Vec, + /// Blocks per `eth_getLogs` chunk during catch-up. + #[serde(default = "default_chunk_size")] + pub chunk_size: u64, + /// Interval for polling for new blocks during live indexing. + #[serde(default = "default_poll_interval_secs")] + pub poll_interval_secs: u64, + /// Number of `eth_getLogs` chunks fetched in parallel during live indexing. + #[serde(default = "default_fetch_concurrency")] + pub fetch_concurrency: usize, + /// `symbol()` / `decimals()` token-metadata RPC calls in flight during + /// the backfill passes. + #[serde(default = "default_prefetch_concurrency")] + pub prefetch_concurrency: usize, + /// Use `latest` instead of `finalized` as the indexing head. Set by tests + /// against Anvil, which doesn't simulate finality. + #[serde(skip)] + pub use_latest: bool, + /// Subgraph GraphQL endpoint for the initial seed. + #[serde(deserialize_with = "configs::deserialize_env::deserialize_url_from_env")] + pub subgraph_url: Url, + /// Block to seed at. Defaults to the subgraph's current block. + pub seed_block: Option, +} + +impl NetworkConfig { + pub fn poll_interval(&self) -> Duration { + Duration::from_secs(self.poll_interval_secs) + } + + pub fn indexer_config(&self, factory: Address) -> IndexerConfig { + IndexerConfig { + network: self.name.clone(), + chain_id: self.chain_id, + factory_address: factory, + chunk_size: self.chunk_size, + use_latest: self.use_latest, + fetch_concurrency: self.fetch_concurrency, + prefetch_concurrency: self.prefetch_concurrency, + } + } + + /// Post-parse sanity checks. + fn validate(&self) -> Result<()> { + anyhow::ensure!( + self.factories.len() == 1, + "network {}: exactly one factory per network is supported in this release, got {}", + self.name, + self.factories.len(), + ); + Ok(()) + } +} + +/// One factory address. The indexer runs a dedicated seed + live-indexing +/// loop per entry in [`NetworkConfig::factories`]. +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct FactoryConfig { + pub address: Address, +} + +/// Subset of [`NetworkConfig`] handed to [`UniswapV3Indexer`] at runtime. +#[derive(Debug, Clone)] +pub struct IndexerConfig { + pub network: NetworkName, + pub chain_id: u64, + pub factory_address: Address, + pub chunk_size: u64, + pub use_latest: bool, + pub fetch_concurrency: usize, + pub prefetch_concurrency: usize, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct ApiConfig { + #[serde(default = "default_bind_address")] + pub bind_address: SocketAddr, +} + +impl Default for ApiConfig { + fn default() -> Self { + Self { + bind_address: default_bind_address(), + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct MetricsConfig { + #[serde(default = "default_metrics_address")] + pub bind_address: SocketAddr, +} + +impl Default for MetricsConfig { + fn default() -> Self { + Self { + bind_address: default_metrics_address(), + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Configuration { + pub database: DatabaseConfig, + pub network: NetworkConfig, + #[serde(default)] + pub api: ApiConfig, + #[serde(default)] + pub metrics: MetricsConfig, +} + +impl Configuration { + pub fn from_path(path: &Path) -> Result { + let content = std::fs::read_to_string(path) + .with_context(|| format!("reading config file {}", path.display()))?; + let parsed: Self = toml::from_str(&content).context("parsing config file")?; + parsed.network.validate()?; + Ok(parsed) + } +} diff --git a/crates/pool-indexer/src/db/mod.rs b/crates/pool-indexer/src/db/mod.rs new file mode 100644 index 0000000000..c24144d0e0 --- /dev/null +++ b/crates/pool-indexer/src/db/mod.rs @@ -0,0 +1 @@ +pub mod uniswap_v3; diff --git a/crates/pool-indexer/src/db/uniswap_v3.rs b/crates/pool-indexer/src/db/uniswap_v3.rs new file mode 100644 index 0000000000..0b7fe77717 --- /dev/null +++ b/crates/pool-indexer/src/db/uniswap_v3.rs @@ -0,0 +1,689 @@ +use { + crate::indexer::uniswap_v3::{LiquidityUpdateData, NewPoolData, PoolStateData, TickDeltaData}, + alloy_primitives::Address, + anyhow::{Context, Result}, + bigdecimal::BigDecimal, + num::ToPrimitive, + number::conversions::u160_to_big_decimal, + sqlx::{PgPool, Postgres, Row, Transaction, postgres::PgRow}, +}; + +fn bytes_to_addr(b: Vec) -> Result
{ + Address::try_from(b.as_slice()).context("invalid address bytes") +} + +fn address_bytes_list(addresses: &[Address]) -> Vec<&[u8]> { + addresses.iter().map(|address| address.as_slice()).collect() +} + +fn decode_pool_rows(rows: Vec) -> Result> { + rows.into_iter().map(PoolRow::try_from).collect() +} + +pub async fn get_checkpoint(pool: &PgPool, contract: &Address) -> Result> { + let row = sqlx::query( + "SELECT block_number FROM pool_indexer_checkpoints WHERE contract_address = $1", + ) + .bind(contract.as_slice()) + .fetch_optional(pool) + .await + .context("get_checkpoint")?; + + Ok(row.map(|r| r.get::("block_number").cast_unsigned())) +} + +pub async fn set_checkpoint( + tx: &mut Transaction<'_, Postgres>, + contract: &Address, + block_number: u64, +) -> Result<()> { + sqlx::query( + "INSERT INTO pool_indexer_checkpoints (contract_address, block_number) + VALUES ($1, $2) + ON CONFLICT (contract_address) DO UPDATE SET block_number = EXCLUDED.block_number", + ) + .bind(contract.as_slice()) + .bind(block_number.cast_signed()) + .execute(&mut **tx) + .await + .context("set_checkpoint")?; + Ok(()) +} + +pub async fn insert_pools( + tx: &mut Transaction<'_, Postgres>, + factory: &Address, + pools: &[NewPoolData], +) -> Result<()> { + if pools.is_empty() { + return Ok(()); + } + let len = pools.len(); + let mut addresses: Vec<&[u8]> = Vec::with_capacity(len); + let mut token0s: Vec<&[u8]> = Vec::with_capacity(len); + let mut token1s: Vec<&[u8]> = Vec::with_capacity(len); + let mut fees: Vec = Vec::with_capacity(len); + let mut t0_decimals: Vec> = Vec::with_capacity(len); + let mut t1_decimals: Vec> = Vec::with_capacity(len); + let mut t0_symbols: Vec> = Vec::with_capacity(len); + let mut t1_symbols: Vec> = Vec::with_capacity(len); + let mut created_blocks: Vec = Vec::with_capacity(len); + for pool in pools { + addresses.push(pool.address.as_slice()); + token0s.push(pool.token0.as_slice()); + token1s.push(pool.token1.as_slice()); + fees.push(pool.fee.cast_signed()); + t0_decimals.push(pool.token0_decimals.map(i16::from)); + t1_decimals.push(pool.token1_decimals.map(i16::from)); + t0_symbols.push(pool.token0_symbol.clone()); + t1_symbols.push(pool.token1_symbol.clone()); + created_blocks.push(pool.created_block.cast_signed()); + } + + sqlx::query( + "INSERT INTO uniswap_v3_pools + (address, factory, token0, token1, fee, token0_decimals, token1_decimals, + token0_symbol, token1_symbol, created_block) + SELECT t.addr, $1, t.t0, t.t1, t.fee, t.t0d, t.t1d, t.t0s, t.t1s, t.cblk + FROM UNNEST($2::BYTEA[], $3::BYTEA[], $4::BYTEA[], $5::INT4[], $6::INT2[], $7::INT2[], + $8::TEXT[], $9::TEXT[], $10::INT8[]) + AS t(addr, t0, t1, fee, t0d, t1d, t0s, t1s, cblk) + ON CONFLICT (address) DO NOTHING", + ) + .bind(factory.as_slice()) + .bind(addresses) + .bind(token0s) + .bind(token1s) + .bind(fees) + .bind(t0_decimals) + .bind(t1_decimals) + .bind(t0_symbols) + .bind(t1_symbols) + .bind(created_blocks) + .execute(&mut **tx) + .await + .context("insert_pools")?; + Ok(()) +} + +pub async fn upsert_pool_states( + tx: &mut Transaction<'_, Postgres>, + factory: &Address, + states: &[PoolStateData], +) -> Result<()> { + if states.is_empty() { + return Ok(()); + } + let len = states.len(); + let mut addresses: Vec<&[u8]> = Vec::with_capacity(len); + let mut block_numbers: Vec = Vec::with_capacity(len); + let mut sqrt_prices: Vec = Vec::with_capacity(len); + let mut liquidities: Vec = Vec::with_capacity(len); + let mut ticks: Vec = Vec::with_capacity(len); + for state in states { + addresses.push(state.pool_address.as_slice()); + block_numbers.push(state.block_number.cast_signed()); + sqrt_prices.push(u160_to_big_decimal(&state.sqrt_price_x96)); + liquidities.push(BigDecimal::from(state.liquidity)); + ticks.push(state.tick); + } + + sqlx::query( + "WITH latest AS ( + SELECT DISTINCT ON (addr) addr, blk, sqrt, liq, tick + FROM UNNEST($2::BYTEA[], $3::INT8[], $4::NUMERIC[], $5::NUMERIC[], $6::INT4[]) + AS t(addr, blk, sqrt, liq, tick) + ORDER BY addr, blk DESC + ) + INSERT INTO uniswap_v3_pool_states + (pool_address, block_number, sqrt_price_x96, liquidity, tick) + SELECT l.addr, l.blk, l.sqrt, l.liq, l.tick + FROM latest l + WHERE EXISTS ( + SELECT 1 FROM uniswap_v3_pools + WHERE address = l.addr AND factory = $1 + ) + ON CONFLICT (pool_address) DO UPDATE + SET block_number = EXCLUDED.block_number, + sqrt_price_x96 = EXCLUDED.sqrt_price_x96, + liquidity = EXCLUDED.liquidity, + tick = EXCLUDED.tick", + ) + .bind(factory.as_slice()) + .bind(addresses) + .bind(block_numbers) + .bind(sqrt_prices) + .bind(liquidities) + .bind(ticks) + .execute(&mut **tx) + .await + .context("upsert_pool_states")?; + Ok(()) +} + +pub async fn batch_update_pool_liquidity( + tx: &mut Transaction<'_, Postgres>, + factory: &Address, + updates: &[LiquidityUpdateData], +) -> Result<()> { + if updates.is_empty() { + return Ok(()); + } + let addresses: Vec<&[u8]> = updates + .iter() + .map(|update| update.pool_address.as_slice()) + .collect(); + let liquidities: Vec = updates + .iter() + .map(|update| BigDecimal::from(update.liquidity)) + .collect(); + let block_numbers: Vec = updates + .iter() + .map(|update| update.block_number.cast_signed()) + .collect(); + + sqlx::query( + "WITH latest AS ( + SELECT DISTINCT ON (addr) addr, liq, blk + FROM UNNEST($2::BYTEA[], $3::NUMERIC[], $4::INT8[]) AS t(addr, liq, blk) + ORDER BY addr, blk DESC + ) + UPDATE uniswap_v3_pool_states s + SET liquidity = l.liq, block_number = l.blk + FROM latest l + WHERE s.pool_address = l.addr + AND EXISTS ( + SELECT 1 FROM uniswap_v3_pools p + WHERE p.address = l.addr AND p.factory = $1 + )", + ) + .bind(factory.as_slice()) + .bind(addresses) + .bind(liquidities) + .bind(block_numbers) + .execute(&mut **tx) + .await + .context("batch_update_pool_liquidity")?; + Ok(()) +} + +/// Filters `candidates` down to addresses already persisted as pools of +/// `factory`. Used to gate event dispatch: an emitter we didn't create +/// could otherwise spoof state via matching event signatures. Pools created +/// in the current chunk aren't yet committed, so callers must track them +/// separately. +pub async fn known_pool_addresses( + db: &PgPool, + factory: &Address, + candidates: &[Address], +) -> Result> { + if candidates.is_empty() { + return Ok(std::collections::HashSet::new()); + } + let rows = sqlx::query( + "SELECT address FROM uniswap_v3_pools WHERE factory = $1 AND address = ANY($2)", + ) + .bind(factory.as_slice()) + .bind(address_bytes_list(candidates)) + .fetch_all(db) + .await + .context("known_pool_addresses")?; + + rows.into_iter() + .map(|r| bytes_to_addr(r.get("address"))) + .collect() +} + +/// `(tick, liquidity)` for pools about to be touched by Mint/Burn events. +/// Pools not yet in `uniswap_v3_pool_states` are absent from the result; +/// callers treat absence as "skip this pool". +pub async fn get_base_pool_states( + db: &PgPool, + factory: &Address, + addresses: &[Address], +) -> Result> { + if addresses.is_empty() { + return Ok(std::collections::HashMap::new()); + } + let rows = sqlx::query( + "SELECT s.pool_address, s.tick, s.liquidity + FROM uniswap_v3_pool_states s + JOIN uniswap_v3_pools p ON p.address = s.pool_address + WHERE p.factory = $1 + AND s.pool_address = ANY($2)", + ) + .bind(factory.as_slice()) + .bind(address_bytes_list(addresses)) + .fetch_all(db) + .await + .context("get_base_pool_states")?; + + rows.into_iter() + .map(|r| { + let addr = bytes_to_addr(r.get("pool_address"))?; + let tick: i32 = r.get("tick"); + let liquidity = r + .get::("liquidity") + .to_u128() + .context("pool_states.liquidity value overflows u128")?; + Ok((addr, (tick, liquidity))) + }) + .collect() +} + +pub async fn batch_update_ticks( + tx: &mut Transaction<'_, Postgres>, + factory: &Address, + deltas: &[TickDeltaData], +) -> Result<()> { + if deltas.is_empty() { + return Ok(()); + } + let addresses: Vec<&[u8]> = deltas + .iter() + .map(|delta| delta.pool_address.as_slice()) + .collect(); + let tick_idxs: Vec = deltas.iter().map(|delta| delta.tick_idx).collect(); + let delta_values: Vec = deltas + .iter() + .map(|delta| BigDecimal::from(delta.delta)) + .collect(); + + // Invariant: never persist a row with `liquidity_net = 0`. + // + // - INSERT: skip rows whose aggregated delta is zero. The trailing DELETE can't + // see freshly-inserted rows in the same statement (Postgres modifying-CTE + // snapshot rules), so we gate at the INSERT side instead. + // - UPDATE: when an existing row sums to zero, it's in the snapshot the DELETE + // sees, so the DELETE removes it. + // + // `into_chunk_changes` filters single zero entries upstream, but two + // in-batch entries summing to zero for the same `(pool, tick)` would + // still reach the SQL; `AND i.total_delta <> 0` closes that gap. + sqlx::query( + "WITH input AS ( + SELECT t.addr, t.tick_idx, SUM(t.delta) AS total_delta + FROM UNNEST($2::BYTEA[], $3::INT4[], $4::NUMERIC[]) AS t(addr, tick_idx, delta) + GROUP BY t.addr, t.tick_idx + ), + upserted AS ( + INSERT INTO uniswap_v3_ticks (pool_address, tick_idx, liquidity_net) + SELECT i.addr, i.tick_idx, i.total_delta + FROM input i + WHERE i.total_delta <> 0 + AND EXISTS ( + SELECT 1 FROM uniswap_v3_pools + WHERE address = i.addr AND factory = $1 + ) + ON CONFLICT (pool_address, tick_idx) DO UPDATE + SET liquidity_net = uniswap_v3_ticks.liquidity_net + EXCLUDED.liquidity_net + RETURNING pool_address, tick_idx, liquidity_net + ) + DELETE FROM uniswap_v3_ticks ticks + USING upserted + WHERE ticks.pool_address = upserted.pool_address + AND ticks.tick_idx = upserted.tick_idx + AND upserted.liquidity_net = 0", + ) + .bind(factory.as_slice()) + .bind(addresses) + .bind(tick_idxs) + .bind(delta_values) + .execute(&mut **tx) + .await + .context("batch_update_ticks")?; + Ok(()) +} + +/// Set `liquidity_net` directly (no delta accumulation). Used by the seeder +/// where the subgraph value is already the net. +pub async fn batch_seed_ticks( + tx: &mut Transaction<'_, Postgres>, + factory: &Address, + ticks: &[TickDeltaData], +) -> Result<()> { + if ticks.is_empty() { + return Ok(()); + } + let addresses: Vec<&[u8]> = ticks + .iter() + .map(|tick| tick.pool_address.as_slice()) + .collect(); + let tick_idxs: Vec = ticks.iter().map(|tick| tick.tick_idx).collect(); + let values: Vec = ticks + .iter() + .map(|tick| BigDecimal::from(tick.delta)) + .collect(); + + sqlx::query( + "WITH input AS ( + SELECT t.addr, t.tick_idx, SUM(t.val) AS net + FROM UNNEST($2::BYTEA[], $3::INT4[], $4::NUMERIC[]) AS t(addr, tick_idx, val) + GROUP BY t.addr, t.tick_idx + ) + INSERT INTO uniswap_v3_ticks (pool_address, tick_idx, liquidity_net) + SELECT i.addr, i.tick_idx, i.net + FROM input i + WHERE EXISTS ( + SELECT 1 FROM uniswap_v3_pools + WHERE address = i.addr AND factory = $1 + ) + AND i.net <> 0 + ON CONFLICT (pool_address, tick_idx) DO UPDATE + SET liquidity_net = EXCLUDED.liquidity_net", + ) + .bind(factory.as_slice()) + .bind(addresses) + .bind(tick_idxs) + .bind(values) + .execute(&mut **tx) + .await + .context("batch_seed_ticks")?; + Ok(()) +} + +/// Deletes ticks for all pools of `factory`. Used by the seeder before a +/// reseed. Scoped to one factory so other factories aren't affected. +pub async fn delete_ticks_for_factory( + tx: &mut Transaction<'_, Postgres>, + factory: &Address, +) -> Result<()> { + sqlx::query( + "DELETE FROM uniswap_v3_ticks t + USING uniswap_v3_pools p + WHERE p.address = t.pool_address + AND p.factory = $1", + ) + .bind(factory.as_slice()) + .execute(&mut **tx) + .await + .context("delete_ticks_for_factory")?; + Ok(()) +} + +/// A pool joined with its current state row. +pub struct PoolRow { + pub address: Address, + pub token0: Address, + pub token1: Address, + pub fee: u32, + pub token0_decimals: Option, + pub token1_decimals: Option, + pub token0_symbol: Option, + pub token1_symbol: Option, + pub sqrt_price_x96: BigDecimal, + pub liquidity: BigDecimal, + pub tick: i32, +} + +impl TryFrom for PoolRow { + type Error = anyhow::Error; + + fn try_from(r: PgRow) -> Result { + Ok(Self { + address: bytes_to_addr(r.get("address"))?, + token0: bytes_to_addr(r.get("token0"))?, + token1: bytes_to_addr(r.get("token1"))?, + fee: r.get::("fee").cast_unsigned(), + // `-1` is the "tried, failed" sentinel from the decimals + // backfill; `u8::try_from` rejects it, surfacing it as `None`. + token0_decimals: r + .get::, _>("token0_decimals") + .and_then(|d| u8::try_from(d).ok()), + token1_decimals: r + .get::, _>("token1_decimals") + .and_then(|d| u8::try_from(d).ok()), + token0_symbol: r.get("token0_symbol"), + token1_symbol: r.get("token1_symbol"), + sqrt_price_x96: r.get("sqrt_price_x96"), + liquidity: r.get("liquidity"), + tick: r.get("tick"), + }) + } +} + +/// Page of pools ordered by address. `cursor = None` starts a new scan; +/// otherwise pass the previous page's last address (keyset pagination). +pub async fn get_pools(pool: &PgPool, cursor: Option>, limit: u64) -> Result> { + let rows = sqlx::query( + "SELECT p.address, p.token0, p.token1, p.fee, + p.token0_decimals, p.token1_decimals, + p.token0_symbol, p.token1_symbol, + s.sqrt_price_x96, s.liquidity, s.tick + FROM uniswap_v3_pools p + JOIN uniswap_v3_pool_states s ON s.pool_address = p.address + WHERE ($1::BYTEA IS NULL OR p.address > $1) + ORDER BY p.address + LIMIT $2", + ) + .bind(cursor) + .bind(limit.cast_signed()) + .fetch_all(pool) + .await + .context("get_pools")?; + + decode_pool_rows(rows) +} + +pub struct TickRow { + pub tick_idx: i32, + pub liquidity_net: BigDecimal, +} + +/// A tick tagged with its owning pool, for bulk-tick queries. +pub struct PoolTickRow { + pub pool_address: Address, + pub tick_idx: i32, + pub liquidity_net: BigDecimal, +} + +/// Pools matching `addresses` with their current state. Unknown addresses +/// are skipped; rows come back sorted by address. +pub async fn get_pools_by_ids(pool: &PgPool, addresses: &[Address]) -> Result> { + if addresses.is_empty() { + return Ok(Vec::new()); + } + let rows = sqlx::query( + "SELECT p.address, p.token0, p.token1, p.fee, + p.token0_decimals, p.token1_decimals, + p.token0_symbol, p.token1_symbol, + s.sqrt_price_x96, s.liquidity, s.tick + FROM uniswap_v3_pools p + JOIN uniswap_v3_pool_states s ON s.pool_address = p.address + WHERE p.address = ANY($1) + ORDER BY p.address", + ) + .bind(address_bytes_list(addresses)) + .fetch_all(pool) + .await + .context("get_pools_by_ids")?; + + decode_pool_rows(rows) +} + +/// Ticks for multiple pools, sorted by `(pool_address, tick_idx)` so the +/// caller can group in one pass. +/// +/// No per-pool tick cap. Bulk callers already cap their pool list (driver- +/// side `POOL_IDS_PER_REQUEST`), and the largest mainnet pool has ~1500 +/// active ticks — well below anything that would warrant truncation. If +/// that changes, add a per-pool `truncated: bool` to the response rather +/// than silently dropping rows: missing ticks produce a wrong price curve +/// the driver can't detect. +pub async fn get_ticks_for_pools(pool: &PgPool, addresses: &[Address]) -> Result> { + if addresses.is_empty() { + return Ok(Vec::new()); + } + let rows = sqlx::query( + "SELECT pool_address, tick_idx, liquidity_net + FROM uniswap_v3_ticks + WHERE pool_address = ANY($1) + ORDER BY pool_address, tick_idx", + ) + .bind(address_bytes_list(addresses)) + .fetch_all(pool) + .await + .context("get_ticks_for_pools")?; + + rows.into_iter() + .map(|r| { + Ok(PoolTickRow { + pool_address: bytes_to_addr(r.get("pool_address"))?, + tick_idx: r.get("tick_idx"), + liquidity_net: r.get("liquidity_net"), + }) + }) + .collect() +} + +pub async fn get_ticks(pool: &PgPool, pool_address: &Address) -> Result> { + sqlx::query( + "SELECT tick_idx, liquidity_net + FROM uniswap_v3_ticks + WHERE pool_address = $1 + ORDER BY tick_idx", + ) + .bind(pool_address.as_slice()) + .fetch_all(pool) + .await + .context("get_ticks") + .map(|rows| { + rows.into_iter() + .map(|r| TickRow { + tick_idx: r.get("tick_idx"), + liquidity_net: r.get("liquidity_net"), + }) + .collect() + }) +} + +/// All distinct token addresses with no `symbol` recorded. +pub async fn get_tokens_missing_symbols(pool: &PgPool) -> Result> { + let rows = sqlx::query( + "SELECT DISTINCT token FROM ( + SELECT token0 AS token FROM uniswap_v3_pools WHERE token0_symbol IS NULL + UNION + SELECT token1 AS token FROM uniswap_v3_pools WHERE token1_symbol IS NULL + ) t", + ) + .fetch_all(pool) + .await + .context("get_tokens_missing_symbols")?; + + rows.into_iter() + .map(|r| bytes_to_addr(r.get("token"))) + .collect() +} + +/// All distinct token addresses with no `decimals` recorded. +pub async fn get_tokens_missing_decimals(pool: &PgPool) -> Result> { + let rows = sqlx::query( + "SELECT DISTINCT token FROM ( + SELECT token0 AS token FROM uniswap_v3_pools WHERE token0_decimals IS NULL + UNION + SELECT token1 AS token FROM uniswap_v3_pools WHERE token1_decimals IS NULL + ) t", + ) + .fetch_all(pool) + .await + .context("get_tokens_missing_decimals")?; + + rows.into_iter() + .map(|r| bytes_to_addr(r.get("token"))) + .collect() +} + +/// Sets `token0_decimals` / `token1_decimals` for every pool containing +/// one of the input tokens. Pass `-1` for "tried, failed" so the next +/// backfill's `IS NULL` filter still skips it. +/// +/// Two separate UPDATEs (via a writeable CTE) keyed on `token0` and +/// `token1` separately — a single `UPDATE ... FROM UNNEST` would let +/// Postgres pick an arbitrary row when both columns matched, setting only +/// one side. +pub async fn batch_set_token_decimals( + tx: &mut Transaction<'_, Postgres>, + entries: &[(Address, i16)], +) -> Result<()> { + if entries.is_empty() { + return Ok(()); + } + let tokens: Vec<&[u8]> = entries.iter().map(|(t, _)| t.as_slice()).collect(); + let decimals: Vec = entries.iter().map(|(_, d)| *d).collect(); + + sqlx::query( + "WITH input AS ( + SELECT * FROM UNNEST($1::BYTEA[], $2::INT2[]) AS t(tok, dec) + ), + update_t0 AS ( + UPDATE uniswap_v3_pools p + SET token0_decimals = i.dec + FROM input i + WHERE p.token0 = i.tok + AND p.token0_decimals IS NULL + RETURNING 1 + ) + UPDATE uniswap_v3_pools p + SET token1_decimals = i.dec + FROM input i + WHERE p.token1 = i.tok + AND p.token1_decimals IS NULL", + ) + .bind(tokens) + .bind(decimals) + .execute(&mut **tx) + .await + .context("batch_set_token_decimals")?; + + Ok(()) +} + +/// Symbol-side counterpart of [`batch_set_token_decimals`]. Pass `""` for +/// "tried, failed". +pub async fn batch_set_token_symbols( + tx: &mut Transaction<'_, Postgres>, + entries: &[(Address, String)], +) -> Result<()> { + if entries.is_empty() { + return Ok(()); + } + let tokens: Vec<&[u8]> = entries.iter().map(|(t, _)| t.as_slice()).collect(); + let symbols: Vec<&str> = entries.iter().map(|(_, s)| s.as_str()).collect(); + + sqlx::query( + "WITH input AS ( + SELECT * FROM UNNEST($1::BYTEA[], $2::TEXT[]) AS t(tok, sym) + ), + update_t0 AS ( + UPDATE uniswap_v3_pools p + SET token0_symbol = i.sym + FROM input i + WHERE p.token0 = i.tok + AND p.token0_symbol IS NULL + RETURNING 1 + ) + UPDATE uniswap_v3_pools p + SET token1_symbol = i.sym + FROM input i + WHERE p.token1 = i.tok + AND p.token1_symbol IS NULL", + ) + .bind(tokens) + .bind(symbols) + .execute(&mut **tx) + .await + .context("batch_set_token_symbols")?; + + Ok(()) +} + +pub async fn get_latest_indexed_block(pool: &PgPool) -> Result> { + let row = sqlx::query("SELECT MAX(block_number) AS max_block FROM pool_indexer_checkpoints") + .fetch_one(pool) + .await + .context("get_latest_indexed_block")?; + + Ok(row + .get::, _>("max_block") + .map(|b| b.cast_unsigned())) +} diff --git a/crates/pool-indexer/src/indexer/mod.rs b/crates/pool-indexer/src/indexer/mod.rs new file mode 100644 index 0000000000..c24144d0e0 --- /dev/null +++ b/crates/pool-indexer/src/indexer/mod.rs @@ -0,0 +1 @@ +pub mod uniswap_v3; diff --git a/crates/pool-indexer/src/indexer/uniswap_v3.rs b/crates/pool-indexer/src/indexer/uniswap_v3.rs new file mode 100644 index 0000000000..049f0bbd72 --- /dev/null +++ b/crates/pool-indexer/src/indexer/uniswap_v3.rs @@ -0,0 +1,1405 @@ +use { + crate::{ + config::{IndexerConfig, NetworkName}, + db::uniswap_v3 as db, + }, + alloy_primitives::{Address, B256, aliases::U160}, + alloy_provider::Provider, + alloy_rpc_types_eth::{BlockNumberOrTag, Filter, FilterSet, Log}, + alloy_sol_types::SolEvent, + alloy_transport::RpcError, + anyhow::{Context, Result}, + contracts::{ + ERC20, + IUniswapV3Factory::IUniswapV3Factory::PoolCreated, + UniswapV3Pool::UniswapV3Pool::{Burn, Initialize, Mint, Swap}, + }, + ethrpc::{AlloyProvider, alloy::errors::ContractErrorExt}, + futures::{StreamExt, TryStreamExt}, + itertools::Itertools, + sqlx::PgPool, + std::collections::{HashMap, HashSet}, + tracing::instrument, +}; + +/// Snapshot of `(tick, liquidity)` per pool, loaded from +/// `uniswap_v3_pool_states` before a chunk's logs. Provides the starting +/// state when a `Mint`/`Burn` lands without a `Swap`/`Initialize` earlier +/// in the same chunk. Pools missing from the map are uninitialised; the +/// liquidity update for that event is skipped. +type BasePoolStates = HashMap; +type DecimalsCache = HashMap; + +const SYMBOL_BACKFILL_BATCH_SIZE: usize = 500; + +/// Data for a newly discovered pool, sourced from a `PoolCreated` factory +/// event. +pub struct NewPoolData { + pub address: Address, + pub token0: Address, + pub token1: Address, + /// Raw fee in hundredths of a basis point (e.g. 3000 = 0.3 %). + pub fee: u32, + pub token0_decimals: Option, + pub token1_decimals: Option, + pub token0_symbol: Option, + pub token1_symbol: Option, + pub created_block: u64, +} + +/// Pool state at a given block, from an `Initialize` or `Swap` event. +pub struct PoolStateData { + pub pool_address: Address, + pub block_number: u64, + pub sqrt_price_x96: U160, + pub liquidity: u128, + pub tick: i32, +} + +/// Liquidity-only update for a pool that had a `Mint`/`Burn` but no +/// `Swap`/`Initialize` in the same chunk. +pub struct LiquidityUpdateData { + pub pool_address: Address, + pub block_number: u64, + pub liquidity: u128, +} + +/// Signed delta to a tick's `liquidity_net`. Accumulated from `Mint` +/// (+amount) and `Burn` (-amount) events. +pub struct TickDeltaData { + pub pool_address: Address, + pub tick_idx: i32, + pub delta: i128, +} + +/// All DB changes from one chunk of logs, ready to write in one tx. +struct ChunkChanges { + new_pools: Vec, + pool_states: Vec, + liquidity_updates: Vec, + tick_deltas: Vec, +} + +#[derive(Clone, Copy, Debug)] +struct ChunkRange { + start: u64, + end: u64, +} + +/// Indexes Uniswap V3 events for one factory, persisting pool state and +/// tick liquidity to Postgres. +pub struct UniswapV3Indexer { + provider: AlloyProvider, + db: PgPool, + network: NetworkName, + chain_id: u64, + factory: Address, + chunk_size: u64, + finality_tag: BlockNumberOrTag, + fetch_concurrency: usize, + prefetch_concurrency: usize, +} + +impl UniswapV3Indexer { + pub fn new(provider: AlloyProvider, db: PgPool, config: &IndexerConfig) -> Self { + Self { + provider, + db, + network: config.network.clone(), + chain_id: config.chain_id, + factory: config.factory_address, + chunk_size: config.chunk_size, + finality_tag: if config.use_latest { + BlockNumberOrTag::Latest + } else { + BlockNumberOrTag::Finalized + }, + fetch_concurrency: config.fetch_concurrency, + prefetch_concurrency: config.prefetch_concurrency, + } + } + + /// Per-factory live-indexing loop. Backfill tasks live at the network + /// level (see `run_network_indexer`). + pub async fn run(self, poll_interval: std::time::Duration) -> ! { + let mut interval = tokio::time::interval(poll_interval); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); + loop { + interval.tick().await; + if let Err(err) = self.run_once().await { + crate::metrics::Metrics::get() + .indexer_errors + .with_label_values(&[self.network.as_str()]) + .inc(); + tracing::error!(?err, "indexer error, retrying after poll interval"); + } + } + } + + /// Brings a freshly-seeded factory up to the current finalized block + /// and returns. Loops in case more blocks finalize during a long + /// catch-up. Call exactly once, right after seeding. + /// + /// The subgraph's `block: { number: X }` returns state as of the end + /// of block `X` — events at `X` are included. The checkpoint stores + /// the last indexed block and `run_once` resumes at `checkpoint + 1`, + /// so we set the checkpoint to `from_block` itself to avoid replaying + /// (and double-applying) the seed block's Mint/Burn events. + /// + /// Bails if a checkpoint already exists — overwriting would silently + /// regress and re-index history. + pub async fn catch_up(&self, from_block: u64) -> Result<()> { + if db::get_checkpoint(&self.db, &self.factory).await?.is_some() { + anyhow::bail!( + "catch_up called but checkpoint already exists for chain {} factory {}", + self.chain_id, + self.factory, + ); + } + let mut tx = self.db.begin().await.context("begin checkpoint tx")?; + db::set_checkpoint(&mut tx, &self.factory, from_block).await?; + tx.commit().await.context("commit checkpoint tx")?; + + loop { + let finalized_block = self.finalized_block().await?; + let last_indexed_block = self.last_indexed_block().await?; + + if last_indexed_block >= finalized_block { + tracing::info!(block = finalized_block, "caught up to finalized block"); + return Ok(()); + } + + self.run_once().await?; + } + } + + async fn run_once(&self) -> Result<()> { + let finalized_block = self.finalized_block().await?; + let last_indexed_block = self.last_indexed_block().await?; + + let lag = finalized_block.saturating_sub(last_indexed_block); + crate::metrics::Metrics::get() + .indexer_lag_blocks + .with_label_values(&[self.network.as_str()]) + .set(i64::try_from(lag).unwrap_or(i64::MAX)); + + if last_indexed_block >= finalized_block { + return Ok(()); + } + + // Fetch chunks in parallel, commit in order. + futures::stream::iter(self.pending_chunks(last_indexed_block, finalized_block)) + .map(|chunk| async move { + let logs = self.fetch_logs_bisecting(chunk.start, chunk.end).await?; + Ok::<_, anyhow::Error>((chunk, logs)) + }) + .buffered(self.fetch_concurrency) + .try_for_each(|(chunk, logs)| self.commit_chunk(chunk, logs, finalized_block)) + .await?; + + tracing::info!( + block = finalized_block, + blocks_processed = lag, + "live indexer caught up to finalized block", + ); + Ok(()) + } + + async fn finalized_block(&self) -> Result { + Ok(self + .provider + .get_block_by_number(self.finality_tag) + .await + .context("get finalized block")? + .context("no finalized block")? + .header + .number) + } + + async fn last_indexed_block(&self) -> Result { + Ok(db::get_checkpoint(&self.db, &self.factory) + .await? + .unwrap_or(0)) + } + + fn pending_chunks(&self, last_indexed_block: u64, finalized_block: u64) -> Vec { + let mut chunks = Vec::new(); + let mut next_start = last_indexed_block + 1; + + while next_start <= finalized_block { + let next_end = (next_start + self.chunk_size - 1).min(finalized_block); + chunks.push(ChunkRange { + start: next_start, + end: next_end, + }); + next_start = next_end + 1; + } + + chunks + } + + async fn fetch_logs_bisecting(&self, from: u64, to: u64) -> Result> { + // No address filter on `eth_getLogs`: `PoolCreated` comes from the + // factory but the other four events come from each pool, and that + // list (tens of thousands of pools on mainnet) blows past most + // RPCs' filter-size cap. The filter would also apply across all + // topics at once, so we can't scope per-event. + // + // Instead we filter client-side in `collect_log_changes`: + // - PoolCreated → emitter must be `self.factory`. + // - Mint/Burn/Swap/Initialize → emitter must be a known pool of our factory + // (DB or in-chunk PoolCreated). + // + // The `WHERE EXISTS (… uniswap_v3_pools …)` clauses in the batch + // writers stay as defense-in-depth. + bisecting_get_logs( + &self.provider, + from, + to, + vec![], + vec![ + PoolCreated::SIGNATURE_HASH, + Initialize::SIGNATURE_HASH, + Mint::SIGNATURE_HASH, + Burn::SIGNATURE_HASH, + Swap::SIGNATURE_HASH, + ], + ) + .await + } + + #[instrument(skip(self, logs), fields(chunk_start = chunk.start, chunk_end = chunk.end))] + async fn commit_chunk( + &self, + chunk: ChunkRange, + logs: Vec, + target_block: u64, + ) -> Result<()> { + // Pre-fetch decimals + load base states + known pools in parallel + // before opening the chunk tx. Symbols are deliberately excluded: + // a hung `symbol()` call must never block pool inserts, so the + // async backfill picks them up later. + use crate::metrics::HistogramVecExt; + + let metrics = crate::metrics::Metrics::get(); + let chunk_timer_labels = [self.network.as_str()]; + let _chunk_timer = metrics.chunk_commit_seconds.timer(&chunk_timer_labels); + let mint_burn_pools = mint_burn_pool_addresses(&logs); + let pool_event_emitters = pool_event_emitters(&logs); + let (decimals, base_states, known_pools_db) = tokio::join!( + self.prefetch_decimals(&logs), + db::get_base_pool_states(&self.db, &self.factory, &mint_burn_pools), + db::known_pool_addresses(&self.db, &self.factory, &pool_event_emitters), + ); + let base_states = base_states?; + let known_pools_db = known_pools_db?; + let changes = collect_log_changes( + self.factory, + &logs, + &base_states, + &decimals, + &known_pools_db, + ); + + tracing::debug!( + chunk_start = chunk.start, + chunk_end = chunk.end, + log_count = logs.len(), + new_pools = changes.new_pools.len(), + pool_states = changes.pool_states.len(), + liq_updates = changes.liquidity_updates.len(), + tick_deltas = changes.tick_deltas.len(), + "processing chunk" + ); + + let network = self.network.as_str(); + for (kind, count) in [ + ("new_pool", changes.new_pools.len()), + ("pool_state", changes.pool_states.len()), + ("liq_update", changes.liquidity_updates.len()), + ("tick_delta", changes.tick_deltas.len()), + ] { + metrics + .events_applied + .with_label_values(&[network, kind]) + .inc_by(count as u64); + } + + self.persist_chunk(chunk, changes).await?; + + metrics + .indexed_block + .with_label_values(&[network]) + .set(i64::try_from(chunk.end).unwrap_or(i64::MAX)); + // `target_block` is the finalized tip from the start of this + // `run_once`. Refreshing the lag metric per chunk lets dashboards + // watch it shrink during multi-chunk catch-ups. + let lag = target_block.saturating_sub(chunk.end); + metrics + .indexer_lag_blocks + .with_label_values(&[network]) + .set(i64::try_from(lag).unwrap_or(i64::MAX)); + Ok(()) + } + + async fn persist_chunk(&self, chunk: ChunkRange, changes: ChunkChanges) -> Result<()> { + let mut tx = self.db.begin().await.context("begin transaction")?; + db::insert_pools(&mut tx, &self.factory, &changes.new_pools).await?; + db::upsert_pool_states(&mut tx, &self.factory, &changes.pool_states).await?; + db::batch_update_pool_liquidity(&mut tx, &self.factory, &changes.liquidity_updates).await?; + db::batch_update_ticks(&mut tx, &self.factory, &changes.tick_deltas).await?; + db::set_checkpoint(&mut tx, &self.factory, chunk.end).await?; + tx.commit().await.context("commit transaction")?; + + Ok(()) + } + + /// Concurrent `decimals()` fetches for tokens in this chunk's + /// PoolCreated events. + async fn prefetch_decimals(&self, logs: &[Log]) -> DecimalsCache { + futures::stream::iter(pool_created_token_addresses(self.factory, logs)) + .map(|token| async move { + let dec = fetch_decimals(&self.provider, token).await; + (token, dec) + }) + .buffer_unordered(self.prefetch_concurrency) + .filter_map(|(token, opt)| async move { opt.map(|d| (token, d)) }) + .collect() + .await + } +} + +/// Retries `f` while the error is a transient transport failure +/// (`is_node_error`). Contract reverts and decoding failures bail out +/// immediately. On giveup, hands `on_giveup` the accumulated errors and +/// returns `None`. +async fn retry_node_call( + f: impl Fn() -> Fut, + on_giveup: impl FnOnce(&[alloy_contract::Error]), +) -> Option +where + Fut: std::future::Future>, +{ + match shared::retry::retry_with_sleep_if(f, |err: &alloy_contract::Error| err.is_node_error()) + .await + { + Ok(v) => Some(v), + Err(errors) => { + on_giveup(&errors); + None + } + } +} + +/// Unique addresses with a `Mint` or `Burn` in the chunk. We pre-load +/// their `(tick, liquidity)` so the post-event liquidity can be derived +/// from the in-event delta without an extra RPC. +fn mint_burn_pool_addresses(logs: &[Log]) -> Vec
{ + logs.iter() + .filter_map(|log| { + let t = log.topic0()?; + (*t == Mint::SIGNATURE_HASH || *t == Burn::SIGNATURE_HASH).then(|| log.address()) + }) + .unique() + .collect() +} + +/// Unique emitter addresses for the per-pool events +/// (`Initialize`/`Swap`/`Mint`/`Burn`). Feeds the DB lookup that filters +/// out foreign emitters before `collect_log_changes` dispatches. +fn pool_event_emitters(logs: &[Log]) -> Vec
{ + logs.iter() + .filter_map(|log| { + let t = log.topic0()?; + (*t == Initialize::SIGNATURE_HASH + || *t == Swap::SIGNATURE_HASH + || *t == Mint::SIGNATURE_HASH + || *t == Burn::SIGNATURE_HASH) + .then(|| log.address()) + }) + .unique() + .collect() +} + +async fn fetch_decimals(provider: &AlloyProvider, token: Address) -> Option { + retry_node_call( + || async move { + ERC20::Instance::new(token, provider.clone()) + .decimals() + .call() + .await + }, + |errors| tracing::warn!(%token, ?errors, "fetch_decimals gave up"), + ) + .await +} + +/// Periodically fills `token{0,1}_symbol` on newly-indexed pools. +/// +/// Tokens whose `symbol()` call fails (revert / decode / empty) are stored +/// as `""` so the next pass skips them — without this we'd hammer known- +/// broken tokens forever. A restart re-probes them once. +pub(crate) async fn backfill_symbols( + provider: AlloyProvider, + db: sqlx::PgPool, + network: NetworkName, + prefetch_concurrency: usize, + poll_interval: std::time::Duration, +) { + let mut interval = tokio::time::interval(poll_interval); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); + loop { + interval.tick().await; + if let Err(err) = + run_symbol_backfill_pass(&provider, &db, &network, prefetch_concurrency).await + { + tracing::error!(?err, "token symbol backfill pass failed"); + } + } +} + +async fn run_symbol_backfill_pass( + provider: &AlloyProvider, + db: &sqlx::PgPool, + network: &NetworkName, + prefetch_concurrency: usize, +) -> Result<()> { + let tokens = db::get_tokens_missing_symbols(db) + .await + .context("get_tokens_missing_symbols")?; + let network = network.as_str(); + crate::metrics::Metrics::get() + .backfill_pending + .with_label_values(&[network, "symbol"]) + // `-1` on overflow surfaces the defensive `usize → i64` case as a + // visible signal instead of masquerading as "no work pending". + .set(i64::try_from(tokens.len()).unwrap_or(-1)); + if tokens.is_empty() { + return Ok(()); + } + let total = tokens.len(); + tracing::info!(total, "backfilling token symbols"); + + let mut updated = 0usize; + let mut processed = 0usize; + + // Pipeline tokens through `symbol()` concurrently and batch the + // results into DB writes. Faster tokens don't wait for slower ones in + // the same batch, only for the next `ready_chunks` slot. + let mut stream = futures::stream::iter(tokens) + .map(|token| async move { + // `None` → `""` is the "tried and failed" sentinel; the + // `IS NULL` filter on the next pass skips it. + let sym = fetch_symbol(provider, token).await.unwrap_or_default(); + (token, sym) + }) + .buffer_unordered(prefetch_concurrency) + .ready_chunks(SYMBOL_BACKFILL_BATCH_SIZE); + + while let Some(symbols) = stream.next().await { + let batch_len = symbols.len(); + let metrics = crate::metrics::Metrics::get(); + match write_symbols_batch(db, &symbols).await { + Ok(()) => { + for (_, symbol) in &symbols { + updated += 1; + let result = if symbol.is_empty() { "empty" } else { "ok" }; + metrics + .backfilled + .with_label_values(&[network, "symbol", result]) + .inc(); + } + } + Err(err) => tracing::warn!( + ?err, + batch_size = batch_len, + "failed to backfill symbols batch" + ), + } + + processed += batch_len; + tracing::info!(processed, total, updated, "token symbol backfill progress"); + } + + tracing::info!(updated, total, "token symbol backfill pass complete"); + Ok(()) +} + +/// Decimals counterpart of [`backfill_symbols`]. Uses `-1` as the "tried +/// and failed" sentinel. +pub(crate) async fn backfill_decimals( + provider: AlloyProvider, + db: sqlx::PgPool, + network: NetworkName, + prefetch_concurrency: usize, + poll_interval: std::time::Duration, +) { + let mut interval = tokio::time::interval(poll_interval); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); + loop { + interval.tick().await; + if let Err(err) = + run_decimals_backfill_pass(&provider, &db, &network, prefetch_concurrency).await + { + tracing::error!(?err, "token decimals backfill pass failed"); + } + } +} + +async fn run_decimals_backfill_pass( + provider: &AlloyProvider, + db: &sqlx::PgPool, + network: &NetworkName, + prefetch_concurrency: usize, +) -> Result<()> { + let tokens = db::get_tokens_missing_decimals(db) + .await + .context("get_tokens_missing_decimals")?; + let network = network.as_str(); + crate::metrics::Metrics::get() + .backfill_pending + .with_label_values(&[network, "decimals"]) + // -1: see the `symbol` pass above for the rationale. + .set(i64::try_from(tokens.len()).unwrap_or(-1)); + if tokens.is_empty() { + return Ok(()); + } + let total = tokens.len(); + tracing::info!(total, "backfilling token decimals"); + + let mut updated = 0usize; + let mut processed = 0usize; + + let mut stream = futures::stream::iter(tokens) + .map(|token| async move { + // `None` → `-1` is the "tried and failed" sentinel; the + // `IS NULL` filter on the next pass skips it. + let dec = fetch_decimals(provider, token) + .await + .map(i16::from) + .unwrap_or(-1); + (token, dec) + }) + .buffer_unordered(prefetch_concurrency) + .ready_chunks(SYMBOL_BACKFILL_BATCH_SIZE); + + while let Some(decimals) = stream.next().await { + let batch_len = decimals.len(); + let metrics = crate::metrics::Metrics::get(); + match write_decimals_batch(db, &decimals).await { + Ok(()) => { + for (_, dec) in &decimals { + updated += 1; + let result = if *dec < 0 { "empty" } else { "ok" }; + metrics + .backfilled + .with_label_values(&[network, "decimals", result]) + .inc(); + } + } + Err(err) => tracing::warn!( + ?err, + batch_size = batch_len, + "failed to backfill decimals batch" + ), + } + + processed += batch_len; + tracing::info!( + processed, + total, + updated, + "token decimals backfill progress" + ); + } + + tracing::info!(updated, total, "token decimals backfill pass complete"); + Ok(()) +} + +async fn write_symbols_batch(db: &sqlx::PgPool, entries: &[(Address, String)]) -> Result<()> { + let mut tx = db.begin().await.context("begin symbols batch tx")?; + db::batch_set_token_symbols(&mut tx, entries).await?; + tx.commit().await.context("commit symbols batch tx")?; + Ok(()) +} + +async fn write_decimals_batch(db: &sqlx::PgPool, entries: &[(Address, i16)]) -> Result<()> { + let mut tx = db.begin().await.context("begin decimals batch tx")?; + db::batch_set_token_decimals(&mut tx, entries).await?; + tx.commit().await.context("commit decimals batch tx")?; + Ok(()) +} + +async fn fetch_symbol(provider: &AlloyProvider, token: Address) -> Option { + let sym = ERC20::Instance::new(token, provider.clone()) + .symbol() + .call() + .await + .ok()?; + // Strip null bytes — some tokens embed \x00 in their symbol which Postgres + // rejects. + let cleaned = sym.replace('\x00', ""); + (!cleaned.is_empty()).then_some(cleaned) +} + +/// True if the server-side JSON-RPC payload rejected `eth_getLogs` for +/// being too wide / returning too many logs / exceeding a response-size +/// cap / hitting the server's query timeout. Substrings cover the +/// rejections empirically seen on OVH and Alchemy mainnet. Transport-level +/// errors (HTTP timeouts, DNS, connection resets) live in other `RpcError` +/// variants and short-circuit to false, so client-side noise can't trigger +/// pointless bisection. +pub(crate) fn is_range_too_large(err: &alloy_transport::TransportError) -> bool { + let RpcError::ErrorResp(payload) = err else { + return false; + }; + let msg = payload.message.to_lowercase(); + msg.contains("max block range") + || msg.contains("max results") + || msg.contains("log response size exceeded") + || msg.contains("query timeout exceeded") + || msg.contains("response is too big") +} + +/// Bisecting bound — substring matching on RPC error messages is necessarily +/// approximate, and a misclassified error would otherwise burn `log2(range)` +/// RPC calls before the recursion bottoms out at `to == from`. 8 halvings = +/// 256× resolution; for the indexer's ~1k-block chunks that means giving up +/// around ~4-block ranges, well past where range-size could plausibly still +/// be the cause. +const MAX_BISECTION_DEPTH: u32 = 8; + +/// Fetches logs for `[from, to]` filtered by the given contract addresses +/// and `topic0` event signatures, sequentially bisecting the block range on +/// "too large" rejections until each sub-range is tractable. An empty +/// `addresses` list means "any contract". Bisection depth is capped by +/// [`MAX_BISECTION_DEPTH`]. +pub(crate) fn bisecting_get_logs( + provider: &AlloyProvider, + from: u64, + to: u64, + addresses: Vec
, + topics: Vec, +) -> futures::future::BoxFuture<'_, Result>> { + bisecting_get_logs_with_depth(provider, from, to, addresses, topics, 0) +} + +fn bisecting_get_logs_with_depth( + provider: &AlloyProvider, + from: u64, + to: u64, + addresses: Vec
, + topics: Vec, + depth: u32, +) -> futures::future::BoxFuture<'_, Result>> { + Box::pin(async move { + let filter = Filter::new() + .address(addresses.clone()) + .event_signature(FilterSet::from_iter(topics.clone())) + .from_block(from) + .to_block(to); + + let err = match provider.get_logs(&filter).await { + Ok(logs) => return Ok(logs), + Err(err) => err, + }; + if !is_range_too_large(&err) || to <= from || depth >= MAX_BISECTION_DEPTH { + return Err(anyhow::Error::new(err).context(format!("get_logs({from}..={to})"))); + } + + let mid = (from + to) / 2; + tracing::debug!(from, to, mid, depth, "range too large, bisecting"); + let mut left = bisecting_get_logs_with_depth( + provider, + from, + mid, + addresses.clone(), + topics.clone(), + depth + 1, + ) + .await?; + let right = + bisecting_get_logs_with_depth(provider, mid + 1, to, addresses, topics, depth + 1) + .await?; + left.extend(right); + Ok(left) + }) +} + +/// Collects the unique set of token addresses from all `PoolCreated` events +/// emitted by `factory` in `logs`. +fn pool_created_token_addresses( + factory: Address, + logs: &[Log], +) -> std::collections::HashSet
{ + logs.iter() + .filter_map(|log| { + let t = log.topic0()?; + if *t != PoolCreated::SIGNATURE_HASH || log.address() != factory { + return None; + } + let decoded = PoolCreated::decode_log(&log.inner).ok()?; + Some([decoded.data.token0, decoded.data.token1]) + }) + .flatten() + .collect() +} + +/// Per-event-type state accumulator for one chunk of logs. +#[derive(Default)] +struct LogAccumulator { + new_pools: HashMap, + /// Latest full state per pool from this chunk's `Initialize`/`Swap`. + full_states: HashMap, + /// Liquidity-only state per pool, used when neither `Initialize` nor + /// `Swap` has been seen in this chunk. `(block, liquidity, tick)` — we + /// carry `tick` so consecutive Mint/Burns reuse it (they don't move it). + liq_only: HashMap, + /// Signed liquidity deltas keyed by `(pool, tick_idx)`. + tick_deltas: HashMap<(Address, i32), i128>, +} + +impl LogAccumulator { + /// Records a new pool, filling decimals from the prefetch cache. + /// Symbols are left `None`: a hung `symbol()` call must not block pool + /// inserts, and the async backfill picks them up later. + /// + /// Returns the pool address so the caller can add it to the chunk- + /// local emitter set; `None` if the log fails to decode. + fn handle_pool_created(&mut self, log: &Log, dec_cache: &DecimalsCache) -> Option
{ + let decoded = match PoolCreated::decode_log(&log.inner) { + Ok(d) => d, + Err(err) => { + tracing::warn!(?err, pool = %log.address(), block = ?log.block_number, "failed to decode PoolCreated log"); + return None; + } + }; + let e = &decoded.data; + let pool: Address = e.pool; + let token0: Address = e.token0; + let token1: Address = e.token1; + let created_block = log.block_number.unwrap_or_default(); + tracing::debug!(%pool, %token0, %token1, fee = e.fee.to::(), "discovered pool"); + self.new_pools.insert( + pool, + NewPoolData { + address: pool, + token0, + token1, + fee: e.fee.to::(), + token0_decimals: dec_cache.get(&token0).copied(), + token1_decimals: dec_cache.get(&token1).copied(), + token0_symbol: None, + token1_symbol: None, + created_block, + }, + ); + Some(pool) + } + + /// Records initial price and tick from an `Initialize` event. + /// Preserves any liquidity already seen for the pool in this chunk. + fn handle_initialize(&mut self, log: &Log) { + let decoded = match Initialize::decode_log(&log.inner) { + Ok(d) => d, + Err(err) => { + tracing::warn!(?err, pool = %log.address(), block = ?log.block_number, "failed to decode Initialize log"); + return; + } + }; + let e = &decoded.data; + let pool = log.address(); + let block = log.block_number.unwrap_or_default(); + let liquidity = self + .full_states + .get(&pool) + .map(|s| s.liquidity) + .unwrap_or(0); + self.full_states.insert( + pool, + PoolStateData { + pool_address: pool, + block_number: block, + sqrt_price_x96: e.sqrtPriceX96, + liquidity, + tick: e.tick.as_i32(), + }, + ); + self.liq_only.remove(&pool); + } + + /// Records full pool state (price, liquidity, tick) from a `Swap`. + fn handle_swap(&mut self, log: &Log) { + let decoded = match Swap::decode_log(&log.inner) { + Ok(d) => d, + Err(err) => { + tracing::warn!(?err, pool = %log.address(), block = ?log.block_number, "failed to decode Swap log"); + return; + } + }; + let e = &decoded.data; + let pool = log.address(); + let block = log.block_number.unwrap_or_default(); + self.full_states.insert( + pool, + PoolStateData { + pool_address: pool, + block_number: block, + sqrt_price_x96: e.sqrtPriceX96, + liquidity: e.liquidity, + tick: e.tick.as_i32(), + }, + ); + self.liq_only.remove(&pool); + } + + /// Applies a `Mint`: positive tick deltas at the range bounds, plus a + /// pool-liquidity bump if the active tick is in range + /// (see [`Self::apply_position_delta_to_pool_liq`]). + fn handle_mint(&mut self, log: &Log, base_states: &BasePoolStates) { + let decoded = match Mint::decode_log(&log.inner) { + Ok(d) => d, + Err(err) => { + tracing::warn!(?err, pool = %log.address(), block = ?log.block_number, "failed to decode Mint log"); + return; + } + }; + let e = &decoded.data; + let pool = log.address(); + let block = log.block_number.unwrap_or_default(); + let tick_lower = e.tickLower.as_i32(); + let tick_upper = e.tickUpper.as_i32(); + let amount = e.amount.cast_signed(); + self.record_tick_range_delta(pool, tick_lower, tick_upper, amount); + self.apply_position_delta_to_pool_liq( + pool, + block, + tick_lower, + tick_upper, + amount, + base_states, + ); + } + + /// `handle_mint` with the sign flipped. + fn handle_burn(&mut self, log: &Log, base_states: &BasePoolStates) { + let decoded = match Burn::decode_log(&log.inner) { + Ok(d) => d, + Err(err) => { + tracing::warn!(?err, pool = %log.address(), block = ?log.block_number, "failed to decode Burn log"); + return; + } + }; + let e = &decoded.data; + let pool = log.address(); + let block = log.block_number.unwrap_or_default(); + let tick_lower = e.tickLower.as_i32(); + let tick_upper = e.tickUpper.as_i32(); + let amount = e.amount.cast_signed(); + self.record_tick_range_delta(pool, tick_lower, tick_upper, -amount); + self.apply_position_delta_to_pool_liq( + pool, + block, + tick_lower, + tick_upper, + -amount, + base_states, + ); + } + + fn record_tick_range_delta( + &mut self, + pool: Address, + lower_tick: i32, + upper_tick: i32, + liquidity_delta: i128, + ) { + *self.tick_deltas.entry((pool, lower_tick)).or_default() += liquidity_delta; + *self.tick_deltas.entry((pool, upper_tick)).or_default() -= liquidity_delta; + } + + /// Applies a position-liquidity delta to the pool's *active* + /// liquidity. Uniswap V3 only moves `pool.liquidity` when the current + /// `tick` falls within `[lower, upper)`; positions outside that range + /// affect tick-level liquidity only. + /// + /// Pre-event `(tick, liquidity)` is read in priority order from + /// `full_states[pool]` (this chunk's `Swap`/`Initialize`) → + /// `liq_only[pool]` (this chunk's earlier `Mint`/`Burn`) → + /// `base_states[pool]` (DB). + /// + /// If none of those has the pool, we return silently. Dispatch already + /// filters foreign emitters via `collect_log_changes`'s known-pools + /// gate, so reaching this with no state means Mint/Burn before + /// Initialize for one of our pools — impossible per V3 contract + /// semantics. The silent skip isn't hiding a real bug. + fn apply_position_delta_to_pool_liq( + &mut self, + pool: Address, + block: u64, + tick_lower: i32, + tick_upper: i32, + delta: i128, + base_states: &BasePoolStates, + ) { + let (tick, prev_liq) = if let Some(state) = self.full_states.get(&pool) { + (state.tick, state.liquidity) + } else if let Some(&(_, liq, tick)) = self.liq_only.get(&pool) { + (tick, liq) + } else if let Some(&(tick, liq)) = base_states.get(&pool) { + (tick, liq) + } else { + return; + }; + + let new_liq = if tick_lower <= tick && tick < tick_upper { + let signed = prev_liq.cast_signed().saturating_add(delta); + if signed < 0 { + tracing::error!(%pool, block, prev_liq, delta, "negative pool liquidity computed; clamping to 0"); + 0 + } else { + signed.cast_unsigned() + } + } else { + prev_liq + }; + + if let Some(state) = self.full_states.get_mut(&pool) { + state.liquidity = new_liq; + state.block_number = block; + } else { + self.liq_only.insert(pool, (block, new_liq, tick)); + } + } + + fn into_chunk_changes(self) -> ChunkChanges { + ChunkChanges { + new_pools: self.new_pools.into_values().collect(), + pool_states: self.full_states.into_values().collect(), + liquidity_updates: self + .liq_only + .into_iter() + .map(|(pool, (block, liq, _tick))| LiquidityUpdateData { + pool_address: pool, + block_number: block, + liquidity: liq, + }) + .collect(), + tick_deltas: self + .tick_deltas + .into_iter() + .filter(|(_, d)| *d != 0) + .map(|((pool, tick), delta)| TickDeltaData { + pool_address: pool, + tick_idx: tick, + delta, + }) + .collect(), + } + } +} + +fn collect_log_changes( + factory: Address, + logs: &[Log], + base_states: &BasePoolStates, + dec_cache: &DecimalsCache, + known_pools_db: &HashSet
, +) -> ChunkChanges { + let mut acc = LogAccumulator::default(); + // Pools created earlier in this chunk. With `known_pools_db` (already + // committed) this is the set of accepted emitters for the per-pool + // events that follow. The DB writers' `WHERE EXISTS (… pools WHERE + // factory=$1)` would also drop foreign-emitter writes, but gating here + // keeps the security check in one place and skips the in-memory work. + let mut known_pools_chunk: HashSet
= HashSet::new(); + + for log in logs { + let Some(t) = log.topic0() else { continue }; + let topic = *t; + + if topic == PoolCreated::SIGNATURE_HASH { + // PoolCreated must come from our factory. + if log.address() != factory { + continue; + } + if let Some(pool) = acc.handle_pool_created(log, dec_cache) { + known_pools_chunk.insert(pool); + } + continue; + } + + // Per-pool event: emitter must be one of our factory's pools, + // either committed (DB) or created earlier in this chunk. + let emitter = log.address(); + if !known_pools_db.contains(&emitter) && !known_pools_chunk.contains(&emitter) { + continue; + } + + match topic { + t if t == Initialize::SIGNATURE_HASH => acc.handle_initialize(log), + t if t == Swap::SIGNATURE_HASH => acc.handle_swap(log), + t if t == Mint::SIGNATURE_HASH => acc.handle_mint(log, base_states), + t if t == Burn::SIGNATURE_HASH => acc.handle_burn(log, base_states), + _ => {} + } + } + acc.into_chunk_changes() +} + +#[cfg(test)] +mod tests { + use { + super::*, + alloy_primitives::{ + I256, + U256, + aliases::{I24, U24, U160}, + }, + alloy_sol_types::SolEvent, + contracts::{ + IUniswapV3Factory::IUniswapV3Factory::PoolCreated, + UniswapV3Pool::UniswapV3Pool::{Burn, Initialize, Mint, Swap}, + }, + }; + + const FACTORY: Address = Address::repeat_byte(0xFA); + const POOL: Address = Address::repeat_byte(0x01); + const TOKEN0: Address = Address::repeat_byte(0x02); + const TOKEN1: Address = Address::repeat_byte(0x03); + // `price = 1` in V3's Q64.96 = `sqrt(1) * 2^96 = 2^96`. + const SQRT_PRICE_1: u128 = 1u128 << 96; + + fn t(n: i32) -> I24 { + I24::try_from(n).unwrap() + } + + fn make_log(address: Address, block: u64, event: impl SolEvent) -> Log { + Log { + inner: alloy_primitives::Log { + address, + data: event.encode_log_data(), + }, + block_number: Some(block), + block_hash: None, + block_timestamp: None, + transaction_hash: None, + transaction_index: None, + log_index: None, + removed: false, + } + } + + /// `known_pools_db` builder for tests. An empty set means "no pools + /// committed yet — only in-chunk PoolCreateds are accepted." + fn known(pools: &[Address]) -> HashSet
{ + pools.iter().copied().collect() + } + + #[test] + fn empty_logs_produce_empty_changes() { + let c = collect_log_changes( + FACTORY, + &[], + &Default::default(), + &Default::default(), + &known(&[]), + ); + assert!(c.new_pools.is_empty()); + assert!(c.pool_states.is_empty()); + assert!(c.liquidity_updates.is_empty()); + assert!(c.tick_deltas.is_empty()); + } + + #[test] + fn pool_created_from_factory_inserted() { + let event = PoolCreated { + token0: TOKEN0, + token1: TOKEN1, + fee: U24::from(500u32), + tickSpacing: t(10), + pool: POOL, + }; + let log = make_log(FACTORY, 100, event); + let c = collect_log_changes( + FACTORY, + &[log], + &Default::default(), + &Default::default(), + &known(&[]), + ); + assert_eq!(c.new_pools.len(), 1); + assert_eq!(c.new_pools[0].address, POOL); + assert_eq!(c.new_pools[0].fee, 500); + } + + #[test] + fn pool_created_wrong_factory_ignored() { + let event = PoolCreated { + token0: TOKEN0, + token1: TOKEN1, + fee: U24::from(500u32), + tickSpacing: t(10), + pool: POOL, + }; + let log = make_log(Address::repeat_byte(0xBB), 100, event); + let c = collect_log_changes( + FACTORY, + &[log], + &Default::default(), + &Default::default(), + &known(&[]), + ); + assert!(c.new_pools.is_empty()); + } + + #[test] + fn initialize_creates_full_state_with_zero_liquidity() { + let event = Initialize { + sqrtPriceX96: U160::from(SQRT_PRICE_1), + tick: t(0), + }; + let log = make_log(POOL, 100, event); + let c = collect_log_changes( + FACTORY, + &[log], + &Default::default(), + &Default::default(), + &known(&[POOL]), + ); + assert_eq!(c.pool_states.len(), 1); + assert_eq!(c.pool_states[0].pool_address, POOL); + assert_eq!(c.pool_states[0].block_number, 100); + assert_eq!(c.pool_states[0].tick, 0); + assert_eq!(c.pool_states[0].liquidity, 0); + } + + #[test] + fn swap_creates_full_state() { + let event = Swap { + sender: Address::ZERO, + recipient: Address::ZERO, + amount0: I256::ZERO, + amount1: I256::ZERO, + sqrtPriceX96: U160::from(SQRT_PRICE_1), + liquidity: 500_000u128, + tick: t(42), + }; + let log = make_log(POOL, 200, event); + let c = collect_log_changes( + FACTORY, + &[log], + &Default::default(), + &Default::default(), + &known(&[POOL]), + ); + assert_eq!(c.pool_states.len(), 1); + assert_eq!(c.pool_states[0].tick, 42); + assert_eq!(c.pool_states[0].liquidity, 500_000); + assert_eq!(c.pool_states[0].block_number, 200); + } + + #[test] + fn mint_produces_correct_tick_deltas_and_liq_only() { + let amount = 1_000_000u128; + let event = Mint { + sender: Address::ZERO, + owner: Address::ZERO, + tickLower: t(-100), + tickUpper: t(100), + amount, + amount0: U256::ZERO, + amount1: U256::ZERO, + }; + // Pool starts at tick 0 / liq 0. The Mint at [-100, 100) is + // in-range, so active liquidity grows by `amount`. + let base_states: BasePoolStates = HashMap::from([(POOL, (0i32, 0u128))]); + let log = make_log(POOL, 100, event); + let c = collect_log_changes( + FACTORY, + &[log], + &base_states, + &Default::default(), + &known(&[POOL]), + ); + + assert_eq!(c.tick_deltas.len(), 2); + let lower = c.tick_deltas.iter().find(|d| d.tick_idx == -100).unwrap(); + let upper = c.tick_deltas.iter().find(|d| d.tick_idx == 100).unwrap(); + assert_eq!(lower.delta, amount.cast_signed()); + assert_eq!(upper.delta, -amount.cast_signed()); + + // No prior full state → liq_only update from the event amount. + assert_eq!(c.liquidity_updates.len(), 1); + assert_eq!(c.liquidity_updates[0].liquidity, amount); + assert!(c.pool_states.is_empty()); + } + + #[test] + fn mint_after_swap_updates_full_state_liquidity() { + let swap_liq = 500_000u128; + let after_mint_liq = 600_000u128; + + let swap = Swap { + sender: Address::ZERO, + recipient: Address::ZERO, + amount0: I256::ZERO, + amount1: I256::ZERO, + sqrtPriceX96: U160::from(SQRT_PRICE_1), + liquidity: swap_liq, + tick: t(0), + }; + let mint = Mint { + sender: Address::ZERO, + owner: Address::ZERO, + tickLower: t(-100), + tickUpper: t(100), + amount: 100_000u128, + amount0: U256::ZERO, + amount1: U256::ZERO, + }; + // Swap sets full_states[POOL]; the Mint applies against that. + let logs = vec![make_log(POOL, 200, swap), make_log(POOL, 201, mint)]; + let c = collect_log_changes( + FACTORY, + &logs, + &Default::default(), + &Default::default(), + &known(&[POOL]), + ); + + assert_eq!(c.pool_states.len(), 1); + // Mint adds 100_000 because tick 0 is in [-100, 100). + assert_eq!(c.pool_states[0].liquidity, after_mint_liq); + assert_eq!(c.pool_states[0].block_number, 201); + assert!(c.liquidity_updates.is_empty()); + } + + #[test] + fn burn_zeroes_tick_filtered_out() { + let amount = 1_000_000u128; + let mint = Mint { + sender: Address::ZERO, + owner: Address::ZERO, + tickLower: t(-100), + tickUpper: t(100), + amount, + amount0: U256::ZERO, + amount1: U256::ZERO, + }; + let burn = Burn { + owner: Address::ZERO, + tickLower: t(-100), + tickUpper: t(100), + amount, + amount0: U256::ZERO, + amount1: U256::ZERO, + }; + let logs = vec![make_log(POOL, 100, mint), make_log(POOL, 101, burn)]; + let c = collect_log_changes( + FACTORY, + &logs, + &Default::default(), + &Default::default(), + &known(&[POOL]), + ); + assert!(c.tick_deltas.is_empty(), "zero-net ticks must be pruned"); + } + + #[test] + fn partial_burn_leaves_nonzero_delta() { + let mint_amount = 1_000_000u128; + let burn_amount = 400_000u128; + let mint = Mint { + sender: Address::ZERO, + owner: Address::ZERO, + tickLower: t(-100), + tickUpper: t(100), + amount: mint_amount, + amount0: U256::ZERO, + amount1: U256::ZERO, + }; + let burn = Burn { + owner: Address::ZERO, + tickLower: t(-100), + tickUpper: t(100), + amount: burn_amount, + amount0: U256::ZERO, + amount1: U256::ZERO, + }; + let logs = vec![make_log(POOL, 100, mint), make_log(POOL, 101, burn)]; + let c = collect_log_changes( + FACTORY, + &logs, + &Default::default(), + &Default::default(), + &known(&[POOL]), + ); + + let expected = (mint_amount - burn_amount).cast_signed(); + let lower = c.tick_deltas.iter().find(|d| d.tick_idx == -100).unwrap(); + let upper = c.tick_deltas.iter().find(|d| d.tick_idx == 100).unwrap(); + assert_eq!(lower.delta, expected); + assert_eq!(upper.delta, -expected); + } + + #[test] + fn pool_created_and_initialize_same_chunk() { + let created = PoolCreated { + token0: TOKEN0, + token1: TOKEN1, + fee: U24::from(3000u32), + tickSpacing: t(60), + pool: POOL, + }; + let init = Initialize { + sqrtPriceX96: U160::from(SQRT_PRICE_1), + tick: t(0), + }; + let logs = vec![make_log(FACTORY, 100, created), make_log(POOL, 100, init)]; + // POOL is admitted via the chunk-local set populated by this + // chunk's PoolCreated; the Initialize that follows is accepted. + let c = collect_log_changes( + FACTORY, + &logs, + &Default::default(), + &Default::default(), + &known(&[]), + ); + assert_eq!(c.new_pools.len(), 1); + assert_eq!(c.pool_states.len(), 1); + assert_eq!(c.pool_states[0].pool_address, POOL); + } + + #[test] + fn event_from_unknown_emitter_is_dropped() { + // A foreign emitter (not in known_pools_db, not created in this + // chunk) must not affect indexed state. Without the dispatch gate + // its Swap would slip into `pool_states` and only get dropped at + // write time by the DB's `WHERE EXISTS` guard. + let foreign = Address::repeat_byte(0xEE); + let swap = Swap { + sender: Address::ZERO, + recipient: Address::ZERO, + amount0: I256::ZERO, + amount1: I256::ZERO, + sqrtPriceX96: U160::from(SQRT_PRICE_1), + liquidity: 500_000u128, + tick: t(42), + }; + let log = make_log(foreign, 100, swap); + let c = collect_log_changes( + FACTORY, + &[log], + &Default::default(), + &Default::default(), + &known(&[POOL]), + ); + assert!( + c.pool_states.is_empty(), + "foreign-emitter Swap must be dropped" + ); + assert!(c.tick_deltas.is_empty()); + } +} diff --git a/crates/pool-indexer/src/lib.rs b/crates/pool-indexer/src/lib.rs new file mode 100644 index 0000000000..7a12692bfb --- /dev/null +++ b/crates/pool-indexer/src/lib.rs @@ -0,0 +1,10 @@ +pub mod config; +pub use run::{run, start}; + +mod api; +mod arguments; +mod db; +mod indexer; +mod metrics; +mod run; +mod subgraph_seeder; diff --git a/crates/pool-indexer/src/main.rs b/crates/pool-indexer/src/main.rs new file mode 100644 index 0000000000..646eb280fd --- /dev/null +++ b/crates/pool-indexer/src/main.rs @@ -0,0 +1,12 @@ +#[cfg(feature = "mimalloc-allocator")] +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +#[cfg(not(feature = "mimalloc-allocator"))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +#[tokio::main] +async fn main() { + pool_indexer::start(std::env::args()).await; +} diff --git a/crates/pool-indexer/src/metrics.rs b/crates/pool-indexer/src/metrics.rs new file mode 100644 index 0000000000..316cfc9790 --- /dev/null +++ b/crates/pool-indexer/src/metrics.rs @@ -0,0 +1,75 @@ +use {prometheus::HistogramVec, prometheus_metric_storage::MetricStorage}; + +#[derive(MetricStorage)] +#[metric(subsystem = "pool_indexer")] +pub struct Metrics { + /// Chunk commit duration. The `_count` series doubles as a chunks- + /// committed rate. + #[metric( + labels("network"), + buckets(0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0) + )] + pub chunk_commit_seconds: HistogramVec, + + /// Events applied to the DB, labelled by event type. + #[metric(labels("network", "kind"))] + pub events_applied: prometheus::IntCounterVec, + + /// Highest block committed by the live indexer. + #[metric(labels("network"))] + pub indexed_block: prometheus::IntGaugeVec, + + /// Blocks between the chain head and the indexer's checkpoint. + /// Refreshed at the start of every `run_once` and after each chunk + /// commit so dashboards can watch the lag drain in real time. + #[metric(labels("network"))] + pub indexer_lag_blocks: prometheus::IntGaugeVec, + + /// `run_once` failures that forced a retry. + #[metric(labels("network"))] + pub indexer_errors: prometheus::IntCounterVec, + + /// Tokens still missing `symbol` / `decimals`. Sampled each backfill pass. + #[metric(labels("network", "field"))] + pub backfill_pending: prometheus::IntGaugeVec, + + /// Backfill writes. `result=ok` is a real value, `result=empty` is the + /// "tried and failed" sentinel (so we don't retry forever). + #[metric(labels("network", "field", "result"))] + pub backfilled: prometheus::IntCounterVec, + + /// API request count by route + HTTP status. + #[metric(labels("route", "status"))] + pub api_requests: prometheus::IntCounterVec, + + /// API request latency by route. + #[metric( + labels("route"), + buckets(0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5) + )] + pub api_request_seconds: HistogramVec, +} + +impl Metrics { + pub fn get() -> &'static Self { + Self::instance(observe::metrics::get_storage_registry()) + .expect("unexpected pool_indexer metrics duplicate registration") + } +} + +/// `timer(&[labels])` on a [`HistogramVec`] returns a guard that records +/// elapsed wall time on drop. +pub trait HistogramVecExt { + #[must_use] + fn timer<'a>(&'a self, labels: &'a [&'a str]) -> impl Drop + use<'a, Self>; +} + +impl HistogramVecExt for HistogramVec { + fn timer<'a>(&'a self, labels: &'a [&'a str]) -> impl Drop + use<'a> { + let start = std::time::Instant::now(); + scopeguard::guard(start, move |start| { + self.with_label_values(labels) + .observe(start.elapsed().as_secs_f64()); + }) + } +} diff --git a/crates/pool-indexer/src/run.rs b/crates/pool-indexer/src/run.rs new file mode 100644 index 0000000000..b9ce460fcf --- /dev/null +++ b/crates/pool-indexer/src/run.rs @@ -0,0 +1,272 @@ +use { + crate::{ + api::AppState, + arguments::Arguments, + config::{Configuration, NetworkConfig}, + indexer::uniswap_v3::UniswapV3Indexer, + }, + alloy_provider::Provider, + clap::Parser, + ethrpc::{AlloyProvider, Config as EthRpcConfig, web3}, + sqlx::{PgPool, postgres::PgPoolOptions}, + std::sync::{ + Arc, + atomic::{AtomicBool, AtomicUsize, Ordering}, + }, + tokio::task::JoinSet, +}; + +pub async fn start(args: impl Iterator) { + let args = Arguments::parse_from(args); + initialize_observability(&args); + observe::metrics::setup_registry(None, None); + let config = Configuration::from_path(&args.config).expect("failed to load configuration"); + tracing::info!("pool-indexer starting"); + run(config).await; +} + +pub async fn run(config: Configuration) { + let db = connect_db(&config).await; + let api_state = build_api_state(&db, &config.network); + + // Flips to 200 once every factory has finished seeding + catch-up. + let startup = Arc::new(Some(AtomicBool::new(false))); + let barrier = Arc::new(StartupBarrier::new( + startup.clone(), + config.network.factories.len(), + )); + + // Abort the metrics task when `run` exits, so tests can rebind the port. + let _metrics = AbortOnDrop(observe::metrics::serve_metrics( + Arc::new(AlwaysAlive), + config.metrics.bind_address, + Default::default(), + startup, + )); + + let mut set = JoinSet::new(); + let api_router = crate::api::router(api_state); + let api_addr = config.api.bind_address; + set.spawn(async move { serve(api_router, api_addr).await }); + set.spawn(run_network_indexer(db, config.network, barrier)); + + // Both spawned tasks are infinite loops; any return is a bug, so crash + // and let the orchestrator restart the pod. + if let Some(result) = set.join_next().await { + panic!("pool-indexer task exited (expected infinite loop): {result:?}"); + } +} + +/// Counts down pending factory bootstraps; flips the `/startup` flag to +/// ready when the count hits zero. Latch-once for the process lifetime. +struct StartupBarrier { + remaining: AtomicUsize, + flag: Arc>, +} + +impl StartupBarrier { + fn new(flag: Arc>, total: usize) -> Self { + Self { + remaining: AtomicUsize::new(total), + flag, + } + } + + fn factory_bootstrapped(&self) { + if self.remaining.fetch_sub(1, Ordering::AcqRel) == 1 + && let Some(flag) = self.flag.as_ref() + { + flag.store(true, Ordering::Release); + tracing::info!("all factories bootstrapped, marking startup ready"); + } + } +} + +struct AbortOnDrop(tokio::task::JoinHandle<()>); +impl Drop for AbortOnDrop { + fn drop(&mut self) { + self.0.abort(); + } +} + +/// The indexer panics on unrecoverable faults, so process-up == alive. +struct AlwaysAlive; + +#[async_trait::async_trait] +impl observe::metrics::LivenessChecking for AlwaysAlive { + async fn is_alive(&self) -> bool { + true + } +} + +fn initialize_observability(args: &Arguments) { + let obs_config = observe::Config::new( + args.logging.log_filter.as_str(), + args.logging.log_stderr_threshold, + args.logging.use_json_logs, + None, + ); + observe::tracing::init::initialize(&obs_config); + observe::panic_hook::install(); +} + +fn build_api_state(db: &PgPool, network: &NetworkConfig) -> Arc { + Arc::new(AppState { + db: db.clone(), + network: network.name.clone(), + }) +} + +async fn run_network_indexer(db: PgPool, network: NetworkConfig, barrier: Arc) { + tracing::info!( + network = %network.name, + chain_id = network.chain_id, + factories = network.factories.len(), + "starting network indexer", + ); + + let provider = build_provider(&network); + + // Catch misconfigured RPC-vs-network pairings (e.g. chain_id=1 pointed + // at an Arbitrum node) before we index the wrong chain into the DB. + let actual_chain_id = provider + .get_chain_id() + .await + .expect("failed to fetch chain_id from RPC"); + assert_eq!( + actual_chain_id, network.chain_id, + "chain_id mismatch for network {}: config says {}, RPC reports {}", + network.name, network.chain_id, actual_chain_id, + ); + + let network = Arc::new(network); + + // One task per factory. Provider + DB pool are shared; checkpoints are + // per-factory because they're keyed by `contract_address`. + let mut factory_set = JoinSet::new(); + for factory in network.factories.iter().copied() { + let indexer = UniswapV3Indexer::new( + provider.clone(), + db.clone(), + &network.indexer_config(factory.address), + ); + factory_set.spawn(run_factory_indexer( + db.clone(), + indexer, + network.clone(), + factory, + barrier.clone(), + )); + } + + // The symbol/decimals backfill scans every token missing the field, so + // one pair per process is enough (not per-factory). Spawned into the + // same JoinSet so a panic crashes the process via the same supervisor. + let backfill_concurrency = network.prefetch_concurrency; + let backfill_interval = network.poll_interval(); + factory_set.spawn(crate::indexer::uniswap_v3::backfill_symbols( + provider.clone(), + db.clone(), + network.name.clone(), + backfill_concurrency, + backfill_interval, + )); + factory_set.spawn(crate::indexer::uniswap_v3::backfill_decimals( + provider.clone(), + db.clone(), + network.name.clone(), + backfill_concurrency, + backfill_interval, + )); + + // Factory indexers + backfill are all infinite loops; any return is a + // bug, so crash and let the orchestrator restart the pod. + if let Some(result) = factory_set.join_next().await { + panic!( + "pool-indexer {}: task exited (expected infinite loop): {result:?}", + network.name, + ); + } +} + +async fn run_factory_indexer( + db: PgPool, + indexer: UniswapV3Indexer, + network: Arc, + factory: crate::config::FactoryConfig, + barrier: Arc, +) { + tracing::info!( + network = %network.name, + chain_id = network.chain_id, + factory = %factory.address, + "starting factory indexer", + ); + + bootstrap_factory(&db, &indexer, &network, &factory).await; + barrier.factory_bootstrapped(); + indexer.run(network.poll_interval()).await; +} + +/// Seed + catch-up for a fresh factory. If a checkpoint already exists, +/// skip straight to live indexing. +async fn bootstrap_factory( + db: &PgPool, + indexer: &UniswapV3Indexer, + network: &NetworkConfig, + factory: &crate::config::FactoryConfig, +) { + let checkpoint = crate::db::uniswap_v3::get_checkpoint(db, &factory.address) + .await + .expect("failed to read checkpoint"); + if let Some(block) = checkpoint { + tracing::info!( + chain_id = network.chain_id, + factory = %factory.address, + block, + "existing checkpoint found, skipping bootstrap", + ); + return; + } + + let seeded_block = crate::subgraph_seeder::seed( + db, + network.name.as_str(), + network.chain_id, + factory.address, + &network.subgraph_url, + network.seed_block, + ) + .await + .expect("subgraph seeding failed"); + indexer + .catch_up(seeded_block) + .await + .expect("catch-up indexing failed"); +} + +fn build_provider(network: &NetworkConfig) -> AlloyProvider { + web3( + EthRpcConfig::default(), + &network.rpc_url, + Some(&format!("pool-indexer-{}", network.name)), + ) + .provider + .clone() +} + +async fn connect_db(config: &Configuration) -> sqlx::PgPool { + PgPoolOptions::new() + .max_connections(config.database.max_connections.get()) + .connect(config.database.url.as_str()) + .await + .expect("failed to connect to database") +} + +async fn serve(router: axum::Router, addr: std::net::SocketAddr) { + let listener = tokio::net::TcpListener::bind(addr) + .await + .expect("failed to bind TCP listener"); + tracing::info!(%addr, "serving pool-indexer API"); + axum::serve(listener, router).await.expect("server error"); +} diff --git a/crates/pool-indexer/src/subgraph_seeder.rs b/crates/pool-indexer/src/subgraph_seeder.rs new file mode 100644 index 0000000000..2179840f9b --- /dev/null +++ b/crates/pool-indexer/src/subgraph_seeder.rs @@ -0,0 +1,480 @@ +//! Bootstraps the pool-indexer DB from a Uniswap V3 subgraph. +//! +//! 1. **Pools** — fetched with keyset pagination, written page-by-page. +//! 2. **Ticks** — fetched concurrently per pool (up to [`TICK_CONCURRENCY`] in +//! flight), buffered, then swapped in via a single delete-then-insert +//! transaction so the API never sees an empty tick set mid-reseed. +//! +//! Both phases query at the same block so the snapshot is consistent. The +//! caller catches up live state via `UniswapV3Indexer::catch_up` after +//! seeding returns. + +use { + crate::{ + db::uniswap_v3 as db, + indexer::uniswap_v3::{NewPoolData, PoolStateData, TickDeltaData}, + }, + alloy_primitives::{Address, aliases::U160}, + anyhow::{Context, Result, bail}, + futures::{StreamExt, TryStreamExt}, + reqwest::Client, + serde::Deserialize, + serde_json::{Value, json}, + sqlx::PgPool, + std::time::Duration, + tracing::{info, instrument}, + url::Url, +}; + +/// Number of pools (or ticks) returned per GraphQL page. +const PAGE_SIZE: usize = 1000; + +/// Maximum number of pools whose ticks are fetched concurrently. +const TICK_CONCURRENCY: usize = 50; + +/// Timeout for individual subgraph HTTP requests. +const SUBGRAPH_REQUEST_TIMEOUT: Duration = Duration::from_secs(30); + +/// One below the minimum Uniswap V3 tick (-887272), so the first page +/// includes the lowest valid tick. +const TICK_IDX_CURSOR_START: i64 = -887_273; + +#[derive(Deserialize)] +struct GqlResponse { + data: Option, + errors: Option, +} + +#[derive(Deserialize)] +struct PoolsPage { + pools: Vec, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct SubgraphPool { + id: String, + token0: SubgraphToken, + token1: SubgraphToken, + fee_tier: String, + created_at_block_number: String, + sqrt_price: String, + liquidity: String, + tick: Option, +} + +#[derive(Deserialize)] +struct SubgraphToken { + id: String, + decimals: String, + symbol: Option, +} + +#[derive(Deserialize)] +struct TicksPage { + ticks: Vec, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct SubgraphTick { + tick_idx: String, + liquidity_net: String, +} + +#[derive(Deserialize)] +struct MetaPage { + #[serde(rename = "_meta")] + meta: MetaInfo, +} + +#[derive(Deserialize)] +struct MetaInfo { + block: MetaBlock, +} + +#[derive(Deserialize)] +struct MetaBlock { + number: u64, +} + +#[derive(Clone)] +struct SubgraphClient { + http: Client, + url: Url, +} + +impl SubgraphClient { + fn new(url: &Url) -> Result { + let http = Client::builder() + .timeout(SUBGRAPH_REQUEST_TIMEOUT) + .build() + .context("build HTTP client")?; + + Ok(Self { + http, + url: url.clone(), + }) + } + + /// Runs a GraphQL query and decodes `data`. Errors if the response has + /// a top-level `errors` array. + async fn query Deserialize<'de>>(&self, query: &str, vars: Value) -> Result { + let response = self + .http + .post(self.url.as_str()) + .json(&json!({ "query": query, "variables": vars })) + .send() + .await + .context("subgraph HTTP request")?; + + let gql_response: GqlResponse = + response.json().await.context("decode subgraph response")?; + if let Some(errors) = gql_response.errors { + bail!("subgraph errors: {errors}"); + } + + let data = gql_response.data.context("missing data field")?; + serde_json::from_value(data).context("decode subgraph data") + } + + async fn current_block(&self) -> Result { + let page: MetaPage = self + .query("{ _meta { block { number } } }", json!({})) + .await?; + Ok(page.meta.block.number) + } + + /// Reads the factory address from the subgraph. Used to catch + /// misconfigured deployments (e.g. a Uniswap V3 config pointed at a + /// PancakeSwap V3 subgraph) before any rows get written. + /// + /// Queried via `factories` rather than `pool.factory` because some + /// Goldsky-hosted Uniswap V3 schema forks (e.g. Ink) drop the per-pool + /// `factory` field but keep the singleton `Factory` entity. + async fn fetch_factory_attestation(&self, block: u64) -> Result
{ + #[derive(Deserialize)] + struct ProbePage { + factories: Vec, + } + #[derive(Deserialize)] + struct FactoryProbe { + id: String, + } + let query = "query($block: Int!) { + factories(first: 1, block: {number: $block}) { + id + } + }"; + let page: ProbePage = self.query(query, json!({ "block": block })).await?; + let probe = page + .factories + .into_iter() + .next() + .context("subgraph returned no factory entity — cannot attest factory address")?; + probe + .id + .parse::
() + .context("parse factory address from subgraph probe") + } + + /// One page of pools at `block`, ordered by id, starting after + /// `cursor` (empty string for the first page). + async fn fetch_pools_page(&self, block: u64, cursor: &str) -> Result> { + let query = "query($block: Int!, $cursor: String!) { + pools(first: 1000, orderBy: id, where: {id_gt: $cursor}, block: {number: $block}) { + id + token0 { id decimals symbol } + token1 { id decimals symbol } + feeTier + createdAtBlockNumber + sqrtPrice + liquidity + tick + } + }"; + + let page: PoolsPage = self + .query(query, json!({ "block": block, "cursor": cursor })) + .await?; + Ok(page.pools) + } + + /// All ticks for `pool_id` at `block`, via keyset pagination over + /// `tickIdx`. Each `delta` is the subgraph's `liquidityNet` — an + /// absolute net, not a running delta — and the seeder writes it + /// directly (no accumulation). + async fn fetch_ticks_for_pool( + &self, + pool_id: String, + block: u64, + ) -> Result> { + let query = "query($pool: String!, $cursor: Int!, $block: Int!) { + ticks( + first: 1000, + orderBy: tickIdx, + where: { pool: $pool, tickIdx_gt: $cursor }, + block: { number: $block } + ) { + tickIdx + liquidityNet + } + }"; + + let pool_address: Address = pool_id.parse().context("parse pool address")?; + let mut ticks = Vec::new(); + let mut cursor = TICK_IDX_CURSOR_START; + + loop { + let page: TicksPage = self + .query( + query, + json!({ "pool": pool_id, "cursor": cursor, "block": block }), + ) + .await?; + + for tick in &page.ticks { + ticks.push(TickDeltaData { + pool_address, + tick_idx: tick.tick_idx.parse().context("parse tickIdx")?, + delta: tick.liquidity_net.parse().context("parse liquidityNet")?, + }); + } + + if page.ticks.len() < PAGE_SIZE { + break; + } + + cursor = ticks.last().expect("tick page is non-empty").tick_idx as i64; + } + + Ok(ticks) + } +} + +struct SubgraphSeeder<'a> { + db: &'a PgPool, + chain_id: u64, + factory: Address, + subgraph: SubgraphClient, + snapshot_block: u64, +} + +impl<'a> SubgraphSeeder<'a> { + async fn new( + db: &'a PgPool, + chain_id: u64, + factory: Address, + subgraph_url: &Url, + block: Option, + ) -> Result { + let subgraph = SubgraphClient::new(subgraph_url)?; + let snapshot_block = match block { + Some(block) => block, + None => subgraph + .current_block() + .await + .context("fetch current subgraph block")?, + }; + + Ok(Self { + db, + chain_id, + factory, + subgraph, + snapshot_block, + }) + } + + #[instrument(skip_all, fields(chain_id = self.chain_id))] + async fn seed(self) -> Result { + info!( + block = self.snapshot_block, + "seeding pool-indexer from subgraph" + ); + + // Confirm the subgraph's factory matches our configured one before + // writing anything. Otherwise pools get stamped with a `factory` + // that doesn't reflect their on-chain origin. + let subgraph_factory = self + .subgraph + .fetch_factory_attestation(self.snapshot_block) + .await + .context("factory attestation probe failed")?; + anyhow::ensure!( + subgraph_factory == self.factory, + "subgraph factory mismatch: configured {configured:#x}, subgraph reports {actual:#x} \ + — verify the subgraph URL matches the configured factory", + configured = self.factory, + actual = subgraph_factory, + ); + + let pool_ids = self.seed_pools().await?; + let total_ticks = self.seed_ticks(&pool_ids).await?; + + info!( + block = self.snapshot_block, + pools = pool_ids.len(), + ticks = total_ticks, + "seeding complete" + ); + Ok(self.snapshot_block) + } + + async fn seed_pools(&self) -> Result> { + let mut all_pool_ids = Vec::new(); + let mut cursor = String::new(); + + loop { + let page = self + .subgraph + .fetch_pools_page(self.snapshot_block, &cursor) + .await?; + + all_pool_ids.extend(self.persist_pool_page(&page).await?); + info!(total = all_pool_ids.len(), "pools seeded"); + + if page.len() < PAGE_SIZE { + break; + } + + cursor = page.last().expect("full pages are non-empty").id.clone(); + } + + info!( + total = all_pool_ids.len(), + "all pools seeded — starting tick seeding" + ); + Ok(all_pool_ids) + } + + async fn persist_pool_page(&self, page: &[SubgraphPool]) -> Result> { + let mut pool_ids = Vec::with_capacity(page.len()); + let mut new_pools = Vec::with_capacity(page.len()); + let mut pool_states = Vec::with_capacity(page.len()); + + for pool in page { + let (pool_id, new_pool, pool_state) = parse_seeded_pool(pool, self.snapshot_block)?; + pool_ids.push(pool_id); + new_pools.push(new_pool); + + if let Some(pool_state) = pool_state { + pool_states.push(pool_state); + } + } + + let mut tx = self.db.begin().await.context("begin pool tx")?; + db::insert_pools(&mut tx, &self.factory, &new_pools).await?; + db::upsert_pool_states(&mut tx, &self.factory, &pool_states).await?; + tx.commit().await.context("commit pool tx")?; + + Ok(pool_ids) + } + + async fn seed_ticks(&self, pool_ids: &[String]) -> Result { + // Delete + insert run in one transaction so the API never sees an + // empty tick set mid-reseed. Subgraph fetches happen outside the + // tx so we don't hold a DB connection during slow HTTP I/O. + let mut all_ticks: Vec = Vec::new(); + for pool_batch in pool_ids.chunks(TICK_CONCURRENCY) { + let ticks = self.fetch_tick_batch(pool_batch).await?; + all_ticks.extend(ticks); + info!(total = all_ticks.len(), "ticks fetched"); + } + + let total_ticks = all_ticks.len(); + let mut tx = self.db.begin().await.context("begin tick reseed tx")?; + db::delete_ticks_for_factory(&mut tx, &self.factory).await?; + if !all_ticks.is_empty() { + db::batch_seed_ticks(&mut tx, &self.factory, &all_ticks).await?; + } + tx.commit().await.context("commit tick reseed tx")?; + + info!(total = total_ticks, "ticks seeded"); + Ok(total_ticks) + } + + async fn fetch_tick_batch(&self, pool_batch: &[String]) -> Result> { + let subgraph = self.subgraph.clone(); + let snapshot_block = self.snapshot_block; + + let tick_batches: Vec> = + futures::stream::iter(pool_batch.iter().cloned()) + .map(move |pool_id| { + let subgraph = subgraph.clone(); + async move { subgraph.fetch_ticks_for_pool(pool_id, snapshot_block).await } + }) + .buffer_unordered(TICK_CONCURRENCY) + .try_collect() + .await?; + + Ok(tick_batches.into_iter().flatten().collect()) + } +} + +fn parse_seeded_pool( + pool: &SubgraphPool, + snapshot_block: u64, +) -> Result<(String, NewPoolData, Option)> { + let address: Address = pool.id.parse().context("parse pool id")?; + let new_pool = NewPoolData { + address, + token0: pool.token0.id.parse().context("parse token0")?, + token1: pool.token1.id.parse().context("parse token1")?, + fee: pool.fee_tier.parse().context("parse feeTier")?, + token0_decimals: pool.token0.decimals.parse::().ok(), + token1_decimals: pool.token1.decimals.parse::().ok(), + token0_symbol: pool.token0.symbol.clone(), + token1_symbol: pool.token1.symbol.clone(), + created_block: pool + .created_at_block_number + .parse() + .context("parse createdAtBlockNumber")?, + }; + + Ok(( + pool.id.clone(), + new_pool, + parse_seeded_pool_state(pool, address, snapshot_block)?, + )) +} + +fn parse_seeded_pool_state( + pool: &SubgraphPool, + address: Address, + snapshot_block: u64, +) -> Result> { + let Some(tick) = pool.tick.as_deref() else { + return Ok(None); + }; + if pool.sqrt_price == "0" { + return Ok(None); + } + + Ok(Some(PoolStateData { + pool_address: address, + block_number: snapshot_block, + sqrt_price_x96: pool.sqrt_price.parse::().context("parse sqrtPrice")?, + liquidity: pool.liquidity.parse().context("parse liquidity")?, + tick: tick.parse().context("parse tick")?, + })) +} + +/// Seeds pools and ticks from the subgraph and returns the seeded block. +/// The caller catches up from there via `UniswapV3Indexer::catch_up`. +pub async fn seed( + db: &PgPool, + network: &str, + chain_id: u64, + factory: Address, + subgraph_url: &Url, + block: Option, +) -> Result { + let start = std::time::Instant::now(); + let result = SubgraphSeeder::new(db, chain_id, factory, subgraph_url, block) + .await? + .seed() + .await; + info!(network, %factory, elapsed = ?start.elapsed(), "subgraph seed complete"); + result +} diff --git a/crates/price-estimation/Cargo.toml b/crates/price-estimation/Cargo.toml new file mode 100644 index 0000000000..98ea29733c --- /dev/null +++ b/crates/price-estimation/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "price-estimation" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy = { workspace = true, features = ["providers", "rpc", "rpc-types", "sol-types"] } +anyhow = { workspace = true } +app-data = { workspace = true } +arc-swap = { workspace = true } +async-trait = { workspace = true } +bad-tokens = { workspace = true } +balance-overrides = { workspace = true } +bigdecimal = { workspace = true } +bytes-hex = { workspace = true } +cached = { workspace = true } +chain = { workspace = true } +chrono = { workspace = true } +clap = { workspace = true } +configs = { workspace = true } +const-hex = { workspace = true } +contracts = { workspace = true } +dashmap = { workspace = true } +derive_more = { workspace = true } +ethrpc = { workspace = true } +futures = { workspace = true } +gas-price-estimation = { workspace = true } +http-client = { workspace = true } +humantime = { workspace = true } +humantime-serde = { workspace = true } +itertools = { workspace = true } +mockall = { workspace = true, optional = true } +model = { workspace = true } +moka = { workspace = true } +num = { workspace = true } +number = { workspace = true } +observe = { workspace = true } +prometheus = { workspace = true } +prometheus-metric-storage = { workspace = true } +rand = { workspace = true } +rate-limit = { workspace = true } +request-sharing = { workspace = true } +reqwest = { workspace = true, features = ["query"] } +rust_decimal = { workspace = true, features = ["maths"] } +serde = { workspace = true } +serde_json = { workspace = true } +serde_with = { workspace = true } +simulator = { workspace = true } +thiserror = { workspace = true } +token-info = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +url = { workspace = true } + +[dev-dependencies] +ethrpc = { workspace = true, features = ["test-util"] } +hex-literal = { workspace = true } +maplit = { workspace = true } +mockall = { workspace = true } +testlib = { workspace = true } +token-info = { workspace = true, features = ["test-util"] } +toml = { workspace = true } + +[features] +test-util = ["dep:mockall"] + +[lints] +workspace = true diff --git a/crates/price-estimation/LICENSE-APACHE b/crates/price-estimation/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/price-estimation/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/price-estimation/LICENSE-MIT b/crates/price-estimation/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/price-estimation/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/shared/src/price_estimation/buffered.rs b/crates/price-estimation/src/buffered.rs similarity index 95% rename from crates/shared/src/price_estimation/buffered.rs rename to crates/price-estimation/src/buffered.rs index 0f23d3bc25..6cebf2e974 100644 --- a/crates/shared/src/price_estimation/buffered.rs +++ b/crates/price-estimation/src/buffered.rs @@ -2,19 +2,17 @@ //! requests into batches. use { - crate::price_estimation::{ + crate::{ PriceEstimationError, native::{NativePriceEstimateResult, NativePriceEstimating}, }, alloy::primitives::Address, anyhow::anyhow, - ethrpc::alloy::conversions::IntoLegacy, futures::{ channel::mpsc, future::FutureExt as _, stream::{self, FusedStream, Stream, StreamExt as _}, }, - primitive_types::H160, std::{ collections::{HashMap, HashSet}, future::Future, @@ -53,11 +51,11 @@ pub trait NativePriceBatchFetching: Sync + Send + NativePriceEstimating { /// estimator result fn fetch_native_prices( &self, - tokens: HashSet, + tokens: HashSet
, timeout: Duration, ) -> futures::future::BoxFuture< '_, - Result, PriceEstimationError>, + Result, PriceEstimationError>, >; /// Returns the number of prices that can be fetched in a single batch. @@ -69,14 +67,14 @@ pub trait NativePriceBatchFetching: Sync + Send + NativePriceEstimating { #[derive(Clone)] pub struct BufferedRequest { inner: std::marker::PhantomData, - requests: mpsc::UnboundedSender, + requests: mpsc::UnboundedSender
, results: broadcast::Sender, } /// Object to map the token with its native price estimator result #[derive(Clone)] struct NativePriceResult { - token: H160, + token: Address, result: Result, } @@ -99,19 +97,17 @@ where let mut rx = self.results.subscribe(); // Sends the token for requesting price - self.requests - .unbounded_send(token.into_legacy()) - .map_err(|e| { - PriceEstimationError::ProtocolInternal(anyhow!( - "failed to append a new token to the queue: {e:?}" - )) - })?; + self.requests.unbounded_send(token).map_err(|e| { + PriceEstimationError::ProtocolInternal(anyhow!( + "failed to append a new token to the queue: {e:?}" + )) + })?; tokio::time::timeout(timeout, async { loop { match rx.recv().await { Ok(value) => { - if value.token == token.into_legacy() { + if value.token == token { return value.result; } } @@ -161,7 +157,7 @@ where fn background_worker( inner: Arc, config: Configuration, - requests: mpsc::UnboundedReceiver, + requests: mpsc::UnboundedReceiver
, results_sender: broadcast::Sender, ) -> JoinHandle<()> { let timeout = config.result_ready_timeout; @@ -254,10 +250,7 @@ where mod tests { use { super::*, - crate::price_estimation::{ - HEALTHY_PRICE_ESTIMATION_TIME, - native::MockNativePriceEstimating, - }, + crate::{HEALTHY_PRICE_ESTIMATION_TIME, native::MockNativePriceEstimating}, futures::future::try_join_all, num::ToPrimitive, tokio::time::sleep, @@ -271,10 +264,10 @@ mod tests { ) -> futures::future::BoxFuture<'_, NativePriceEstimateResult> { async move { let prices = self - .fetch_native_prices(HashSet::from([token.into_legacy()]), timeout) + .fetch_native_prices(HashSet::from([token]), timeout) .await?; prices - .get(&token.into_legacy()) + .get(&token) .cloned() .ok_or(PriceEstimationError::NoLiquidity)? } diff --git a/crates/shared/src/price_estimation/competition/mod.rs b/crates/price-estimation/src/competition/mod.rs similarity index 90% rename from crates/shared/src/price_estimation/competition/mod.rs rename to crates/price-estimation/src/competition/mod.rs index 9db12164b4..b2b1e1cb9e 100644 --- a/crates/shared/src/price_estimation/competition/mod.rs +++ b/crates/price-estimation/src/competition/mod.rs @@ -1,11 +1,11 @@ use { super::{QuoteVerificationMode, native::NativePriceEstimating}, - crate::price_estimation::PriceEstimationError, + crate::PriceEstimationError, futures::{ future::{BoxFuture, FutureExt}, stream::{FuturesUnordered, StreamExt}, }, - gas_estimation::GasPriceEstimating, + gas_price_estimation::GasPriceEstimating, model::order::OrderKind, std::{ cmp::Ordering, @@ -108,9 +108,10 @@ impl CompetitionEstimator { while stage_index < self.stages.len() && requests.len() < requests_for_batch { let stage = &self.stages.get(stage_index).expect("index checked by loop"); - let futures = stage.iter().enumerate().map(|(index, (_name, estimator))| { + let futures = stage.iter().enumerate().map(|(index, (name, estimator))| { get_single_result(Context { estimator, + name, query: query.clone(), remaining_stages: Arc::clone(&remaining_stages), }) @@ -160,7 +161,7 @@ impl CompetitionEstimator { if result.is_ok() { metrics() .queries_won - .with_label_values(&[name, kind.label()]) + .with_label_values(&[name.as_str(), kind.label()]) .inc(); } result @@ -175,6 +176,8 @@ struct Context<'a, ESTIMATOR, QUERY> { /// the number of stages that are left after the queries /// produced by this Context's stages. remaining_stages: Arc>, + /// Name of the estimator + name: &'a str, } impl<'a, E, Q> Context<'a, E, Q> { @@ -194,6 +197,10 @@ fn compare_error(a: &PriceEstimationError, b: &PriceEstimationError) -> Ordering fn error_to_integer_priority(err: &PriceEstimationError) -> u8 { match err { // highest priority (prefer) + PriceEstimationError::TradingOutsideAllowedWindow { .. } + | PriceEstimationError::TokenTemporarilySuspended { .. } + | PriceEstimationError::InsufficientLiquidity { .. } + | PriceEstimationError::CustomSolverError { .. } => 6, PriceEstimationError::RateLimited => 5, PriceEstimationError::ProtocolInternal(_) => 4, PriceEstimationError::EstimatorInternal(_) => 3, @@ -241,18 +248,18 @@ pub enum PriceRanking { mod tests { use { super::*, - crate::price_estimation::{ + crate::{ Estimate, HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating, PriceEstimating, Query, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, anyhow::anyhow, futures::channel::oneshot::channel, model::order::OrderKind, - number::nonzero::U256 as NonZeroU256, + number::nonzero::NonZeroU256, std::time::Duration, tokio::time::sleep, }; @@ -308,12 +315,12 @@ mod tests { ]; let estimates = [ Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 1, ..Default::default() }, Estimate { - out_amount: 2.into(), + out_amount: U256::from(2), gas: 1, ..Default::default() }, @@ -398,7 +405,7 @@ mod tests { fn estimate(amount: u64) -> Estimate { Estimate { - out_amount: amount.into(), + out_amount: U256::from(amount), gas: 1, ..Default::default() } @@ -459,7 +466,7 @@ mod tests { fn estimate(amount: u64) -> Estimate { Estimate { - out_amount: amount.into(), + out_amount: U256::from(amount), gas: 1, ..Default::default() } @@ -536,7 +543,7 @@ mod tests { fn estimate(amount: u64) -> Estimate { Estimate { - out_amount: amount.into(), + out_amount: U256::from(amount), gas: 1, ..Default::default() } @@ -590,4 +597,41 @@ mod tests { racing.estimate(query).await.unwrap(); } + + #[test] + fn custom_solver_errors_have_higher_priority_than_generic_errors() { + let custom_errors = [ + PriceEstimationError::TradingOutsideAllowedWindow { + message: "window".to_string(), + }, + PriceEstimationError::TokenTemporarilySuspended { + message: "suspended".to_string(), + }, + PriceEstimationError::InsufficientLiquidity { + message: "insufficient".to_string(), + }, + PriceEstimationError::CustomSolverError { + message: "custom".to_string(), + }, + ]; + + let generic_errors = [ + PriceEstimationError::RateLimited, + PriceEstimationError::ProtocolInternal(anyhow!("protocol")), + PriceEstimationError::EstimatorInternal(anyhow!("estimator")), + PriceEstimationError::UnsupportedToken { + token: Address::new([0; 20]), + reason: "unsupported".to_string(), + }, + PriceEstimationError::NoLiquidity, + PriceEstimationError::UnsupportedOrderType("buy".to_string()), + ]; + + for custom in &custom_errors { + for generic in &generic_errors { + assert_eq!(compare_error(custom, generic), Ordering::Greater); + assert_eq!(compare_error(generic, custom), Ordering::Less); + } + } + } } diff --git a/crates/shared/src/price_estimation/competition/native.rs b/crates/price-estimation/src/competition/native.rs similarity index 99% rename from crates/shared/src/price_estimation/competition/native.rs rename to crates/price-estimation/src/competition/native.rs index 2c987362c0..8292199a61 100644 --- a/crates/shared/src/price_estimation/competition/native.rs +++ b/crates/price-estimation/src/competition/native.rs @@ -1,6 +1,6 @@ use { super::{CompetitionEstimator, compare_error}, - crate::price_estimation::{ + crate::{ PriceEstimationError, native::{NativePriceEstimateResult, NativePriceEstimating, is_price_malformed}, }, @@ -76,7 +76,7 @@ fn compare_native_result( mod tests { use { super::*, - crate::price_estimation::{ + crate::{ HEALTHY_PRICE_ESTIMATION_TIME, competition::PriceRanking, native::MockNativePriceEstimating, diff --git a/crates/shared/src/price_estimation/competition/quote.rs b/crates/price-estimation/src/competition/quote.rs similarity index 65% rename from crates/shared/src/price_estimation/competition/quote.rs rename to crates/price-estimation/src/competition/quote.rs index b061127cd2..7b0d3bd0b5 100644 --- a/crates/shared/src/price_estimation/competition/quote.rs +++ b/crates/price-estimation/src/competition/quote.rs @@ -1,6 +1,6 @@ use { super::{CompetitionEstimator, PriceRanking, compare_error}, - crate::price_estimation::{ + crate::{ Estimate, PriceEstimateResult, PriceEstimating, @@ -8,12 +8,16 @@ use { Query, QuoteVerificationMode, }, - anyhow::Context, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + alloy::primitives::{Address, U256}, + anyhow::Context as _, futures::future::{BoxFuture, FutureExt, TryFutureExt}, model::order::OrderKind, - primitive_types::{H160, U256}, - std::{cmp::Ordering, sync::Arc, time::Duration}, + serde::Serialize, + std::{ + cmp::Ordering, + sync::Arc, + time::{Duration, Instant}, + }, tracing::instrument, }; @@ -27,17 +31,30 @@ impl PriceEstimating for CompetitionEstimator> { OrderKind::Buy => query.sell_token, OrderKind::Sell => query.buy_token, }; - let get_context = self - .ranking - .provide_context(out_token.into_legacy(), query.timeout); - - // Filter out 0 gas cost estimate because they are obviously wrong and would - // likely win the price competition which would lead to us paying huge - // subsidies. - let gas_is_reasonable = |r: &PriceEstimateResult| r.as_ref().is_ok_and(|r| r.gas > 0); + let get_context = self.ranking.provide_context(out_token, query.timeout); + + // Filter out obviously wrong estimates: + // - 0 gas cost would lead to us paying huge subsidies + // - 0 out_amount means the quote is useless + let is_reasonable = |r: &PriceEstimateResult| { + r.as_ref() + .is_ok_and(|r| r.gas > 0 && !r.out_amount.is_zero()) + }; let get_results = self - .produce_results(query.clone(), gas_is_reasonable, |context| { - context.estimator.estimate(context.query) + .produce_results(query.clone(), is_reasonable, |context| { + // Call estimate() eagerly so its side-effects still happen + // when an early-return drops the future before it's polled. + let start = Instant::now(); + let estimator_name = context.name; + let inner_query = context.query.clone(); + context + .estimator + .estimate(context.query.clone()) + .map(move |res| { + emit_quote_event(estimator_name, &inner_query, &res, start.elapsed()); + res + }) + .boxed() }) .map(Result::Ok); @@ -45,7 +62,7 @@ impl PriceEstimating for CompetitionEstimator> { let winner = results .into_iter() - .filter(|(_index, r)| r.is_err() || gas_is_reasonable(r)) + .filter(|(_index, r)| r.is_err() || is_reasonable(r)) .max_by(|a, b| { compare_quote_result( &query, @@ -55,7 +72,7 @@ impl PriceEstimating for CompetitionEstimator> { !matches!(self.verification_mode, QuoteVerificationMode::Unverified), ) }) - .with_context(|| "all price estimates reported 0 gas cost") + .with_context(|| "all price estimates were unreasonable (0 gas or 0 out_amount)") .map_err(PriceEstimationError::EstimatorInternal)?; self.report_winner(&query, query.kind, winner) } @@ -97,7 +114,7 @@ fn compare_quote(query: &Query, a: &Estimate, b: &Estimate, context: &RankingCon impl PriceRanking { async fn provide_context( &self, - token: H160, + token: Address, timeout: Duration, ) -> Result { match self { @@ -109,17 +126,14 @@ impl PriceRanking { let gas = gas.clone(); let native = native.clone(); let gas = gas - .estimate() - .map_ok(|gas| gas.effective_gas_price()) + .effective_gas_price() .map_err(PriceEstimationError::ProtocolInternal); - let (native_price, gas_price) = futures::try_join!( - native.estimate_native_price(token.into_alloy(), timeout), - gas - )?; + let (native_price, gas_price) = + futures::try_join!(native.estimate_native_price(token, timeout), gas)?; Ok(RankingContext { native_price, - gas_price, + gas_price: gas_price as f64, }) } } @@ -138,7 +152,7 @@ impl RankingContext { /// trade route would report a higher `out_amount_in_eth`. This is also /// referred to as "bang-for-buck" and what matters most to traders. fn effective_eth_out(&self, estimate: &Estimate, kind: OrderKind) -> U256 { - let eth_out = estimate.out_amount.to_f64_lossy() * self.native_price; + let eth_out = f64::from(estimate.out_amount) * self.native_price; let fees = estimate.gas as f64 * self.gas_price; let effective_eth_out = match kind { // High fees mean receiving less `buy_token` from your sell order. @@ -146,30 +160,154 @@ impl RankingContext { // High fees mean paying more `sell_token` for your buy order. OrderKind::Buy => eth_out + fees, }; - // converts `NaN` and `(-∞, 0]` to `0` - U256::from_f64_lossy(effective_eth_out) + match effective_eth_out { + // converts `NaN` and `(-∞, 0]` to `0` + v if v.is_sign_negative() || v.is_nan() => U256::ZERO, + // Previous case already covered negative infinity + v if v.is_infinite() => U256::MAX, + // Note on truncation: previously we used primitive_types::U256::from_f64_lossy which + // truncated the floating point, while alloy is slightly more faithful to the original + // value and rounds to closest integer: [0, 0.5) => 0, [0.5, 1] => 1 + v => U256::from(v.trunc()), + } } } +fn emit_quote_event( + estimator_name: &str, + query: &Query, + result: &PriceEstimateResult, + elapsed: Duration, +) { + let event = PriceEstimateEvent { + query: QueryFields { + sell_token: query.sell_token.to_string(), + buy_token: query.buy_token.to_string(), + in_amount: query.in_amount.to_string(), + kind: match query.kind { + OrderKind::Sell => "sell", + OrderKind::Buy => "buy", + }, + }, + from: query.verification.from, + timeout: query.timeout.as_millis(), + elapsed: elapsed.as_millis(), + estimator: estimator_name, + result: match result { + Ok(estimate) => EstimateResult::Ok { + out_amount: estimate.out_amount.to_string(), + gas: estimate.gas.to_string(), + verified: estimate.verified, + }, + Err(err) => EstimateResult::Err { + error: err.to_string(), + }, + }, + }; + observe::event_bus::publish("priceEstimate", event); +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct PriceEstimateEvent<'a> { + query: QueryFields, + from: Address, + timeout: u128, + elapsed: u128, + estimator: &'a str, + result: EstimateResult, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct QueryFields { + sell_token: String, + buy_token: String, + in_amount: String, + kind: &'static str, +} + +/// Mirrors the previous JSON: either the estimate fields or an `error`. +#[derive(Serialize)] +#[serde(untagged)] +enum EstimateResult { + #[serde(rename_all = "camelCase")] + Ok { + out_amount: String, + gas: String, + verified: bool, + }, + Err { + error: String, + }, +} + #[cfg(test)] mod tests { use { super::*, - crate::{ - gas_price_estimation::FakeGasPriceEstimator, - price_estimation::{ - MockPriceEstimating, - QuoteVerificationMode, - native::MockNativePriceEstimating, - }, - }, - gas_estimation::GasPrice1559, + crate::{MockPriceEstimating, QuoteVerificationMode, native::MockNativePriceEstimating}, + alloy::{eips::eip1559::Eip1559Estimation, primitives::U256}, + gas_price_estimation::FakeGasPriceEstimator, model::order::OrderKind, + serde_json::json, }; + #[test] + fn price_estimate_event_matches_wire_format() { + let event = PriceEstimateEvent { + query: QueryFields { + sell_token: "0x01".into(), + buy_token: "0x02".into(), + in_amount: "100".into(), + kind: "sell", + }, + from: Address::ZERO, + timeout: 5000, + elapsed: 12, + estimator: "baseline", + result: EstimateResult::Ok { + out_amount: "99".into(), + gas: "21000".into(), + verified: true, + }, + }; + assert_eq!( + serde_json::to_value(&event).unwrap(), + json!({ + "query": { + "sellToken": "0x01", + "buyToken": "0x02", + "inAmount": "100", + "kind": "sell", + }, + "from": Address::ZERO, + "timeout": 5000, + "elapsed": 12, + "estimator": "baseline", + "result": { + "outAmount": "99", + "gas": "21000", + "verified": true, + }, + }), + ); + } + + #[test] + fn price_estimate_event_error_variant() { + let result = EstimateResult::Err { + error: "boom".into(), + }; + assert_eq!( + serde_json::to_value(&result).unwrap(), + json!({ "error": "boom" }), + ); + } + fn price(out_amount: u128, gas: u64) -> PriceEstimateResult { Ok(Estimate { - out_amount: out_amount.into(), + out_amount: U256::from(out_amount), gas, ..Default::default() }) @@ -190,10 +328,9 @@ mod tests { native .expect_estimate_native_price() .returning(move |_, _| async { Ok(0.5) }.boxed()); - let gas = Arc::new(FakeGasPriceEstimator::new(GasPrice1559 { - base_fee_per_gas: 2.0, - max_fee_per_gas: 2.0, - max_priority_fee_per_gas: 2.0, + let gas = Arc::new(FakeGasPriceEstimator::new(Eip1559Estimation { + max_fee_per_gas: 2, + max_priority_fee_per_gas: 2, })); PriceRanking::BestBangForBuck { native: Arc::new(native), @@ -352,13 +489,13 @@ mod tests { #[tokio::test] async fn prefer_verified_over_unverified() { let worse_verified_quote = Ok(Estimate { - out_amount: 900_000.into(), + out_amount: U256::from(900_000), gas: 2_000, verified: true, ..Default::default() }); let better_unverified_quote = Ok(Estimate { - out_amount: 1_000_000.into(), + out_amount: U256::from(1_000_000), gas: 1_000, verified: false, ..Default::default() @@ -376,18 +513,6 @@ mod tests { .await; assert_eq!(best, worse_verified_quote.clone()); - let best = best_response( - PriceRanking::MaxOutAmount, - OrderKind::Sell, - vec![ - better_unverified_quote.clone(), - worse_verified_quote.clone(), - ], - QuoteVerificationMode::EnforceWhenPossible, - ) - .await; - assert_eq!(best, worse_verified_quote.clone()); - let best = best_response( PriceRanking::MaxOutAmount, OrderKind::Sell, diff --git a/crates/price-estimation/src/config/mod.rs b/crates/price-estimation/src/config/mod.rs new file mode 100644 index 0000000000..cfbcaeb995 --- /dev/null +++ b/crates/price-estimation/src/config/mod.rs @@ -0,0 +1,2 @@ +pub mod native_price; +pub mod price_estimation; diff --git a/crates/price-estimation/src/config/native_price.rs b/crates/price-estimation/src/config/native_price.rs new file mode 100644 index 0000000000..ff2b425281 --- /dev/null +++ b/crates/price-estimation/src/config/native_price.rs @@ -0,0 +1 @@ +pub use configs::native_price::{CacheConfig, NativePriceConfig}; diff --git a/crates/price-estimation/src/config/price_estimation.rs b/crates/price-estimation/src/config/price_estimation.rs new file mode 100644 index 0000000000..ca59659460 --- /dev/null +++ b/crates/price-estimation/src/config/price_estimation.rs @@ -0,0 +1,20 @@ +use { + balance_overrides::StateOverriding, + configs::price_estimation::BalanceOverridesConfig, + std::sync::Arc, +}; + +pub trait BalanceOverridesConfigExt { + fn init(&self, web3: ethrpc::Web3) -> Arc; +} + +impl BalanceOverridesConfigExt for BalanceOverridesConfig { + fn init(&self, web3: ethrpc::Web3) -> Arc { + Arc::new(balance_overrides::StateOverrides::with_config( + web3, + self.probing_depth, + self.detection_timeout, + self.cache_size, + )) + } +} diff --git a/crates/shared/src/price_estimation/external.rs b/crates/price-estimation/src/external.rs similarity index 90% rename from crates/shared/src/price_estimation/external.rs rename to crates/price-estimation/src/external.rs index 1fe216d4c9..cbb00d38d5 100644 --- a/crates/shared/src/price_estimation/external.rs +++ b/crates/price-estimation/src/external.rs @@ -1,12 +1,11 @@ use { - super::{ + crate::{ PriceEstimateResult, PriceEstimating, Query, - trade_finder::TradeEstimator, + trade_finding::{external::ExternalTradeFinder, trade_estimator::TradeEstimator}, trade_verifier::TradeVerifying, }, - crate::trade_finding::external::ExternalTradeFinder, ethrpc::block_stream::CurrentBlockWatcher, rate_limit::RateLimiter, reqwest::{Client, Url}, diff --git a/crates/shared/src/price_estimation/factory.rs b/crates/price-estimation/src/factory.rs similarity index 55% rename from crates/shared/src/price_estimation/factory.rs rename to crates/price-estimation/src/factory.rs index af5a6e7d9b..7f37cfd6b9 100644 --- a/crates/shared/src/price_estimation/factory.rs +++ b/crates/price-estimation/src/factory.rs @@ -1,55 +1,37 @@ use { super::{ - Arguments, NativePriceEstimator as NativePriceEstimatorSource, PriceEstimating, competition::CompetitionEstimator, external::ExternalPriceEstimator, instrumented::InstrumentedPriceEstimator, - native::{self, NativePriceEstimator}, - native_price_cache::CachingNativePriceEstimator, + native::{self, NativePriceEstimating, NativePriceEstimator}, + native_price_cache::{self, ApproximationToken}, sanitized::SanitizedPriceEstimator, trade_verifier::{TradeVerifier, TradeVerifying}, }, crate::{ - arguments, - bad_token::BadTokenDetecting, - baseline_solver::BaseTokens, - code_fetching::CachedCodeFetcher, - ethrpc::Web3, - http_client::HttpClientFactory, - price_estimation::{ - ExternalSolver, - buffered::{self, BufferedRequest, NativePriceBatchFetching}, - competition::PriceRanking, - native::NativePriceEstimating, - }, - tenderly_api::TenderlyCodeSimulator, - token_info::TokenInfoFetching, + ExternalSolver, + buffered::{self, BufferedRequest, NativePriceBatchFetching}, + competition::PriceRanking, + config::{native_price::NativePriceConfig, price_estimation::BalanceOverridesConfigExt}, }, + alloy::primitives::Address, anyhow::{Context as _, Result}, - contracts::alloy::WETH9, - ethcontract::H160, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, - gas_estimation::GasPriceEstimating, - number::nonzero::U256 as NonZeroU256, + bad_tokens::list_based::DenyListedTokens, + configs::price_estimation::PriceEstimation, + contracts::{GPv2Settlement, WETH9}, + ethrpc::{Web3, alloy::ProviderLabelingExt, block_stream::CurrentBlockWatcher}, + gas_price_estimation::GasPriceEstimating, + http_client::HttpClientFactory, + number::nonzero::NonZeroU256, rate_limit::RateLimiter, reqwest::Url, + simulator::{simulation_builder::SettlementSimulator, tenderly}, std::{collections::HashMap, num::NonZeroUsize, sync::Arc}, + token_info::TokenInfoFetching, }; -/// A factory for initializing shared price estimators. -pub struct PriceEstimatorFactory<'a> { - args: &'a Arguments, - network: Network, - components: Components, - trade_verifier: Option>, - estimators: HashMap, -} - #[derive(Clone)] struct EstimatorEntry { optimal: Arc, @@ -62,85 +44,117 @@ pub struct Network { pub web3: Web3, pub simulation_web3: Option, pub chain: chain::Chain, - pub native_token: H160, - pub settlement: H160, - pub authenticator: H160, - pub base_tokens: Arc, + pub native_token: Address, + pub settlement: Address, + pub authenticator: Address, pub block_stream: CurrentBlockWatcher, + pub flash_loan_router: Address, + pub hooks_trampoline: Address, } /// The shared components needed for creating price estimators. pub struct Components { pub http_factory: HttpClientFactory, - pub bad_token_detector: Arc, + pub deny_listed_tokens: DenyListedTokens, pub tokens: Arc, - pub code_fetcher: Arc, +} + +/// A factory for initializing shared price estimators. +pub struct PriceEstimatorFactory<'a> { + args: &'a PriceEstimation, + config: &'a NativePriceConfig, + network: Network, + components: Components, + settlement_simulator: Option, + trade_verifier: Option>, + estimators: HashMap, } impl<'a> PriceEstimatorFactory<'a> { pub async fn new( - args: &'a Arguments, - shared_args: &'a arguments::Arguments, + args: &'a PriceEstimation, + config: &'a NativePriceConfig, network: Network, components: Components, ) -> Result { + let (settlement_simulator, tenderly) = + Self::build_simulator(args, &network, &components).await?; + let trade_verifier = settlement_simulator + .as_ref() + .map(|simulator| Self::build_trade_verifier(args, simulator.clone(), tenderly)); Ok(Self { - trade_verifier: Self::trade_verifier(args, shared_args, &network, &components).await?, + settlement_simulator, + trade_verifier, args, + config, network, components, estimators: HashMap::new(), }) } - async fn trade_verifier( - args: &'a Arguments, - shared_args: &arguments::Arguments, + pub fn settlement_simulator(&self) -> Option<&SettlementSimulator> { + self.settlement_simulator.as_ref() + } + + async fn build_simulator( + args: &PriceEstimation, network: &Network, components: &Components, - ) -> Result>> { + ) -> Result<(Option, Option>)> { let Some(web3) = network.simulation_web3.clone() else { - return Ok(None); + return Ok((None, None)); }; - let web3 = ethrpc::instrumented::instrument_with_label(&web3, "simulator".into()); - - let tenderly = shared_args - .tenderly - .get_api_instance(&components.http_factory, "price_estimation".to_owned()) - .unwrap() - .map(|t| Arc::new(TenderlyCodeSimulator::new(t, network.chain.id()))); + let web3 = web3.labeled("simulator"); let balance_overrides = args.balance_overrides.init(web3.clone()); - let verifier = TradeVerifier::new( - web3, - tenderly, - components.code_fetcher.clone(), + let tenderly = args.tenderly.as_ref().map(|config| { + Arc::new(tenderly::TenderlyApi::new_instrumented( + "price_estimation".to_string(), + config, + &components.http_factory, + network.chain.id().to_string(), + )) as Arc + }); + let settlement_contract = + GPv2Settlement::GPv2Settlement::new(network.settlement, web3.provider.clone()); + let simulator = SettlementSimulator::new( + settlement_contract, + network.flash_loan_router, + network.hooks_trampoline, + network.native_token, + args.max_gas_per_tx, balance_overrides, network.block_stream.clone(), - network.settlement, - network.native_token, - args.quote_inaccuracy_limit.clone(), - args.tokens_without_verification.iter().cloned().collect(), + tenderly.clone(), ) .await?; - Ok(Some(Arc::new(verifier))) + + Ok((Some(simulator), tenderly)) + } + + fn build_trade_verifier( + args: &PriceEstimation, + simulator: SettlementSimulator, + tenderly: Option>, + ) -> Arc { + Arc::new(TradeVerifier::new( + simulator, + tenderly, + args.quote_inaccuracy_limit.clone(), + args.tokens_without_verification.iter().cloned().collect(), + args.min_gas_amount_for_unverified_quotes, + args.max_gas_amount_for_unverified_quotes, + )) } fn native_token_price_estimation_amount(&self) -> Result { - NonZeroU256::try_from( - self.args - .amount_to_estimate_prices_with - .or_else(|| { - Some( - self.network - .chain - .default_amount_to_estimate_native_prices_with() - .into_legacy(), - ) - }) - .context("No amount to estimate prices with set.")?, - ) + NonZeroU256::try_from(self.args.amount_to_estimate_prices_with.unwrap_or_else(|| { + self.network + .chain + .default_amount_to_estimate_native_prices_with() + })) } fn rate_limiter(&self, name: &str) -> Arc { @@ -192,6 +206,16 @@ impl<'a> PriceEstimatorFactory<'a> { weth: &WETH9::Instance, ) -> Result<(String, Arc)> { match source { + NativePriceEstimatorSource::Forwarder { url } => { + let name = format!("Forwarder|{}", url); + Ok(( + name.clone(), + Arc::new(InstrumentedPriceEstimator::new( + native::Forwarder::new(self.components.http_factory.create(), url.clone()), + name, + )), + )) + } NativePriceEstimatorSource::Driver(driver) => { let native_token_price_estimation_amount = self.native_token_price_estimation_amount()?; @@ -200,7 +224,7 @@ impl<'a> PriceEstimatorFactory<'a> { driver.name.clone(), Arc::new(InstrumentedPriceEstimator::new( NativePriceEstimator::new( - Arc::new(self.sanitized(estimator)), + Arc::new(self.sanitized_native_price(estimator)), self.network.native_token, native_token_price_estimation_amount, ), @@ -209,14 +233,19 @@ impl<'a> PriceEstimatorFactory<'a> { )) } NativePriceEstimatorSource::OneInchSpotPriceApi => { + let one_inch = self + .args + .one_inch + .as_ref() + .context("one-inch config must be set when OneInchSpotPriceApi is used")?; let name = "OneInchSpotPriceApi".to_string(); Ok(( name.clone(), Arc::new(InstrumentedPriceEstimator::new( native::OneInch::new( self.components.http_factory.create(), - self.args.one_inch_url.clone(), - self.args.one_inch_api_key.clone(), + one_inch.url.clone(), + Some(one_inch.api_key.clone()), self.network.chain.id(), self.network.block_stream.clone(), self.components.tokens.clone(), @@ -226,26 +255,25 @@ impl<'a> PriceEstimatorFactory<'a> { )) } NativePriceEstimatorSource::CoinGecko => { - anyhow::ensure!( - self.args.coin_gecko.coin_gecko_api_key.is_some(), - "coin_gecko_api_key must be set when CoinGecko is used as native price estimator" - ); + let coin_gecko_config = self + .args + .coin_gecko + .as_ref() + .context("coin-gecko config must be set when CoinGecko is used")?; let name = "CoinGecko".to_string(); let coin_gecko = native::CoinGecko::new( self.components.http_factory.create(), - self.args.coin_gecko.coin_gecko_url.clone(), - self.args.coin_gecko.coin_gecko_api_key.clone(), + coin_gecko_config.url.clone(), + Some(coin_gecko_config.api_key.clone()), &self.network.chain, - weth.address().into_legacy(), + *weth.address(), self.components.tokens.clone(), ) .await?; let coin_gecko: Arc = - if let Some(coin_gecko_buffered_configuration) = - &self.args.coin_gecko.coin_gecko_buffered - { + if let Some(buffered_config) = &coin_gecko_config.buffered { let configuration = buffered::Configuration { max_concurrent_requests: Some( coin_gecko @@ -253,13 +281,9 @@ impl<'a> PriceEstimatorFactory<'a> { .try_into() .context("invalid CoinGecko max batch size")?, ), - debouncing_time: coin_gecko_buffered_configuration - .coin_gecko_debouncing_time - .unwrap(), + debouncing_time: buffered_config.debouncing_time, result_ready_timeout: self.args.quote_timeout, - broadcast_channel_capacity: coin_gecko_buffered_configuration - .coin_gecko_broadcast_channel_capacity - .unwrap(), + broadcast_channel_capacity: buffered_config.broadcast_channel_capacity, }; Arc::new(InstrumentedPriceEstimator::new( @@ -307,8 +331,23 @@ impl<'a> PriceEstimatorFactory<'a> { fn sanitized(&self, estimator: Arc) -> SanitizedPriceEstimator { SanitizedPriceEstimator::new( estimator, - self.network.native_token.into_alloy(), - self.components.bad_token_detector.clone(), + self.network.native_token, + self.components.deny_listed_tokens.clone(), + false, // not estimating native price + ) + } + + /// Creates a SanitizedPriceEstimator that is used for native price + /// estimations + fn sanitized_native_price( + &self, + estimator: Arc, + ) -> SanitizedPriceEstimator { + SanitizedPriceEstimator::new( + estimator, + self.network.native_token, + self.components.deny_listed_tokens.clone(), + true, // estimating native price ) } @@ -346,22 +385,20 @@ impl<'a> PriceEstimatorFactory<'a> { )) } + /// Creates a native price estimator from the given sources. When `eip4626` + /// is true the resulting estimator is wrapped in an [`native::Eip4626`] + /// layer that transparently prices vault tokens. pub async fn native_price_estimator( &mut self, native: &[Vec], results_required: NonZeroUsize, - weth: WETH9::Instance, - ) -> Result> { - anyhow::ensure!( - self.args.native_price_cache_max_age > self.args.native_price_prefetch_time, - "price cache prefetch time needs to be less than price cache max age" - ); - + weth: &WETH9::Instance, + ) -> Result> { let mut estimators = Vec::with_capacity(native.len()); for stage in native.iter() { let mut stages = Vec::with_capacity(stage.len()); for source in stage { - stages.push(self.create_native_estimator(source, &weth).await?); + stages.push(self.create_native_estimator(source, weth).await?); } estimators.push(stages); } @@ -370,21 +407,101 @@ impl<'a> PriceEstimatorFactory<'a> { CompetitionEstimator::new(estimators, PriceRanking::MaxOutAmount) .with_verification(self.args.quote_verification) .with_early_return(results_required); - let native_estimator = Arc::new(CachingNativePriceEstimator::new( - Box::new(competition_estimator), - self.args.native_price_cache_max_age, - self.args.native_price_cache_refresh, - Some(self.args.native_price_cache_max_update_size), - self.args.native_price_prefetch_time, - self.args.native_price_cache_concurrent_requests, - self.args - .native_price_approximation_tokens - .clone() - .into_iter() - .collect(), + Ok(Box::new(competition_estimator)) + } + + /// Creates a [`CachingNativePriceEstimator`] that wraps a native price + /// estimator with an in-memory cache. + /// + /// If `eip4626` is true, it will wrap the estimator with EIP-4626 + /// unwrapping. + pub async fn caching_native_price_estimator( + &mut self, + native: &[Vec], + results_required: NonZeroUsize, + weth: &WETH9::Instance, + cache: native_price_cache::Cache, + eip4626: bool, + ) -> native_price_cache::CachingNativePriceEstimator { + let inner = self + .native_price_estimator(native, results_required, weth) + .await + .expect("failed to build native price estimator"); + let inner = if eip4626 { + Box::new(InstrumentedPriceEstimator::new( + native::Eip4626::new(inner, self.network.web3.provider.clone()), + "Eip4626".to_string(), + )) + } else { + inner + }; + self.caching_native_price_estimator_from_inner(inner, cache) + .await + } + + /// Creates a [`CachingNativePriceEstimator`] from a pre-built inner + /// estimator. + pub async fn caching_native_price_estimator_from_inner( + &mut self, + inner: Box, + cache: native_price_cache::Cache, + ) -> native_price_cache::CachingNativePriceEstimator { + let approximation_tokens = self + .build_approximation_tokens() + .await + .expect("failed to build native price approximation tokens"); + native_price_cache::CachingNativePriceEstimator::new( + inner, + cache, + self.config.cache.concurrent_requests.get(), + approximation_tokens, self.args.quote_timeout, - )); - Ok(native_estimator) + ) + } + + /// Builds the approximation tokens mapping with normalization factors based + /// on decimal differences between token pairs. + async fn build_approximation_tokens(&self) -> Result> { + let pairs = &self.config.approximation_tokens; + if pairs.is_empty() { + return Ok(HashMap::new()); + } + + // Collect all unique addresses to fetch their decimals + let all_addresses: Vec
= pairs + .iter() + .flat_map(|(from, to)| [*from, *to]) + .collect::>() + .into_iter() + .collect(); + + let token_infos = self.components.tokens.get_token_infos(&all_addresses).await; + + let mut approximation_tokens = HashMap::new(); + for (from_token, to_token) in pairs { + let from_decimals = token_infos + .get(from_token) + .and_then(|info| info.decimals) + .with_context(|| { + format!( + "could not fetch decimals for approximation source token {from_token:?}" + ) + })?; + + let to_decimals = token_infos + .get(to_token) + .and_then(|info| info.decimals) + .with_context(|| { + format!("could not fetch decimals for approximation target token {to_token:?}") + })?; + + approximation_tokens.insert( + *from_token, + ApproximationToken::with_normalization((*to_token, to_decimals), from_decimals), + ); + } + + Ok(approximation_tokens) } } diff --git a/crates/shared/src/price_estimation/gas.rs b/crates/price-estimation/src/gas.rs similarity index 100% rename from crates/shared/src/price_estimation/gas.rs rename to crates/price-estimation/src/gas.rs diff --git a/crates/shared/src/price_estimation/instrumented.rs b/crates/price-estimation/src/instrumented.rs similarity index 84% rename from crates/shared/src/price_estimation/instrumented.rs rename to crates/price-estimation/src/instrumented.rs index 91ab34223c..b06225559f 100644 --- a/crates/shared/src/price_estimation/instrumented.rs +++ b/crates/price-estimation/src/instrumented.rs @@ -1,13 +1,12 @@ use { - crate::price_estimation::{ + crate::{ PriceEstimating, PriceEstimationError, Query, native::{NativePriceEstimateResult, NativePriceEstimating}, }, alloy::primitives::Address, - ethcontract::jsonrpc::futures_util::future::BoxFuture, - futures::future::FutureExt, + futures::future::{BoxFuture, FutureExt}, prometheus::{HistogramVec, IntCounterVec}, std::{ sync::Arc, @@ -51,6 +50,14 @@ impl InstrumentedPriceEstimator { Err(PriceEstimationError::UnsupportedToken { .. }) => "unsupported_token", Err(PriceEstimationError::UnsupportedOrderType(_)) => "unsupported_order_type", Err(PriceEstimationError::RateLimited) => "rate_limited", + Err(PriceEstimationError::TradingOutsideAllowedWindow { .. }) => { + "trading_outside_allowed_window" + } + Err(PriceEstimationError::TokenTemporarilySuspended { .. }) => { + "token_temporarily_suspended" + } + Err(PriceEstimationError::InsufficientLiquidity { .. }) => "insufficient_liquidity", + Err(PriceEstimationError::CustomSolverError { .. }) => "custom_solver_error", Err(PriceEstimationError::EstimatorInternal(_)) => "estimator_internal_error", Err(PriceEstimationError::ProtocolInternal(_)) => "protocol_internal_error", } @@ -123,7 +130,7 @@ struct Metrics { mod tests { use { super::*, - crate::price_estimation::{ + crate::{ Estimate, HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating, @@ -132,7 +139,7 @@ mod tests { alloy::primitives::Address, anyhow::anyhow, model::order::OrderKind, - number::nonzero::U256 as NonZeroU256, + number::nonzero::NonZeroU256, }; #[tokio::test] @@ -157,6 +164,18 @@ mod tests { }), Err(PriceEstimationError::UnsupportedOrderType("".to_string())), Err(PriceEstimationError::RateLimited), + Err(PriceEstimationError::TradingOutsideAllowedWindow { + message: "window".to_string(), + }), + Err(PriceEstimationError::TokenTemporarilySuspended { + message: "suspended".to_string(), + }), + Err(PriceEstimationError::InsufficientLiquidity { + message: "insufficient".to_string(), + }), + Err(PriceEstimationError::CustomSolverError { + message: "custom".to_string(), + }), Err(PriceEstimationError::EstimatorInternal(anyhow!(""))), Err(PriceEstimationError::ProtocolInternal(anyhow!(""))), ]; @@ -185,6 +204,10 @@ mod tests { "unsupported_token", "unsupported_order_type", "rate_limited", + "trading_outside_allowed_window", + "token_temporarily_suspended", + "insufficient_liquidity", + "custom_solver_error", "estimator_internal_error", "protocol_internal_error", ] { @@ -206,6 +229,6 @@ mod tests { .price_estimation_times .with_label_values(&["foo"]) .get_sample_count(); - assert_eq!(observed_count, 7); + assert_eq!(observed_count, 11); } } diff --git a/crates/price-estimation/src/lib.rs b/crates/price-estimation/src/lib.rs new file mode 100644 index 0000000000..917c6160c0 --- /dev/null +++ b/crates/price-estimation/src/lib.rs @@ -0,0 +1,348 @@ +pub use configs::{ + native_price_estimators::{ExternalSolver, NativePriceEstimator, NativePriceEstimators}, + price_estimation::QuoteVerificationMode, +}; +use { + crate::trade_finding::QuoteExecution, + alloy::primitives::{Address, U256}, + anyhow::Result, + futures::future::BoxFuture, + model::order::OrderKind, + number::nonzero::NonZeroU256, + rate_limit::RateLimiter, + serde::{Deserialize, Serialize}, + std::{ + cmp::{Eq, PartialEq}, + future::Future, + sync::Arc, + time::{Duration, Instant}, + }, + thiserror::Error, +}; + +mod buffered; +pub mod competition; +pub mod config; +pub mod external; +pub mod factory; +pub mod gas; +pub mod instrumented; +pub mod native; +pub mod native_price_cache; +pub mod sanitized; +pub mod trade_finding; +pub mod trade_verifier; +pub mod utils; + +#[derive(Error, Debug)] +pub enum PriceEstimationError { + #[error("token {token:?} is not supported: {reason:}")] + UnsupportedToken { token: Address, reason: String }, + + #[error("No liquidity")] + NoLiquidity, + + #[error("Unsupported Order Type")] + UnsupportedOrderType(String), + + #[error("Rate limited")] + RateLimited, + + /// Token can only be traded during specific time windows (e.g. xStocks/Ondo + /// RWA tokens). + #[error("{message}")] + TradingOutsideAllowedWindow { message: String }, + + /// Token is temporarily suspended from trading by the solver. + #[error("{message}")] + TokenTemporarilySuspended { message: String }, + + /// Insufficient liquidity to fill the requested trade size. + #[error("{message}")] + InsufficientLiquidity { message: String }, + + /// Solver returned a custom error that doesn't map to a known variant. + #[error("{message}")] + CustomSolverError { message: String }, + + #[error(transparent)] + EstimatorInternal(anyhow::Error), + + #[error(transparent)] + ProtocolInternal(anyhow::Error), +} + +#[cfg(test)] +impl PartialEq for PriceEstimationError { + // Can't use `Self` here because `discriminant` is only defined for enums + // and the compiler is not smart enough to figure out that `Self` is always + // an enum here. + fn eq(&self, other: &PriceEstimationError) -> bool { + let me = self as &PriceEstimationError; + std::mem::discriminant(me) == std::mem::discriminant(other) + } +} + +impl Clone for PriceEstimationError { + fn clone(&self) -> Self { + match self { + Self::UnsupportedToken { token, reason } => Self::UnsupportedToken { + token: *token, + reason: reason.clone(), + }, + Self::NoLiquidity => Self::NoLiquidity, + Self::UnsupportedOrderType(order_type) => { + Self::UnsupportedOrderType(order_type.clone()) + } + Self::RateLimited => Self::RateLimited, + Self::TradingOutsideAllowedWindow { message } => Self::TradingOutsideAllowedWindow { + message: message.clone(), + }, + Self::TokenTemporarilySuspended { message } => Self::TokenTemporarilySuspended { + message: message.clone(), + }, + Self::InsufficientLiquidity { message } => Self::InsufficientLiquidity { + message: message.clone(), + }, + Self::CustomSolverError { message } => Self::CustomSolverError { + message: message.clone(), + }, + Self::EstimatorInternal(err) => { + Self::EstimatorInternal(crate::utils::clone_anyhow_error(err)) + } + Self::ProtocolInternal(err) => { + Self::ProtocolInternal(crate::utils::clone_anyhow_error(err)) + } + } + } +} + +#[cfg(test)] +mod price_estimation_error_tests { + use super::PriceEstimationError; + + #[test] + fn clone_preserves_custom_solver_error_messages() { + let cases = [ + PriceEstimationError::TradingOutsideAllowedWindow { + message: "window".to_string(), + }, + PriceEstimationError::TokenTemporarilySuspended { + message: "suspended".to_string(), + }, + PriceEstimationError::InsufficientLiquidity { + message: "insufficient".to_string(), + }, + PriceEstimationError::CustomSolverError { + message: "custom".to_string(), + }, + ]; + + for err in cases { + let cloned = err.clone(); + assert_eq!(cloned.to_string(), err.to_string()); + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize)] +pub struct Query { + pub sell_token: Address, + pub buy_token: Address, + /// For OrderKind::Sell amount is in sell_token and for OrderKind::Buy in + /// buy_token. + pub in_amount: NonZeroU256, + pub kind: OrderKind, + pub verification: Verification, + /// Signals whether responses from that were valid on previous blocks can be + /// used to answer the query. + #[serde(skip_serializing)] + pub block_dependent: bool, + pub timeout: Duration, +} + +/// Conditions under which a given price estimate needs to work in order to be +/// viable. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize)] +pub struct Verification { + /// This address needs to have the `sell_token`. + pub from: Address, + /// This address will receive the `buy_token`. + pub receiver: Address, + /// App data provided with the quote that encodes things like + /// hooks and custom wrappers. + pub app_data: Arc, +} + +impl Verification { + pub fn effective_receiver(&self) -> &Address { + match self.receiver.is_zero() { + true => &self.from, + false => &self.receiver, + } + } +} + +#[derive(Clone, derive_more::Debug, Default, Eq, PartialEq, Deserialize)] +pub struct Estimate { + pub out_amount: U256, + /// full gas cost when settling this order alone on gp + pub gas: u64, + /// Address of the solver that provided the quote. + pub solver: Address, + /// Did we verify the correctness of this estimate's properties? + pub verified: bool, + /// Data associated with this estimation. + #[debug(ignore)] + pub execution: QuoteExecution, +} + +impl Estimate { + /// Returns (sell_amount, buy_amount). + pub fn amounts(&self, query: &Query) -> (U256, U256) { + match query.kind { + OrderKind::Buy => (self.out_amount, query.in_amount.get()), + OrderKind::Sell => (query.in_amount.get(), self.out_amount), + } + } + + /// The price of the estimate denominated in buy token. + /// + /// The resulting price is how many units of buy_token are bought for one + /// unit of sell_token (buy_amount / sell_amount). + pub fn price_in_buy_token_f64(&self, query: &Query) -> f64 { + let (sell_amount, buy_amount) = self.amounts(query); + f64::from(buy_amount) / f64::from(sell_amount) + } +} + +pub type PriceEstimateResult = Result; + +#[cfg_attr(any(test, feature = "test-util"), mockall::automock)] +pub trait PriceEstimating: Send + Sync + 'static { + fn estimate(&self, query: Arc) -> BoxFuture<'_, PriceEstimateResult>; +} + +pub const HEALTHY_PRICE_ESTIMATION_TIME: Duration = Duration::from_millis(5_000); + +pub async fn rate_limited( + rate_limiter: Arc, + estimation: impl Future>, +) -> Result { + let timed_estimation = async move { + let start = Instant::now(); + let result = estimation.await; + (start.elapsed(), result) + }; + let rate_limited_estimation = + rate_limiter.execute(timed_estimation, |(estimation_time, result)| { + let too_slow = *estimation_time > HEALTHY_PRICE_ESTIMATION_TIME; + let api_rate_limited = matches!(result, Err(PriceEstimationError::RateLimited)); + too_slow || api_rate_limited + }); + match rate_limited_estimation.await { + Ok((_estimation_time, Ok(result))) => Ok(result), + // return original PriceEstimationError + Ok((_estimation_time, Err(err))) => Err(err), + // convert the RateLimiterError to a PriceEstimationError + Err(_) => Err(PriceEstimationError::RateLimited), + } +} + +pub mod mocks { + use {super::*, anyhow::anyhow, futures::FutureExt}; + + pub struct FakePriceEstimator(pub Estimate); + impl PriceEstimating for FakePriceEstimator { + fn estimate(&self, _query: Arc) -> BoxFuture<'_, PriceEstimateResult> { + async { Ok(self.0.clone()) }.boxed() + } + } + + pub struct FailingPriceEstimator; + impl PriceEstimating for FailingPriceEstimator { + fn estimate(&self, _query: Arc) -> BoxFuture<'_, PriceEstimateResult> { + async { + Err(PriceEstimationError::EstimatorInternal(anyhow!( + "always fail" + ))) + } + .boxed() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn toml_deserialize_estimators_empty() { + #[derive(Deserialize)] + struct Helper { + _estimators: NativePriceEstimators, + } + + assert!(toml::from_str::("estimators = []").is_err()); + assert!(toml::from_str::("estimators = [[]]").is_err()); + } + + #[test] + fn toml_deserialize_estimators_single_stage() { + let toml = r#" + estimators = [[{type = "CoinGecko"}, {type = "OneInchSpotPriceApi"}]] + "#; + + #[derive(Deserialize)] + struct Helper { + estimators: NativePriceEstimators, + } + + let parsed: Helper = toml::from_str(toml).unwrap(); + assert_eq!( + parsed.estimators.as_slice(), + vec![vec![ + NativePriceEstimator::CoinGecko, + NativePriceEstimator::OneInchSpotPriceApi, + ]] + ); + } + + #[test] + fn toml_deserialize_estimators_multiple_stages() { + let toml = r#" + estimators = [ + [{type = "CoinGecko"}, {type = "Driver", name = "solver1", url = "http://localhost:8080"}], + [{type = "Forwarder", url = "http://localhost:12088"}], + ] + "#; + + #[derive(Deserialize)] + struct Helper { + estimators: NativePriceEstimators, + } + + let parsed: Helper = toml::from_str(toml).unwrap(); + assert_eq!( + parsed.estimators.as_slice(), + vec![ + vec![ + NativePriceEstimator::CoinGecko, + NativePriceEstimator::Driver(ExternalSolver { + name: "solver1".to_string(), + url: "http://localhost:8080".parse().unwrap(), + }), + ], + vec![NativePriceEstimator::Forwarder { + url: "http://localhost:12088".parse().unwrap(), + }], + ] + ); + } + + #[test] + fn toml_deserialize_estimators_default() { + let estimators = NativePriceEstimators::default(); + assert!(estimators.as_slice().is_empty()); + } +} diff --git a/crates/shared/src/price_estimation/native/coingecko.rs b/crates/price-estimation/src/native/coingecko.rs similarity index 89% rename from crates/shared/src/price_estimation/native/coingecko.rs rename to crates/price-estimation/src/native/coingecko.rs index ccf6d371ea..9f54c32346 100644 --- a/crates/shared/src/price_estimation/native/coingecko.rs +++ b/crates/price-estimation/src/native/coingecko.rs @@ -1,15 +1,10 @@ use { super::{NativePriceEstimateResult, NativePriceEstimating}, - crate::{ - price_estimation::{PriceEstimationError, buffered::NativePriceBatchFetching}, - token_info::{TokenInfo, TokenInfoFetching}, - }, + crate::{PriceEstimationError, buffered::NativePriceBatchFetching}, alloy::primitives::Address, anyhow::{Context, Result, anyhow}, chain::Chain, - ethrpc::alloy::conversions::IntoLegacy, futures::{FutureExt, future::BoxFuture}, - primitive_types::H160, reqwest::{Client, StatusCode}, rust_decimal::{Decimal, MathematicalOps, prelude::ToPrimitive}, serde::Deserialize, @@ -18,19 +13,20 @@ use { sync::Arc, time::Duration, }, + token_info::{TokenInfo, TokenInfoFetching}, tracing::instrument, url::Url, }; #[derive(Debug, Deserialize)] -struct Response(HashMap); +struct Response(HashMap); #[derive(Debug, Deserialize)] struct Price { eth: Option, } -type Token = H160; +type Token = Address; pub struct CoinGecko { client: Client, @@ -43,7 +39,7 @@ pub struct CoinGecko { /// The token in which prices are denominated in. struct Denominator { - address: H160, + address: Address, /// Number of decimals of the token. This is necessary /// to know in order to normalize prices for tokens /// with a different number of decimals. @@ -59,7 +55,7 @@ impl CoinGecko { base_url: Url, api_key: Option, chain: &Chain, - native_token: H160, + native_token: Address, token_infos: Arc, ) -> Result { let denominator_decimals = token_infos @@ -82,10 +78,10 @@ impl CoinGecko { Chain::Polygon => "polygon-pos".to_string(), Chain::Optimism => "optimistic-ethereum".to_string(), Chain::Bnb => "binance-smart-chain".to_string(), - Chain::Lens => "lens".to_string(), Chain::Linea => "linea".to_string(), Chain::Plasma => "plasma".to_string(), - Chain::Sepolia | Chain::Goerli | Chain::Hardhat => { + Chain::Ink => "ink".to_string(), + Chain::Sepolia | Chain::Hardhat => { anyhow::bail!("unsupported network {}", chain.name()) } }; @@ -104,17 +100,14 @@ impl CoinGecko { tokens: &HashSet, timeout: Duration, ) -> Result, PriceEstimationError> { - let mut url = crate::url::join(&self.base_url, &self.chain); + let mut url = crate::utils::join_url(&self.base_url, &self.chain); metrics::batch_size(tokens.len()); + // Sort to make the token order deterministic for better caching on CoinGecko + // egress proxy which needs the URL to be the same for cache to be hit + let mut sorted_tokens: Vec<_> = tokens.iter().map(|token| format!("{token:#x}")).collect(); + sorted_tokens.sort(); url.query_pairs_mut() - .append_pair( - "contract_addresses", - &tokens - .iter() - .map(|token| format!("{token:#x}")) - .collect::>() - .join(","), - ) + .append_pair("contract_addresses", &sorted_tokens.join(",")) .append_pair("vs_currencies", "eth") .append_pair("precision", "full"); @@ -154,7 +147,7 @@ impl CoinGecko { &self, mut tokens: HashSet, timeout: Duration, - ) -> Result, PriceEstimationError> { + ) -> Result, PriceEstimationError> { tokens.insert(self.denominator.address); let tokens_vec: Vec<_> = tokens.iter().cloned().collect(); @@ -170,7 +163,7 @@ impl CoinGecko { .cloned() .ok_or(PriceEstimationError::NoLiquidity)? .try_into() - .context("failed to convert price to decimal")?; + .map_err(|e| anyhow::anyhow!("failed to convert price to decimal: {:?}", e))?; let prices_in_denominator = tokens .into_iter() @@ -209,7 +202,7 @@ impl CoinGecko { .cloned() .ok_or(PriceEstimationError::NoLiquidity)? .try_into() - .context("failed to convert price to decimal")?; + .map_err(|e| anyhow::anyhow!("failed to convert price to decimal: {:?}", e))?; // When the quoted token and the denominator have different number of decimals // the computed price effectively needs to be shifted by the difference. @@ -235,7 +228,8 @@ impl NativePriceBatchFetching for CoinGecko { &'_ self, tokens: HashSet, timeout: Duration, - ) -> BoxFuture<'_, Result, PriceEstimationError>> { + ) -> BoxFuture<'_, Result, PriceEstimationError>> + { self.bulk_fetch_denominated_in_token(tokens, timeout) .boxed() } @@ -259,10 +253,10 @@ impl NativePriceEstimating for CoinGecko { ) -> BoxFuture<'_, NativePriceEstimateResult> { async move { let prices = self - .fetch_native_prices(HashSet::from([token.into_legacy()]), timeout) + .fetch_native_prices(HashSet::from([token]), timeout) .await?; prices - .get(&token.into_legacy()) + .get(&token) .ok_or(PriceEstimationError::NoLiquidity)? .clone() } @@ -322,12 +316,10 @@ mod metrics { mod tests { use { super::*, - crate::{ - price_estimation::HEALTHY_PRICE_ESTIMATION_TIME, - token_info::{MockTokenInfoFetching, TokenInfo}, - }, + crate::HEALTHY_PRICE_ESTIMATION_TIME, alloy::primitives::address, std::env, + token_info::{MockTokenInfoFetching, TokenInfo}, }; impl CoinGecko { @@ -342,21 +334,21 @@ mod tests { Chain::Mainnet => ( "ethereum".to_string(), Denominator { - address: addr!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), + address: address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), decimals: 18, }, ), Chain::Gnosis => ( "xdai".to_string(), Denominator { - address: addr!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), + address: address!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), decimals: 18, }, ), Chain::ArbitrumOne => ( "arbitrum-one".to_string(), Denominator { - address: addr!("82af49447d8a07e3bd95bd0d56f35241523fbab1"), + address: address!("82af49447d8a07e3bd95bd0d56f35241523fbab1"), decimals: 18, }, ), @@ -450,8 +442,8 @@ mod tests { #[tokio::test] #[ignore] async fn works_multiple_tokens() { - let usdt_token = addr!("4ECaBa5870353805a9F068101A40E0f32ed605C6"); - let usdc_token = addr!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); + let usdt_token = address!("4ECaBa5870353805a9F068101A40E0f32ed605C6"); + let usdc_token = address!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); let instance = CoinGecko::new_for_test( Client::default(), Url::parse(BASE_API_PRO_URL).unwrap(), @@ -479,8 +471,8 @@ mod tests { #[tokio::test] #[ignore] async fn unknown_token_does_not_ruin_batch() { - let usdc = addr!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); - let unknown_token = addr!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + let usdc = address!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); + let unknown_token = address!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); let instance = CoinGecko::new_for_test( Client::default(), Url::parse(BASE_API_PRO_URL).unwrap(), @@ -515,11 +507,7 @@ mod tests { tokens .iter() .map(|t| { - let decimals = if *t == usdc.into_legacy() { - Some(6) - } else { - Some(18) - }; + let decimals = if *t == usdc { Some(6) } else { Some(18) }; let info = TokenInfo { decimals, symbol: None, @@ -573,11 +561,7 @@ mod tests { .map(|t| { // Let's pretend USDC has 21 decimals to check if the price adjustment // also works when the requested token has more decimals. - let decimals = if *t == usdc.into_legacy() { - Some(21) - } else { - Some(18) - }; + let decimals = if *t == usdc { Some(21) } else { Some(18) }; let info = TokenInfo { decimals, symbol: None, diff --git a/crates/price-estimation/src/native/eip4626.rs b/crates/price-estimation/src/native/eip4626.rs new file mode 100644 index 0000000000..1c733bc1be --- /dev/null +++ b/crates/price-estimation/src/native/eip4626.rs @@ -0,0 +1,377 @@ +//! Native price estimation for EIP-4626 vault tokens. +//! +//! The protocol's inner native price estimators only know about plain +//! ERC-20s, so this module wraps one and adds support for vaults: it asks +//! the vault for its underlying asset and conversion rate, prices the +//! underlying through the inner estimator, then rescales by the vault's +//! per-atom factor. Non-vault tokens pass through unchanged. See +//! [`Eip4626`] for the step-by-step derivation. +//! +//! # Terminology +//! - an *atom* is one U256 of a token — its smallest indivisible unit +//! - a *whole* token is `10^decimals` atoms (e.g. one whole USDC = `10^6` +//! atoms) +//! - a *native price* is denominated in **wei per atom** of the priced token, +//! where wei is one atom of the chain's native asset + +use { + super::{NativePriceEstimateResult, NativePriceEstimating}, + crate::PriceEstimationError, + alloy::primitives::{Address, U256}, + anyhow::Context, + contracts::{ERC20, IERC4626}, + dashmap::DashSet, + ethrpc::{AlloyProvider, alloy::errors::ContractErrorExt}, + futures::{FutureExt, future::BoxFuture}, + model::order::BUY_ETH_ADDRESS, + num::{BigInt, BigRational, ToPrimitive}, + number::conversions::u256_to_big_rational, + std::time::{Duration, Instant}, +}; + +/// Estimates the native price of EIP-4626 vault tokens. +/// +/// To price one atom of a vault we need to know how many atoms of the +/// underlying that atom is worth, then multiply by the underlying's own +/// native price. The steps are: +/// +/// 1. Call `asset()` and `decimals()` on the vault to identify the underlying +/// asset and the vault's whole-token size. +/// 2. Call `convertToAssets(10^vault_decimals)` to learn how many *atoms* of +/// the underlying *one whole* vault token is worth. +/// 3. Divide that result by `10^vault_decimals` to get the per-atom conversion +/// factor. +/// 4. Multiply by the underlying's native price (from the inner estimator) to +/// obtain the vault's native price. +/// +/// Worked example — `ynUSDx`, an 18-decimal yield-bearing vault wrapping +/// USDC (6 decimals). The share price grows as yield accrues, so the rate is +/// a snapshot at query time; assume here that 1 whole ynUSDx is currently +/// worth 1.1 whole USDC at the queried block: +/// - `ynUSDx.asset() == USDC`, `ynUSDx.decimals() == 18` +/// - `convertToAssets(10^18) == 1_100_000` (= 1.1 whole USDC, in atoms) +/// - per-atom factor: `1_100_000 / 10^18 == 1.1e-12` +/// - if USDC's native price is `x`, then ynUSDx's is `x * 1.1e-12` +/// +/// Tokens whose `asset()` call reverts are remembered in a negative cache so +/// subsequent requests skip the RPC and go straight to the inner estimator. +pub struct Eip4626 { + inner: Box, + provider: AlloyProvider, + /// Addresses that are known *not* to be EIP-4626 vaults (i.e. `asset()` + /// reverted). Checked before making any RPC calls. + non_vault_tokens: DashSet
, +} + +impl Eip4626 { + pub fn new(inner: Box, provider: AlloyProvider) -> Self { + Self { + inner, + provider, + // BUY_ETH_ADDRESS is not ERC-20, but it is a valid estimation address + // so we need to make sure it bypasses the EIP-4626 estimator + non_vault_tokens: DashSet::from_iter([BUY_ETH_ADDRESS]), + } + } + + async fn estimate(&self, token: Address, timeout: Duration) -> NativePriceEstimateResult { + let deadline = Instant::now() + timeout; + let (underlying, cumulative_rate) = + tokio::time::timeout(timeout, self.unwrap_all_layers(token)) + .await + .map_err(|_| { + PriceEstimationError::EstimatorInternal(anyhow::anyhow!( + "timeout while unwrapping EIP-4626 layers for {token}" + )) + })??; + + let remaining = deadline.saturating_duration_since(Instant::now()); + let asset_price = self + .inner + .estimate_native_price(underlying, remaining) + .await?; + let estimate = asset_price * cumulative_rate; + tracing::debug!(%token, estimate, "eip4626: estimated native price"); + Ok(estimate) + } + + /// Follows the vault chain (e.g. vault → vault → asset) until reaching a + /// non-vault token, returning the terminal token and the cumulative + /// shares-to-assets rate. + async fn unwrap_all_layers( + &self, + token: Address, + ) -> Result<(Address, f64), PriceEstimationError> { + let mut current_token = token; + let mut cumulative_rate = 1.0; + while let Some((asset, rate)) = self.unwrap_vault_layer(current_token).await? { + cumulative_rate *= rate; + current_token = asset; + } + Ok((current_token, cumulative_rate)) + } + + /// Returns: + /// - `Ok(Some((asset, rate)))` when `token` is a vault. + /// - `Ok(None)` when it's a plain ERC-20. + /// - `Err` on RPC/computation failures that don't let us classify the + /// token. + async fn unwrap_vault_layer( + &self, + token: Address, + ) -> Result, PriceEstimationError> { + if self.non_vault_tokens.contains(&token) { + tracing::debug!(%token, "eip4626: cached non-vault, stop unwrapping"); + return Ok(None); + } + + let Some((asset, vault_decimals)) = self.fetch_vault_info(token).await? else { + self.non_vault_tokens.insert(token); + metrics::non_vault_cache_size(self.non_vault_tokens.len()); + tracing::debug!(%token, "eip4626: classified as non-vault"); + return Ok(None); + }; + let assets = self.fetch_conversion_data(token, vault_decimals).await?; + let rate = conversion_rate(assets, vault_decimals) + .context("conversion rate is not representable as f64") + .map_err(PriceEstimationError::EstimatorInternal)?; + tracing::debug!(%token, %asset, rate, "eip4626: unwrapped vault layer"); + Ok(Some((asset, rate))) + } + + /// Fetches the vault's underlying asset address and vault token decimals. + /// + /// Returns: + /// - `Ok(Some(...))` when `token` is a vault. + /// - `Ok(None)` when `asset()` reverts (indicating it is a regular ERC-20). + /// - `Err` on transient transport failures — those are *not* cached as + /// non-vault. + async fn fetch_vault_info( + &self, + token: Address, + ) -> Result, PriceEstimationError> { + let vault = IERC4626::IERC4626::new(token, &self.provider); + let vault_erc20 = ERC20::ERC20::new(token, &self.provider); + let asset_call = vault.asset(); + let decimals_call = vault_erc20.decimals(); + let (asset_result, decimals_result) = tokio::join!(asset_call.call(), decimals_call.call()); + + match asset_result { + Ok(asset) => { + // EIP-4626 vaults implement ERC-20 so decimals() must succeed too. + let vault_decimals = decimals_result.map_err(|err| { + PriceEstimationError::EstimatorInternal(anyhow::anyhow!( + "failed to call decimals() on {token}: {err}" + )) + })?; + Ok(Some((asset, vault_decimals))) + } + // Contract-level revert on `asset()` + working `decimals()` = + // plain ERC-20. Transient transport failures propagate so they + // retry instead of pinning the token as non-vault. + Err(err) if err.is_contract_revert() && decimals_result.is_ok() => Ok(None), + Err(err) => Err(PriceEstimationError::EstimatorInternal(anyhow::anyhow!( + "failed to call asset() on {token}: {err}" + ))), + } + } + + /// Fetches `convertToAssets(10^vault_decimals)` — how many atomic units of + /// the underlying asset correspond to one full vault token. + async fn fetch_conversion_data( + &self, + token: Address, + vault_decimals: u8, + ) -> Result { + let one_token = U256::from(10u64) + .checked_pow(U256::from(vault_decimals)) + .ok_or_else(|| { + PriceEstimationError::EstimatorInternal(anyhow::anyhow!( + "vault decimals {vault_decimals} for {token} cause U256 overflow" + )) + })?; + + let vault = IERC4626::IERC4626::new(token, &self.provider); + vault + .convertToAssets(one_token) + .call() + .await + .map_err(|err| { + PriceEstimationError::EstimatorInternal(anyhow::anyhow!( + "failed to call convertToAssets() on {token}: {err}" + )) + }) + } +} + +impl NativePriceEstimating for Eip4626 { + fn estimate_native_price( + &self, + token: Address, + timeout: Duration, + ) -> BoxFuture<'_, NativePriceEstimateResult> { + self.estimate(token, timeout).boxed() + } +} + +/// Converts the result of `convertToAssets(10^vault_decimals)` into the +/// per-atom factor (atoms of underlying per atom of vault) by dividing by +/// `10^vault_decimals`. See the module docstring for the full derivation. +/// +/// This differs from the intuitive whole-to-whole share rate by +/// `10^(asset_decimals - vault_decimals)` — they only coincide when vault +/// and asset decimals match. +/// +/// Returns `None` when the result is not representable as `f64`. +fn conversion_rate(assets: U256, vault_decimals: u8) -> Option { + let denominator = BigRational::from_integer(BigInt::from(10u64).pow(vault_decimals as u32)); + (u256_to_big_rational(&assets) / denominator).to_f64() +} + +mod metrics { + use {observe::metrics, prometheus::IntGauge}; + + #[derive(prometheus_metric_storage::MetricStorage)] + struct Metrics { + /// Number of tokens in the EIP-4626 negative cache (known non-vault + /// tokens). + eip4626_non_vault_cache_size: IntGauge, + } + + impl Metrics { + fn get() -> &'static Self { + Metrics::instance(metrics::get_storage_registry()).unwrap() + } + } + + pub(super) fn non_vault_cache_size(size: usize) { + Metrics::get() + .eip4626_non_vault_cache_size + .set(i64::try_from(size).unwrap_or(i64::MAX)); + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{HEALTHY_PRICE_ESTIMATION_TIME, native::MockNativePriceEstimating}, + alloy::providers::mock::Asserter, + std::borrow::Cow, + }; + + const TOLERANCE: f64 = 1e-9; + + /// Asserts `computed_rate` is within a `tolerance` of `expected_rate`. + fn assert_rate_close(computed_rate: f64, expected_rate: f64, tolerance: f64) { + let slack = expected_rate.abs() * tolerance; + let expected_range = (expected_rate - slack)..(expected_rate + slack); + assert!( + expected_range.contains(&computed_rate), + "computed_rate={computed_rate}, expected_rate={expected_rate}, tolerance={tolerance}", + ); + } + + #[test] + fn rate_math_same_decimals() { + // 18-decimal vault wrapping 18-decimal asset: + // 1 whole share = 1.5 whole asset tokens. + // - vault.decimals() = 18, asset.decimals() = 18 + // - convertToAssets(10^18) = 1.5 * 10^18 (in asset atoms) + // - per-atom factor = 1.5 * 10^18 / 10^18 = 1.5 + // - matches the whole-to-whole rate exactly when decimals align. + let assets = U256::from(15u64) * U256::from(10u64).pow(U256::from(17u64)); + let computed_rate = conversion_rate(assets, 18).unwrap(); + + assert_rate_close(computed_rate, 1.5, TOLERANCE); + } + + #[test] + fn rate_math_vault_18_asset_6() { + // 18-decimal vault wrapping 6-decimal USDC: + // 1 whole share = 1.5 whole USDC. + // - vault.decimals() = 18, asset.decimals() = 6 + // - convertToAssets(10^18) = 1_500_000 (= 1.5 whole USDC, in atoms) + // - per-atom factor = 1_500_000 / 10^18 = 1.5e-12 + // - = whole-share rate (1.5) scaled by 10^(asset_dec - vault_dec) = 10^-12. + let assets = U256::from(1_500_000u64); + let computed_rate = conversion_rate(assets, 18).unwrap(); + + assert_rate_close(computed_rate, 1.5e-12, TOLERANCE); + } + + #[test] + fn rate_math_vault_6_asset_18() { + // 6-decimal vault wrapping 18-decimal asset: + // 1 whole share = 2 whole asset tokens. + // - vault.decimals() = 6, asset.decimals() = 18 + // - convertToAssets(10^6) = 2 * 10^18 (= 2 whole tokens, in atoms) + // - per-atom factor = 2 * 10^18 / 10^6 = 2e12 + // - = whole-share rate (2) scaled by 10^(asset_dec - vault_dec) = 10^12. + let assets = U256::from(2u64) * U256::from(10u64).pow(U256::from(18u64)); + let computed_rate = conversion_rate(assets, 6).unwrap(); + + assert_rate_close(computed_rate, 2e12, TOLERANCE); + } + + /// Tests two (related) things: + /// * Cached tokens bypass the EIP-4626 provider calls — i.e. calling + /// decimals, assets, etc + /// * That the BUY_ETH_ADDRESS is cached by default (and the previous + /// applies to it) + #[tokio::test] + async fn buy_eth_address_bypasses_eth_calls() { + let mut inner = MockNativePriceEstimating::new(); + let token = BUY_ETH_ADDRESS; + let expected_price = 1.5; + inner + .expect_estimate_native_price() + .withf(move |t, _| *t == token) + .returning(move |_, _| Box::pin(async move { Ok(expected_price) })); + + let asserter = Asserter::new(); + asserter.push_failure_msg(Cow::from("calls are not being bypassed")); + let web3 = ethrpc::Web3::with_asserter(asserter); + + let estimator = Eip4626::new(Box::new(inner), web3.provider); + + let result = estimator + .estimate(token, HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.unwrap(), expected_price); + + let result = estimator + .estimate(Address::random(), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert!( + matches!(result, Err(PriceEstimationError::EstimatorInternal(_))), + "{result:?}" + ); + } + + #[tokio::test] + async fn non_vault_tokens_delegate_to_inner() { + let mut inner = MockNativePriceEstimating::new(); + let token = Address::repeat_byte(0x42); + let expected_price = 1.5; + inner + .expect_estimate_native_price() + .withf(move |t, _| *t == token) + .returning(move |_, _| Box::pin(async move { Ok(expected_price) })); + + let non_vault_tokens = DashSet::new(); + non_vault_tokens.insert(token); + + let estimator = Eip4626 { + inner: Box::new(inner), + // The provider is never reached because the cache short-circuits. + provider: ethrpc::Web3::new_from_url("http://localhost:1").provider, + non_vault_tokens, + }; + + let result = estimator + .estimate(token, HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.unwrap(), expected_price); + } +} diff --git a/crates/price-estimation/src/native/fallback.rs b/crates/price-estimation/src/native/fallback.rs new file mode 100644 index 0000000000..d67e5aba9f --- /dev/null +++ b/crates/price-estimation/src/native/fallback.rs @@ -0,0 +1,530 @@ +//! A native price estimator wrapper that automatically switches to a fallback +//! estimator when the primary becomes unavailable. +//! +//! # State Machine +//! +//! The estimator operates as a two-state machine: +//! +//! ```text +//! 3 consecutive +//! ProtocolInternal errors +//! ┌─────────┐ ───────────────────────> ┌──────────┐ +//! │ Primary │ │ Fallback │ +//! └─────────┘ <─────────────────────── └──────────┘ +//! probe succeeds +//! (every PROBE_INTERVAL) +//! ``` +//! +//! **Primary state**: All requests go to the primary estimator. A counter +//! tracks consecutive [`PriceEstimationError::ProtocolInternal`] errors. Any +//! success resets the counter. Once the counter reaches +//! [`CONSECUTIVE_ERRORS_THRESHOLD`], the estimator switches to fallback and +//! the current request is retried against the fallback. +//! +//! **Fallback state**: All requests go to the fallback estimator. Every +//! [`PROBE_INTERVAL`], one request probes both the primary and fallback +//! concurrently. If the primary probe succeeds, the estimator switches back to +//! primary; otherwise it stays in fallback and resets the probe timer. +//! +//! Only `ProtocolInternal` errors (e.g. connection refused, timeouts) trigger +//! the switch. Domain errors like `NoLiquidity` do not affect the state. + +use { + crate::{ + PriceEstimationError, + native::{NativePriceEstimateResult, NativePriceEstimating}, + }, + alloy::primitives::Address, + futures::{FutureExt, future::BoxFuture}, + std::{ + sync::Mutex, + time::{Duration, Instant}, + }, +}; + +/// How often the estimator probes the primary while in fallback state. +const PROBE_INTERVAL: Duration = Duration::from_secs(60); + +/// Number of consecutive `ProtocolInternal` errors from the primary before +/// switching to fallback. +const CONSECUTIVE_ERRORS_THRESHOLD: u32 = 3; + +enum State { + Primary { + /// Counts consecutive protocol internal errors from the primary + /// estimator. + consecutive_errors: u32, + }, + Fallback { + /// Tracks when we last tried the primary. + last_probe: Instant, + }, +} + +/// What the estimator should do for the current request based on the current +/// state and probe timing. +enum Action { + /// Use the primary estimator. + Primary, + /// Use the fallback estimator directly (within probe interval). + Fallback, + /// Probe both primary and fallback concurrently (probe interval elapsed). + Probe, +} + +/// Wraps a primary and fallback [`NativePriceEstimating`] implementation, +/// automatically switching to the fallback when the primary experiences +/// repeated `ProtocolInternal` failures and periodically probing to recover. +pub struct FallbackNativePriceEstimator { + primary: Box, + fallback: Box, + state: Mutex, +} + +impl FallbackNativePriceEstimator { + pub fn new( + primary: Box, + fallback: Box, + ) -> Self { + Self { + primary, + fallback, + state: Mutex::new(State::Primary { + consecutive_errors: 0, + }), + } + } +} + +impl FallbackNativePriceEstimator { + /// Returns `true` if the fallback should be used. + fn should_use_fallback(&self, result: &NativePriceEstimateResult) -> bool { + let Err(PriceEstimationError::ProtocolInternal(err)) = result else { + if let State::Primary { + consecutive_errors, .. + } = &mut *self.state.lock().unwrap() + { + *consecutive_errors = 0; + } + return false; + }; + + let (use_fallback, consecutive_errors) = { + let mut state = self.state.lock().unwrap(); + let State::Primary { + consecutive_errors, .. + } = &mut *state + else { + return false; + }; + *consecutive_errors += 1; + let count = *consecutive_errors; + if count >= CONSECUTIVE_ERRORS_THRESHOLD { + *state = State::Fallback { + last_probe: Instant::now(), + }; + (true, count) + } else { + (false, count) + } + }; + + if use_fallback { + tracing::info!( + ?err, + consecutive_errors, + "primary native price estimator down, switching to fallback" + ); + } else { + tracing::debug!( + ?err, + consecutive_errors, + "primary native price estimator error, not yet switching to fallback" + ); + } + use_fallback + } + + fn next_action(&self) -> Action { + let mut state = self.state.lock().unwrap(); + match &mut *state { + State::Primary { .. } => Action::Primary, + State::Fallback { last_probe } if last_probe.elapsed() >= PROBE_INTERVAL => { + // Update immediately to prevent concurrent requests from also + // probing (thundering herd). + *last_probe = Instant::now(); + Action::Probe + } + State::Fallback { .. } => Action::Fallback, + } + } + + async fn estimate_with_primary( + &self, + token: Address, + timeout: Duration, + ) -> NativePriceEstimateResult { + let result = self.primary.estimate_native_price(token, timeout).await; + if self.should_use_fallback(&result) { + self.fallback.estimate_native_price(token, timeout).await + } else { + result + } + } + + async fn estimate_with_probe( + &self, + token: Address, + timeout: Duration, + ) -> NativePriceEstimateResult { + let (primary_result, fallback_result) = futures::join!( + self.primary.estimate_native_price(token, timeout), + self.fallback.estimate_native_price(token, timeout), + ); + + if matches!( + &primary_result, + Err(PriceEstimationError::ProtocolInternal(_)) + ) { + { + let mut state = self.state.lock().unwrap(); + *state = State::Fallback { + last_probe: Instant::now(), + }; + } + tracing::debug!("primary still down after probe, continuing with fallback"); + fallback_result + } else { + { + let mut state = self.state.lock().unwrap(); + *state = State::Primary { + consecutive_errors: 0, + }; + } + tracing::info!("primary native price estimator recovered"); + primary_result + } + } +} + +impl NativePriceEstimating for FallbackNativePriceEstimator { + fn estimate_native_price( + &self, + token: Address, + timeout: Duration, + ) -> BoxFuture<'_, NativePriceEstimateResult> { + async move { + match self.next_action() { + Action::Primary => self.estimate_with_primary(token, timeout).await, + Action::Probe => self.estimate_with_probe(token, timeout).await, + Action::Fallback => self.fallback.estimate_native_price(token, timeout).await, + } + } + .boxed() + } +} + +#[cfg(test)] +mod tests { + use {super::*, crate::native::MockNativePriceEstimating, futures::FutureExt}; + + const TOKEN: Address = Address::with_last_byte(1); + const TIMEOUT: Duration = Duration::from_secs(5); + + #[tokio::test] + async fn uses_primary_when_healthy() { + let mut primary = MockNativePriceEstimating::new(); + primary + .expect_estimate_native_price() + .returning(|_, _| async { Ok(1.0) }.boxed()); + + let mut fallback = MockNativePriceEstimating::new(); + fallback.expect_estimate_native_price().never(); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 1.0); + } + + #[tokio::test] + async fn switches_to_fallback_on_protocol_internal() { + let mut primary = MockNativePriceEstimating::new(); + primary + .expect_estimate_native_price() + .times(3) + .returning(|_, _| { + async { + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "connection refused" + ))) + } + .boxed() + }); + + let mut fallback = MockNativePriceEstimating::new(); + fallback + .expect_estimate_native_price() + .times(1) + .returning(|_, _| async { Ok(2.0) }.boxed()); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + // First two errors: stay in primary, return the error + for _ in 0..2 { + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert!(matches!( + result, + Err(PriceEstimationError::ProtocolInternal(_)) + )); + } + + // Third error: threshold reached, switch to fallback + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 2.0); + } + + #[tokio::test] + async fn stays_in_fallback_without_probing_before_interval() { + let mut primary = MockNativePriceEstimating::new(); + // Called 3 times (threshold) for the initial failures, NOT called again before + // probe interval + primary + .expect_estimate_native_price() + .times(3) + .returning(|_, _| { + async { + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "connection refused" + ))) + } + .boxed() + }); + + let mut fallback = MockNativePriceEstimating::new(); + // Called once when threshold is reached, once for the subsequent request + fallback + .expect_estimate_native_price() + .times(2) + .returning(|_, _| async { Ok(2.0) }.boxed()); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + // First two calls: primary errors returned (below threshold) + for _ in 0..2 { + let _ = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + } + + // Third call: threshold reached, triggers fallback + let _ = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + + // Fourth call should use fallback directly (within probe interval) + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 2.0); + } + + #[tokio::test] + async fn probes_primary_after_interval_and_recovers() { + let mut primary = MockNativePriceEstimating::new(); + let mut call_count = 0u32; + primary + .expect_estimate_native_price() + .times(4) // 3 for threshold + 1 probe + .returning(move |_, _| { + call_count += 1; + if call_count <= 3 { + // First 3 calls: primary is down (reaching threshold) + async { + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "connection refused" + ))) + } + .boxed() + } else { + // Fourth call (probe): primary recovered + async { Ok(1.0) }.boxed() + } + }); + + let mut fallback = MockNativePriceEstimating::new(); + // Called once when threshold is reached + once during probe (concurrent) + fallback + .expect_estimate_native_price() + .times(2) + .returning(|_, _| async { Ok(2.0) }.boxed()); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + // First two calls: primary errors returned (below threshold) + for _ in 0..2 { + let _ = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + } + + // Third call: threshold reached, triggers fallback + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 2.0); + + // Force probe interval to expire + { + let mut state = estimator.state.lock().unwrap(); + *state = State::Fallback { + last_probe: Instant::now() - PROBE_INTERVAL - Duration::from_secs(1), + }; + } + + // This call should probe primary (which recovers) and return primary result + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 1.0); + } + + #[tokio::test] + async fn probes_primary_after_interval_stays_in_fallback_if_still_down() { + let mut primary = MockNativePriceEstimating::new(); + primary.expect_estimate_native_price().returning(|_, _| { + async { + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "connection refused" + ))) + } + .boxed() + }); + + let mut fallback = MockNativePriceEstimating::new(); + fallback + .expect_estimate_native_price() + .returning(|_, _| async { Ok(2.0) }.boxed()); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + // First two calls: primary errors (below threshold) + for _ in 0..2 { + let _ = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + } + + // Third call: threshold reached, triggers fallback + let _ = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + + // Force probe interval to expire + { + let mut state = estimator.state.lock().unwrap(); + *state = State::Fallback { + last_probe: Instant::now() - PROBE_INTERVAL - Duration::from_secs(1), + }; + } + + // Probe fires, primary still down → use fallback result + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 2.0); + } + + #[tokio::test] + async fn does_not_switch_on_fewer_than_threshold_errors() { + let mut primary = MockNativePriceEstimating::new(); + let mut call_count = 0u32; + primary + .expect_estimate_native_price() + .times(3) + .returning(move |_, _| { + call_count += 1; + if call_count <= 2 { + async { + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "transient error" + ))) + } + .boxed() + } else { + // Third call: primary recovers before threshold + async { Ok(1.0) }.boxed() + } + }); + + let mut fallback = MockNativePriceEstimating::new(); + fallback.expect_estimate_native_price().never(); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + // Two errors: below threshold, stay in primary + for _ in 0..2 { + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert!(matches!( + result, + Err(PriceEstimationError::ProtocolInternal(_)) + )); + } + + // Third call: primary succeeds, fallback never used + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 1.0); + } + + #[tokio::test] + async fn resets_counter_on_success() { + let mut primary = MockNativePriceEstimating::new(); + let mut call_count = 0u32; + primary + .expect_estimate_native_price() + .times(4) + .returning(move |_, _| { + call_count += 1; + match call_count { + // error, success, error, error — never reaches 3 consecutive + 1 | 3 | 4 => async { + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "transient error" + ))) + } + .boxed(), + 2 => async { Ok(1.0) }.boxed(), + _ => unreachable!(), + } + }); + + let mut fallback = MockNativePriceEstimating::new(); + fallback.expect_estimate_native_price().never(); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + // Call 1: error (consecutive_errors = 1) + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert!(matches!( + result, + Err(PriceEstimationError::ProtocolInternal(_)) + )); + + // Call 2: success (consecutive_errors reset to 0) + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert_eq!(result.unwrap(), 1.0); + + // Call 3: error (consecutive_errors = 1) + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert!(matches!( + result, + Err(PriceEstimationError::ProtocolInternal(_)) + )); + + // Call 4: error (consecutive_errors = 2, still below threshold) + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert!(matches!( + result, + Err(PriceEstimationError::ProtocolInternal(_)) + )); + } + + #[tokio::test] + async fn does_not_switch_on_non_protocol_errors() { + let mut primary = MockNativePriceEstimating::new(); + primary + .expect_estimate_native_price() + .times(1) + .returning(|_, _| async { Err(PriceEstimationError::NoLiquidity) }.boxed()); + + let mut fallback = MockNativePriceEstimating::new(); + fallback.expect_estimate_native_price().never(); + + let estimator = FallbackNativePriceEstimator::new(Box::new(primary), Box::new(fallback)); + + let result = estimator.estimate_native_price(TOKEN, TIMEOUT).await; + assert!(matches!(result, Err(PriceEstimationError::NoLiquidity))); + } +} diff --git a/crates/price-estimation/src/native/forwarder.rs b/crates/price-estimation/src/native/forwarder.rs new file mode 100644 index 0000000000..99198eb2c9 --- /dev/null +++ b/crates/price-estimation/src/native/forwarder.rs @@ -0,0 +1,93 @@ +//! Forwards native price estimation requests to autopilot's HTTP API. +//! +//! This allows orderbook instances to share autopilot's native price cache +//! instead of maintaining independent caches, avoiding cache inconsistencies +//! and reducing rate limiting from external price estimators. + +use { + super::{NativePriceEstimateResult, NativePriceEstimating}, + crate::PriceEstimationError, + alloy::primitives::Address, + anyhow::Context, + futures::{FutureExt, future::BoxFuture}, + model::quote::NativeTokenPrice, + reqwest::StatusCode, + std::time::Duration, + url::Url, +}; + +pub struct Forwarder { + client: reqwest::Client, + autopilot_url: Url, +} + +impl Forwarder { + pub fn new(client: reqwest::Client, autopilot_url: Url) -> Self { + Self { + client, + autopilot_url, + } + } + + async fn try_fetch(&self, token: Address, timeout: Duration) -> NativePriceEstimateResult { + let url = self + .autopilot_url + .join(format!("native_price/{:?}", token).as_str()) + .context("failed to construct autopilot URL")?; + + let mut request = self + .client + .get(url) + .query(&[("timeout_ms", timeout.as_millis() as u64)]) + .timeout(timeout); + if let Some(id) = observe::tracing::distributed::request_id::from_current_span() { + request = request.header("X-REQUEST-ID", id); + } + let response = request.send().await.map_err(|err| { + PriceEstimationError::ProtocolInternal( + anyhow::Error::new(err).context("failed to send request"), + ) + })?; + + match response.status() { + StatusCode::OK => { + let price: NativeTokenPrice = + response.json().await.context("failed to parse response")?; + Ok(price.price) + } + StatusCode::NOT_FOUND => Err(PriceEstimationError::NoLiquidity), + StatusCode::TOO_MANY_REQUESTS => Err(PriceEstimationError::RateLimited), + StatusCode::BAD_REQUEST => { + let error_text = response + .text() + .await + .unwrap_or_else(|_| "unknown error".to_string()); + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "bad request: {}", + error_text + ))) + } + status => { + let error_text = response + .text() + .await + .unwrap_or_else(|_| format!("HTTP {}", status)); + Err(PriceEstimationError::ProtocolInternal(anyhow::anyhow!( + "autopilot returned status {}: {}", + status, + error_text + ))) + } + } + } +} + +impl NativePriceEstimating for Forwarder { + fn estimate_native_price( + &self, + token: Address, + timeout: Duration, + ) -> BoxFuture<'_, NativePriceEstimateResult> { + self.try_fetch(token, timeout).boxed() + } +} diff --git a/crates/shared/src/price_estimation/native/mod.rs b/crates/price-estimation/src/native/mod.rs similarity index 78% rename from crates/shared/src/price_estimation/native/mod.rs rename to crates/price-estimation/src/native/mod.rs index 5070e93aa8..95338b3562 100644 --- a/crates/shared/src/price_estimation/native/mod.rs +++ b/crates/price-estimation/src/native/mod.rs @@ -1,12 +1,10 @@ use { - crate::price_estimation::{PriceEstimating, PriceEstimationError, Query}, + crate::{PriceEstimating, PriceEstimationError, Query}, alloy::primitives::Address, bigdecimal::{BigDecimal, ToPrimitive}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::FutureExt, model::order::OrderKind, - number::nonzero::U256 as NonZeroU256, - primitive_types::{H160, U256}, + number::nonzero::NonZeroU256, std::{ sync::{Arc, LazyLock}, time::Duration, @@ -15,9 +13,18 @@ use { }; mod coingecko; +mod eip4626; +pub mod fallback; +mod forwarder; mod oneinch; -pub use self::{coingecko::CoinGecko, oneinch::OneInch}; +pub use self::{ + coingecko::CoinGecko, + eip4626::Eip4626, + fallback::FallbackNativePriceEstimator, + forwarder::Forwarder, + oneinch::OneInch, +}; pub type NativePrice = f64; pub type NativePriceEstimateResult = Result; @@ -37,12 +44,12 @@ pub fn from_normalized_price(price: BigDecimal) -> Option { } /// Convert from floating point price to normalized price -pub fn to_normalized_price(price: f64) -> Option { +pub fn to_normalized_price(price: f64) -> Option { let uint_max = 2.0_f64.powi(256); let price_in_eth = 1e18 * price; (price_in_eth.is_normal() && price_in_eth >= 1. && price_in_eth < uint_max) - .then_some(U256::from_f64_lossy(price_in_eth)) + .then_some(alloy::primitives::U256::saturating_from(price_in_eth)) } #[cfg_attr(any(test, feature = "test-util"), mockall::automock)] @@ -62,14 +69,14 @@ pub trait NativePriceEstimating: Send + Sync { /// compared to the current chain's native token. pub struct NativePriceEstimator { inner: Arc, - native_token: H160, + native_token: Address, price_estimation_amount: NonZeroU256, } impl NativePriceEstimator { pub fn new( inner: Arc, - native_token: H160, + native_token: Address, price_estimation_amount: NonZeroU256, ) -> Self { Self { @@ -80,10 +87,10 @@ impl NativePriceEstimator { } // TODO explain why we use BUY order type (shallow liquidity) - fn query(&self, token: &H160, timeout: Duration) -> Query { + fn query(&self, token: &Address, timeout: Duration) -> Query { Query { - sell_token: token.into_alloy(), - buy_token: self.native_token.into_alloy(), + sell_token: *token, + buy_token: self.native_token, in_amount: self.price_estimation_amount, kind: OrderKind::Buy, verification: Default::default(), @@ -101,7 +108,7 @@ impl NativePriceEstimating for NativePriceEstimator { timeout: Duration, ) -> futures::future::BoxFuture<'_, NativePriceEstimateResult> { async move { - let query = Arc::new(self.query(&token.into_legacy(), timeout)); + let query = Arc::new(self.query(&token, timeout)); let estimate = self.inner.estimate(query.clone()).await?; let price = estimate.price_in_buy_token_f64(&query); if is_price_malformed(price) { @@ -116,16 +123,22 @@ impl NativePriceEstimating for NativePriceEstimator { } pub(crate) fn is_price_malformed(price: f64) -> bool { - !price.is_normal() || price <= 0. + !price.is_normal() + || price <= 0. + // To convert the f64 native price into a format usable in the auction + // the autopilot calls `to_normalized_price()`. Orders placed using a + // native price that fails this conversion will likely time out because + // the autopilot will not put them into the auction. To prevent that we + // already check the conversion here. + || to_normalized_price(price).is_none() } #[cfg(test)] mod tests { use { super::*, - crate::price_estimation::{Estimate, HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating}, - alloy::primitives::Address, - primitive_types::H160, + crate::{Estimate, HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating}, + alloy::primitives::{Address, U256}, std::str::FromStr, }; @@ -137,9 +150,9 @@ mod tests { assert!(query.sell_token == Address::with_last_byte(3)); async { Ok(Estimate { - out_amount: 123_456_789_000_000_000u128.into(), + out_amount: U256::from(123_456_789_000_000_000u128), gas: 0, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, execution: Default::default(), }) @@ -149,8 +162,9 @@ mod tests { let native_price_estimator = NativePriceEstimator { inner: Arc::new(inner), - native_token: H160::from_low_u64_be(7), - price_estimation_amount: NonZeroU256::try_from(U256::exp10(18)).unwrap(), + native_token: Address::with_last_byte(7), + price_estimation_amount: NonZeroU256::try_from(U256::from(10).pow(U256::from(18))) + .unwrap(), }; let result = native_price_estimator @@ -170,8 +184,9 @@ mod tests { let native_price_estimator = NativePriceEstimator { inner: Arc::new(inner), - native_token: H160::from_low_u64_be(7), - price_estimation_amount: NonZeroU256::try_from(U256::exp10(18)).unwrap(), + native_token: Address::with_last_byte(7), + price_estimation_amount: NonZeroU256::try_from(U256::from(10).pow(U256::from(18))) + .unwrap(), }; let result = native_price_estimator diff --git a/crates/shared/src/price_estimation/native/oneinch.rs b/crates/price-estimation/src/native/oneinch.rs similarity index 91% rename from crates/shared/src/price_estimation/native/oneinch.rs rename to crates/price-estimation/src/native/oneinch.rs index 71328f2954..155d77c0e3 100644 --- a/crates/shared/src/price_estimation/native/oneinch.rs +++ b/crates/price-estimation/src/native/oneinch.rs @@ -1,16 +1,12 @@ use { super::{NativePrice, NativePriceEstimateResult, NativePriceEstimating}, - crate::{price_estimation::PriceEstimationError, token_info::TokenInfoFetching}, - alloy::primitives::Address, + crate::PriceEstimationError, + alloy::primitives::{Address, U256}, anyhow::{Context, Result, anyhow}, - ethrpc::{ - alloy::conversions::IntoAlloy, - block_stream::{CurrentBlockWatcher, into_stream}, - }, + ethrpc::block_stream::{CurrentBlockWatcher, into_stream}, futures::{FutureExt, StreamExt, future::BoxFuture}, num::ToPrimitive, number::{conversions::u256_to_big_rational, serialization::HexOrDecimalU256}, - primitive_types::{H160, U256}, reqwest::{Client, header::AUTHORIZATION}, serde::Deserialize, serde_with::serde_as, @@ -19,13 +15,14 @@ use { sync::{Arc, Mutex}, time::Duration, }, + token_info::TokenInfoFetching, tracing::instrument, url::Url, }; #[serde_as] #[derive(Debug, Deserialize)] -struct Response(#[serde_as(as = "HashMap<_, HexOrDecimalU256>")] HashMap); +struct Response(#[serde_as(as = "HashMap<_, HexOrDecimalU256>")] HashMap); type Token = Address; @@ -118,7 +115,7 @@ async fn get_current_prices( chain: u64, token_info: &dyn TokenInfoFetching, ) -> Result> { - let url = crate::url::join(&base_url, &format!("/price/v1.1/{chain}")); + let url = crate::utils::join_url(&base_url, &format!("/price/v1.1/{chain}")); let mut builder = client.get(url); if let Some(api_key) = api_key { builder = builder.header(AUTHORIZATION, api_key) @@ -155,7 +152,7 @@ async fn get_current_prices( let unit = num::BigRational::from_integer(num::BigInt::from(10u64).pow(decimals.into())); let normalized_price = u256_to_big_rational(&price) / unit; - Some((token.into_alloy(), normalized_price.to_f64()?)) + Some((token, normalized_price.to_f64()?)) }) .collect(); Ok(normalized_prices) @@ -165,12 +162,10 @@ async fn get_current_prices( mod tests { use { super::*, - crate::{ - price_estimation::HEALTHY_PRICE_ESTIMATION_TIME, - token_info::{MockTokenInfoFetching, TokenInfo}, - }, + crate::HEALTHY_PRICE_ESTIMATION_TIME, alloy::primitives::address, std::env, + token_info::{MockTokenInfoFetching, TokenInfo}, }; const BASE_URL: &str = "https://api.1inch.dev/"; diff --git a/crates/price-estimation/src/native_price_cache.rs b/crates/price-estimation/src/native_price_cache.rs new file mode 100644 index 0000000000..c6da967733 --- /dev/null +++ b/crates/price-estimation/src/native_price_cache.rs @@ -0,0 +1,1199 @@ +use { + super::PriceEstimationError, + crate::native::{NativePriceEstimateResult, NativePriceEstimating, from_normalized_price}, + alloy::primitives::Address, + arc_swap::ArcSwap, + bigdecimal::BigDecimal, + futures::{FutureExt, StreamExt}, + prometheus::{IntCounter, IntCounterVec, IntGauge}, + rand::Rng, + std::{ + collections::{HashMap, HashSet}, + sync::Arc, + time::{Duration, Instant}, + }, + tokio::time, + tracing::{Instrument, instrument}, +}; + +/// Represents a token used for price approximation, including the normalization +/// factor needed to convert between tokens with potentially different decimals. +#[derive(Debug, Clone, Copy)] +pub struct ApproximationToken { + /// The address of the token to use for price approximation. + pub address: Address, + /// The factor to multiply the approximated price by to normalize for + /// decimal differences. Computed as 10^(to_decimals - from_decimals). + pub normalization_factor: f64, +} + +impl ApproximationToken { + /// Creates an approximation token with no decimal normalization needed + /// (both tokens have the same decimals). + pub fn same_decimals(address: Address) -> Self { + Self { + address, + normalization_factor: 1.0, + } + } + + /// Creates an approximation token with the specified normalization factor. + /// The normalization factor converts prices from the approximation token's + /// decimal basis to the source token's decimal basis. + pub fn with_normalization( + (peg_token, peg_token_decimals): (Address, u8), + token_decimals: u8, + ) -> Self { + let decimals_diff = i32::from(peg_token_decimals) - i32::from(token_decimals); + Self { + address: peg_token, + normalization_factor: 10f64.powi(decimals_diff), + } + } + + /// Applies the normalization factor to a price. + pub fn normalize_price(&self, price: f64) -> f64 { + price * self.normalization_factor + } +} + +#[derive(prometheus_metric_storage::MetricStorage)] +struct CacheMetrics { + /// native price cache hits misses + #[metric(labels("result"))] + native_price_cache_access: IntCounterVec, + /// number of items in cache + native_price_cache_size: IntGauge, +} + +impl CacheMetrics { + fn get() -> &'static Self { + CacheMetrics::instance(observe::metrics::get_storage_registry()).unwrap() + } +} + +#[derive(prometheus_metric_storage::MetricStorage)] +struct UpdaterMetrics { + /// number of background updates performed + native_price_cache_background_updates: IntCounter, +} + +impl UpdaterMetrics { + fn get() -> &'static Self { + UpdaterMetrics::instance(observe::metrics::get_storage_registry()).unwrap() + } +} + +type CacheEntry = Result; + +#[derive(Debug, Clone)] +struct CachedResult { + result: CacheEntry, + updated_at: Instant, + accumulative_errors_count: u32, +} + +/// Defines how many consecutive errors are allowed before the cache starts +/// returning the error to the user without trying to fetch the price from the +/// estimator. +const ACCUMULATIVE_ERRORS_THRESHOLD: u32 = 5; + +impl CachedResult { + fn new(result: CacheEntry) -> Self { + let now = Instant::now(); + let is_accumulating_error = + matches!(result, Err(PriceEstimationError::EstimatorInternal(_))); + + Self { + result, + updated_at: now, + accumulative_errors_count: u32::from(is_accumulating_error), + } + } + + fn update(&mut self, result: CacheEntry) { + let now = Instant::now(); + self.updated_at = now; + self.accumulative_errors_count = match result { + Err(PriceEstimationError::EstimatorInternal(_)) => self.accumulative_errors_count + 1, + _ => 0, + }; + self.result = result; + } + + /// The result is not ready if the estimator has returned an internal error + /// and consecutive errors are less than + /// `ESTIMATOR_INTERNAL_ERRORS_THRESHOLD`. + fn is_ready(&self) -> bool { + !matches!(self.result, Err(PriceEstimationError::EstimatorInternal(_))) + || self.accumulative_errors_count >= ACCUMULATIVE_ERRORS_THRESHOLD + } +} + +fn should_cache(result: &Result) -> bool { + // We don't want to cache errors that we consider transient + match result { + Ok(_) + | Err(PriceEstimationError::NoLiquidity) + | Err(PriceEstimationError::UnsupportedToken { .. }) + | Err(PriceEstimationError::EstimatorInternal(_)) => true, + Err(PriceEstimationError::ProtocolInternal(_)) | Err(PriceEstimationError::RateLimited) => { + false + } + Err(PriceEstimationError::UnsupportedOrderType(_)) + | Err(PriceEstimationError::TradingOutsideAllowedWindow { .. }) + | Err(PriceEstimationError::TokenTemporarilySuspended { .. }) + | Err(PriceEstimationError::InsufficientLiquidity { .. }) + | Err(PriceEstimationError::CustomSolverError { .. }) => { + tracing::error!(?result, "Unexpected error in native price cache"); + false + } + } +} + +/// Passive shared data store for native price cache entries. Clone via internal +/// `Arc`. +#[derive(Clone)] +pub struct Cache(Arc); + +const MAX_CACHE_SIZE: u64 = 20_000; + +struct CacheInner { + data: moka::sync::Cache, + max_age: Duration, +} + +impl Cache { + pub fn new(max_age: Duration, initial_prices: HashMap) -> Self { + let mut rng = rand::rng(); + let now = std::time::Instant::now(); + + let data = moka::sync::Cache::builder() + .max_capacity(MAX_CACHE_SIZE) + .build(); + + for (token, price) in initial_prices { + if let Some(price) = from_normalized_price(price) { + let updated_at = Self::random_updated_at(max_age, now, &mut rng); + data.insert( + token, + CachedResult { + result: Ok(price), + updated_at, + accumulative_errors_count: 0, + }, + ); + } + } + + Self(Arc::new(CacheInner { data, max_age })) + } + + fn max_age(&self) -> Duration { + self.0.max_age + } + + /// Returns a timestamp that is a `percentage` of `max_age` + /// in the past. Clamps to `now` if an underflow occurs. + fn updated_at_percentage(max_age: Duration, now: Instant, percentage: u32) -> Instant { + let percentage = std::cmp::min(percentage, 100); + max_age + // Duration stores secs in u64, so overflow happens at u64::MAX + .checked_mul(percentage) + .and_then(|age| age.checked_div(100)) + .and_then(|age| now.checked_sub(age)) + .unwrap_or(now) + } + + /// Returns a randomized `updated_at_percentage` timestamp that is 50–90% of + /// `max_age` in the past, to avoid spikes of expired prices all being + /// fetched at once. + fn random_updated_at(max_age: Duration, now: Instant, rng: &mut impl Rng) -> Instant { + let percent_expired: u32 = rng.random_range(50..=90); + Self::updated_at_percentage(max_age, now, percent_expired) + } + + fn len(&self) -> usize { + // Should never fire since we are bounded with MAX_CACHE_SIZE + usize::try_from(self.0.data.entry_count()).expect("cache size should fit in a usize") + } + + fn get_cached_price( + token: Address, + now: Instant, + cache: &moka::sync::Cache, + max_age: &Duration, + ) -> Option { + let entry = cache.get(&token)?; + let is_recent = now.saturating_duration_since(entry.updated_at) < *max_age; + (is_recent && entry.is_ready()).then_some(entry) + } + + /// Only returns prices that are currently cached. + fn get_cached_prices( + &self, + tokens: &[Address], + ) -> HashMap> { + let now = Instant::now(); + let mut results = HashMap::default(); + for token in tokens { + let cached = Self::get_cached_price(*token, now, &self.0.data, &self.0.max_age); + let label = if cached.is_some() { "hits" } else { "misses" }; + CacheMetrics::get() + .native_price_cache_access + .with_label_values(&[label]) + .inc_by(1); + if let Some(result) = cached { + results.insert(*token, result.result); + } + } + results + } + + fn insert(&self, token: Address, result: CacheEntry) { + self.0 + .data + .entry_by_ref(&token) + .and_upsert_with(|maybe_entry| match maybe_entry { + Some(entry) => { + let mut cached = entry.into_value(); + cached.update(result); + cached + } + None => CachedResult::new(result), + }); + } +} + +/// Wrapper around `Box` which caches successful +/// price estimates for some time. Does not spawn any background tasks. +/// +/// Is an Arc internally. +#[derive(Clone)] +pub struct CachingNativePriceEstimator(Arc); + +struct CachingInner { + estimator: Box, + cache: Cache, + concurrent_requests: usize, + // TODO remove when implementing a less hacky solution + /// Maps a requested token to an approximating token. If the system + /// wants to get the native price for the requested token the native + /// price of the approximating token should be fetched and returned instead. + /// This can be useful for tokens that are hard to route but are pegged to + /// the same underlying asset so approximating their native prices is deemed + /// safe (e.g. csUSDL => Dai). + /// The normalization factor handles decimal differences between tokens. + /// After startup this is a read only value. + approximation_tokens: HashMap, + quote_timeout: Duration, +} + +impl CachingNativePriceEstimator { + pub fn new( + estimator: Box, + cache: Cache, + concurrent_requests: usize, + approximation_tokens: HashMap, + quote_timeout: Duration, + ) -> Self { + let inner = Arc::new(CachingInner { + estimator, + cache, + concurrent_requests, + approximation_tokens, + quote_timeout, + }); + Self(inner) + } + + /// Checks cache for the given tokens one by one. If the price is already + /// cached, it gets returned. If it's not in the cache, a new price + /// estimation request gets issued. We check the cache before each + /// request because they can take a long time and some other task might + /// have fetched some requested price in the meantime. + fn estimate_prices_and_update_cache<'a, I>( + &'a self, + tokens: I, + max_age: Duration, + request_timeout: Duration, + ) -> futures::stream::BoxStream<'a, (Address, NativePriceEstimateResult)> + where + I: IntoIterator, + I::IntoIter: Send + 'a, + { + let estimates = tokens.into_iter().map(move |token| async move { + // check if the price is cached by now + let now = Instant::now(); + if let Some(cached) = + Cache::get_cached_price(token, now, &self.0.cache.0.data, &max_age) + { + return (token, cached.result); + } + + let approximation = self + .0 + .approximation_tokens + .get(&token) + .copied() + .unwrap_or(ApproximationToken::same_decimals(token)); + + let result = self + .0 + .estimator + .estimate_native_price(approximation.address, request_timeout) + .await + .map(|price| approximation.normalize_price(price)); + + // update price in cache + if should_cache(&result) { + self.0.cache.insert(token, result.clone()); + }; + + (token, result) + }); + futures::stream::iter(estimates) + .buffer_unordered(self.0.concurrent_requests) + .boxed() + } + + fn cache(&self) -> &Cache { + &self.0.cache + } + + pub async fn fetch_prices( + &self, + tokens: &[Address], + timeout: Duration, + ) -> HashMap { + let mut prices = self.0.cache.get_cached_prices(tokens); + if timeout.is_zero() { + return prices; + } + + let uncached_tokens: Vec<_> = tokens + .iter() + .filter(|t| !prices.contains_key(*t)) + .copied() + .collect(); + let price_stream = + self.estimate_prices_and_update_cache(uncached_tokens, self.0.cache.max_age(), timeout); + + let _ = time::timeout(timeout, async { + let mut price_stream = price_stream; + + while let Some((token, result)) = price_stream.next().await { + prices.insert(token, result); + } + }) + .await; + + // Return whatever was collected up to that point, regardless of the timeout + prices + } +} + +impl NativePriceEstimating for CachingNativePriceEstimator { + #[instrument(skip_all)] + fn estimate_native_price( + &self, + token: Address, + timeout: Duration, + ) -> futures::future::BoxFuture<'_, NativePriceEstimateResult> { + async move { + let cached = { + let now = Instant::now(); + Cache::get_cached_price(token, now, &self.0.cache.0.data, &self.0.cache.0.max_age) + }; + + let label = if cached.is_some() { "hits" } else { "misses" }; + CacheMetrics::get() + .native_price_cache_access + .with_label_values(&[label]) + .inc_by(1); + + if let Some(cached) = cached { + return cached.result; + } + + self.estimate_prices_and_update_cache([token], self.0.cache.max_age(), timeout) + .next() + .await + .unwrap() + .1 + } + .boxed() + } +} + +/// Background maintenance worker that periodically updates native prices +/// for a set of tokens. Uses a `CachingNativePriceEstimator` for fetching +/// and caching prices. +pub struct NativePriceUpdater { + estimator: CachingNativePriceEstimator, + tokens_to_update: ArcSwap>, +} + +impl NativePriceUpdater { + pub fn new( + estimator: CachingNativePriceEstimator, + update_interval: Duration, + prefetch_time: Duration, + ) -> Arc { + assert!( + estimator.cache().max_age() > prefetch_time, + "price cache prefetch time ({:?}) must be less than max age ({:?})", + prefetch_time, + estimator.cache().max_age(), + ); + + let updater = Arc::new(Self { + estimator, + tokens_to_update: ArcSwap::new(Arc::new(HashSet::new())), + }); + + // Don't keep the updater alive just for the background task + let weak = Arc::downgrade(&updater); + let update_task = async move { + while let Some(updater) = weak.upgrade() { + let now = Instant::now(); + updater.single_update(prefetch_time).await; + drop(updater); + tokio::time::sleep(update_interval.saturating_sub(now.elapsed())).await; + } + } + .instrument(tracing::info_span!("native_price_updater")); + tokio::spawn(update_task); + + updater + } + + /// Replaces the full set of tokens that should be maintained by the + /// background task and fetches their current prices. + pub async fn update_tokens_and_fetch_prices( + &self, + tokens: HashSet
, + timeout: Duration, + ) -> HashMap { + tracing::trace!(?tokens, "update tokens to maintain"); + let token_list: Vec<_> = tokens.iter().copied().collect(); + self.tokens_to_update.store(Arc::new(tokens)); + self.estimator.fetch_prices(&token_list, timeout).await + } + + async fn single_update(&self, prefetch_time: Duration) { + let metrics = UpdaterMetrics::get(); + let cache = self.estimator.cache(); + + CacheMetrics::get() + .native_price_cache_size + .set(i64::try_from(cache.len()).unwrap_or(i64::MAX)); + + let tokens_to_update = self.tokens_to_update.load_full(); + if tokens_to_update.is_empty() { + return; + } + + let max_age = cache.max_age().saturating_sub(prefetch_time); + let timeout = self.estimator.0.quote_timeout; + + // Pre-filter to only tokens whose cache entries have expired. + let now = Instant::now(); + let expired_tokens: Vec<_> = tokens_to_update + .iter() + .copied() + .filter(|token| Cache::get_cached_price(*token, now, &cache.0.data, &max_age).is_none()) + .collect(); + + // Process expired tokens in chunks, waiting for each chunk to complete + // before starting the next. This ensures all tokens in a chunk reach + // the BufferedRequest channel simultaneously, producing full CoinGecko + // API batches instead of trickling tokens one-by-one. Normally it's + // better to just pass the whole vector to `estimate_prices_and_update_cache` + // and let it handle the chunking, but in this case we want to ensure that all + // tokens go in in chunks of 19 to fetch as many tokens from CoinGecko as is + // allowed. We debounce request to CoinGecko to happen once every 100ms + // to build the batches and if we use buffer_unordered deeper in the stack the + // execution will happen faster, but we will build more smaller batches that we + // send to CoinGecko. This happens because we also use estimations from solvers + // which vary in time, so as requests in the buffer_unorderd() stream + // finish, new ones start immediately, tokens "trickle in" and we build smaller + // batches. + let chunk_size = self.estimator.0.concurrent_requests; + for chunk in expired_tokens.chunks(chunk_size) { + self.estimator + .estimate_prices_and_update_cache(chunk.iter().copied(), max_age, timeout) + .for_each(|_| async {}) + .await; + } + + metrics + .native_price_cache_background_updates + .inc_by(expired_tokens.len() as u64); + } +} + +impl NativePriceEstimating for NativePriceUpdater { + fn estimate_native_price( + &self, + token: Address, + timeout: Duration, + ) -> futures::future::BoxFuture<'_, NativePriceEstimateResult> { + self.estimator.estimate_native_price(token, timeout) + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + HEALTHY_PRICE_ESTIMATION_TIME, + PriceEstimationError, + native::{MockNativePriceEstimating, NativePriceEstimating}, + }, + anyhow::anyhow, + futures::FutureExt, + num::ToPrimitive, + rand::{SeedableRng, rngs::StdRng}, + }; + + fn token(u: u64) -> Address { + Address::left_padding_from(&u.to_be_bytes()) + } + + /// Helper to create a CachingNativePriceEstimator with its own Cache + /// (convenience for tests that don't need a separate Cache). + fn create_caching_estimator( + inner: MockNativePriceEstimating, + max_age: Duration, + concurrent_requests: usize, + approximation_tokens: HashMap, + ) -> CachingNativePriceEstimator { + let cache = Cache::new(max_age, Default::default()); + CachingNativePriceEstimator::new( + Box::new(inner), + cache, + concurrent_requests, + approximation_tokens, + HEALTHY_PRICE_ESTIMATION_TIME, + ) + } + + #[tokio::test] + async fn caches_successful_estimates_with_loaded_prices() { + let mut inner = MockNativePriceEstimating::new(); + inner.expect_estimate_native_price().never(); + + const MAX_AGE_SECS: u64 = 600; + let min_age = Duration::from_secs(MAX_AGE_SECS * 49 / 100); + let max_age = Duration::from_secs(MAX_AGE_SECS * 91 / 100); + + let prices = + HashMap::from_iter((0..10).map(|t| (token(t), BigDecimal::try_from(1e18).unwrap()))); + let cache = Cache::new(Duration::from_secs(MAX_AGE_SECS), prices); + let estimator = CachingNativePriceEstimator::new( + Box::new(inner), + cache, + 1, + Default::default(), + HEALTHY_PRICE_ESTIMATION_TIME, + ); + + { + // Check that `updated_at` timestamps are initialized with + // reasonable values. + for (_, value) in &estimator.cache().0.data { + let elapsed = value.updated_at.elapsed(); + assert!(elapsed >= min_age && elapsed <= max_age); + } + } + + for i in 0..10 { + let result = estimator + .estimate_native_price(token(i), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); + } + } + + #[tokio::test] + async fn caches_successful_estimates() { + let mut inner = MockNativePriceEstimating::new(); + inner + .expect_estimate_native_price() + .times(1) + .returning(|_, _| async { Ok(1.0) }.boxed()); + + let estimator = + create_caching_estimator(inner, Duration::from_millis(30), 1, Default::default()); + + for _ in 0..10 { + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); + } + } + + #[tokio::test] + async fn caches_approximated_estimates_use() { + let mut inner = MockNativePriceEstimating::new(); + inner + .expect_estimate_native_price() + .times(1) + .withf(move |t, _| *t == token(0)) + .returning(|_, _| async { Ok(1.0) }.boxed()); + inner + .expect_estimate_native_price() + .times(1) + .withf(move |t, _| *t == token(100)) + .returning(|_, _| async { Ok(100.0) }.boxed()); + inner + .expect_estimate_native_price() + .times(1) + .withf(move |t, _| *t == token(200)) + .returning(|_, _| async { Ok(200.0) }.boxed()); + + let estimator = create_caching_estimator( + inner, + Duration::from_millis(30), + 1, + // set token approximations for tokens 1 and 2 (same decimals) + HashMap::from([ + ( + Address::with_last_byte(1), + ApproximationToken::same_decimals(Address::with_last_byte(100)), + ), + ( + Address::with_last_byte(2), + ApproximationToken::same_decimals(Address::with_last_byte(200)), + ), + ]), + ); + + // no approximation token used for token 0 + assert_eq!( + estimator + .estimate_native_price(Address::with_last_byte(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap() + .to_i64() + .unwrap(), + 1 + ); + + // approximation price used for tokens 1 and 2 + assert_eq!( + estimator + .estimate_native_price(Address::with_last_byte(1), HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap() + .to_i64() + .unwrap(), + 100 + ); + assert_eq!( + estimator + .estimate_native_price(Address::with_last_byte(2), HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap() + .to_i64() + .unwrap(), + 200 + ); + } + + #[tokio::test] + async fn approximation_normalizes_when_target_has_more_decimals() { + // Scenario: Token 1 is USDC-like (6 decimals), approximated by DAI-like token + // 100 (18 decimals) Both worth $1, so they're pegged 1:1 in value + let mut inner = MockNativePriceEstimating::new(); + // DAI-like token returns price of 5e-22 ETH per wei (smallest unit) + inner + .expect_estimate_native_price() + .times(1) + .withf(move |t, _| *t == token(100)) + .returning(|_, _| async { Ok(5e-22) }.boxed()); + + // from_decimals=6 (USDC), to_decimals=18 (DAI) + // Normalization factor = 10^(18-6) = 10^12 + // Price should be 5e-22 * 10^12 = 5e-10 ETH per USDC microunit + let estimator = create_caching_estimator( + inner, + Duration::from_millis(30), + 1, + HashMap::from([( + Address::with_last_byte(1), + ApproximationToken::with_normalization((Address::with_last_byte(100), 18), 6), + )]), + ); + + let price = estimator + .estimate_native_price(Address::with_last_byte(1), HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap(); + // 5e-22 * 10^12 = 5e-10 + // Note: small floating point error due to 10^12 not being exactly representable + let expected = 5e-10; + assert!( + (price - expected).abs() / expected < f64::EPSILON, + "price {price} not within relative epsilon of {expected}" + ); + } + + #[tokio::test] + async fn approximation_normalizes_when_target_has_fewer_decimals() { + // Scenario: Token 1 is DAI-like (18 decimals), approximated by USDC-like token + // 100 (6 decimals) Both worth $1, so they're pegged 1:1 in value + let mut inner = MockNativePriceEstimating::new(); + // USDC-like token returns price of 5e-10 ETH per microunit (smallest unit) + inner + .expect_estimate_native_price() + .times(1) + .withf(move |t, _| *t == token(100)) + .returning(|_, _| async { Ok(5e-10) }.boxed()); + + // from_decimals=18 (DAI), to_decimals=6 (USDC) + // Normalization factor = 10^(6-18) = 10^-12 + // Price should be 5e-10 * 10^-12 = 5e-22 ETH per DAI wei + let estimator = create_caching_estimator( + inner, + Duration::from_millis(30), + 1, + HashMap::from([( + Address::with_last_byte(1), + ApproximationToken::with_normalization((Address::with_last_byte(100), 6), 18), + )]), + ); + + let price = estimator + .estimate_native_price(Address::with_last_byte(1), HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap(); + // 5e-10 * 10^-12 = 5e-22 + // Note: small floating point error due to 10^-12 not being exactly + // representable + let expected = 5e-22; + assert!( + (price - expected).abs() / expected < f64::EPSILON, + "price {price} not within relative epsilon of {expected}" + ); + } + + #[tokio::test] + async fn caches_nonrecoverable_failed_estimates() { + let mut inner = MockNativePriceEstimating::new(); + inner + .expect_estimate_native_price() + .times(1) + .returning(|_, _| async { Err(PriceEstimationError::NoLiquidity) }.boxed()); + + let estimator = + create_caching_estimator(inner, Duration::from_millis(30), 1, Default::default()); + + for _ in 0..10 { + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert!(matches!( + result.as_ref().unwrap_err(), + PriceEstimationError::NoLiquidity + )); + } + } + + #[tokio::test] + async fn properly_caches_accumulative_errors() { + let mut inner = MockNativePriceEstimating::new(); + let mut seq = mockall::Sequence::new(); + + // First 3 calls: Return EstimatorInternal error. Increment the errors counter. + inner + .expect_estimate_native_price() + .times(3) + .in_sequence(&mut seq) + .returning(|_, _| { + async { Err(PriceEstimationError::EstimatorInternal(anyhow!("boom"))) }.boxed() + }); + + // Next 1 call: Return Ok(1.0). This resets the errors counter. + inner + .expect_estimate_native_price() + .once() + .in_sequence(&mut seq) + .returning(|_, _| async { Ok(1.0) }.boxed()); + + // Next 2 calls: Return EstimatorInternal error. Start incrementing the errors + // counter from the beginning. + inner + .expect_estimate_native_price() + .times(2) + .in_sequence(&mut seq) + .returning(|_, _| { + async { Err(PriceEstimationError::EstimatorInternal(anyhow!("boom"))) }.boxed() + }); + + // Next call: Return a recoverable error, which doesn't affect the errors + // counter. + inner + .expect_estimate_native_price() + .once() + .in_sequence(&mut seq) + .returning(|_, _| async { Err(PriceEstimationError::RateLimited) }.boxed()); + + // Since the ACCUMULATIVE_ERRORS_THRESHOLD is 5, there are only 3 more calls + // remain. Anything exceeding that must return the cached value. + inner + .expect_estimate_native_price() + .times(3) + .in_sequence(&mut seq) + .returning(|_, _| { + async { Err(PriceEstimationError::EstimatorInternal(anyhow!("boom"))) }.boxed() + }); + + let estimator = + create_caching_estimator(inner, Duration::from_millis(100), 1, Default::default()); + + // First 3 calls: The cache is not used. Counter gets increased. + for _ in 0..3 { + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert!(matches!( + result.as_ref().unwrap_err(), + PriceEstimationError::EstimatorInternal(_) + )); + } + + // Reset the errors counter. + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); + + // Make sure the cached value gets evicted. + tokio::time::sleep(Duration::from_millis(120)).await; + + // Increment the errors counter again. + for _ in 0..2 { + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert!(matches!( + result.as_ref().unwrap_err(), + PriceEstimationError::EstimatorInternal(_) + )); + } + + // Receive a recoverable error, which shouldn't affect the counter. + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert!(matches!( + result.as_ref().unwrap_err(), + PriceEstimationError::RateLimited + )); + + // Make more than expected calls. The cache should be used once the threshold is + // reached. + for _ in 0..(ACCUMULATIVE_ERRORS_THRESHOLD * 2) { + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert!(matches!( + result.as_ref().unwrap_err(), + PriceEstimationError::EstimatorInternal(_) + )); + } + } + + #[tokio::test] + async fn does_not_cache_recoverable_failed_estimates() { + let mut inner = MockNativePriceEstimating::new(); + inner + .expect_estimate_native_price() + .times(10) + .returning(|_, _| async { Err(PriceEstimationError::RateLimited) }.boxed()); + + let estimator = + create_caching_estimator(inner, Duration::from_millis(30), 1, Default::default()); + + for _ in 0..10 { + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert!(matches!( + result.as_ref().unwrap_err(), + PriceEstimationError::RateLimited + )); + } + } + + #[tokio::test] + async fn maintenance_can_limit_update_size_to_n() { + let mut inner = MockNativePriceEstimating::new(); + // first request from user + inner + .expect_estimate_native_price() + .times(1) + .returning(|passed_token, _| { + assert_eq!(passed_token, token(0)); + async { Ok(1.0) }.boxed() + }); + // second request from user + inner + .expect_estimate_native_price() + .times(1) + .returning(|passed_token, _| { + assert_eq!(passed_token, token(1)); + async { Ok(2.0) }.boxed() + }); + // maintenance task updates outdated prices (order is non-deterministic) + inner + .expect_estimate_native_price() + .times(2) + .returning(|passed_token, _| { + let price = if passed_token == token(0) { 3.0 } else { 4.0 }; + async move { Ok(price) }.boxed() + }); + + let cache = Cache::new(Duration::from_millis(30), Default::default()); + let estimator = CachingNativePriceEstimator::new( + Box::new(inner), + cache, + 1, + Default::default(), + HEALTHY_PRICE_ESTIMATION_TIME, + ); + let updater = NativePriceUpdater::new( + estimator.clone(), + Duration::from_millis(50), + Duration::default(), + ); + + // fill cache with 2 different queries + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); + let result = estimator + .estimate_native_price(token(1), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 2); + + // Tell the updater about these tokens + updater + .update_tokens_and_fetch_prices( + [token(0), token(1)].into_iter().collect(), + Duration::ZERO, + ) + .await; + + // wait for maintenance cycle + tokio::time::sleep(Duration::from_millis(60)).await; + + let result = estimator + .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 3); + + let result = estimator + .estimate_native_price(token(1), HEALTHY_PRICE_ESTIMATION_TIME) + .await; + assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 4); + } + + #[tokio::test] + async fn maintenance_can_update_all_old_queries() { + let mut inner = MockNativePriceEstimating::new(); + inner + .expect_estimate_native_price() + .times(10) + .returning(move |_, _| async { Ok(1.0) }.boxed()); + inner + .expect_estimate_native_price() + .times(10) + .returning(move |_, _| async { Ok(2.0) }.boxed()); + + let cache = Cache::new(Duration::from_millis(30), Default::default()); + let estimator = CachingNativePriceEstimator::new( + Box::new(inner), + cache, + 1, + Default::default(), + HEALTHY_PRICE_ESTIMATION_TIME, + ); + let all_tokens: HashSet<_> = (0..10).map(Address::with_last_byte).collect(); + let updater = NativePriceUpdater::new( + estimator.clone(), + Duration::from_millis(50), + Duration::default(), + ); + updater + .update_tokens_and_fetch_prices(all_tokens, Duration::ZERO) + .await; + + let tokens: Vec<_> = (0..10).map(Address::with_last_byte).collect(); + for token in &tokens { + let price = estimator + .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap(); + assert_eq!(price.to_i64().unwrap(), 1); + } + + // wait for maintenance cycle + tokio::time::sleep(Duration::from_millis(60)).await; + + for token in &tokens { + let price = estimator + .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap(); + assert_eq!(price.to_i64().unwrap(), 2); + } + } + + #[tokio::test] + async fn maintenance_can_update_concurrently() { + const WAIT_TIME_MS: u64 = 100; + const BATCH_SIZE: usize = 100; + let mut inner = MockNativePriceEstimating::new(); + inner + .expect_estimate_native_price() + .times(BATCH_SIZE) + .returning(|_, _| async { Ok(1.0) }.boxed()); + inner + .expect_estimate_native_price() + .times(BATCH_SIZE) + .returning(move |_, _| { + async move { + tokio::time::sleep(tokio::time::Duration::from_millis(WAIT_TIME_MS)).await; + Ok(2.0) + } + .boxed() + }); + + let cache = Cache::new(Duration::from_millis(30), Default::default()); + let estimator = CachingNativePriceEstimator::new( + Box::new(inner), + cache, + BATCH_SIZE, + Default::default(), + HEALTHY_PRICE_ESTIMATION_TIME, + ); + let all_tokens: HashSet<_> = (0..BATCH_SIZE as u64) + .map(|u| Address::left_padding_from(&u.to_be_bytes())) + .collect(); + let updater = NativePriceUpdater::new( + estimator.clone(), + Duration::from_millis(50), + Duration::default(), + ); + updater + .update_tokens_and_fetch_prices(all_tokens, Duration::ZERO) + .await; + + let tokens: Vec<_> = (0..BATCH_SIZE as u64).map(token).collect(); + for token in &tokens { + let price = estimator + .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap(); + assert_eq!(price.to_i64().unwrap(), 1); + } + + // wait for maintenance cycle + tokio::time::sleep(Duration::from_millis(60 + WAIT_TIME_MS)).await; + + for token in &tokens { + let price = estimator + .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) + .await + .unwrap(); + assert_eq!(price.to_i64().unwrap(), 2); + } + } + + #[test] + fn should_cache_filters_custom_solver_errors() { + let custom_errors = [ + PriceEstimationError::TradingOutsideAllowedWindow { + message: "window".to_string(), + }, + PriceEstimationError::TokenTemporarilySuspended { + message: "suspended".to_string(), + }, + PriceEstimationError::InsufficientLiquidity { + message: "insufficient".to_string(), + }, + PriceEstimationError::CustomSolverError { + message: "custom".to_string(), + }, + ]; + + for err in &custom_errors { + assert!(!should_cache(&Err(err.clone()))); + } + } + + #[test] + fn should_cache_keeps_expected_entries() { + assert!(should_cache(&Ok(1.0))); + assert!(should_cache(&Err(PriceEstimationError::NoLiquidity))); + assert!(should_cache(&Err(PriceEstimationError::UnsupportedToken { + token: Address::new([0; 20]), + reason: "unsupported".to_string(), + }))); + assert!(should_cache(&Err(PriceEstimationError::EstimatorInternal( + anyhow!("estimator") + )))); + + assert!(!should_cache(&Err(PriceEstimationError::RateLimited))); + assert!(!should_cache(&Err(PriceEstimationError::ProtocolInternal( + anyhow!("protocol") + )))); + } + + #[test] + fn updated_at_percentage_overflow_check() { + let now = Instant::now(); + let age = Duration::MAX; + let updated_at = Cache::updated_at_percentage(age, now, 90); + assert_eq!(updated_at, now); + } + + #[test] + fn updated_at_percent_edges() { + let now = Instant::now(); + let max_age = Duration::from_secs(600); + let cases = [ + (0, now), // 0% + (50, now - Duration::from_secs(300)), // 50% + (90, now - Duration::from_secs(540)), // 90% + (100, now - Duration::from_secs(600)), // 100% + ]; + + for (percentage, expected) in cases { + assert_eq!( + Cache::updated_at_percentage(max_age, now, percentage), + expected, + ); + } + } + + #[test] + fn random_updated_at_range() { + let now = Instant::now(); + let max_age = Duration::from_secs(600); + let mut rng = StdRng::seed_from_u64(0); + let min = now - (max_age * 90 / 100); + let max = now - (max_age * 50 / 100); + + for _ in 0..100 { + let updated_at = Cache::random_updated_at(max_age, now, &mut rng); + assert!(updated_at >= min && updated_at <= max); + } + } +} diff --git a/crates/shared/src/price_estimation/sanitized.rs b/crates/price-estimation/src/sanitized.rs similarity index 67% rename from crates/shared/src/price_estimation/sanitized.rs rename to crates/price-estimation/src/sanitized.rs index a8b20b6838..c2c083d479 100644 --- a/crates/shared/src/price_estimation/sanitized.rs +++ b/crates/price-estimation/src/sanitized.rs @@ -1,17 +1,14 @@ use { crate::{ - bad_token::{BadTokenDetecting, TokenQuality}, - price_estimation::{ - Estimate, - PriceEstimating, - PriceEstimationError, - Query, - gas::{GAS_PER_WETH_UNWRAP, GAS_PER_WETH_WRAP}, - }, + Estimate, + PriceEstimating, + PriceEstimationError, + Query, + gas::{GAS_PER_WETH_UNWRAP, GAS_PER_WETH_WRAP, SETTLEMENT_OVERHEAD}, }, alloy::primitives::Address, anyhow::anyhow, - ethrpc::alloy::conversions::IntoAlloy, + bad_tokens::list_based::DenyListedTokens, futures::FutureExt, model::order::BUY_ETH_ADDRESS, std::sync::Arc, @@ -22,32 +19,36 @@ use { /// ETH as buy token appropriately. pub struct SanitizedPriceEstimator { inner: Arc, - bad_token_detector: Arc, + deny_listed_tokens: DenyListedTokens, native_token: Address, + /// Enables the short-circuiting logic in case the sell and buy tokens are + /// the same + is_estimating_native_price: bool, } impl SanitizedPriceEstimator { pub fn new( inner: Arc, native_token: Address, - bad_token_detector: Arc, + deny_listed_tokens: DenyListedTokens, + is_estimating_native_price: bool, ) -> Self { Self { inner, native_token, - bad_token_detector, + deny_listed_tokens, + is_estimating_native_price, } } /// Checks if the traded tokens are supported by the protocol. - async fn handle_bad_tokens(&self, query: &Query) -> Result<(), PriceEstimationError> { + fn handle_deny_listed_tokens(&self, query: &Query) -> Result<(), PriceEstimationError> { for token in [query.sell_token, query.buy_token] { - match self.bad_token_detector.detect(token).await { - Err(err) => return Err(PriceEstimationError::ProtocolInternal(err)), - Ok(TokenQuality::Bad { reason }) => { - return Err(PriceEstimationError::UnsupportedToken { token, reason }); - } - _ => (), + if self.deny_listed_tokens.contains(&token) { + return Err(PriceEstimationError::UnsupportedToken { + token, + reason: "token is deny listed".to_string(), + }); } } Ok(()) @@ -61,10 +62,11 @@ impl PriceEstimating for SanitizedPriceEstimator { query: Arc, ) -> futures::future::BoxFuture<'_, super::PriceEstimateResult> { async move { - self.handle_bad_tokens(&query).await?; - - // buy_token == sell_token => 1 to 1 conversion - if query.buy_token == query.sell_token { + self.handle_deny_listed_tokens(&query)?; + // When estimating native price the sell token is substituted by + // native one. In that case, the output amount of the price + // estimation can be trivially computed as the same amount as input + if self.is_estimating_native_price && query.buy_token == query.sell_token { let estimation = Estimate { out_amount: query.in_amount.get(), gas: 0, @@ -77,12 +79,11 @@ impl PriceEstimating for SanitizedPriceEstimator { } // sell WETH for ETH => 1 to 1 conversion with cost for unwrapping - if query.sell_token == self.native_token - && query.buy_token == BUY_ETH_ADDRESS.into_alloy() - { + // The resulting gas is the sum of unwrap and the settlement itself + if query.sell_token == self.native_token && query.buy_token == BUY_ETH_ADDRESS { let estimation = Estimate { out_amount: query.in_amount.get(), - gas: GAS_PER_WETH_UNWRAP, + gas: GAS_PER_WETH_UNWRAP + SETTLEMENT_OVERHEAD, solver: Default::default(), verified: true, execution: Default::default(), @@ -92,12 +93,11 @@ impl PriceEstimating for SanitizedPriceEstimator { } // sell ETH for WETH => 1 to 1 conversion with cost for wrapping - if query.sell_token == BUY_ETH_ADDRESS.into_alloy() - && query.buy_token == self.native_token - { + // The resulting gas is the sum of unwrap and the settlement itself + if query.sell_token == BUY_ETH_ADDRESS && query.buy_token == self.native_token { let estimation = Estimate { out_amount: query.in_amount.get(), - gas: GAS_PER_WETH_WRAP, + gas: GAS_PER_WETH_WRAP + SETTLEMENT_OVERHEAD, solver: Default::default(), verified: true, execution: Default::default(), @@ -112,14 +112,12 @@ impl PriceEstimating for SanitizedPriceEstimator { let mut adjusted_query = Query::clone(&*query); let modification = if query.sell_token != self.native_token - && query.buy_token == BUY_ETH_ADDRESS.into_alloy() + && query.buy_token == BUY_ETH_ADDRESS { tracing::debug!(?query, "estimate price for buying native asset"); adjusted_query.buy_token = self.native_token; Some(Modification::AddGas(GAS_PER_WETH_UNWRAP)) - } else if query.sell_token == BUY_ETH_ADDRESS.into_alloy() - && query.buy_token != self.native_token - { + } else if query.sell_token == BUY_ETH_ADDRESS && query.buy_token != self.native_token { tracing::debug!(?query, "estimate price for selling native asset"); adjusted_query.sell_token = self.native_token; Some(Modification::AddGas(GAS_PER_WETH_WRAP)) @@ -154,31 +152,17 @@ impl PriceEstimating for SanitizedPriceEstimator { mod tests { use { super::*, - crate::{ - bad_token::{MockBadTokenDetecting, TokenQuality}, - price_estimation::{HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating}, - }, - alloy::primitives::Address, - ethrpc::alloy::conversions::IntoAlloy, + crate::{HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating}, + alloy::primitives::{Address, U256}, model::order::OrderKind, - number::nonzero::U256 as NonZeroU256, - primitive_types::{H160, U256}, + number::nonzero::NonZeroU256, }; - const BAD_TOKEN: H160 = H160([0x12; 20]); + const BAD_TOKEN: Address = Address::repeat_byte(0x12); #[tokio::test] async fn handles_trivial_estimates_on_its_own() { - let mut bad_token_detector = MockBadTokenDetecting::new(); - bad_token_detector.expect_detect().returning(|token| { - if token == BAD_TOKEN.into_alloy() { - Ok(TokenQuality::Bad { - reason: "Token not supported".into(), - }) - } else { - Ok(TokenQuality::Good) - } - }); + let deny_listed_tokens = DenyListedTokens::new(vec![BAD_TOKEN]); let native_token = Address::with_last_byte(42); @@ -196,7 +180,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 100, solver: Default::default(), verified: false, @@ -210,14 +194,14 @@ mod tests { Query { verification: Default::default(), sell_token: Address::with_last_byte(1), - buy_token: BUY_ETH_ADDRESS.into_alloy(), + buy_token: BUY_ETH_ADDRESS, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Buy, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, //sanitized_estimator will add ETH_UNWRAP_COST to the gas of any //Query with ETH as the buy_token. gas: GAS_PER_WETH_UNWRAP + 100, @@ -231,8 +215,8 @@ mod tests { Query { verification: Default::default(), sell_token: Address::with_last_byte(1), - buy_token: BUY_ETH_ADDRESS.into_alloy(), - in_amount: NonZeroU256::try_from(U256::MAX).unwrap(), + buy_token: BUY_ETH_ADDRESS, + in_amount: NonZeroU256::MAX, kind: OrderKind::Buy, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, @@ -247,7 +231,7 @@ mod tests { ( Query { verification: Default::default(), - sell_token: BUY_ETH_ADDRESS.into_alloy(), + sell_token: BUY_ETH_ADDRESS, buy_token: Address::with_last_byte(1), in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Buy, @@ -255,7 +239,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, //sanitized_estimator will add ETH_WRAP_COST to the gas of any //Query with ETH as the sell_token. gas: GAS_PER_WETH_WRAP + 100, @@ -277,7 +261,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 0, solver: Default::default(), verified: true, @@ -288,15 +272,15 @@ mod tests { ( Query { verification: Default::default(), - sell_token: BUY_ETH_ADDRESS.into_alloy(), - buy_token: BUY_ETH_ADDRESS.into_alloy(), + sell_token: BUY_ETH_ADDRESS, + buy_token: BUY_ETH_ADDRESS, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Sell, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 0, solver: Default::default(), verified: true, @@ -308,16 +292,16 @@ mod tests { Query { verification: Default::default(), sell_token: native_token, - buy_token: BUY_ETH_ADDRESS.into_alloy(), + buy_token: BUY_ETH_ADDRESS, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Sell, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, // Sanitized estimator will report a 1:1 estimate when unwrapping native token. - gas: GAS_PER_WETH_UNWRAP, + gas: GAS_PER_WETH_UNWRAP + SETTLEMENT_OVERHEAD, solver: Default::default(), verified: true, execution: Default::default(), @@ -327,7 +311,7 @@ mod tests { ( Query { verification: Default::default(), - sell_token: BUY_ETH_ADDRESS.into_alloy(), + sell_token: BUY_ETH_ADDRESS, buy_token: native_token, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Sell, @@ -335,9 +319,9 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, // Sanitized estimator will report a 1:1 estimate when wrapping native token. - gas: GAS_PER_WETH_WRAP, + gas: GAS_PER_WETH_WRAP + SETTLEMENT_OVERHEAD, solver: Default::default(), verified: true, execution: Default::default(), @@ -347,7 +331,7 @@ mod tests { ( Query { verification: Default::default(), - sell_token: BAD_TOKEN.into_alloy(), + sell_token: BAD_TOKEN, buy_token: Address::with_last_byte(1), in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Buy, @@ -355,7 +339,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Err(PriceEstimationError::UnsupportedToken { - token: BAD_TOKEN.into_alloy(), + token: BAD_TOKEN, reason: "".to_string(), }), ), @@ -364,14 +348,14 @@ mod tests { Query { verification: Default::default(), sell_token: Address::with_last_byte(1), - buy_token: BAD_TOKEN.into_alloy(), + buy_token: BAD_TOKEN, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Buy, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Err(PriceEstimationError::UnsupportedToken { - token: BAD_TOKEN.into_alloy(), + token: BAD_TOKEN, reason: "".to_string(), }), ), @@ -403,7 +387,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 100, solver: Default::default(), verified: false, @@ -419,7 +403,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 100, solver: Default::default(), verified: false, @@ -435,7 +419,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: u64::MAX, solver: Default::default(), verified: false, @@ -451,7 +435,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 100, solver: Default::default(), verified: false, @@ -460,11 +444,11 @@ mod tests { } .boxed() }); - let sanitized_estimator = SanitizedPriceEstimator { inner: Arc::new(wrapped_estimator), - bad_token_detector: Arc::new(bad_token_detector), + deny_listed_tokens: deny_listed_tokens.clone(), native_token, + is_estimating_native_price: true, }; for (query, expectation) in queries { @@ -479,5 +463,110 @@ mod tests { } } } + + let queries = [ + // Can be estimated by `sanitized_estimator` because `buy_token` and `sell_token` are + // identical. + ( + Query { + verification: Default::default(), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(1), + in_amount: Default::default(), + kind: OrderKind::Sell, + block_dependent: false, + timeout: HEALTHY_PRICE_ESTIMATION_TIME, + }, + Ok(Estimate { + out_amount: U256::ONE, + gas: 100, + solver: Default::default(), + verified: true, + execution: Default::default(), + }), + ), + ( + Query { + verification: Default::default(), + sell_token: native_token, + buy_token: native_token, + in_amount: NonZeroU256::try_from(1).unwrap(), + kind: OrderKind::Sell, + block_dependent: false, + timeout: HEALTHY_PRICE_ESTIMATION_TIME, + }, + Ok(Estimate { + out_amount: U256::ONE, + gas: 100, + solver: Default::default(), + verified: true, + execution: Default::default(), + }), + ), + ]; + + // SanitizedPriceEstimator will simply forward the Query in the sell=buy case + // if it is not calculating native price + let first_forwarded_query = queries[0].0.clone(); + + // SanitizedPriceEstimator will simply forward the Query if sell=buy of native + // token case if it is not calculating the native price + let second_forwarded_query = queries[1].0.clone(); + + let mut wrapped_estimator = MockPriceEstimating::new(); + wrapped_estimator + .expect_estimate() + .times(1) + .withf(move |query| **query == first_forwarded_query) + .returning(|_| { + async { + Ok(Estimate { + out_amount: U256::ONE, + gas: 100, + solver: Default::default(), + verified: true, + execution: Default::default(), + }) + } + .boxed() + }); + wrapped_estimator + .expect_estimate() + .times(1) + .withf(move |query| **query == second_forwarded_query) + .returning(|_| { + async { + Ok(Estimate { + out_amount: U256::ONE, + gas: 100, + solver: Default::default(), + verified: true, + execution: Default::default(), + }) + } + .boxed() + }); + + let sanitized_estimator_non_native = SanitizedPriceEstimator { + inner: Arc::new(wrapped_estimator), + deny_listed_tokens, + native_token, + is_estimating_native_price: false, + }; + + for (query, expectation) in queries { + let result = sanitized_estimator_non_native + .estimate(Arc::new(query)) + .await; + match result { + Ok(estimate) => assert_eq!(estimate, expectation.unwrap()), + Err(err) => { + // we only compare the error variant; everything else would be a PITA + let reported_error = std::mem::discriminant(&err); + let expected_error = std::mem::discriminant(&expectation.unwrap_err()); + assert_eq!(reported_error, expected_error); + } + } + } } } diff --git a/crates/shared/src/trade_finding/external.rs b/crates/price-estimation/src/trade_finding/external.rs similarity index 51% rename from crates/shared/src/trade_finding/external.rs rename to crates/price-estimation/src/trade_finding/external.rs index 00da7f7771..211de54382 100644 --- a/crates/shared/src/trade_finding/external.rs +++ b/crates/price-estimation/src/trade_finding/external.rs @@ -2,8 +2,8 @@ use { crate::{ - price_estimation::{PriceEstimationError, Query}, - request_sharing::{BoxRequestSharing, RequestSharing}, + PriceEstimationError, + Query, trade_finding::{ Interaction, LegacyTrade, @@ -15,19 +15,27 @@ use { TradeKind, map_interactions_data, }, + trade_verifier::PriceQuery, }, anyhow::{Context, anyhow}, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, + ethrpc::block_stream::CurrentBlockWatcher, futures::FutureExt, - observe::tracing::tracing_headers, - reqwest::{Client, header}, + observe::tracing::distributed::headers::tracing_headers, + request_sharing::{BoxRequestSharing, RequestSharing}, + reqwest::{Client, StatusCode, header}, tracing::instrument, url::Url, }; +/// Wraps a trade result with the request ID of the HTTP request that produced +/// it, so that consumers reusing a shared in-flight request can identify the +/// original request. +#[derive(Clone)] +struct SharedTradeResponse { + result: Result, + request_id: Option, +} + pub struct ExternalTradeFinder { /// URL to call to in the driver to get a quote with call data for a trade. quote_endpoint: Url, @@ -35,7 +43,7 @@ pub struct ExternalTradeFinder { /// Utility to make sure no 2 identical requests are in-flight at the same /// time. Instead of issuing a duplicated request this awaits the /// response of the in-flight request. - sharing: BoxRequestSharing>, + sharing: BoxRequestSharing, /// Client to issue http requests with. client: Client, @@ -47,7 +55,7 @@ pub struct ExternalTradeFinder { impl ExternalTradeFinder { pub fn new(driver: Url, client: Client, block_stream: CurrentBlockWatcher) -> Self { Self { - quote_endpoint: crate::url::join(&driver, "quote"), + quote_endpoint: crate::utils::join_url(&driver, "quote"), sharing: RequestSharing::labelled(format!("tradefinder_{driver}")), client, block_stream, @@ -59,14 +67,14 @@ impl ExternalTradeFinder { async fn shared_query(&self, query: &Query) -> Result { let fut = move |query: &Query| { let order = dto::Order { - sell_token: query.sell_token.into_legacy(), - buy_token: query.buy_token.into_legacy(), + sell_token: query.sell_token, + buy_token: query.buy_token, amount: query.in_amount.get(), kind: query.kind, deadline: chrono::Utc::now() + query.timeout, }; let block_dependent = query.block_dependent; - let id = observe::distributed_tracing::request_id::from_current_span(); + let id = observe::tracing::distributed::request_id::from_current_span(); let client = self.client.clone(); let quote_endpoint = self.quote_endpoint.clone(); let block_hash = self.block_stream.borrow().hash; @@ -85,39 +93,55 @@ impl ExternalTradeFinder { request = request.header("X-Current-Block-Hash", block_hash.to_string()) } - if let Some(id) = id { - request = request.header("X-REQUEST-ID", id); + if let Some(ref id) = id { + request = request.header("X-REQUEST-ID", id.clone()); } - let response = request - .timeout(timeout) - .send() - .await - .map_err(|err| PriceEstimationError::EstimatorInternal(anyhow!(err)))?; - if response.status() == 429 { - return Err(PriceEstimationError::RateLimited); + let result = async { + let response = request + .timeout(timeout) + .send() + .await + .map_err(|err| PriceEstimationError::EstimatorInternal(anyhow!(err)))?; + if response.status() == StatusCode::TOO_MANY_REQUESTS { + return Err(PriceEstimationError::RateLimited); + } + let text = response + .text() + .await + .map_err(|err| PriceEstimationError::EstimatorInternal(anyhow!(err)))?; + serde_json::from_str::(&text) + .map(TradeKind::from) + .map_err(|err| { + serde_json::from_str::(&text) + .map(PriceEstimationError::from) + .unwrap_or_else(|_| { + PriceEstimationError::EstimatorInternal(anyhow!(err)) + }) + }) + } + .await; + + SharedTradeResponse { + result, + request_id: id, } - let text = response - .text() - .await - .map_err(|err| PriceEstimationError::EstimatorInternal(anyhow!(err)))?; - serde_json::from_str::(&text) - .map(TradeKind::from) - .map_err(|err| { - if let Ok(err) = serde_json::from_str::(&text) { - PriceEstimationError::from(err) - } else { - PriceEstimationError::EstimatorInternal(anyhow!(err)) - } - }) } .boxed() }; - self.sharing - .shared_or_else(query.clone(), fut) - .await - .map_err(TradeError::from) + let shared = self.sharing.shared_or_else(query.clone(), fut); + let is_shared = shared.is_shared; + let response = shared.await; + + if is_shared { + tracing::debug!( + original_request_id = ?response.request_id, + "reusing in-flight quote request" + ); + } + + response.result.map_err(TradeError::from) } } @@ -133,19 +157,19 @@ impl From for TradeKind { impl From for LegacyTrade { fn from(quote: dto::LegacyQuote) -> Self { Self { - out_amount: quote.amount.into_alloy(), + out_amount: quote.amount, gas_estimate: quote.gas, interactions: quote .interactions .into_iter() .map(|interaction| Interaction { - target: interaction.target.into_alloy(), - value: interaction.value.into_alloy(), + target: interaction.target, + value: interaction.value, data: interaction.call_data, }) .collect(), - solver: quote.solver.into_alloy(), - tx_origin: quote.tx_origin.map(IntoAlloy::into_alloy), + solver: quote.solver, + tx_origin: quote.tx_origin, } } } @@ -153,18 +177,14 @@ impl From for LegacyTrade { impl From for Trade { fn from(quote: dto::Quote) -> Self { Self { - clearing_prices: quote - .clearing_prices - .into_iter() - .map(|(k, v)| (k.into_alloy(), v.into_alloy())) - .collect(), + clearing_prices: quote.clearing_prices, gas_estimate: quote.gas, pre_interactions: quote .pre_interactions .into_iter() .map(|interaction| Interaction { - target: interaction.target.into_alloy(), - value: interaction.value.into_alloy(), + target: interaction.target, + value: interaction.value, data: interaction.call_data, }) .collect(), @@ -172,13 +192,13 @@ impl From for Trade { .interactions .into_iter() .map(|interaction| Interaction { - target: interaction.target.into_alloy(), - value: interaction.value.into_alloy(), + target: interaction.target, + value: interaction.value, data: interaction.call_data, }) .collect(), - solver: quote.solver.into_alloy(), - tx_origin: quote.tx_origin.map(IntoAlloy::into_alloy), + solver: quote.solver, + tx_origin: quote.tx_origin, jit_orders: quote.jit_orders, } } @@ -188,6 +208,18 @@ impl From for PriceEstimationError { fn from(value: dto::Error) -> Self { match value.kind.as_str() { "QuotingFailed" => Self::NoLiquidity, + "TradingOutsideAllowedWindow" => Self::TradingOutsideAllowedWindow { + message: value.description, + }, + "TokenTemporarilySuspended" => Self::TokenTemporarilySuspended { + message: value.description, + }, + "InsufficientLiquidity" => Self::InsufficientLiquidity { + message: value.description, + }, + "CustomSolverError" => Self::CustomSolverError { + message: value.description, + }, _ => Self::EstimatorInternal(anyhow!("{}", value.description)), } } @@ -196,13 +228,103 @@ impl From for PriceEstimationError { impl From for Interaction { fn from(interaction: dto::Interaction) -> Self { Self { - target: interaction.target.into_alloy(), - value: interaction.value.into_alloy(), + target: interaction.target, + value: interaction.value, data: interaction.call_data, } } } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn maps_known_custom_error_kinds() { + let cases = [ + ( + "TradingOutsideAllowedWindow", + "window closed", + "TradingOutsideAllowedWindow", + ), + ( + "TokenTemporarilySuspended", + "token suspended", + "TokenTemporarilySuspended", + ), + ( + "InsufficientLiquidity", + "not enough liquidity", + "InsufficientLiquidity", + ), + ( + "CustomSolverError", + "custom solver reason", + "CustomSolverError", + ), + ("QuotingFailed", "ignored", "QuotingFailed"), + ]; + + for (kind, description, expected) in cases { + let error = dto::Error { + kind: kind.to_string(), + description: description.to_string(), + }; + + let mapped = PriceEstimationError::from(error); + match expected { + "TradingOutsideAllowedWindow" => { + assert!(matches!( + mapped, + PriceEstimationError::TradingOutsideAllowedWindow { message } + if message == description + )); + } + "TokenTemporarilySuspended" => { + assert!(matches!( + mapped, + PriceEstimationError::TokenTemporarilySuspended { message } + if message == description + )); + } + "InsufficientLiquidity" => { + assert!(matches!( + mapped, + PriceEstimationError::InsufficientLiquidity { message } + if message == description + )); + } + "CustomSolverError" => { + assert!(matches!( + mapped, + PriceEstimationError::CustomSolverError { message } + if message == description + )); + } + "QuotingFailed" => { + assert!(matches!(mapped, PriceEstimationError::NoLiquidity)); + } + _ => unreachable!(), + } + } + } + + #[test] + fn maps_unknown_error_kind_to_estimator_internal() { + let error = dto::Error { + kind: "SomeFutureKind".to_string(), + description: "driver sent unknown error kind".to_string(), + }; + + let mapped = PriceEstimationError::from(error); + assert!(matches!( + mapped, + PriceEstimationError::EstimatorInternal(err) + if err.to_string() == "driver sent unknown error kind" + )); + } +} + #[async_trait::async_trait] impl TradeFinding for ExternalTradeFinder { #[instrument(skip_all)] @@ -216,19 +338,19 @@ impl TradeFinding for ExternalTradeFinder { .map_err(TradeError::Other)?; Ok(Quote { out_amount: trade - .out_amount( - &query.buy_token, - &query.sell_token, - &query.in_amount.get().into_alloy(), - &query.kind, - ) + .out_amount(&PriceQuery { + sell_token: query.sell_token, + buy_token: query.buy_token, + kind: query.kind, + in_amount: query.in_amount, + }) .map_err(TradeError::Other)?, gas_estimate, solver: trade.solver(), execution: QuoteExecution { - interactions: map_interactions_data(&trade.interactions()), - pre_interactions: map_interactions_data(&trade.pre_interactions()), - jit_orders: trade.jit_orders(), + interactions: map_interactions_data(trade.interactions()), + pre_interactions: map_interactions_data(trade.pre_interactions()), + jit_orders: trade.jit_orders().cloned().collect(), }, }) } @@ -239,11 +361,11 @@ impl TradeFinding for ExternalTradeFinder { } } -pub(crate) mod dto { +pub mod dto { use { + alloy::primitives::{Address, U256}, app_data::AppDataHash, bytes_hex::BytesHex, - ethcontract::{H160, U256}, model::{ order::{BuyTokenDestination, OrderKind, SellTokenSource}, signature::SigningScheme, @@ -258,8 +380,8 @@ pub(crate) mod dto { #[derive(Clone, Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Order { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, #[serde_as(as = "HexOrDecimalU256")] pub amount: U256, pub kind: OrderKind, @@ -281,10 +403,10 @@ pub(crate) mod dto { #[serde_as(as = "HexOrDecimalU256")] pub amount: U256, pub interactions: Vec, - pub solver: H160, + pub solver: Address, pub gas: Option, #[serde(default)] - pub tx_origin: Option, + pub tx_origin: Option
, } #[serde_as] @@ -292,14 +414,14 @@ pub(crate) mod dto { #[serde(rename_all = "camelCase")] pub struct Quote { #[serde_as(as = "HashMap<_, HexOrDecimalU256>")] - pub clearing_prices: HashMap, + pub clearing_prices: HashMap, #[serde(default)] pub pre_interactions: Vec, #[serde(default)] pub interactions: Vec, - pub solver: H160, + pub solver: Address, pub gas: Option, - pub tx_origin: Option, + pub tx_origin: Option
, #[serde(default)] pub jit_orders: Vec, } @@ -308,7 +430,7 @@ pub(crate) mod dto { #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Interaction { - pub target: H160, + pub target: Address, #[serde_as(as = "HexOrDecimalU256")] pub value: U256, #[serde_as(as = "BytesHex")] @@ -319,15 +441,15 @@ pub(crate) mod dto { #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct JitOrder { - pub buy_token: H160, - pub sell_token: H160, + pub buy_token: Address, + pub sell_token: Address, #[serde_as(as = "HexOrDecimalU256")] pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] pub buy_amount: U256, #[serde_as(as = "HexOrDecimalU256")] pub executed_amount: U256, - pub receiver: H160, + pub receiver: Address, pub valid_to: u32, pub app_data: AppDataHash, pub side: Side, diff --git a/crates/shared/src/trade_finding/mod.rs b/crates/price-estimation/src/trade_finding/mod.rs similarity index 52% rename from crates/shared/src/trade_finding/mod.rs rename to crates/price-estimation/src/trade_finding/mod.rs index 540289ddd8..f4f8be4a19 100644 --- a/crates/shared/src/trade_finding/mod.rs +++ b/crates/price-estimation/src/trade_finding/mod.rs @@ -2,20 +2,19 @@ //! for a specified token pair and amount. pub mod external; +pub mod trade_estimator; use { - crate::{ - conversions::U256Ext, - price_estimation::{PriceEstimationError, Query}, - trade_finding::external::dto, - }, + crate::{PriceEstimationError, Query, trade_verifier::PriceQuery}, alloy::primitives::{Address, Bytes, U256}, anyhow::{Context, Result}, derive_more::Debug, + external::dto, model::{interaction::InteractionData, order::OrderKind}, num::CheckedDiv, - number::conversions::alloy::big_rational_to_u256, + number::{conversions::big_rational_to_u256, u256_ext::U256Ext}, serde::{Deserialize, Serialize}, + simulator::encoding::InteractionEncoding, std::{collections::HashMap, ops::Mul}, thiserror::Error, }; @@ -31,11 +30,12 @@ pub trait TradeFinding: Send + Sync + 'static { } /// A quote. -#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[derive(Clone, derive_more::Debug, Default, Eq, PartialEq)] pub struct Quote { pub out_amount: U256, pub gas_estimate: u64, pub solver: Address, + #[debug(ignore)] pub execution: QuoteExecution, } @@ -81,39 +81,43 @@ impl TradeKind { } } - pub fn out_amount( - &self, - buy_token: &Address, - sell_token: &Address, - in_amount: &U256, - order_kind: &OrderKind, - ) -> Result { + pub fn simulation_solver_address(&self) -> Address { + self.tx_origin().unwrap_or(self.solver()) + } + + pub fn out_amount(&self, query: &PriceQuery) -> Result { match self { TradeKind::Legacy(trade) => Ok(trade.out_amount), - TradeKind::Regular(trade) => { - trade.out_amount(buy_token, sell_token, in_amount, order_kind) - } + TradeKind::Regular(trade) => trade.out_amount(query), } } - pub fn interactions(&self) -> Vec { + /// Returns whether the solution contains anything that could + /// actually produce the promised buy tokens. + pub fn has_execution_plan(&self) -> bool { + self.interactions().next().is_some() + || self.jit_orders().next().is_some() + || self.pre_interactions().next().is_some() + } + + pub fn interactions(&self) -> impl std::iter::Iterator { match self { - TradeKind::Legacy(trade) => trade.interactions.clone(), - TradeKind::Regular(trade) => trade.interactions.clone(), + TradeKind::Legacy(trade) => trade.interactions.iter(), + TradeKind::Regular(trade) => trade.interactions.iter(), } } - pub fn pre_interactions(&self) -> Vec { + pub fn pre_interactions(&self) -> impl std::iter::Iterator { match self { - TradeKind::Legacy(_) => Vec::new(), - TradeKind::Regular(trade) => trade.pre_interactions.clone(), + TradeKind::Legacy(_) => [].iter(), + TradeKind::Regular(trade) => trade.pre_interactions.iter(), } } - pub fn jit_orders(&self) -> Vec { + pub fn jit_orders(&self) -> impl std::iter::Iterator { match self { - TradeKind::Legacy(_) => Vec::new(), - TradeKind::Regular(trade) => trade.jit_orders.clone(), + TradeKind::Legacy(_) => [].iter(), + TradeKind::Regular(trade) => trade.jit_orders.iter(), } } } @@ -138,7 +142,7 @@ pub struct LegacyTrade { /// A trade with JIT orders. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Trade { - pub clearing_prices: HashMap, + pub clearing_prices: HashMap, /// How many units of gas this trade will roughly cost. pub gas_estimate: Option, /// The onchain calls to run before sending user funds to the settlement @@ -155,26 +159,20 @@ pub struct Trade { } impl Trade { - pub fn out_amount( - &self, - buy_token: &Address, - sell_token: &Address, - in_amount: &U256, - order_kind: &OrderKind, - ) -> Result { + pub fn out_amount(&self, query: &PriceQuery) -> Result { let sell_price = self .clearing_prices - .get(sell_token) + .get(&query.sell_token) .context("clearing sell price missing")? .to_big_rational(); let buy_price = self .clearing_prices - .get(buy_token) + .get(&query.buy_token) .context("clearing buy price missing")? .to_big_rational(); - let order_amount = in_amount.to_big_rational(); + let order_amount = query.in_amount.get().to_big_rational(); - let out_amount = match order_kind { + let out_amount = match &query.kind { OrderKind::Sell => order_amount .mul(&sell_price) .checked_div(&buy_price) @@ -200,14 +198,6 @@ pub struct Interaction { } impl Interaction { - pub fn encode(&self) -> EncodedInteraction { - ( - self.target, - self.value, - Bytes::copy_from_slice(self.data.as_slice()), - ) - } - pub fn to_interaction_data(&self) -> InteractionData { InteractionData { target: self.target, @@ -217,6 +207,16 @@ impl Interaction { } } +impl InteractionEncoding for Interaction { + fn encode(&self) -> simulator::encoding::EncodedInteraction { + ( + self.target, + self.value, + Bytes::copy_from_slice(self.data.as_slice()), + ) + } +} + impl From for Interaction { fn from(interaction: InteractionData) -> Self { Self { @@ -227,7 +227,15 @@ impl From for Interaction { } } -pub type EncodedInteraction = (Address, U256, Bytes); +impl From for simulator::encoding::Interaction { + fn from(interaction: Interaction) -> Self { + Self { + target: interaction.target, + value: interaction.value, + data: interaction.data, + } + } +} #[derive(Debug, Error)] pub enum TradeError { @@ -243,6 +251,23 @@ pub enum TradeError { #[error("Rate limited")] RateLimited, + /// Token can only be traded during specific time windows (e.g. xStocks/Ondo + /// RWA tokens). + #[error("{message}")] + TradingOutsideAllowedWindow { message: String }, + + /// Token is temporarily suspended from trading by the solver. + #[error("{message}")] + TokenTemporarilySuspended { message: String }, + + /// Insufficient liquidity to fill the requested trade size. + #[error("{message}")] + InsufficientLiquidity { message: String }, + + /// Solver returned a custom error that doesn't map to a known variant. + #[error("{message}")] + CustomSolverError { message: String }, + #[error(transparent)] Other(#[from] anyhow::Error), } @@ -258,6 +283,18 @@ impl From for TradeError { Self::UnsupportedOrderType(format!("{token:#x}")) } PriceEstimationError::RateLimited => Self::RateLimited, + PriceEstimationError::TradingOutsideAllowedWindow { message } => { + Self::TradingOutsideAllowedWindow { message } + } + PriceEstimationError::TokenTemporarilySuspended { message } => { + Self::TokenTemporarilySuspended { message } + } + PriceEstimationError::InsufficientLiquidity { message } => { + Self::InsufficientLiquidity { message } + } + PriceEstimationError::CustomSolverError { message } => { + Self::CustomSolverError { message } + } PriceEstimationError::EstimatorInternal(err) | PriceEstimationError::ProtocolInternal(err) => Self::Other(err), } @@ -273,7 +310,19 @@ impl Clone for TradeError { } Self::DeadlineExceeded => Self::DeadlineExceeded, Self::RateLimited => Self::RateLimited, - Self::Other(err) => Self::Other(crate::clone_anyhow_error(err)), + Self::TradingOutsideAllowedWindow { message } => Self::TradingOutsideAllowedWindow { + message: message.clone(), + }, + Self::TokenTemporarilySuspended { message } => Self::TokenTemporarilySuspended { + message: message.clone(), + }, + Self::InsufficientLiquidity { message } => Self::InsufficientLiquidity { + message: message.clone(), + }, + Self::CustomSolverError { message } => Self::CustomSolverError { + message: message.clone(), + }, + Self::Other(err) => Self::Other(crate::utils::clone_anyhow_error(err)), } } } @@ -282,17 +331,18 @@ pub fn map_interactions(interactions: &[InteractionData]) -> Vec { interactions.iter().cloned().map(Into::into).collect() } -pub fn map_interactions_data(interactions: &[Interaction]) -> Vec { +pub fn map_interactions_data<'a>( + interactions: impl IntoIterator, +) -> Vec { interactions - .iter() - .cloned() + .into_iter() .map(|i| i.to_interaction_data()) .collect() } #[cfg(test)] mod tests { - use super::*; + use {super::*, crate::PriceEstimationError}; #[test] fn test_debug_interaction() { @@ -310,4 +360,88 @@ mod tests { 0x010203040506 }" ) } + + #[test] + fn maps_custom_price_estimation_errors_to_trade_errors() { + let cases = [ + ( + PriceEstimationError::TradingOutsideAllowedWindow { + message: "window".to_string(), + }, + "window", + 0, + ), + ( + PriceEstimationError::TokenTemporarilySuspended { + message: "suspended".to_string(), + }, + "suspended", + 1, + ), + ( + PriceEstimationError::InsufficientLiquidity { + message: "insufficient".to_string(), + }, + "insufficient", + 2, + ), + ( + PriceEstimationError::CustomSolverError { + message: "custom".to_string(), + }, + "custom", + 3, + ), + ]; + + for (input, expected_message, expected_variant) in cases { + let mapped: TradeError = input.into(); + match expected_variant { + 0 => assert!(matches!( + mapped, + TradeError::TradingOutsideAllowedWindow { message } + if message == expected_message + )), + 1 => assert!(matches!( + mapped, + TradeError::TokenTemporarilySuspended { message } + if message == expected_message + )), + 2 => assert!(matches!( + mapped, + TradeError::InsufficientLiquidity { message } + if message == expected_message + )), + 3 => assert!(matches!( + mapped, + TradeError::CustomSolverError { message } + if message == expected_message + )), + _ => unreachable!(), + } + } + } + + #[test] + fn clone_preserves_trade_error_custom_messages() { + let cases = [ + TradeError::TradingOutsideAllowedWindow { + message: "window".to_string(), + }, + TradeError::TokenTemporarilySuspended { + message: "suspended".to_string(), + }, + TradeError::InsufficientLiquidity { + message: "insufficient".to_string(), + }, + TradeError::CustomSolverError { + message: "custom".to_string(), + }, + ]; + + for err in cases { + let cloned = err.clone(); + assert_eq!(cloned.to_string(), err.to_string()); + } + } } diff --git a/crates/shared/src/price_estimation/trade_finder.rs b/crates/price-estimation/src/trade_finding/trade_estimator.rs similarity index 52% rename from crates/shared/src/price_estimation/trade_finder.rs rename to crates/price-estimation/src/trade_finding/trade_estimator.rs index fa1314eca8..27bd9593ec 100644 --- a/crates/shared/src/price_estimation/trade_finder.rs +++ b/crates/price-estimation/src/trade_finding/trade_estimator.rs @@ -2,18 +2,17 @@ //! from an inner `TradeFinding`. use { - super::{ + crate::{ Estimate, PriceEstimateResult, PriceEstimating, PriceEstimationError, Query, rate_limited, + trade_finding::{TradeError, TradeFinding}, trade_verifier::{PriceQuery, TradeVerifying}, }, - crate::trade_finding::{TradeError, TradeFinding}, anyhow::{Result, anyhow}, - ethrpc::alloy::conversions::IntoLegacy, futures::future::FutureExt, rate_limit::RateLimiter, std::sync::Arc, @@ -72,8 +71,8 @@ impl Inner { if let Some(verifier) = &self.verifier { let trade = self.finder.get_trade(&query).await?; let price_query = PriceQuery { - sell_token: query.sell_token.into_legacy(), - buy_token: query.buy_token.into_legacy(), + sell_token: query.sell_token, + buy_token: query.buy_token, in_amount: query.in_amount, kind: query.kind, }; @@ -86,9 +85,9 @@ impl Inner { let quote = self.finder.get_quote(&query).await?; Ok(Estimate { - out_amount: quote.out_amount.into_legacy(), + out_amount: quote.out_amount, gas: quote.gas_estimate, - solver: quote.solver.into_legacy(), + solver: quote.solver, verified: false, execution: quote.execution, }) @@ -109,7 +108,83 @@ impl From for PriceEstimationError { TradeError::UnsupportedOrderType(order_type) => Self::UnsupportedOrderType(order_type), TradeError::DeadlineExceeded => Self::EstimatorInternal(anyhow!("timeout")), TradeError::RateLimited => Self::RateLimited, + TradeError::TradingOutsideAllowedWindow { message } => { + Self::TradingOutsideAllowedWindow { message } + } + TradeError::TokenTemporarilySuspended { message } => { + Self::TokenTemporarilySuspended { message } + } + TradeError::InsufficientLiquidity { message } => { + Self::InsufficientLiquidity { message } + } + TradeError::CustomSolverError { message } => Self::CustomSolverError { message }, TradeError::Other(err) => Self::EstimatorInternal(err), } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn maps_custom_trade_errors_to_price_estimation_errors() { + let cases = [ + ( + TradeError::TradingOutsideAllowedWindow { + message: "window".to_string(), + }, + "window", + 0, + ), + ( + TradeError::TokenTemporarilySuspended { + message: "suspended".to_string(), + }, + "suspended", + 1, + ), + ( + TradeError::InsufficientLiquidity { + message: "insufficient".to_string(), + }, + "insufficient", + 2, + ), + ( + TradeError::CustomSolverError { + message: "custom".to_string(), + }, + "custom", + 3, + ), + ]; + + for (input, expected_message, expected_variant) in cases { + let mapped: PriceEstimationError = input.into(); + match expected_variant { + 0 => assert!(matches!( + mapped, + PriceEstimationError::TradingOutsideAllowedWindow { message } + if message == expected_message + )), + 1 => assert!(matches!( + mapped, + PriceEstimationError::TokenTemporarilySuspended { message } + if message == expected_message + )), + 2 => assert!(matches!( + mapped, + PriceEstimationError::InsufficientLiquidity { message } + if message == expected_message + )), + 3 => assert!(matches!( + mapped, + PriceEstimationError::CustomSolverError { message } + if message == expected_message + )), + _ => unreachable!(), + } + } + } +} diff --git a/crates/price-estimation/src/trade_verifier.rs b/crates/price-estimation/src/trade_verifier.rs new file mode 100644 index 0000000000..c890702ddd --- /dev/null +++ b/crates/price-estimation/src/trade_verifier.rs @@ -0,0 +1,1111 @@ +use { + super::{Estimate, Verification}, + crate::trade_finding::{ + QuoteExecution, + TradeKind, + external::dto::{self, Side}, + map_interactions_data, + }, + ::alloy::sol_types::SolCall, + alloy::primitives::{Address, U256, address, aliases::I512}, + anyhow::{Context, Result}, + bigdecimal::BigDecimal, + contracts::support::Solver, + model::{ + DomainSeparator, + interaction::InteractionData, + order::{BuyTokenDestination, OrderData, OrderKind, SellTokenSource}, + signature::{Signature, SigningScheme}, + }, + num::BigRational, + number::{ + conversions::{ + big_decimal_to_big_rational, + i512_to_big_rational, + i512_to_u256, + u256_to_big_rational, + }, + nonzero::NonZeroU256, + }, + simulator::{ + simulation_builder::{ + self as sim_builder, + AccountOverrideRequest, + EthCallInputs, + ExecutionAmount, + PriceEncoding, + SettlementSimulator, + Solver as SimulationSolver, + }, + tenderly, + }, + std::{ + collections::{HashMap, HashSet}, + sync::Arc, + }, + tracing::instrument, +}; + +#[async_trait::async_trait] +pub trait TradeVerifying: Send + Sync + 'static { + /// Verifies if the proposed [`TradeKind`] actually fulfills the + /// [`PriceQuery`]. + async fn verify( + &self, + query: &PriceQuery, + verification: &Verification, + trade: TradeKind, + ) -> Result; +} + +/// Component that verifies a trade is actually executable by simulating it +/// and determines a price estimate based off of that simulation. +#[derive(Clone)] +pub struct TradeVerifier { + tenderly: Option>, + simulator: SettlementSimulator, + quote_inaccuracy_limit: BigRational, + tokens_without_verification: HashSet
, + min_gas_amount_for_unverified_quotes: u32, + max_gas_amount_for_unverified_quotes: u32, +} + +impl TradeVerifier { + /// Special contract the simulation setup logic can take sell tokens from in + /// case the trader doesn't have enough. + /// We use this **constant** helper contract because computing state + /// overrides to fake balances for a token can be very expensive. If we + /// always have to override the balance of the same account we can + /// compute the necessary state overrides once and cache that. + /// Additionally using a contract means we can expose a function that + /// handles token transfers instead of setting up Erc20 approvals. + /// If you change this value the same constant in `Solver.sol` must be + /// updated as well. + const SPARDOSE: Address = address!("0x1111111111111111111111111111111111111111"); + + pub fn new( + simulator: SettlementSimulator, + tenderly: Option>, + quote_inaccuracy_limit: BigDecimal, + tokens_without_verification: HashSet
, + min_gas_amount_for_unverified_quotes: u32, + max_gas_amount_for_unverified_quotes: u32, + ) -> Self { + assert!( + min_gas_amount_for_unverified_quotes <= max_gas_amount_for_unverified_quotes, + "gas floor ({min_gas_amount_for_unverified_quotes}) exceeds gas ceiling \ + ({max_gas_amount_for_unverified_quotes}) for unverified quotes" + ); + Self { + tenderly, + simulator, + quote_inaccuracy_limit: big_decimal_to_big_rational("e_inaccuracy_limit), + tokens_without_verification, + min_gas_amount_for_unverified_quotes, + max_gas_amount_for_unverified_quotes, + } + } + + async fn verify_inner( + &self, + query: &PriceQuery, + mut verification: Verification, + trade: &TradeKind, + ) -> Result { + let start = std::time::Instant::now(); + let out_amount = trade.out_amount(query)?; + + // if the user does not have their wallet connected we use a random + // address because many tokens revert when transfers involve the 0 address. + if verification.from.is_zero() { + verification.from = Address::random(); + tracing::debug!( + trader = ?verification.from, + "using random trader address with fake balances" + ); + } + + let settle_call = self + .assemble_settle_call(&verification, query, trade) + .await?; + + let summary = self + .generate_execution_report(settle_call, trade, query, &verification) + .await?; + + tracing::debug!( + tokens_lost = ?summary.tokens_lost, + gas_diff = ?trade.gas_estimate().unwrap_or_default().abs_diff(summary.gas_used.saturating_to()), + time = ?start.elapsed(), + promised_out_amount = ?out_amount, + verified_out_amount = ?summary.out_amount, + promised_gas = trade.gas_estimate(), + verified_gas = ?summary.gas_used, + out_diff = ?(I512::from(out_amount) - summary.out_amount).abs(), + ?query, + ?verification, + "verified quote", + ); + + ensure_quote_accuracy(&self.quote_inaccuracy_limit, query, trade, &summary) + } + + /// To understand what's happening during the `settle_call` we need to + /// execute it through a helper contract. This function sets this up, + /// runs the simulation, and returns the resulting report. + async fn generate_execution_report( + &self, + settle_call: EthCallInputs, + trade: &TradeKind, + query: &PriceQuery, + verification: &Verification, + ) -> Result { + // Use `tx_origin` if response indicates that a special address is needed for + // the simulation to pass. Otherwise just use the solver address. + let solver_contract = + Solver::Instance::new(trade.simulation_solver_address(), self.simulator.provider()); + + // `tokens` is passed to `Solver::swap` so it can measure balance changes; + // it is independent of the settlement's token/price vectors. + let tokens: Vec
= match trade { + TradeKind::Legacy(_) => vec![query.sell_token, query.buy_token], + TradeKind::Regular(trade) => trade.clearing_prices.keys().copied().collect(), + }; + + // compute the sell amount the user needs to have (solver sends the difference + // between current balance and required balance from the piggy bank to the + // trader). + let sell_amount = match query.kind { + OrderKind::Sell => query.in_amount.get(), + OrderKind::Buy => trade.out_amount(query)?, + }; + + let swap_call = solver_contract + .swap( + self.simulator.settlement_address(), + tokens.clone(), + *verification.effective_receiver(), + verification.from, + query.sell_token, + sell_amount, + settle_call.to, + settle_call.calldata.clone(), + ) + .from(*solver_contract.address()) + .gas(self.simulator.max_gas_limit()) + .block(settle_call.block.into()) + .state(settle_call.state_overrides.clone()); + + if let Some(tenderly) = &self.tenderly + && let Err(err) = tenderly.log_simulation_command( + swap_call.clone().into_transaction_request(), + settle_call.state_overrides, + settle_call.block.into(), + ) + { + tracing::debug!(?err, "could not log tenderly simulation command"); + } + + let output = swap_call + .call() + .await + .context("failed to simulate quote") + .map_err(Error::SimulationFailed)?; + + let mut summary = SettleOutput::from_swap(output, query.kind, &tokens)?; + + // adjust the reported gas cost since it does not take into account the 21K + // units every tx has to pay and the cost for the calldata. we are + // overcounting the calldata cost slightly since a regular settlement + // would not include the 2 interactions measuring the token balances. + let call_data_cost = settle_call + .calldata + .iter() + .map(|byte| if byte == &0x0 { 4 } else { 16 }) + .sum::(); + summary.gas_used += U256::from(21_000) + U256::from(call_data_cost); + + Self::post_process_summary( + self.simulator.settlement_address(), + summary, + query, + verification, + ) + } + + /// Generates the calldata for the underlying `settle()` call as well as all + /// the required state overrides (user approval, sell_token balance, + /// order signature, etc.). This settle call also has a few tweaks that + /// are specific to the verification aspect: + /// * has 2 additional interactions tracking relevant balances throughout + /// the settlement + /// * order has a limit price that is trivial to achieve (e.g. buy order + /// buys is willing to sell `U256::MAX`, sell order only wants to buy + /// `0`). That way the solver can deliver **less** than promised and we + /// can still measure how much they actually delivered since the + /// simulation will not revert due to limit price violations. + async fn assemble_settle_call( + &self, + verification: &Verification, + query: &PriceQuery, + trade: &TradeKind, + ) -> Result { + // assemble all sub-components that are needed to just simulate + // the proposed trade. + let override_requests = self.prepare_state_overrides(verification, query, trade)?; + let fake_order = self.assemble_fake_order(query, verification, trade)?; + let jit_orders = encode_jit_orders(trade, &self.simulator.domain_separator())?; + + let store_balance = Self::assemble_interaction_for_tracking_balances( + query, + verification, + trade.simulation_solver_address(), + ); + + self + .simulator + .new_simulation_builder() + .with_orders(std::iter::once(fake_order).chain(jit_orders)) + .from_solver(SimulationSolver::OriginUnaltered(trade.simulation_solver_address())) + .presign_orders() + .with_overrides(override_requests) + // the order in which we add interactions is currently quite fragile. + // Each function appends to the interactions and since we want to measure + // user balance as the last thing in the pre-interactions and the first thing + // in the post-interations we first add `store_balance` to the post-interactions + // then we add the order's interactions with `parameters_from_app_data` and + // finally we add the `store_balance` pre-interaction. + .append_post_interactions([store_balance.clone()]) + .parameters_from_app_data(&verification.app_data)? + .append_pre_interactions(map_interactions_data(trade.pre_interactions())) + .append_pre_interactions([store_balance]) + .append_main_interactions(map_interactions_data(trade.interactions())) + .build() + .await + .map_err(Error::FailedToBuildSimulation) + } + + /// Builds an interaction that queries the balances of the relevant account + /// throughout the settlement to figure out how much they actually get from + /// the trade. + /// sell order: track buy token balance of receiver + /// buy order: track sell token balance of trader + fn assemble_interaction_for_tracking_balances( + query: &PriceQuery, + verification: &Verification, + solver: Address, + ) -> InteractionData { + // storeBalance interactions surrounding the settlement to measure the actual + // out_amount + let (tracked_token, tracked_owner) = match query.kind { + OrderKind::Sell => (query.buy_token, *verification.effective_receiver()), + OrderKind::Buy => (query.sell_token, verification.from), + }; + InteractionData { + target: solver, + value: U256::ZERO, + call_data: Solver::Solver::storeBalanceCall { + token: tracked_token, + owner: tracked_owner, + countGas: true, + } + .abi_encode(), + } + } + + /// There are a few edge cases where the flow of the funds appears to be + /// nonsensical when they are actually fine. This functions fixes + /// [`SettleOutput`] for those edge cases: + /// * trader or receiver is the settlement contrat itself + /// * sell_token == buy_token + fn post_process_summary( + settlement_address: Address, + mut summary: SettleOutput, + query: &PriceQuery, + verification: &Verification, + ) -> Result { + // Quote accuracy gets determined by how many tokens had to be paid out of the + // settlement buffers to make the quote happen. When the settlement contract + // itself is the trader or receiver these values need to be adjusted slightly. + let (sell_amount, buy_amount) = match query.kind { + OrderKind::Sell => (I512::from(query.in_amount.get()), summary.out_amount), + OrderKind::Buy => (summary.out_amount, I512::from(query.in_amount.get())), + }; + + // It looks like the contract lost a lot of sell tokens but only because it was + // the trader and had to pay for the trade. Adjust tokens lost downward. + if verification.from == settlement_address { + summary + .tokens_lost + .entry(query.sell_token) + .and_modify(|balance| *balance -= i512_to_big_rational(&sell_amount)); + } + // It looks like the contract gained a lot of buy tokens (negative loss) but + // only because it was the receiver and got the payout. Adjust the tokens lost + // upward. + if verification.receiver == settlement_address { + summary + .tokens_lost + .entry(query.buy_token) + .and_modify(|balance| *balance += i512_to_big_rational(&buy_amount)); + } + + // The swap simulation computes the out_amount like this: + // sell order => receiver_buy_balance_before - receiver_buy_balance_after + // buy_order => trader_sell_balance_after - trader_sell_balance_before + // + // The trade verification assumes that the sell tokens don't flow back into + // the same account. + // However, in case of sell=buy where the receiver is also the owner, this + // assumption is broken. The balance is only ever getting smaller, as the + // trader will always get less tokens out, which causes the above calculations + // to result in 0 or (more likely) negative values. + // + // Example sell order: + // Trader having 1 ETH in their account, selling 0.3 ETH, with tx hooks cost of + // 0.1 ETH: in_amount = 0.3 ETH + // trader_balance_before = 1 ETH + // trader_balance_after = 0.9 ETH + // out_amount = 0.9 ETH - 1 ETH = -0.1 ETH + // The correct out_amount = 0.3 ETH (input) + (-0.1ETH) (out_amount) = 0.2 ETH + // + // Meaning they can sell 0.3 ETH for 0.2 ETH, considering the costs + // + // Example buy order: + // Trader having 1 ETH in their account, buying 1 wei, with tx hooks cost of 0.1 + // ETH in_amount = 1 wei + // trader_balance_before = 1 ETH + // trader_balance_after = 0.9 ETH + // out_amount = 1 ETH - 0.9 ETH = 0.1 ETH + // The correct out_amount = 1 wei (input) + 0.1 ETH (out_amount) = 0.1000...1 + // ETH + // + // Meaning they can buy 1 wei for 0.1ETH + 1 wei, considering the costs + // + // The general formula being: correct_out_amount = query.input + out_amount + let owner_is_receiver = + verification.receiver.is_zero() || verification.receiver == verification.from; + if query.sell_token == query.buy_token && owner_is_receiver { + summary.out_amount = I512::from(query.in_amount.get()) + summary.out_amount; + } else if summary.out_amount < I512::ZERO { + tracing::debug!("Trade out amount is negative"); + return Err(Error::BuffersPayForOrder); + } + + Ok(summary) + } + + /// Builds a fake order that has the expected sell and buy token but has a + /// limit price that is trivial to achieve. We do this to avoid reverts + /// in case the solver promised too much. That way we can still reason + /// about what the user **would** have gotten from this trade. + /// As the limit price we use the amounts reported by the quote. + /// Because a user doesn't provide a signature with their request the + /// generated order will use pre-sign. A valid signature can trivially + /// be faked using state overrides. + fn assemble_fake_order( + &self, + query: &PriceQuery, + verification: &Verification, + trade: &TradeKind, + ) -> Result { + let out_amount = trade.out_amount(query)?; + let (sell_price, buy_price) = match trade { + TradeKind::Legacy(_) => match query.kind { + OrderKind::Sell => (out_amount, query.in_amount.get()), + OrderKind::Buy => (query.in_amount.get(), out_amount), + }, + TradeKind::Regular(trade) => ( + trade + .clearing_prices + .get(&query.sell_token) + .copied() + .unwrap_or(U256::ONE), + trade + .clearing_prices + .get(&query.buy_token) + .copied() + .unwrap_or(U256::ONE), + ), + }; + + let (sell_amount, buy_amount) = match query.kind { + OrderKind::Sell => (query.in_amount, out_amount), + OrderKind::Buy => ( + NonZeroU256::try_from(out_amount).context("computed sell amount is zero")?, + query.in_amount.get(), + ), + }; + + // Set limit amounts to always pass the settlement check so the actual + // out_amount can be measured via the storeBalance interactions. + let (fake_sell_amount, fake_buy_amount) = match query.kind { + OrderKind::Sell => (sell_amount.get(), U256::ZERO), + OrderKind::Buy => (sell_amount.get().max(U256::from(u128::MAX)), buy_amount), + }; + Ok(sim_builder::Order::new(OrderData { + sell_token: query.sell_token, + sell_amount: fake_sell_amount, + buy_token: query.buy_token, + buy_amount: fake_buy_amount, + receiver: Some(*verification.effective_receiver()), + valid_to: u32::MAX, + app_data: Default::default(), + fee_amount: U256::ZERO, + kind: query.kind, + partially_fillable: false, + sell_token_balance: SellTokenSource::Erc20, + buy_token_balance: BuyTokenDestination::Erc20, + }) + .with_signature( + verification.from, + Signature::default_with(SigningScheme::PreSign), + ) + .fill_at( + ExecutionAmount::Full, + PriceEncoding::Custom { + sell_price, + buy_price, + }, + )) + } + + /// Configures all the state overrides that are needed to mock the given + /// trade (approval, sell_token balance, helper contract at solver address, + /// allow listing, ETH balance). + fn prepare_state_overrides( + &self, + verification: &Verification, + query: &PriceQuery, + trade: &TradeKind, + ) -> Result> { + let solver = trade.simulation_solver_address(); + + // Setup the necessary preconditions (sell token balance, vault relayer + // approval) using state overrides. + let needed = match query.kind { + OrderKind::Sell => query.in_amount.get(), + OrderKind::Buy => trade.out_amount(query)?, + }; + + let mut requests = vec![ + // give the required approval on behalf of the trader + AccountOverrideRequest::Approval { + owner: verification.from, + spender: self.simulator.vault_relayer_address(), + amount: needed, + token: query.sell_token, + }, + // Deploy the piggy bank account we can draw sell tokens from + AccountOverrideRequest::Code { + account: Self::SPARDOSE, + code: contracts::support::Spardose::Spardose::DEPLOYED_BYTECODE.clone(), + }, + // Give the piggy bank enough tokens to fund the trader + AccountOverrideRequest::Balance { + holder: Self::SPARDOSE, + token: query.sell_token, + amount: give_slightly_more(needed), + }, + ]; + + // Set up mocked solver with enough ETH to proceed even if the real account + // holds none. + requests.push(AccountOverrideRequest::Code { + account: solver, + code: Solver::Solver::DEPLOYED_BYTECODE.clone(), + }); + // Usually we would require the solver accounts to actually have enough ETH + // to execute the proposed quote. Otherwise we might get many great quotes + // which lead to orders that don't get filled because the solver that can + // settle them actually has no funds. + // However, this is quite rare and there are also smart contract solvers. Those + // contracts basically just manage a list of EOAs that are allowed to submit txs + // on its behalf (similar to our EIP-7702 submission setup). In practice + // it doesn't make sense for smart contract solvers to hold ETH + // as they are not the ones paying for the ETH anyway. So in order to avoid + // teams having to send small amounts of ETH to their contract we fund the + // solver address with ETH during our simulation. + requests.push(AccountOverrideRequest::SufficientEthBalance(solver)); + + // Some solvers are also market makers and quote via their own inventory + // - effectively giving out signed orders swapping tokens directly with the + // user. + // Due to their security policies some don't want to give out signatures that + // could actually be used onchain as those would effectively be free options. + // To still generate verifiable quotes solvers can sign orders that only work + // for a specific `tx.origin` they are sure nobody actually has control over. + // For example they would sign an order that can be executed if the tx is + // executed by account `0x1111..111111`. + // Since such an address is not a registered solver we register it via state + // overrides. + if let Some(custom_origin) = trade.tx_origin() + && custom_origin != trade.solver() + { + requests.push(AccountOverrideRequest::AuthenticateAsSolver(custom_origin)) + } + + Ok(requests) + } +} + +#[async_trait::async_trait] +impl TradeVerifying for TradeVerifier { + #[instrument(skip_all)] + async fn verify( + &self, + query: &PriceQuery, + verification: &Verification, + trade: TradeKind, + ) -> Result { + let out_amount = trade + .out_amount(query) + .context("failed to compute trade out amount")?; + + let unverified_result = trade + .gas_estimate() + .map(|gas| { + let gas = gas.clamp( + self.min_gas_amount_for_unverified_quotes as u64, + self.max_gas_amount_for_unverified_quotes as u64, + ); + + Estimate { + out_amount, + gas, + solver: trade.solver(), + verified: false, + execution: QuoteExecution { + interactions: map_interactions_data(trade.interactions()), + pre_interactions: map_interactions_data(trade.pre_interactions()), + jit_orders: trade.jit_orders().cloned().collect(), + }, + } + }) + .context("solver provided no gas estimate"); + + let skip_verification = [query.buy_token, query.sell_token] + .iter() + .any(|token| self.tokens_without_verification.contains(token)); + if skip_verification { + tracing::debug!(estimate = ?unverified_result, "quote verification skipped"); + return unverified_result; + } + + match self.verify_inner(query, verification.clone(), &trade).await { + Ok(verified) => Ok(verified), + Err(err) => { + // For some tokens it's not possible to provide verifiable calldata in the + // quote (e.g. when they require the use of proprietary APIs which don't give + // out calldata willy nilly). + // + // Since you can't magically make up calldata that makes your quote verifiable + // solvers don't provide any call data in those cases. + // This has 2 possible outcomes: + // 1. the settlement contract has enough buy_tokens to pay for the order => + // Error::BuffersPayForOrder + // 2. not enough buy tokens in buffer => error::SimulationFailure + // + // To make handling of these quotes more predictable we'll only discard + // `Error::BufferPayForOrder` errors if the solver actually tried to provide a + // an execution plan but it's just not correct. In all other cases we just flag + // the solution as unverified but let it pass. + let has_execution_plan = trade.has_execution_plan(); + if has_execution_plan && matches!(err, Error::BuffersPayForOrder) { + tracing::debug!( + has_execution_plan, + "discarding quote because buffers pay for order" + ); + Err(err.into()) + } else { + tracing::debug!(estimate = ?unverified_result, ?err, "quote verification failed"); + unverified_result + } + } + } + } +} + +/// Analyzed output of `Solver::settle` smart contract call. +#[derive(Debug)] +struct SettleOutput { + /// Gas used for the `settle()` call. + gas_used: U256, + /// `out_amount` perceived by the trader (sell token for buy orders or buy + /// token for sell order) + out_amount: alloy::primitives::aliases::I512, + /// Tokens difference of the settlement contract before and after the trade. + tokens_lost: HashMap, +} + +impl SettleOutput { + fn from_swap( + Solver::Solver::swapReturn { + gasUsed, + queriedBalances, + }: Solver::Solver::swapReturn, + kind: OrderKind, + tokens_vec: &[Address], + ) -> Result { + // The balances are stored in the following order: + // [...tokens_before, user_balance_before, user_balance_after, ...tokens_after] + let expected_len = tokens_vec.len() * 2 + 2; + anyhow::ensure!( + queriedBalances.len() == expected_len, + "Solver returned {} balances, expected {} (tokens={})", + queriedBalances.len(), + expected_len, + tokens_vec.len(), + ); + + let mut i = 0; + let mut tokens_lost = HashMap::new(); + // Get settlement contract balances before the trade + for token in tokens_vec.iter() { + // TODO: add alloy support to the numeric functions + let balance_before = u256_to_big_rational(&queriedBalances[i]); + tokens_lost.insert(*token, balance_before); + i += 1; + } + + let trader_balance_before = I512::from(queriedBalances[i]); + let trader_balance_after = I512::from(queriedBalances[i + 1]); + i += 2; + + // Get settlement contract balances after the trade + for token in tokens_vec.iter() { + let balance_after = u256_to_big_rational(&queriedBalances[i]); + tokens_lost + .entry(*token) + .and_modify(|balance_before| *balance_before -= balance_after); + i += 1; + } + + let out_amount = match kind { + // for sell orders we track the buy_token amount which increases during the settlement + OrderKind::Sell => trader_balance_after - trader_balance_before, + // for buy orders we track the sell_token amount which decreases during the settlement + OrderKind::Buy => trader_balance_before - trader_balance_after, + }; + + Ok(SettleOutput { + gas_used: gasUsed, + out_amount, + tokens_lost, + }) + } +} + +/// Returns an error if settling the quote would require using too much of the +/// settlement contract buffers. +fn ensure_quote_accuracy( + inaccuracy_limit: &BigRational, + query: &PriceQuery, + trade: &TradeKind, + summary: &SettleOutput, +) -> std::result::Result { + // amounts verified by the simulation + let (sell_amount, buy_amount) = match query.kind { + OrderKind::Buy => (summary.out_amount, I512::from(query.in_amount.get())), + OrderKind::Sell => (I512::from(query.in_amount.get()), summary.out_amount), + }; + let (sell_amount, buy_amount) = ( + i512_to_big_rational(&sell_amount), + i512_to_big_rational(&buy_amount), + ); + let sell_token_lost_limit = inaccuracy_limit * &sell_amount; + let buy_token_lost_limit = inaccuracy_limit * &buy_amount; + + let sell_token_lost = summary + .tokens_lost + .get(&query.sell_token) + .context("summary sell token is missing")?; + let buy_token_lost = summary + .tokens_lost + .get(&query.buy_token) + .context("summary buy token is missing")?; + + if (*sell_token_lost >= sell_token_lost_limit) || (*buy_token_lost >= buy_token_lost_limit) { + return Err(Error::BuffersPayForOrder); + } + + Ok(Estimate { + out_amount: i512_to_u256(&summary.out_amount)?, + gas: summary.gas_used.saturating_to(), + solver: trade.solver(), + verified: true, + execution: QuoteExecution { + interactions: map_interactions_data(trade.interactions()), + pre_interactions: map_interactions_data(trade.pre_interactions()), + jit_orders: trade.jit_orders().cloned().collect(), + }, + }) +} + +#[derive(Debug)] +pub struct PriceQuery { + pub sell_token: Address, + // This should be `BUY_ETH_ADDRESS` if you actually want to trade `ETH` + pub buy_token: Address, + pub kind: OrderKind, + pub in_amount: NonZeroU256, +} + +fn encode_jit_orders( + trade: &TradeKind, + domain_separator: &DomainSeparator, +) -> Result> { + let TradeKind::Regular(trade) = trade else { + return Ok(vec![]); + }; + + trade + .jit_orders + .iter() + .map(|jit_order| { + let order_data = OrderData { + sell_token: jit_order.sell_token, + buy_token: jit_order.buy_token, + receiver: Some(jit_order.receiver), + sell_amount: jit_order.sell_amount, + buy_amount: jit_order.buy_amount, + valid_to: jit_order.valid_to, + app_data: jit_order.app_data, + fee_amount: U256::ZERO, + kind: match &jit_order.side { + Side::Buy => OrderKind::Buy, + Side::Sell => OrderKind::Sell, + }, + partially_fillable: jit_order.partially_fillable, + sell_token_balance: jit_order.sell_token_source, + buy_token_balance: jit_order.buy_token_destination, + }; + let (owner, signature) = + recover_jit_order_owner(jit_order, &order_data, domain_separator)?; + Ok(sim_builder::Order::new(order_data) + .with_signature(owner, signature) + .fill_at( + ExecutionAmount::Explicit(jit_order.executed_amount), + PriceEncoding::LimitPrice, + )) + }) + .collect::>() +} + +/// Recovers the owner and signature from a `JitOrder`. +fn recover_jit_order_owner( + jit_order: &dto::JitOrder, + order_data: &OrderData, + domain_separator: &DomainSeparator, +) -> Result<(Address, Signature)> { + let (owner, signature) = match jit_order.signing_scheme { + SigningScheme::Eip1271 => { + let (owner, signature) = jit_order.signature.split_at(20); + let owner = Address::from_slice(owner); + let signature = Signature::from_bytes(jit_order.signing_scheme, signature)?; + (owner, signature) + } + SigningScheme::PreSign => { + let owner = Address::from_slice(&jit_order.signature); + let signature = Signature::from_bytes(jit_order.signing_scheme, Vec::new().as_slice())?; + (owner, signature) + } + _ => { + let signature = Signature::from_bytes(jit_order.signing_scheme, &jit_order.signature)?; + let owner = signature + .recover(domain_separator, &order_data.hash_struct())? + .context("could not recover the owner")? + .signer; + (owner, signature) + } + }; + Ok((owner, signature)) +} + +#[derive(thiserror::Error, Debug)] +enum Error { + /// Verification logic ran successfully but the quote was deemed too + /// inaccurate because too many buy tokens came from the settlement + /// contract's buffers. + #[error("buffers pay for order")] + BuffersPayForOrder, + /// Some error caused the simulation to not finish successfully. + #[error("quote could not be simulated")] + SimulationFailed(#[from] anyhow::Error), + #[error("failed to build the verification simuation")] + FailedToBuildSimulation(#[from] simulator::simulation_builder::BuildError), +} + +/// Some tokens accrue interest over time so the balance on block `n+1` +/// would be bigger than on block `n` with the same state override. +/// To not run into race conditions where we compute the state override +/// on one block but run the actual simulation on the next block we give +/// the user 1% (or at least 1 wei in case of rounding issues) more sell +/// tokens to compensate for that. +fn give_slightly_more(needed: U256) -> U256 { + let buffer = std::cmp::max(U256::ONE, needed / U256::from(100u64)); + needed.saturating_add(buffer) +} + +#[cfg(test)] +mod tests { + use {super::*, U256, maplit::hashmap, std::str::FromStr}; + + #[test] + fn spardose_amount_applies_1pct_overshoot() { + assert_eq!( + give_slightly_more(U256::from(1_000_000_000_000_000_000u128)), + U256::from(1_010_000_000_000_000_000u128) + ); + // Amounts below 100 still get at least 1 wei of headroom, so the + // boundary stays covered when integer division would otherwise + // round the 1% buffer to 0. + assert_eq!(give_slightly_more(U256::from(99u64)), U256::from(100u64)); + assert_eq!(give_slightly_more(U256::ONE), U256::from(2u64)); + assert_eq!(give_slightly_more(U256::ZERO), U256::ONE); + // Saturates at U256::MAX instead of overflowing. + assert_eq!(give_slightly_more(U256::MAX), U256::MAX); + } + + #[test] + fn discards_inaccurate_quotes() { + // let's use 0.5 as the base case to avoid rounding issues introduced by float + // conversion + let low_threshold = big_decimal_to_big_rational(&BigDecimal::from_str("0.5").unwrap()); + let high_threshold = big_decimal_to_big_rational(&BigDecimal::from_str("0.51").unwrap()); + + let sell_token = Address::repeat_byte(1); + let buy_token = Address::repeat_byte(2); + + let query = PriceQuery { + in_amount: 1_000.try_into().unwrap(), + kind: OrderKind::Sell, + sell_token, + buy_token, + }; + + // buy token is lost + let tokens_lost = hashmap! { + sell_token => BigRational::from_integer(500.into()), + }; + let summary = SettleOutput { + gas_used: U256::ZERO, + out_amount: I512::try_from(2_000).unwrap(), + tokens_lost, + }; + let estimate = + ensure_quote_accuracy(&low_threshold, &query, &TradeKind::default(), &summary); + assert!(matches!(estimate, Err(Error::SimulationFailed(_)))); + + // sell token is lost + let tokens_lost = hashmap! { + buy_token => BigRational::from_integer(0.into()), + }; + let summary = SettleOutput { + gas_used: U256::ZERO, + out_amount: I512::try_from(2_000).unwrap(), + tokens_lost, + }; + + let estimate = + ensure_quote_accuracy(&low_threshold, &query, &TradeKind::default(), &summary); + assert!(matches!(estimate, Err(Error::SimulationFailed(_)))); + + // everything is in-place + let tokens_lost = hashmap! { + sell_token => BigRational::from_integer(400.into()), + buy_token => BigRational::from_integer(0.into()), + }; + let summary = SettleOutput { + gas_used: U256::ZERO, + out_amount: I512::try_from(2_000).unwrap(), + tokens_lost, + }; + let estimate = + ensure_quote_accuracy(&low_threshold, &query, &TradeKind::default(), &summary); + assert!(estimate.is_ok()); + + let tokens_lost = hashmap! { + sell_token => BigRational::from_integer(500.into()), + buy_token => BigRational::from_integer(0.into()), + }; + + let sell_more = SettleOutput { + gas_used: U256::ZERO, + out_amount: I512::try_from(2_000).unwrap(), + tokens_lost, + }; + + let estimate = + ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &sell_more); + assert!(matches!(estimate, Err(Error::BuffersPayForOrder))); + + // passes with slightly higher tolerance + let estimate = + ensure_quote_accuracy(&high_threshold, &query, &Default::default(), &sell_more); + assert!(estimate.is_ok()); + + let tokens_lost = hashmap! { + sell_token => BigRational::from_integer(0.into()), + buy_token => BigRational::from_integer(1_000.into()), + }; + + let pay_out_more = SettleOutput { + gas_used: U256::ZERO, + out_amount: I512::try_from(2_000).unwrap(), + tokens_lost, + }; + + let estimate = + ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &pay_out_more); + assert!(matches!(estimate, Err(Error::BuffersPayForOrder))); + + // passes with slightly higher tolerance + let estimate = + ensure_quote_accuracy(&high_threshold, &query, &Default::default(), &pay_out_more); + assert!(estimate.is_ok()); + + let tokens_lost = hashmap! { + sell_token => BigRational::from_integer((-500).into()), + buy_token => BigRational::from_integer(0.into()), + }; + + let sell_less = SettleOutput { + gas_used: U256::ZERO, + out_amount: I512::try_from(2_000).unwrap(), + tokens_lost, + }; + // Ending up with surplus in the buffers is always fine + let estimate = + ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &sell_less); + assert!(estimate.is_ok()); + + let tokens_lost = hashmap! { + sell_token => BigRational::from_integer(0.into()), + buy_token => BigRational::from_integer((-1_000).into()), + }; + + let pay_out_less = SettleOutput { + gas_used: U256::ZERO, + out_amount: I512::try_from(2_000).unwrap(), + tokens_lost, + }; + // Ending up with surplus in the buffers is always fine + let estimate = + ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &pay_out_less); + assert!(estimate.is_ok()); + } + + /// Regression test: when the on-chain `Solver` helper returns fewer + /// balance entries than expected (observed for wrapper-bearing orders + /// that revert inside the helper), `from_swap` must return an error + /// instead of panicking with `index out of bounds`. + #[test] + fn from_swap_returns_error_on_short_balances() { + let tokens_vec = vec![Address::repeat_byte(1), Address::repeat_byte(2)]; + // Expected length is `2 * tokens.len() + 2 = 6`. We feed 4, which is + // what the verifier observed in production for a wrapper order. + let swap_return = Solver::Solver::swapReturn { + gasUsed: U256::ZERO, + queriedBalances: vec![U256::ZERO; 4], + }; + let err = SettleOutput::from_swap(swap_return, OrderKind::Sell, &tokens_vec) + .expect_err("from_swap must surface a short response as an error rather than panic"); + let msg = err.to_string(); + assert!(msg.contains("4"), "error must mention actual length: {msg}"); + assert!( + msg.contains("6"), + "error must mention expected length: {msg}" + ); + } + + #[test] + fn from_swap_accepts_expected_length() { + let tokens_vec = vec![Address::repeat_byte(1), Address::repeat_byte(2)]; + let swap_return = Solver::Solver::swapReturn { + gasUsed: U256::ZERO, + queriedBalances: vec![U256::ZERO; 6], + }; + SettleOutput::from_swap(swap_return, OrderKind::Sell, &tokens_vec) + .expect("well-formed response must parse"); + } + + /// Regression test for same sell==buy token verification, which buy orders + /// can now reach via `SameTokensPolicy::Allow` (issue #3963). When the + /// trader is also the receiver the simulated balance only ever shrinks, so + /// `from_swap` reports the *net* change. The `query.in_amount + out_amount` + /// correction must recover the gross amount the trader perceives, for both + /// order kinds. + #[test] + fn post_process_same_token_recovers_gross_amount() { + let token_a = Address::repeat_byte(1); + let token_b = Address::repeat_byte(3); + let trader = Address::repeat_byte(2); + // A settlement address that is neither trader nor receiver, so the + // buffer adjustments stay untouched and we isolate the same-token fix. + let settlement = Address::repeat_byte(0xff); + // Zero receiver means the trader is also the receiver. + let verification = Verification { + from: trader, + receiver: Address::ZERO, + app_data: Default::default(), + }; + let summary = |out_amount: I512| SettleOutput { + gas_used: U256::ZERO, + out_amount, + tokens_lost: hashmap! { token_a => BigRational::from_integer(0.into()) }, + }; + + // Buy 100 of `token` back into the same account: the trader pays 103 + // gross, so the simulation measures a net change of 103 - 100 = 3. The + // correction must report the 103 actually sold. + let buy_query = PriceQuery { + in_amount: 100.try_into().unwrap(), + kind: OrderKind::Buy, + sell_token: token_a, + buy_token: token_a, + }; + let out = TradeVerifier::post_process_summary( + settlement, + summary(I512::try_from(3).unwrap()), + &buy_query, + &verification, + ) + .unwrap(); + assert_eq!(out.out_amount, I512::try_from(103).unwrap()); + + // Sell 100 of `token` back into the same account: the trader nets 98, + // so the simulation measures 98 - 100 = -2. The correction must report + // the 98 actually received. + let sell_query = PriceQuery { + in_amount: 100.try_into().unwrap(), + kind: OrderKind::Sell, + sell_token: token_a, + buy_token: token_a, + }; + let out = TradeVerifier::post_process_summary( + settlement, + summary(I512::ZERO - I512::try_from(2).unwrap()), + &sell_query, + &verification, + ) + .unwrap(); + assert_eq!(out.out_amount, I512::try_from(98).unwrap()); + + // Sanity: with distinct tokens the correction must NOT fire, so a + // negative out amount is still rejected as the buffers paying the order. + let distinct_query = PriceQuery { + in_amount: 100.try_into().unwrap(), + kind: OrderKind::Buy, + sell_token: token_a, + buy_token: token_b, + }; + let err = TradeVerifier::post_process_summary( + settlement, + summary(I512::ZERO - I512::try_from(2).unwrap()), + &distinct_query, + &verification, + ); + assert!(matches!(err, Err(Error::BuffersPayForOrder))); + } +} diff --git a/crates/price-estimation/src/utils/encoding.rs b/crates/price-estimation/src/utils/encoding.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/price-estimation/src/utils/encoding.rs @@ -0,0 +1 @@ + diff --git a/crates/price-estimation/src/utils/http_client_factory.rs b/crates/price-estimation/src/utils/http_client_factory.rs new file mode 100644 index 0000000000..4771a8d48c --- /dev/null +++ b/crates/price-estimation/src/utils/http_client_factory.rs @@ -0,0 +1,52 @@ +use { + reqwest::{Client, ClientBuilder}, + std::time::Duration, +}; + +/// An HTTP client factory. +/// +/// This ensures a common configuration for all our HTTP clients used in various +/// places, while allowing for separate configurations, connection pools, and +/// cookie stores (for things like sessions and default headers) across +/// different APIs. +#[derive(Clone, Debug)] +pub struct HttpClientFactory { + timeout: Duration, +} + +impl HttpClientFactory { + pub fn new(timeout: Duration) -> Self { + Self { timeout } + } + + /// Creates a new HTTP client with the default settings. + pub fn create(&self) -> Client { + self.builder() + .build() + .expect("builder config is not malformed") + } + + /// Creates a new HTTP client, allowing for additional configuration. + pub fn configure(&self, config: impl FnOnce(ClientBuilder) -> ClientBuilder) -> Client { + config(self.builder()) + .build() + .expect("builder config is not malformed") + } + + /// Returns a `ClientBuilder` with the default settings. + pub fn builder(&self) -> ClientBuilder { + const USER_AGENT: &str = "cowprotocol-services/2.0.0"; + ClientBuilder::new() + .timeout(self.timeout) + .tcp_keepalive(Duration::from_secs(60)) + .user_agent(USER_AGENT) + } +} + +impl Default for HttpClientFactory { + fn default() -> Self { + Self { + timeout: Duration::from_secs(10), + } + } +} diff --git a/crates/price-estimation/src/utils/mod.rs b/crates/price-estimation/src/utils/mod.rs new file mode 100644 index 0000000000..3dbb8bc13d --- /dev/null +++ b/crates/price-estimation/src/utils/mod.rs @@ -0,0 +1,49 @@ +//! Module with a few functions duplicated from `shared` in order +//! to break cyclical dependencies and break off this crate. + +use { + std::fmt::{Display, Formatter}, + url::Url, +}; + +pub mod encoding; + +/// Join a path with a URL, ensuring that there is only one slash between them. +/// It doesn't matter if the URL ends with a slash or the path starts with one. +pub fn join_url(url: &Url, mut path: &str) -> Url { + let mut url = url.to_string(); + while url.ends_with('/') { + url.pop(); + } + while path.starts_with('/') { + path = &path[1..] + } + Url::parse(&format!("{url}/{path}")).expect("\"path\" contains a valid path segement") +} + +/// anyhow errors are not clonable natively. This is a workaround that creates a +/// new anyhow error based on formatting the error with its inner sources +/// without backtrace. +pub fn clone_anyhow_error(err: &anyhow::Error) -> anyhow::Error { + anyhow::anyhow!("{:#}", err) +} + +pub fn display_secret_option( + f: &mut Formatter<'_>, + name: &str, + option: Option<&T>, +) -> std::fmt::Result { + display_option(f, name, &option.as_ref().map(|_| "SECRET")) +} + +pub fn display_option( + f: &mut Formatter<'_>, + name: &str, + option: &Option, +) -> std::fmt::Result { + write!(f, "{name}: ")?; + match option { + Some(display) => writeln!(f, "{display}"), + None => writeln!(f, "None"), + } +} diff --git a/crates/rate-limit/Cargo.toml b/crates/rate-limit/Cargo.toml index bea4f42014..ac59c53469 100644 --- a/crates/rate-limit/Cargo.toml +++ b/crates/rate-limit/Cargo.toml @@ -7,15 +7,23 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow = { workspace = true } +configs = { workspace = true } futures = { workspace = true } -humantime = { workspace = true } +humantime-serde = { workspace = true } observe = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } reqwest = { workspace = true, features = ["json"] } +serde = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = [] } tracing = { workspace = true } +[dev-dependencies] +serde_json = { workspace = true } + +[features] +test-util = [] + [lints] workspace = true diff --git a/crates/rate-limit/src/lib.rs b/crates/rate-limit/src/lib.rs index 8534f9e46e..6171bdcac1 100644 --- a/crates/rate-limit/src/lib.rs +++ b/crates/rate-limit/src/lib.rs @@ -1,9 +1,8 @@ use { - anyhow::{Context, Result, ensure}, + anyhow::Result, + configs::rate_limit::Strategy, std::{ - fmt::{Display, Formatter}, future::Future, - str::FromStr, sync::{Arc, Mutex, MutexGuard}, time::{Duration, Instant}, }, @@ -29,84 +28,25 @@ fn metrics() -> &'static Metrics { .expect("unexpected error getting metrics instance") } -#[derive(Debug, Clone)] -pub struct Strategy { - drop_requests_until: Instant, - /// How many requests got rate limited in a row. - times_rate_limited: u64, - back_off_growth_factor: f64, - min_back_off: Duration, - max_back_off: Duration, -} +trait StrategyExt { + /// Resets back off and stops rate limiting requests. + fn response_ok(&mut self, name: &str); -impl Default for Strategy { - fn default() -> Self { - Self::try_new(1.0, Duration::default(), Duration::default()).unwrap() - } -} + /// Calculates back off based on how often we got rate limited in a row. + fn get_current_back_off(&self) -> Duration; -impl Display for Strategy { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "RateLimitingStrategy{{ min_back_off: {:?}, max_back_off: {:?}, growth_factor: {:?} }}", - self.min_back_off, self.max_back_off, self.back_off_growth_factor - ) - } -} + /// Returns updated back off if no other thread increased it in the mean + /// time. + fn response_rate_limited(&mut self, previous_rate_limits: u64, name: &str) -> Option; -impl FromStr for Strategy { - type Err = anyhow::Error; - - fn from_str(config: &str) -> Result { - let mut parts = config.split(','); - let back_off_growth_factor = parts.next().context("missing back_off_growth_factor")?; - let min_back_off = parts.next().context("missing min_back_off")?; - let max_back_off = parts.next().context("missing max_back_off")?; - ensure!( - parts.next().is_none(), - "extraneous rate limiting parameters" - ); - let back_off_growth_factor: f64 = back_off_growth_factor - .parse() - .context("parsing back_off_growth_factor")?; - let min_back_off = - humantime::parse_duration(min_back_off).context("parsing min_back_off")?; - let max_back_off = - humantime::parse_duration(max_back_off).context("parsing max_back_off")?; - Self::try_new(back_off_growth_factor, min_back_off, max_back_off) - } + /// Returns number of times we got rate limited in a row if we are currently + /// allowing requests. + fn times_rate_limited(&self, now: Instant, name: &str) -> Option; } -impl Strategy { - pub fn try_new( - back_off_growth_factor: f64, - min_back_off: Duration, - max_back_off: Duration, - ) -> Result { - ensure!( - back_off_growth_factor.is_normal(), - "back_off_growth_factor must be a normal f64" - ); - ensure!( - back_off_growth_factor >= 1.0, - "back_off_growth_factor needs to be at least 1.0" - ); - ensure!( - min_back_off <= max_back_off, - "min_back_off needs to be <= max_back_off" - ); - Ok(Self { - drop_requests_until: Instant::now(), - times_rate_limited: 0, - back_off_growth_factor, - min_back_off, - max_back_off, - }) - } - +impl StrategyExt for Strategy { /// Resets back off and stops rate limiting requests. - pub fn response_ok(&mut self, name: &str) { + fn response_ok(&mut self, name: &str) { metrics() .successful_requests .with_label_values(&[name]) @@ -129,11 +69,7 @@ impl Strategy { /// Returns updated back off if no other thread increased it in the mean /// time. - pub fn response_rate_limited( - &mut self, - previous_rate_limits: u64, - name: &str, - ) -> Option { + fn response_rate_limited(&mut self, previous_rate_limits: u64, name: &str) -> Option { metrics() .rate_limited_requests .with_label_values(&[name]) @@ -151,7 +87,7 @@ impl Strategy { /// Returns number of times we got rate limited in a row if we are currently /// allowing requests. - pub fn times_rate_limited(&self, now: Instant, name: &str) -> Option { + fn times_rate_limited(&self, now: Instant, name: &str) -> Option { if self.drop_requests_until > now { metrics().requests_dropped.with_label_values(&[name]).inc(); return None; @@ -286,6 +222,20 @@ pub mod back_off { mod tests { use {super::*, futures::FutureExt, std::ops::Add, tokio::time::sleep}; + #[test] + fn serde_roundtrip() { + let strategy = + Strategy::try_new(2.0, Duration::from_millis(100), Duration::from_secs(30)).unwrap(); + let serialized = serde_json::to_string(&strategy).unwrap(); + let deserialized: Strategy = serde_json::from_str(&serialized).unwrap(); + assert_eq!( + strategy.back_off_growth_factor, + deserialized.back_off_growth_factor, + ); + assert_eq!(strategy.min_back_off, deserialized.min_back_off); + assert_eq!(strategy.max_back_off, deserialized.max_back_off); + } + #[test] fn current_back_off_does_not_panic() { let max = Duration::from_secs(60); diff --git a/crates/refunder/Cargo.toml b/crates/refunder/Cargo.toml index a4dcdca595..a08f32eeba 100644 --- a/crates/refunder/Cargo.toml +++ b/crates/refunder/Cargo.toml @@ -10,23 +10,34 @@ alloy = { workspace = true } anyhow = { workspace = true } async-trait = { workspace = true } clap = { workspace = true } +const-hex = { workspace = true } contracts = { workspace = true } database = { workspace = true } ethrpc = { workspace = true } futures = { workspace = true } -gas-estimation = { workspace = true } -const-hex = { workspace = true } +gas-price-estimation = { workspace = true } +http-client = { workspace = true } humantime = { workspace = true } -mimalloc = { workspace = true } +mimalloc = { workspace = true, optional = true } number = { workspace = true } observe = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } shared = { workspace = true } sqlx = { workspace = true } -tokio = { workspace = true, features = ["macros", "time", "rt-multi-thread"] } +tikv-jemallocator = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } tracing = { workspace = true } url = { workspace = true } +[dev-dependencies] +mockall = { workspace = true } +rand = { workspace = true } +rstest = { workspace = true } + +[features] +mimalloc-allocator = ["dep:mimalloc"] +tokio-console = ["observe/tokio-console"] + [lints] workspace = true diff --git a/crates/refunder/src/arguments.rs b/crates/refunder/src/arguments.rs index c2fe82a132..6eb2bba00a 100644 --- a/crates/refunder/src/arguments.rs +++ b/crates/refunder/src/arguments.rs @@ -1,24 +1,52 @@ use { alloy::primitives::Address, clap::Parser, - shared::{arguments::display_option, ethrpc, http_client, logging_args_with_default_filter}, - std::time::Duration, + shared::{arguments::display_option, logging_args_with_default_filter, web3}, + std::{ + fmt::{self, Display, Formatter}, + time::Duration, + }, url::Url, }; logging_args_with_default_filter!(LoggingArguments, "warn,refunder=debug,shared=debug"); +/// Command line arguments for the common HTTP factory. +/// TODO: will be removed after refunder is migrated to `configs` crate. +#[derive(clap::Parser)] +#[group(skip)] +pub struct HttpClientArguments { + /// Default timeout in seconds for http requests. + #[clap( + long, + env, + default_value = "10s", + value_parser = humantime::parse_duration, + )] + pub http_timeout: Duration, +} + +impl Display for HttpClientArguments { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Self { http_timeout } = self; + writeln!(f, "http_timeout: {http_timeout:?}") + } +} + #[derive(Parser)] pub struct Arguments { #[clap(flatten)] - pub http_client: http_client::Arguments, + pub http_client: HttpClientArguments, #[clap(flatten)] - pub ethrpc: ethrpc::Arguments, + pub ethrpc: web3::Arguments, #[clap(flatten)] pub logging: LoggingArguments, + #[clap(flatten)] + pub database_pool: shared::arguments::DatabasePoolConfig, + /// Minimum time in seconds an order must have been valid for /// to be eligible for refunding #[clap( @@ -76,6 +104,10 @@ pub struct Arguments { /// Default is 30 Gwei (30_000_000_000 wei) #[clap(long, env, default_value = "30000000000")] pub start_priority_fee_tip: u64, + + /// Time period in which the service looks for refundable orders. + #[clap(long, env, value_parser = humantime::parse_duration, default_value = "1 week")] + pub lookback_time: Duration, } impl std::fmt::Display for Arguments { @@ -90,15 +122,18 @@ impl std::fmt::Display for Arguments { ethflow_contracts, metrics_port, logging, + database_pool, db_url, refunder_pk, max_gas_price, start_priority_fee_tip, + lookback_time, } = self; write!(f, "{http_client}")?; write!(f, "{ethrpc}")?; write!(f, "{logging}")?; + write!(f, "{database_pool}")?; writeln!(f, "min_validity_duration: {min_validity_duration:?}")?; writeln!(f, "min_price_deviation_bps: {min_price_deviation_bps}")?; let _intentionally_ignored = db_url; @@ -111,6 +146,7 @@ impl std::fmt::Display for Arguments { writeln!(f, "metrics_port: {metrics_port}")?; writeln!(f, "max_gas_price: {max_gas_price}")?; writeln!(f, "start_priority_fee_tip: {start_priority_fee_tip}")?; + writeln!(f, "lookback_time: {lookback_time:?}")?; Ok(()) } } diff --git a/crates/refunder/src/infra/chain.rs b/crates/refunder/src/infra/chain.rs new file mode 100644 index 0000000000..8664e172a8 --- /dev/null +++ b/crates/refunder/src/infra/chain.rs @@ -0,0 +1,64 @@ +//! Blockchain access via Alloy. + +use { + crate::traits::{ChainRead, RefundStatus}, + alloy::{primitives::Address, providers::Provider, rpc::types::TransactionRequest}, + anyhow::{Result, anyhow}, + contracts::CoWSwapEthFlow, + ethrpc::{AlloyProvider, block_stream::timestamp_of_current_block_in_seconds}, + std::collections::HashMap, +}; + +/// [`ChainRead`] implementation using Alloy. +pub struct AlloyChain { + provider: AlloyProvider, + ethflow_contracts: HashMap, +} + +impl AlloyChain { + pub fn new(provider: AlloyProvider, ethflow_addresses: Vec
) -> Self { + let ethflow_contracts = ethflow_addresses + .into_iter() + .map(|addr| { + let instance = CoWSwapEthFlow::Instance::new(addr, provider.clone()); + (addr, instance) + }) + .collect(); + Self { + provider, + ethflow_contracts, + } + } +} + +impl ChainRead for AlloyChain { + async fn current_block_timestamp(&self) -> Result { + timestamp_of_current_block_in_seconds(&self.provider).await + } + + async fn can_receive_eth(&self, address: Address) -> bool { + let tx = TransactionRequest::default() + .to(address) + .value(alloy::primitives::U256::from(1)); + + self.provider.estimate_gas(tx).await.is_ok() + } + + fn ethflow_addresses(&self) -> Vec
{ + self.ethflow_contracts.keys().copied().collect() + } + + async fn get_order_status( + &self, + ethflow_address: Address, + order_hash: alloy::primitives::B256, + ) -> Result { + let contract = self + .ethflow_contracts + .get(ðflow_address) + .ok_or_else(|| anyhow!("Unknown EthFlow contract: {ethflow_address}"))?; + + let order = contract.orders(order_hash).call().await?; + Ok(order.into()) + } +} diff --git a/crates/refunder/src/infra/database.rs b/crates/refunder/src/infra/database.rs new file mode 100644 index 0000000000..92964f395e --- /dev/null +++ b/crates/refunder/src/infra/database.rs @@ -0,0 +1,89 @@ +//! Database access via PostgreSQL. + +use { + crate::traits::DbRead, + alloy::primitives::Address, + anyhow::{Context, Result}, + contracts::CoWSwapEthFlow::EthFlowOrder, + database::{ + OrderUid, + ethflow_orders::{EthOrderPlacement, read_order, refundable_orders}, + orders::read_order as read_db_order, + }, + number::conversions::big_decimal_to_u256, + sqlx::PgPool, + std::time::Duration, +}; + +/// [`DbRead`] implementation using PostgreSQL. +pub struct Postgres { + pool: PgPool, + lookback_time: Option, +} + +impl Postgres { + pub fn new(pool: PgPool, lookback_time: Option) -> Self { + Self { + pool, + lookback_time, + } + } +} + +impl DbRead for Postgres { + async fn get_refundable_orders( + &self, + block_time: i64, + min_validity_duration: i64, + min_price_deviation: f64, + ) -> Result> { + let mut ex = self.pool.acquire().await?; + refundable_orders( + &mut ex, + block_time, + min_validity_duration, + min_price_deviation, + self.lookback_time, + ) + .await + .context("Error while retrieving the refundable ethflow orders from db") + } + + async fn get_ethflow_order_data(&self, uid: &OrderUid) -> Result { + let mut ex = self + .pool + .acquire() + .await + .with_context(|| format!("acquire connection for uid {uid:?}"))?; + let order = read_db_order(&mut ex, uid) + .await + .with_context(|| format!("read order {uid:?}"))? + .with_context(|| format!("missing order {uid:?}"))?; + let ethflow_order = read_order(&mut ex, uid) + .await + .with_context(|| format!("read ethflow order {uid:?}"))? + .with_context(|| format!("missing ethflow order {uid:?}"))?; + + let receiver = order + .receiver + .with_context(|| format!("order {uid:?} missing receiver"))?; + let sell_amount = big_decimal_to_u256(&order.sell_amount) + .with_context(|| format!("order {uid:?} invalid sell_amount"))?; + let buy_amount = big_decimal_to_u256(&order.buy_amount) + .with_context(|| format!("order {uid:?} invalid buy_amount"))?; + let fee_amount = big_decimal_to_u256(&order.fee_amount) + .with_context(|| format!("order {uid:?} invalid fee_amount"))?; + + Ok(EthFlowOrder::Data { + buyToken: Address::from(order.buy_token.0), + receiver: Address::from(receiver.0), + sellAmount: sell_amount, + buyAmount: buy_amount, + appData: order.app_data.0.into(), + feeAmount: fee_amount, + validTo: ethflow_order.valid_to as u32, + partiallyFillable: order.partially_fillable, + quoteId: 0i64, // quoteId is not important for refunding and will be ignored + }) + } +} diff --git a/crates/refunder/src/infra/mod.rs b/crates/refunder/src/infra/mod.rs new file mode 100644 index 0000000000..fc1819c3cf --- /dev/null +++ b/crates/refunder/src/infra/mod.rs @@ -0,0 +1,6 @@ +//! Production implementations of `DbRead`, `ChainRead`, and `ChainWrite`. + +mod chain; +mod database; + +pub use {chain::AlloyChain, database::Postgres}; diff --git a/crates/refunder/src/lib.rs b/crates/refunder/src/lib.rs index ed4f010696..346ced2d3f 100644 --- a/crates/refunder/src/lib.rs +++ b/crates/refunder/src/lib.rs @@ -1,16 +1,27 @@ +//! Automated refunder for expired EthFlow orders. +//! +//! Monitors EthFlow orders and returns ETH to users whose orders expired +//! without filling. Runs every 30 seconds: queries database, validates on-chain +//! status, submits batch refunds. +//! +//! Shares PostgreSQL with orderbook (read-only). Refunds tracked via on-chain +//! events. + pub mod arguments; +pub mod infra; pub mod refund_service; pub mod submitter; +pub mod traits; +// Re-export commonly used types for external consumers (e.g., e2e tests) +pub use traits::RefundStatus; use { crate::arguments::Arguments, - alloy::signers::local::PrivateKeySigner, + alloy::{providers::Provider, signers::local::PrivateKeySigner}, clap::Parser, - contracts::alloy::CoWSwapEthFlow, observe::metrics::LivenessChecking, refund_service::RefundService, - shared::http_client::HttpClientFactory, - sqlx::PgPool, + sqlx::postgres::PgPoolOptions, std::{ sync::{Arc, RwLock}, time::{Duration, Instant}, @@ -28,65 +39,74 @@ pub async fn start(args: impl Iterator) { args.logging.use_json_logs, None, ); - observe::tracing::initialize(&obs_config); + observe::tracing::init::initialize(&obs_config); observe::panic_hook::install(); + #[cfg(unix)] + observe::heap_dump_handler::spawn_heap_dump_handler(); tracing::info!("running refunder with validated arguments:\n{}", args); observe::metrics::setup_registry(Some("refunder".into()), None); run(args).await; } pub async fn run(args: arguments::Arguments) { - let http_factory = HttpClientFactory::new(&args.http_client); - let web3 = shared::ethrpc::web3(&args.ethrpc, &http_factory, &args.node_url, "base"); + // Observability setup + let liveness = Arc::new(Liveness { + last_successful_loop: RwLock::new(Instant::now()), + }); + observe::metrics::serve_metrics( + liveness.clone(), + ([0, 0, 0, 0], args.metrics_port).into(), + Default::default(), + Default::default(), + ); + + // Database initialization + let pg_pool = PgPoolOptions::new() + .max_connections(args.database_pool.db_max_connections.get()) + .connect_lazy(args.db_url.as_str()) + .expect("failed to create database"); + + // Blockchain/RPC setup + let web3 = shared::web3::web3(&args.ethrpc, &args.node_url, "base"); + if let Some(expected_chain_id) = args.chain_id { let chain_id = web3 - .eth() - .chain_id() + .provider + .get_chain_id() .await - .expect("Could not get chainId") - .as_u64(); + .expect("Could not get chainId"); assert_eq!( chain_id, expected_chain_id, "connected to node with incorrect chain ID", ); } - let pg_pool = PgPool::connect_lazy(args.db_url.as_str()).expect("failed to create database"); + // Signer configuration + let signer = args + .refunder_pk + .parse::() + .expect("couldn't parse refunder private key"); - let liveness = Arc::new(Liveness { - // Program will be healthy at the start even if no loop was ran yet. - last_successful_loop: RwLock::new(Instant::now()), - }); - observe::metrics::serve_metrics( - liveness.clone(), - ([0, 0, 0, 0], args.metrics_port).into(), - Default::default(), - Default::default(), - ); + // Service construction + let min_validity_duration = + i64::try_from(args.min_validity_duration.as_secs()).unwrap_or(i64::MAX); - let ethflow_contracts = args - .ethflow_contracts - .iter() - .map(|contract| CoWSwapEthFlow::Instance::new(*contract, web3.alloy.clone())) - .collect(); - let refunder_account = Box::new( - args.refunder_pk - .parse::() - .expect("couldn't parse refunder private key"), - ); - let mut refunder = RefundService::new( + let mut refunder = RefundService::from_components( pg_pool, web3, - ethflow_contracts, - i64::try_from(args.min_validity_duration.as_secs()).unwrap_or(i64::MAX), + args.ethflow_contracts, + min_validity_duration, args.min_price_deviation_bps, - refunder_account, + signer, args.max_gas_price, args.start_priority_fee_tip, + Some(args.lookback_time), ); + + // Main loop loop { - tracing::info!("Staring a new refunding loop"); - match refunder.try_to_refund_all_eligble_orders().await { + tracing::info!("Starting a new refunding loop"); + match refunder.try_to_refund_all_eligible_orders().await { Ok(_) => { track_refunding_loop_result("success"); *liveness.last_successful_loop.write().unwrap() = Instant::now() diff --git a/crates/refunder/src/main.rs b/crates/refunder/src/main.rs index be0bb41fa5..fa29490e76 100644 --- a/crates/refunder/src/main.rs +++ b/crates/refunder/src/main.rs @@ -1,6 +1,11 @@ +#[cfg(feature = "mimalloc-allocator")] #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +#[cfg(not(feature = "mimalloc-allocator"))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + #[tokio::main] async fn main() { refunder::start(std::env::args()).await diff --git a/crates/refunder/src/refund_service.rs b/crates/refunder/src/refund_service.rs index 7391f196ca..1bdeaeba23 100644 --- a/crates/refunder/src/refund_service.rs +++ b/crates/refunder/src/refund_service.rs @@ -1,215 +1,195 @@ +//! Refund eligibility checks and batch submission. + use { - crate::submitter::Submitter, - alloy::{ - network::TxSigner, - primitives::{Address, B256, Signature, address}, - }, - anyhow::{Context, Result, anyhow}, - contracts::alloy::CoWSwapEthFlow, - database::{ - OrderUid, - ethflow_orders::{EthOrderPlacement, read_order, refundable_orders}, - orders::read_order as read_db_order, + crate::{ + infra::{AlloyChain, Postgres}, + submitter::Submitter, + traits::{ChainRead, ChainWrite, DbRead, RefundStatus}, }, - ethrpc::{Web3, block_stream::timestamp_of_current_block_in_seconds}, + alloy::primitives::{Address, B256}, + anyhow::Result, + database::{OrderUid, ethflow_orders::EthOrderPlacement}, futures::{StreamExt, stream}, - number::conversions::alloy::big_decimal_to_u256, - sqlx::PgPool, + gas_price_estimation::eth_node::NodeGasPriceEstimator, std::collections::HashMap, }; -pub const NO_OWNER: Address = Address::ZERO; -pub const INVALIDATED_OWNER: Address = address!("0xffffffffffffffffffffffffffffffffffffffff"); const MAX_NUMBER_OF_UIDS_PER_REFUND_TX: usize = 30; +const BASIS_POINT_DENOMINATOR: f64 = 10_000.0; type CoWSwapEthFlowAddress = Address; -pub struct RefundService { - pub db: PgPool, - pub web3: Web3, - pub ethflow_contracts: Vec, - pub min_validity_duration: i64, - pub min_price_deviation: f64, - pub submitter: Submitter, - pub max_gas_price: u64, - pub start_priority_fee_tip: u64, +/// Extracts the EthFlow contract address from an order if it's in the +/// allowlist. +/// +/// Returns `None` (with a warning log) if the contract is not enabled for +/// refunds. +fn extract_known_ethflow_address( + eth_order_placement: &EthOrderPlacement, + known_ethflow_addresses: &[Address], +) -> Option
{ + let ethflow_contract_address = Address::from_slice(ð_order_placement.uid.0[32..52]); + if known_ethflow_addresses.contains(ðflow_contract_address) { + Some(ethflow_contract_address) + } else { + tracing::warn!( + uid = const_hex::encode_prefixed(eth_order_placement.uid.0), + ethflow = ?ethflow_contract_address, + "refunding orders from specific contract is not enabled", + ); + None + } } -#[derive(Debug, Eq, PartialEq)] -enum RefundStatus { - Refunded, - NotYetRefunded, - Invalid, +/// Queries on-chain refund status for a single order. +/// +/// Returns `None` if the status query fails. Marks orders as `Invalid` if +/// the owner cannot receive ETH. +async fn query_order_refund_status( + chain: &C, + eth_order_placement: &EthOrderPlacement, + ethflow_contract_address: Address, +) -> Option<(OrderUid, RefundStatus, Address)> { + use RefundStatus::*; + let order_hash: [u8; 32] = eth_order_placement.uid.0[0..32] + .try_into() + .expect("order_uid slice with incorrect length"); + + let status = match chain + .get_order_status(ethflow_contract_address, B256::from(order_hash)) + .await + { + Err(err) => { + tracing::error!( + uid =? B256::from(order_hash), + ?err, + "Error while getting the current onchain status of the order" + ); + return None; + } + Ok(NotYetRefunded(owner)) if !chain.can_receive_eth(owner).await => { + tracing::warn!( + uid = const_hex::encode_prefixed(eth_order_placement.uid.0), + ?owner, + "Order owner cannot receive ETH - marking as invalid" + ); + Invalid + } + Ok(other) => other, + }; + + Some((eth_order_placement.uid, status, ethflow_contract_address)) } -impl RefundService { - #[allow(clippy::too_many_arguments)] +/// Filters `refundable_order_uids` by on-chain status, returning only orders +/// that need refund, grouped by EthFlow contract. +/// +/// Excludes orders from unknown contracts, failed status queries, already +/// refunded orders, and owners that can't receive ETH. +async fn identify_uids_refunding_status( + chain: &C, + refundable_order_uids: &[EthOrderPlacement], +) -> HashMap> { + let known_ethflow_addresses = chain.ethflow_addresses(); + + let futures = refundable_order_uids + .iter() + .filter_map(|eth_order_placement| { + let address = + extract_known_ethflow_address(eth_order_placement, &known_ethflow_addresses)?; + Some((eth_order_placement, address)) + }) + .map(|(eth_order_placement, ethflow_contract_address)| { + query_order_refund_status(chain, eth_order_placement, ethflow_contract_address) + }); + + let uid_with_latest_refundablility = futures::future::join_all(futures).await; + let mut to_be_refunded_uids = HashMap::<_, Vec<_>>::new(); + let mut invalid_uids = Vec::new(); + for (uid, status, contract_address) in uid_with_latest_refundablility.into_iter().flatten() { + match status { + RefundStatus::Refunded => (), + RefundStatus::Invalid => invalid_uids.push(uid), + RefundStatus::NotYetRefunded(_) => { + to_be_refunded_uids + .entry(contract_address) + .or_default() + .push(uid); + } + } + } + if !invalid_uids.is_empty() { + // In exceptional cases, e.g. if the refunder tries to refund orders from a + // previous contract, the order_owners could be zero, or the owner cannot + // receive ETH (e.g. EOF contracts or contracts with restrictive receive logic) + tracing::warn!( + "Skipping invalid orders (not created in current contract or owner cannot receive \ + ETH). Uids: {:?}", + invalid_uids + ); + } + to_be_refunded_uids +} + +pub struct RefundService +where + D: DbRead, + CR: ChainRead, + CW: ChainWrite, +{ + pub database: D, + pub chain: CR, + pub submitter: CW, + pub min_validity_duration: i64, + pub min_price_deviation_bps: i64, +} + +impl RefundService +where + D: DbRead, + CR: ChainRead, + CW: ChainWrite, +{ pub fn new( - db: PgPool, - web3: Web3, - ethflow_contracts: Vec, + database: D, + chain: CR, + submitter: CW, min_validity_duration: i64, min_price_deviation_bps: i64, - signer: Box + Send + Sync + 'static>, - max_gas_price: u64, - start_priority_fee_tip: u64, ) -> Self { - let signer_address = signer.address(); - let gas_estimator = Box::new(web3.legacy.clone()); - web3.wallet.register_signer(signer); RefundService { - db, - web3: web3.clone(), - ethflow_contracts, + database, + chain, + submitter, min_validity_duration, - min_price_deviation: min_price_deviation_bps as f64 / 10000f64, - max_gas_price, - start_priority_fee_tip, - submitter: Submitter { - web3, - signer_address, - gas_estimator, - gas_parameters_of_last_tx: None, - nonce_of_last_submission: None, - max_gas_price, - start_priority_fee_tip, - }, + min_price_deviation_bps, } } - pub async fn try_to_refund_all_eligble_orders(&mut self) -> Result<()> { + /// Fetches refundable orders from DB, validates on-chain, and submits batch + /// refunds. Individual failures are logged and skipped. + pub async fn try_to_refund_all_eligible_orders(&mut self) -> Result<()> { let refundable_order_uids = self.get_refundable_ethflow_orders_from_db().await?; - let to_be_refunded_uids = self - .identify_uids_refunding_status_via_web3_calls(refundable_order_uids) - .await; + let to_be_refunded_uids = + identify_uids_refunding_status(&self.chain, &refundable_order_uids).await; self.send_out_refunding_tx(to_be_refunded_uids).await?; Ok(()) } + /// Fetches expired EthFlow orders that haven't been refunded, invalidated, + /// or filled. pub async fn get_refundable_ethflow_orders_from_db(&self) -> Result> { - let block_time = timestamp_of_current_block_in_seconds(&self.web3.alloy).await? as i64; - - let mut ex = self.db.acquire().await?; - refundable_orders( - &mut ex, - block_time, - self.min_validity_duration, - self.min_price_deviation, - ) - .await - .map_err(|err| { - anyhow!( - "Error while retrieving the refundable ethflow orders from db: {:?}", - err - ) - }) - } - - async fn identify_uids_refunding_status_via_web3_calls( - &self, - refundable_order_uids: Vec, - ) -> HashMap> { - let futures = refundable_order_uids - .into_iter() - .filter_map(|eth_order_placement| { - // Owner of the ethflow order is always the ethflow contract itself - let ethflow_contract_address = - Address::from_slice(ð_order_placement.uid.0[32..52]); - let ethflow_contract = self - .ethflow_contracts - .iter() - .find(|contract| *contract.address() == ethflow_contract_address); - if ethflow_contract.is_none() { - tracing::warn!( - uid = const_hex::encode_prefixed(eth_order_placement.uid.0), - ethflow = ?ethflow_contract_address, - "refunding orders from specific contract is not enabled", - ); - } - ethflow_contract.map(|contract| (eth_order_placement, contract)) - }) - .map(|(eth_order_placement, ethflow_contract)| async move { - let order_hash: [u8; 32] = eth_order_placement.uid.0[0..32] - .try_into() - .expect("order_uid slice with incorrect length"); - let order = ethflow_contract.orders(order_hash.into()).call().await; - let order_owner = match order { - Ok(order) => Some(order.owner), - Err(err) => { - tracing::error!( - uid =? B256::from(order_hash), - ?err, - "Error while getting the current onchain status ot the order" - ); - return None; - } - }; - let refund_status = match order_owner { - Some(bytes) if bytes == INVALIDATED_OWNER => RefundStatus::Refunded, - Some(bytes) if bytes == NO_OWNER => RefundStatus::Invalid, - // any other owner - _ => RefundStatus::NotYetRefunded, - }; - Some((eth_order_placement.uid, refund_status, ethflow_contract)) - }); - - let uid_with_latest_refundablility = futures::future::join_all(futures).await; - let mut to_be_refunded_uids = HashMap::<_, Vec<_>>::new(); - let mut invalid_uids = Vec::new(); - for (uid, refund_status, ethflow_contract) in - uid_with_latest_refundablility.into_iter().flatten() - { - match refund_status { - RefundStatus::Refunded => (), - RefundStatus::Invalid => invalid_uids.push(uid), - RefundStatus::NotYetRefunded => { - to_be_refunded_uids - .entry(*ethflow_contract.address()) - .or_default() - .push(uid); - } - } - } - if !invalid_uids.is_empty() { - // In exceptional cases, e.g. if the refunder tries to refund orders from a - // previous contract, the order_owners could be zero - tracing::warn!( - "Trying to invalidate orders that weren't created in the current contract. Uids: \ - {:?}", - invalid_uids - ); - } - to_be_refunded_uids - } + let block_time = self.chain.current_block_timestamp().await? as i64; - async fn get_ethflow_data_from_db( - &self, - uid: &OrderUid, - ) -> Result { - let mut ex = self.db.acquire().await.context("acquire")?; - let order = read_db_order(&mut ex, uid) - .await - .context("read order")? - .context("missing order")?; - let ethflow_order = read_order(&mut ex, uid) + self.database + .get_refundable_orders( + block_time, + self.min_validity_duration, + self.min_price_deviation_bps as f64 / BASIS_POINT_DENOMINATOR, + ) .await - .context("read ethflow order")? - .context("missing ethflow order")?; - - Ok(CoWSwapEthFlow::EthFlowOrder::Data { - buyToken: Address::from(order.buy_token.0), - // ethflow orders have always a receiver. It's enforced by the contract. - receiver: Address::from(order.receiver.unwrap().0), - sellAmount: big_decimal_to_u256(&order.sell_amount).unwrap(), - buyAmount: big_decimal_to_u256(&order.buy_amount).unwrap(), - appData: order.app_data.0.into(), - feeAmount: big_decimal_to_u256(&order.fee_amount).unwrap(), - validTo: ethflow_order.valid_to as u32, - partiallyFillable: order.partially_fillable, - quoteId: 0i64, // quoteId is not important for refunding and will be ignored - }) } async fn send_out_refunding_tx( @@ -229,13 +209,8 @@ impl RefundService { tracing::debug!("Trying to refund the following uids: {:?}", uids); let futures = uids.iter().map(|uid| { - let (uid, self_) = (*uid, &self); - async move { - self_ - .get_ethflow_data_from_db(&uid) - .await - .context(format!("uid {uid:?}")) - } + let (uid, database) = (*uid, &self.database); + async move { database.get_ethflow_order_data(&uid).await } }); let encoded_ethflow_orders: Vec<_> = stream::iter(futures) .buffer_unordered(10) @@ -247,10 +222,849 @@ impl RefundService { .collect() .await; self.submitter - .submit(uids, encoded_ethflow_orders, contract) + .submit_batch(&uids, encoded_ethflow_orders, contract) .await?; } Ok(()) } } + +impl RefundService { + /// Creates a `RefundService` from its (concrete) components. + #[allow(clippy::too_many_arguments)] + pub fn from_components( + db: sqlx::PgPool, + web3: ethrpc::Web3, + ethflow_addresses: Vec
, + min_validity_duration: i64, + min_price_deviation_bps: i64, + signer: alloy::signers::local::PrivateKeySigner, + max_gas_price: u64, + start_priority_fee_tip: u64, + lookback_time: Option, + ) -> Self { + // Database layer + let database = Postgres::new(db, lookback_time); + + // Chain reader + let chain = AlloyChain::new(web3.provider.clone(), ethflow_addresses); + + // Signer/wallet configuration + let signer_address = signer.address(); + web3.wallet.register_signer(signer); + + // Transaction submitter + let gas_estimator = Box::new(NodeGasPriceEstimator::new(web3.provider.clone())); + let submitter = Submitter { + web3, + signer_address, + gas_estimator, + gas_parameters_of_last_tx: None, + nonce_of_last_submission: None, + max_gas_price, + start_priority_fee_tip, + }; + + Self::new( + database, + chain, + submitter, + min_validity_duration, + min_price_deviation_bps, + ) + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::traits::{ + MockChainRead, + MockChainWrite, + MockDbRead, + test::{MockChainReadExt, MockDbReadExt}, + }, + alloy::primitives::Address, + anyhow::anyhow, + contracts::CoWSwapEthFlow::EthFlowOrder, + database::{byte_array::ByteArray, ethflow_orders::EthOrderPlacement}, + rand::random, + rstest::rstest, + std::collections::{HashMap, HashSet}, + }; + + /// Test addresses with semantic meaning for filtering logic. + pub const KNOWN_ETHFLOW: Address = Address::repeat_byte(0x11); + pub const KNOWN_ETHFLOW_2: Address = Address::repeat_byte(0x22); + pub const EOA_OWNER: Address = Address::repeat_byte(0x44); + pub const CONTRACT_REJECTING_ETH: Address = Address::repeat_byte(0x55); + pub const UNKNOWN_ETHFLOW: Address = Address::repeat_byte(0x66); + + /// Asserts the expected number of orders per contract in a grouped result. + /// + /// # Panics + /// Panics if the number of orders for the specified contract does not match + /// the expected count, or if the set of UID suffixes differs. + #[track_caller] + fn assert_orders_by_contract( + result: &HashMap>, + contract: Address, + expected_uid_suffixes: &[u8], + ) { + // Retrieve the order list for the contract (empty slice if missing) + let orders = result.get(&contract).map(|v| v.as_slice()).unwrap_or(&[]); + + // Verify the count + let actual_count = orders.len(); + let expected_count = expected_uid_suffixes.len(); + assert_eq!( + actual_count, expected_count, + "Expected {expected_count} orders for contract {contract}, got {actual_count}" + ); + + // Verify the UID suffixes (order‑independent) + let actual_suffixes: HashSet = orders.iter().map(|uid| uid.0[31]).collect(); + let expected_suffixes: HashSet = expected_uid_suffixes.iter().copied().collect(); + + assert_eq!( + actual_suffixes, expected_suffixes, + "Order uid_suffixes mismatch for contract {contract}" + ); + } + + /// Builds an `EthOrderPlacement` with the given contract address embedded + /// in the UID. + /// + /// # UID Structure (56 bytes total) + /// + /// The CoW Protocol Order UID has the following layout: + /// - Bytes 0-31: Order hash (keccak256 of order data) + /// - Bytes 32-51: Contract address (EthFlow contract that created the + /// order) + /// - Bytes 52-55: Valid-to timestamp (big-endian u32) + /// + /// This function creates a test UID where: + /// - `uid_suffix` is placed at byte 31 (end of order hash) for easy + /// identification + /// - `contract_addr` occupies bytes 32-52 to simulate the EthFlow contract + /// address + /// + /// # Arguments + /// - `uid_suffix`: A byte value placed at position 31 to distinguish test + /// orders + /// - `contract_addr`: The EthFlow contract address to embed in bytes 32-52 + fn create_test_order_placement(uid_suffix: u8, contract_addr: Address) -> EthOrderPlacement { + let mut uid_bytes = [0u8; 56]; + uid_bytes[31] = uid_suffix; + uid_bytes[32..52].copy_from_slice(contract_addr.as_slice()); + EthOrderPlacement { + uid: ByteArray(uid_bytes), + valid_to: 1000, + } + } + + // Tests + + /// Orders with owners that cannot receive ETH are filtered out. + #[rstest] + #[case::eoa_can_receive_eth(EOA_OWNER, true)] + #[case::contract_rejects_eth(CONTRACT_REJECTING_ETH, false)] + #[tokio::test] + async fn test_eth_receivability_filtering(#[case] owner: Address, #[case] can_receive: bool) { + let mut mock_chain = MockChainRead::new(); + + mock_chain + // Configure the known EthFlow contracts so orders from KNOWN_ETHFLOW pass the + // allowlist check + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]) + // All orders report as "not yet refunded" with the parameterized owner address + // This sets up the precondition for testing the ETH receivability check + .with_order_status(RefundStatus::NotYetRefunded(owner)); + + // Return parameterized ETH receivability result to test both EOA (can receive) + // and contract-rejecting-ETH (cannot receive) scenarios + mock_chain + .expect_can_receive_eth() + .withf(move |addr| *addr == owner) + .returning(move |_| can_receive); + + let order = create_test_order_placement(1, KNOWN_ETHFLOW); + let result = identify_uids_refunding_status(&mock_chain, &[order]).await; + + let expected_orders: &[u8] = if can_receive { &[1] } else { &[] }; + assert_orders_by_contract(&result, KNOWN_ETHFLOW, expected_orders); + } + + /// Orders from unknown EthFlow contracts are filtered out. + #[rstest] + #[case::known_contract_included(KNOWN_ETHFLOW)] + #[case::unknown_contract_filtered(UNKNOWN_ETHFLOW)] + #[tokio::test] + async fn test_ethflow_contract_filtering(#[case] contract: Address) { + let mut mock_chain = MockChainRead::new(); + mock_chain + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]) + .with_order_status(RefundStatus::NotYetRefunded(EOA_OWNER)) + .receiving_eth(); + + let order = create_test_order_placement(1, contract); + let result = identify_uids_refunding_status(&mock_chain, &[order]).await; + + let expected_suffixes: &[u8] = if contract == KNOWN_ETHFLOW { &[1] } else { &[] }; + assert_orders_by_contract(&result, contract, expected_suffixes); + } + + /// Orders with non-refundable status or status query errors are excluded. + #[rstest] + #[case::already_refunded(Some(RefundStatus::Refunded))] + #[case::invalid_order(Some(RefundStatus::Invalid))] + #[case::status_query_error(None)] + #[tokio::test] + async fn test_non_refundable_status_excludes_order(#[case] status: Option) { + let mut mock_chain = MockChainRead::new(); + + // Allow the order through the allowlist check + mock_chain.with_ethflow_addresses(vec![KNOWN_ETHFLOW]); + + // Return the parameterized status (Refunded, Invalid, or Error) to verify + // that orders with non-refundable statuses are excluded from the result + mock_chain + .expect_get_order_status() + .returning(move |_, _| status.ok_or(anyhow!("RPC error"))); + + let order = create_test_order_placement(1, KNOWN_ETHFLOW); + let result = identify_uids_refunding_status(&mock_chain, &[order]).await; + + assert!(result.is_empty()); + } + + /// When all orders are already refunded on-chain, the result is empty. + /// + /// This verifies the edge case where no orders need refund, which should + /// result in an empty map (and thus no submission). + #[tokio::test] + async fn test_all_orders_already_refunded() { + let mut mock_chain = MockChainRead::new(); + mock_chain + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]) + .with_order_status(RefundStatus::Refunded); + + let orders: Vec<_> = (1..=5) + .map(|i| create_test_order_placement(i, KNOWN_ETHFLOW)) + .collect(); + + let result = identify_uids_refunding_status(&mock_chain, &orders).await; + + assert!( + result.is_empty(), + "All orders were refunded; result should be empty" + ); + } + + /// A single order is forwarded to the submitter with correct arguments. + #[tokio::test] + async fn test_send_out_refunding_tx_calls_submitter() { + let order = create_test_order_placement(1, KNOWN_ETHFLOW); + let uid = order.uid; + + let mut mock_db = MockDbRead::new(); + mock_db.with_default_ethflow_order_data(); + + let mock_chain = MockChainRead::new(); + + let mut mock_submitter = MockChainWrite::new(); + mock_submitter + .expect_submit_batch() + .times(1) + .withf(|uids, orders, contract| { + uids.len() == 1 && orders.len() == 1 && *contract == KNOWN_ETHFLOW + }) + .returning(|_, _, _| Ok(())); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let mut uids_by_contract = HashMap::new(); + uids_by_contract.insert(KNOWN_ETHFLOW, vec![uid]); + + let result = service.send_out_refunding_tx(uids_by_contract).await; + assert!(result.is_ok()); + } + + /// Empty order map does not trigger any submission. + #[tokio::test] + async fn test_send_out_refunding_tx_empty_map_skips_submission() { + // No expectations needed for DB or chain because empty input short-circuits + // before any DB and chain calls + let mock_db = MockDbRead::new(); + let mock_chain = MockChainRead::new(); + + // Submitter has no expectations: test will fail if submit is called, + // verifying that empty input correctly skips submission + let mock_submitter = MockChainWrite::new(); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let result = service.send_out_refunding_tx(HashMap::new()).await; + assert!(result.is_ok()); + } + + /// Orders are capped at `MAX_NUMBER_OF_UIDS_PER_REFUND_TX` per contract. + #[rstest] + #[case::below_max_no_truncation(29, 29)] + #[case::at_max_no_truncation( + MAX_NUMBER_OF_UIDS_PER_REFUND_TX, + MAX_NUMBER_OF_UIDS_PER_REFUND_TX + )] + #[case::one_above_max_truncates(31, MAX_NUMBER_OF_UIDS_PER_REFUND_TX)] + #[case::above_max_truncates(35, MAX_NUMBER_OF_UIDS_PER_REFUND_TX)] + #[case::double_max_truncates(60, MAX_NUMBER_OF_UIDS_PER_REFUND_TX)] + #[tokio::test] + async fn test_send_out_refunding_tx_order_count_boundary( + #[case] input_count: usize, + #[case] expected_count: usize, + ) { + let mut mock_db = MockDbRead::new(); + mock_db.with_default_ethflow_order_data(); + + let mock_chain = MockChainRead::new(); + + let mut mock_submitter = MockChainWrite::new(); + mock_submitter + .expect_submit_batch() + .times(1) + .withf(move |uids, orders, _| { + uids.len() == expected_count && orders.len() == expected_count + }) + .returning(|_, _, _| Ok(())); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let mut uids_by_contract = HashMap::new(); + let uids = (0..input_count as u8) + .map(|i| create_test_order_placement(i, KNOWN_ETHFLOW).uid) + .collect(); + uids_by_contract.insert(KNOWN_ETHFLOW, uids); + + let result = service.send_out_refunding_tx(uids_by_contract).await; + assert!(result.is_ok()); + } + + /// Orders from multiple contracts trigger separate submissions. + #[tokio::test] + async fn test_send_out_refunding_tx_multiple_contracts() { + let mut mock_db = MockDbRead::new(); + mock_db.with_default_ethflow_order_data(); + + let mock_chain = MockChainRead::new(); + + let mut mock_submitter = MockChainWrite::new(); + + // Expect exactly 2 submissions because orders are grouped by contract, + // and each contract gets its own refund transaction + mock_submitter + .expect_submit_batch() + .times(2) + .returning(|_, _, _| Ok(())); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let uid1 = create_test_order_placement(1, KNOWN_ETHFLOW).uid; + let uid2 = create_test_order_placement(2, KNOWN_ETHFLOW_2).uid; + let mut uids_by_contract = HashMap::new(); + uids_by_contract.insert(KNOWN_ETHFLOW, vec![uid1]); + uids_by_contract.insert(KNOWN_ETHFLOW_2, vec![uid2]); + + let result = service.send_out_refunding_tx(uids_by_contract).await; + assert!(result.is_ok()); + } + + /// DB errors for individual orders are skipped; other orders proceed. + /// + /// # Current Behavior (documented, not necessarily ideal) + /// + /// When a DB lookup fails for an order: + /// - The error is logged and the order data is excluded from the submission + /// - However, the UID is still included in the submission + /// + /// This means `submit` receives: + /// - `uids`: ALL original UIDs (including those with failed lookups) + /// - `orders`: Only the order data for successful lookups + /// + /// This creates a mismatch between UIDs and order data. See the TODO in + /// `test_send_out_refunding_tx_all_db_calls_fail_still_submits` for + /// discussion of potential fixes. + #[tokio::test] + async fn test_send_out_refunding_tx_db_error_skips_order() { + let uid1 = create_test_order_placement(1, KNOWN_ETHFLOW).uid; + let uid2 = create_test_order_placement(2, KNOWN_ETHFLOW).uid; + + let mut mock_db = MockDbRead::new(); + + // First order (uid_suffix=1) fails DB lookup to test error handling + mock_db + .expect_get_ethflow_order_data() + .withf(|uid| uid.0[31] == 1) + .returning(|_| Err(anyhow!("DB error"))); + + // Second order (uid_suffix=2) succeeds to verify partial success behavior + mock_db + .expect_get_ethflow_order_data() + .withf(|uid| uid.0[31] == 2) + .returning(|_| Ok(EthFlowOrder::Data::default())); + + let mock_chain = MockChainRead::new(); + + let mut mock_submitter = MockChainWrite::new(); + + // Current behavior: ALL UIDs are passed, but only successful order data. + // - uids contains both uid1 (suffix=1) and uid2 (suffix=2) + // - orders contains only 1 entry (from uid2's successful lookup) + mock_submitter + .expect_submit_batch() + .times(1) + .withf(|uids, orders, _| { + let has_both_uids = uids.len() == 2 + && uids.iter().any(|uid| uid.0[31] == 1) + && uids.iter().any(|uid| uid.0[31] == 2); + let has_one_order = orders.len() == 1; + has_both_uids && has_one_order + }) + .returning(|_, _, _| Ok(())); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let mut uids_by_contract = HashMap::new(); + uids_by_contract.insert(KNOWN_ETHFLOW, vec![uid1, uid2]); + + let result = service.send_out_refunding_tx(uids_by_contract).await; + assert!(result.is_ok()); + } + + /// If every DB lookup fails, we still call the submitter with the original + /// UIDs but without any order data. + /// + /// What actually happens: + /// - Each failed order‑data fetch is logged and ignored (it doesn't stop + /// the whole batch). + /// - The submitter gets the same list of UIDs we started with, but the + /// `orders` slice may be empty (or contain fewer entries) because some or + /// all lookups failed. + /// + /// TODO: Is this the behavior we really want? Submitting a refund that + /// contains UIDs but no order details feels off. Possible fixes: + /// 1. Skip the submission entirely when `encoded_ethflow_orders` is empty. + /// 2. Return an error if *all* order‑data lookups fail. + /// 3. Filter the UID list so it only includes IDs with successful lookups. + /// + /// NOTE: This test complements + /// `test_send_out_refunding_tx_db_error_skips_order`. That test covers + /// partial DB failure (some lookups succeed); this one covers + /// total DB failure (all lookups fail). Together they verify that DB errors + /// are non-fatal and UIDs are always preserved regardless of lookup + /// success. + #[tokio::test] + async fn test_send_out_refunding_tx_all_db_calls_fail_still_submits() { + let uid1 = create_test_order_placement(1, KNOWN_ETHFLOW).uid; + let uid2 = create_test_order_placement(2, KNOWN_ETHFLOW).uid; + + let mut mock_db = MockDbRead::new(); + + // All DB lookups fail to test edge case where no order data is available + mock_db + .expect_get_ethflow_order_data() + .returning(|_| Err(anyhow!("DB connection lost"))); + + let mock_chain = MockChainRead::new(); + + let mut mock_submitter = MockChainWrite::new(); + + // Verify submission still happens with original UIDs but empty orders list + // This documents current (possibly unintended) behavior where UIDs and orders + // mismatch + mock_submitter + .expect_submit_batch() + .times(1) + .withf(|uids, orders, contract| { + // UIDs are preserved, but orders is empty because all DB lookups failed + uids.len() == 2 && orders.is_empty() && *contract == KNOWN_ETHFLOW + }) + .returning(|_, _, _| Ok(())); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let mut uids_by_contract = HashMap::new(); + uids_by_contract.insert(KNOWN_ETHFLOW, vec![uid1, uid2]); + + let result = service.send_out_refunding_tx(uids_by_contract).await; + assert!(result.is_ok()); + } + + /// Submitter error on first contract short-circuits; remaining contracts + /// are not attempted. + /// + /// NOTE: HashMap iteration order is non-deterministic, so we cannot predict + /// which contract will be processed first. This test verifies that: + /// 1. The error propagates (result is Err) + /// 2. Only one submission is attempted (times(1)) + /// + /// The test remains valid regardless of iteration order because both + /// contracts would fail with the same error. + #[tokio::test] + async fn test_send_out_refunding_tx_error_short_circuits() { + let mut mock_db = MockDbRead::new(); + // Return order data successfully; the error will come from submission + mock_db.with_default_ethflow_order_data(); + + let mock_chain = MockChainRead::new(); + + let mut mock_submitter = MockChainWrite::new(); + + // Fail on first submission to verify error propagation stops processing + // Due to HashMap's non-deterministic iteration order, we cannot predict + // which contract will be attempted first, but we know only one will be tried + mock_submitter + .expect_submit_batch() + .times(1) + .returning(|_, _, _| Err(anyhow!("Submission failed"))); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let uid1 = create_test_order_placement(1, KNOWN_ETHFLOW).uid; + let uid2 = create_test_order_placement(2, KNOWN_ETHFLOW_2).uid; + let mut uids_by_contract = HashMap::new(); + uids_by_contract.insert(KNOWN_ETHFLOW, vec![uid1]); + uids_by_contract.insert(KNOWN_ETHFLOW_2, vec![uid2]); + + let result = service.send_out_refunding_tx(uids_by_contract).await; + assert!(result.is_err()); + } + + /// An eligible order is fetched, validated, and submitted for refund. + #[tokio::test] + async fn test_try_to_refund_happy_path() { + let mut mock_db = MockDbRead::new(); + let order = vec![create_test_order_placement(1, KNOWN_ETHFLOW)]; + mock_db.with_refundable_orders(order); + + mock_db.with_default_ethflow_order_data(); + + let mut mock_chain = MockChainRead::new(); + mock_chain + .with_block_timestamp(1000) + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]) + .with_order_status(RefundStatus::NotYetRefunded(EOA_OWNER)) + .receiving_eth(); + + let mut mock_submitter = MockChainWrite::new(); + mock_submitter + .expect_submit_batch() + .times(1) + .returning(|_, _, _| Ok(())); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let result = service.try_to_refund_all_eligible_orders().await; + assert!(result.is_ok()); + } + + /// Empty database result does not trigger any submission. + #[tokio::test] + async fn test_try_to_refund_empty_db_result() { + let mut mock_db = MockDbRead::new(); + mock_db.with_refundable_orders(vec![]); + + let mut mock_chain = MockChainRead::new(); + mock_chain + .with_block_timestamp(1000) + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]); + + // Submitter has no expectations: test fails if submit is called + let mock_submitter = MockChainWrite::new(); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let result = service.try_to_refund_all_eligible_orders().await; + assert!(result.is_ok()); + } + + /// When some orders are already refunded on-chain, only pending orders are + /// submitted. + #[tokio::test] + async fn test_try_to_refund_mixed_orders() { + let order_valid = create_test_order_placement(1, KNOWN_ETHFLOW); + let order_refunded = create_test_order_placement(2, KNOWN_ETHFLOW); + + let mut mock_db = MockDbRead::new(); + + // Return two orders from DB: one still needs refund, one already refunded + // on-chain + mock_db.with_refundable_orders(vec![order_valid, order_refunded]); + + // Return order data for the order that passes on-chain validation + mock_db.with_default_ethflow_order_data(); + + let mut mock_chain = MockChainRead::new(); + + // Block timestamp and known contracts for DB query + mock_chain + .with_block_timestamp(1000) + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]) + .receiving_eth(); + + // Order 1 (uid_suffix=1) is eligible for refund + mock_chain + .expect_get_order_status() + .withf(|_, order_hash| order_hash.0[31] == 1) + .returning(|_, _| Ok(RefundStatus::NotYetRefunded(EOA_OWNER))); + + // Order 2 (uid_suffix=2) was already refunded on-chain, should be filtered out + mock_chain + .expect_get_order_status() + .withf(|_, order_hash| order_hash.0[31] == 2) + .returning(|_, _| Ok(RefundStatus::Refunded)); + + let mut mock_submitter = MockChainWrite::new(); + + // Only 1 order should be submitted (order 2 is filtered out as already + // refunded) + mock_submitter + .expect_submit_batch() + .times(1) + .withf(|uids, _, _| uids.len() == 1) + .returning(|_, _, _| Ok(())); + + let mut service = RefundService::new(mock_db, mock_chain, mock_submitter, 3600, 100); + + let result = service.try_to_refund_all_eligible_orders().await; + assert!(result.is_ok()); + } + + /// Orders are grouped by their originating EthFlow contract. + #[tokio::test] + async fn test_identify_groups_orders_by_contract() { + let order1 = create_test_order_placement(1, KNOWN_ETHFLOW); + let order2 = create_test_order_placement(2, KNOWN_ETHFLOW); + let order3 = create_test_order_placement(3, KNOWN_ETHFLOW_2); + + let mut mock_chain = MockChainRead::new(); + mock_chain + .with_ethflow_addresses(vec![KNOWN_ETHFLOW, KNOWN_ETHFLOW_2]) + .with_order_status(RefundStatus::NotYetRefunded(EOA_OWNER)) + .receiving_eth(); + + let result = identify_uids_refunding_status(&mock_chain, &[order1, order2, order3]).await; + + assert_eq!(result.len(), 2); + assert_orders_by_contract(&result, KNOWN_ETHFLOW, &[1, 2]); + assert_orders_by_contract(&result, KNOWN_ETHFLOW_2, &[3]); + } + + /// Empty input returns empty result. + #[tokio::test] + async fn test_identify_empty_input() { + let mut mock_chain = MockChainRead::new(); + mock_chain.with_ethflow_addresses(vec![KNOWN_ETHFLOW]); + + let result = identify_uids_refunding_status(&mock_chain, &[]).await; + + assert!(result.is_empty()); + } + + /// Verifies that the order hash is correctly extracted from UID bytes + /// [0..32]. + /// + /// The refund service extracts the order hash from the first 32 bytes of + /// the UID to query on-chain status. + #[tokio::test] + async fn test_order_hash_extraction_from_uid() { + let expected_hash: [u8; 32] = random(); + + let mut mock_chain = MockChainRead::new(); + mock_chain + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]) + .receiving_eth(); + + // Capture the order_hash passed to get_order_status and verify it matches + mock_chain + .expect_get_order_status() + .withf(move |_, order_hash| order_hash.0 == expected_hash) + .returning(|_, _| Ok(RefundStatus::NotYetRefunded(EOA_OWNER))); + + // Build a UID with the expected hash in bytes [0..32] + let mut uid_bytes = [0u8; 56]; + uid_bytes[0..32].copy_from_slice(&expected_hash); + uid_bytes[32..52].copy_from_slice(KNOWN_ETHFLOW.as_slice()); + + let order = EthOrderPlacement { + uid: ByteArray(uid_bytes), + valid_to: 1000, + }; + + let result = identify_uids_refunding_status(&mock_chain, &[order]).await; + + // Verify the result contains our order with the expected hash + let uids = result + .get(&KNOWN_ETHFLOW) + .expect("should have orders for contract"); + assert_eq!(uids.len(), 1); + assert_eq!(&uids[0].0[0..32], &expected_hash); + } + + /// Verifies that the contract address is correctly extracted from UID bytes + /// [32..52]. + /// + /// The refund service extracts the EthFlow contract address from bytes + /// 32-52 to determine which contract the order belongs to. This test + /// ensures the extraction produces the correct Address value. + #[rstest] + #[case::known_ethflow(KNOWN_ETHFLOW)] + #[case::known_ethflow_2(KNOWN_ETHFLOW_2)] + #[case::all_zeros(Address::ZERO)] + #[case::all_ones(Address::repeat_byte(0xFF))] + #[tokio::test] + async fn test_contract_address_extraction_from_uid(#[case] contract: Address) { + let mut mock_chain = MockChainRead::new(); + + // Only allow the specific contract being tested + mock_chain + .with_ethflow_addresses(vec![contract]) + .with_order_status(RefundStatus::NotYetRefunded(EOA_OWNER)) + .receiving_eth(); + + // Build a UID with the contract address in bytes [32..52] + let mut uid_bytes = [0u8; 56]; + uid_bytes[31] = 1; // uid_suffix for identification + uid_bytes[32..52].copy_from_slice(contract.as_slice()); + + let order = EthOrderPlacement { + uid: ByteArray(uid_bytes), + valid_to: 1000, + }; + + let result = identify_uids_refunding_status(&mock_chain, &[order]).await; + + // The order should be grouped under the correct contract + assert_orders_by_contract(&result, contract, &[1]); + } + + /// Multiple orders with different owners are filtered based on each owner's + /// ability to receive ETH. + /// + /// This test verifies that the ETH receivability check is performed + /// per-owner, not globally. Orders from owners that can receive ETH are + /// included; orders from owners that cannot receive ETH are excluded. + #[tokio::test] + async fn test_mixed_eth_receivability_multiple_owners() { + // Define owners with different ETH receivability + const OWNER_CAN_RECEIVE_1: Address = Address::repeat_byte(0xA1); + const OWNER_CAN_RECEIVE_2: Address = Address::repeat_byte(0xA2); + const OWNER_CANNOT_RECEIVE_1: Address = Address::repeat_byte(0xB1); + const OWNER_CANNOT_RECEIVE_2: Address = Address::repeat_byte(0xB2); + + let mut mock_chain = MockChainRead::new(); + mock_chain.with_ethflow_addresses(vec![KNOWN_ETHFLOW]); + + // Each order has a different owner + mock_chain + .expect_get_order_status() + .returning(|_, order_hash| { + let owner = match order_hash.0[31] { + 1 => OWNER_CAN_RECEIVE_1, + 2 => OWNER_CANNOT_RECEIVE_1, + 3 => OWNER_CAN_RECEIVE_2, + 4 => OWNER_CANNOT_RECEIVE_2, + _ => unreachable!(), + }; + Ok(RefundStatus::NotYetRefunded(owner)) + }); + + // ETH receivability depends on owner address + mock_chain + .expect_can_receive_eth() + .returning(|owner| [OWNER_CAN_RECEIVE_1, OWNER_CAN_RECEIVE_2].contains(&owner)); + + let orders: Vec<_> = (1..=4) + .map(|i| create_test_order_placement(i, KNOWN_ETHFLOW)) + .collect(); + + let result = identify_uids_refunding_status(&mock_chain, &orders).await; + + // Only orders 1 and 3 (owners that can receive ETH) should be included + assert_orders_by_contract(&result, KNOWN_ETHFLOW, &[1, 3]); + } + + /// When multiple status queries fail, all failed orders are excluded. + #[tokio::test] + async fn test_multiple_status_query_failures() { + // Orders 1 and 2 fail with RPC errors to test partial failure handling + // Order 3 succeeds to verify successful orders are still processed + let order1 = create_test_order_placement(1, KNOWN_ETHFLOW); + let order2 = create_test_order_placement(2, KNOWN_ETHFLOW); + let order3 = create_test_order_placement(3, KNOWN_ETHFLOW); + + let mut mock_chain = MockChainRead::new(); + + // All orders pass the allowlist check + mock_chain + .with_ethflow_addresses(vec![KNOWN_ETHFLOW]) + .receiving_eth() // Owner can receive ETH (only relevant for order 3 which passes status check) + + .expect_get_order_status() + .returning(|_, order_hash| { + match order_hash.0[31] { + 1 | 2 => Err(anyhow!("RPC timeout")), + 3 => Ok(RefundStatus::NotYetRefunded(EOA_OWNER)), + _ => unreachable!() + } + }); + + let result = identify_uids_refunding_status(&mock_chain, &[order1, order2, order3]).await; + + // Only order 3 should be included (orders 1 and 2 failed status check) + assert_orders_by_contract(&result, KNOWN_ETHFLOW, &[3]); + } + + /// Verifies that `can_receive_eth()` correctly identifies addresses that + /// cannot receive ETH transfers. Some smart contracts reject ETH transfers + /// (e.g., EOF contracts or contracts without receive/fallback functions), + /// which causes batch refunds to fail with EthTransferFailed errors. + /// + /// This test uses a real Sepolia EOF contract address that rejects ETH and + /// compares it against a normal EOA to ensure the filtering logic works. + #[tokio::test] + #[ignore] // Run with: cargo test --package refunder --lib test_problematic_sepolia_address -- --ignored + async fn test_problematic_sepolia_address() { + use crate::infra::AlloyChain; + + let (provider, _wallet) = ethrpc::alloy::provider( + "https://ethereum-sepolia-rpc.publicnode.com", + ethrpc::Config::default(), + None, + ); + let chain = AlloyChain::new(provider, vec![]); + + // EOF contract that cannot receive ETH (0xef01... bytecode prefix) + let problematic: Address = "0x66C9152339ce05EE0C8A8eff9EeF8230AbFe8350" + .parse() + .unwrap(); + + // Normal EOA for comparison + let working: Address = "0x5b485e4431853F82d89dba68220A422CC17cE024" + .parse() + .unwrap(); + + // Test that can_receive_eth correctly identifies the problematic address + assert!( + !chain.can_receive_eth(problematic).await, + "EOF contract should be identified as unable to receive ETH" + ); + + // Test that can_receive_eth correctly identifies a working address + assert!( + chain.can_receive_eth(working).await, + "Normal EOA should be identified as able to receive ETH" + ); + } +} diff --git a/crates/refunder/src/submitter.rs b/crates/refunder/src/submitter.rs index 742178edff..e2f3e64ba0 100644 --- a/crates/refunder/src/submitter.rs +++ b/crates/refunder/src/submitter.rs @@ -1,20 +1,18 @@ -// This submitter has the following logic: -// It tries to submit a tx - as EIP1559 - with a small tx tip, -// but a quite high max_fee_per_gas such that it's likely being mined quickly -// -// Then it waits for 5 blocks. If the tx is not mined, it will return an error -// and it needs to be called again. If the last submission was not successful, -// this submitter stores the last gas_price in order to submit the new tx with -// a higher gas price, in order to avoid: ErrReplaceUnderpriced erros -// In the re-newed attempt for submission the same nonce is used as before. +//! Refund transaction submitter. +//! +//! Submits EIP-1559 transactions with a small tip but high `max_fee_per_gas` +//! to get mined quickly. Waits 5 blocks for confirmation; on timeout, the next +//! call bumps gas price (using the same nonce) to avoid +//! `ErrReplaceUnderpriced`. use { - alloy::{primitives::Address, providers::Provider}, + crate::traits::ChainWrite, + alloy::{eips::eip1559::Eip1559Estimation, primitives::Address, providers::Provider}, anyhow::{Context, Result}, - contracts::alloy::CoWSwapEthFlow::{self, EthFlowOrder}, + contracts::CoWSwapEthFlow::{self, EthFlowOrder}, database::OrderUid, - gas_estimation::{GasPrice1559, GasPriceEstimating}, - shared::ethrpc::Web3, + ethrpc::Web3, + gas_price_estimation::{Eip1559EstimationExt, GasPriceEstimating}, std::time::Duration, }; @@ -22,105 +20,104 @@ use { // send out EIP1559 txs. // Example: If the prevailing gas is 10Gwei and the buffer factor is 1.20 // then the gas_price used will be 12. -const GAS_PRICE_BUFFER_FACTOR: f64 = 1.3; +const GAS_PRICE_BUFFER_PCT: u64 = 30; // In order to resubmit a new tx with the same nonce, the gas tip and // max_fee_per_gas needs to be increased by at least 10 percent. -const GAS_PRICE_BUMP: f64 = 1.125; +const GAS_PRICE_BUMP_PERMIL: u64 = 125; -/// Type safe cast to avoid unexpected issues due to type changes. -const fn f64_to_u128(n: f64) -> u128 { - n as u128 -} +const TIMEOUT_5_BLOCKS: Duration = Duration::from_secs(60); pub struct Submitter { pub web3: Web3, pub signer_address: Address, pub gas_estimator: Box, - pub gas_parameters_of_last_tx: Option, + pub gas_parameters_of_last_tx: Option, pub nonce_of_last_submission: Option, pub max_gas_price: u64, pub start_priority_fee_tip: u64, } -impl Submitter { - async fn get_submission_nonce(&self) -> Result { - // this command returns the tx count ever mined at the latest block - // Mempool tx are not considered. - self.web3 - .alloy - .get_transaction_count(self.signer_address) - .await - .with_context(|| { - format!( - "could not get latest nonce for address {:?}", - self.signer_address - ) - }) - } - - pub async fn submit( +impl ChainWrite for Submitter { + async fn submit_batch( &mut self, - uids: Vec, + uids: &[OrderUid], encoded_ethflow_orders: Vec, ethflow_contract: Address, ) -> Result<()> { - const TIMEOUT_5_BLOCKS: Duration = Duration::from_secs(60); - - let gas_price_estimation = self.gas_estimator.estimate().await?; - let nonce = self.get_submission_nonce().await?; - let gas_price = calculate_submission_gas_price( - self.gas_parameters_of_last_tx, - gas_price_estimation, - nonce, - self.nonce_of_last_submission, - self.max_gas_price, - self.start_priority_fee_tip, - )?; - - self.gas_parameters_of_last_tx = Some(gas_price); - self.nonce_of_last_submission = Some(nonce); - - let ethflow_contract = - CoWSwapEthFlow::Instance::new(ethflow_contract, self.web3.alloy.clone()); - let tx_result = ethflow_contract + { + let gas_price_estimation = self.gas_estimator.estimate().await?; + let nonce = self.get_submission_nonce().await?; + let gas_price = calculate_submission_gas_price( + self.gas_parameters_of_last_tx, + gas_price_estimation, + nonce, + self.nonce_of_last_submission, + self.max_gas_price, + self.start_priority_fee_tip, + )?; + + self.gas_parameters_of_last_tx = Some(gas_price); + self.nonce_of_last_submission = Some(nonce); + + let ethflow_contract = + CoWSwapEthFlow::Instance::new(ethflow_contract, self.web3.provider.clone()); + let tx_result = ethflow_contract .invalidateOrdersIgnoringNotAllowed(encoded_ethflow_orders) // Gas conversions are lossy but technically the should not have decimal points even though they're floats - .max_priority_fee_per_gas(f64_to_u128(gas_price.max_priority_fee_per_gas)) - .max_fee_per_gas(f64_to_u128(gas_price.max_fee_per_gas)) + .max_priority_fee_per_gas(gas_price.max_priority_fee_per_gas) + .max_fee_per_gas(gas_price.max_fee_per_gas) .from(self.signer_address) .nonce(nonce) .send() .await?.with_timeout(Some(TIMEOUT_5_BLOCKS)).get_receipt().await; - match tx_result { - Ok(receipt) => { - tracing::debug!( - "Tx to refund the orderuids {:?} yielded following result {:?}", - uids, - receipt - ); + match tx_result { + Ok(receipt) => { + tracing::debug!( + "Tx to refund the orderuids {:?} yielded following result {:?}", + uids, + receipt + ); + } + Err(err) => tracing::debug!("transaction failed with: {err}"), } - Err(err) => tracing::debug!("transaction failed with: {err}"), + Ok(()) } - Ok(()) + } +} + +impl Submitter { + async fn get_submission_nonce(&self) -> Result { + // this command returns the tx count ever mined at the latest block + // Mempool tx are not considered. + self.web3 + .provider + .get_transaction_count(self.signer_address) + .await + .with_context(|| { + format!( + "could not get latest nonce for address {:?}", + self.signer_address + ) + }) } } fn calculate_submission_gas_price( - gas_price_of_last_submission: Option, - web3_gas_estimation: GasPrice1559, + gas_price_of_last_submission: Option, + web3_gas_estimation: Eip1559Estimation, newest_nonce: u64, nonce_of_last_submission: Option, max_gas_price: u64, start_priority_fee_tip: u64, -) -> Result { +) -> Result { // The gas price of the refund tx is the current prevailing gas price // of the web3 gas estimation plus a buffer. - let mut new_gas_price = web3_gas_estimation.bump(GAS_PRICE_BUFFER_FACTOR); + let mut new_gas_price = web3_gas_estimation.scaled_by_pct(GAS_PRICE_BUFFER_PCT); // limit the prio_fee to max_fee_per_gas as otherwise tx is invalid new_gas_price.max_priority_fee_per_gas = - (start_priority_fee_tip as f64).min(new_gas_price.max_fee_per_gas); + (start_priority_fee_tip as u128).min(new_gas_price.max_fee_per_gas); // If tx from the previous submission was not mined, // we incease the tip and max_gas_fee for miners @@ -128,7 +125,8 @@ fn calculate_submission_gas_price( if Some(newest_nonce) == nonce_of_last_submission && let Some(gas_price_of_last_submission) = gas_price_of_last_submission { - let gas_price_of_last_submission = gas_price_of_last_submission.bump(GAS_PRICE_BUMP); + let gas_price_of_last_submission = + gas_price_of_last_submission.scaled_by_pml(GAS_PRICE_BUMP_PERMIL); new_gas_price.max_fee_per_gas = new_gas_price .max_fee_per_gas .max(gas_price_of_last_submission.max_fee_per_gas); @@ -137,7 +135,7 @@ fn calculate_submission_gas_price( .max(gas_price_of_last_submission.max_priority_fee_per_gas); } - if new_gas_price.max_fee_per_gas > max_gas_price as f64 { + if new_gas_price.max_fee_per_gas > max_gas_price as u128 { tracing::warn!( "Refunding txs are likely not mined in time, as the current gas price {:?} is higher \ than MAX_GAS_PRICE specified {:?}", @@ -145,9 +143,9 @@ fn calculate_submission_gas_price( max_gas_price ); new_gas_price.max_fee_per_gas = - f64::min(max_gas_price as f64, new_gas_price.max_fee_per_gas); + u128::min(max_gas_price as u128, new_gas_price.max_fee_per_gas); } - new_gas_price.max_priority_fee_per_gas = f64::min( + new_gas_price.max_priority_fee_per_gas = u128::min( new_gas_price.max_priority_fee_per_gas, new_gas_price.max_fee_per_gas, ); @@ -164,11 +162,10 @@ mod tests { const TEST_START_PRIORITY_FEE_TIP: u64 = 2_000_000_000; // First case: previous tx was successful - let max_fee_per_gas = 4_000_000_000f64; - let web3_gas_estimation = GasPrice1559 { - base_fee_per_gas: 2_000_000_000f64, + let max_fee_per_gas = 4_000_000_000_u128; + let web3_gas_estimation = Eip1559Estimation { max_fee_per_gas, - max_priority_fee_per_gas: 3_000_000_000f64, + max_priority_fee_per_gas: 3_000_000_000_u128, }; let newest_nonce = 1; let nonce_of_last_submission = None; @@ -182,19 +179,18 @@ mod tests { TEST_START_PRIORITY_FEE_TIP, ) .unwrap(); - let expected_result = GasPrice1559 { - max_fee_per_gas: max_fee_per_gas * GAS_PRICE_BUFFER_FACTOR, - max_priority_fee_per_gas: TEST_START_PRIORITY_FEE_TIP as f64, - base_fee_per_gas: 2_000_000_000f64, + + let expected_result = Eip1559Estimation { + max_fee_per_gas: max_fee_per_gas * (100 + GAS_PRICE_BUFFER_PCT as u128) / 100, + max_priority_fee_per_gas: TEST_START_PRIORITY_FEE_TIP as u128, }; assert_eq!(result, expected_result); // Second case: Previous tx was not successful let nonce_of_last_submission = Some(newest_nonce); - let max_fee_per_gas_of_last_tx = max_fee_per_gas * 2f64; - let gas_price_of_last_submission = GasPrice1559 { + let max_fee_per_gas_of_last_tx = max_fee_per_gas * 2; + let gas_price_of_last_submission = Eip1559Estimation { max_fee_per_gas: max_fee_per_gas_of_last_tx, - max_priority_fee_per_gas: TEST_START_PRIORITY_FEE_TIP as f64, - base_fee_per_gas: 2_000_000_000f64, + max_priority_fee_per_gas: TEST_START_PRIORITY_FEE_TIP as u128, }; let result = calculate_submission_gas_price( Some(gas_price_of_last_submission), @@ -205,18 +201,19 @@ mod tests { TEST_START_PRIORITY_FEE_TIP, ) .unwrap(); - let expected_result = GasPrice1559 { - max_fee_per_gas: max_fee_per_gas_of_last_tx * GAS_PRICE_BUMP, - max_priority_fee_per_gas: TEST_START_PRIORITY_FEE_TIP as f64 * GAS_PRICE_BUMP, - base_fee_per_gas: 2_000_000_000f64, + let expected_result = Eip1559Estimation { + max_fee_per_gas: max_fee_per_gas_of_last_tx * (1000 + GAS_PRICE_BUMP_PERMIL as u128) + / 1000, + max_priority_fee_per_gas: (TEST_START_PRIORITY_FEE_TIP as u128) + * (1000 + GAS_PRICE_BUMP_PERMIL as u128) + / 1000, }; assert_eq!(result, expected_result); // Thrid case: MAX_GAS_PRICE is not exceeded - let max_fee_per_gas = TEST_MAX_GAS_PRICE as f64 + 1000f64; - let web3_gas_estimation = GasPrice1559 { - base_fee_per_gas: 2_000_000_000f64, + let max_fee_per_gas = TEST_MAX_GAS_PRICE as u128 + 1000_u128; + let web3_gas_estimation = Eip1559Estimation { max_fee_per_gas, - max_priority_fee_per_gas: 3_000_000_000f64, + max_priority_fee_per_gas: 3_000_000_000_u128, }; let nonce_of_last_submission = None; let gas_price_of_last_submission = None; @@ -229,10 +226,9 @@ mod tests { TEST_START_PRIORITY_FEE_TIP, ) .unwrap(); - let expected_result = GasPrice1559 { - base_fee_per_gas: 2_000_000_000f64, - max_fee_per_gas: TEST_MAX_GAS_PRICE as f64, - max_priority_fee_per_gas: TEST_START_PRIORITY_FEE_TIP as f64, + let expected_result = Eip1559Estimation { + max_fee_per_gas: TEST_MAX_GAS_PRICE as u128, + max_priority_fee_per_gas: TEST_START_PRIORITY_FEE_TIP as u128, }; assert_eq!(result, expected_result); } diff --git a/crates/refunder/src/traits.rs b/crates/refunder/src/traits.rs new file mode 100644 index 0000000000..4a957c5aa8 --- /dev/null +++ b/crates/refunder/src/traits.rs @@ -0,0 +1,142 @@ +//! Trait definitions for database and blockchain access. + +#![allow(async_fn_in_trait)] + +use { + alloy::primitives::{Address, B256}, + anyhow::Result, + contracts::CoWSwapEthFlow::{self, EthFlowOrder}, + database::{OrderUid, ethflow_orders::EthOrderPlacement}, +}; + +const NO_OWNER: Address = Address::ZERO; +const INVALIDATED_OWNER: Address = Address::repeat_byte(0xff); + +/// Status of an EthFlow order refund eligibility. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RefundStatus { + /// Order has already been refunded or cancelled. + Refunded, + /// Order is still active and eligible for refund, with the given owner + /// address. + NotYetRefunded(Address), + /// Order is invalid (never created, already freed, or owner cannot receive + /// ETH). + Invalid, +} + +impl From for RefundStatus { + fn from(value: CoWSwapEthFlow::CoWSwapEthFlow::ordersReturn) -> Self { + match value.owner { + NO_OWNER => Self::Invalid, + INVALIDATED_OWNER => Self::Refunded, + owner => Self::NotYetRefunded(owner), + } + } +} + +/// Database read operations. +#[cfg_attr(test, mockall::automock)] +pub trait DbRead: Send + Sync { + /// Fetches orders eligible for refund (expired, not invalidated, not + /// filled, meets price deviation threshold). + async fn get_refundable_orders( + &self, + block_time: i64, + min_validity_duration: i64, + min_price_deviation: f64, + ) -> Result>; + + /// Fetches the EthFlow order data for `uid`. + async fn get_ethflow_order_data(&self, uid: &OrderUid) -> Result; +} + +/// Blockchain read operations. +#[cfg_attr(test, mockall::automock)] +pub trait ChainRead: Send + Sync { + /// Returns the current block's timestamp. + async fn current_block_timestamp(&self) -> Result; + + /// Returns `true` if `address` can receive ETH + async fn can_receive_eth(&self, address: Address) -> bool; + + /// Returns the configured EthFlow contract addresses. + fn ethflow_addresses(&self) -> Vec
; + + /// Queries the on-chain refund status of an order. + async fn get_order_status( + &self, + ethflow_address: Address, + order_hash: B256, + ) -> Result; +} + +/// Blockchain write operations. +#[cfg_attr(test, mockall::automock)] +pub trait ChainWrite: Send + Sync { + /// Submits a batch refund transaction. + async fn submit_batch( + &mut self, + uids: &[OrderUid], + encoded_ethflow_orders: Vec, + ethflow_contract: Address, + ) -> Result<()>; +} + +#[cfg(test)] +pub mod test { + use super::*; + + /// Extension trait for `MockChainRead` to reduce mock setup boilerplate. + pub trait MockChainReadExt { + fn with_block_timestamp(&mut self, timestamp: u32) -> &mut Self; + fn with_ethflow_addresses(&mut self, addresses: Vec
) -> &mut Self; + fn with_order_status(&mut self, status: RefundStatus) -> &mut Self; + fn receiving_eth(&mut self) -> &mut Self; + } + + impl MockChainReadExt for MockChainRead { + fn with_block_timestamp(&mut self, timestamp: u32) -> &mut Self { + self.expect_current_block_timestamp() + .returning(move || Ok(timestamp)); + self + } + + fn with_ethflow_addresses(&mut self, addresses: Vec
) -> &mut Self { + self.expect_ethflow_addresses() + .returning(move || addresses.clone()); + self + } + + fn with_order_status(&mut self, status: RefundStatus) -> &mut Self { + self.expect_get_order_status() + .returning(move |_, _| Ok(status)); + self + } + + fn receiving_eth(&mut self) -> &mut Self { + self.expect_can_receive_eth().returning(|_| true); + self + } + } + + /// Extension trait for `MockDbRead` to reduce mock setup boilerplate. + pub trait MockDbReadExt { + fn with_default_ethflow_order_data(&mut self) -> &mut Self; + fn with_refundable_orders(&mut self, orders: Vec) -> &mut Self; + } + + impl MockDbReadExt for MockDbRead { + fn with_default_ethflow_order_data(&mut self) -> &mut Self { + self.expect_get_ethflow_order_data() + .returning(|_| Ok(EthFlowOrder::Data::default())); + self + } + + fn with_refundable_orders(&mut self, orders: Vec) -> &mut Self { + self.expect_get_refundable_orders() + .returning(move |_, _, _| Ok(orders.clone())); + self + } + } +} diff --git a/crates/request-sharing/Cargo.toml b/crates/request-sharing/Cargo.toml new file mode 100644 index 0000000000..cd6d16c09c --- /dev/null +++ b/crates/request-sharing/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "request-sharing" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +futures = { workspace = true } +observe = { workspace = true } +prometheus = { workspace = true } +prometheus-metric-storage = { workspace = true } +tokio = { workspace = true } + +[lints] +workspace = true diff --git a/crates/request-sharing/LICENSE-APACHE b/crates/request-sharing/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/request-sharing/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/request-sharing/LICENSE-MIT b/crates/request-sharing/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/request-sharing/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/shared/src/request_sharing.rs b/crates/request-sharing/src/lib.rs similarity index 71% rename from crates/shared/src/request_sharing.rs rename to crates/request-sharing/src/lib.rs index 461a618d77..5eb5066bf2 100644 --- a/crates/shared/src/request_sharing.rs +++ b/crates/request-sharing/src/lib.rs @@ -11,7 +11,9 @@ use { collections::HashMap, future::Future, hash::Hash, + pin::Pin, sync::{Arc, Mutex}, + task::{Context, Poll}, time::Duration, }, }; @@ -39,6 +41,28 @@ pub type BoxRequestSharing = /// A boxed shared future. pub type BoxShared = Shared>; +/// Result of [`RequestSharing::shared_or_else`] indicating whether an +/// already in-flight future was reused or a new one was created. +/// +/// Implements [`Future`] so it can be awaited directly. +pub struct SharedResult { + future: Shared, + /// `true` when an existing in-flight request was reused instead of + /// starting a new one. + pub is_shared: bool, +} + +impl Future for SharedResult +where + Fut::Output: Clone, +{ + type Output = Fut::Output; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Pin::new(&mut self.future).poll(cx) + } +} + type Cache = Arc>>>; impl RequestSharing @@ -64,10 +88,19 @@ where } fn spawn_gc(cache: Cache, label: String) { + let weak = Arc::downgrade(&cache); tokio::task::spawn(async move { loop { - Self::collect_garbage(&cache, &label); tokio::time::sleep(Duration::from_millis(500)).await; + if let Some(cache) = weak.upgrade() { + Self::collect_garbage(&cache, &label); + } else { + Metrics::get() + .request_sharing_cached_items + .with_label_values(&[label]) + .set(0); + return; + } } }); } @@ -82,16 +115,6 @@ impl Drop for RequestSharing { } } -/// Returns a shallow copy (without any pending requests) -impl Clone for RequestSharing { - fn clone(&self) -> Self { - Self { - in_flight: Default::default(), - request_label: self.request_label.clone(), - } - } -} - impl RequestSharing where Request: Eq + Hash, @@ -100,7 +123,7 @@ where { /// Returns an existing in flight future or creates and uses a new future /// from the specified closure. - pub fn shared_or_else(&self, request: Request, future: F) -> Shared + pub fn shared_or_else(&self, request: Request, future: F) -> SharedResult where F: FnOnce(&Request) -> Fut, { @@ -111,14 +134,17 @@ where if let Some(existing) = existing { Metrics::get() .request_sharing_access - .with_label_values(&[&self.request_label, "hits"]) + .with_label_values(&[self.request_label.as_str(), "hits"]) .inc(); - return existing; + return SharedResult { + future: existing, + is_shared: true, + }; } Metrics::get() .request_sharing_access - .with_label_values(&[&self.request_label, "misses"]) + .with_label_values(&[self.request_label.as_str(), "misses"]) .inc(); let shared = future(&request).shared(); @@ -129,7 +155,10 @@ where .request_sharing_cached_items .with_label_values(&[&self.request_label]) .set(in_flight.len() as u64); - shared + SharedResult { + future: shared, + is_shared: false, + } } } @@ -156,7 +185,7 @@ mod tests { #[tokio::test] async fn shares_request() { - // Manually create [`RequestSharing`] so we can have fine grained control + // Manually create [`RequestSharing`] so we can have fine-grain control // over the garbage collection. let cache: Cache> = Default::default(); let label = "test".to_string(); @@ -165,30 +194,26 @@ mod tests { request_label: label.clone(), }; - let shared0 = sharing.shared_or_else(0, |_| futures::future::ready(0).boxed()); - let shared1 = sharing.shared_or_else(0, |_| async { panic!() }.boxed()); + let result0 = sharing.shared_or_else(0, |_| futures::future::ready(0).boxed()); + let result1 = sharing.shared_or_else(0, |_| async { panic!() }.boxed()); - assert!(shared0.ptr_eq(&shared1)); - assert_eq!(shared0.strong_count().unwrap(), 2); - assert_eq!(shared1.strong_count().unwrap(), 2); - assert_eq!(shared0.weak_count().unwrap(), 1); + assert!(!result0.is_shared); + assert!(result1.is_shared); - // complete first shared - assert_eq!(shared0.now_or_never().unwrap(), 0); - assert_eq!(shared1.strong_count().unwrap(), 1); - assert_eq!(shared1.weak_count().unwrap(), 1); + // Complete first shared — result1 still holds a reference. + assert_eq!(result0.await, 0); - // GC does not delete any keys because some tasks still use the future + // GC does not delete because result1 still references the future. RequestSharing::collect_garbage(&sharing.in_flight, &label); assert_eq!(sharing.in_flight.lock().unwrap().len(), 1); assert!(sharing.in_flight.lock().unwrap().get(&0).is_some()); - // complete second shared - assert_eq!(shared1.now_or_never().unwrap(), 0); + // Complete second shared — proves sharing since its factory would panic. + assert_eq!(result1.await, 0); RequestSharing::collect_garbage(&sharing.in_flight, &label); - // GC deleted all now unused futures + // GC deleted all now unused futures. assert!(sharing.in_flight.lock().unwrap().is_empty()); } } diff --git a/crates/s3/Cargo.toml b/crates/s3/Cargo.toml index c0fa2981d4..32ea75ac17 100644 --- a/crates/s3/Cargo.toml +++ b/crates/s3/Cargo.toml @@ -8,14 +8,16 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow = { workspace = true } aws-config = { workspace = true, features = ["behavior-version-latest"] } -aws-sdk-s3 = { workspace = true, features = ["rustls", "rt-tokio"] } +aws-sdk-s3 = { workspace = true, features = ["default-https-client", "rt-tokio"] } +bytes = { workspace = true } flate2 = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +tokio = { workspace = true } [dev-dependencies] chrono = { workspace = true, features = ["clock"] } -tokio = { workspace = true, features = ["test-util", "macros"] } +tokio = { workspace = true, features = ["macros", "test-util"] } [lints] workspace = true diff --git a/crates/s3/src/lib.rs b/crates/s3/src/lib.rs index ee2235200b..ba461c7e40 100644 --- a/crates/s3/src/lib.rs +++ b/crates/s3/src/lib.rs @@ -2,7 +2,11 @@ use { anyhow::{Context, Result, anyhow}, - aws_sdk_s3::{Client, primitives::ByteStream}, + aws_sdk_s3::{ + Client, + primitives::{ByteStream, SdkBody}, + }, + bytes::Bytes, flate2::{Compression, bufread::GzEncoder}, serde::Serialize, std::io::Read, @@ -35,9 +39,25 @@ impl Uploader { /// Upload the bytes json encoded to the configured S3 bucket. Returns the /// key under which the file can be queried - pub async fn upload(&self, id: String, content: impl Serialize) -> Result { - let bytes = serde_json::to_vec(&content)?; - let encoded = self.gzip(&bytes)?; + pub async fn upload( + &self, + id: String, + content: impl Serialize + Send + Sync + 'static, + ) -> Result { + let bytes = + tokio::task::spawn_blocking(move || serde_json::to_vec(&content).map(Bytes::from)) + .await + .context("serialization task panicked")??; + self.upload_json_bytes(id, bytes).await + } + + /// Uploads bytes which are expected to be valid JSON to the configured S3 + /// bucket. Compresses the bytes before uploading. Returns the key under + /// which the file can be queried. + pub async fn upload_json_bytes(&self, id: String, content: Bytes) -> Result { + let compressed = tokio::task::spawn_blocking(move || Self::gzip(&content)) + .await + .context("compression task panicked")??; let key = std::path::Path::new(&self.filename_prefix) .join(format!("{id}.json")) .to_str() @@ -47,7 +67,7 @@ impl Uploader { .put_object() .bucket(self.bucket.clone()) .key(key.clone()) - .body(ByteStream::new(encoded.into())) + .body(ByteStream::new(SdkBody::from(compressed))) .content_encoding("gzip") .content_type("application/json") .send() @@ -75,8 +95,8 @@ impl Uploader { } /// Compresses the input bytes using Gzip. - fn gzip(&self, bytes: &[u8]) -> Result> { - let mut encoder = GzEncoder::new(bytes, Compression::best()); + fn gzip(bytes: &[u8]) -> Result> { + let mut encoder = GzEncoder::new(bytes, Compression::new(3)); let mut encoded: Vec = Vec::with_capacity(bytes.len()); encoder.read_to_end(&mut encoded).context("gzip encoding")?; Ok(encoded) @@ -109,7 +129,7 @@ mod tests { let uploader = Uploader::new(config).await; let key = uploader - .upload("test".to_string(), value.as_bytes()) + .upload("test".to_string(), value.clone().into_bytes()) .await .unwrap(); diff --git a/crates/serde-ext/Cargo.toml b/crates/serde-ext/Cargo.toml new file mode 100644 index 0000000000..f3720ab8f5 --- /dev/null +++ b/crates/serde-ext/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "serde-ext" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-primitives = { workspace = true } +const-hex = { workspace = true } +serde = { workspace = true } +serde_with = { workspace = true } diff --git a/crates/driver/src/util/serialize/hex.rs b/crates/serde-ext/src/hex.rs similarity index 100% rename from crates/driver/src/util/serialize/hex.rs rename to crates/serde-ext/src/hex.rs diff --git a/crates/driver/src/util/serialize/mod.rs b/crates/serde-ext/src/lib.rs similarity index 100% rename from crates/driver/src/util/serialize/mod.rs rename to crates/serde-ext/src/lib.rs diff --git a/crates/driver/src/util/serialize/u256.rs b/crates/serde-ext/src/u256.rs similarity index 53% rename from crates/driver/src/util/serialize/u256.rs rename to crates/serde-ext/src/u256.rs index 8cef0df143..68dc258054 100644 --- a/crates/driver/src/util/serialize/u256.rs +++ b/crates/serde-ext/src/u256.rs @@ -1,19 +1,22 @@ use { - crate::domain::eth, serde::{Deserializer, Serializer, de}, serde_with::{DeserializeAs, SerializeAs}, }; +// NOTE(jmg-duarte): not sure if we still need this module + /// Serialize and deserialize [`eth::U256`] as a decimal string. #[derive(Debug)] pub struct U256; -impl<'de> DeserializeAs<'de, eth::U256> for U256 { - fn deserialize_as>(deserializer: D) -> Result { +impl<'de> DeserializeAs<'de, alloy_primitives::U256> for U256 { + fn deserialize_as>( + deserializer: D, + ) -> Result { struct Visitor; impl de::Visitor<'_> for Visitor { - type Value = eth::U256; + type Value = alloy_primitives::U256; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a 256-bit decimal string") @@ -23,7 +26,7 @@ impl<'de> DeserializeAs<'de, eth::U256> for U256 { where E: de::Error, { - eth::U256::from_dec_str(s).map_err(|err| { + alloy_primitives::U256::from_str_radix(s, 10).map_err(|err| { de::Error::custom(format!("failed to decode {s:?} as a 256-bit number: {err}")) }) } @@ -33,14 +36,11 @@ impl<'de> DeserializeAs<'de, eth::U256> for U256 { } } -impl SerializeAs for U256 { - fn serialize_as(source: ð::U256, serializer: S) -> Result { - // `primitive_types::U256::to_string()` is so slow that - // it's still faster to first convert to alloy's U256 - // and convert that to string... - let mut buf = [0u8; 32]; - source.to_big_endian(&mut buf); - let source = alloy::primitives::U256::from_be_bytes(buf); +impl SerializeAs for U256 { + fn serialize_as( + source: &alloy_primitives::U256, + serializer: S, + ) -> Result { serializer.serialize_str(&source.to_string()) } } diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index cb5cee77c4..549a4d9a60 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -9,66 +9,77 @@ license = "MIT OR Apache-2.0" doctest = false [dependencies] -alloy = { workspace = true, features = ["sol-types"] } +account-balances = { workspace = true } +alloy = { workspace = true, features = ["provider-trace-api", "rand", "signer-local", "sol-types"] } anyhow = { workspace = true } app-data = { workspace = true } -bytes-hex = { workspace = true } +arc-swap = { workspace = true } async-trait = { workspace = true } +bad-tokens = { workspace = true } +balance-overrides = { workspace = true } bigdecimal = { workspace = true } +bytes-hex = { workspace = true } cached = { workspace = true } chain = { workspace = true } chrono = { workspace = true, features = ["clock"] } clap = { workspace = true } +configs = { workspace = true } +const-hex = { workspace = true } contracts = { workspace = true } dashmap = { workspace = true } database = { workspace = true } derive_more = { workspace = true } -derivative = { workspace = true } -ethcontract = { workspace = true } ethrpc = { workspace = true } futures = { workspace = true } -gas-estimation = { workspace = true } -observe = { workspace = true } -const-hex = { workspace = true } +gas-price-estimation = { workspace = true } hex-literal = { workspace = true } humantime = { workspace = true } indexmap = { workspace = true } itertools = { workspace = true } -maplit = { workspace = true } +liquidity-sources = { workspace = true } +mockall = { workspace = true, optional = true } model = { workspace = true } +moka = { workspace = true, features = ["sync"] } num = { workspace = true } number = { workspace = true } +observe = { workspace = true } order-validation = { workspace = true } -primitive-types = { workspace = true } +price-estimation = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } rand = { workspace = true } rate-limit = { workspace = true } -reqwest = { workspace = true, features = ["cookies", "gzip", "json"] } +request-sharing = { workspace = true } +reqwest = { workspace = true, features = ["cookies", "gzip", "json", "query"] } rust_decimal = { workspace = true, features = ["maths"] } -secp256k1 = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } +signature-validator = { workspace = true } +simulator = { workspace = true } strum = { workspace = true } thiserror = { workspace = true } -tokio = { workspace = true, features = ["macros", "time"] } +token-info = { workspace = true } +tokio = { workspace = true, features = ["macros", "signal", "time"] } tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "time"] } url = { workspace = true } -web3 = { workspace = true } - -mockall = { workspace = true, optional = true } [dev-dependencies] +account-balances = { workspace = true, features = ["test-util"] } +alloy = { workspace = true, features = ["rand"] } +app-data = { workspace = true, features = ["test_helpers"] } async-stream = { workspace = true } -ethcontract-mock = { workspace = true } +ethrpc = { workspace = true, features = ["test-util"] } +maplit = { workspace = true } +mockall = { workspace = true } +price-estimation = { workspace = true, features = ["test-util"] } regex = { workspace = true } +signature-validator = { workspace = true, features = ["test-util"] } +simulator = { workspace = true, features = ["test-util"] } testlib = { workspace = true } -app-data = { workspace = true, features = ["test_helpers"] } tokio = { workspace = true, features = ["rt-multi-thread"] } -mockall = { workspace = true } -ethrpc = {workspace = true, features = ["test-util"]} +toml = { workspace = true } [features] test-util = ["dep:mockall"] diff --git a/crates/shared/src/arguments.rs b/crates/shared/src/arguments.rs index ac8fa00b8b..c2727d37e9 100644 --- a/crates/shared/src/arguments.rs +++ b/crates/shared/src/arguments.rs @@ -2,27 +2,16 @@ //! the binaries. use { - crate::{ - gas_price_estimation::GasEstimatorType, - sources::{ - BaselineSource, - balancer_v2::BalancerFactoryKind, - uniswap_v2::UniV2BaselineSourceParameters, - }, - tenderly_api, - }, alloy::primitives::Address, - anyhow::{Context, Result, ensure}, - bigdecimal::BigDecimal, - ethcontract::{H160, U256}, + configs::fee_factor::FeeFactor, + gas_price_estimation::GasEstimatorType, observe::TracingConfig, std::{ + collections::HashSet, fmt::{self, Display, Formatter}, - num::NonZeroU64, - str::FromStr, + num::NonZeroU32, time::Duration, }, - url::Url, }; #[macro_export] @@ -57,51 +46,6 @@ macro_rules! logging_args_with_default_filter { }; } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ExternalSolver { - pub name: String, - pub url: Url, -} - -// The following arguments are used to configure the order creation process -// The arguments are shared between the orderbook crate and the autopilot crate, -// as both crates can create orders -#[derive(clap::Parser)] -pub struct OrderQuotingArguments { - /// A list of external drivers used for price estimation in the following - /// format: `|,|` - #[clap(long, env, use_value_delimiter = true)] - pub price_estimation_drivers: Vec, - - /// The time period an EIP1271-quote request is valid. - #[clap( - long, - env, - default_value = "10m", - value_parser = humantime::parse_duration, - )] - pub eip1271_onchain_quote_validity: Duration, - - /// The time period an PRESIGN-quote request is valid. - #[clap( - long, - env, - default_value = "10m", - value_parser = humantime::parse_duration, - )] - pub presign_onchain_quote_validity: Duration, - - /// The time period a regular offchain-quote request (ethsign/eip712) is - /// valid. - #[clap( - long, - env, - default_value = "1m", - value_parser = humantime::parse_duration, - )] - pub standard_offchain_quote_validity: Duration, -} - logging_args_with_default_filter!( LoggingArguments, "info,autopilot=debug,driver=debug,observe=info,orderbook=debug,solver=debug,shared=debug,\ @@ -131,180 +75,27 @@ pub fn tracing_config(args: &TracingArguments, service_name: String) -> Option, - - /// The expected chain ID that the services are expected to run against. - /// This can be optionally specified in order to check at startup whether - /// the connected nodes match to detect misconfigurations. - #[clap(long, env)] - pub chain_id: Option, - - /// Which gas estimators to use. Multiple estimators are used in sequence if - /// a previous one fails. Individual estimators support different - /// networks. `EthGasStation`: supports mainnet. - /// `GasNow`: supports mainnet. - /// `Web3`: supports every network. - /// `Native`: supports every network. - #[clap( - long, - env, - default_value = "Web3", - use_value_delimiter = true, - value_parser = clap::value_parser!(GasEstimatorType) - )] - pub gas_estimators: Vec, - - /// Base tokens used for finding multi-hop paths between multiple AMMs - /// Should be the most liquid tokens of the given network. - #[clap(long, env, use_value_delimiter = true)] - pub base_tokens: Vec, - - /// Which Liquidity sources to be used by Price Estimator. - #[clap(long, env, value_enum, ignore_case = true, use_value_delimiter = true)] - pub baseline_sources: Option>, +// Matches SQLx default connection pool size. +// SAFETY: 10 > 0 +pub const DB_MAX_CONNECTIONS_DEFAULT: NonZeroU32 = NonZeroU32::new(10).unwrap(); - /// List of non hardcoded univ2-like contracts. - /// - /// For example to add a univ2-like liquidity source the argument could be - /// set to - /// - /// 0x0000000000000000000000000000000000000001|0x0000000000000000000000000000000000000000000000000000000000000002 - /// - /// which sets the router address to 0x01 and the init code digest to 0x02. - #[clap(long, env, value_enum, ignore_case = true, use_value_delimiter = true)] - pub custom_univ2_baseline_sources: Vec, - - /// The number of blocks kept in the pool cache. - #[clap(long, env, default_value = "10")] - pub pool_cache_blocks: NonZeroU64, - - /// The number of pairs that are automatically updated in the pool cache. - #[clap(long, env, default_value = "4")] - pub pool_cache_maximum_recent_block_age: u64, - - /// How often to retry requests in the pool cache. - #[clap(long, env, default_value = "5")] - pub pool_cache_maximum_retries: u32, - - /// How long to sleep in seconds between retries in the pool cache. - #[clap(long, env, default_value = "1s", value_parser = humantime::parse_duration)] - pub pool_cache_delay_between_retries: Duration, - - /// If solvers should use internal buffers to improve solution quality. - #[clap(long, env, action = clap::ArgAction::Set, default_value = "false")] - pub use_internal_buffers: bool, - - /// The Balancer V2 factories to consider for indexing liquidity. Allows - /// specific pool kinds to be disabled via configuration. Will use all - /// supported Balancer V2 factory kinds if not specified. - #[clap(long, env, value_enum, ignore_case = true, use_value_delimiter = true)] - pub balancer_factories: Option>, - - /// Value of the authorization header for the solver competition post api. - #[clap(long, env)] - pub solver_competition_auth: Option, - - /// If liquidity pool fetcher has caching mechanism, this argument defines - /// how old pool data is allowed to be before updating - #[clap( - long, - env, - default_value = "30s", - value_parser = humantime::parse_duration, - )] - pub liquidity_fetcher_max_age_update: Duration, - - /// The number of pools to initially populate the UniswapV3 cache - #[clap(long, env, default_value = "100")] - pub max_pools_to_initialize_cache: usize, - - /// The time between new blocks on the network. - #[clap(long, env, value_parser = humantime::parse_duration)] - pub network_block_interval: Option, - - /// Override address of the settlement contract. - #[clap(long, env)] - pub settlement_contract_address: Option, - - /// Override address of the Balances contract. - #[clap(long, env)] - pub balances_contract_address: Option
, - - /// Override address of the Signatures contract. - #[clap(long, env)] - pub signatures_contract_address: Option, - - /// Override address of the settlement contract. - #[clap(long, env)] - pub native_token_address: Option
, +#[derive(Debug, Clone, clap::Parser)] +pub struct DatabasePoolConfig { + /// Maximum number of connections in the database connection pool. + #[clap(long, env, default_value_t = DB_MAX_CONNECTIONS_DEFAULT)] + pub db_max_connections: NonZeroU32, - /// Override the address of the `HooksTrampoline` contract used for - /// trampolining custom order interactions. If not specified, the default - /// contract deployment for the current network will be used. - #[clap(long, env)] - pub hooks_contract_address: Option, - - /// Override address of the balancer vault contract. - #[clap(long, env)] - pub balancer_v2_vault_address: Option
, - - /// The amount of time a classification of a token into good or - /// bad is valid for. - #[clap( - long, - env, - default_value = "10m", - value_parser = humantime::parse_duration, - )] - pub token_quality_cache_expiry: Duration, - - /// How long before expiry the token quality cache should try to update the - /// token quality in the background. This is useful to make sure that token - /// quality for every cached token is usable at all times. This value - /// has to be smaller than `token_quality_cache_expiry` - /// This configuration also affects the period of the token quality - /// maintenance job. Maintenance period = - /// `token_quality_cache_prefetch_time` / 2 - #[clap( - long, - env, - default_value = "2m", - value_parser = humantime::parse_duration, - )] - pub token_quality_cache_prefetch_time: Duration, + /// Timeout for database read queries, only applied to read-only connections + /// — for example, the Orderbook. + #[clap(long, env, default_value = "30s", value_parser = humantime::parse_duration)] + pub statement_timeout: Duration, } -pub fn display_secret_option( - f: &mut Formatter<'_>, - name: &str, - option: Option<&T>, -) -> std::fmt::Result { - display_option(f, name, &option.as_ref().map(|_| "SECRET")) +impl Display for DatabasePoolConfig { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + writeln!(f, "db_max_connections: {}", self.db_max_connections)?; + writeln!(f, "statement_timeout: {:?}", self.statement_timeout) + } } pub fn display_option( @@ -319,237 +110,28 @@ pub fn display_option( } } -pub fn display_list( - f: &mut Formatter<'_>, - name: &str, - iter: impl IntoIterator, -) -> std::fmt::Result -where - T: Display, -{ - write!(f, "{name}: [")?; - for (i, t) in iter.into_iter().enumerate() { - if i != 0 { - f.write_str(", ")?; - } - write!(f, "{t}")?; - } - writeln!(f, "]")?; - Ok(()) -} - -impl Display for OrderQuotingArguments { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let Self { - eip1271_onchain_quote_validity, - presign_onchain_quote_validity, - price_estimation_drivers, - standard_offchain_quote_validity, - } = self; - - writeln!( - f, - "eip1271_onchain_quote_validity_second: {eip1271_onchain_quote_validity:?}" - )?; - writeln!( - f, - "presign_onchain_quote_validity_second: {presign_onchain_quote_validity:?}" - )?; - display_list(f, "price_estimation_drivers", price_estimation_drivers)?; - writeln!( - f, - "standard_offchain_quote_validity: {standard_offchain_quote_validity:?}" - )?; - Ok(()) - } -} -// We have a custom Display implementation so that we can log the arguments on -// start up without leaking any potentially secret values. -impl Display for Arguments { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Self { - ethrpc, - current_block, - tenderly, - logging, - node_url, - chain_id, - simulation_node_url, - gas_estimators, - base_tokens, - baseline_sources, - pool_cache_blocks, - pool_cache_maximum_recent_block_age, - pool_cache_maximum_retries, - pool_cache_delay_between_retries, - use_internal_buffers, - balancer_factories, - solver_competition_auth, - network_block_interval, - settlement_contract_address, - balances_contract_address, - signatures_contract_address, - native_token_address, - hooks_contract_address, - balancer_v2_vault_address, - custom_univ2_baseline_sources, - liquidity_fetcher_max_age_update, - max_pools_to_initialize_cache, - token_quality_cache_expiry, - token_quality_cache_prefetch_time, - tracing, - } = self; - - write!(f, "{ethrpc}")?; - write!(f, "{current_block}")?; - write!(f, "{tenderly}")?; - write!(f, "{logging}")?; - writeln!(f, "node_url: {node_url}")?; - display_option(f, "chain_id", chain_id)?; - display_option(f, "simulation_node_url", simulation_node_url)?; - writeln!(f, "gas_estimators: {gas_estimators:?}")?; - writeln!(f, "base_tokens: {base_tokens:?}")?; - writeln!(f, "baseline_sources: {baseline_sources:?}")?; - writeln!(f, "pool_cache_blocks: {pool_cache_blocks}")?; - writeln!( - f, - "pool_cache_maximum_recent_block_age: {pool_cache_maximum_recent_block_age}" - )?; - writeln!( - f, - "pool_cache_maximum_retries: {pool_cache_maximum_retries}" - )?; - writeln!( - f, - "pool_cache_delay_between_retries: {pool_cache_delay_between_retries:?}" - )?; - writeln!(f, "use_internal_buffers: {use_internal_buffers}")?; - writeln!(f, "balancer_factories: {balancer_factories:?}")?; - display_secret_option( - f, - "solver_competition_auth", - solver_competition_auth.as_ref(), - )?; - display_option( - f, - "network_block_interval", - &network_block_interval.map(|duration| duration.as_secs_f32()), - )?; - display_option( - f, - "settlement_contract_address", - &settlement_contract_address.map(|a| format!("{a:?}")), - )?; - display_option( - f, - "balances_contract_address", - &balances_contract_address.map(|a| format!("{a:?}")), - )?; - display_option( - f, - "signatures_contract_address", - &signatures_contract_address.map(|a| format!("{a:?}")), - )?; - display_option( - f, - "native_token_address", - &native_token_address.map(|a| format!("{a:?}")), - )?; - display_option( - f, - "hooks_contract_address", - &hooks_contract_address.map(|a| format!("{a:?}")), - )?; - display_option( - f, - "balancer_v2_vault_address", - &balancer_v2_vault_address.map(|a| format!("{a:?}")), - )?; - display_list( - f, - "custom_univ2_baseline_sources", - custom_univ2_baseline_sources, - )?; - writeln!( - f, - "liquidity_fetcher_max_age_update: {liquidity_fetcher_max_age_update:?}" - )?; - writeln!( - f, - "max_pools_to_initialize_cache: {max_pools_to_initialize_cache}" - )?; - writeln!( - f, - "token_quality_cache_expiry: {token_quality_cache_expiry:?}" - )?; - writeln!( - f, - "token_quality_cache_prefetch_time: {token_quality_cache_prefetch_time:?}" - )?; - write!(f, "{tracing:?}")?; - - Ok(()) - } +/// Helper type for parsing token bucket fee overrides from strings +#[derive(Debug, Clone)] +pub struct TokenBucketFeeOverride { + pub tokens: HashSet
, + pub factor: FeeFactor, } -impl Display for ExternalSolver { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}({})", self.name, self.url) +pub fn gas_estimator_type_from_config( + config: &configs::shared::GasEstimatorType, +) -> GasEstimatorType { + match config { + configs::shared::GasEstimatorType::Web3 => GasEstimatorType::Web3, + configs::shared::GasEstimatorType::Driver { url } => GasEstimatorType::Driver(url.clone()), + configs::shared::GasEstimatorType::Alloy => GasEstimatorType::Alloy, } } -pub fn parse_percentage_factor(s: &str) -> Result { - let percentage_factor = f64::from_str(s)?; - ensure!(percentage_factor.is_finite() && (0. ..=1.0).contains(&percentage_factor)); - Ok(percentage_factor) -} - -pub fn wei_from_ether(s: &str) -> anyhow::Result { - let in_ether = s.parse::()?; - let base = BigDecimal::new(1.into(), -18); - number::conversions::big_decimal_to_u256(&(in_ether * base)).context("invalid Ether value") -} - -pub fn wei_from_gwei(s: &str) -> anyhow::Result { - let in_gwei: f64 = s.parse()?; - Ok(in_gwei * 1e9) -} - -impl FromStr for ExternalSolver { - type Err = anyhow::Error; - - fn from_str(solver: &str) -> Result { - let parts: Vec<&str> = solver.split('|').collect(); - ensure!( - parts.len() == 2, - "wrong number of arguments for external solver" - ); - let (name, url) = (parts[0], parts[1]); - let url: Url = url.parse()?; - - Ok(Self { - name: name.to_owned(), - url, - }) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn parse_drivers_wrong_arguments() { - // too few arguments - assert!(ExternalSolver::from_str("").is_err()); - assert!(ExternalSolver::from_str("name").is_err()); - - // broken URL - assert!(ExternalSolver::from_str("name1|sdfsdfds").is_err()); - - // too many arguments - assert!( - ExternalSolver::from_str("name1|http://localhost:8080|additional_argument").is_err() - ); +impl From<&configs::shared::TokenBucketFeeOverride> for TokenBucketFeeOverride { + fn from(config: &configs::shared::TokenBucketFeeOverride) -> Self { + Self { + tokens: config.tokens.clone(), + factor: config.factor, + } } } diff --git a/crates/shared/src/bad_token/cache.rs b/crates/shared/src/bad_token/cache.rs deleted file mode 100644 index 86743a33a3..0000000000 --- a/crates/shared/src/bad_token/cache.rs +++ /dev/null @@ -1,216 +0,0 @@ -use { - super::{BadTokenDetecting, TokenQuality}, - alloy::primitives::Address, - anyhow::Result, - dashmap::DashMap, - futures::future::join_all, - std::{ - ops::Div, - sync::Arc, - time::{Duration, Instant}, - }, - tracing::instrument, -}; - -pub struct CachingDetector { - inner: Box, - cache: DashMap, - cache_expiry: Duration, - prefetch_time: Duration, -} - -#[async_trait::async_trait] -impl BadTokenDetecting for CachingDetector { - #[instrument(skip_all)] - async fn detect(&self, token: Address) -> Result { - if let Some(quality) = self.get_from_cache(&token, Instant::now()) { - return Ok(quality); - } - - let result = self.inner.detect(token).await?; - self.cache.insert(token, (Instant::now(), result.clone())); - Ok(result) - } -} - -impl CachingDetector { - pub fn new( - inner: Box, - cache_expiry: Duration, - prefetch_time: Duration, - ) -> Arc { - assert!( - cache_expiry > prefetch_time, - "token quality cache prefetch time needs to be less than token quality cache expiry" - ); - let detector = Arc::new(Self { - inner, - cache: Default::default(), - cache_expiry, - prefetch_time, - }); - detector.clone().spawn_maintenance_task(); - detector - } - - fn get_from_cache(&self, token: &Address, now: Instant) -> Option { - let (instant, quality) = self.cache.get(token)?.value().clone(); - let still_valid = now.saturating_duration_since(instant) < self.cache_expiry; - still_valid.then_some(quality) - } - - fn insert_many_into_cache(&self, tokens: impl Iterator) { - let now = Instant::now(); - tokens.into_iter().for_each(|(token, quality)| { - self.cache.insert(token, (now, quality)); - }); - } - - fn spawn_maintenance_task(self: Arc) { - // We need to prefetch the token quality the `prefetch_time` before the cache - // expires - let prefetch_time_to_expire = self.cache_expiry - self.prefetch_time; - // The maintenance frequency has to be at least double of the prefetch time - // frequency in order to guarantee that the prefetch time is executed - // before the token quality expires. This is because of the - // Nyquist–Shannon sampling theorem. - let maintenance_timeout = self.prefetch_time.div(2); - let detector = Arc::clone(&self); - - tokio::task::spawn(async move { - loop { - let start = Instant::now(); - - let futures = detector.cache.iter().filter_map(|entry| { - let (token, (instant, _)) = entry.pair(); - let (token, instant) = (*token, *instant); - if start.saturating_duration_since(instant) < prefetch_time_to_expire { - return None; - } - let detector = detector.clone(); - Some(async move { - match detector.inner.detect(token).await { - Ok(result) => Some((token, result)), - Err(err) => { - tracing::warn!( - ?token, - ?err, - "unable to determine token quality in the background task" - ); - None - } - } - }) - }); - - let results = join_all(futures).await; - detector.insert_many_into_cache(results.into_iter().flatten()); - - let remaining_sleep = maintenance_timeout.saturating_sub(start.elapsed()); - tokio::time::sleep(remaining_sleep).await; - } - }); - } -} - -#[cfg(test)] -mod tests { - use {super::*, crate::bad_token::MockBadTokenDetecting, futures::FutureExt}; - - #[tokio::test] - async fn goes_to_cache() { - // Would panic if called twice. - let mut inner = MockBadTokenDetecting::new(); - inner - .expect_detect() - .times(1) - .returning(|_| Ok(TokenQuality::Good)); - - let detector = CachingDetector::new( - Box::new(inner), - Duration::from_secs(1), - Duration::from_millis(200), - ); - - for _ in 0..2 { - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(result.unwrap().is_good()); - } - } - - #[tokio::test] - async fn cache_expires() { - let inner = MockBadTokenDetecting::new(); - let token = Address::with_last_byte(0); - let detector = CachingDetector::new( - Box::new(inner), - Duration::from_secs(2), - Duration::from_millis(200), - ); - let now = Instant::now(); - detector.cache.insert(token, (now, TokenQuality::Good)); - assert!( - detector - .get_from_cache(&token, now + Duration::from_secs(1)) - .is_some() - ); - assert!( - detector - .get_from_cache(&token, now + Duration::from_secs(3)) - .is_none() - ); - } - - #[tokio::test] - async fn cache_prefetch_works() { - let mut inner = MockBadTokenDetecting::new(); - // we expect it to be called twice: first time + prefetch time - let mut seq = mockall::Sequence::new(); - // First call returns Ok(TokenQuality::Good) - inner - .expect_detect() - .times(1) - .in_sequence(&mut seq) - .returning(|_| Ok(TokenQuality::Good)); - // Second call returns Ok(TokenQuality::Bad) - inner - .expect_detect() - .times(1) - .in_sequence(&mut seq) - .returning(|_| { - Ok(TokenQuality::Bad { - reason: "bad token".to_string(), - }) - }); - - let detector = CachingDetector::new( - Box::new(inner), - Duration::from_millis(200), - Duration::from_millis(50), - ); - - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(result.unwrap().is_good()); - // Check that the result is the same because we haven't reached the prefetch - // time yet - tokio::time::sleep(Duration::from_millis(100)).await; - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(result.unwrap().is_good()); - // We wait so the prefetch fetches the data - tokio::time::sleep(Duration::from_millis(70)).await; - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(!result.unwrap().is_good()); - } -} diff --git a/crates/shared/src/bad_token/instrumented.rs b/crates/shared/src/bad_token/instrumented.rs deleted file mode 100644 index d6a876b406..0000000000 --- a/crates/shared/src/bad_token/instrumented.rs +++ /dev/null @@ -1,73 +0,0 @@ -use { - super::{BadTokenDetecting, TokenQuality}, - alloy::primitives::Address, - anyhow::Result, - prometheus::IntCounterVec, - prometheus_metric_storage::MetricStorage, - tracing::Instrument, -}; - -pub trait InstrumentedBadTokenDetectorExt { - fn instrumented(self) -> InstrumentedBadTokenDetector; -} - -impl InstrumentedBadTokenDetectorExt for T { - fn instrumented(self) -> InstrumentedBadTokenDetector { - InstrumentedBadTokenDetector { - inner: Box::new(self), - } - } -} - -#[derive(MetricStorage, Clone, Debug)] -#[metric(subsystem = "token_quality")] -struct Metrics { - /// Tracks how many token detections result in good or bad token quality or - /// an error. - #[metric(labels("quality"))] - results: IntCounterVec, -} - -pub struct InstrumentedBadTokenDetector { - inner: Box, -} - -#[async_trait::async_trait] -impl BadTokenDetecting for InstrumentedBadTokenDetector { - async fn detect(&self, token: Address) -> Result { - let result = self - .inner - .detect(token) - .instrument(tracing::info_span!( - "token_quality", - token = format!("{token:#x}") - )) - .await; - - let label = match &result { - Ok(TokenQuality::Good) => "good", - // prometheus isn't very good for string based data so we simply log the bad - // tokens/errors and get the information from Kibana when we need it. - Err(err) => { - tracing::warn!( - "bad token detection for {:?} returned error:\n{:?}", - token, - err - ); - "error" - } - Ok(quality @ TokenQuality::Bad { .. }) => { - tracing::debug!("bad token detection for {:?} returned {:?}", token, quality); - "bad" - } - }; - - Metrics::instance(observe::metrics::get_storage_registry()) - .expect("unexpected error getting metrics instance") - .results - .with_label_values(&[label]) - .inc(); - - result - } -} diff --git a/crates/shared/src/bad_token/list_based.rs b/crates/shared/src/bad_token/list_based.rs deleted file mode 100644 index 9731716b0f..0000000000 --- a/crates/shared/src/bad_token/list_based.rs +++ /dev/null @@ -1,146 +0,0 @@ -use { - super::{BadTokenDetecting, TokenQuality}, - alloy::primitives::Address, - anyhow::Result, - std::sync::Arc, - tracing::instrument, -}; - -/// If a token is neither in the allow nor the deny list treat it this way. -pub enum UnknownTokenStrategy { - Allow, - Deny, - Forward(Arc), -} - -/// Classify tokens with explicit allow and deny lists. -pub struct ListBasedDetector { - allow_list: Vec
, - deny_list: Vec
, - strategy: UnknownTokenStrategy, -} - -impl ListBasedDetector { - /// Panics if same token is both allowed and denied. - pub fn new( - allow_list: Vec
, - deny_list: Vec
, - strategy: UnknownTokenStrategy, - ) -> Self { - assert!( - allow_list.iter().all(|token| !deny_list.contains(token)), - "token is allowed and denied" - ); - Self { - allow_list, - deny_list, - strategy, - } - } - - pub fn deny_list(list: Vec
) -> Self { - Self { - allow_list: Vec::new(), - deny_list: list, - strategy: UnknownTokenStrategy::Allow, - } - } -} - -#[async_trait::async_trait] -impl BadTokenDetecting for ListBasedDetector { - #[instrument(skip_all)] - async fn detect(&self, token: Address) -> Result { - if self.allow_list.contains(&token) { - return Ok(TokenQuality::Good); - } - - if self.deny_list.contains(&token) { - return Ok(TokenQuality::Bad { - reason: "token is explicitly deny listed".to_string(), - }); - } - - match &self.strategy { - UnknownTokenStrategy::Allow => Ok(TokenQuality::Good), - UnknownTokenStrategy::Deny => Ok(TokenQuality::Bad { - reason: "token is not allow listed".to_string(), - }), - UnknownTokenStrategy::Forward(inner) => inner.detect(token).await, - } - } -} - -#[cfg(test)] -mod tests { - use {super::*, crate::bad_token::MockBadTokenDetecting, futures::FutureExt}; - - #[test] - fn uses_lists() { - // Would panic if used. - let inner = MockBadTokenDetecting::new(); - let detector = ListBasedDetector { - allow_list: vec![Address::with_last_byte(0)], - deny_list: vec![Address::with_last_byte(1)], - strategy: UnknownTokenStrategy::Forward(Arc::new(inner)), - }; - - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(result.unwrap().is_good()); - - let result = detector - .detect(Address::with_last_byte(1)) - .now_or_never() - .unwrap(); - assert!(!result.unwrap().is_good()); - } - - #[test] - fn not_in_list_default() { - let detector = ListBasedDetector { - allow_list: Vec::new(), - deny_list: Vec::new(), - strategy: UnknownTokenStrategy::Allow, - }; - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(result.unwrap().is_good()); - - let detector = ListBasedDetector { - allow_list: Vec::new(), - deny_list: Vec::new(), - strategy: UnknownTokenStrategy::Deny, - }; - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(!result.unwrap().is_good()); - } - - #[test] - fn not_in_list_forwards() { - let mut inner = MockBadTokenDetecting::new(); - inner - .expect_detect() - .times(1) - .returning(|_| Ok(TokenQuality::Good)); - - let detector = ListBasedDetector { - allow_list: Vec::new(), - deny_list: Vec::new(), - strategy: UnknownTokenStrategy::Forward(Arc::new(inner)), - }; - - let result = detector - .detect(Address::with_last_byte(0)) - .now_or_never() - .unwrap(); - assert!(result.unwrap().is_good()); - } -} diff --git a/crates/shared/src/bad_token/token_owner_finder/blockscout.rs b/crates/shared/src/bad_token/token_owner_finder/blockscout.rs deleted file mode 100644 index 9dec687e05..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/blockscout.rs +++ /dev/null @@ -1,172 +0,0 @@ -use { - super::TokenOwnerProposing, - anyhow::Result, - chain::Chain, - ethcontract::H160, - prometheus::IntCounterVec, - prometheus_metric_storage::MetricStorage, - rate_limit::{RateLimiter, Strategy, back_off}, - reqwest::{Client, Url}, - serde::Deserialize, -}; - -pub struct BlockscoutTokenOwnerFinder { - client: Client, - base: Url, - api_key: Option, - rate_limiter: Option, -} - -impl BlockscoutTokenOwnerFinder { - pub fn with_network(client: Client, chain: &Chain) -> Result { - let base_url = match chain { - Chain::Mainnet => "https://eth.blockscout.com/api", - Chain::Goerli => "https://eth-goerli.blockscout.com/api", - Chain::Gnosis => "https://blockscout.com/xdai/mainnet/api", - Chain::Sepolia => "https://eth-sepolia.blockscout.com/api", - Chain::ArbitrumOne => "https://arbitrum.blockscout.com/api", - Chain::Base => "https://base.blockscout.com/api", - _ => anyhow::bail!("Chain not supported"), - }; - - Ok(Self { - client, - base: Url::parse(base_url)?, - api_key: None, - rate_limiter: None, - }) - } - - pub fn with_base_url(&mut self, base_url: Url) -> &mut Self { - self.base = base_url; - self - } - - pub fn with_api_key(&mut self, api_key: String) -> &mut Self { - self.api_key = Some(api_key); - self - } - - pub fn with_rate_limiter(&mut self, strategy: Strategy) -> &mut Self { - self.rate_limiter = Some(RateLimiter::from_strategy( - strategy, - "blockscout".to_owned(), - )); - self - } - - async fn query_owners(&self, token: H160) -> Result> { - let mut url = self.base.clone(); - url.query_pairs_mut() - .append_pair("module", "token") - .append_pair("action", "getTokenHolders") - .append_pair("contractaddress", &format!("{token:#x}")); - - // Don't log the API key! - tracing::debug!(%url, "Querying Blockscout API"); - - if let Some(api_key) = &self.api_key { - url.query_pairs_mut().append_pair("apikey", api_key); - } - - let request = self.client.get(url).send(); - let response = match &self.rate_limiter { - Some(limiter) => limiter.execute(request, back_off::on_http_429).await??, - _ => request.await?, - }; - let status = response.status(); - let status_result = response.error_for_status_ref().map(|_| ()); - let body = response.text().await?; - - tracing::debug!(%status, %body, "Response from Blockscout API"); - - status_result?; - let parsed = serde_json::from_str::(&body)?; - - // We technically only need one candidate, returning the top 2 in case there is - // a race condition and tokens have just been transferred out - Ok(parsed - .result - .into_iter() - .map(|owner| owner.address) - .take(2) - .collect()) - } -} - -#[derive(Deserialize)] -struct Response { - result: Vec, -} - -#[derive(Deserialize)] -struct TokenOwner { - address: H160, -} - -#[derive(MetricStorage, Clone, Debug)] -#[metric(subsystem = "blockscout_token_owner_finding")] -struct Metrics { - /// Tracks number of "ok" or "err" responses from blockscout. - #[metric(labels("result"))] - results: IntCounterVec, -} - -#[async_trait::async_trait] -impl TokenOwnerProposing for BlockscoutTokenOwnerFinder { - async fn find_candidate_owners(&self, token: H160) -> Result> { - let metric = &Metrics::instance(observe::metrics::get_storage_registry()) - .unwrap() - .results; - - match self.query_owners(token).await { - Ok(ok) => { - metric.with_label_values(&["ok"]).inc(); - Ok(ok) - } - Err(err) => { - tracing::warn!(?err, "error finding token owners with Blockscout"); - metric.with_label_values(&["err"]).inc(); - Err(err) - } - } - } -} - -#[cfg(test)] -mod tests { - use {super::*, hex_literal::hex}; - - #[tokio::test] - #[ignore] - async fn test_blockscout_token_finding_mainnet() { - let finder = - BlockscoutTokenOwnerFinder::with_network(Client::default(), &Chain::Mainnet).unwrap(); - let owners = finder - .find_candidate_owners(H160(hex!("1337BedC9D22ecbe766dF105c9623922A27963EC"))) - .await; - assert!(!owners.unwrap().is_empty()); - } - - #[tokio::test] - #[ignore] - async fn test_blockscout_token_finding_xdai() { - let finder = - BlockscoutTokenOwnerFinder::with_network(Client::default(), &Chain::Gnosis).unwrap(); - let owners = finder - .find_candidate_owners(H160(hex!("1337BedC9D22ecbe766dF105c9623922A27963EC"))) - .await; - assert!(!owners.unwrap().is_empty()); - } - - #[tokio::test] - #[ignore] - async fn test_blockscout_token_finding_no_owners() { - let finder = - BlockscoutTokenOwnerFinder::with_network(Client::default(), &Chain::Gnosis).unwrap(); - let owners = finder - .find_candidate_owners(H160(hex!("000000000000000000000000000000000000def1"))) - .await; - assert!(owners.unwrap().is_empty()); - } -} diff --git a/crates/shared/src/bad_token/token_owner_finder/ethplorer.rs b/crates/shared/src/bad_token/token_owner_finder/ethplorer.rs deleted file mode 100644 index 1bf6f90ae7..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/ethplorer.rs +++ /dev/null @@ -1,179 +0,0 @@ -use { - super::TokenOwnerProposing, - anyhow::{Result, ensure}, - chain::Chain, - ethcontract::H160, - prometheus::IntCounterVec, - prometheus_metric_storage::MetricStorage, - rate_limit::{RateLimiter, Strategy, back_off}, - reqwest::{Client, StatusCode, Url}, - serde::Deserialize, -}; - -const BASE: &str = "https://api.ethplorer.io"; -const FREE_API_KEY: &str = "freekey"; - -pub struct EthplorerTokenOwnerFinder { - client: Client, - base: Url, - api_key: String, - - /// The low tiers for Ethplorer have very aggressive rate limiting, so be - /// sure to setup a rate limiter for Ethplorer requests. - rate_limiter: Option, - - metrics: &'static Metrics, -} - -impl EthplorerTokenOwnerFinder { - pub fn try_with_network( - client: Client, - api_key: Option, - chain: &Chain, - ) -> Result { - ensure!( - *chain == Chain::Mainnet, - "Ethplorer API unsupported network" - ); - Ok(Self { - client, - base: Url::try_from(BASE).unwrap(), - api_key: api_key.unwrap_or_else(|| FREE_API_KEY.to_owned()), - rate_limiter: None, - metrics: Metrics::instance(observe::metrics::get_storage_registry())?, - }) - } - - pub fn with_base_url(&mut self, base_url: Url) -> &mut Self { - self.base = base_url; - self - } - - pub fn with_rate_limiter(&mut self, strategy: Strategy) -> &mut Self { - self.rate_limiter = Some(RateLimiter::from_strategy(strategy, "ethplorer".to_owned())); - self - } - - async fn query_owners(&self, token: H160) -> Result> { - let mut url = crate::url::join(&self.base, &format!("getTopTokenHolders/{token:?}")); - // We technically only need one candidate, returning the top 2 in case there - // is a race condition and tokens have just been transferred out. - url.query_pairs_mut().append_pair("limit", "2"); - - tracing::debug!(%url, "querying Ethplorer"); - // Don't log the API key! - url.query_pairs_mut().append_pair("apiKey", &self.api_key); - - let request = self.client.get(url).send(); - let response = match &self.rate_limiter { - Some(limiter) => limiter.execute(request, back_off::on_http_429).await??, - _ => request.await?, - }; - - let status = response.status(); - let status_result = response.error_for_status_ref().map(|_| ()); - let body = response.text().await?; - - tracing::debug!(%status, %body, "response from Ethplorer API"); - - // We need some special handling for "not a token contract" errors. In - // this case, we just want to return an empty token holder list to conform - // to the expectations of the `TokenHolderProposing` trait. - if status == StatusCode::BAD_REQUEST { - let err = serde_json::from_str::(&body)?; - if err.not_token_contract() { - return Ok(Default::default()); - } - } - status_result?; - - let parsed = serde_json::from_str::(&body)?; - - Ok(parsed - .holders - .into_iter() - .map(|holder| holder.address) - .collect()) - } -} - -#[derive(Deserialize)] -struct Response { - holders: Vec, -} - -#[derive(Deserialize)] -struct Holder { - address: H160, -} - -#[derive(Deserialize)] -struct Error { - error: ErrorData, -} - -#[derive(Deserialize)] -struct ErrorData { - code: i64, -} - -impl Error { - fn not_token_contract(&self) -> bool { - // https://github.com/EverexIO/Ethplorer/wiki/Ethplorer-API#error-codes - self.error.code == 150 - } -} - -#[derive(MetricStorage, Clone, Debug)] -#[metric(subsystem = "ethplorer_token_owner_finding")] -struct Metrics { - /// Tracks number of "ok" or "err" responses from ethplorer. - #[metric(labels("result"))] - results: IntCounterVec, -} - -#[async_trait::async_trait] -impl TokenOwnerProposing for EthplorerTokenOwnerFinder { - async fn find_candidate_owners(&self, token: H160) -> Result> { - let metric = &self.metrics.results; - let result = self.query_owners(token).await; - match &result { - Ok(_) => metric.with_label_values(&["ok"]).inc(), - Err(err) => { - tracing::warn!(?err, "error finding token owners with Ethplorer"); - metric.with_label_values(&["err"]).inc(); - } - } - - result - } -} - -#[cfg(test)] -mod tests { - use {super::*, hex_literal::hex}; - - #[tokio::test] - #[ignore] - async fn token_finding_mainnet() { - let finder = - EthplorerTokenOwnerFinder::try_with_network(Client::default(), None, &Chain::Mainnet) - .unwrap(); - let owners = finder - .find_candidate_owners(H160(hex!("1337BedC9D22ecbe766dF105c9623922A27963EC"))) - .await; - assert!(!owners.unwrap().is_empty()); - } - - #[tokio::test] - #[ignore] - async fn returns_no_owners_on_invalid_token() { - let finder = - EthplorerTokenOwnerFinder::try_with_network(Client::default(), None, &Chain::Gnosis) - .unwrap(); - let owners = finder - .find_candidate_owners(H160(hex!("000000000000000000000000000000000000def1"))) - .await; - assert!(owners.unwrap().is_empty()); - } -} diff --git a/crates/shared/src/bad_token/token_owner_finder/liquidity.rs b/crates/shared/src/bad_token/token_owner_finder/liquidity.rs deleted file mode 100644 index 34a633821e..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/liquidity.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! Module containing liquidity-based token owner finding implementations. - -use { - super::TokenOwnerProposing, - crate::sources::{uniswap_v2::pair_provider::PairProvider, uniswap_v3_pair_provider}, - alloy::eips::BlockNumberOrTag, - anyhow::Result, - contracts::alloy::{BalancerV2Vault, IUniswapV3Factory}, - ethcontract::H160, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - model::TokenPair, -}; - -pub struct UniswapLikePairProviderFinder { - pub inner: PairProvider, - pub base_tokens: Vec, -} - -#[async_trait::async_trait] -impl TokenOwnerProposing for UniswapLikePairProviderFinder { - async fn find_candidate_owners(&self, token: H160) -> Result> { - Ok(self - .base_tokens - .iter() - .filter_map(|base_token| TokenPair::new(base_token.into_alloy(), token.into_alloy())) - .map(|pair| self.inner.pair_address(&pair)) - .collect()) - } -} - -/// The balancer vault contract contains all the balances of all pools. -pub struct BalancerVaultFinder(pub BalancerV2Vault::Instance); - -#[async_trait::async_trait] -impl TokenOwnerProposing for BalancerVaultFinder { - async fn find_candidate_owners(&self, _: H160) -> Result> { - Ok(vec![self.0.address().into_legacy()]) - } -} - -pub struct UniswapV3Finder { - pub factory: IUniswapV3Factory::Instance, - pub base_tokens: Vec, - fee_values: Vec, -} - -#[derive(Debug, Clone, Copy, clap::ValueEnum)] -pub enum FeeValues { - /// Use hardcoded list - Static, - /// Fetch on creation based on events queried from node. - /// Some nodes struggle with the request and take a long time to respond - /// leading to timeouts. - Dynamic, -} - -impl UniswapV3Finder { - pub async fn new( - factory: IUniswapV3Factory::Instance, - base_tokens: Vec, - fee_values: FeeValues, - ) -> Result { - let fee_values = match fee_values { - FeeValues::Static => vec![500, 3000, 10000, 100], - // We fetch these once at start up because we don't expect them to change often. - // Alternatively could use a time based cache. - FeeValues::Dynamic => Self::fee_values(&factory).await?, - }; - tracing::debug!(?fee_values); - Ok(Self { - factory, - base_tokens, - fee_values, - }) - } - - // Possible fee values as given by - // https://github.com/Uniswap/v3-core/blob/9161f9ae4aaa109f7efdff84f1df8d4bc8bfd042/contracts/UniswapV3Factory.sol#L26 - async fn fee_values(factory: &IUniswapV3Factory::Instance) -> Result> { - // We expect there to be few of these kind of events (currently there are 4) so - // fetching all of them is fine. Alternatively we could index these - // events in the database. - let events = factory - .FeeAmountEnabled_filter() - .from_block(BlockNumberOrTag::Earliest) - .to_block(BlockNumberOrTag::Latest) - .query() - .await?; - let fee_values = events - .into_iter() - .map(|(enabled, _)| { - enabled - .fee - .try_into() - .expect("uint24 always fits inside u32") - }) - .collect(); - Ok(fee_values) - } -} - -#[async_trait::async_trait] -impl TokenOwnerProposing for UniswapV3Finder { - async fn find_candidate_owners(&self, token: H160) -> Result> { - Ok(self - .base_tokens - .iter() - .filter_map(|base_token| TokenPair::new(base_token.into_alloy(), token.into_alloy())) - .flat_map(|pair| self.fee_values.iter().map(move |fee| (pair, *fee))) - .map(|(pair, fee)| { - uniswap_v3_pair_provider::pair_address( - &self.factory.address().into_legacy(), - &pair, - fee, - ) - }) - .collect()) - } -} diff --git a/crates/shared/src/bad_token/token_owner_finder/mod.rs b/crates/shared/src/bad_token/token_owner_finder/mod.rs deleted file mode 100644 index 9282789fb3..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/mod.rs +++ /dev/null @@ -1,585 +0,0 @@ -pub mod blockscout; -pub mod ethplorer; -pub mod liquidity; -pub mod solvers; -pub mod token_owner_list; - -use { - self::{ - blockscout::BlockscoutTokenOwnerFinder, - liquidity::{ - BalancerVaultFinder, - FeeValues, - UniswapLikePairProviderFinder, - UniswapV3Finder, - }, - }, - crate::{ - arguments::{display_list, display_option, display_secret_option}, - bad_token::token_owner_finder::{ - ethplorer::EthplorerTokenOwnerFinder, - solvers::{ - solver_api::SolverConfiguration, - solver_finder::AutoUpdatingSolverTokenOwnerFinder, - }, - token_owner_list::TokenOwnerList, - }, - baseline_solver::BaseTokens, - ethrpc::{MAX_BATCH_SIZE, Web3}, - http_client::HttpClientFactory, - sources::uniswap_v2::pair_provider::PairProvider, - }, - anyhow::{Context, Result}, - chain::Chain, - contracts::alloy::{BalancerV2Vault, ERC20, IUniswapV3Factory}, - ethcontract::U256, - ethrpc::alloy::{ - conversions::{IntoAlloy, IntoLegacy}, - errors::ContractErrorExt, - }, - futures::{Stream, StreamExt as _}, - primitive_types::H160, - rate_limit::Strategy, - reqwest::Url, - std::{ - collections::HashMap, - fmt::{self, Display, Formatter}, - sync::Arc, - time::Duration, - }, -}; - -/// This trait abstracts various sources for proposing token owner candidates -/// which are likely, but not guaranteed, to have some token balance. -#[async_trait::async_trait] -pub trait TokenOwnerProposing: Send + Sync { - /// Find candidate addresses that might own the token. - async fn find_candidate_owners(&self, token: H160) -> Result>; -} - -/// To detect bad tokens we need to find some address on the network that owns -/// the token so that we can use it in our simulations. -#[async_trait::async_trait] -pub trait TokenOwnerFinding: Send + Sync { - /// Find an addresses with at least `min_balance` of tokens and return it, - /// along with its actual balance. - async fn find_owner(&self, token: H160, min_balance: U256) -> Result>; -} - -/// Arguments related to the token owner finder. -#[derive(clap::Parser)] -#[group(skip)] -pub struct Arguments { - /// The token owner finding strategies to use. - #[clap(long, env, use_value_delimiter = true, value_enum)] - pub token_owner_finders: Option>, - - /// The fee value strategy to use for locating Uniswap V3 pools as token - /// holders for bad token detection. - #[clap(long, env, default_value = "static", value_enum)] - pub token_owner_finder_uniswap_v3_fee_values: FeeValues, - - /// The blockscout configuration. - #[clap(flatten)] - pub blockscout: Option, - - /// The ethplorer configuration. - #[clap(flatten)] - pub ethplorer: Option, - - /// Token owner finding rate limiting strategy. See - /// --price-estimation-rate-limiter documentation for format details. - #[clap(long, env)] - pub token_owner_finder_rate_limiter: Option, - - /// List of token addresses to be whitelisted as a potential token owners - /// For each token a list of owners is defined. - #[clap( - long, - env, - value_parser = parse_owners, - default_value = "", - )] - pub whitelisted_owners: HashMap>, - - /// The solvers urls to query the token owner pairs. - #[clap(long, env, use_value_delimiter = true)] - pub solver_token_owners_urls: Vec, - - /// Interval in seconds between consecutive queries to update the solver - /// token owner pairs. Values should be in pair with - /// `solver_token_owners_urls` - #[clap(long, env, use_value_delimiter = true, value_parser = humantime::parse_duration)] - pub solver_token_owners_cache_update_intervals: Vec, -} - -#[derive(clap::Parser)] -#[clap(group( - clap::ArgGroup::new("blockscout") - .requires_all(&[ - "blockscout_api_url", - "blockscout_api_key", - ]) - .multiple(true) - .required(false), -))] -pub struct Blockscout { - /// Override the default blockscout API url for this network - #[clap(long, env, group = "blockscout", required = false)] - pub blockscout_api_url: Url, - - /// The blockscout API key. - #[clap(long, env, group = "blockscout", required = false)] - pub blockscout_api_key: String, -} - -#[derive(clap::Parser)] -#[clap(group( - clap::ArgGroup::new("ethplorer") - .requires_all(&[ - "ethplorer_api_url", - "ethplorer_api_key", - ]) - .multiple(true) - .required(false), -))] -pub struct Ethplorer { - /// Override the default ethplorer API url - #[clap(long, env, group = "ethplorer", required = false)] - pub ethplorer_api_url: Url, - - /// The Ethplorer token holder API key. - #[clap(long, env, group = "ethplorer", required = false)] - pub ethplorer_api_key: String, -} - -fn parse_owners(s: &str) -> Result>> { - if s.is_empty() { - return Ok(Default::default()); - } - s.split(';') - .map(|pair_str| { - let (key, values) = pair_str - .split_once(':') - .context("missing token and owners")?; - let key = key.trim().parse()?; - let values = values - .trim() - .split(',') - .map(|value| value.trim().parse().context("failed to parse token owner")) - .collect::>()?; - Ok((key, values)) - }) - .collect() -} - -/// Support token owner finding strategies. -#[derive(Clone, Copy, Debug, Eq, PartialEq, clap::ValueEnum)] -pub enum TokenOwnerFindingStrategy { - /// Using baseline liquidity pools as token owners. - /// - /// The actual liquidity pools used depends on the configured baseline - /// liquidity. - Liquidity, - - /// Use the Blockscout token holder API to find token holders. - Blockscout, - - /// Use the Ethplorer token holder API. - Ethplorer, - - /// Use lists provided by the external solver teams - Solvers, -} - -impl TokenOwnerFindingStrategy { - /// Returns the default set of token owner finding strategies. - pub fn defaults_for_network(chain: &Chain) -> &'static [Self] { - match chain { - Chain::Mainnet => &[Self::Liquidity, Self::Blockscout, Self::Ethplorer], - Chain::Gnosis => &[Self::Liquidity, Self::Blockscout], - Chain::Sepolia - | Chain::Goerli - | Chain::ArbitrumOne - | Chain::Base - | Chain::Bnb - | Chain::Optimism - | Chain::Avalanche - | Chain::Polygon - | Chain::Linea - | Chain::Plasma - | Chain::Lens => &[Self::Liquidity], - Chain::Hardhat => panic!("unsupported chain for token owner finding"), - } - } -} - -impl Display for Arguments { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Self { - token_owner_finders, - token_owner_finder_uniswap_v3_fee_values, - blockscout, - ethplorer, - token_owner_finder_rate_limiter, - whitelisted_owners, - solver_token_owners_urls, - solver_token_owners_cache_update_intervals, - } = self; - - writeln!(f, "token_owner_finders: {token_owner_finders:?}")?; - writeln!( - f, - "token_owner_finder_uniswap_v3_fee_values: \ - {token_owner_finder_uniswap_v3_fee_values:?}" - )?; - display_option( - f, - "blockscout_api_url", - &blockscout - .as_ref() - .map(|blockscout| blockscout.blockscout_api_url.clone()), - )?; - display_secret_option( - f, - "blockscout_api_key", - blockscout - .as_ref() - .map(|blockscout| blockscout.blockscout_api_key.clone()) - .as_ref(), - )?; - display_option( - f, - "ethplorer_api_url", - ðplorer - .as_ref() - .map(|blockscout| blockscout.ethplorer_api_url.clone()) - .as_ref(), - )?; - display_secret_option( - f, - "ethplorer_api_key", - ethplorer - .as_ref() - .map(|blockscout| blockscout.ethplorer_api_key.clone()) - .as_ref(), - )?; - display_option( - f, - "token_owner_finder_rate_limiter", - token_owner_finder_rate_limiter, - )?; - writeln!(f, "whitelisted_owners, {whitelisted_owners:?}")?; - display_list(f, "solver_token_owners_urls", solver_token_owners_urls)?; - writeln!( - f, - "solver_token_owners_cache_update_intervals, \ - {solver_token_owners_cache_update_intervals:?}" - )?; - Ok(()) - } -} - -/// Initializes a set of token owner finders. -#[expect(clippy::too_many_arguments)] -pub async fn init( - args: &Arguments, - web3: Web3, - chain: &Chain, - http_factory: &HttpClientFactory, - pair_providers: &[PairProvider], - vault: Option<&BalancerV2Vault::Instance>, - uniswapv3_factory: Option<&IUniswapV3Factory::Instance>, - base_tokens: &BaseTokens, - settlement_contract: H160, -) -> Result> { - let web3 = ethrpc::instrumented::instrument_with_label(&web3, "tokenOwners".into()); - let finders = args - .token_owner_finders - .as_deref() - .unwrap_or_else(|| TokenOwnerFindingStrategy::defaults_for_network(chain)); - tracing::debug!(?finders, "initializing token owner finders"); - - let mut proposers = Vec::>::new(); - - if finders.contains(&TokenOwnerFindingStrategy::Liquidity) { - proposers.extend( - pair_providers - .iter() - .map(|provider| -> Arc { - Arc::new(UniswapLikePairProviderFinder { - inner: *provider, - base_tokens: base_tokens.tokens().iter().copied().collect(), - }) - }), - ); - if let Some(contract) = vault { - proposers.push(Arc::new(BalancerVaultFinder(contract.clone()))); - } - if let Some(contract) = uniswapv3_factory { - proposers.push(Arc::new( - UniswapV3Finder::new( - contract.clone(), - base_tokens.tokens().iter().copied().collect(), - args.token_owner_finder_uniswap_v3_fee_values, - ) - .await?, - )); - } - } - - if finders.contains(&TokenOwnerFindingStrategy::Blockscout) { - let mut blockscout = - BlockscoutTokenOwnerFinder::with_network(http_factory.create(), chain)?; - if let Some(blockscout_config) = &args.blockscout { - blockscout.with_base_url(blockscout_config.blockscout_api_url.clone()); - blockscout.with_api_key(blockscout_config.blockscout_api_key.clone()); - } - if let Some(strategy) = args.token_owner_finder_rate_limiter.clone() { - blockscout.with_rate_limiter(strategy); - } - proposers.push(Arc::new(blockscout)); - } - - if finders.contains(&TokenOwnerFindingStrategy::Ethplorer) { - let mut ethplorer = EthplorerTokenOwnerFinder::try_with_network( - http_factory.create(), - args.ethplorer - .as_ref() - .map(|ethplorer| ethplorer.ethplorer_api_key.clone()), - chain, - )?; - if let Some(ethplorer_config) = &args.ethplorer { - ethplorer.with_base_url(ethplorer_config.ethplorer_api_url.clone()); - } - if let Some(strategy) = args.token_owner_finder_rate_limiter.clone() { - ethplorer.with_rate_limiter(strategy); - } - proposers.push(Arc::new(ethplorer)); - } - - if finders.contains(&TokenOwnerFindingStrategy::Solvers) { - for (url, update_interval) in args - .solver_token_owners_urls - .clone() - .into_iter() - .zip(args.solver_token_owners_cache_update_intervals.clone()) - { - let identifier = url.to_string(); - let solver = Box::new(SolverConfiguration { - url, - client: http_factory.create(), - }); - let solver = - AutoUpdatingSolverTokenOwnerFinder::new(solver, update_interval, identifier); - proposers.push(Arc::new(solver)); - } - } - - proposers.push(Arc::new(TokenOwnerList::new( - args.whitelisted_owners.clone(), - ))); - - Ok(Arc::new(TokenOwnerFinder { - web3, - proposers, - settlement_contract, - })) -} - -/// A `TokenOwnerFinding` implementation that queries a node with proposed owner -/// candidates from an internal list of `TokenOwnerProposing` implementations. -pub struct TokenOwnerFinder { - pub web3: Web3, - pub proposers: Vec>, - pub settlement_contract: H160, -} - -impl TokenOwnerFinder { - /// Stream of addresses that might own the token. - fn candidate_owners(&self, token: H160) -> impl Stream + '_ { - // Combine the results of all finders into a single stream. - let streams = self.proposers.iter().map(|finder| { - futures::stream::once(finder.find_candidate_owners(token)) - .filter_map(|result| async { - match result { - Ok(inner) => Some(futures::stream::iter(inner)), - Err(err) => { - tracing::warn!(?err, "token owner proposing failed"); - None - } - } - }) - .flatten() - .boxed() - }); - futures::stream::select_all(streams) - } -} - -#[async_trait::async_trait] -impl TokenOwnerFinding for TokenOwnerFinder { - async fn find_owner(&self, token: H160, min_balance: U256) -> Result> { - let instance = ERC20::Instance::new(token.into_alloy(), self.web3.alloy.clone()); - - // We use a stream with ready_chunks so that we can start with the addresses of - // fast TokenOwnerFinding implementations first without having to wait - // for slow ones. - let stream = self.candidate_owners(token).ready_chunks(MAX_BATCH_SIZE); - futures::pin_mut!(stream); - - while let Some(chunk) = stream.next().await { - let futures = chunk - .into_iter() - // The token balance assertions of the bad token test assume the token - // owner is not the settlement contract. - .filter(|owner| *owner != self.settlement_contract) - .map(|owner| { - let balance = instance.balanceOf(owner.into_alloy()); - async move { - match balance.call().await { - Ok(balance) => Ok((owner, balance)), - Err(err) if err.is_contract_error() => { - Ok((owner, alloy::primitives::U256::ZERO)) - } - Err(err) => Err(err), - } - } - }); - let balances = futures::future::try_join_all(futures).await?; - - if let Some((addr, balance)) = balances - .into_iter() - .find(|(_, balance)| *balance >= min_balance.into_alloy()) - { - return Ok(Some((addr, balance.into_legacy()))); - } - } - - Ok(None) - } -} - -#[cfg(test)] -mod test { - use {super::*, clap::Parser}; - - const TOKEN1: H160 = addr!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); - const TOKEN2: H160 = addr!("7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"); - const OWNER1: H160 = addr!("06920c9fc643de77b99cb7670a944ad31eaaa260"); - const OWNER2: H160 = addr!("06601571aa9d3e8f5f7cdd5b993192618964bab5"); - - #[test] - fn parse_owners_empty() { - assert_eq!(parse_owners("").unwrap(), Default::default()); - } - - #[test] - fn parse_owners_one_owner() { - let mut expected = HashMap::new(); - expected.insert(TOKEN1, vec![OWNER1]); - let parsed = parse_owners( - " - 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2: - 0x06920c9fc643de77b99cb7670a944ad31eaaa260 - ", - ) - .unwrap(); - assert_eq!(parsed, expected); - } - - #[test] - fn parse_owners_two_owners() { - let mut expected = HashMap::new(); - expected.insert(TOKEN1, vec![OWNER1, OWNER2]); - let parsed = parse_owners( - " - 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2: - 0x06920c9fc643de77b99cb7670a944ad31eaaa260, - 0x06601571aa9d3e8f5f7cdd5b993192618964bab5 - ", - ) - .unwrap(); - assert_eq!(parsed, expected); - } - - #[test] - fn parse_owners_two_tokens_with_one_owners() { - let mut expected = HashMap::new(); - expected.insert(TOKEN1, vec![OWNER1]); - expected.insert(TOKEN2, vec![OWNER2]); - let parsed = parse_owners( - " - 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2: - 0x06920c9fc643de77b99cb7670a944ad31eaaa260; - 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9: - 0x06601571aa9d3e8f5f7cdd5b993192618964bab5 - ", - ) - .unwrap(); - assert_eq!(parsed, expected); - } - - #[test] - fn parse_owners_err() { - assert!(parse_owners("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2:").is_err()); - assert!(parse_owners("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").is_err()); - assert!(parse_owners(":0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").is_err()); - } - - #[test] - fn blockscout_correctly_configured() { - let args = vec![ - "test", // Program name - "--blockscout-api-key", - "someapikey", - "--blockscout-api-url", - "https://swap.cow.fi", - ]; - - let blockscout = Blockscout::try_parse_from(args); - - assert!(blockscout.is_ok()); - } - - #[test] - fn blockscout_wrongly_configured() { - let args = vec![ - "test", // Program name - "--blockscout-api-key", - "someapikey", - ]; - - let result = Blockscout::try_parse_from(args); - - assert!(result.is_err()); - } - - #[test] - fn ethplorer_correctly_configured() { - let args = vec![ - "test", // Program name - "--ethplorer-api-key", - "someapikey", - "--ethplorer-api-url", - "https://swap.cow.fi", - ]; - - let ethplorer = Ethplorer::try_parse_from(args); - - assert!(ethplorer.is_ok()); - } - - #[test] - fn ethplorer_wrongly_configured() { - let args = vec![ - "test", // Program name - "--ethplorer-api-key", - "someapikey", - ]; - - let result = Ethplorer::try_parse_from(args); - - assert!(result.is_err()); - } -} diff --git a/crates/shared/src/bad_token/token_owner_finder/solvers/mod.rs b/crates/shared/src/bad_token/token_owner_finder/solvers/mod.rs deleted file mode 100644 index 5b1ab4983b..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/solvers/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub mod solver_api; -pub mod solver_finder; - -use {anyhow::Result, ethcontract::H160, std::collections::HashMap}; - -type Token = H160; -type Owner = H160; - -#[async_trait::async_trait] -pub trait TokenOwnerSolverApi: Send + Sync { - /// Get token owner pairs from specific solver - async fn get_token_owner_pairs(&self) -> Result>>; -} diff --git a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_api.rs b/crates/shared/src/bad_token/token_owner_finder/solvers/solver_api.rs deleted file mode 100644 index d034c5ffe3..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_api.rs +++ /dev/null @@ -1,30 +0,0 @@ -use { - super::TokenOwnerSolverApi, - anyhow::{Context, Result}, - ethcontract::H160, - reqwest::{Client, Url}, - std::collections::HashMap, -}; - -type Token = H160; -type Owner = H160; - -#[derive(Clone, Debug)] -pub struct SolverConfiguration { - pub url: Url, - pub client: Client, -} - -#[async_trait::async_trait] -impl TokenOwnerSolverApi for SolverConfiguration { - async fn get_token_owner_pairs(&self) -> Result>> { - let response = self - .client - .get(self.url.clone()) - .send() - .await? - .text() - .await?; - serde_json::from_str(&response).context(format!("bad query response: {response:?}")) - } -} diff --git a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_finder.rs b/crates/shared/src/bad_token/token_owner_finder/solvers/solver_finder.rs deleted file mode 100644 index 7ad7aee2b2..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_finder.rs +++ /dev/null @@ -1,153 +0,0 @@ -use { - super::TokenOwnerSolverApi, - crate::bad_token::token_owner_finder::TokenOwnerProposing, - anyhow::Result, - ethcontract::H160, - prometheus::{ - IntCounterVec, - core::{AtomicU64, GenericCounter}, - }, - std::{ - collections::HashMap, - fmt::{self, Debug, Formatter}, - sync::{Arc, RwLock}, - time::Duration, - }, - tracing::Instrument, -}; - -type Token = H160; -type Owner = H160; - -#[derive(Debug)] -pub struct AutoUpdatingSolverTokenOwnerFinder { - inner: Arc, -} - -#[derive(prometheus_metric_storage::MetricStorage, Clone, Debug)] -struct Metrics { - /// Tracks how often a token owner update succeeded or failed. - #[metric(labels("identifier", "result"))] - token_owner_list_updates: IntCounterVec, -} - -struct Inner { - solver: Box, - cache: RwLock>>, - metrics: &'static Metrics, - identifier: String, -} - -impl Inner { - pub fn get_update_counter(&self, success: bool) -> GenericCounter { - let result = if success { "success" } else { "failure" }; - self.metrics - .token_owner_list_updates - .with_label_values(&[&self.identifier, result]) - } -} - -impl AutoUpdatingSolverTokenOwnerFinder { - pub fn new( - solver: Box, - update_interval: Duration, - identifier: String, - ) -> Self { - let inner = Arc::new(Inner { - solver, - cache: RwLock::new(Default::default()), - metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), - identifier, - }); - - // reset metrics for consistent graphs in grafana - inner.get_update_counter(true).reset(); - inner.get_update_counter(false).reset(); - - // spawn a background task to regularly update cache - { - let inner = inner.clone(); - let updater = async move { - loop { - let result = inner.update().await; - inner.get_update_counter(result.is_ok()).inc(); - if let Err(err) = result { - tracing::warn!(?err, "failed to update token list"); - } - tokio::time::sleep(update_interval).await; - } - }; - tokio::task::spawn( - updater.instrument(tracing::info_span!("auto_updating_token_owner_finder")), - ); - } - - Self { inner } - } - - pub async fn update(&self) -> Result<()> { - self.inner.update().await - } -} - -impl Inner { - async fn update(&self) -> Result<()> { - let token_owner_pairs = self.solver.get_token_owner_pairs().await?; - - let mut cache = self.cache.write().unwrap(); - *cache = token_owner_pairs; - - Ok(()) - } -} - -impl Debug for Inner { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct("Inner").field("cache", &self.cache).finish() - } -} - -#[async_trait::async_trait] -impl TokenOwnerProposing for AutoUpdatingSolverTokenOwnerFinder { - async fn find_candidate_owners(&self, token: Token) -> Result> { - Ok(self - .inner - .cache - .read() - .unwrap() - .get(&token) - .cloned() - .unwrap_or_default()) - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::bad_token::token_owner_finder::solvers::solver_api::SolverConfiguration, - reqwest::{Client, Url}, - std::str::FromStr, - }; - - #[tokio::test] - #[ignore] - async fn seasolver_e2e_test() { - let url = std::env::var("SEASOLVER_TOKEN_HOLDERS").unwrap(); - let configuration = Box::new(SolverConfiguration { - url: Url::from_str(&url).unwrap(), - client: Client::new(), - }); - let finder = AutoUpdatingSolverTokenOwnerFinder::new( - configuration, - Duration::from_secs(1000), - "test".to_owned(), - ); - tokio::time::sleep(Duration::from_secs(10)).await; - let owners = finder - .find_candidate_owners(addr!("132d8D2C76Db3812403431fAcB00F3453Fc42125")) - .await - .unwrap(); - dbg!(owners); - } -} diff --git a/crates/shared/src/bad_token/token_owner_finder/token_owner_list.rs b/crates/shared/src/bad_token/token_owner_finder/token_owner_list.rs deleted file mode 100644 index 75eb953ea7..0000000000 --- a/crates/shared/src/bad_token/token_owner_finder/token_owner_list.rs +++ /dev/null @@ -1,47 +0,0 @@ -use {super::TokenOwnerProposing, anyhow::Result, ethcontract::H160, std::collections::HashMap}; - -type Token = H160; -type Owner = H160; - -pub struct TokenOwnerList { - owners: HashMap>, -} - -impl TokenOwnerList { - pub fn new(owners: HashMap>) -> Self { - Self { owners } - } -} - -#[async_trait::async_trait] -impl TokenOwnerProposing for TokenOwnerList { - async fn find_candidate_owners(&self, token: H160) -> Result> { - Ok(self.owners.get(&token).cloned().unwrap_or_default()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn token_owner_list_constructor_empty() { - let finder = TokenOwnerList::new(Default::default()); - let candidate_owners = finder - .find_candidate_owners(H160::from_low_u64_be(10)) - .await; - assert!(candidate_owners.unwrap().is_empty()); - } - - #[tokio::test] - async fn token_owner_list_constructor() { - let token = H160::from_low_u64_be(1); - let owners = vec![H160::from_low_u64_be(2), H160::from_low_u64_be(3)]; - let finder = TokenOwnerList::new(HashMap::from([(token, owners.clone())])); - let candidate_owners = finder - .find_candidate_owners(H160::from_low_u64_be(1)) - .await - .unwrap(); - assert_eq!(owners, candidate_owners); - } -} diff --git a/crates/shared/src/bad_token/trace_call.rs b/crates/shared/src/bad_token/trace_call.rs deleted file mode 100644 index ae8ad73018..0000000000 --- a/crates/shared/src/bad_token/trace_call.rs +++ /dev/null @@ -1,957 +0,0 @@ -use { - super::{BadTokenDetecting, TokenQuality, token_owner_finder::TokenOwnerFinding}, - crate::{ethrpc::Web3, trace_many}, - alloy::{primitives::Address, sol_types::SolCall}, - anyhow::{Context, Result, bail, ensure}, - contracts::alloy::ERC20, - ethcontract::{PrivateKey, jsonrpc::ErrorCode}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - model::interaction::InteractionData, - primitive_types::{H160, U256}, - std::{cmp, sync::Arc}, - tracing::instrument, - web3::{ - error::TransportError, - signing::keccak256, - types::{BlockTrace, Bytes, CallRequest, Res}, - }, -}; - -/// Detects whether a token is "bad" (works in unexpected ways that are -/// problematic for solving) by simulating several transfers of a token. To find -/// an initial address to transfer from we use the amm pair providers. -/// Tokens are bad if: -/// - we cannot find an amm pool of the token to one of the base tokens -/// - transfer into the settlement contract or back out fails -/// - a transfer loses total balance -pub struct TraceCallDetector { - inner: TraceCallDetectorRaw, - finder: Arc, -} - -#[async_trait::async_trait] -impl BadTokenDetecting for TraceCallDetector { - #[instrument(skip_all)] - async fn detect(&self, token: Address) -> Result { - let quality = self.detect_impl(token).await?; - tracing::debug!(?token, ?quality, "determined token quality"); - Ok(quality) - } -} - -impl TraceCallDetector { - pub fn new(web3: Web3, settlement: H160, finder: Arc) -> Self { - Self { - inner: TraceCallDetectorRaw::new(web3, settlement), - finder, - } - } - - async fn detect_impl(&self, token: Address) -> Result { - // Arbitrary amount that is large enough that small relative fees should be - // visible. - const MIN_AMOUNT: u64 = 100_000; - let (take_from, amount) = match self - .finder - .find_owner(token.into_legacy(), MIN_AMOUNT.into()) - .await - .context("find_owner")? - { - Some((address, balance)) => { - // Don't use the full balance, but instead a portion of it. This - // makes the trace call less racy and prone to the transfer - // failing because of a balance change from one block to the - // next. This can happen because of either: - // - Block propagation - the trace_callMany is handled by a node that is 1 block - // in the past - // - New block observed - the trace_callMany is executed on a block that came in - // since we read the balance - let amount = cmp::max(balance / 2, MIN_AMOUNT.into()); - - tracing::debug!(?token, ?address, ?amount, "found owner"); - (address, amount) - } - None => { - return Ok(TokenQuality::bad(format!( - "Could not find on chain source of the token with at least {MIN_AMOUNT} \ - balance.", - ))); - } - }; - self.inner - .test_transfer(take_from, token.into_legacy(), amount, &[]) - .await - } -} - -/// Detects whether a token is "bad" (works in unexpected ways that are -/// problematic for solving) by simulating several transfers of a token. -#[derive(Debug, Clone)] -pub struct TraceCallDetectorRaw { - pub web3: Web3, - pub settlement_contract: H160, -} - -impl TraceCallDetectorRaw { - pub fn new(web3: Web3, settlement: H160) -> Self { - Self { - web3, - settlement_contract: settlement, - } - } - - pub async fn test_transfer( - &self, - take_from: H160, - token: H160, - amount: U256, - pre_interactions: &[InteractionData], - ) -> Result { - let mut request: Vec<_> = pre_interactions - .iter() - .map(|i| CallRequest { - to: Some(i.target.into_legacy()), - value: Some(i.value.into_legacy()), - data: Some(Bytes(i.call_data.clone())), - ..Default::default() - }) - .collect(); - // We transfer the full available amount of the token from the amm pool into the - // settlement contract and then to an arbitrary address. - // Note that gas use can depend on the recipient because for the standard - // implementation sending to an address that does not have any balance - // yet (implicitly 0) causes an allocation. - request.append(&mut self.create_trace_request(token, amount, take_from)); - let traces = match trace_many::trace_many(request, &self.web3).await { - Ok(result) => result, - Err(e) => { - // If the node doesn't support trace calls, consider the token as good to not - // block the system - if matches!( - e, - web3::Error::Rpc(ethcontract::jsonrpc::Error { - code: ErrorCode::MethodNotFound, - .. - }) - ) || matches!( - e, - // Alchemy specific error - web3::Error::Transport(TransportError::Message(ref msg)) if msg == "HTTP error 400 Bad Request" - ) { - tracing::warn!( - error=?e, - "unable to perform trace call with configured node, assume good quality" - ); - return Ok(TokenQuality::Good); - } - return Err(e).context("trace_many"); - } - }; - let relevant_traces = &traces[pre_interactions.len()..]; - Self::handle_response(relevant_traces, amount, take_from) - } - - // For the out transfer we use an arbitrary address without balance to detect - // tokens that usually apply fees but not if the the sender or receiver is - // specifically exempt like their own uniswap pools. - fn arbitrary_recipient() -> H160 { - PrivateKey::from_raw(keccak256(b"moo")) - .unwrap() - .public_address() - } - - fn create_trace_request(&self, token: H160, amount: U256, take_from: H160) -> Vec { - let mut requests = Vec::new(); - let recipient = Self::arbitrary_recipient().into_alloy(); - let settlement_contract = self.settlement_contract.into_alloy(); - - // 0 - let calldata = ERC20::ERC20::balanceOfCall { - account: settlement_contract, - } - .abi_encode(); - requests.push(call_request(None, token, calldata)); - // 1 - let calldata = ERC20::ERC20::transferCall { - recipient: settlement_contract, - amount: amount.into_alloy(), - } - .abi_encode(); - requests.push(call_request(Some(take_from), token, calldata)); - // 2 - let calldata = ERC20::ERC20::balanceOfCall { - account: settlement_contract, - } - .abi_encode(); - requests.push(call_request(None, token, calldata)); - // 3 - let calldata = ERC20::ERC20::balanceOfCall { account: recipient }.abi_encode(); - requests.push(call_request(None, token, calldata)); - // 4 - let calldata = ERC20::ERC20::transferCall { - recipient, - amount: amount.into_alloy(), - } - .abi_encode(); - requests.push(call_request( - Some(self.settlement_contract), - token, - calldata, - )); - // 5 - let calldata = ERC20::ERC20::balanceOfCall { - account: settlement_contract, - } - .abi_encode(); - requests.push(call_request(None, token, calldata)); - // 6 - let calldata = ERC20::ERC20::balanceOfCall { account: recipient }.abi_encode(); - requests.push(call_request(None, token, calldata)); - - // 7 - let calldata = ERC20::ERC20::approveCall { - spender: recipient, - amount: alloy::primitives::U256::MAX, - } - .abi_encode(); - requests.push(call_request( - Some(self.settlement_contract), - token, - calldata, - )); - - requests - } - - fn handle_response( - traces: &[BlockTrace], - amount: U256, - take_from: H160, - ) -> Result { - ensure!(traces.len() == 8, "unexpected number of traces"); - - let gas_in = match ensure_transaction_ok_and_get_gas(&traces[1])? { - Ok(gas) => gas, - Err(reason) => { - return Ok(TokenQuality::bad(format!( - "Transfer of token from on chain source {take_from:?} into settlement \ - contract failed: {reason}" - ))); - } - }; - let arbitrary = Self::arbitrary_recipient(); - let gas_out = match ensure_transaction_ok_and_get_gas(&traces[4])? { - Ok(gas) => gas, - Err(reason) => { - return Ok(TokenQuality::bad(format!( - "Transfer token out of settlement contract to arbitrary recipient \ - {arbitrary:?} failed: {reason}", - ))); - } - }; - - let message = "\ - Failed to decode the token's balanceOf response because it did not \ - return 32 bytes. A common cause of this is a bug in the Vyper \ - smart contract compiler. See \ - https://github.com/cowprotocol/services/pull/781 for more \ - information.\ - "; - let bad = TokenQuality::Bad { - reason: message.to_string(), - }; - let balance_before_in = match decode_u256(&traces[0]) { - Some(balance) => balance, - None => return Ok(bad), - }; - let balance_after_in = match decode_u256(&traces[2]) { - Some(balance) => balance, - None => return Ok(bad), - }; - let balance_after_out = match decode_u256(&traces[5]) { - Some(balance) => balance, - None => return Ok(bad), - }; - let balance_recipient_before = match decode_u256(&traces[3]) { - Some(balance) => balance, - None => return Ok(bad), - }; - let balance_recipient_after = match decode_u256(&traces[6]) { - Some(balance) => balance, - None => return Ok(bad), - }; - - tracing::debug!(%amount, %balance_before_in, %balance_after_in, %balance_after_out); - - let computed_balance_after_in = match balance_before_in.checked_add(amount) { - Some(amount) => amount, - None => { - return Ok(TokenQuality::bad(format!( - "Transferring {amount} into settlement contract would overflow its balance." - ))); - } - }; - // Allow for a small discrepancy (1 wei) in the balance after the transfer which - // may come from rounding discrepancies in tokens that track balances - // with "shares" (e.g. eUSD). - if balance_after_in < computed_balance_after_in.saturating_sub(U256::one()) { - return Ok(TokenQuality::bad(format!( - "Transferring {amount} into settlement contract was expected to result in a \ - balance of {computed_balance_after_in} but actually resulted in \ - {balance_after_in}. A common cause for this is that the token takes a fee on \ - transfer." - ))); - } - if balance_after_out != balance_before_in { - return Ok(TokenQuality::bad(format!( - "Transferring {amount} out of settlement contract was expected to result in the \ - original balance of {balance_before_in} but actually resulted in \ - {balance_after_out}." - ))); - } - let computed_balance_recipient_after = match balance_recipient_before.checked_add(amount) { - Some(amount) => amount, - None => { - return Ok(TokenQuality::bad(format!( - "Transferring {amount} into arbitrary recipient {arbitrary:?} would overflow \ - its balance." - ))); - } - }; - // Allow for a small discrepancy (1 wei) in the balance after the transfer - // which may come from rounding discrepancies in tokens that track - // balances with "shares" (e.g. eUSD). - if computed_balance_recipient_after < balance_recipient_after.saturating_sub(U256::one()) { - return Ok(TokenQuality::bad(format!( - "Transferring {amount} into arbitrary recipient {arbitrary:?} was expected to \ - result in a balance of {computed_balance_recipient_after} but actually resulted \ - in {balance_recipient_after}. A common cause for this is that the token takes a \ - fee on transfer." - ))); - } - - if let Err(err) = ensure_transaction_ok_and_get_gas(&traces[7])? { - return Ok(TokenQuality::bad(format!( - "Approval of U256::MAX failed: {err}" - ))); - } - - let _gas_per_transfer = (gas_in + gas_out) / 2; - Ok(TokenQuality::Good) - } -} - -fn call_request(from: Option, to: H160, calldata: Vec) -> CallRequest { - CallRequest { - from, - to: Some(to), - data: Some(calldata.into()), - ..Default::default() - } -} - -/// Returns none if the length of the bytes in the trace output is not 32. -fn decode_u256(trace: &BlockTrace) -> Option { - let bytes = trace.output.0.as_slice(); - if bytes.len() != 32 { - return None; - } - Some(U256::from_big_endian(bytes)) -} - -// The outer result signals communication failure with the node. -// The inner result is Ok(gas_price) or Err if the transaction failed. -fn ensure_transaction_ok_and_get_gas(trace: &BlockTrace) -> Result> { - let transaction_traces = trace.trace.as_ref().context("trace not set")?; - let first = transaction_traces - .first() - .context("expected at least one trace")?; - if let Some(error) = &first.error { - return Ok(Err(format!("transaction failed: {error}"))); - } - let call_result = match &first.result { - Some(Res::Call(call)) => call, - _ => bail!("no error but also no call result"), - }; - Ok(Ok(call_result.gas_used)) -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::{ - bad_token::token_owner_finder::{ - TokenOwnerFinder, - blockscout::BlockscoutTokenOwnerFinder, - liquidity::{ - BalancerVaultFinder, - FeeValues, - UniswapLikePairProviderFinder, - UniswapV3Finder, - }, - solvers::{ - solver_api::SolverConfiguration, - solver_finder::AutoUpdatingSolverTokenOwnerFinder, - }, - }, - sources::{BaselineSource, uniswap_v2}, - }, - alloy::primitives::address, - chain::Chain, - contracts::alloy::{BalancerV2Vault, GPv2Settlement, IUniswapV3Factory, InstanceExt}, - ethrpc::{Web3, alloy::conversions::IntoLegacy}, - std::{env, time::Duration}, - web3::types::{ - Action, - ActionType, - Bytes, - Call, - CallResult, - CallType, - Res, - TransactionTrace, - }, - }; - - fn encode_u256(u256: U256) -> Bytes { - let mut bytes = vec![0u8; 32]; - u256.to_big_endian(&mut bytes); - Bytes(bytes) - } - - #[test] - fn handle_response_ok() { - let traces = &[ - BlockTrace { - output: encode_u256(0.into()), - trace: None, - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - BlockTrace { - output: Default::default(), - trace: Some(vec![TransactionTrace { - trace_address: Vec::new(), - subtraces: 0, - action: Action::Call(Call { - from: H160::zero(), - to: H160::zero(), - value: 0.into(), - gas: 0.into(), - input: Bytes(Vec::new()), - call_type: CallType::None, - }), - action_type: ActionType::Call, - result: Some(Res::Call(CallResult { - gas_used: 1.into(), - output: Bytes(Vec::new()), - })), - error: None, - }]), - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - BlockTrace { - output: encode_u256(1.into()), - trace: None, - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - BlockTrace { - output: encode_u256(0.into()), - trace: None, - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - BlockTrace { - output: Default::default(), - trace: Some(vec![TransactionTrace { - trace_address: Vec::new(), - subtraces: 0, - action: Action::Call(Call { - from: H160::zero(), - to: H160::zero(), - value: 0.into(), - gas: 0.into(), - input: Bytes(Vec::new()), - call_type: CallType::None, - }), - action_type: ActionType::Call, - result: Some(Res::Call(CallResult { - gas_used: 3.into(), - output: Bytes(Vec::new()), - })), - error: None, - }]), - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - BlockTrace { - output: encode_u256(0.into()), - trace: None, - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - BlockTrace { - output: encode_u256(1.into()), - trace: None, - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - BlockTrace { - output: Default::default(), - trace: Some(vec![TransactionTrace { - trace_address: Vec::new(), - subtraces: 0, - action: Action::Call(Call { - from: H160::zero(), - to: H160::zero(), - value: 0.into(), - gas: 0.into(), - input: Bytes(Vec::new()), - call_type: CallType::None, - }), - action_type: ActionType::Call, - result: Some(Res::Call(CallResult { - gas_used: 1.into(), - output: Bytes(Vec::new()), - })), - error: None, - }]), - vm_trace: None, - state_diff: None, - transaction_hash: None, - }, - ]; - - let result = TraceCallDetectorRaw::handle_response(traces, 1.into(), H160::zero()).unwrap(); - let expected = TokenQuality::Good; - assert_eq!(result, expected); - } - - #[test] - fn arbitrary_recipient_() { - println!("{:?}", TraceCallDetectorRaw::arbitrary_recipient()); - } - - // cargo test -p shared mainnet_tokens -- --nocapture --ignored - #[tokio::test] - #[ignore] - async fn mainnet_tokens() { - // observe::tracing::initialize("orderbook::bad_token=debug, - // shared::transport=debug", tracing::level_filters::LevelFilter::OFF); - let web3 = Web3::new_from_env(); - let version = web3.eth().chain_id().await.unwrap().to_string(); - - let base_tokens = &[ - testlib::tokens::WETH, - testlib::tokens::DAI, - testlib::tokens::USDC, - testlib::tokens::USDT, - testlib::tokens::COMP, - testlib::tokens::MKR, - testlib::tokens::WBTC, - ]; - - // tokens from our deny list - let bad_tokens = &[ - addr!("0027449Bf0887ca3E431D263FFDeFb244D95b555"), // All balances are maxuint256 - addr!("0189d31f6629c359007f72b8d5ec8fa1c126f95c"), - addr!("01995786f1435743c42b7f2276c496a610b58612"), - addr!("072c46f392e729c1f0d92a307c2c6dba06b5d078"), - addr!("074545177a36ab81aac783211f25e14f1ed03c2b"), - addr!("07be1ead7aebee544618bdc688fa3cff09857c32"), - addr!("0858a26055d6584e5b47bbecf7f7e8cbc390995b"), - addr!("0aacfbec6a24756c20d41914f2caba817c0d8521"), - addr!("0ba45a8b5d5575935b8158a88c631e9f9c95a2e5"), - addr!("0e69d0a2bbb30abcb7e5cfea0e4fde19c00a8d47"), - addr!("1016f3c0a1939fa27538339da7e2a300031b6f37"), - addr!("106552c11272420aad5d7e94f8acab9095a6c952"), - addr!("106d3c66d22d2dd0446df23d7f5960752994d600"), - addr!("1337DEF18C680aF1f9f45cBcab6309562975b1dD"), - addr!("1341a2257fa7b770420ef70616f888056f90926c"), - addr!("1426cc6d52d1b14e2b3b1cb04d57ea42b39c4c7c"), - addr!("14dd7ebe6cb084cb73ef377e115554d47dc9d61e"), - addr!("15874d65e649880c2614e7a480cb7c9a55787ff6"), - addr!("1681bcb589b3cfcf0c0616b0ce9b19b240643dc1"), - addr!("18bdfc80b97cb97f6b466cce967849ce9cd9d58c"), - addr!("1b9baf2a3edea91ee431f02d449a1044d5726669"), - addr!("2129ff6000b95a973236020bcd2b2006b0d8e019"), - addr!("239dc02a28a0774738463e06245544a72745d5c5"), - addr!("251457b7c5d85251ca1ab384361c821330be2520"), - addr!("25a1de1c3ee658fe034b8914a1d8d34110423af8"), - addr!("26a79bd709a7ef5e5f747b8d8f83326ea044d8cc"), - addr!("289d5488ab09f43471914e572ec9e3651c735af2"), - addr!("298d492e8c1d909d3f63bc4a36c66c64acb3d695"), - addr!("2b1fe2cea92436e8c34b7c215af66aaa2932a8b2"), - addr!("31acf54fae6166dc2f90c4d6f20d379965e96bc1"), - addr!("32c868f6318d6334b2250f323d914bc2239e4eee"), - addr!("33f128394af03db639107473e52d84ff1290499e"), - addr!("37611b28aca5673744161dc337128cfdd2657f69"), - addr!("389999216860ab8e0175387a0c90e5c52522c945"), - addr!("39b8523fa094b0dc045e2c3e5dff34b3f2ca6220"), - addr!("3a6fe4c752eb8d571a660a776be4003d619c30a3"), - addr!("3a9fff453d50d4ac52a6890647b823379ba36b9e"), - addr!("3ea50b7ef6a7eaf7e966e2cb72b519c16557497c"), - addr!("3fca773d13f831753ec3ae9f39ad4a6814ebb695"), - addr!("41933422dc4a1cb8c822e06f12f7b52fa5e7e094"), - addr!("45734927fa2f616fbe19e65f42a0ef3d37d1c80a"), - addr!("45804880de22913dafe09f4980848ece6ecbaf78"), - addr!("48be867b240d2ffaff69e0746130f2c027d8d3d2"), - addr!("4a6be56a211a4c4e0dd4474d524138933c17f3e3"), - addr!("4b86e0295e7d32433ffa6411b82b4f4e56a581e1"), - addr!("4ba6ddd7b89ed838fed25d208d4f644106e34279"), - addr!("4bae380b5d762d543d426331b8437926443ae9ec"), - addr!("4bcddfcfa8cb923952bcf16644b36e5da5ca3184"), - addr!("4c9d5672ae33522240532206ab45508116daf263"), - addr!("4F9254C83EB525f9FCf346490bbb3ed28a81C667"), - addr!("4fab740779c73aa3945a5cf6025bf1b0e7f6349c"), - addr!("51d3e4c0b2c83e62f5d517d250b3e856897d2052"), - addr!("53ba22cb4e5e9c1be0d73913764f572192a71aca"), - addr!("56de8bc61346321d4f2211e3ac3c0a7f00db9b76"), - addr!("576097fa17e1f702bb9167f0f08f2ea0898a3ea5"), - addr!("577e7f9fa80ab33e87a01b701114257c8d9455a8"), - addr!("586c680e9a6d21b81ebecf46d78844dab7b3bcf9"), - addr!("5d0fa08aeb173ade44b0cf7f31d506d8e04f0ac8"), - addr!("62359ed7505efc61ff1d56fef82158ccaffa23d7"), - addr!("63d0eea1d7c0d1e89d7e665708d7e8997c0a9ed6"), - addr!("66d31def9c47b62184d7f57175eed5b5d9b7f038"), - addr!("671ab077497575dcafb68327d2d2329207323e74"), - addr!("685aea4f02e39e5a5bb7f7117e88db1151f38364"), - addr!("68e0a48d3bff6633a31d1d100b70f93c3859218b"), - addr!("69692d3345010a207b759a7d1af6fc7f38b35c5e"), - addr!("6a00b86e30167f73e38be086081b80213e8266aa"), - addr!("6b8e77d3db1faa17f7b24c24242b6a1eb5008a16"), - addr!("6e10aacb89a28d6fa0fe68790777fec7e7f01890"), - addr!("6fcb6408499a7c0f242e32d77eb51ffa1dd28a7e"), - addr!("714599f7604144a3fe1737c440a70fc0fd6503ea"), - addr!("75fef397d74a2d11b64e6915cd847c1e7f8e5520"), - addr!("76851a93977bea9264c32255b6457882035c7501"), - addr!("79ba92dda26fce15e1e9af47d5cfdfd2a093e000"), - addr!("7f0f118d083d5175ab9d2d34c4c8fa4f43c3f47b"), - addr!("7ff4169a6b5122b664c51c95727d87750ec07c84"), - addr!("801ea8c463a776e85344c565e355137b5c3324cd"), - addr!("88ef27e69108b2633f8e1c184cc37940a075cc02"), - addr!("8c7424c3000942e5a93de4a01ce2ec86c06333cb"), - addr!("8eb24319393716668d768dcec29356ae9cffe285"), - addr!("910524678c0b1b23ffb9285a81f99c29c11cbaed"), - addr!("910985ffa7101bf5801dd2e91555c465efd9aab3"), - addr!("925f2c11b99c1a4c46606898ee91ed3d450cfeda"), - addr!("944eee930933be5e23b690c8589021ec8619a301"), - addr!("94987bc8aa5f36cb2461c190134929a29c3df726"), - addr!("97ad070879be5c31a03a1fe7e35dfb7d51d0eef1"), - addr!("97b65710d03e12775189f0d113202cc1443b0aa2"), - addr!("98ecf3d8e21adaafe16c00cc3ff681e72690278b"), - addr!("99043bb680ab9262c7b2ac524e00b215efb7db9b"), - addr!("99ddddd8dfe33905338a073047cfad72e6833c06"), - addr!("9a514389172863f12854ad40090aa4b928028542"), - addr!("9af15d7b8776fa296019979e70a5be53c714a7ec"), - addr!("9ea3b5b4ec044b70375236a281986106457b20ef"), - addr!("9f41da75ab2b8c6f0dcef7173c4bf66bd4f6b36a"), - addr!("a03f1250aa448226ed4066d8d1722ddd8b51df59"), - addr!("a2b4c0af19cc16a6cfacce81f192b024d625817d"), - addr!("a3e059c0b01f07f211c85bf7b4f1d907afb011df"), - addr!("a5959e9412d27041194c3c3bcbe855face2864f7"), - addr!("a9a8377287ea9c6b8b4249dd502e75d34148fc5b"), - addr!("adaa92cba08434c22d036c4115a6b3d7e2b5569b"), - addr!("aee53701e18d5ff6af4964c3a381e7d09b9b9075"), - addr!("b893a8049f250b57efa8c62d51527a22404d7c9a"), - addr!("B96f0e9bb32760091eb2D6B0A5Ca0D2C7b5644B1"), - addr!("ba7435a4b4c747e0101780073eeda872a69bdcd4"), - addr!("bae5f2d8a1299e5c4963eaff3312399253f27ccb"), - addr!("bd36b14c63f483b286c7b49b6eaffb2fe10aabc4"), - addr!("bdea5bb640dbfc4593809deec5cdb8f99b704cd2"), - addr!("bf04e48c5d8880306591ef888cde201d3984eb3e"), - addr!("bf25ea982b4f850dafb4a95367b890eee5a9e8f2"), - addr!("bf494f02ee3fde1f20bee6242bce2d1ed0c15e47"), - addr!("c03841b5135600312707d39eb2af0d2ad5d51a91"), - addr!("c10bbb8fd399d580b740ed31ff5ac94aa78ba9ed"), - addr!("c12d1c73ee7dc3615ba4e37e4abfdbddfa38907e"), - addr!("c40af1e4fecfa05ce6bab79dcd8b373d2e436c4e"), - addr!("c4d586ef7be9ebe80bd5ee4fbd228fe2db5f2c4e"), - addr!("c50ef449171a51fbeafd7c562b064b6471c36caa"), - addr!("c626d951eff8e421448074bd2ad7805c6d585793"), - addr!("c73c167e7a4ba109e4052f70d5466d0c312a344d"), - addr!("c7c24fe893c21e8a4ef46eaf31badcab9f362841"), - addr!("cd7492db29e2ab436e819b249452ee1bbdf52214"), - addr!("cf0c122c6b73ff809c693db761e7baebe62b6a2e"), - addr!("cf2f589bea4645c3ef47f1f33bebf100bee66e05"), - addr!("cf8c23cf17bb5815d5705a15486fa83805415625"), - addr!("d0834d08c83dbe216811aaea0eeffb2349e57634"), - addr!("d0d3ebcad6a20ce69bc3bc0e1ec964075425e533"), - addr!("d1afbccc9a2c2187ea544363b986ea0ab6ef08b5"), - addr!("d375a513692336cf9eebce5e38869b447948016f"), - addr!("d3f6571be1d91ac68b40daaa24075ca7e2f0f72e"), - addr!("d50825f50384bc40d5a10118996ef503b3670afd"), - addr!("d5281bb2d1ee94866b03a0fccdd4e900c8cb5091"), - addr!("da1e53e088023fe4d1dc5a418581748f52cbd1b8"), - addr!("dd339f370bbb18b8f389bd0443329d82ecf4b593"), - addr!("decade1c6bf2cd9fb89afad73e4a519c867adcf5"), /* Should be denied because can't - * approve more than balance */ - addr!("dfdd3459d4f87234751696840092ee20c970fb07"), - addr!("e0bdaafd0aab238c55d68ad54e616305d4a21772"), - addr!("e2d66561b39eadbd488868af8493fb55d4b9d084"), - addr!("e302bf71b1f6f3024e7642f9c824ac86b58436a0"), - addr!("ea319e87cf06203dae107dd8e5672175e3ee976c"), - addr!("ed5e5ab076ae60bdb9c49ac255553e65426a2167"), - addr!("eeee2a622330e6d2036691e983dee87330588603"), - addr!("ef5b32486ed432b804a51d129f4d2fbdf18057ec"), - addr!("f1365ab39e192808b5301bcf6da973830e9e817f"), - addr!("f198B4a2631B7D0B9FAc36f8B546Ed3DCe472A47"), - addr!("fad45e47083e4607302aa43c65fb3106f1cd7607"), - addr!("fcaa8eef70f373e00ac29208023d106c846259ee"), - addr!("ff69e48af1174da7f15d0c771861c33d3f19ed8a"), - ]; - - // Of the deny listed tokens the following are detected as good: - // - token 0xc12d1c73ee7dc3615ba4e37e4abfdbddfa38907e Has some kind of - // "freezing" mechanism where some balance is unusuable. We don't seem to - // trigger it. - // - 0x910524678c0b1b23ffb9285a81f99c29c11cbaed Has some kind of time lock that - // we don't encounter. - // - 0xed5e5ab076ae60bdb9c49ac255553e65426a2167 Not sure why deny listed. - // - 0x1337def18c680af1f9f45cbcab6309562975b1dd Not sure why deny listed, maybe - // the callback that I didn't follow in the SC code. - // - 0x4f9254c83eb525f9fcf346490bbb3ed28a81c667 Not sure why deny listed. - - let settlement = GPv2Settlement::Instance::deployed(&web3.alloy) - .await - .unwrap(); - let finder = Arc::new(TokenOwnerFinder { - web3: web3.clone(), - settlement_contract: settlement.address().into_legacy(), - proposers: vec![ - Arc::new(UniswapLikePairProviderFinder { - inner: uniswap_v2::UniV2BaselineSourceParameters::from_baseline_source( - BaselineSource::UniswapV2, - &version, - ) - .unwrap() - .into_source(&web3) - .await - .unwrap() - .pair_provider, - base_tokens: base_tokens - .iter() - .map(|token| token.into_legacy()) - .collect::>(), - }), - Arc::new(UniswapLikePairProviderFinder { - inner: uniswap_v2::UniV2BaselineSourceParameters::from_baseline_source( - BaselineSource::SushiSwap, - &version, - ) - .unwrap() - .into_source(&web3) - .await - .unwrap() - .pair_provider, - base_tokens: base_tokens - .iter() - .map(|token| token.into_legacy()) - .collect::>(), - }), - Arc::new(BalancerVaultFinder( - BalancerV2Vault::Instance::deployed(&web3.alloy) - .await - .unwrap(), - )), - Arc::new( - UniswapV3Finder::new( - IUniswapV3Factory::Instance::deployed(&web3.alloy) - .await - .unwrap(), - base_tokens - .iter() - .map(|token| token.into_legacy()) - .collect::>(), - FeeValues::Static, - ) - .await - .unwrap(), - ), - Arc::new( - BlockscoutTokenOwnerFinder::with_network( - reqwest::Client::new(), - &Chain::Mainnet, - ) - .unwrap(), - ), - ], - }); - let token_cache = TraceCallDetector::new(web3, settlement.address().into_legacy(), finder); - - println!("testing good tokens"); - for &token in base_tokens { - let result = token_cache.detect(token).await; - println!("token {token:?} is {result:?}"); - } - - println!("testing bad tokens"); - for &token in bad_tokens { - let result = token_cache.detect(token.into_alloy()).await; - println!("token {token:?} is {result:?}"); - } - } - - #[tokio::test] - #[ignore] - async fn mainnet_univ3() { - observe::tracing::initialize(&observe::Config::default().with_env_filter("shared=debug")); - let web3 = Web3::new_from_env(); - let base_tokens = vec![testlib::tokens::WETH.into_legacy()]; - let settlement = GPv2Settlement::Instance::deployed(&web3.alloy) - .await - .unwrap(); - let factory = IUniswapV3Factory::Instance::deployed(&web3.alloy) - .await - .unwrap(); - let univ3 = Arc::new( - UniswapV3Finder::new(factory, base_tokens, FeeValues::Dynamic) - .await - .unwrap(), - ); - let finder = Arc::new(TokenOwnerFinder { - web3: web3.clone(), - settlement_contract: settlement.address().into_legacy(), - proposers: vec![univ3], - }); - let token_cache = TraceCallDetector::new(web3, settlement.address().into_legacy(), finder); - - let result = token_cache.detect(testlib::tokens::USDC).await; - dbg!(&result); - assert!(result.unwrap().is_good()); - - let only_v3_token = address!("f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b"); - let result = token_cache.detect(only_v3_token).await; - dbg!(&result); - assert!(result.unwrap().is_good()); - } - - #[tokio::test] - #[ignore] - async fn yearn_vault_tokens() { - let tokens = [ - address!("1025b1641d1F23C289412Dd5E5701e9810103a93"), - address!("132d8D2C76Db3812403431fAcB00F3453Fc42125"), - address!("1635b506a88fBF428465Ad65d00e8d6B6E5846C3"), - address!("16825039dfe2a5b01F3E1E6a2BBF9a576c6F95c4"), - address!("1b905331F7dE2748F4D6a0678e1521E20347643F"), - address!("23D3D0f1c697247d5e0a9efB37d8b0ED0C464f7f"), - address!("25212Df29073FfFA7A67399AcEfC2dd75a831A1A"), - address!("27B5739e22ad9033bcBf192059122d163b60349D"), - address!("2D5D4869381C4Fce34789BC1D38aCCe747E295AE"), - address!("2DfB14E32e2F8156ec15a2c21c3A6c053af52Be8"), - address!("2a38B9B0201Ca39B17B460eD2f11e4929559071E"), - address!("2e5c7e9B1Da0D9Cb2832eBb06241d18552A85400"), - address!("30FCf7c6cDfC46eC237783D94Fc78553E79d4E9C"), - address!("341bb10D8f5947f3066502DC8125d9b8949FD3D6"), - address!("378cb52b00F9D0921cb46dFc099CFf73b42419dC"), - address!("39CAF13a104FF567f71fd2A4c68C026FDB6E740B"), - address!("3B27F92C0e212C671EA351827EDF93DB27cc0c65"), - address!("3B96d491f067912D18563d56858Ba7d6EC67a6fa"), - address!("3c5DF3077BcF800640B5DAE8c91106575a4826E6"), - address!("4560b99C904aAD03027B5178CCa81584744AC01f"), - address!("490bD0886F221A5F79713D3E84404355A9293C50"), - address!("4B5BfD52124784745c1071dcB244C6688d2533d3"), - address!("528D50dC9a333f01544177a924893FA1F5b9F748"), - address!("59518884EeBFb03e90a18ADBAAAB770d4666471e"), - address!("595a68a8c9D5C230001848B69b1947ee2A607164"), - address!("5AB64C599FcC59f0f2726A300b03166A395578Da"), - address!("5a770DbD3Ee6bAF2802D29a901Ef11501C44797A"), - address!("5c0A86A32c129538D62C106Eb8115a8b02358d57"), - address!("5e69e8b51B71C8596817fD442849BD44219bb095"), - address!("5fA5B62c8AF877CB37031e0a3B2f34A78e3C56A6"), - address!("625b7DF2fa8aBe21B0A976736CDa4775523aeD1E"), - address!("671a912C10bba0CFA74Cfc2d6Fba9BA1ed9530B2"), - address!("67e019bfbd5a67207755D04467D6A70c0B75bF60"), - address!("6A5468752f8DB94134B6508dAbAC54D3b45efCE6"), - address!("6B5ce31AF687a671a804d8070Ddda99Cab926dfE"), - address!("6Ede7F19df5df6EF23bD5B9CeDb651580Bdf56Ca"), - address!("6d765CbE5bC922694afE112C140b8878b9FB0390"), - address!("7047F90229a057C13BF847C0744D646CFb6c9E1A"), - address!("718AbE90777F5B778B52D553a5aBaa148DD0dc5D"), - address!("790a60024bC3aea28385b60480f15a0771f26D09"), - address!("801Ab06154Bf539dea4385a39f5fa8534fB53073"), - address!("8414Db07a7F743dEbaFb402070AB01a4E0d2E45e"), - address!("84E13785B5a27879921D6F685f041421C7F482dA"), - address!("873fB544277FD7b977B196a826459a69E27eA4ea"), - address!("8b9C0c24307344B6D7941ab654b2Aeee25347473"), - address!("8cc94ccd0f3841a468184aCA3Cc478D2148E1757"), - address!("8ee57c05741aA9DB947A744E713C15d4d19D8822"), - address!("8fA3A9ecd9EFb07A8CE90A6eb014CF3c0E3B32Ef"), - address!("9A39f31DD5EDF5919A5C0c2433cE053fAD2E0336"), - address!("9d409a0A012CFbA9B15F6D4B36Ac57A46966Ab9a"), - address!("A696a63cc78DfFa1a63E9E50587C197387FF6C7E"), - address!("A74d4B67b3368E83797a35382AFB776bAAE4F5C8"), - address!("A9412Ffd7E0866755ae0dda3318470A61F62abe8"), - address!("B4AdA607B9d6b2c9Ee07A275e9616B84AC560139"), - address!("BCBB5b54Fa51e7b7Dc920340043B203447842A6b"), - address!("Bfedbcbe27171C418CDabC2477042554b1904857"), - address!("C4dAf3b5e2A9e93861c3FBDd25f1e943B8D87417"), - address!("D6Ea40597Be05c201845c0bFd2e96A60bACde267"), - address!("E537B5cc158EB71037D4125BDD7538421981E6AA"), - address!("E5eDcE53e39Cbc6d819E2C340BCF295e0084ff7c"), - address!("F29AE508698bDeF169B89834F76704C3B205aedf"), - address!("F59D66c1d593Fb10e2f8c2a6fD2C958792434B9c"), - address!("F6B9DFE6bc42ed2eaB44D6B829017f7B78B29f88"), - address!("FBEB78a723b8087fD2ea7Ef1afEc93d35E8Bed42"), - address!("FD0877d9095789cAF24c98F7CCe092fa8E120775"), - address!("a258C4606Ca8206D8aA700cE2143D7db854D168c"), - address!("a354F35829Ae975e850e23e9615b11Da1B3dC4DE"), - address!("b09F2a67a731466182518fae980feAe96479d80b"), - address!("b4D1Be44BfF40ad6e506edf43156577a3f8672eC"), - address!("c5F3D11580c41cD07104e9AF154Fc6428bb93c73"), - address!("c97232527B62eFb0D8ed38CF3EA103A6CcA4037e"), - address!("c97511a1dDB162C8742D39FF320CfDCd13fBcf7e"), - address!("d88dBBA3f9c4391Ee46f5FF548f289054db6E51C"), - address!("d8C620991b8E626C099eAaB29B1E3eEa279763bb"), - address!("d9788f3931Ede4D5018184E198699dC6d66C1915"), - address!("dA816459F1AB5631232FE5e97a05BBBb94970c95"), - address!("db25cA703181E7484a155DD612b06f57E12Be5F0"), - address!("e9Dc63083c464d6EDcCFf23444fF3CFc6886f6FB"), - address!("f2db9a7c0ACd427A680D640F02d90f6186E71725"), - address!("f8768814b88281DE4F532a3beEfA5b85B69b9324"), - ]; - - let solver_token_finder = Arc::new(AutoUpdatingSolverTokenOwnerFinder::new( - Box::new(SolverConfiguration { - url: env::var("SOLVER_TOKEN_OWNERS_URLS") - .unwrap() - .parse() - .unwrap(), - client: reqwest::Client::new(), - }), - Duration::MAX, - "test".to_owned(), - )); - - // Force the cache to update at least once. - solver_token_finder.update().await.unwrap(); - - let web3 = Web3::new_from_env(); - - let settlement = GPv2Settlement::Instance::deployed(&web3.alloy) - .await - .unwrap(); - let finder = Arc::new(TokenOwnerFinder { - web3: web3.clone(), - proposers: vec![solver_token_finder], - settlement_contract: settlement.address().into_legacy(), - }); - let token_cache = TraceCallDetector::new(web3, settlement.address().into_legacy(), finder); - - for token in tokens { - let result = token_cache.detect(token).await; - println!("token {token:?} is {result:?}"); - } - } -} diff --git a/crates/shared/src/code_fetching.rs b/crates/shared/src/code_fetching.rs deleted file mode 100644 index 54f1f108d6..0000000000 --- a/crates/shared/src/code_fetching.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Module containing traits for abstracting Web3 operations so components can -//! more easily be tested with mocked versions of these behaviours. - -use { - crate::ethrpc::Web3, - anyhow::Result, - cached::{Cached, SizedCache}, - std::sync::{Arc, Mutex}, - tracing::instrument, - web3::types::{Bytes, H160}, -}; - -#[cfg_attr(any(test, feature = "test-util"), mockall::automock)] -#[async_trait::async_trait] -pub trait CodeFetching: Send + Sync + 'static { - /// Fetches the code for the specified address. - async fn code(&self, address: H160) -> Result; - - /// Fetches the code size at the specified address. - async fn code_size(&self, address: H160) -> Result; -} - -#[async_trait::async_trait] -impl CodeFetching for Web3 { - #[instrument(skip_all)] - async fn code(&self, address: H160) -> Result { - Ok(self.eth().code(address, None).await?) - } - - #[instrument(skip_all)] - async fn code_size(&self, address: H160) -> Result { - Ok(self.code(address).await?.0.len()) - } -} - -pub struct CachedCodeFetcher { - inner: Arc, - cache: Mutex>, -} - -impl CachedCodeFetcher { - const CACHE_SIZE: usize = 1_000; - - pub fn new(inner: Arc) -> Self { - Self { - inner, - cache: Mutex::new(SizedCache::with_size(Self::CACHE_SIZE)), - } - } - - async fn cached_code(&self, address: H160, handle: F) -> Result - where - F: FnOnce(&Bytes) -> T, - { - { - let mut cache = self.cache.lock().unwrap(); - if let Some(code) = cache.cache_get(&address) { - return Ok(handle(code)); - } - } - - let code = self.inner.code(address).await?; - let result = handle(&code); - self.cache.lock().unwrap().cache_set(address, code); - Ok(result) - } -} - -#[async_trait::async_trait] -impl CodeFetching for CachedCodeFetcher { - async fn code(&self, address: H160) -> Result { - self.cached_code(address, |code| code.clone()).await - } - - async fn code_size(&self, address: H160) -> Result { - self.cached_code(address, |code| code.0.len()).await - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - mockall::{Sequence, predicate}, - }; - - #[tokio::test] - async fn caches_code() { - let mut inner = MockCodeFetching::new(); - let mut seq = Sequence::new(); - inner - .expect_code() - .times(1) - .with(predicate::eq(H160([1; 20]))) - .returning(|_| Ok(Bytes(vec![1; 1]))) - .in_sequence(&mut seq); - inner - .expect_code() - .times(1) - .with(predicate::eq(H160([2; 20]))) - .returning(|_| Ok(Bytes(vec![2; 2]))) - .in_sequence(&mut seq); - - let cached = CachedCodeFetcher::new(Arc::new(inner)); - - assert_eq!(cached.code(H160([1; 20])).await.unwrap().0, [1]); - assert_eq!(cached.code_size(H160([1; 20])).await.unwrap(), 1); - - assert_eq!(cached.code_size(H160([2; 20])).await.unwrap(), 2); - assert_eq!(cached.code(H160([2; 20])).await.unwrap().0, [2; 2]); - } -} diff --git a/crates/shared/src/conversions.rs b/crates/shared/src/conversions.rs deleted file mode 100644 index 4ce38a3f87..0000000000 --- a/crates/shared/src/conversions.rs +++ /dev/null @@ -1,77 +0,0 @@ -use { - anyhow::{Result, ensure}, - num::{BigInt, BigRational, rational::Ratio}, - primitive_types::U256, -}; - -pub fn into_gas_price(gas_price: &gas_estimation::GasPrice1559) -> ethcontract::GasPrice { - ( - gas_price.max_fee_per_gas, - gas_price.max_priority_fee_per_gas, - ) - .into() -} - -// Convenience: - -pub trait RatioExt { - fn new_checked(numerator: T, denominator: T) -> Result>; -} - -impl RatioExt for Ratio { - fn new_checked(numerator: T, denominator: T) -> Result> { - ensure!( - !denominator.is_zero(), - "Cannot create Ratio with 0 denominator" - ); - Ok(Ratio::new(numerator, denominator)) - } -} - -pub trait U256Ext: Sized { - fn to_big_int(&self) -> BigInt; - fn to_big_rational(&self) -> BigRational; - - fn checked_ceil_div(&self, other: &Self) -> Option; - fn ceil_div(&self, other: &Self) -> Self; -} - -impl U256Ext for U256 { - fn to_big_int(&self) -> BigInt { - number::conversions::u256_to_big_int(self) - } - - fn to_big_rational(&self) -> BigRational { - number::conversions::u256_to_big_rational(self) - } - - fn checked_ceil_div(&self, other: &Self) -> Option { - self.checked_add(other.checked_sub(1.into())?)? - .checked_div(*other) - } - - fn ceil_div(&self, other: &Self) -> Self { - self.checked_ceil_div(other) - .expect("ceiling division arithmetic error") - } -} - -impl U256Ext for alloy::primitives::U256 { - fn to_big_int(&self) -> BigInt { - number::conversions::alloy::u256_to_big_int(self) - } - - fn to_big_rational(&self) -> BigRational { - number::conversions::alloy::u256_to_big_rational(self) - } - - fn checked_ceil_div(&self, other: &Self) -> Option { - self.checked_add(other.checked_sub(alloy::primitives::U256::ONE)?)? - .checked_div(*other) - } - - fn ceil_div(&self, other: &Self) -> Self { - self.checked_ceil_div(other) - .expect("ceiling division arithmetic error") - } -} diff --git a/crates/shared/src/current_block.rs b/crates/shared/src/current_block.rs index 4f68b6d0fa..537724552f 100644 --- a/crates/shared/src/current_block.rs +++ b/crates/shared/src/current_block.rs @@ -59,6 +59,15 @@ impl Arguments { } } +impl From<&configs::shared::CurrentBlockConfig> for Arguments { + fn from(config: &configs::shared::CurrentBlockConfig) -> Self { + Self { + block_stream_poll_interval: config.poll_interval, + node_ws_url: config.ws_url.clone(), + } + } +} + impl Display for Arguments { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let Self { diff --git a/crates/shared/src/db_order_conversions.rs b/crates/shared/src/db_order_conversions.rs index 87471cd992..96e90bdf6d 100644 --- a/crates/shared/src/db_order_conversions.rs +++ b/crates/shared/src/db_order_conversions.rs @@ -1,5 +1,5 @@ use { - alloy::primitives::Address, + alloy::primitives::{Address, B256}, anyhow::{Context, Result}, app_data::AppDataHash, bigdecimal::BigDecimal, @@ -15,8 +15,6 @@ use { SigningScheme as DbSigningScheme, }, }, - ethcontract::{H160, H256}, - ethrpc::alloy::conversions::IntoAlloy, model::{ interaction::InteractionData, order::{ @@ -38,11 +36,7 @@ use { signature::{Signature, SigningScheme}, }, num::FromPrimitive, - number::conversions::{ - alloy::big_decimal_to_u256 as alloy_big_decimal_to_u256, - big_decimal_to_big_uint, - big_decimal_to_u256, - }, + number::conversions::{big_decimal_to_big_uint, big_decimal_to_u256}, }; pub fn full_order_into_model_order(order: database::orders::FullOrder) -> Result { @@ -56,7 +50,7 @@ pub fn full_order_into_model_order(order: database::orders::FullOrder) -> Result let ethflow_data = if let Some((refund_tx, user_valid_to)) = order.ethflow_data { Some(EthflowData { user_valid_to, - refund_tx_hash: refund_tx.map(|hash| H256::from(hash.0)), + refund_tx_hash: refund_tx.map(|hash| B256::from(hash.0)), }) } else { None @@ -111,14 +105,11 @@ pub fn full_order_into_model_order(order: database::orders::FullOrder) -> Result sell_token: Address::new(order.sell_token.0), buy_token: Address::new(order.buy_token.0), receiver: order.receiver.map(|address| Address::new(address.0)), - sell_amount: alloy_big_decimal_to_u256(&order.sell_amount) - .context("sell_amount is not U256")?, - buy_amount: alloy_big_decimal_to_u256(&order.buy_amount) - .context("buy_amount is not U256")?, + sell_amount: big_decimal_to_u256(&order.sell_amount).context("sell_amount is not U256")?, + buy_amount: big_decimal_to_u256(&order.buy_amount).context("buy_amount is not U256")?, valid_to: order.valid_to.try_into().context("valid_to is not u32")?, app_data: AppDataHash(order.app_data.0), - fee_amount: alloy_big_decimal_to_u256(&order.fee_amount) - .context("fee_amount is not U256")?, + fee_amount: big_decimal_to_u256(&order.fee_amount).context("fee_amount is not U256")?, kind: order_kind_from(order.kind), partially_fillable: order.partially_fillable, sell_token_balance: sell_token_source_from(order.sell_token_balance), @@ -149,6 +140,13 @@ pub fn order_quote_into_model( _ => quote.metadata.clone(), }; + let fee_amount = crate::fee::FeeParameters { + gas_amount: quote.gas_amount, + gas_price: quote.gas_price, + sell_token_price: quote.sell_token_price, + } + .fee(); + Ok(OrderQuote { gas_amount: BigDecimal::from_f64(quote.gas_amount).context("gas_amount is not U256")?, gas_price: BigDecimal::from_f64(quote.gas_price).context("gas_price is not U256")?, @@ -156,7 +154,8 @@ pub fn order_quote_into_model( .context("gas_price is not U256")?, sell_amount: big_decimal_to_u256("e.sell_amount).context("sell_amount is not U256")?, buy_amount: big_decimal_to_u256("e.buy_amount).context("buy_amount is not U256")?, - solver: H160(quote.solver.0), + fee_amount, + solver: Address::new(quote.solver.0), verified: quote.verified, metadata, }) @@ -176,7 +175,6 @@ pub fn extract_interactions( Ok(InteractionData { target: Address::from_slice(&interaction.0.0), value: big_decimal_to_u256(&interaction.1) - .map(IntoAlloy::into_alloy) .context("interaction value is not U256")?, call_data: interaction.2.to_vec(), }) diff --git a/crates/shared/src/encoded_settlement.rs b/crates/shared/src/encoded_settlement.rs deleted file mode 100644 index dc20aac189..0000000000 --- a/crates/shared/src/encoded_settlement.rs +++ /dev/null @@ -1,218 +0,0 @@ -use { - crate::interaction::EncodedInteraction, - alloy::primitives::Address, - ethcontract::Bytes, - ethrpc::alloy::conversions::IntoLegacy, - model::{ - order::{BuyTokenDestination, OrderData, OrderKind, SellTokenSource}, - signature::{Signature, SigningScheme}, - }, - primitive_types::{H160, U256}, -}; - -pub type EncodedTrade = ( - U256, // sellTokenIndex - U256, // buyTokenIndex - H160, // receiver - U256, // sellAmount - U256, // buyAmount - u32, // validTo - Bytes<[u8; 32]>, // appData - U256, // feeAmount - U256, // flags - U256, // executedAmount - Bytes>, // signature -); - -/// Creates the data which the smart contract's `decodeTrade` expects. -pub fn encode_trade( - order: &OrderData, - signature: &Signature, - owner: H160, - sell_token_index: usize, - buy_token_index: usize, - executed_amount: &U256, -) -> EncodedTrade { - ( - sell_token_index.into(), - buy_token_index.into(), - order.receiver.unwrap_or(Address::ZERO).into_legacy(), - order.sell_amount.into_legacy(), - order.buy_amount.into_legacy(), - order.valid_to, - Bytes(order.app_data.0), - order.fee_amount.into_legacy(), - order_flags(order, signature), - *executed_amount, - Bytes(signature.encode_for_settlement(owner).to_vec()), - ) -} - -fn order_flags(order: &OrderData, signature: &Signature) -> U256 { - let mut result = 0u8; - // The kind is encoded as 1 bit in position 0. - result |= match order.kind { - OrderKind::Sell => 0b0, - OrderKind::Buy => 0b1, - }; - // The order fill kind is encoded as 1 bit in position 1. - result |= (order.partially_fillable as u8) << 1; - // The order sell token balance is encoded as 2 bits in position 2. - result |= match order.sell_token_balance { - SellTokenSource::Erc20 => 0b00, - SellTokenSource::External => 0b10, - SellTokenSource::Internal => 0b11, - } << 2; - // The order buy token balance is encoded as 1 bit in position 4. - result |= match order.buy_token_balance { - BuyTokenDestination::Erc20 => 0b0, - BuyTokenDestination::Internal => 0b1, - } << 4; - // The signing scheme is encoded as a 2 bits in position 5. - result |= match signature.scheme() { - SigningScheme::Eip712 => 0b00, - SigningScheme::EthSign => 0b01, - SigningScheme::Eip1271 => 0b10, - SigningScheme::PreSign => 0b11, - } << 5; - result.into() -} - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct EncodedSettlement { - pub tokens: Vec, - pub clearing_prices: Vec, - pub trades: Vec, - pub interactions: [Vec; 3], -} - -#[cfg(test)] -mod tests { - use {super::*, ethcontract::H256, hex_literal::hex, model::signature::EcdsaSignature}; - - #[test] - fn order_flag_permutations() { - for (order, scheme, flags) in [ - ( - OrderData { - kind: OrderKind::Sell, - partially_fillable: false, - sell_token_balance: SellTokenSource::Erc20, - buy_token_balance: BuyTokenDestination::Erc20, - ..Default::default() - }, - SigningScheme::Eip712, - // ......0 - sell order - // .....0. - fill-or-kill order - // ...00.. - ERC20 sell token balance - // ..0.... - ERC20 buy token balance - // 00..... - EIP-712 signing scheme - 0b0000000, - ), - ( - OrderData { - kind: OrderKind::Sell, - partially_fillable: true, - sell_token_balance: SellTokenSource::Erc20, - buy_token_balance: BuyTokenDestination::Internal, - ..Default::default() - }, - SigningScheme::Eip1271, - // ......0 - sell order - // .....1. - partially fillable order - // ...00.. - ERC20 sell token balance - // ..1.... - Vault-internal buy token balance - // 10..... - EIP-712 signing scheme - 0b1010010, - ), - ( - OrderData { - kind: OrderKind::Buy, - partially_fillable: false, - sell_token_balance: SellTokenSource::External, - buy_token_balance: BuyTokenDestination::Erc20, - ..Default::default() - }, - SigningScheme::PreSign, - // ......1 - buy order - // .....0. - fill-or-kill order - // ...10.. - Vault-external sell token balance - // ..0.... - ERC20 buy token balance - // 11..... - Pre-sign signing scheme - 0b1101001, - ), - ( - OrderData { - kind: OrderKind::Sell, - partially_fillable: false, - sell_token_balance: SellTokenSource::Internal, - buy_token_balance: BuyTokenDestination::Erc20, - ..Default::default() - }, - SigningScheme::EthSign, - // ......0 - sell order - // .....0. - fill-or-kill order - // ...11.. - Vault-internal sell token balance - // ..0.... - ERC20 buy token balance - // 01..... - Eth-sign signing scheme - 0b0101100, - ), - ( - OrderData { - kind: OrderKind::Buy, - partially_fillable: true, - sell_token_balance: SellTokenSource::Internal, - buy_token_balance: BuyTokenDestination::Internal, - ..Default::default() - }, - SigningScheme::PreSign, - // ......1 - buy order - // .....1. - partially fillable order - // ...11.. - Vault-internal sell token balance - // ..1.... - Vault-internal buy token balance - // 11..... - Pre-sign signing scheme - 0b1111111, - ), - ] { - assert_eq!( - order_flags(&order, &Signature::default_with(scheme)), - U256::from(flags) - ); - } - } - - #[test] - fn trade_signature_encoding() { - let owner = H160([1; 20]); - for (signature, bytes) in [ - (Signature::Eip712(Default::default()), vec![0; 65]), - ( - Signature::EthSign(EcdsaSignature { - r: H256([1; 32]), - s: H256([1; 32]), - v: 1, - }), - vec![1; 65], - ), - ( - Signature::Eip1271(vec![1, 2, 3, 4]), - hex!( - "0101010101010101010101010101010101010101" - "01020304" - ) - .to_vec(), - ), - (Signature::PreSign, vec![1; 20]), - ] { - let (.., encoded_signature) = encode_trade( - &Default::default(), - &signature, - owner, - Default::default(), - Default::default(), - &Default::default(), - ); - assert_eq!(encoded_signature.0, bytes); - } - } -} diff --git a/crates/shared/src/event_storing_helpers.rs b/crates/shared/src/event_storing_helpers.rs index aa43a0e0d1..fef7d56bb1 100644 --- a/crates/shared/src/event_storing_helpers.rs +++ b/crates/shared/src/event_storing_helpers.rs @@ -15,8 +15,8 @@ use { pub fn create_quote_row(data: QuoteData) -> Result { Ok(DbQuote { id: Default::default(), - sell_token: ByteArray(data.sell_token.0), - buy_token: ByteArray(data.buy_token.0), + sell_token: ByteArray(*data.sell_token.0), + buy_token: ByteArray(*data.buy_token.0), sell_amount: u256_to_big_decimal(&data.quoted_sell_amount), buy_amount: u256_to_big_decimal(&data.quoted_buy_amount), gas_amount: data.fee_parameters.gas_amount, @@ -25,7 +25,7 @@ pub fn create_quote_row(data: QuoteData) -> Result { order_kind: order_kind_into(data.kind), expiration_timestamp: data.expiration, quote_kind: data.quote_kind, - solver: ByteArray(data.solver.0), + solver: ByteArray(*data.solver.0), verified: data.verified, metadata: data.metadata.try_into()?, }) @@ -36,8 +36,8 @@ pub fn create_db_search_parameters( expiration: DateTime, ) -> DbQuoteSearchParameters { DbQuoteSearchParameters { - sell_token: ByteArray(params.sell_token.0), - buy_token: ByteArray(params.buy_token.0), + sell_token: ByteArray(*params.sell_token.0), + buy_token: ByteArray(*params.buy_token.0), sell_amount_0: u256_to_big_decimal(¶ms.sell_amount), sell_amount_1: u256_to_big_decimal(&(params.sell_amount + params.fee_amount)), buy_amount: u256_to_big_decimal(¶ms.buy_amount), diff --git a/crates/shared/src/external_prices.rs b/crates/shared/src/external_prices.rs index 77a08cd6d3..26a2bbd775 100644 --- a/crates/shared/src/external_prices.rs +++ b/crates/shared/src/external_prices.rs @@ -6,11 +6,11 @@ //! native asset and native wrapped token exist with a value of 1. use { - crate::conversions::U256Ext, + alloy::primitives::{Address, U256}, anyhow::{Result, bail}, - ethcontract::{H160, U256}, model::order::BUY_ETH_ADDRESS, num::{BigInt, BigRational, One as _, ToPrimitive as _}, + number::u256_ext::U256Ext, std::{ collections::{BTreeMap, HashMap}, sync::LazyLock, @@ -20,11 +20,14 @@ use { /// A collection of external prices used for converting token amounts to native /// assets. #[derive(Clone, Debug)] -pub struct ExternalPrices(HashMap); +pub struct ExternalPrices(HashMap); impl ExternalPrices { /// Creates a new set of external prices for the specified exchange rates. - pub fn try_new(native_token: H160, mut xrates: HashMap) -> Result { + pub fn try_new( + native_token: Address, + mut xrates: HashMap, + ) -> Result { // Make sure to verify our invariant that native asset price and native // wrapped asset price exist with a value of 1. This protects us from // malformed input (in case there are issues with the prices from the @@ -47,8 +50,8 @@ impl ExternalPrices { /// Returns a set of external prices for the specified auction model prices. pub fn try_from_auction_prices( - native_token: H160, - prices: BTreeMap, + native_token: Address, + prices: BTreeMap, ) -> Result { Self::try_new( native_token, @@ -63,7 +66,7 @@ impl ExternalPrices { /// I.e., the price of the native token is 1 and /// the price of a token T is represented as how much native token // is needed in order to buy 1 atom of the token T - pub fn price(&self, token: &H160) -> Option<&BigRational> { + pub fn price(&self, token: &Address) -> Option<&BigRational> { self.0.get(token) } } @@ -103,7 +106,7 @@ mod tests { // GNO is typically traded at around Ξ0.1. With the price // representation we use here, this would be 1e17. - let gno_price = U256::from_f64_lossy(1e17); + let gno_price = U256::from(10).pow(U256::from(17)); let gno_xrate = to_native_xrate(gno_price); assert_eq!( gno_xrate, @@ -121,18 +124,18 @@ mod tests { #[test] fn augments_price_map_with_native_token_prices() { - let native_token = H160([42; 20]); + let native_token = Address::repeat_byte(42); assert_eq!( ExternalPrices::try_from_auction_prices( native_token, btreemap! { - H160([1; 20]) => U256::from(100_000_000_000_000_000_u128), + Address::repeat_byte(1) => U256::from(100_000_000_000_000_000_u128), }, ) .unwrap() .0, hashmap! { - H160([1; 20]) => BigRational::new(1.into(), 10.into()), + Address::repeat_byte(1) => BigRational::new(1.into(), 10.into()), native_token => BigRational::one(), BUY_ETH_ADDRESS => BigRational::one(), }, @@ -141,7 +144,7 @@ mod tests { #[test] fn from_auction_price_errors_on_invalid_native_prices() { - let native_token = H160([42; 20]); + let native_token = Address::repeat_byte(42); assert!( ExternalPrices::try_from_auction_prices( native_token, diff --git a/crates/shared/src/fee.rs b/crates/shared/src/fee.rs index 4bea308ada..9160d2d4ce 100644 --- a/crates/shared/src/fee.rs +++ b/crates/shared/src/fee.rs @@ -1,4 +1,8 @@ -use ethcontract::U256; +use { + crate::arguments::TokenBucketFeeOverride, + alloy::primitives::{Address, U256}, + configs::fee_factor::FeeFactor, +}; /// Everything required to compute the fee amount in sell token #[derive(Debug, Clone, Copy, PartialEq)] @@ -41,6 +45,97 @@ impl FeeParameters { // 1. For final amounts that end up close to 0 atoms we always take a fee so we // are not attackable through low decimal tokens. // 2. When validating fees this consistently picks the same amount. - U256::from_f64_lossy((fee_in_eth / self.sell_token_price).ceil()) + U256::from((fee_in_eth / self.sell_token_price).ceil()) + } +} + +pub struct VolumeFeePolicy { + bucket_overrides: Vec, + default_factor: Option, + enable_sell_equals_buy_volume_fee: bool, +} + +impl VolumeFeePolicy { + pub fn new( + bucket_overrides: Vec, + default_factor: Option, + enable_sell_equals_buy_volume_fee: bool, + ) -> Self { + Self { + bucket_overrides, + default_factor, + enable_sell_equals_buy_volume_fee, + } + } + + /// Determines the applicable volume fee factor for a token pair, + /// considering same-token trade configuration, token bucket overrides + /// and default fee factor. + /// + /// `fee_factor_override` can be used to provide an ad-hoc default factor + /// which is useful in autopilot where the factor is not known upfront. + pub fn get_applicable_volume_fee_factor( + &self, + buy_token: Address, + sell_token: Address, + fee_factor: Option, + ) -> Option { + // Skip volume fee for same-token trades if the flag is disabled + if buy_token == sell_token && !self.enable_sell_equals_buy_volume_fee { + return None; + } + + // Check for token bucket overrides first (both tokens must be in the same + // bucket) + for fee_override in &self.bucket_overrides { + if fee_override.tokens.contains(&buy_token) && fee_override.tokens.contains(&sell_token) + { + return Some(fee_override.factor); + } + } + + // Fall back to default factor either from argument or configured default + fee_factor.or(self.default_factor) + } +} + +#[cfg(test)] +mod tests { + use {super::*, alloy::primitives::address}; + + #[test] + fn test_volume_fee_bucket_override() { + let usdc = address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); + let dai = address!("6B175474E89094C44Da98b954EedeAC495271d0F"); + let usdt = address!("dAC17F958D2ee523a2206206994597C13D831ec7"); + let weth = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); + + let bucket_pair_override = TokenBucketFeeOverride { + tokens: [usdc, dai].into_iter().collect(), + factor: FeeFactor::try_from(0.0005).unwrap(), // 0.05% + }; + let bucket_group_override = TokenBucketFeeOverride { + tokens: [usdc, dai, usdt].into_iter().collect(), + factor: FeeFactor::try_from(0.0).unwrap(), // 0% + }; + + let default_fee = FeeFactor::try_from(0.001).unwrap(); // 0.1% + let volume_fee_policy = VolumeFeePolicy::new( + vec![bucket_pair_override, bucket_group_override], + Some(default_fee), + false, + ); + + // USDC-DAI (matches both buckets) - pair bucket takes precedence + let override_ = volume_fee_policy.get_applicable_volume_fee_factor(usdc, dai, None); + assert_eq!(override_, Some(FeeFactor::try_from(0.0005).unwrap())); + + // DAI-USDT (only in 3-token bucket) - should have override + let override_ = volume_fee_policy.get_applicable_volume_fee_factor(dai, usdt, None); + assert_eq!(override_, Some(FeeFactor::try_from(0.0).unwrap())); + + // WETH-DAI (only one in bucket) - should fall back to default fee + let override_ = volume_fee_policy.get_applicable_volume_fee_factor(weth, dai, None); + assert_eq!(override_, Some(default_fee)); } } diff --git a/crates/shared/src/gas_price.rs b/crates/shared/src/gas_price.rs deleted file mode 100644 index c67b495092..0000000000 --- a/crates/shared/src/gas_price.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Module defining an instrumented Ethereum gas price estimator. -//! -//! This allows us to keep track of historic gas prices in Grafana and do things -//! like alert when gas prices get too high as well as detect spikes and other -//! anomalies. - -use { - anyhow::Result, - gas_estimation::{GasPrice1559, GasPriceEstimating}, - std::time::Duration, - tracing::instrument, -}; - -/// An instrumented gas price estimator that wraps an inner one. -pub struct InstrumentedGasEstimator { - inner: T, - metrics: &'static Metrics, -} - -impl InstrumentedGasEstimator -where - T: GasPriceEstimating, -{ - pub fn new(inner: T) -> Self { - Self { - inner, - metrics: Metrics::instance(observe::metrics::get_storage_registry()).unwrap(), - } - } -} - -#[async_trait::async_trait] -impl GasPriceEstimating for InstrumentedGasEstimator -where - T: GasPriceEstimating, -{ - #[instrument(skip_all)] - async fn estimate_with_limits( - &self, - gas_limit: f64, - time_limit: Duration, - ) -> Result { - // Instrumenting gas estimates with limits is hard. Since we don't use - // it in the orderbook, lets leave this out for now. - self.inner.estimate_with_limits(gas_limit, time_limit).await - } - - #[instrument(skip_all)] - async fn estimate(&self) -> Result { - let estimate = self.inner.estimate().await?; - self.metrics - .gas_price - .set(estimate.effective_gas_price() / 1e9); - Ok(estimate) - } -} - -#[derive(prometheus_metric_storage::MetricStorage)] -struct Metrics { - /// Last measured gas price in gwei - gas_price: prometheus::Gauge, -} diff --git a/crates/shared/src/gas_price_estimation/alloy.rs b/crates/shared/src/gas_price_estimation/alloy.rs deleted file mode 100644 index db4e25aa2a..0000000000 --- a/crates/shared/src/gas_price_estimation/alloy.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Uses `alloy`'s logic for suggesting reasonable EIP-1559 -//! gas price values. It computes the suggested gas price -//! based on the 20th percentile of fee rewards for -//! transactions of the last 10 blocks. -//! See -//! for the implementation details. - -use { - alloy::{consensus::BlockHeader, providers::Provider}, - anyhow::{Context, Result}, - ethrpc::AlloyProvider, - futures::TryFutureExt, - gas_estimation::{GasPrice1559, GasPriceEstimating}, - std::{ops::Mul, time::Duration}, - tracing::instrument, -}; - -pub struct AlloyGasPriceEstimator(AlloyProvider); - -impl AlloyGasPriceEstimator { - pub fn new(provider: AlloyProvider) -> Self { - Self(provider) - } -} - -#[async_trait::async_trait] -impl GasPriceEstimating for AlloyGasPriceEstimator { - #[instrument(skip(self))] - async fn estimate_with_limits( - &self, - _gas_limit: f64, - _time_limit: Duration, - ) -> Result { - let estimate_fees = self - .0 - .estimate_eip1559_fees() - .map_err(|err| anyhow::anyhow!("could not estimate EIP 1559 fees: {err:?}")); - let get_block = self - .0 - .get_block(alloy::eips::BlockId::Number( - alloy::eips::BlockNumberOrTag::Latest, - )) - .into_future() - .map_err(|err| anyhow::anyhow!("could not fetch latest block: {err:?}")); - let (fees, block) = tokio::try_join!(estimate_fees, get_block)?; - - /// `Alloy`'s constant growth factor to estimate the base_fee - /// of the next block. () - const MAX_GAS_PRICE_INCREASE_PER_BLOCK: f64 = 2.; - - let base_fee_per_gas = u64_to_f64( - block - .context("latest block is missing")? - .into_consensus_header() - .base_fee_per_gas() - .context("no base_fee_per_gas")?, - ) - .context("could not convert base_fee_per_gas to f64")? - .mul(MAX_GAS_PRICE_INCREASE_PER_BLOCK); - - Ok(GasPrice1559 { - base_fee_per_gas, - max_fee_per_gas: u128_to_f64(fees.max_fee_per_gas) - .context("could not convert max_fee_per_gas to f64")?, - max_priority_fee_per_gas: u128_to_f64(fees.max_priority_fee_per_gas) - .context("could not convert max_priority_fee_per_gas to f64")?, - }) - } -} - -fn u128_to_f64(val: u128) -> Result { - if val > 2u128.pow(f64::MANTISSA_DIGITS) { - anyhow::bail!(format!("could not convert u128 to f64: {val}")); - } - Ok(val as f64) -} - -fn u64_to_f64(val: u64) -> Result { - if val > 2u64.pow(f64::MANTISSA_DIGITS) { - anyhow::bail!(format!("could not convert u64 to f64: {val}")); - } - Ok(val as f64) -} diff --git a/crates/shared/src/gas_price_estimation/fake.rs b/crates/shared/src/gas_price_estimation/fake.rs deleted file mode 100644 index 4ecd612dfe..0000000000 --- a/crates/shared/src/gas_price_estimation/fake.rs +++ /dev/null @@ -1,20 +0,0 @@ -use { - anyhow::Result, - gas_estimation::{GasPrice1559, GasPriceEstimating}, -}; - -#[derive(Default)] -pub struct FakeGasPriceEstimator(pub GasPrice1559); - -impl FakeGasPriceEstimator { - pub fn new(gas_price: GasPrice1559) -> Self { - Self(gas_price) - } -} - -#[async_trait::async_trait] -impl GasPriceEstimating for FakeGasPriceEstimator { - async fn estimate_with_limits(&self, _: f64, _: std::time::Duration) -> Result { - Ok(self.0) - } -} diff --git a/crates/shared/src/gas_price_estimation/mod.rs b/crates/shared/src/gas_price_estimation/mod.rs deleted file mode 100644 index 750c96c5e0..0000000000 --- a/crates/shared/src/gas_price_estimation/mod.rs +++ /dev/null @@ -1,81 +0,0 @@ -pub mod alloy; -pub mod driver; -pub mod fake; - -use { - crate::{ - ethrpc::Web3, - gas_price_estimation::alloy::AlloyGasPriceEstimator, - http_client::HttpClientFactory, - }, - anyhow::Result, - gas_estimation::{ - GasPriceEstimating, - PriorityGasPriceEstimating, - nativegasestimator::NativeGasEstimator, - }, - std::str::FromStr, - tracing::instrument, - url::Url, -}; -pub use {driver::DriverGasEstimator, fake::FakeGasPriceEstimator}; - -#[derive(Clone, Debug)] -pub enum GasEstimatorType { - Web3, - Native, - Driver(Url), - Alloy, -} - -impl FromStr for GasEstimatorType { - type Err = String; - - fn from_str(s: &str) -> Result { - match s.to_ascii_lowercase().as_str() { - "web3" => Ok(GasEstimatorType::Web3), - "alloy" => Ok(GasEstimatorType::Alloy), - "native" => Ok(GasEstimatorType::Native), - _ => Url::parse(s).map(GasEstimatorType::Driver).map_err(|e| { - format!("expected 'web3', 'native', or a valid driver URL; got {s:?}: {e}") - }), - } - } -} - -#[instrument(skip_all)] -pub async fn create_priority_estimator( - http_factory: &HttpClientFactory, - web3: &Web3, - estimator_types: &[GasEstimatorType], -) -> Result> { - let network_id = web3.eth().chain_id().await?.to_string(); - let mut estimators = Vec::>::new(); - - for estimator_type in estimator_types { - tracing::info!("estimator {estimator_type:?}, networkid {network_id}"); - match estimator_type { - GasEstimatorType::Driver(url) => { - estimators.push(Box::new(DriverGasEstimator::new( - http_factory.create(), - url.clone(), - ))); - } - GasEstimatorType::Web3 => estimators.push(Box::new(web3.legacy.clone())), - GasEstimatorType::Alloy => { - estimators.push(Box::new(AlloyGasPriceEstimator::new(web3.alloy.clone()))) - } - GasEstimatorType::Native => { - match NativeGasEstimator::new(web3.transport().clone(), None).await { - Ok(estimator) => estimators.push(Box::new(estimator)), - Err(err) => tracing::error!("nativegasestimator failed: {}", err), - } - } - } - } - anyhow::ensure!( - !estimators.is_empty(), - "all gas estimators failed to initialize" - ); - Ok(PriorityGasPriceEstimating::new(estimators)) -} diff --git a/crates/shared/src/http_solver.rs b/crates/shared/src/http_solver.rs index 805e2d84ab..161e2e464b 100644 --- a/crates/shared/src/http_solver.rs +++ b/crates/shared/src/http_solver.rs @@ -1,14 +1,17 @@ pub mod model { - use {ethcontract::H160, primitive_types::U256, serde::Serialize}; + use { + alloy::primitives::{Address, U256}, + serde::Serialize, + }; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct TokenAmount { pub amount: U256, - pub token: H160, + pub token: Address, } impl TokenAmount { - pub fn new>(token: H160, amount: T) -> Self { + pub fn new>(token: Address, amount: T) -> Self { Self { amount: amount.into(), token, diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index bf6aaaa255..66f00b8303 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -1,45 +1,22 @@ -use {ethcontract::Account, primitive_types::H160, std::sync::LazyLock}; - #[macro_use] pub mod macros; -pub mod account_balances; pub mod arguments; -pub mod bad_token; -pub mod baseline_solver; -pub mod code_fetching; -pub mod conversions; pub mod current_block; pub mod db_order_conversions; -pub mod encoded_settlement; -pub mod ethrpc; -pub mod event_handling; pub mod event_storing_helpers; pub mod external_prices; pub mod fee; -pub mod gas_price; -pub mod gas_price_estimation; -pub mod http_client; pub mod http_solver; pub mod interaction; -pub mod maintenance; +pub mod order_creation_simulation; pub mod order_quoting; pub mod order_validation; -pub mod price_estimation; -pub mod recent_block_cache; pub mod remaining_amounts; -pub mod request_sharing; -pub mod signature_validator; -pub mod sources; -pub mod subgraph; -pub mod submitter_constants; -pub mod tenderly_api; -pub mod token_info; +pub mod retry; pub mod token_list; -pub mod trace_many; -pub mod trade_finding; pub mod url; -pub mod zeroex_api; +pub mod web3; /// anyhow errors are not clonable natively. This is a workaround that creates a /// new anyhow error based on formatting the error with its inner sources @@ -47,8 +24,3 @@ pub mod zeroex_api; pub fn clone_anyhow_error(err: &anyhow::Error) -> anyhow::Error { anyhow::anyhow!("{:#}", err) } - -// ZKSync-based chains don't use the default 0x0 account when `tx.from` is not -// specified, so we need to use a random account when sending a simulation tx. -pub static SIMULATION_ACCOUNT: LazyLock = - LazyLock::new(|| Account::Local(H160::random(), None)); diff --git a/crates/shared/src/macros.rs b/crates/shared/src/macros.rs index 628612a230..5465d2747d 100644 --- a/crates/shared/src/macros.rs +++ b/crates/shared/src/macros.rs @@ -1,38 +1,3 @@ -#[macro_export] -macro_rules! addr { - ($val:literal) => { - ::ethcontract::H160(::hex_literal::hex!($val)) - }; -} - -#[macro_export] -macro_rules! bfp { - ($val:literal) => { - ($val) - .parse::<$crate::sources::balancer_v2::swap::fixed_point::Bfp>() - .unwrap() - }; -} - -#[macro_export] -macro_rules! bytes { - ($x:literal) => { - ::ethcontract::web3::types::Bytes(::hex_literal::hex!($x).to_vec()) - }; -} - -#[macro_export] -macro_rules! json_map { - ($($key:expr_2021 => $value:expr_2021),* $(,)?) => {{ - #[allow(unused_mut)] - let mut map = ::serde_json::Map::::new(); - $( - map.insert(($key).into(), ($value).into()); - )* - map - }} -} - #[macro_export] macro_rules! externalprices { (native_token: $nt:expr_2021 $(, $($t:tt)*)?) => { diff --git a/crates/shared/src/order_creation_simulation.rs b/crates/shared/src/order_creation_simulation.rs new file mode 100644 index 0000000000..9d55d0d09a --- /dev/null +++ b/crates/shared/src/order_creation_simulation.rs @@ -0,0 +1,107 @@ +use { + anyhow::anyhow, + async_trait::async_trait, + model::order::Order, + simulator::{ + simulation_builder::{ + self, + Block, + ExecutionAmount, + PriceEncoding, + SettlementSimulator, + Solver, + }, + tenderly, + }, +}; + +/// Outcome of the order creation simulation. +#[derive(Debug)] +pub enum OrderSimulationError { + /// The simulation ran and the transaction reverted. `reason` is the + /// revert string returned by the EVM (or a Tenderly reason string). + /// `tenderly_request` carries the full payload (calldata, state + /// overrides, block) needed to replay the simulation manually or against + /// Tenderly's API, independent of whether `tenderly_url` was produced. + /// Boxed because the request DTO is large enough that an inline copy + /// would blow up `Result<(), OrderSimulationError>`'s stack footprint. + Reverted { + reason: String, + tenderly_url: Option, + tenderly_request: Option>, + }, + /// The simulation could not run (RPC failure, Tenderly error, malformed + /// input, timeout). Treated as fail-open. + Infra(anyhow::Error), +} + +/// Simulates an order's pre-hooks, swap, and post-hooks against the chain. +#[cfg_attr(any(test, feature = "test-util"), mockall::automock)] +#[async_trait] +pub trait OrderSimulating: Send + Sync { + async fn simulate( + &self, + order: &Order, + full_app_data: &str, + ) -> Result<(), OrderSimulationError>; +} + +/// Drives [`SettlementSimulator`] to run a full-order simulation at order +/// creation time, including pre/post hooks, swap, and any wrapper chain. +pub struct OrderCreationSimulator { + inner: SettlementSimulator, +} + +impl OrderCreationSimulator { + pub fn new(inner: SettlementSimulator) -> Self { + Self { inner } + } +} + +#[async_trait] +impl OrderSimulating for OrderCreationSimulator { + #[tracing::instrument(skip_all, fields(order_uid = %order.metadata.uid))] + async fn simulate( + &self, + order: &Order, + full_app_data: &str, + ) -> Result<(), OrderSimulationError> { + let sim_order = simulation_builder::Order::new(order.data) + .with_signature(order.metadata.owner, order.signature.clone()) + .fill_at(ExecutionAmount::Full, PriceEncoding::LimitPrice); + + let inputs = self + .inner + .new_simulation_builder() + .with_orders([sim_order]) + .parameters_from_app_data(full_app_data) + .map_err(|err| OrderSimulationError::Infra(anyhow!(err).context("parse app data")))? + .from_solver(Solver::Fake(None)) + .provide_sufficient_buy_tokens() + .presign_orders() + .at_block(Block::Latest) + .build() + .await + .map_err(|err| OrderSimulationError::Infra(anyhow!(err).context("build")))?; + + // Capture the Tenderly handle and the diagnostic request before + // consuming `inputs` with `simulate()`. The Tenderly call is only + // dispatched on revert, since the URL is only useful for diagnostics + // and most simulations succeed. + let tenderly = inputs.simulator.tenderly(); + let tenderly_request = inputs.to_tenderly_request().ok(); + + let Err(err) = inputs.simulate().await else { + return Ok(()); + }; + let tenderly_url = match (tenderly, tenderly_request.as_ref()) { + (Some(api), Some(req)) => api.simulate_and_share(req.clone()).await.ok(), + _ => None, + }; + Err(OrderSimulationError::Reverted { + reason: err.to_string(), + tenderly_url, + tenderly_request: tenderly_request.map(Box::new), + }) + } +} diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 383706df22..be6e0426e6 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -1,25 +1,15 @@ use { - super::price_estimation::{ - self, - PriceEstimating, - PriceEstimationError, - native::NativePriceEstimating, - }, crate::{ - account_balances::{BalanceFetching, Query}, db_order_conversions::order_kind_from, fee::FeeParameters, order_validation::PreOrderData, - price_estimation::{Estimate, QuoteVerificationMode, Verification}, - trade_finding::external::dto, }, + alloy::primitives::{Address, U256, U512, ruint::UintTryFrom}, anyhow::{Context, Result}, chrono::{DateTime, Duration, Utc}, database::quotes::{Quote as QuoteRow, QuoteKind}, - ethcontract::{H160, U256}, - ethrpc::alloy::conversions::IntoAlloy, futures::TryFutureExt, - gas_estimation::GasPriceEstimating, + gas_price_estimation::GasPriceEstimating, model::{ interaction::InteractionData, order::{OrderClass, OrderKind}, @@ -27,6 +17,14 @@ use { }, num::FromPrimitive, number::conversions::big_decimal_to_u256, + price_estimation::{ + self, + PriceEstimating, + PriceEstimationError, + Verification, + native::NativePriceEstimating, + trade_finding::external::dto, + }, std::sync::Arc, thiserror::Error, tracing::instrument, @@ -35,8 +33,8 @@ use { /// Order parameters for quoting. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct QuoteParameters { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, pub side: OrderQuoteSide, pub verification: Verification, pub signing_scheme: QuoteSigningScheme, @@ -48,6 +46,7 @@ impl QuoteParameters { fn to_price_query( &self, default_quote_timeout: std::time::Duration, + max_quote_timeout: std::time::Duration, ) -> price_estimation::Query { let (kind, in_amount) = match self.side { OrderQuoteSide::Sell { @@ -63,12 +62,12 @@ impl QuoteParameters { let timeout = self .timeout .unwrap_or(default_quote_timeout) - .min(default_quote_timeout); + .min(max_quote_timeout); price_estimation::Query { verification: self.verification.clone(), - sell_token: self.sell_token.into_alloy(), - buy_token: self.buy_token.into_alloy(), + sell_token: self.sell_token, + buy_token: self.buy_token, in_amount, kind, block_dependent: true, @@ -144,10 +143,14 @@ impl Quote { self.sell_amount = sell_amount; // Use `full_mul: (U256, U256) -> U512` to avoid any overflow // errors computing the initial product. - self.buy_amount = (self.data.quoted_buy_amount.full_mul(sell_amount) - / self.data.quoted_sell_amount) - .try_into() - .unwrap_or(U256::MAX); + + self.buy_amount = U256::uint_try_from( + self.data + .quoted_buy_amount + .widening_mul::<_, _, 512, 8>(sell_amount) + / U512::from(self.data.quoted_sell_amount), + ) + .unwrap_or(U256::MAX); self } @@ -165,6 +168,7 @@ impl Quote { .context("sell token price is not a valid BigDecimal")?, sell_amount: self.sell_amount, buy_amount: self.buy_amount, + fee_amount: self.fee_amount, solver: self.data.solver, verified: self.data.verified, metadata: serde_json::to_value(&self.data.metadata)?, @@ -175,8 +179,8 @@ impl Quote { /// Detailed data for a computed order quote. #[derive(Clone, Debug, Default, PartialEq)] pub struct QuoteData { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, /// The sell amount used when computing the exchange rate for this quote. /// /// For buy orders, this will be the expected sell amount for some fixed @@ -200,7 +204,7 @@ pub struct QuoteData { /// we need to store the quote kind to prevent missuse of quotes. pub quote_kind: QuoteKind, /// The address of the solver that provided the quote. - pub solver: H160, + pub solver: Address, /// Were we able to verify that this quote is accurate? pub verified: bool, /// Additional data associated with the quote. @@ -212,8 +216,8 @@ impl TryFrom for QuoteData { fn try_from(row: QuoteRow) -> Result { Ok(QuoteData { - sell_token: H160(row.sell_token.0), - buy_token: H160(row.buy_token.0), + sell_token: Address::from_slice(&row.sell_token.0), + buy_token: Address::from_slice(&row.buy_token.0), quoted_sell_amount: big_decimal_to_u256(&row.sell_amount) .context("quoted sell amount is not a valid U256")?, quoted_buy_amount: big_decimal_to_u256(&row.buy_amount) @@ -226,7 +230,7 @@ impl TryFrom for QuoteData { kind: order_kind_from(row.order_kind), expiration: row.expiration_timestamp, quote_kind: row.quote_kind, - solver: H160(row.solver.0), + solver: Address::from_slice(&row.solver.0), verified: row.verified, metadata: row.metadata.try_into()?, }) @@ -256,7 +260,7 @@ pub trait OrderQuoting: Send + Sync { #[derive(Error, Debug)] pub enum CalculateQuoteError { - #[error("sell amount does not cover fee")] + #[error("sell amount does not cover fee {fee_amount:?}")] SellAmountDoesNotCoverFee { fee_amount: U256 }, #[error("{estimator_kind:?} estimator failed: {source}")] @@ -311,8 +315,8 @@ pub enum FindQuoteError { /// Fields for searching stored quotes. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct QuoteSearchParameters { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, pub sell_amount: U256, pub buy_amount: U256, pub fee_amount: U256, @@ -412,23 +416,24 @@ pub struct OrderQuoter { storage: Arc, now: Arc, validity: Validity, - balance_fetcher: Arc, - quote_verification: QuoteVerificationMode, default_quote_timeout: std::time::Duration, + max_quote_timeout: std::time::Duration, } impl OrderQuoter { - #[expect(clippy::too_many_arguments)] pub fn new( price_estimator: Arc, native_price_estimator: Arc, gas_estimator: Arc, storage: Arc, validity: Validity, - balance_fetcher: Arc, - quote_verification: QuoteVerificationMode, default_quote_timeout: std::time::Duration, + max_quote_timeout: std::time::Duration, ) -> Self { + assert!( + max_quote_timeout >= default_quote_timeout, + "max-quote-timeout needs to be greater or equal quote-timeout" + ); Self { price_estimator, native_price_estimator, @@ -436,9 +441,8 @@ impl OrderQuoter { storage, now: Arc::new(Utc::now), validity, - balance_fetcher, - quote_verification, default_quote_timeout, + max_quote_timeout, } } @@ -457,10 +461,11 @@ impl OrderQuoter { _ => self.now.now() + self.validity.standard_quote, }; - let trade_query = Arc::new(parameters.to_price_query(self.default_quote_timeout)); - let (gas_estimate, trade_estimate, sell_token_price, _) = futures::try_join!( + let trade_query = + Arc::new(parameters.to_price_query(self.default_quote_timeout, self.max_quote_timeout)); + let (effective_gas_price, trade_estimate, sell_token_price, _) = futures::try_join!( self.gas_estimator - .estimate() + .effective_gas_price() .map_err(|err| CalculateQuoteError::from(( EstimatorKind::Gas, PriceEstimationError::ProtocolInternal(err) @@ -469,13 +474,13 @@ impl OrderQuoter { .estimate(trade_query.clone()) .map_err(|err| (EstimatorKind::Regular, err).into()), self.native_price_estimator - .estimate_native_price(parameters.sell_token.into_alloy(), trade_query.timeout) + .estimate_native_price(parameters.sell_token, trade_query.timeout) .map_err(|err| (EstimatorKind::NativeSell, err).into()), // We don't care about the native price of the buy_token for the quote but we need it // when we build the auction. To prevent creating orders which we can't settle later on // we make the native buy_token price a requirement here as well. self.native_price_estimator - .estimate_native_price(parameters.buy_token.into_alloy(), trade_query.timeout) + .estimate_native_price(parameters.buy_token, trade_query.timeout) .map_err(|err| (EstimatorKind::NativeBuy, err).into()), )?; @@ -490,15 +495,13 @@ impl OrderQuoter { buy_amount_after_fee: buy_amount, } => (trade_estimate.out_amount, buy_amount.get()), }; + let fee_parameters = FeeParameters { - gas_amount: trade_estimate.gas as _, - gas_price: gas_estimate.effective_gas_price(), + gas_amount: trade_estimate.gas as f64, + gas_price: effective_gas_price as f64, sell_token_price, }; - self.verify_quote(&trade_estimate, parameters, quoted_sell_amount) - .await?; - let quote_kind = quote_kind_from_signing_scheme(¶meters.signing_scheme); let quote = QuoteData { sell_token: parameters.sell_token, @@ -521,64 +524,6 @@ impl OrderQuoter { Ok(quote) } - - /// Makes sure a quote was verified according to the configured rule. - async fn verify_quote( - &self, - estimate: &Estimate, - parameters: &QuoteParameters, - sell_amount: U256, - ) -> Result<(), CalculateQuoteError> { - if estimate.verified - || !matches!( - self.quote_verification, - QuoteVerificationMode::EnforceWhenPossible - ) - { - // verification was successful or not strictly required - return Ok(()); - } - - let balance = match self - .get_balance(¶meters.verification, parameters.sell_token) - .await - { - Ok(balance) => balance, - Err(err) => { - tracing::warn!(?err, "could not fetch balance for verification"); - return Err(CalculateQuoteError::QuoteNotVerified); - } - }; - - if balance >= sell_amount { - // Quote could not be verified although user has the required balance. - // This likely indicates a weird token that solvers are not able to handle. - return Err(CalculateQuoteError::QuoteNotVerified); - } - - Ok(()) - } - - async fn get_balance(&self, verification: &Verification, token: H160) -> Result { - let query = Query { - owner: verification.from, - token, - source: verification.sell_token_source, - interactions: verification - .pre_interactions - .iter() - .map(|i| InteractionData { - target: i.target, - value: i.value, - call_data: i.data.clone(), - }) - .collect(), - // quote verification already tries to auto-fake missing balances - balance_override: None, - }; - let mut balances = self.balance_fetcher.get_balances(&[query]).await; - balances.pop().context("missing balance result")? - } } #[async_trait::async_trait] @@ -601,9 +546,10 @@ impl OrderQuoting for OrderQuoter { }, } = ¶meters.side { - let sell_amount = - Into::::into(*sell_amount_before_fee).saturating_sub(quote.fee_amount); - if sell_amount == U256::zero() { + let sell_amount = sell_amount_before_fee + .get() + .saturating_sub(quote.fee_amount); + if sell_amount.is_zero() { // We want a sell_amount of at least 1! return Err(CalculateQuoteError::SellAmountDoesNotCoverFee { fee_amount: quote.fee_amount, @@ -692,6 +638,10 @@ impl From<&OrderQuoteRequest> for PreOrderData { sell_token_balance: quote_request.sell_token_balance, signing_scheme: quote_request.signing_scheme.into(), class: OrderClass::Market, + kind: match quote_request.side { + OrderQuoteSide::Buy { .. } => OrderKind::Buy, + OrderQuoteSide::Sell { .. } => OrderKind::Sell, + }, } } } @@ -775,33 +725,23 @@ pub struct QuoteMetadataV1 { mod tests { use { super::*, - crate::{ - account_balances::MockBalanceFetching, - gas_price_estimation::FakeGasPriceEstimator, - price_estimation::{ - HEALTHY_PRICE_ESTIMATION_TIME, - MockPriceEstimating, - native::MockNativePriceEstimating, - }, + alloy::{ + eips::eip1559::Eip1559Estimation, + primitives::{Address, U256}, }, - alloy::primitives::Address, chrono::Utc, - ethcontract::H160, - ethrpc::alloy::conversions::IntoLegacy, futures::FutureExt, - gas_estimation::GasPrice1559, + gas_price_estimation::FakeGasPriceEstimator, mockall::{Sequence, predicate::eq}, model::time, - number::nonzero::U256 as NonZeroU256, + number::nonzero::NonZeroU256, + price_estimation::{ + HEALTHY_PRICE_ESTIMATION_TIME, + MockPriceEstimating, + native::MockNativePriceEstimating, + }, }; - fn mock_balance_fetcher() -> Arc { - let mut mock = MockBalanceFetching::new(); - mock.expect_get_balances() - .returning(|addresses| addresses.iter().map(|_| Ok(U256::MAX)).collect()); - Arc::new(mock) - } - #[test] fn pre_order_data_from_quote_request() { let quote_request = OrderQuoteRequest { @@ -831,25 +771,24 @@ mod tests { async fn compute_sell_before_fee_quote() { let now = Utc::now(); let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(100).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, timeout: None, }; - let gas_price = GasPrice1559 { - base_fee_per_gas: 1.5, - max_fee_per_gas: 3.0, - max_priority_fee_per_gas: 0.5, + let gas_price = Eip1559Estimation { + max_fee_per_gas: 2, + max_priority_fee_per_gas: 1, }; let mut price_estimator = MockPriceEstimating::new(); @@ -858,10 +797,10 @@ mod tests { .withf(|q| { **q == price_estimation::Query { verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, - sell_token: Address::new([1; 20]), + sell_token: Address::repeat_byte(1), buy_token: Address::new([2; 20]), in_amount: NonZeroU256::try_from(100).unwrap(), kind: OrderKind::Sell, @@ -872,9 +811,9 @@ mod tests { .returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 42.into(), + out_amount: U256::from(42), gas: 3, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, execution: Default::default(), }) @@ -887,14 +826,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); @@ -904,10 +843,10 @@ mod tests { storage .expect_save() .with(eq(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -916,7 +855,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -929,9 +868,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(now), validity: super::Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; let quote = quoter.calculate_quote(parameters).await.unwrap(); @@ -942,10 +880,10 @@ mod tests { Quote { id: Some(1337), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -954,13 +892,13 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, - sell_amount: 70.into(), - buy_amount: 29.into(), - fee_amount: 30.into(), + sell_amount: U256::from(70), + buy_amount: U256::from(29), + fee_amount: U256::from(30), } ); } @@ -969,15 +907,15 @@ mod tests { async fn compute_sell_after_fee_quote() { let now = Utc::now(); let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(100).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip1271 { @@ -987,10 +925,9 @@ mod tests { additional_gas: 2, timeout: None, }; - let gas_price = GasPrice1559 { - base_fee_per_gas: 1.5, - max_fee_per_gas: 3.0, - max_priority_fee_per_gas: 0.5, + let gas_price = Eip1559Estimation { + max_fee_per_gas: 2, + max_priority_fee_per_gas: 1, }; let mut price_estimator = MockPriceEstimating::new(); @@ -999,10 +936,10 @@ mod tests { .withf(|q| { **q == price_estimation::Query { verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, - sell_token: Address::new([1; 20]), + sell_token: Address::repeat_byte(1), buy_token: Address::new([2; 20]), in_amount: NonZeroU256::try_from(100).unwrap(), kind: OrderKind::Sell, @@ -1013,9 +950,9 @@ mod tests { .returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 42.into(), + out_amount: U256::from(42), gas: 3, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, execution: Default::default(), }) @@ -1028,14 +965,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); @@ -1045,10 +982,10 @@ mod tests { storage .expect_save() .with(eq(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1057,7 +994,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1070,9 +1007,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; let quote = quoter.calculate_quote(parameters).await.unwrap(); @@ -1083,10 +1019,10 @@ mod tests { Quote { id: Some(1337), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1095,13 +1031,13 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 60.into(), + sell_amount: U256::from(100), + buy_amount: U256::from(42), + fee_amount: U256::from(60), } ); } @@ -1110,23 +1046,22 @@ mod tests { async fn compute_buy_quote() { let now = Utc::now(); let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Buy { buy_amount_after_fee: NonZeroU256::try_from(42).unwrap(), }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, timeout: None, }; - let gas_price = GasPrice1559 { - base_fee_per_gas: 1.5, - max_fee_per_gas: 3.0, - max_priority_fee_per_gas: 0.5, + let gas_price = Eip1559Estimation { + max_fee_per_gas: 2, + max_priority_fee_per_gas: 1, }; let mut price_estimator = MockPriceEstimating::new(); @@ -1135,10 +1070,10 @@ mod tests { .withf(|q| { **q == price_estimation::Query { verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, - sell_token: Address::new([1; 20]), + sell_token: Address::repeat_byte(1), buy_token: Address::new([2; 20]), in_amount: NonZeroU256::try_from(42).unwrap(), kind: OrderKind::Buy, @@ -1149,9 +1084,9 @@ mod tests { .returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 100.into(), + out_amount: U256::from(100), gas: 3, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, execution: Default::default(), }) @@ -1164,14 +1099,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); @@ -1181,10 +1116,10 @@ mod tests { storage .expect_save() .with(eq(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1193,7 +1128,7 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1206,9 +1141,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; let quote = quoter.calculate_quote(parameters).await.unwrap(); @@ -1219,10 +1153,10 @@ mod tests { Quote { id: Some(1337), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1231,13 +1165,13 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_amount: U256::from(100), + buy_amount: U256::from(42), + fee_amount: U256::from(30), } ); } @@ -1245,34 +1179,33 @@ mod tests { #[tokio::test] async fn compute_sell_before_fee_quote_insufficient_amount_error() { let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(100).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, timeout: None, }; - let gas_price = GasPrice1559 { - base_fee_per_gas: 1., - max_fee_per_gas: 2., - max_priority_fee_per_gas: 0., + let gas_price = Eip1559Estimation { + max_fee_per_gas: 1, + max_priority_fee_per_gas: 0, }; let mut price_estimator = MockPriceEstimating::new(); price_estimator.expect_estimate().returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 100.into(), + out_amount: U256::from(100), gas: 200, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, execution: Default::default(), }) @@ -1285,14 +1218,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(1.) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(1.) }.boxed()); @@ -1305,9 +1238,8 @@ mod tests { storage: Arc::new(MockQuoteStoring::new()), now: Arc::new(Utc::now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; assert!(matches!( @@ -1319,34 +1251,33 @@ mod tests { #[tokio::test] async fn require_native_price_for_buy_token() { let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(100_000).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, timeout: None, }; - let gas_price = GasPrice1559 { - base_fee_per_gas: 1., - max_fee_per_gas: 2., - max_priority_fee_per_gas: 0., + let gas_price = Eip1559Estimation { + max_fee_per_gas: 2, + max_priority_fee_per_gas: 0, }; let mut price_estimator = MockPriceEstimating::new(); price_estimator.expect_estimate().returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 100.into(), + out_amount: U256::from(100), gas: 200, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, execution: Default::default(), }) @@ -1359,14 +1290,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(1.) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Err(PriceEstimationError::NoLiquidity) }.boxed()); @@ -1379,9 +1310,8 @@ mod tests { storage: Arc::new(MockQuoteStoring::new()), now: Arc::new(Utc::now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; assert!(matches!( @@ -1398,16 +1328,16 @@ mod tests { let now = Utc::now(); let quote_id = 42; let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 85.into(), - buy_amount: 40.into(), - fee_amount: 15.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: U256::from(85), + buy_amount: U256::from(40), + fee_amount: U256::from(15), kind: OrderKind::Sell, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, }; @@ -1415,10 +1345,10 @@ mod tests { let mut storage = MockQuoteStoring::new(); storage.expect_get().with(eq(42)).returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1427,7 +1357,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1440,9 +1370,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; assert_eq!( @@ -1450,10 +1379,10 @@ mod tests { Quote { id: Some(42), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1462,16 +1391,16 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, - sell_amount: 85.into(), + sell_amount: U256::from(85), // Allows for "out-of-price" buy amounts. This means that order // be used for providing liquidity at a premium over current // market price. - buy_amount: 35.into(), - fee_amount: 30.into(), + buy_amount: U256::from(35), + fee_amount: U256::from(30), } ); } @@ -1481,16 +1410,16 @@ mod tests { let now = Utc::now(); let quote_id = 42; let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 100.into(), - buy_amount: 40.into(), - fee_amount: 30.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: U256::from(100), + buy_amount: U256::from(40), + fee_amount: U256::from(30), kind: OrderKind::Sell, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, }; @@ -1498,10 +1427,10 @@ mod tests { let mut storage = MockQuoteStoring::new(); storage.expect_get().with(eq(42)).returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1510,7 +1439,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1523,9 +1452,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; assert_eq!( @@ -1533,10 +1461,10 @@ mod tests { Quote { id: Some(42), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1545,13 +1473,13 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_amount: U256::from(100), + buy_amount: U256::from(42), + fee_amount: U256::from(30), } ); } @@ -1560,16 +1488,16 @@ mod tests { async fn finds_quote_by_parameters() { let now = Utc::now(); let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 110.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: U256::from(110), + buy_amount: U256::from(42), + fee_amount: U256::from(30), kind: OrderKind::Buy, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, }; @@ -1582,10 +1510,10 @@ mod tests { Ok(Some(( 42, QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1594,7 +1522,7 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1608,9 +1536,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; assert_eq!( @@ -1618,10 +1545,10 @@ mod tests { Quote { id: Some(42), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: U256::from(100), + quoted_buy_amount: U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1630,13 +1557,13 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_amount: U256::from(100), + buy_amount: U256::from(42), + fee_amount: U256::from(30), } ); } @@ -1645,7 +1572,7 @@ mod tests { async fn find_invalid_quote_error() { let now = Utc::now(); let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), + sell_token: Address::repeat_byte(1), ..Default::default() }; @@ -1657,7 +1584,7 @@ mod tests { .in_sequence(&mut sequence) .returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([2; 20]), + sell_token: Address::repeat_byte(2), expiration: now, ..Default::default() })) @@ -1668,7 +1595,7 @@ mod tests { .in_sequence(&mut sequence) .returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([1; 20]), + sell_token: Address::repeat_byte(1), expiration: now - chrono::Duration::seconds(1), ..Default::default() })) @@ -1681,9 +1608,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; assert!(matches!( @@ -1712,9 +1638,8 @@ mod tests { storage: Arc::new(storage), now: Arc::new(Utc::now), validity: Validity::default(), - quote_verification: QuoteVerificationMode::Unverified, - balance_fetcher: mock_balance_fetcher(), default_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, + max_quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, }; assert!(matches!( @@ -1739,34 +1664,34 @@ mod tests { interactions: vec![ InteractionData { target: Address::from_slice(&[1; 20]), - value: alloy::primitives::U256::ONE, + value: U256::ONE, call_data: vec![1], }, InteractionData { target: Address::from_slice(&[2; 20]), - value: alloy::primitives::U256::from(2), + value: U256::from(2), call_data: vec![2], }, ], pre_interactions: vec![ InteractionData { target: Address::from_slice(&[3; 20]), - value: alloy::primitives::U256::from(3), + value: U256::from(3), call_data: vec![3], }, InteractionData { target: Address::from_slice(&[4; 20]), - value: alloy::primitives::U256::from(4), + value: U256::from(4), call_data: vec![4], }, ], jit_orders: vec![dto::JitOrder { - buy_token: H160([4; 20]), - sell_token: H160([5; 20]), + buy_token: Address::repeat_byte(4), + sell_token: Address::repeat_byte(5), sell_amount: U256::from(10), buy_amount: U256::from(20), executed_amount: U256::from(11), - receiver: H160([6; 20]), + receiver: Address::repeat_byte(6), valid_to: 1734084318, app_data: Default::default(), side: dto::Side::Sell, diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index 89c25eefa2..f5f22316d6 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -1,8 +1,6 @@ use { crate::{ - account_balances::{self, BalanceFetching, TransferSimulationError}, - bad_token::{BadTokenDetecting, TokenQuality}, - code_fetching::CodeFetching, + order_creation_simulation::{OrderSimulating, OrderSimulationError}, order_quoting::{ CalculateQuoteError, OrderQuoting, @@ -10,21 +8,16 @@ use { QuoteParameters, QuoteSearchParameters, }, - price_estimation::{ - PriceEstimationError, - Verification, - trade_verifier::balance_overrides::BalanceOverrideRequest, - }, - signature_validator::{SignatureCheck, SignatureValidating, SignatureValidationError}, - trade_finding, }, - alloy::primitives::Address, + account_balances::{self, BalanceFetching, TransferSimulationError}, + alloy::primitives::{Address, B256, U256}, anyhow::{Result, anyhow}, app_data::{AppDataHash, Hook, Hooks, ValidatedAppData, Validator}, async_trait::async_trait, - contracts::alloy::{HooksTrampoline, WETH9}, - ethcontract::{H160, H256, U256}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + bad_tokens::list_based::DenyListedTokens, + balance_overrides::BalanceOverrideRequest, + contracts::{HooksTrampoline, WETH9}, + futures::future::OptionFuture, model::{ DomainSeparator, interaction::InteractionData, @@ -47,10 +40,129 @@ use { signature::{self, Signature, SigningScheme, hashed_eip712_message}, time, }, - std::{sync::Arc, time::Duration}, + price_estimation::{PriceEstimationError, Verification}, + signature_validator::{SignatureCheck, SignatureValidating, SignatureValidationError}, + std::{ + sync::Arc, + time::{Duration, Instant}, + }, tracing::instrument, }; +/// Order simulation paired with the EIP-1271 signature check. The +/// simulation result is logged but does not affect order acceptance. +#[derive(Clone)] +pub struct OrderSimulator { + pub simulator: Arc, + pub timeout: Duration, +} + +#[derive(prometheus_metric_storage::MetricStorage)] +#[metric(subsystem = "onchain_orders")] +struct Metrics { + /// Wall-clock time of a single order simulation, labelled by outcome. + #[metric( + labels("outcome"), + buckets(0.05, 0.1, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0, 8.0) + )] + duration_seconds: prometheus::HistogramVec, +} + +impl Metrics { + fn get() -> &'static Self { + Self::instance(observe::metrics::get_storage_registry()).unwrap() + } +} + +impl OrderSimulator { + pub async fn simulate_with_timeout( + &self, + order: &Order, + full_app_data: &str, + ) -> Result<(), OrderSimulationError> { + let start = Instant::now(); + let (outcome, result) = + match tokio::time::timeout(self.timeout, self.simulator.simulate(order, full_app_data)) + .await + { + Ok(r @ Ok(())) => ("ok", r), + Ok(r @ Err(OrderSimulationError::Reverted { .. })) => ("reverted", r), + Ok(r @ Err(OrderSimulationError::Infra(_))) => ("infra", r), + Err(_) => ( + "timeout", + Err(OrderSimulationError::Infra(anyhow!( + "order simulation timeout" + ))), + ), + }; + + Metrics::get() + .duration_seconds + .with_label_values(&[outcome]) + .observe(start.elapsed().as_secs_f64()); + + result + } +} + +/// Logs disagreements (signature pass + simulation revert, or vice versa) +/// and infra errors as warnings. Agreement is silent. +fn log_simulation_outcome( + signature: &Result, + simulation: &Result<(), OrderSimulationError>, + preview_order: &Order, + full_app_data: &str, +) { + let order_uid = preview_order.metadata.uid; + let owner = preview_order.metadata.owner; + let order_data = &preview_order.data; + let order_signature = &preview_order.signature; + match (signature, simulation) { + ( + Ok(_), + Err(OrderSimulationError::Reverted { + reason, + tenderly_url, + tenderly_request, + }), + ) => { + let tenderly_request_json = tenderly_request + .as_deref() + .and_then(|r| serde_json::to_string(r).ok()) + .unwrap_or_default(); + tracing::warn!( + ?order_uid, + ?owner, + ?order_data, + full_app_data, + ?order_signature, + ?reason, + ?tenderly_url, + tenderly_request = %tenderly_request_json, + "order simulation disagreement: signature passed, simulation reverted", + ); + } + (Err(SignatureValidationError::Invalid), Ok(())) => tracing::warn!( + ?order_uid, + ?owner, + ?order_data, + full_app_data, + ?order_signature, + "order simulation disagreement: signature invalid, simulation passed", + ), + (_, Err(OrderSimulationError::Infra(err))) => tracing::warn!( + ?order_uid, + ?owner, + ?order_data, + full_app_data, + ?order_signature, + ?err, + "order simulation infra error", + ), + _ => {} + } +} + #[cfg_attr(any(test, feature = "test-util"), mockall::automock)] #[async_trait::async_trait] pub trait OrderValidating: Send + Sync { @@ -99,7 +211,7 @@ pub trait OrderValidating: Send + Sync { &self, order: OrderCreation, domain_separator: &DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, full_app_data_override: Option, ) -> Result<(Order, Option), ValidationError>; } @@ -113,7 +225,7 @@ pub enum PartialValidationError { UnsupportedBuyTokenDestination(BuyTokenDestination), UnsupportedSellTokenSource(SellTokenSource), UnsupportedOrderType, - UnsupportedToken { token: H160, reason: String }, + UnsupportedToken { token: Address, reason: String }, Other(anyhow::Error), } @@ -145,7 +257,7 @@ pub enum ValidationError { InvalidSignature, /// If fee and sell amount overflow u256 SellAmountOverflow, - TransferSimulationFailed, + TransferSimulationFailed(Vec), /// The specified on-chain signature requires the from address of the /// order signer. MissingFrom, @@ -155,7 +267,7 @@ pub enum ValidationError { WrongOwner(signature::Recovered), /// An invalid EIP-1271 signature, where the on-chain validation check /// reverted or did not return the expected value. - InvalidEip1271Signature(H256), + InvalidEip1271Signature(B256), ZeroAmount, IncompatibleSigningScheme, TooManyLimitOrders, @@ -187,10 +299,9 @@ impl From for ValidationError { CalculateQuoteError::Price { source: PriceEstimationError::UnsupportedToken { token, reason }, .. - } => ValidationError::Partial(PartialValidationError::UnsupportedToken { - token: token.into_legacy(), - reason, - }), + } => { + ValidationError::Partial(PartialValidationError::UnsupportedToken { token, reason }) + } CalculateQuoteError::Price { source: PriceEstimationError::ProtocolInternal(err), .. @@ -212,7 +323,28 @@ impl From for ValidationError { #[cfg_attr(any(test, feature = "test-util"), mockall::automock)] #[async_trait] pub trait LimitOrderCounting: Send + Sync { - async fn count(&self, owner: H160) -> Result; + async fn count(&self, owner: Address) -> Result; +} + +pub use configs::orderbook::order_validation::SameTokensPolicy; + +fn validate_same_sell_and_buy_token( + policy: &SameTokensPolicy, + order: &PreOrderData, + native_token: &Address, +) -> Result<(), PartialValidationError> { + let same_token = order.sell_token == order.buy_token + || (&order.sell_token == native_token && order.buy_token == BUY_ETH_ADDRESS); + + if !same_token { + return Ok(()); + } + + match (policy, order.kind) { + (SameTokensPolicy::Allow, _) => Ok(()), + (SameTokensPolicy::AllowSell, OrderKind::Sell) => Ok(()), + _ => Err(PartialValidationError::SameBuyAndSellToken), + } } #[derive(Clone)] @@ -222,53 +354,52 @@ pub struct OrderValidator { native_token: WETH9::Instance, banned_users: Arc, validity_configuration: OrderValidPeriodConfiguration, + /// Whether to skip EIP-1271 signature validation. eip1271_skip_creation_validation: bool, - bad_token_detector: Arc, + deny_listed_tokens: DenyListedTokens, hooks: HooksTrampoline::Instance, /// For Full-Validation: performed time of order placement quoter: Arc, balance_fetcher: Arc, signature_validator: Arc, + order_simulator: Option, limit_order_counter: Arc, max_limit_orders_per_user: u64, - pub code_fetcher: Arc, app_data_validator: Validator, max_gas_per_order: u64, + same_tokens_policy: SameTokensPolicy, } #[derive(Debug, Eq, PartialEq, Default)] pub struct PreOrderData { - pub owner: H160, - pub sell_token: H160, - pub buy_token: H160, - pub receiver: H160, + pub owner: Address, + pub sell_token: Address, + pub buy_token: Address, + pub receiver: Address, pub valid_to: u32, pub partially_fillable: bool, pub buy_token_balance: BuyTokenDestination, pub sell_token_balance: SellTokenSource, pub signing_scheme: SigningScheme, pub class: OrderClass, + pub kind: OrderKind, } -fn actual_receiver(owner: H160, order: &OrderData) -> H160 { +fn actual_receiver(owner: Address, order: &OrderData) -> Address { let receiver = order.receiver.unwrap_or_default(); - if receiver.is_zero() { - owner - } else { - receiver.into_legacy() - } + if receiver.is_zero() { owner } else { receiver } } impl PreOrderData { pub fn from_order_creation( - owner: H160, + owner: Address, order: &OrderData, signing_scheme: SigningScheme, ) -> Self { Self { owner, - sell_token: order.sell_token.into_legacy(), - buy_token: order.buy_token.into_legacy(), + sell_token: order.sell_token, + buy_token: order.buy_token, receiver: actual_receiver(owner, order), valid_to: order.valid_to, partially_fillable: order.partially_fillable, @@ -279,6 +410,7 @@ impl PreOrderData { true => OrderClass::Limit, false => OrderClass::Market, }, + kind: order.kind, } } } @@ -295,36 +427,38 @@ impl OrderValidator { banned_users: Arc, validity_configuration: OrderValidPeriodConfiguration, eip1271_skip_creation_validation: bool, - bad_token_detector: Arc, + deny_listed_tokens: DenyListedTokens, hooks: HooksTrampoline::Instance, quoter: Arc, balance_fetcher: Arc, signature_validator: Arc, + order_simulator: Option, limit_order_counter: Arc, max_limit_orders_per_user: u64, - code_fetcher: Arc, app_data_validator: Validator, max_gas_per_order: u64, + same_tokens_policy: SameTokensPolicy, ) -> Self { Self { native_token, banned_users, validity_configuration, eip1271_skip_creation_validation, - bad_token_detector, + deny_listed_tokens, hooks, quoter, balance_fetcher, signature_validator, + order_simulator, limit_order_counter, max_limit_orders_per_user, - code_fetcher, app_data_validator, max_gas_per_order, + same_tokens_policy, } } - async fn check_max_limit_orders(&self, owner: H160) -> Result<(), ValidationError> { + async fn check_max_limit_orders(&self, owner: Address) -> Result<(), ValidationError> { let num_limit_orders = self .limit_order_counter .count(owner) @@ -341,7 +475,7 @@ impl OrderValidator { /// /// This is done by returning the [`HooksTrampoline`] `execute` calldata /// with the (pre/post) hooks calldata as the parameter. - fn custom_interactions(&self, hooks: &Hooks) -> Interactions { + pub fn custom_interactions(&self, hooks: &Hooks) -> Interactions { let to_interactions = |hooks: &[Hook]| -> Vec { if hooks.is_empty() { vec![] @@ -375,81 +509,109 @@ impl OrderValidator { } } + async fn simulate_token_transfer( + &self, + order: &OrderCreation, + owner: Address, + app_data: &OrderAppData, + transfer_amount: U256, + ) -> Result<(), TransferSimulationError> { + self.balance_fetcher + .can_transfer( + &account_balances::Query { + token: order.data().sell_token, + owner, + source: order.data().sell_token_balance, + interactions: app_data.interactions.pre.clone(), + balance_override: app_data.inner.protocol.flashloan.as_ref().map(|loan| { + BalanceOverrideRequest { + token: loan.token, + holder: loan.receiver, + amount: loan.amount, + } + }), + }, + transfer_amount, + ) + .await + } + /// Verifies that tokens can actually be transferred from the user account /// to the settlement contract (takes pre-hooks into account). async fn ensure_token_is_transferable( &self, order: &OrderCreation, - owner: H160, + owner: Address, app_data: &OrderAppData, ) -> Result<(), ValidationError> { - let mut res = Ok(()); - - // Simulate transferring a small token balance into the settlement contract. - // As a spam protection we require that an account must have at least 1 atom - // of the sell_token. However, some tokens (e.g. rebasing tokens) actually run - // into numerical issues with such small amounts. But there are also tokens - // where a single atom is already quite expensive (tokenized stocks). - // To cover both cases we simulate multiple small transfers. As soon as one - // passes we consider the token transferable. If all transfers fail we return - // the last error. - for transfer_amount in [1, 10, 100].into_iter().map(U256::from) { - match self - .balance_fetcher - .can_transfer( - &account_balances::Query { - token: order.data().sell_token.into_legacy(), - owner, - source: order.data().sell_token_balance, - interactions: app_data.interactions.pre.clone(), - balance_override: app_data.inner.protocol.flashloan.as_ref().map(|loan| { - BalanceOverrideRequest { - token: loan.token.into_legacy(), - holder: loan.receiver.into_legacy(), - amount: loan.amount.into_legacy(), - } - }), - }, - transfer_amount, - ) - .await - { - Ok(_) => return Ok(()), - Err( + let simulate_transfers = async |transfer_amounts: &[U256]| { + let mut res = Ok(()); + let has_wrappers = !app_data.inner.protocol.wrappers.is_empty(); + + for transfer_amount in transfer_amounts { + let Err(err) = self + .simulate_token_transfer(order, owner, app_data, *transfer_amount) + .await + else { + return Ok(()); + }; + + res = match err { TransferSimulationError::InsufficientAllowance | TransferSimulationError::InsufficientBalance - | TransferSimulationError::TransferFailed, - ) if order.signature == Signature::PreSign => { - // Pre-sign orders do not require sufficient balance or allowance. - // The idea is that this allows smart contracts to place orders bundled with - // other transactions that either produce the required balance or set the - // allowance. This would, for example, allow a Gnosis Safe to bundle the - // pre-signature transaction with a WETH wrap and WETH approval to the vault - // relayer contract. - return Ok(()); - } - Err(err) => match err { + | TransferSimulationError::TransferFailed(_) + if order.signature == Signature::PreSign || has_wrappers => + { + // Pre-sign orders do not require sufficient balance or allowance. + // The idea is that this allows smart contracts to place orders bundled with + // other transactions that either produce the required balance or set the + // allowance. This would, for example, allow a Gnosis Safe to bundle the + // pre-signature transaction with a WETH wrap and WETH approval to the vault + // relayer contract. + // + // Similarly, orders with wrappers may produce the required balance or + // allowance as part of the wrapper execution. + return Ok(()); + } TransferSimulationError::InsufficientAllowance => { // This error will be triggered regardless of the amount return Err(ValidationError::InsufficientAllowance); } TransferSimulationError::InsufficientBalance => { - // Since the amount starts at 1 atom, if this error is triggered then it + // Since the amount either starts at 1 atom, or is set to the full sell + // token amount if this error is triggered then it // will be triggered for the other amounts too return Err(ValidationError::InsufficientBalance); } - TransferSimulationError::TransferFailed => { - res = Err(ValidationError::TransferSimulationFailed); + TransferSimulationError::TransferFailed(reason) => { + Err(ValidationError::TransferSimulationFailed(reason)) } TransferSimulationError::Other(err) => { tracing::warn!("TransferSimulation failed: {:?}", err); - res = Err(ValidationError::TransferSimulationFailed); + Err(ValidationError::TransferSimulationFailed(Vec::new())) } - }, + }; } - } + res + }; - res + if order.full_balance_check { + // If requested at order creation, simulate transferring full sell_amount + // into the settlement contract. + // This will ensure the account has enough allowance and balance for + // the transfer at the order creation time. + simulate_transfers([order.data().sell_amount].as_slice()).await + } else { + // Simulate transferring a small token balance into the settlement contract. + // As a spam protection we require that an account must have at least 1 atom + // of the sell_token. However, some tokens (e.g. rebasing tokens) actually run + // into numerical issues with such small amounts. But there are also tokens + // where a single atom is already quite expensive (tokenized stocks). + // To cover both cases we simulate multiple small transfers. As soon as one + // passes we consider the token transferable. If all transfers fail we return + // the last error. + simulate_transfers([1, 10, 100].map(U256::from).as_slice()).await + } } } @@ -459,7 +621,7 @@ impl OrderValidating for OrderValidator { async fn partial_validate(&self, order: PreOrderData) -> Result<(), PartialValidationError> { if !self .banned_users - .banned([order.receiver.into_alloy(), order.owner.into_alloy()]) + .banned([order.receiver, order.owner]) .await .is_empty() { @@ -485,22 +647,22 @@ impl OrderValidating for OrderValidator { } self.validity_configuration.validate_period(&order)?; + validate_same_sell_and_buy_token( + &self.same_tokens_policy, + &order, + self.native_token.address(), + )?; - if has_same_buy_and_sell_token(&order, self.native_token.address()) { - return Err(PartialValidationError::SameBuyAndSellToken); - } - if order.sell_token.into_alloy() == BUY_ETH_ADDRESS.into_alloy() { + if order.sell_token == BUY_ETH_ADDRESS { return Err(PartialValidationError::InvalidNativeSellToken); } - for &token in &[order.sell_token, order.buy_token] { - if let TokenQuality::Bad { reason } = self - .bad_token_detector - .detect(token.into_alloy()) - .await - .map_err(PartialValidationError::Other)? - { - return Err(PartialValidationError::UnsupportedToken { token, reason }); + for token in &[order.sell_token, order.buy_token] { + if self.deny_listed_tokens.contains(token) { + return Err(PartialValidationError::UnsupportedToken { + token: *token, + reason: "token is deny listed".to_string(), + }); } } @@ -543,8 +705,8 @@ impl OrderValidating for OrderValidator { OrderCreationAppData::Hash { hash } => { // Eventually we're not going to accept orders that set only a // hash and where we can't find full app data elsewhere. - let protocol = if let Some(full) = full_app_data_override { - validate(full)?.protocol + let validated = if let Some(full) = full_app_data_override { + validate(full)? } else { return Err(AppDataValidationError::Invalid(anyhow!( "Unknown pre-image for app data hash {:?}", @@ -552,10 +714,14 @@ impl OrderValidating for OrderValidator { ))); }; + // Keep the validated document, since the order creation simulator re-parses + // this document to rebuild the pre/post hooks, so dropping it + // makes the simulation skip the hooks (e.g. a permit approval) + // and revert spuriously. ValidatedAppData { hash: *hash, - document: String::new(), - protocol, + document: validated.document, + protocol: validated.protocol, } } OrderCreationAppData::Full { full } => validate(full)?, @@ -574,13 +740,13 @@ impl OrderValidating for OrderValidator { &self, order: OrderCreation, domain_separator: &DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, full_app_data_override: Option, ) -> Result<(Order, Option), ValidationError> { // Happens before signature verification because a miscalculated app data hash // by the API user would lead to being unable to validate the signature below. let app_data = self.validate_app_data(&order.app_data, &full_app_data_override)?; - let app_data_signer = app_data.inner.protocol.signer.map(IntoLegacy::into_legacy); + let app_data_signer = app_data.inner.protocol.signer; let owner = order.verify_owner(domain_separator, app_data_signer)?; tracing::debug!(?owner, "recovered owner from order and signature"); @@ -589,42 +755,12 @@ impl OrderValidating for OrderValidator { app_data: app_data.inner.hash, ..order.data() }; - let uid = data.uid(domain_separator, &owner); - - let verification_gas_limit = if let Signature::Eip1271(signature) = &order.signature { - if self.eip1271_skip_creation_validation { - tracing::debug!(?signature, "skipping EIP-1271 signature validation"); - // We don't care! Because we are skipping validation anyway - 0u64 - } else { - let hash = hashed_eip712_message(domain_separator, &data.hash_struct()); - self.signature_validator - .validate_signature_and_get_additional_gas(SignatureCheck { - signer: owner, - hash, - signature: signature.to_owned(), - interactions: app_data.interactions.pre.clone(), - balance_override: app_data.inner.protocol.flashloan.as_ref().map(|loan| { - BalanceOverrideRequest { - token: loan.token.into_legacy(), - holder: loan.receiver.into_legacy(), - amount: loan.amount.into_legacy(), - } - }), - }) - .await - .map_err(|err| match err { - SignatureValidationError::Invalid => { - ValidationError::InvalidEip1271Signature(H256(hash)) - } - SignatureValidationError::Other(err) => ValidationError::Other(err), - })? - } - } else { - // in any other case, just apply 0 - 0u64 - }; + let uid = data.uid(domain_separator, owner); + // Cheap in-memory rejection checks run before the eth_call-driven + // verification step below so banned users, forbidden tokens, and + // zero-amount orders fail fast without consuming a simulation-node + // round-trip. if data.buy_amount.is_zero() || data.sell_amount.is_zero() { return Err(ValidationError::ZeroAmount); } @@ -635,21 +771,97 @@ impl OrderValidating for OrderValidator { .await .map_err(ValidationError::Partial)?; + let preview_order = Order { + metadata: OrderMetadata { + owner, + uid, + ..Default::default() + }, + data, + signature: order.signature.clone(), + interactions: app_data.interactions.clone(), + }; + let full_app_data = app_data.inner.document.clone(); + let hash = hashed_eip712_message(domain_separator, &data.hash_struct()); + + let eip1271_check = if let Signature::Eip1271(sig) = &order.signature + && !self.eip1271_skip_creation_validation + { + Some(SignatureCheck::new( + owner, + hash.0, + sig.to_owned(), + app_data.interactions.pre.clone(), + app_data + .inner + .protocol + .flashloan + .as_ref() + .map(|loan| BalanceOverrideRequest { + token: loan.token, + holder: loan.receiver, + amount: loan.amount, + }), + )) + } else { + None + }; + + let simulation_fut = OptionFuture::from( + self.order_simulator + .as_ref() + .map(|c| c.simulate_with_timeout(&preview_order, &full_app_data)), + ); + let transfer_fut = self.ensure_token_is_transferable(&order, owner, &app_data); + + let verification_gas_limit = match eip1271_check { + Some(check) => { + let signature_fut = self + .signature_validator + .validate_signature_and_get_additional_gas(check); + let (signature_res, simulation_opt, transfer_res) = + tokio::join!(signature_fut, simulation_fut, transfer_fut); + + if let Some(simulation) = &simulation_opt { + log_simulation_outcome( + &signature_res, + simulation, + &preview_order, + &full_app_data, + ); + } + + let gas_limit = signature_res.map_err(|err| match err { + SignatureValidationError::Invalid => { + ValidationError::InvalidEip1271Signature(hash) + } + SignatureValidationError::Other(err) => ValidationError::Other(err), + })?; + transfer_res?; + gas_limit + } + None => { + let (simulation_opt, transfer_res) = tokio::join!(simulation_fut, transfer_fut); + if let Some(simulation) = simulation_opt { + log_simulation_outcome(&Ok(0), &simulation, &preview_order, &full_app_data); + } + transfer_res?; + 0 + } + }; + let verification = Verification { from: owner, receiver: order.receiver.unwrap_or(owner), - sell_token_source: order.sell_token_balance, - buy_token_destination: order.buy_token_balance, - pre_interactions: trade_finding::map_interactions(&app_data.interactions.pre), - post_interactions: trade_finding::map_interactions(&app_data.interactions.post), + app_data: Arc::new(app_data.inner.document.clone()), }; let quote_parameters = QuoteSearchParameters { - sell_token: data.sell_token.into_legacy(), - buy_token: data.buy_token.into_legacy(), - sell_amount: data.sell_amount.into_legacy(), - buy_amount: data.buy_amount.into_legacy(), - fee_amount: data.fee_amount.into_legacy(), + sell_token: data.sell_token, + buy_token: data.buy_token, + sell_amount: data.sell_amount, + buy_amount: data.buy_amount, + fee_amount: data.fee_amount, kind: data.kind, signing_scheme: convert_signing_scheme_into_quote_signing_scheme( order.signature.scheme(), @@ -661,9 +873,6 @@ impl OrderValidating for OrderValidator { verification, }; - self.ensure_token_is_transferable(&order, owner, &app_data) - .await?; - // Check if we need to re-classify the market order if it is outside the market // price. We consider out-of-price orders as liquidity orders. See // . @@ -674,7 +883,7 @@ impl OrderValidating for OrderValidator { &*self.quoter, "e_parameters, order.quote_id, - Some(data.fee_amount.into_legacy()), + Some(data.fee_amount), ) .await?; tracing::debug!( @@ -685,9 +894,9 @@ impl OrderValidating for OrderValidator { ); if is_order_outside_market_price( &Amounts { - sell: data.sell_amount.into_legacy(), - buy: data.buy_amount.into_legacy(), - fee: data.fee_amount.into_legacy(), + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, }, &Amounts { sell: quote.sell_amount, @@ -715,9 +924,9 @@ impl OrderValidating for OrderValidator { // If the order is not "In-Market", check for the limit orders if is_order_outside_market_price( &Amounts { - sell: data.sell_amount.into_legacy(), - buy: data.buy_amount.into_legacy(), - fee: data.fee_amount.into_legacy(), + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, }, &Amounts { sell: quote.sell_amount, @@ -726,6 +935,7 @@ impl OrderValidating for OrderValidator { }, data.kind, ) { + tracing::debug!(%uid, ?owner, ?class, "order being flagged as outside market price"); self.check_max_limit_orders(owner).await?; } (class, Some(quote)) @@ -746,9 +956,9 @@ impl OrderValidating for OrderValidator { // If the order is not "In-Market", check for the limit orders if is_order_outside_market_price( &Amounts { - sell: data.sell_amount.into_legacy(), - buy: data.buy_amount.into_legacy(), - fee: data.fee_amount.into_legacy(), + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, }, &Amounts { sell: quote.sell_amount, @@ -757,6 +967,7 @@ impl OrderValidating for OrderValidator { }, data.kind, ) { + tracing::debug!(%uid, ?owner, ?class, "order being flagged as outside market price"); self.check_max_limit_orders(owner).await?; } (OrderClass::Limit, None) @@ -773,10 +984,10 @@ impl OrderValidating for OrderValidator { let order = Order { metadata: OrderMetadata { - owner: owner.into_alloy(), + owner, creation_date: chrono::offset::Utc::now(), uid, - settlement_contract: settlement_contract.into_alloy(), + settlement_contract, class, full_app_data: match order.app_data { OrderCreationAppData::Both { full, .. } @@ -853,15 +1064,6 @@ pub enum OrderValidToError { Excessive, } -/// Returns true if the orders have same buy and sell tokens. -/// -/// This also checks for orders selling wrapped native token for native token. -fn has_same_buy_and_sell_token(order: &PreOrderData, native_token: &Address) -> bool { - order.sell_token == order.buy_token - || (order.sell_token == native_token.into_legacy() - && order.buy_token.into_alloy() == BUY_ETH_ADDRESS.into_alloy()) -} - /// Retrieves the quote for an order that is being created and verify that its /// fee is sufficient. /// @@ -933,7 +1135,11 @@ async fn get_or_create_quote( .await .map_err(ValidationError::Other)?; - tracing::debug!(quote_id =? quote.id, "computed fresh quote for order creation"); + tracing::debug!( + original_quote_id = ?quote_id, + quote_id =? quote.id, + "computed fresh quote for order creation" + ); quote } }; @@ -944,17 +1150,17 @@ async fn get_or_create_quote( /// Amounts used for market price checker. #[derive(Debug)] pub struct Amounts { - pub sell: U256, - pub buy: U256, - pub fee: U256, + pub sell: alloy::primitives::U256, + pub buy: alloy::primitives::U256, + pub fee: alloy::primitives::U256, } impl From<&model::order::Order> for Amounts { fn from(order: &model::order::Order) -> Self { Self { - sell: order.data.sell_amount.into_legacy(), - buy: order.data.buy_amount.into_legacy(), - fee: order.data.fee_amount.into_legacy(), + sell: order.data.sell_amount, + buy: order.data.buy_amount, + fee: order.data.fee_amount, } } } @@ -967,25 +1173,22 @@ pub fn is_order_outside_market_price( kind: model::order::OrderKind, ) -> bool { let check = move || match kind { - OrderKind::Buy => { - Some(order.sell.full_mul(quote.buy) < (quote.sell + quote.fee).full_mul(order.buy)) - } + OrderKind::Buy => Some( + order.sell.widening_mul::<256, 4, 512, 8>(quote.buy) + < (quote.sell + quote.fee).widening_mul::<256, 4, 512, 8>(order.buy), + ), OrderKind::Sell => { let quote_buy = quote .buy .checked_sub(quote.fee.checked_mul(quote.buy)?.checked_div(quote.sell)?)?; - Some(order.sell.full_mul(quote_buy) < quote.sell.full_mul(order.buy)) + Some( + order.sell.widening_mul::<256, 4, 512, 8>(quote_buy) + < quote.sell.widening_mul::<256, 4, 512, 8>(order.buy), + ) } }; - check().unwrap_or_else(|| { - tracing::warn!( - ?order, - ?quote, - "failed to check if order is outside market price" - ); - true - }) + check().unwrap_or(true) } pub struct InvalidSigningScheme; @@ -1015,17 +1218,15 @@ mod tests { use { super::*, crate::{ - account_balances::MockBalanceFetching, - bad_token::{MockBadTokenDetecting, TokenQuality}, - code_fetching::MockCodeFetching, + order_creation_simulation::MockOrderSimulating, order_quoting::{FindQuoteError, MockOrderQuoting}, - signature_validator::MockSignatureValidating, }, + account_balances::MockBalanceFetching, alloy::{ - primitives::{Address, U160, address}, + primitives::{Address, U160, U256, address, b256}, providers::{Provider, ProviderBuilder, mock::Asserter}, + signers::local::PrivateKeySigner, }, - ethcontract::web3::signing::SecretKeyRef, futures::FutureExt, maplit::hashset, mockall::predicate::{always, eq}, @@ -1033,54 +1234,82 @@ mod tests { quote::default_verification_gas_limit, signature::{EcdsaSignature, EcdsaSigningScheme}, }, - number::nonzero::U256 as NonZeroU256, + number::nonzero::NonZeroU256, serde_json::json, - std::str::FromStr, + signature_validator::MockSignatureValidating, }; + const DEFAULT_ORDER_SIM_TIMEOUT: Duration = Duration::from_secs(2); + #[test] - fn detects_orders_with_same_buy_and_sell_token() { - let native_token = [0xef; 20].into(); - assert!(has_same_buy_and_sell_token( - &PreOrderData { - sell_token: H160([0x01; 20]), - buy_token: H160([0x01; 20]), - ..Default::default() - }, - &native_token, - )); - assert!(has_same_buy_and_sell_token( - &PreOrderData { - sell_token: native_token.into_legacy(), - buy_token: BUY_ETH_ADDRESS, - ..Default::default() - }, - &native_token, - )); + fn hash_app_data_keeps_full_document_for_simulation() { + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); + let validity_configuration = OrderValidPeriodConfiguration { + min: Duration::from_secs(1), + max_market: Duration::from_secs(100), + max_limit: Duration::from_secs(200), + }; + let mut limit_order_counter = MockLimitOrderCounting::new(); + limit_order_counter.expect_count().returning(|_| Ok(0u64)); - assert!(!has_same_buy_and_sell_token( - &PreOrderData { - sell_token: H160([0x01; 20]), - buy_token: H160([0x02; 20]), - ..Default::default() - }, - &native_token, - )); - // Sell token set to 0xeee...eee has no special meaning, so it isn't - // considered buying and selling the same token. - assert!(!has_same_buy_and_sell_token( - &PreOrderData { - sell_token: BUY_ETH_ADDRESS, - buy_token: native_token.into_legacy(), - ..Default::default() - }, - &native_token, - )); + let validator = OrderValidator::new( + native_token, + Arc::new(order_validation::banned::Users::from_set(Default::default())), + validity_configuration, + false, + DenyListedTokens::default(), + HooksTrampoline::Instance::new( + Address::repeat_byte(0xcf), + ProviderBuilder::new() + .connect_mocked_client(Asserter::new()) + .erased(), + ), + Arc::new(MockOrderQuoting::new()), + Arc::new(MockBalanceFetching::new()), + Arc::new(MockSignatureValidating::new()), + None, + Arc::new(limit_order_counter), + 0, + Default::default(), + u64::MAX, + SameTokensPolicy::Disallow, + ); + + // App data with a pre-hook (a gasless approval, the shape that surfaced + // this bug), submitted as a bare hash plus a full-app-data override. + let full = r#"{"version":"1.1.0","appCode":"test","metadata":{"hooks":{"pre":[{"target":"0x0000000000000000000000000000000000000001","callData":"0x12345678","gasLimit":"21000"}]}}}"#; + + let app_data = validator + .validate_app_data( + &OrderCreationAppData::Hash { + hash: Default::default(), + }, + &Some(full.to_string()), + ) + .unwrap(); + + // The `Hash` branch used to hardcode the document to `"{}"`, which made + // the order creation simulator re-parse empty app data and drop the + // hooks. The document must survive. + assert_ne!(app_data.inner.document, "{}"); + + // Re-parsing the kept document, as the simulator does, must still yield + // the pre-hook. + let reparsed = validator + .validate_app_data( + &OrderCreationAppData::Full { + full: app_data.inner.document.clone(), + }, + &None, + ) + .unwrap(); + assert!(!reparsed.interactions.pre.is_empty()); } #[tokio::test] async fn pre_validate_err() { - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); + let native_token_address = *native_token.address(); let validity_configuration = OrderValidPeriodConfiguration { min: Duration::from_secs(1), max_market: Duration::from_secs(100), @@ -1096,9 +1325,9 @@ mod tests { Arc::new(order_validation::banned::Users::from_set(banned_users)), validity_configuration, false, - Arc::new(MockBadTokenDetecting::new()), + DenyListedTokens::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1106,11 +1335,12 @@ mod tests { Arc::new(MockOrderQuoting::new()), Arc::new(MockBalanceFetching::new()), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let result = validator .partial_validate(PreOrderData { @@ -1125,7 +1355,7 @@ mod tests { assert!(matches!( validator .partial_validate(PreOrderData { - owner: H160::from_low_u64_be(1), + owner: Address::with_last_byte(1), ..Default::default() }) .await, @@ -1134,7 +1364,7 @@ mod tests { assert!(matches!( validator .partial_validate(PreOrderData { - receiver: H160::from_low_u64_be(1), + receiver: Address::with_last_byte(1), ..Default::default() }) .await, @@ -1204,8 +1434,19 @@ mod tests { validator .partial_validate(PreOrderData { valid_to: legit_valid_to, - buy_token: H160::from_low_u64_be(2), - sell_token: H160::from_low_u64_be(2), + buy_token: Address::with_last_byte(2), + sell_token: Address::with_last_byte(2), + ..Default::default() + }) + .await, + Err(PartialValidationError::SameBuyAndSellToken) + )); + assert!(matches!( + validator + .partial_validate(PreOrderData { + valid_to: legit_valid_to, + buy_token: BUY_ETH_ADDRESS, + sell_token: native_token_address, ..Default::default() }) .await, @@ -1225,33 +1466,24 @@ mod tests { #[tokio::test] async fn pre_validate_ok() { + let native_token = + WETH9::Instance::new(Address::repeat_byte(0xef), ethrpc::mock::web3().provider); let validity_configuration = OrderValidPeriodConfiguration { min: Duration::from_secs(1), max_market: Duration::from_secs(100), max_limit: Duration::from_secs(200), }; - let mut bad_token_detector = MockBadTokenDetecting::new(); - bad_token_detector - .expect_detect() - .with(eq(Address::with_last_byte(1))) - .returning(|_| Ok(TokenQuality::Good)); - bad_token_detector - .expect_detect() - .with(eq(Address::with_last_byte(2))) - .returning(|_| Ok(TokenQuality::Good)); - let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), validity_configuration, false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1259,18 +1491,19 @@ mod tests { Arc::new(MockOrderQuoting::new()), Arc::new(MockBalanceFetching::new()), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let order = || PreOrderData { valid_to: time::now_in_epoch_seconds() + validity_configuration.min.as_secs() as u32 + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), ..Default::default() }; @@ -1289,7 +1522,7 @@ mod tests { validator .partial_validate(PreOrderData { class: OrderClass::Limit, - owner: H160::from_low_u64_be(0x42), + owner: Address::with_last_byte(0x42), valid_to: time::now_in_epoch_seconds() + validity_configuration.max_market.as_secs() as u32 + 2, @@ -1303,7 +1536,7 @@ mod tests { .partial_validate(PreOrderData { partially_fillable: true, class: OrderClass::Liquidity, - owner: H160::from_low_u64_be(0x42), + owner: Address::with_last_byte(0x42), valid_to: u32::MAX, ..order() }) @@ -1312,17 +1545,175 @@ mod tests { ); } + #[tokio::test] + async fn pre_validate_same_tokens_allow_sell() { + let native_token = + WETH9::Instance::new(Address::repeat_byte(0xef), ethrpc::mock::web3().provider); + let validity_configuration = OrderValidPeriodConfiguration { + min: Duration::from_secs(1), + max_market: Duration::from_secs(100), + max_limit: Duration::from_secs(200), + }; + + let mut limit_order_counter = MockLimitOrderCounting::new(); + limit_order_counter.expect_count().returning(|_| Ok(0u64)); + let validator = OrderValidator::new( + native_token.clone(), + Arc::new(order_validation::banned::Users::none()), + validity_configuration, + false, + Default::default(), + HooksTrampoline::Instance::new( + Address::repeat_byte(0xcf), + ProviderBuilder::new() + .connect_mocked_client(Asserter::new()) + .erased(), + ), + Arc::new(MockOrderQuoting::new()), + Arc::new(MockBalanceFetching::new()), + Arc::new(MockSignatureValidating::new()), + None, + Arc::new(limit_order_counter), + 0, + Default::default(), + u64::MAX, + SameTokensPolicy::AllowSell, + ); + + let order = || PreOrderData { + buy_token: Address::with_last_byte(2), + sell_token: Address::with_last_byte(2), + valid_to: time::now_in_epoch_seconds() + + validity_configuration.min.as_secs() as u32 + + 2, + ..Default::default() + }; + + assert!(matches!( + dbg!( + validator + .partial_validate(PreOrderData { + kind: OrderKind::Buy, + ..order() + }) + .await + ), + Err(PartialValidationError::SameBuyAndSellToken) + )); + + assert!( + dbg!( + validator + .partial_validate(PreOrderData { + kind: OrderKind::Sell, + ..order() + }) + .await + ) + .is_ok() + ); + + let native_order = || PreOrderData { + buy_token: BUY_ETH_ADDRESS, + sell_token: *native_token.address(), + valid_to: time::now_in_epoch_seconds() + + validity_configuration.min.as_secs() as u32 + + 2, + ..Default::default() + }; + + assert!(matches!( + validator + .partial_validate(PreOrderData { + kind: OrderKind::Buy, + ..native_order() + }) + .await, + Err(PartialValidationError::SameBuyAndSellToken) + )); + + assert!( + validator + .partial_validate(PreOrderData { + kind: OrderKind::Sell, + ..native_order() + }) + .await + .is_ok() + ); + } + + #[tokio::test] + async fn pre_validate_same_tokens_allow() { + let native_token = + WETH9::Instance::new(Address::repeat_byte(0xef), ethrpc::mock::web3().provider); + let validity_configuration = OrderValidPeriodConfiguration { + min: Duration::from_secs(1), + max_market: Duration::from_secs(100), + max_limit: Duration::from_secs(200), + }; + + let mut limit_order_counter = MockLimitOrderCounting::new(); + limit_order_counter.expect_count().returning(|_| Ok(0u64)); + let validator = OrderValidator::new( + native_token.clone(), + Arc::new(order_validation::banned::Users::none()), + validity_configuration, + false, + Default::default(), + HooksTrampoline::Instance::new( + Address::repeat_byte(0xcf), + ProviderBuilder::new() + .connect_mocked_client(Asserter::new()) + .erased(), + ), + Arc::new(MockOrderQuoting::new()), + Arc::new(MockBalanceFetching::new()), + Arc::new(MockSignatureValidating::new()), + None, + Arc::new(limit_order_counter), + 0, + Default::default(), + u64::MAX, + SameTokensPolicy::Allow, + ); + + let valid_to = + time::now_in_epoch_seconds() + validity_configuration.min.as_secs() as u32 + 2; + + // `Allow` permits same-token orders of either side. The second pair is the + // native-equivalent case: `validate_same_sell_and_buy_token` treats selling + // WETH for `BUY_ETH_ADDRESS` (native ETH) as a sell==buy order. The rejection + // side is covered by `pre_validate_err` (Disallow) and + // `pre_validate_same_tokens_allow_sell` (AllowSell). + for (sell_token, buy_token) in [ + (Address::with_last_byte(2), Address::with_last_byte(2)), + (*native_token.address(), BUY_ETH_ADDRESS), + ] { + for kind in [OrderKind::Buy, OrderKind::Sell] { + assert!( + validator + .partial_validate(PreOrderData { + kind, + sell_token, + buy_token, + valid_to, + ..Default::default() + }) + .await + .is_ok() + ); + } + } + } + #[tokio::test] async fn post_validate_ok() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); @@ -1344,7 +1735,7 @@ mod tests { let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), @@ -1354,25 +1745,26 @@ mod tests { max_limit: Duration::from_secs(200), }, false, - Arc::new(bad_token_detector), + Default::default(), hooks.clone(), Arc::new(order_quoter), Arc::new(balance_fetcher), signature_validating, + None, Arc::new(limit_order_counter), max_limit_orders_per_user, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let creation = OrderCreation { valid_to: time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(1), - sell_amount: U256::from(1), - fee_amount: U256::from(0), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), + sell_amount: alloy::primitives::U256::from(1), + fee_amount: alloy::primitives::U256::from(0), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1391,7 +1783,7 @@ mod tests { let domain_separator = DomainSeparator::default(); let creation = OrderCreation { - from: Some(H160([1; 20])), + from: Some(Address::repeat_byte(1)), signature: Signature::Eip1271(vec![1, 2, 3]), app_data: OrderCreationAppData::Full { full: json!({ @@ -1438,13 +1830,13 @@ mod tests { let mut signature_validator = MockSignatureValidating::new(); signature_validator .expect_validate_signature_and_get_additional_gas() - .with(eq(SignatureCheck { - signer: creation.from.unwrap(), - hash: order_hash, - signature: vec![1, 2, 3], - interactions: pre_interactions.clone(), - balance_override: None, - })) + .with(eq(SignatureCheck::new( + creation.from.unwrap(), + order_hash.0, + vec![1, 2, 3], + pre_interactions.clone(), + None, + ))) .returning(|_| Ok(0u64)); let validator = OrderValidator { @@ -1467,13 +1859,13 @@ mod tests { let mut signature_validator = MockSignatureValidating::new(); signature_validator .expect_validate_signature_and_get_additional_gas() - .with(eq(SignatureCheck { - signer: creation.from.unwrap(), - hash: order_hash, - signature: vec![1, 2, 3], - interactions: pre_interactions.clone(), - balance_override: None, - })) + .with(eq(SignatureCheck::new( + creation.from.unwrap(), + order_hash.0, + vec![1, 2, 3], + pre_interactions.clone(), + None, + ))) .returning(|_| Err(SignatureValidationError::Invalid)); let validator = OrderValidator { @@ -1495,7 +1887,7 @@ mod tests { ); let creation_ = OrderCreation { - fee_amount: U256::zero(), + fee_amount: alloy::primitives::U256::ZERO, ..creation.clone() }; let (order, _) = validator @@ -1506,7 +1898,7 @@ mod tests { assert!(order.metadata.class.is_limit()); let creation_ = OrderCreation { - fee_amount: U256::zero(), + fee_amount: alloy::primitives::U256::ZERO, partially_fillable: true, app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1524,20 +1916,16 @@ mod tests { #[tokio::test] async fn post_validate_too_many_limit_orders() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter.expect_find_quote().returning(|_, _| { Ok(Quote { id: None, data: Default::default(), - sell_amount: U256::from(1), - buy_amount: U256::from(1), + sell_amount: alloy::primitives::U256::from(1), + buy_amount: alloy::primitives::U256::from(1), fee_amount: Default::default(), }) }); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); @@ -1555,7 +1943,7 @@ mod tests { .expect_count() .returning(|_| Ok(MAX_LIMIT_ORDERS_PER_USER)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), @@ -1565,9 +1953,9 @@ mod tests { max_limit: Duration::from_secs(200), }, false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1575,19 +1963,20 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), signature_validating, + None, Arc::new(limit_order_counter), MAX_LIMIT_ORDERS_PER_USER, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let creation = OrderCreation { valid_to: model::time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(10), - sell_amount: U256::from(1), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(10), + sell_amount: alloy::primitives::U256::from(1), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1611,14 +2000,10 @@ mod tests { #[tokio::test] async fn post_limit_does_not_apply_to_in_market_orders() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); @@ -1635,16 +2020,15 @@ mod tests { limit_order_counter .expect_count() .returning(|_| Ok(MAX_LIMIT_ORDERS_PER_USER)); - - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1652,19 +2036,20 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), signature_validating, + None, Arc::new(limit_order_counter), MAX_LIMIT_ORDERS_PER_USER, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let creation = OrderCreation { valid_to: model::time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(1), - sell_amount: U256::from(1), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), + sell_amount: alloy::primitives::U256::from(1), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1687,28 +2072,24 @@ mod tests { #[tokio::test] async fn post_validate_err_zero_amount() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1716,19 +2097,20 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let order = OrderCreation { valid_to: time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(0), - sell_amount: U256::from(0), - fee_amount: U256::from(1), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(0), + sell_amount: alloy::primitives::U256::from(0), + fee_amount: alloy::primitives::U256::from(1), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1744,28 +2126,24 @@ mod tests { #[tokio::test] async fn post_validate_err_wrong_owner() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1773,19 +2151,21 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); + let order = OrderCreation { valid_to: time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(1), - sell_amount: U256::from(1), - fee_amount: U256::from(1), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), + sell_amount: alloy::primitives::U256::from(1), + fee_amount: alloy::primitives::U256::from(1), from: Some(Default::default()), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { @@ -1802,30 +2182,26 @@ mod tests { #[tokio::test] async fn post_validate_err_unsupported_token() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); + let deny_listed_tokens = DenyListedTokens::new(vec![Address::with_last_byte(1)]); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector.expect_detect().returning(|_| { - Ok(TokenQuality::Bad { - reason: Default::default(), - }) - }); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + deny_listed_tokens, HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1833,19 +2209,21 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); + let order = OrderCreation { valid_to: time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(1), - sell_amount: U256::from(1), - fee_amount: U256::from(1), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), + sell_amount: alloy::primitives::U256::from(1), + fee_amount: alloy::primitives::U256::from(1), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1867,28 +2245,24 @@ mod tests { #[tokio::test] async fn post_validate_err_insufficient_balance() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Err(TransferSimulationError::InsufficientBalance)); let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1896,19 +2270,21 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); + let order = OrderCreation { valid_to: time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(1), - sell_amount: U256::from(1), - fee_amount: U256::from(1), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), + sell_amount: alloy::primitives::U256::from(1), + fee_amount: alloy::primitives::U256::from(1), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1925,15 +2301,11 @@ mod tests { #[tokio::test] async fn post_validate_err_invalid_eip1271_signature() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); let mut signature_validator = MockSignatureValidating::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); @@ -1942,15 +2314,15 @@ mod tests { .returning(|_| Err(SignatureValidationError::Invalid)); let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -1958,21 +2330,22 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(signature_validator), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let creation = OrderCreation { valid_to: time::now_in_epoch_seconds() + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(1), - sell_amount: U256::from(1), - fee_amount: U256::from(1), - from: Some(H160([1; 20])), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), + sell_amount: alloy::primitives::U256::from(1), + fee_amount: alloy::primitives::U256::from(1), + from: Some(Address::repeat_byte(1)), signature: Signature::Eip1271(vec![1, 2, 3]), app_data: OrderCreationAppData::Full { full: "{}".to_string(), @@ -1998,26 +2371,23 @@ mod tests { is_expected_error: impl Fn(ValidationError) -> bool, ) { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(move |_, _| Err(create_error())); let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = + WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( Address::from([0xcf; 20]), ProviderBuilder::new() @@ -2027,19 +2397,20 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let order = OrderCreation { valid_to: u32::MAX, - sell_token: H160::from_low_u64_be(1), - sell_amount: 1.into(), - buy_token: H160::from_low_u64_be(2), - buy_amount: 1.into(), + sell_token: Address::with_last_byte(1), + sell_amount: alloy::primitives::U256::from(1), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), app_data: OrderCreationAppData::Full { full: "{}".to_string(), }, @@ -2052,7 +2423,10 @@ mod tests { order.clone().sign( signing_scheme, &Default::default(), - SecretKeyRef::new(&secp256k1::SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap()), + &PrivateKeySigner::from_bytes(&b256!( + "0000000000000000000000000000000000000000000000000000000000000001" + )) + .unwrap(), ), &Default::default(), Default::default(), @@ -2089,28 +2463,24 @@ mod tests { #[test] fn allows_insufficient_balance_for_orders_with_sufficient_flashloan_hint() { let mut order_quoter = MockOrderQuoting::new(); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); order_quoter .expect_find_quote() .returning(|_, _| Ok(Default::default())); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Err(TransferSimulationError::InsufficientBalance)); let mut limit_order_counter = MockLimitOrderCounting::new(); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), OrderValidPeriodConfiguration::any(), false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -2118,20 +2488,21 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(MockSignatureValidating::new()), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); // Test with flashloan hint that covers the sell amount let order_with_sufficient_flashloan = OrderCreation { valid_to: u32::MAX, - sell_token: H160::from_low_u64_be(1), - sell_amount: 100.into(), - buy_token: H160::from_low_u64_be(2), - buy_amount: 1.into(), + sell_token: Address::with_last_byte(1), + sell_amount: alloy::primitives::U256::from(100), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), app_data: OrderCreationAppData::Full { full: r#"{ "metadata": { @@ -2166,10 +2537,10 @@ mod tests { // Test with flashloan hint that doesn't cover the sell amount let order_with_insufficient_flashloan = OrderCreation { valid_to: u32::MAX, - sell_token: H160::from_low_u64_be(1), - sell_amount: 100.into(), - buy_token: H160::from_low_u64_be(2), - buy_amount: 1.into(), + sell_token: Address::with_last_byte(1), + sell_amount: alloy::primitives::U256::from(100), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), app_data: OrderCreationAppData::Full { full: r#"{ "metadata": { @@ -2203,10 +2574,10 @@ mod tests { // Test with flashloan hint for different token let order_with_wrong_token_flashloan = OrderCreation { valid_to: u32::MAX, - sell_token: H160::from_low_u64_be(1), - sell_amount: 100.into(), - buy_token: H160::from_low_u64_be(2), - buy_amount: 1.into(), + sell_token: Address::with_last_byte(1), + sell_amount: alloy::primitives::U256::from(100), + buy_token: Address::with_last_byte(2), + buy_amount: alloy::primitives::U256::from(1), app_data: OrderCreationAppData::Full { full: r#"{ "metadata": { @@ -2242,11 +2613,11 @@ mod tests { async fn get_quote_find_by_id() { let mut order_quoter = MockOrderQuoting::new(); let quote_search_parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 3.into(), - buy_amount: 4.into(), - fee_amount: 0.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(3), + buy_amount: alloy::primitives::U256::from(4), + fee_amount: alloy::primitives::U256::from(0), kind: OrderKind::Buy, signing_scheme: QuoteSigningScheme::Eip1271 { onchain_order: true, @@ -2254,15 +2625,15 @@ mod tests { }, additional_gas: 0, verification: Verification { - from: H160([0xf0; 20]), + from: Address::from([0xf0; 20]), ..Default::default() }, }; let quote_data = Quote { - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() }; - let fee_amount = 0.into(); + let fee_amount = U256::ZERO; let quote_id = Some(42); order_quoter .expect_find_quote() @@ -2281,7 +2652,7 @@ mod tests { assert_eq!( quote, Quote { - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() } ); @@ -2290,7 +2661,7 @@ mod tests { #[tokio::test] async fn get_quote_calculates_fresh_quote_when_not_found() { let verification = Verification { - from: H160([0xf0; 20]), + from: Address::from([0xf0; 20]), ..Default::default() }; @@ -2300,18 +2671,18 @@ mod tests { .with(eq(None), always()) .returning(|_, _| Err(FindQuoteError::NotFound(None))); let quote_search_parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 3.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(3), kind: OrderKind::Sell, verification: verification.clone(), ..Default::default() }; let quote_data = Quote { - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() }; - let fee_amount = 0.into(); + let fee_amount = U256::ZERO; order_quoter .expect_calculate_quote() .with(eq(QuoteParameters { @@ -2319,7 +2690,7 @@ mod tests { buy_token: quote_search_parameters.buy_token, side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { - value: NonZeroU256::try_from(quote_search_parameters.sell_amount).unwrap(), + value: NonZeroU256::new(quote_search_parameters.sell_amount).unwrap(), }, }, verification, @@ -2354,7 +2725,7 @@ mod tests { quote, Quote { id: Some(42), - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() } ); @@ -2363,18 +2734,18 @@ mod tests { #[test] fn detects_market_orders_buy() { let quote = Quote { - sell_amount: 90.into(), - buy_amount: 100.into(), - fee_amount: 10.into(), + sell_amount: alloy::primitives::U256::from(90), + buy_amount: alloy::primitives::U256::from(100), + fee_amount: alloy::primitives::U256::from(10), ..Default::default() }; // at market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 100.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(100), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2386,9 +2757,9 @@ mod tests { // willing to buy less than market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 90.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(90), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2400,9 +2771,9 @@ mod tests { // wanting to buy more than market price assert!(is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 1000.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(1000), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2417,18 +2788,18 @@ mod tests { fn detects_market_orders_sell() { // 1 to 1 conversion let quote = Quote { - sell_amount: 100.into(), - buy_amount: 100.into(), - fee_amount: 10.into(), + sell_amount: alloy::primitives::U256::from(100), + buy_amount: alloy::primitives::U256::from(100), + fee_amount: alloy::primitives::U256::from(10), ..Default::default() }; // at market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 90.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(90), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2440,9 +2811,9 @@ mod tests { // willing to buy less than market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 80.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(80), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2454,9 +2825,9 @@ mod tests { // wanting to buy more than market price assert!(is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 1000.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(1000), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2471,11 +2842,11 @@ mod tests { async fn validate_quote_find_by_id() { let mut order_quoter = MockOrderQuoting::new(); let quote_search_parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 3.into(), - buy_amount: 4.into(), - fee_amount: 0.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(3), + buy_amount: alloy::primitives::U256::from(4), + fee_amount: alloy::primitives::U256::from(0), kind: OrderKind::Buy, signing_scheme: QuoteSigningScheme::Eip1271 { onchain_order: false, @@ -2483,9 +2854,9 @@ mod tests { }, additional_gas: 0, verification: Verification { - from: H160([0xf0; 20]), - receiver: H160([0xf0; 20]), - ..Default::default() + from: Address::from([0xf0; 20]), + receiver: Address::from([0xf0; 20]), + app_data: Arc::new("{}".to_string()), }, }; let quote_id = Some(42); @@ -2498,11 +2869,7 @@ mod tests { .with(eq(quote_id), eq(quote_search_parameters.clone())) .returning(move |_, _| Ok(quote_data.clone())); - let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); - bad_token_detector - .expect_detect() - .returning(|_| Ok(TokenQuality::Good)); balance_fetcher .expect_can_transfer() .returning(|_, _| Ok(())); @@ -2512,8 +2879,8 @@ mod tests { .expect_validate_signature_and_get_additional_gas() .returning(|_| Ok(default_verification_gas_limit())); let mut limit_order_counter = MockLimitOrderCounting::new(); + let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider); limit_order_counter.expect_count().returning(|_| Ok(0u64)); - let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().alloy); let validator = OrderValidator::new( native_token, Arc::new(order_validation::banned::Users::none()), @@ -2523,9 +2890,9 @@ mod tests { max_limit: Duration::from_secs(200), }, false, - Arc::new(bad_token_detector), + Default::default(), HooksTrampoline::Instance::new( - Address::from([0xcf; 20]), + Address::repeat_byte(0xcf), ProviderBuilder::new() .connect_mocked_client(Asserter::new()) .erased(), @@ -2533,26 +2900,27 @@ mod tests { Arc::new(order_quoter), Arc::new(balance_fetcher), Arc::new(signature_validating), + None, Arc::new(limit_order_counter), 0, - Arc::new(MockCodeFetching::new()), Default::default(), u64::MAX, + SameTokensPolicy::Disallow, ); let creation = OrderCreation { valid_to: time::now_in_epoch_seconds() + 10, - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - buy_amount: U256::from(4), - sell_amount: U256::from(3), - fee_amount: U256::from(0), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + buy_amount: alloy::primitives::U256::from(4), + sell_amount: alloy::primitives::U256::from(3), + fee_amount: alloy::primitives::U256::from(0), signature: Signature::Eip1271(vec![1, 2, 3]), app_data: OrderCreationAppData::Full { full: "{}".to_string(), }, - from: Some(H160([0xf0; 20])), - receiver: Some(H160([0xf0; 20])), + from: Some(Address::repeat_byte(0xf0)), + receiver: Some(Address::repeat_byte(0xf0)), quote_id, ..Default::default() }; @@ -2568,4 +2936,245 @@ mod tests { assert_eq!(quote_id, returned_quote_id.and_then(|quote| quote.id)); } + + fn make_1271_order_creation() -> OrderCreation { + OrderCreation { + valid_to: time::now_in_epoch_seconds() + 2, + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), + buy_amount: U256::ONE, + sell_amount: U256::ONE, + fee_amount: U256::ZERO, + from: Some(Address::repeat_byte(1)), + signature: Signature::Eip1271(vec![1, 2, 3]), + app_data: OrderCreationAppData::Full { + full: "{}".to_string(), + }, + ..Default::default() + } + } + + fn order_simulator(sim: MockOrderSimulating) -> OrderSimulator { + OrderSimulator { + simulator: Arc::new(sim), + timeout: DEFAULT_ORDER_SIM_TIMEOUT, + } + } + + fn build_1271_validator( + signature_validator: MockSignatureValidating, + order_simulator: Option, + eip1271_skip_creation_validation: bool, + ) -> OrderValidator { + // The quote lookup, balance fetch, and limit-order count are off the + // path under test here. Stub them to always succeed so every test + // reaches the EIP-1271 block without tripping earlier validation. + let mut order_quoter = MockOrderQuoting::new(); + order_quoter + .expect_find_quote() + .returning(|_, _| Ok(Default::default())); + let mut balance_fetcher = MockBalanceFetching::new(); + balance_fetcher + .expect_can_transfer() + .returning(|_, _| Ok(())); + let mut limit_order_counter = MockLimitOrderCounting::new(); + limit_order_counter.expect_count().returning(|_| Ok(0u64)); + let native_token = + WETH9::Instance::new(Address::repeat_byte(0xef), ethrpc::mock::web3().provider); + OrderValidator::new( + native_token, + Arc::new(order_validation::banned::Users::none()), + OrderValidPeriodConfiguration::any(), + eip1271_skip_creation_validation, + Default::default(), + HooksTrampoline::Instance::new( + Address::repeat_byte(0xcf), + ProviderBuilder::new() + .connect_mocked_client(Asserter::new()) + .erased(), + ), + Arc::new(order_quoter), + Arc::new(balance_fetcher), + Arc::new(signature_validator), + order_simulator, + Arc::new(limit_order_counter), + 0, + Default::default(), + u64::MAX, + SameTokensPolicy::Disallow, + ) + } + + /// Verifies that the signature result alone decides acceptance and the + /// simulation result is observed only. + #[tokio::test] + async fn signature_and_simulation_outcome_matrix() { + #[derive(Copy, Clone, Debug)] + enum Sig { + Pass, + Invalid, + } + #[derive(Copy, Clone, Debug)] + enum Sim { + Pass, + Reverted, + } + #[derive(Copy, Clone, Debug)] + enum Expected { + Accepted, + InvalidSignature, + } + + let cases: &[(Sig, Sim, Expected)] = &[ + (Sig::Pass, Sim::Pass, Expected::Accepted), + (Sig::Pass, Sim::Reverted, Expected::Accepted), + (Sig::Invalid, Sim::Pass, Expected::InvalidSignature), + (Sig::Invalid, Sim::Reverted, Expected::InvalidSignature), + ]; + + for &(sig, simulation, expected) in cases { + let label = format!("sig={sig:?} sim={simulation:?}"); + let mut signature_validator = MockSignatureValidating::new(); + signature_validator + .expect_validate_signature_and_get_additional_gas() + .returning(move |_| match sig { + Sig::Pass => Ok(0u64), + Sig::Invalid => Err(SignatureValidationError::Invalid), + }); + let mut sim = MockOrderSimulating::new(); + sim.expect_simulate() + .times(1) + .returning(move |_, _| match simulation { + Sim::Pass => Ok(()), + Sim::Reverted => Err(OrderSimulationError::Reverted { + reason: "hook reverted".into(), + tenderly_url: None, + tenderly_request: None, + }), + }); + let validator = + build_1271_validator(signature_validator, Some(order_simulator(sim)), false); + let result = validator + .validate_and_construct_order( + make_1271_order_creation(), + &DomainSeparator::default(), + Default::default(), + None, + ) + .await; + match expected { + Expected::Accepted => assert!(result.is_ok(), "{label}: got {result:?}"), + Expected::InvalidSignature => assert!( + matches!(result, Err(ValidationError::InvalidEip1271Signature(_))), + "{label}: got {result:?}" + ), + } + } + } + + #[tokio::test] + async fn simulation_infra_error_does_not_reject_order() { + let mut signature_validator = MockSignatureValidating::new(); + signature_validator + .expect_validate_signature_and_get_additional_gas() + .returning(|_| Ok(0u64)); + let mut sim = MockOrderSimulating::new(); + sim.expect_simulate() + .returning(|_, _| Err(OrderSimulationError::Infra(anyhow!("RPC down")))); + let validator = + build_1271_validator(signature_validator, Some(order_simulator(sim)), false); + let result = validator + .validate_and_construct_order( + make_1271_order_creation(), + &DomainSeparator::default(), + Default::default(), + None, + ) + .await; + assert!(result.is_ok(), "expected Ok, got {result:?}"); + } + + #[tokio::test] + async fn skip_flag_runs_simulation_only_and_never_rejects() { + let mut signature_validator = MockSignatureValidating::new(); + // With `eip1271_skip_creation_validation = true`, the signature + // validator must not be called. + signature_validator + .expect_validate_signature_and_get_additional_gas() + .times(0); + let mut sim = MockOrderSimulating::new(); + sim.expect_simulate().returning(|_, _| { + Err(OrderSimulationError::Reverted { + reason: "x".into(), + tenderly_url: None, + tenderly_request: None, + }) + }); + let validator = build_1271_validator(signature_validator, Some(order_simulator(sim)), true); + let result = validator + .validate_and_construct_order( + make_1271_order_creation(), + &DomainSeparator::default(), + Default::default(), + None, + ) + .await; + assert!(result.is_ok(), "got {result:?}"); + } + + #[tokio::test] + async fn simulator_runs_for_non_eip1271_orders() { + // EOA orders skip the EIP-1271 signature check but still go through + // the simulator for observability. + let mut signature_validator = MockSignatureValidating::new(); + signature_validator + .expect_validate_signature_and_get_additional_gas() + .times(0); + let mut sim = MockOrderSimulating::new(); + sim.expect_simulate().times(1).returning(|_, _| Ok(())); + let validator = + build_1271_validator(signature_validator, Some(order_simulator(sim)), false); + + let eoa_order = OrderCreation { + // `from = None` so `verify_owner` accepts the address recovered + // from the non-zero ECDSA signature, letting the order reach the + // simulator path. + from: None, + signature: Signature::Eip712(EcdsaSignature::non_zero()), + ..make_1271_order_creation() + }; + // Ignore the final result (it will fail WrongOwner/etc. later in the + // pipeline - we only care that the sim was invoked). + let _ = validator + .validate_and_construct_order( + eoa_order, + &DomainSeparator::default(), + Default::default(), + None, + ) + .await; + // `sim.expect_simulate().times(1)` asserts on drop. + } + + #[tokio::test] + async fn invalid_signature_rejected_when_simulator_disabled() { + let mut signature_validator = MockSignatureValidating::new(); + signature_validator + .expect_validate_signature_and_get_additional_gas() + .returning(|_| Err(SignatureValidationError::Invalid)); + let validator = build_1271_validator(signature_validator, None, false); + let err = validator + .validate_and_construct_order( + make_1271_order_creation(), + &DomainSeparator::default(), + Default::default(), + None, + ) + .await + .unwrap_err(); + assert!( + matches!(err, ValidationError::InvalidEip1271Signature(_)), + "got {err:?}" + ); + } } diff --git a/crates/shared/src/price_estimation/mod.rs b/crates/shared/src/price_estimation/mod.rs deleted file mode 100644 index 862cb88735..0000000000 --- a/crates/shared/src/price_estimation/mod.rs +++ /dev/null @@ -1,755 +0,0 @@ -use { - self::trade_verifier::balance_overrides, - crate::{ - arguments::{self, display_option, display_secret_option}, - trade_finding::{Interaction, QuoteExecution}, - }, - alloy::primitives::Address, - anyhow::{Result, ensure}, - bigdecimal::BigDecimal, - ethcontract::{H160, U256}, - futures::future::BoxFuture, - itertools::Itertools, - model::order::{BuyTokenDestination, OrderKind, SellTokenSource}, - number::nonzero::U256 as NonZeroU256, - rate_limit::{RateLimiter, Strategy}, - reqwest::Url, - serde::{Deserialize, Serialize}, - std::{ - cmp::{Eq, PartialEq}, - error::Error, - fmt::{self, Display, Formatter}, - future::Future, - hash::Hash, - str::FromStr, - sync::Arc, - time::{Duration, Instant}, - }, - thiserror::Error, -}; - -mod buffered; -pub mod competition; -pub mod external; -pub mod factory; -pub mod gas; -pub mod instrumented; -pub mod native; -pub mod native_price_cache; -pub mod sanitized; -pub mod trade_finder; -pub mod trade_verifier; - -#[derive(Clone, Debug)] -pub struct NativePriceEstimators(Vec>); - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ExternalSolver { - pub name: String, - pub url: Url, -} - -impl From for ExternalSolver { - fn from(value: arguments::ExternalSolver) -> Self { - Self { - name: value.name, - url: value.url, - } - } -} - -impl FromStr for ExternalSolver { - type Err = anyhow::Error; - - fn from_str(solver: &str) -> Result { - let parts: Vec<&str> = solver.split('|').collect(); - ensure!(parts.len() >= 2, "not enough arguments for external solver"); - let (name, url) = (parts[0], parts[1]); - let url: Url = url.parse()?; - Ok(Self { - name: name.to_owned(), - url, - }) - } -} - -#[derive(Clone, Debug, Hash, Eq, PartialEq)] -pub enum NativePriceEstimator { - Driver(ExternalSolver), - OneInchSpotPriceApi, - CoinGecko, -} - -impl Display for NativePriceEstimator { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let formatter = match self { - NativePriceEstimator::Driver(s) => format!("{}|{}", &s.name, s.url), - NativePriceEstimator::OneInchSpotPriceApi => "OneInchSpotPriceApi".into(), - NativePriceEstimator::CoinGecko => "CoinGecko".into(), - }; - write!(f, "{formatter}") - } -} - -impl NativePriceEstimators { - pub fn as_slice(&self) -> &[Vec] { - &self.0 - } -} - -impl Display for NativePriceEstimators { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let formatter = self - .as_slice() - .iter() - .map(|stage| { - stage - .iter() - .format_with(",", |estimator, f| f(&format_args!("{estimator}"))) - }) - .format(";"); - write!(f, "{formatter}") - } -} - -impl FromStr for NativePriceEstimators { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - Ok(Self( - s.split(';') - .map(|sub_list| { - sub_list - .split(',') - .map(NativePriceEstimator::from_str) - .collect::>>() - }) - .collect::>>>()?, - )) - } -} - -impl FromStr for NativePriceEstimator { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s { - "OneInchSpotPriceApi" => Ok(NativePriceEstimator::OneInchSpotPriceApi), - "CoinGecko" => Ok(NativePriceEstimator::CoinGecko), - estimator => Ok(NativePriceEstimator::Driver(ExternalSolver::from_str( - estimator, - )?)), - } - } -} - -/// Shared price estimation configuration arguments. -#[derive(clap::Parser)] -#[group(skip)] -pub struct Arguments { - /// Configures the back off strategy for price estimators when requests take - /// too long. Requests issued while back off is active get dropped - /// entirely. Needs to be passed as - /// ",,". - /// back_off_growth_factor: f64 >= 1.0 - /// min_back_off: Duration - /// max_back_off: Duration - #[clap(long, env, verbatim_doc_comment)] - pub price_estimation_rate_limiter: Option, - - /// How often the native price estimator should refresh its cache. - #[clap( - long, - env, - default_value = "1s", - value_parser = humantime::parse_duration, - )] - pub native_price_cache_refresh: Duration, - - /// How long cached native prices stay valid. - #[clap( - long, - env, - default_value = "10m", - value_parser = humantime::parse_duration, - )] - pub native_price_cache_max_age: Duration, - - /// How long before expiry the native price cache should try to update the - /// price in the background. This is useful to make sure that prices are - /// usable at all times. This value has to be smaller than - /// `--native-price-cache-max-age`. - #[clap( - long, - env, - default_value = "80s", - value_parser = humantime::parse_duration, - )] - pub native_price_prefetch_time: Duration, - - /// How many cached native token prices can be updated at most in one - /// maintenance cycle. - #[clap(long, env, default_value = "3")] - pub native_price_cache_max_update_size: usize, - - /// How many price estimation requests can be executed concurrently in the - /// maintenance task. - #[clap(long, env, default_value = "1")] - pub native_price_cache_concurrent_requests: usize, - - /// The amount in native tokens atoms to use for price estimation. Should be - /// reasonably large so that small pools do not influence the prices. If - /// not set a reasonable default is used based on network id. - #[clap(long, env, value_parser = U256::from_dec_str)] - pub amount_to_estimate_prices_with: Option, - - /// The API endpoint for the Balancer SOR API for solving. - #[clap(long, env)] - pub balancer_sor_url: Option, - - /// The API key for the 1Inch API. - #[clap(long, env)] - pub one_inch_api_key: Option, - - /// The base URL for the 1Inch API. - #[clap(long, env, default_value = "https://api.1inch.dev/")] - pub one_inch_url: Url, - - /// The CoinGecko native price configuration - #[clap(flatten)] - pub coin_gecko: CoinGecko, - - /// How inaccurate a quote must be before it gets discarded provided as a - /// factor. - /// E.g. a value of `0.01` means at most 1 percent of the sell or buy tokens - /// can be paid out of the settlement contract buffers. - #[clap(long, env, default_value = "1.")] - pub quote_inaccuracy_limit: BigDecimal, - - /// How strict quote verification should be. - #[clap( - long, - env, - default_value = "unverified", - value_enum, - verbatim_doc_comment - )] - pub quote_verification: QuoteVerificationMode, - - /// Default timeout for quote requests. - #[clap( - long, - env, - default_value = "5s", - value_parser = humantime::parse_duration, - )] - pub quote_timeout: Duration, - - #[clap(flatten)] - pub balance_overrides: balance_overrides::Arguments, - - /// List of mappings of native price tokens substitutions with approximated - /// value from other token: - /// "|,|" - /// - token1 is a token address for which we get the native token price - /// - approx_token1 is a token address used for the price approximation - /// - /// It is very important that both tokens in the pair have the same number - /// of decimals. - #[clap( - long, - env, - value_delimiter = ',', - value_parser = parse_tuple:: - )] - pub native_price_approximation_tokens: Vec<(H160, H160)>, - - /// Tokens for which quote verification should not be attempted. This is an - /// escape hatch when there is a very bad but verifiable liquidity source - /// that would win against a very good but unverifiable liquidity source - /// (e.g. private liquidity that exists but can't be verified). - #[clap(long, env, value_delimiter = ',')] - pub tokens_without_verification: Vec, -} - -/// Custom Clap parser for tuple pair -fn parse_tuple(input: &str) -> Result<(T, U), Box> -where - T: std::str::FromStr, - T::Err: Error + Send + Sync + 'static, - U: std::str::FromStr, - U::Err: Error + Send + Sync + 'static, -{ - let pos = input.find('|').ok_or_else(|| { - format!( - "invalid pair values delimiter character, expected: 'value1|value2', got: '{input}'" - ) - })?; - Ok((input[..pos].parse()?, input[pos + 1..].parse()?)) -} - -#[derive(clap::Parser)] -pub struct CoinGecko { - /// The API key for the CoinGecko API. - #[clap(long, env)] - pub coin_gecko_api_key: Option, - - /// The base URL for the CoinGecko API. - #[clap( - long, - env, - default_value = "https://api.coingecko.com/api/v3/simple/token_price" - )] - pub coin_gecko_url: Url, - - #[clap(flatten)] - pub coin_gecko_buffered: Option, -} - -#[derive(clap::Parser)] -#[clap(group( - clap::ArgGroup::new("coin_gecko_buffered") - .requires_all(&[ - "coin_gecko_debouncing_time", - "coin_gecko_broadcast_channel_capacity" - ]) - .multiple(true) - .required(false), -))] -pub struct CoinGeckoBuffered { - /// An additional minimum delay to wait for collecting CoinGecko requests. - /// - /// The delay to start counting after receiving the first request. - #[clap(long, env, value_parser = humantime::parse_duration, group = "coin_gecko_buffered")] - pub coin_gecko_debouncing_time: Option, - - /// Maximum capacity of the broadcast channel to store the CoinGecko native - /// prices results - #[clap(long, env, group = "coin_gecko_buffered")] - pub coin_gecko_broadcast_channel_capacity: Option, -} - -/// Controls which level of quote verification gets applied. -#[derive(Copy, Clone, Debug, clap::ValueEnum)] -#[clap(rename_all = "kebab-case")] -pub enum QuoteVerificationMode { - /// Quotes do not get verified. - Unverified, - /// Quotes get verified whenever possible and verified - /// quotes are preferred over unverified ones. - Prefer, - /// Quotes get discarded if they can't be verified. - /// Some scenarios like missing sell token balance are exempt. - EnforceWhenPossible, -} - -impl Display for Arguments { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Self { - price_estimation_rate_limiter, - native_price_cache_refresh, - native_price_cache_max_age, - native_price_prefetch_time, - native_price_cache_max_update_size, - native_price_cache_concurrent_requests, - amount_to_estimate_prices_with, - balancer_sor_url, - one_inch_api_key, - one_inch_url, - coin_gecko, - quote_inaccuracy_limit, - quote_verification, - quote_timeout, - balance_overrides, - native_price_approximation_tokens, - tokens_without_verification, - } = self; - - display_option( - f, - "price_estimation_rate_limites", - price_estimation_rate_limiter, - )?; - writeln!( - f, - "native_price_cache_refresh: {native_price_cache_refresh:?}" - )?; - writeln!( - f, - "native_price_cache_max_age: {native_price_cache_max_age:?}" - )?; - writeln!( - f, - "native_price_prefetch_time: {native_price_prefetch_time:?}" - )?; - writeln!( - f, - "native_price_cache_max_update_size: {native_price_cache_max_update_size}" - )?; - writeln!( - f, - "native_price_cache_concurrent_requests: {native_price_cache_concurrent_requests}" - )?; - display_option( - f, - "amount_to_estimate_prices_with: {}", - amount_to_estimate_prices_with, - )?; - display_option(f, "balancer_sor_url", balancer_sor_url)?; - display_secret_option( - f, - "one_inch_spot_price_api_key: {:?}", - one_inch_api_key.as_ref(), - )?; - writeln!(f, "one_inch_spot_price_api_url: {one_inch_url}")?; - display_secret_option( - f, - "coin_gecko_api_key: {:?}", - coin_gecko.coin_gecko_api_key.as_ref(), - )?; - writeln!(f, "coin_gecko_api_url: {}", coin_gecko.coin_gecko_url)?; - writeln!(f, "coin_gecko_api_url: {}", coin_gecko.coin_gecko_url)?; - writeln!( - f, - "coin_gecko_debouncing_time: {:?}", - coin_gecko - .coin_gecko_buffered - .as_ref() - .map(|coin_gecko_buffered| coin_gecko_buffered.coin_gecko_debouncing_time), - )?; - writeln!( - f, - "coin_gecko_broadcast_channel_capacity: {:?}", - coin_gecko.coin_gecko_buffered.as_ref().map( - |coin_gecko_buffered| coin_gecko_buffered.coin_gecko_broadcast_channel_capacity - ), - )?; - writeln!(f, "quote_inaccuracy_limit: {quote_inaccuracy_limit}")?; - writeln!(f, "quote_verification: {quote_verification:?}")?; - writeln!(f, "quote_timeout: {quote_timeout:?}")?; - write!(f, "{balance_overrides}")?; - writeln!( - f, - "native_price_approximation_tokens: {native_price_approximation_tokens:?}" - )?; - writeln!( - f, - "tokens_without_verification: {tokens_without_verification:?}" - )?; - - Ok(()) - } -} - -#[derive(Error, Debug)] -pub enum PriceEstimationError { - #[error("token {token:?} is not supported: {reason:}")] - UnsupportedToken { token: Address, reason: String }, - - #[error("No liquidity")] - NoLiquidity, - - #[error("Unsupported Order Type")] - UnsupportedOrderType(String), - - #[error("Rate limited")] - RateLimited, - - #[error(transparent)] - EstimatorInternal(anyhow::Error), - - #[error(transparent)] - ProtocolInternal(anyhow::Error), -} - -#[cfg(test)] -impl PartialEq for PriceEstimationError { - // Can't use `Self` here because `discriminant` is only defined for enums - // and the compiler is not smart enough to figure out that `Self` is always - // an enum here. - fn eq(&self, other: &PriceEstimationError) -> bool { - let me = self as &PriceEstimationError; - std::mem::discriminant(me) == std::mem::discriminant(other) - } -} - -impl Clone for PriceEstimationError { - fn clone(&self) -> Self { - match self { - Self::UnsupportedToken { token, reason } => Self::UnsupportedToken { - token: *token, - reason: reason.clone(), - }, - Self::NoLiquidity => Self::NoLiquidity, - Self::UnsupportedOrderType(order_type) => { - Self::UnsupportedOrderType(order_type.clone()) - } - Self::RateLimited => Self::RateLimited, - Self::EstimatorInternal(err) => Self::EstimatorInternal(crate::clone_anyhow_error(err)), - Self::ProtocolInternal(err) => Self::ProtocolInternal(crate::clone_anyhow_error(err)), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize)] -pub struct Query { - pub sell_token: Address, - pub buy_token: Address, - /// For OrderKind::Sell amount is in sell_token and for OrderKind::Buy in - /// buy_token. - pub in_amount: NonZeroU256, - pub kind: OrderKind, - pub verification: Verification, - /// Signals whether responses from that were valid on previous blocks can be - /// used to answer the query. - #[serde(skip_serializing)] - pub block_dependent: bool, - pub timeout: Duration, -} - -/// Conditions under which a given price estimate needs to work in order to be -/// viable. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize)] -pub struct Verification { - /// This address needs to have the `sell_token`. - pub from: H160, - /// This address will receive the `buy_token`. - pub receiver: H160, - /// These interactions will be executed before the trade. - pub pre_interactions: Vec, - /// These interactions will be executed after the trade. - pub post_interactions: Vec, - /// `sell_token` will be taken via this approach. - pub sell_token_source: SellTokenSource, - /// `buy_token` will be sent via this approach. - pub buy_token_destination: BuyTokenDestination, -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] -pub struct Estimate { - pub out_amount: U256, - /// full gas cost when settling this order alone on gp - pub gas: u64, - /// Address of the solver that provided the quote. - pub solver: H160, - /// Did we verify the correctness of this estimate's properties? - pub verified: bool, - /// Data associated with this estimation. - pub execution: QuoteExecution, -} - -impl Estimate { - /// Returns (sell_amount, buy_amount). - pub fn amounts(&self, query: &Query) -> (U256, U256) { - match query.kind { - OrderKind::Buy => (self.out_amount, query.in_amount.get()), - OrderKind::Sell => (query.in_amount.get(), self.out_amount), - } - } - - /// The price of the estimate denominated in buy token. - /// - /// The resulting price is how many units of buy_token are bought for one - /// unit of sell_token (buy_amount / sell_amount). - pub fn price_in_buy_token_f64(&self, query: &Query) -> f64 { - let (sell_amount, buy_amount) = self.amounts(query); - buy_amount.to_f64_lossy() / sell_amount.to_f64_lossy() - } -} - -pub type PriceEstimateResult = Result; - -#[cfg_attr(any(test, feature = "test-util"), mockall::automock)] -pub trait PriceEstimating: Send + Sync + 'static { - fn estimate(&self, query: Arc) -> BoxFuture<'_, PriceEstimateResult>; -} - -pub const HEALTHY_PRICE_ESTIMATION_TIME: Duration = Duration::from_millis(5_000); - -pub async fn rate_limited( - rate_limiter: Arc, - estimation: impl Future>, -) -> Result { - let timed_estimation = async move { - let start = Instant::now(); - let result = estimation.await; - (start.elapsed(), result) - }; - let rate_limited_estimation = - rate_limiter.execute(timed_estimation, |(estimation_time, result)| { - let too_slow = *estimation_time > HEALTHY_PRICE_ESTIMATION_TIME; - let api_rate_limited = matches!(result, Err(PriceEstimationError::RateLimited)); - too_slow || api_rate_limited - }); - match rate_limited_estimation.await { - Ok((_estimation_time, Ok(result))) => Ok(result), - // return original PriceEstimationError - Ok((_estimation_time, Err(err))) => Err(err), - // convert the RateLimiterError to a PriceEstimationError - Err(_) => Err(PriceEstimationError::RateLimited), - } -} - -pub mod mocks { - use {super::*, anyhow::anyhow, futures::FutureExt}; - - pub struct FakePriceEstimator(pub Estimate); - impl PriceEstimating for FakePriceEstimator { - fn estimate(&self, _query: Arc) -> BoxFuture<'_, PriceEstimateResult> { - async { Ok(self.0.clone()) }.boxed() - } - } - - pub struct FailingPriceEstimator; - impl PriceEstimating for FailingPriceEstimator { - fn estimate(&self, _query: Arc) -> BoxFuture<'_, PriceEstimateResult> { - async { - Err(PriceEstimationError::EstimatorInternal(anyhow!( - "always fail" - ))) - } - .boxed() - } - } -} - -#[cfg(test)] -mod tests { - use {super::*, clap::Parser}; - - #[test] - fn string_repr_round_trip_native_price_estimators() { - // We use NativePriceEstimators as one of the types used in an Arguments object - // that derives clap::Parser. Clap parsing of an argument using - // default_value_t requires that std::fmt::Display roundtrips correctly with the - // Arg::value_parser or #[arg(value_enum)]: - // https://docs.rs/clap/latest/clap/_derive/index.html#arg-attributes - - let parsed = |arg: &str| NativePriceEstimators::from_str(arg); - let stringified = |arg: &NativePriceEstimators| format!("{arg}"); - - for repr in [ - &NativePriceEstimator::Driver( - ExternalSolver::from_str( - "baseline|http://localhost:1234/|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - ) - .unwrap(), - ) - .to_string(), - &NativePriceEstimator::OneInchSpotPriceApi.to_string(), - "one|http://localhost:1111/,two|http://localhost:2222/;three|http://localhost:3333/,four|http://localhost:4444/", - &format!( - "one|http://localhost:1111/,two|http://localhost:2222/;{},four|http://localhost:4444/", - NativePriceEstimator::OneInchSpotPriceApi - ), - ] { - assert_eq!(stringified(&parsed(repr).unwrap()), repr); - } - } - - #[test] - fn enable_coin_gecko_buffered() { - let args = vec![ - "test", // Program name - "--coin-gecko-api-key", - "someapikey", - "--coin-gecko-url", - "https://api.coingecko.com/api/v3/simple/token_price", - "--coin-gecko-debouncing-time", - "300ms", - "--coin-gecko-broadcast-channel-capacity", - "50", - ]; - - let coin_gecko = CoinGecko::parse_from(args); - - assert!(coin_gecko.coin_gecko_buffered.is_some()); - - let buffered = coin_gecko.coin_gecko_buffered.unwrap(); - assert_eq!( - buffered.coin_gecko_debouncing_time.unwrap(), - Duration::from_millis(300) - ); - assert_eq!(buffered.coin_gecko_broadcast_channel_capacity.unwrap(), 50); - } - - #[test] - fn test_without_buffered_present() { - let args = vec![ - "test", // Program name - "--coin-gecko-api-key", - "someapikey", - "--coin-gecko-url", - "https://api.coingecko.com/api/v3/simple/token_price", - ]; - - let coin_gecko = CoinGecko::parse_from(args); - - assert!(coin_gecko.coin_gecko_buffered.is_none()); - } - - #[test] - fn test_invalid_partial_buffered_present() { - let args = vec![ - "test", // Program name - "--coin-gecko-api-key", - "someapikey", - "--coin-gecko-url", - "https://api.coingecko.com/api/v3/simple/token_price", - "--coin-gecko-debouncing-time", - "300ms", - ]; - - let result = CoinGecko::try_parse_from(args); - - assert!(result.is_err()); - } - - #[test] - fn test_parse_tuple() { - let result = parse_tuple::( - "0102030405060708091011121314151617181920|a1a2a3a4a5a6a7a8a9a0a1a2a3a4a5a6a7a8a9a0", - ) - .unwrap(); - assert_eq!( - result.0, - H160::from_str("0102030405060708091011121314151617181920").unwrap() - ); - assert_eq!( - result.1, - H160::from_str("a1a2a3a4a5a6a7a8a9a0a1a2a3a4a5a6a7a8a9a0").unwrap() - ); - - let result = parse_tuple::( - "0102030405060708091011121314151617181920 a1a2a3a4a5a6a7a8a9a0a1a2a3a4a5a6a7a8a9a0", - ); - assert!(result.is_err()); - - // test parsing with delimiter - #[derive(Parser)] - struct Cli { - #[arg(value_delimiter = ',', value_parser = parse_tuple::)] - param: Vec<(H160, H160)>, - } - let cli = Cli::parse_from(vec![ - "", - r#"0102030405060708091011121314151617181920|a1a2a3a4a5a6a7a8a9a0a1a2a3a4a5a6a7a8a9a0, - f102030405060708091011121314151617181920|f1a2a3a4a5a6a7a8a9a0a1a2a3a4a5a6a7a8a9a0"#, - ]); - - assert_eq!( - cli.param[0], - ( - H160::from_str("0102030405060708091011121314151617181920").unwrap(), - H160::from_str("a1a2a3a4a5a6a7a8a9a0a1a2a3a4a5a6a7a8a9a0").unwrap() - ) - ); - assert_eq!( - cli.param[1], - ( - H160::from_str("f102030405060708091011121314151617181920").unwrap(), - H160::from_str("f1a2a3a4a5a6a7a8a9a0a1a2a3a4a5a6a7a8a9a0").unwrap() - ) - ); - } -} diff --git a/crates/shared/src/price_estimation/native_price_cache.rs b/crates/shared/src/price_estimation/native_price_cache.rs deleted file mode 100644 index adb6802366..0000000000 --- a/crates/shared/src/price_estimation/native_price_cache.rs +++ /dev/null @@ -1,1013 +0,0 @@ -use { - super::PriceEstimationError, - crate::price_estimation::native::{ - NativePriceEstimateResult, - NativePriceEstimating, - from_normalized_price, - }, - alloy::primitives::Address, - bigdecimal::BigDecimal, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - futures::{FutureExt, StreamExt}, - indexmap::IndexSet, - primitive_types::H160, - prometheus::{IntCounter, IntCounterVec, IntGauge}, - rand::Rng, - std::{ - collections::{HashMap, hash_map::Entry}, - sync::{Arc, Mutex, MutexGuard, Weak}, - time::{Duration, Instant}, - }, - tokio::time, - tracing::{Instrument, instrument}, -}; - -#[derive(prometheus_metric_storage::MetricStorage)] -struct Metrics { - /// native price cache hits misses - #[metric(labels("result"))] - native_price_cache_access: IntCounterVec, - /// number of items in cache - native_price_cache_size: IntGauge, - /// number of background updates performed - native_price_cache_background_updates: IntCounter, - /// number of items in cache that are outdated - native_price_cache_outdated_entries: IntGauge, -} - -impl Metrics { - fn get() -> &'static Self { - Metrics::instance(observe::metrics::get_storage_registry()).unwrap() - } -} - -/// Wrapper around `Box` which caches successful price -/// estimates for some time and supports updating the cache in the background. -/// -/// The size of the underlying cache is unbounded. -/// -/// Is an Arc internally. -#[derive(Clone)] -pub struct CachingNativePriceEstimator(Arc); - -struct Inner { - cache: Mutex>, - high_priority: Mutex>, - estimator: Box, - max_age: Duration, - concurrent_requests: usize, - // TODO remove when implementing a less hacky solution - /// Maps a requested token to an approximating token. If the system - /// wants to get the native price for the requested token the native - /// price of the approximating token should be fetched and returned instead. - /// This can be useful for tokens that are hard to route but are pegged to - /// the same underlying asset so approximating their native prices is deemed - /// safe (e.g. csUSDL => Dai). - /// It's very important that the 2 tokens have the same number of decimals. - /// After startup this is a read only value. - approximation_tokens: HashMap, - quote_timeout: Duration, -} - -struct UpdateTask { - inner: Weak, - update_interval: Duration, - update_size: Option, - prefetch_time: Duration, -} - -type CacheEntry = Result; - -#[derive(Debug, Clone)] -struct CachedResult { - result: CacheEntry, - updated_at: Instant, - requested_at: Instant, - accumulative_errors_count: u32, -} - -/// Defines how many consecutive errors are allowed before the cache starts -/// returning the error to the user without trying to fetch the price from the -/// estimator. -const ACCUMULATIVE_ERRORS_THRESHOLD: u32 = 5; - -impl CachedResult { - fn new( - result: CacheEntry, - updated_at: Instant, - requested_at: Instant, - current_accumulative_errors_count: u32, - ) -> Self { - let estimator_internal_errors_count = - matches!(result, Err(PriceEstimationError::EstimatorInternal(_))) - .then_some(current_accumulative_errors_count + 1) - .unwrap_or_default(); - - Self { - result, - updated_at, - requested_at, - accumulative_errors_count: estimator_internal_errors_count, - } - } - - /// The result is not ready if the estimator has returned an internal error - /// and consecutive errors are less than - /// `ESTIMATOR_INTERNAL_ERRORS_THRESHOLD`. - fn is_ready(&self) -> bool { - !matches!(self.result, Err(PriceEstimationError::EstimatorInternal(_))) - || self.accumulative_errors_count >= ACCUMULATIVE_ERRORS_THRESHOLD - } -} - -impl Inner { - // Returns a single cached price and updates its `requested_at` field. - fn get_cached_price( - token: H160, - now: Instant, - cache: &mut MutexGuard>, - max_age: &Duration, - create_missing_entry: bool, - ) -> Option { - match cache.entry(token) { - Entry::Occupied(mut entry) => { - let entry = entry.get_mut(); - entry.requested_at = now; - let is_recent = now.saturating_duration_since(entry.updated_at) < *max_age; - is_recent.then_some(entry.clone()) - } - Entry::Vacant(entry) => { - if create_missing_entry { - // Create an outdated cache entry so the background task keeping the cache warm - // will fetch the price during the next maintenance cycle. - // This should happen only for prices missing while building the auction. - // Otherwise malicious actors could easily cause the cache size to blow up. - let outdated_timestamp = now.checked_sub(*max_age).unwrap(); - tracing::trace!(?token, "create outdated price entry"); - entry.insert(CachedResult::new( - Ok(0.), - outdated_timestamp, - now, - Default::default(), - )); - } - None - } - } - } - - fn get_ready_to_use_cached_price( - token: H160, - now: Instant, - cache: &mut MutexGuard>, - max_age: &Duration, - create_missing_entry: bool, - ) -> Option { - Self::get_cached_price(token, now, cache, max_age, create_missing_entry) - .filter(|cached| cached.is_ready()) - } - - /// Checks cache for the given tokens one by one. If the price is already - /// cached, it gets returned. If it's not in the cache, a new price - /// estimation request gets issued. We check the cache before each - /// request because they can take a long time and some other task might - /// have fetched some requested price in the meantime. - fn estimate_prices_and_update_cache<'a>( - &'a self, - tokens: &'a [H160], - max_age: Duration, - request_timeout: Duration, - ) -> futures::stream::BoxStream<'a, (H160, NativePriceEstimateResult)> { - let estimates = tokens.iter().map(move |token| async move { - let current_accumulative_errors_count = { - // check if the price is cached by now - let now = Instant::now(); - let mut cache = self.cache.lock().unwrap(); - - match Self::get_cached_price(*token, now, &mut cache, &max_age, false) { - Some(cached) if cached.is_ready() => { - return (*token, cached.result); - } - Some(cached) => cached.accumulative_errors_count, - None => Default::default(), - } - }; - - let token_to_fetch = *self.approximation_tokens.get(token).unwrap_or(token); - - let result = self - .estimator - .estimate_native_price(token_to_fetch.into_alloy(), request_timeout) - .await; - - // update price in cache - if should_cache(&result) { - let now = Instant::now(); - let mut cache = self.cache.lock().unwrap(); - - cache.insert( - *token, - CachedResult::new(result.clone(), now, now, current_accumulative_errors_count), - ); - }; - - (*token, result) - }); - futures::stream::iter(estimates) - .buffered(self.concurrent_requests) - .boxed() - } - - /// Tokens with highest priority first. - fn sorted_tokens_to_update(&self, max_age: Duration, now: Instant) -> Vec { - let mut outdated: Vec<_> = self - .cache - .lock() - .unwrap() - .iter() - .filter(|(_, cached)| now.saturating_duration_since(cached.updated_at) > max_age) - .map(|(token, cached)| (*token, cached.requested_at)) - .collect(); - - let high_priority = self.high_priority.lock().unwrap().clone(); - let index = |token: &H160| high_priority.get_index_of(token).unwrap_or(usize::MAX); - outdated.sort_by_cached_key(|entry| { - ( - index(&entry.0), // important items have a low index - std::cmp::Reverse(entry.1), // important items have recent (i.e. "big") timestamp - ) - }); - outdated.into_iter().map(|(token, _)| token).collect() - } -} - -fn should_cache(result: &Result) -> bool { - // We don't want to cache errors that we consider transient - match result { - Ok(_) - | Err(PriceEstimationError::NoLiquidity) - | Err(PriceEstimationError::UnsupportedToken { .. }) - | Err(PriceEstimationError::EstimatorInternal(_)) => true, - Err(PriceEstimationError::ProtocolInternal(_)) | Err(PriceEstimationError::RateLimited) => { - false - } - Err(PriceEstimationError::UnsupportedOrderType(_)) => { - tracing::error!(?result, "Unexpected error in native price cache"); - false - } - } -} - -impl UpdateTask { - /// Single run of the background updating process. - async fn single_update(&self, inner: &Inner) { - let metrics = Metrics::get(); - metrics - .native_price_cache_size - .set(i64::try_from(inner.cache.lock().unwrap().len()).unwrap_or(i64::MAX)); - - let max_age = inner.max_age.saturating_sub(self.prefetch_time); - let mut outdated_entries = inner.sorted_tokens_to_update(max_age, Instant::now()); - - tracing::trace!(tokens = ?outdated_entries, first_n = ?self.update_size, "outdated prices to fetch"); - - metrics - .native_price_cache_outdated_entries - .set(i64::try_from(outdated_entries.len()).unwrap_or(i64::MAX)); - - outdated_entries.truncate(self.update_size.unwrap_or(usize::MAX)); - - if outdated_entries.is_empty() { - return; - } - - let mut stream = - inner.estimate_prices_and_update_cache(&outdated_entries, max_age, inner.quote_timeout); - while stream.next().await.is_some() {} - metrics - .native_price_cache_background_updates - .inc_by(outdated_entries.len() as u64); - } - - /// Runs background updates until inner is no longer alive. - async fn run(self) { - while let Some(inner) = self.inner.upgrade() { - let now = Instant::now(); - self.single_update(&inner).await; - tokio::time::sleep(self.update_interval.saturating_sub(now.elapsed())).await; - } - } -} - -impl CachingNativePriceEstimator { - pub fn initialize_cache(&self, prices: HashMap) { - let mut rng = rand::thread_rng(); - let now = std::time::Instant::now(); - - let cache = prices - .into_iter() - .filter_map(|(token, price)| { - // Generate random `updated_at` timestamp - // to avoid spikes of expired prices. - let percent_expired = rng.gen_range(50..=90); - let age = self.0.max_age.as_secs() * percent_expired / 100; - let updated_at = now - Duration::from_secs(age); - - Some(( - token, - CachedResult::new( - Ok(from_normalized_price(price)?), - updated_at, - now, - Default::default(), - ), - )) - }) - .collect::>(); - - *self.0.cache.lock().unwrap() = cache; - } - - /// Creates new CachingNativePriceEstimator using `estimator` to calculate - /// native prices which get cached a duration of `max_age`. - /// Spawns a background task maintaining the cache once per - /// `update_interval`. Only soon to be outdated prices get updated and - /// recently used prices have a higher priority. If `update_size` is - /// `Some(n)` at most `n` prices get updated per interval. - /// If `update_size` is `None` no limit gets applied. - #[expect(clippy::too_many_arguments)] - pub fn new( - estimator: Box, - max_age: Duration, - update_interval: Duration, - update_size: Option, - prefetch_time: Duration, - concurrent_requests: usize, - approximation_tokens: HashMap, - quote_timeout: Duration, - ) -> Self { - let inner = Arc::new(Inner { - estimator, - cache: Default::default(), - high_priority: Default::default(), - max_age, - concurrent_requests, - approximation_tokens, - quote_timeout, - }); - - let update_task = UpdateTask { - inner: Arc::downgrade(&inner), - update_interval, - update_size, - prefetch_time, - } - .run() - .instrument(tracing::info_span!("caching_native_price_estimator")); - tokio::spawn(update_task); - - Self(inner) - } - - /// Only returns prices that are currently cached. Missing prices will get - /// prioritized to get fetched during the next cycles of the maintenance - /// background task. - fn get_cached_prices( - &self, - tokens: &[H160], - ) -> HashMap> { - let now = Instant::now(); - let mut cache = self.0.cache.lock().unwrap(); - let mut results = HashMap::default(); - for token in tokens { - let cached = Inner::get_ready_to_use_cached_price( - *token, - now, - &mut cache, - &self.0.max_age, - true, - ); - let label = if cached.is_some() { "hits" } else { "misses" }; - Metrics::get() - .native_price_cache_access - .with_label_values(&[label]) - .inc_by(1); - if let Some(result) = cached { - results.insert(*token, result.result); - } - } - results - } - - pub fn replace_high_priority(&self, tokens: IndexSet) { - tracing::trace!(?tokens, "update high priority tokens"); - *self.0.high_priority.lock().unwrap() = tokens; - } - - pub async fn estimate_native_prices_with_timeout<'a>( - &'a self, - tokens: &'a [H160], - timeout: Duration, - ) -> HashMap { - let mut prices = self.get_cached_prices(tokens); - if timeout.is_zero() { - return prices; - } - - let uncached_tokens: Vec<_> = tokens - .iter() - .filter(|t| !prices.contains_key(t)) - .copied() - .collect(); - let price_stream = - self.0 - .estimate_prices_and_update_cache(&uncached_tokens, self.0.max_age, timeout); - - let _ = time::timeout(timeout, async { - let mut price_stream = price_stream; - - while let Some((token, result)) = price_stream.next().await { - prices.insert(token, result); - } - }) - .await; - - // Return whatever was collected up to that point, regardless of the timeout - prices - } -} - -impl NativePriceEstimating for CachingNativePriceEstimator { - #[instrument(skip_all)] - fn estimate_native_price( - &self, - token: Address, - timeout: Duration, - ) -> futures::future::BoxFuture<'_, NativePriceEstimateResult> { - async move { - let cached = { - let now = Instant::now(); - let mut cache = self.0.cache.lock().unwrap(); - Inner::get_ready_to_use_cached_price( - token.into_legacy(), - now, - &mut cache, - &self.0.max_age, - false, - ) - }; - - let label = if cached.is_some() { "hits" } else { "misses" }; - Metrics::get() - .native_price_cache_access - .with_label_values(&[label]) - .inc_by(1); - - if let Some(cached) = cached { - return cached.result; - } - - self.0 - .estimate_prices_and_update_cache(&[token.into_legacy()], self.0.max_age, timeout) - .next() - .await - .unwrap() - .1 - } - .boxed() - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::price_estimation::{ - HEALTHY_PRICE_ESTIMATION_TIME, - PriceEstimationError, - native::{MockNativePriceEstimating, NativePriceEstimating}, - }, - anyhow::anyhow, - futures::FutureExt, - num::ToPrimitive, - }; - - fn token(u: u64) -> Address { - Address::left_padding_from(&u.to_be_bytes()) - } - - #[tokio::test] - async fn caches_successful_estimates_with_loaded_prices() { - let mut inner = MockNativePriceEstimating::new(); - inner.expect_estimate_native_price().never(); - - const MAX_AGE_SECS: u64 = 600; - let min_age = Duration::from_secs(MAX_AGE_SECS * 49 / 100); - let max_age = Duration::from_secs(MAX_AGE_SECS * 91 / 100); - - let prices = HashMap::from_iter( - (0..10).map(|t| (token(t).into_legacy(), BigDecimal::try_from(1e18).unwrap())), - ); - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_secs(MAX_AGE_SECS), - Default::default(), - None, - Default::default(), - 1, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - estimator.initialize_cache(prices); - - { - // Check that `updated_at` timestamps are initialized with - // reasonable values. - let cache = estimator.0.cache.lock().unwrap(); - for value in cache.values() { - let elapsed = value.updated_at.elapsed(); - assert!(elapsed >= min_age && elapsed <= max_age); - } - } - - for i in 0..10 { - let result = estimator - .estimate_native_price(token(i), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); - } - } - - #[tokio::test] - async fn caches_successful_estimates() { - let mut inner = MockNativePriceEstimating::new(); - inner - .expect_estimate_native_price() - .times(1) - .returning(|_, _| async { Ok(1.0) }.boxed()); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(30), - Default::default(), - None, - Default::default(), - 1, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - for _ in 0..10 { - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); - } - } - - #[tokio::test] - async fn caches_approximated_estimates_use() { - let mut inner = MockNativePriceEstimating::new(); - inner - .expect_estimate_native_price() - .times(1) - .withf(move |t, _| *t == token(0)) - .returning(|_, _| async { Ok(1.0) }.boxed()); - inner - .expect_estimate_native_price() - .times(1) - .withf(move |t, _| *t == token(100)) - .returning(|_, _| async { Ok(100.0) }.boxed()); - inner - .expect_estimate_native_price() - .times(1) - .withf(move |t, _| *t == token(200)) - .returning(|_, _| async { Ok(200.0) }.boxed()); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(30), - Default::default(), - None, - Default::default(), - 1, - // set token approximations for tokens 1 and 2 - HashMap::from([ - (token(1).into_legacy(), token(100).into_legacy()), - (token(2).into_legacy(), token(200).into_legacy()), - ]), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - // no approximation token used for token 0 - assert_eq!( - estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await - .unwrap() - .to_i64() - .unwrap(), - 1 - ); - - // approximation price used for tokens 1 and 2 - assert_eq!( - estimator - .estimate_native_price(token(1), HEALTHY_PRICE_ESTIMATION_TIME) - .await - .unwrap() - .to_i64() - .unwrap(), - 100 - ); - assert_eq!( - estimator - .estimate_native_price(token(2), HEALTHY_PRICE_ESTIMATION_TIME) - .await - .unwrap() - .to_i64() - .unwrap(), - 200 - ); - } - - #[tokio::test] - async fn caches_nonrecoverable_failed_estimates() { - let mut inner = MockNativePriceEstimating::new(); - inner - .expect_estimate_native_price() - .times(1) - .returning(|_, _| async { Err(PriceEstimationError::NoLiquidity) }.boxed()); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(30), - Default::default(), - None, - Default::default(), - 1, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - for _ in 0..10 { - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert!(matches!( - result.as_ref().unwrap_err(), - PriceEstimationError::NoLiquidity - )); - } - } - - #[tokio::test] - async fn properly_caches_accumulative_errors() { - let mut inner = MockNativePriceEstimating::new(); - let mut seq = mockall::Sequence::new(); - - // First 3 calls: Return EstimatorInternal error. Increment the errors counter. - inner - .expect_estimate_native_price() - .times(3) - .in_sequence(&mut seq) - .returning(|_, _| { - async { Err(PriceEstimationError::EstimatorInternal(anyhow!("boom"))) }.boxed() - }); - - // Next 1 call: Return Ok(1.0). This resets the errors counter. - inner - .expect_estimate_native_price() - .once() - .in_sequence(&mut seq) - .returning(|_, _| async { Ok(1.0) }.boxed()); - - // Next 2 calls: Return EstimatorInternal error. Start incrementing the errors - // counter from the beginning. - inner - .expect_estimate_native_price() - .times(2) - .in_sequence(&mut seq) - .returning(|_, _| { - async { Err(PriceEstimationError::EstimatorInternal(anyhow!("boom"))) }.boxed() - }); - - // Next call: Return a recoverable error, which doesn't affect the errors - // counter. - inner - .expect_estimate_native_price() - .once() - .in_sequence(&mut seq) - .returning(|_, _| async { Err(PriceEstimationError::RateLimited) }.boxed()); - - // Since the ACCUMULATIVE_ERRORS_THRESHOLD is 5, there are only 3 more calls - // remain. Anything exceeding that must return the cached value. - inner - .expect_estimate_native_price() - .times(3) - .in_sequence(&mut seq) - .returning(|_, _| { - async { Err(PriceEstimationError::EstimatorInternal(anyhow!("boom"))) }.boxed() - }); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(100), - Duration::from_millis(200), - None, - Default::default(), - 1, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - // First 3 calls: The cache is not used. Counter gets increased. - for _ in 0..3 { - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert!(matches!( - result.as_ref().unwrap_err(), - PriceEstimationError::EstimatorInternal(_) - )); - } - - // Reset the errors counter. - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); - - // Make sure the cached value gets evicted. - tokio::time::sleep(Duration::from_millis(120)).await; - - // Increment the errors counter again. - for _ in 0..2 { - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert!(matches!( - result.as_ref().unwrap_err(), - PriceEstimationError::EstimatorInternal(_) - )); - } - - // Receive a recoverable error, which shouldn't affect the counter. - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert!(matches!( - result.as_ref().unwrap_err(), - PriceEstimationError::RateLimited - )); - - // Make more than expected calls. The cache should be used once the threshold is - // reached. - for _ in 0..(ACCUMULATIVE_ERRORS_THRESHOLD * 2) { - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert!(matches!( - result.as_ref().unwrap_err(), - PriceEstimationError::EstimatorInternal(_) - )); - } - } - - #[tokio::test] - async fn does_not_cache_recoverable_failed_estimates() { - let mut inner = MockNativePriceEstimating::new(); - inner - .expect_estimate_native_price() - .times(10) - .returning(|_, _| async { Err(PriceEstimationError::RateLimited) }.boxed()); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(30), - Default::default(), - None, - Default::default(), - 1, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - for _ in 0..10 { - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert!(matches!( - result.as_ref().unwrap_err(), - PriceEstimationError::RateLimited - )); - } - } - - #[tokio::test] - async fn maintenance_can_limit_update_size_to_n() { - let mut inner = MockNativePriceEstimating::new(); - // first request from user - inner - .expect_estimate_native_price() - .times(1) - .returning(|passed_token, _| { - assert_eq!(passed_token, token(0)); - async { Ok(1.0) }.boxed() - }); - // second request from user - inner - .expect_estimate_native_price() - .times(1) - .returning(|passed_token, _| { - assert_eq!(passed_token, token(1)); - async { Ok(2.0) }.boxed() - }); - // maintenance task updates n=1 outdated prices - inner - .expect_estimate_native_price() - .times(1) - .returning(|passed_token, _| { - assert_eq!(passed_token, token(1)); - async { Ok(4.0) }.boxed() - }); - // user requested something which has been skipped by the maintenance task - inner - .expect_estimate_native_price() - .times(1) - .returning(|passed_token, _| { - assert_eq!(passed_token, token(0)); - async { Ok(3.0) }.boxed() - }); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(30), - Duration::from_millis(50), - Some(1), - Duration::default(), - 1, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - // fill cache with 2 different queries - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 1); - let result = estimator - .estimate_native_price(token(1), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 2); - - // wait for maintenance cycle - tokio::time::sleep(Duration::from_millis(60)).await; - - let result = estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 3); - - let result = estimator - .estimate_native_price(token(1), HEALTHY_PRICE_ESTIMATION_TIME) - .await; - assert_eq!(result.as_ref().unwrap().to_i64().unwrap(), 4); - } - - #[tokio::test] - async fn maintenance_can_update_all_old_queries() { - let mut inner = MockNativePriceEstimating::new(); - inner - .expect_estimate_native_price() - .times(10) - .returning(move |_, _| async { Ok(1.0) }.boxed()); - // background task updates all outdated prices - inner - .expect_estimate_native_price() - .times(10) - .returning(move |_, _| async { Ok(2.0) }.boxed()); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(30), - Duration::from_millis(50), - None, - Duration::default(), - 1, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - let tokens: Vec<_> = (0..10).map(Address::with_last_byte).collect(); - for token in &tokens { - let price = estimator - .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) - .await - .unwrap(); - assert_eq!(price.to_i64().unwrap(), 1); - } - - // wait for maintenance cycle - tokio::time::sleep(Duration::from_millis(60)).await; - - for token in &tokens { - let price = estimator - .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) - .await - .unwrap(); - assert_eq!(price.to_i64().unwrap(), 2); - } - } - - #[tokio::test] - async fn maintenance_can_update_concurrently() { - const WAIT_TIME_MS: u64 = 100; - const BATCH_SIZE: usize = 100; - let mut inner = MockNativePriceEstimating::new(); - inner - .expect_estimate_native_price() - .times(BATCH_SIZE) - .returning(|_, _| async { Ok(1.0) }.boxed()); - // background task updates all outdated prices - inner - .expect_estimate_native_price() - .times(BATCH_SIZE) - .returning(move |_, _| { - async move { - tokio::time::sleep(tokio::time::Duration::from_millis(WAIT_TIME_MS)).await; - Ok(2.0) - } - .boxed() - }); - - let estimator = CachingNativePriceEstimator::new( - Box::new(inner), - Duration::from_millis(30), - Duration::from_millis(50), - None, - Duration::default(), - BATCH_SIZE, - Default::default(), - HEALTHY_PRICE_ESTIMATION_TIME, - ); - - let tokens: Vec<_> = (0..BATCH_SIZE as u64).map(token).collect(); - for token in &tokens { - let price = estimator - .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) - .await - .unwrap(); - assert_eq!(price.to_i64().unwrap(), 1); - } - - // wait for maintenance cycle - // although we have 100 requests which all take 100ms to complete the - // maintenance cycle completes sooner because all requests are handled - // concurrently. - tokio::time::sleep(Duration::from_millis(60 + WAIT_TIME_MS)).await; - - for token in &tokens { - let price = estimator - .estimate_native_price(*token, HEALTHY_PRICE_ESTIMATION_TIME) - .await - .unwrap(); - assert_eq!(price.to_i64().unwrap(), 2); - } - } - - #[test] - fn outdated_entries_prioritized() { - let t0 = H160::from_low_u64_be(0); - let t1 = H160::from_low_u64_be(1); - let now = Instant::now(); - let inner = Inner { - cache: Mutex::new( - [ - (t0, CachedResult::new(Ok(0.), now, now, Default::default())), - (t1, CachedResult::new(Ok(0.), now, now, Default::default())), - ] - .into_iter() - .collect(), - ), - high_priority: Default::default(), - estimator: Box::new(MockNativePriceEstimating::new()), - max_age: Default::default(), - concurrent_requests: 1, - approximation_tokens: Default::default(), - quote_timeout: HEALTHY_PRICE_ESTIMATION_TIME, - }; - - let now = now + Duration::from_secs(1); - - *inner.high_priority.lock().unwrap() = std::iter::once(t0).collect(); - let tokens = inner.sorted_tokens_to_update(Duration::from_secs(0), now); - assert_eq!(tokens[0], t0); - assert_eq!(tokens[1], t1); - - *inner.high_priority.lock().unwrap() = std::iter::once(t1).collect(); - let tokens = inner.sorted_tokens_to_update(Duration::from_secs(0), now); - assert_eq!(tokens[0], t1); - assert_eq!(tokens[1], t0); - } -} diff --git a/crates/shared/src/price_estimation/trade_verifier/balance_overrides/detector.rs b/crates/shared/src/price_estimation/trade_verifier/balance_overrides/detector.rs deleted file mode 100644 index 94ad5a0712..0000000000 --- a/crates/shared/src/price_estimation/trade_verifier/balance_overrides/detector.rs +++ /dev/null @@ -1,225 +0,0 @@ -use { - super::Strategy, - crate::tenderly_api::SimulationError, - anyhow::Context, - contracts::alloy::ERC20, - ethcontract::{Address, H256, U256, state_overrides::StateOverride}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, - maplit::hashmap, - std::{ - collections::HashMap, - fmt::{self, Debug, Formatter}, - sync::Arc, - }, - thiserror::Error, - web3::signing::keccak256, -}; - -/// A heuristic balance override detector based on `eth_call` simulations. -/// -/// This has the exact same node requirements as trade verification. -#[derive(Clone)] -pub struct Detector(Arc); - -pub struct Inner { - web3: ethrpc::Web3, - /// address that we try to override the balances for - holder: Address, - /// all strategies used to detect successful balance overrides - strategies: Vec, - /// overrides for all tested strategies - state_overrides: HashMap, -} - -impl std::ops::Deref for Detector { - type Target = Inner; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Detector { - /// Creates a new balance override detector. - pub fn new(web3: ethrpc::Web3, probing_depth: u8) -> Self { - let holder = { - // On a technical note, Ethereum public addresses are, for the most - // part, generated by taking the 20 last bytes of a Keccak-256 hash (for - // things like contract creation, public address derivation from a - // Secp256k1 public key, etc.), so we use one for our heuristics from a - // 32-byte digest with no know pre-image, to prevent any weird - // interactions with the weird tokens of the world. - let mut address = Address::default(); - address.0.copy_from_slice(&keccak256(b"Moo!")[12..]); - address.0[19] = address.0[19].wrapping_sub(1); - address - }; - - let strategies: Vec<_> = { - // First test storage slots that don't need guesswork. - let mut strategies = vec![ - Strategy::SoladyMapping, - Strategy::SolidityMapping { - slot: U256::from(OPEN_ZEPPELIN_ERC20_UPGRADEABLE), - }, - ]; - - // For each entry point probe the first n following slots. - let entry_points = [ - // solc lays out memory linearly starting at 0 by default - "0000000000000000000000000000000000000000000000000000000000000000", - ]; - for start_slot in entry_points { - let mut slot = U256::from(start_slot); - for _ in 0..probing_depth { - strategies.push(Strategy::SolidityMapping { slot }); - slot += U256::one(); - } - } - - strategies - .into_iter() - .enumerate() - .map(|(index, strategy)| StrategyHelper::new(strategy, index)) - .collect() - }; - - let state_overrides = strategies - .iter() - .map(|helper| helper.strategy.state_override(&holder, &helper.balance)) - .collect::>(); - - Self(Arc::new(Inner { - web3, - holder, - strategies, - state_overrides, - })) - } - - /// Tries to detect the balance override strategy for the specified token. - /// Returns an `Err` if it cannot detect the strategy or an internal - /// simulation fails. - pub async fn detect(&self, token: Address) -> Result { - let token = ERC20::Instance::new(token.into_alloy(), self.web3.alloy.clone()); - let overrides = hashmap! { - token.address().into_legacy() => StateOverride { - state_diff: Some(self.state_overrides.clone()), - ..Default::default() - }, - }; - let balance = token - .balanceOf(self.holder.into_alloy()) - .state(overrides.into_alloy()) - .call() - .await - .context("eth_call with state overrides failed") - .map_err(|e| DetectionError::Simulation(SimulationError::Other(e)))?; - - self.strategies - .iter() - .find_map(|helper| { - (helper.balance.into_alloy() == balance).then_some(helper.strategy.clone()) - }) - .ok_or(DetectionError::NotFound) - } -} - -/// Contains all the information we need to determine which state override -/// was successful. -struct StrategyHelper { - /// strategy that was used to compute the state override - strategy: Strategy, - /// balance amount the strategy wrote into the storage - balance: U256, -} - -impl StrategyHelper { - fn new(strategy: Strategy, index: usize) -> Self { - let index = u8::try_from(index).expect("unreasonable amount of strategies used"); - Self { - strategy, - // Use an exact value which isn't too large or too small. This helps - // not have false positives for cases where the token balances in - // some other denomination from the actual token balance (such as - // stETH for example) and not run into issues with overflows. - // We also make sure that we avoid 0 because `balanceOf()` returns - // 0 by default so we can't use it to detect successful state overrides. - balance: U256::from(u64::from_be_bytes([index + 1; 8])), - } - } -} - -// -const OPEN_ZEPPELIN_ERC20_UPGRADEABLE: &str = - "52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00"; - -impl Debug for Detector { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct("Detector") - .field("simulator", &format_args!("Arc")) - .finish() - } -} - -/// An error detecting the balance override strategy for a token. -#[derive(Debug, Error)] -pub enum DetectionError { - #[error("could not detect a balance override strategy")] - NotFound, - #[error(transparent)] - Simulation(#[from] SimulationError), -} - -#[cfg(test)] -mod tests { - use {super::*, ethrpc::Web3}; - - /// Tests that we can detect storage slots by probing the first - /// n slots or by checking hardcoded known slots. - /// Set `NODE_URL` environment to a mainnet RPC URL. - #[ignore] - #[tokio::test] - async fn detects_storage_slots_mainnet() { - let detector = Detector::new(Web3::new_from_env(), 60); - - let storage = detector - .detect(addr!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) - .await - .unwrap(); - assert_eq!(storage, Strategy::SolidityMapping { slot: 3.into() }); - - let storage = detector - .detect(addr!("4956b52ae2ff65d74ca2d61207523288e4528f96")) - .await - .unwrap(); - assert_eq!( - storage, - Strategy::SolidityMapping { - slot: U256::from(OPEN_ZEPPELIN_ERC20_UPGRADEABLE), - } - ); - - let storage = detector - .detect(addr!("0000000000c5dc95539589fbd24be07c6c14eca4")) - .await - .unwrap(); - assert_eq!(storage, Strategy::SoladyMapping); - } - - /// Tests that we can detect storage slots by probing the first - /// n slots or by checking hardcoded known slots. - /// Set `NODE_URL` environment to an arbitrum RPC URL. - #[ignore] - #[tokio::test] - async fn detects_storage_slots_arbitrum() { - let detector = Detector::new(Web3::new_from_env(), 60); - - // all bridged tokens on arbitrum require a ton of probing - let storage = detector - .detect(addr!("ff970a61a04b1ca14834a43f5de4533ebddb5cc8")) - .await - .unwrap(); - assert_eq!(storage, Strategy::SolidityMapping { slot: 51.into() }); - } -} diff --git a/crates/shared/src/price_estimation/trade_verifier/balance_overrides/mod.rs b/crates/shared/src/price_estimation/trade_verifier/balance_overrides/mod.rs deleted file mode 100644 index 70fdd90c80..0000000000 --- a/crates/shared/src/price_estimation/trade_verifier/balance_overrides/mod.rs +++ /dev/null @@ -1,458 +0,0 @@ -mod detector; - -use { - self::detector::{DetectionError, Detector}, - anyhow::Context as _, - cached::{Cached, SizedCache}, - ethcontract::{Address, H256, U256, state_overrides::StateOverride}, - maplit::hashmap, - std::{ - collections::HashMap, - fmt::{self, Display, Formatter}, - str::FromStr, - sync::{Arc, Mutex}, - }, - web3::signing, -}; - -/// Balance override configuration arguments. -#[derive(clap::Parser)] -#[group(skip)] -pub struct Arguments { - /// Token configuration for simulated balances on verified quotes. This - /// allows the quote verification system to produce verified quotes for - /// traders without sufficient balance for the configured token pairs. - /// - /// The expected format is a comma separated list of `${ADDR}@${SLOT}`, - /// where `ADDR` is the token address and `SLOT` is the Solidity storage - /// slot for the balances mapping. For example for WETH: - /// `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2@3`. - #[clap(long, env, default_value_t)] - pub quote_token_balance_overrides: TokenConfiguration, - - /// Enable automatic detection of token balance overrides. Note that - /// pre-configured values with the `--quote-token-balance-overrides` flag - /// will take precedence. - #[clap(long, env, action = clap::ArgAction::Set, default_value_t)] - pub quote_autodetect_token_balance_overrides: bool, - - /// Controls how many storage slots get probed per storage entry point - /// for automatically detecting how to override the balances of a token. - #[clap(long, env, action = clap::ArgAction::Set, default_value = "60")] - pub quote_autodetect_token_balance_overrides_probing_depth: u8, - - /// Controls for how many tokens we store the result of the automatic - /// balance override detection before evicting less used entries. - #[clap(long, env, action = clap::ArgAction::Set, default_value = "1000")] - pub quote_autodetect_token_balance_overrides_cache_size: usize, -} - -impl Arguments { - /// Creates a balance overrides instance from the current configuration. - pub fn init(&self, web3: ethrpc::Web3) -> Arc { - Arc::new(BalanceOverrides { - hardcoded: self.quote_token_balance_overrides.0.clone(), - detector: self.quote_autodetect_token_balance_overrides.then(|| { - ( - Detector::new( - web3, - self.quote_autodetect_token_balance_overrides_probing_depth, - ), - Mutex::new(SizedCache::with_size( - self.quote_autodetect_token_balance_overrides_cache_size, - )), - ) - }), - }) - } -} - -impl Display for Arguments { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Self { - quote_token_balance_overrides, - quote_autodetect_token_balance_overrides, - quote_autodetect_token_balance_overrides_probing_depth, - quote_autodetect_token_balance_overrides_cache_size, - } = self; - - writeln!( - f, - "quote_token_balance_overrides: {quote_token_balance_overrides:?}" - )?; - writeln!( - f, - "quote_autodetect_token_balance_overrides: \ - {quote_autodetect_token_balance_overrides:?}" - )?; - writeln!( - f, - "quote_autodetect_token_balance_overrides_probing_depth: \ - {quote_autodetect_token_balance_overrides_probing_depth:?}" - )?; - writeln!( - f, - "quote_autodetect_token_balance_overrides_cache_size: \ - {quote_autodetect_token_balance_overrides_cache_size:?}" - )?; - - Ok(()) - } -} - -/// Token configurations for the `BalanceOverriding` component. -#[derive(Clone, Debug, Default)] -pub struct TokenConfiguration(HashMap); - -impl Display for TokenConfiguration { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let format_entry = - |f: &mut Formatter, (addr, strategy): (&Address, &Strategy)| match strategy { - Strategy::SolidityMapping { slot } => write!(f, "{addr:?}@{slot}"), - Strategy::SoladyMapping => write!(f, "SoladyMapping({addr:?})"), - }; - - let mut entries = self.0.iter(); - - let Some(first) = entries.next() else { - return Ok(()); - }; - format_entry(f, first)?; - - for entry in entries { - f.write_str(",")?; - format_entry(f, entry)?; - } - - Ok(()) - } -} - -impl FromStr for TokenConfiguration { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - if s.is_empty() { - return Ok(Self::default()); - } - - let entries = s - .split(',') - .map(|part| -> Result<_, Self::Err> { - let (addr, slot) = part - .split_once('@') - .context("expected {addr}@{slot} format")?; - Ok(( - addr.parse()?, - Strategy::SolidityMapping { - slot: slot.parse()?, - }, - )) - }) - .collect::>()?; - Ok(Self(entries)) - } -} - -/// A component that can provide balance overrides for tokens. -/// -/// This allows a wider range of verified quotes to work, even when balances -/// are not available for the quoter. -#[async_trait::async_trait] -pub trait BalanceOverriding: Send + Sync + 'static { - async fn state_override( - &self, - request: BalanceOverrideRequest, - ) -> Option<(Address, StateOverride)>; -} - -/// Parameters for computing a balance override request. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct BalanceOverrideRequest { - /// The token for the override. - pub token: Address, - /// The account to override the balance for. - pub holder: Address, - /// The token amount (in atoms) to set the balance to. - pub amount: U256, -} - -/// Balance override strategy for a token. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Strategy { - /// Balance override strategy for tokens whose balances are stored in a - /// direct Solidity mapping from token holder to balance amount in the - /// form `mapping(address holder => uint256 amount)`. - /// - /// The strategy is configured with the storage slot [^1] of the mapping. - /// - /// [^1]: - SolidityMapping { slot: U256 }, - /// Strategy computing storage slot for balances based on the Solady library - /// [^1]. - /// - /// [^1]: - SoladyMapping, -} - -impl Strategy { - /// Computes the storage slot and value to override for a particular token - /// holder and amount. - fn state_override(&self, holder: &Address, amount: &U256) -> (H256, H256) { - let key = match self { - Self::SolidityMapping { slot } => { - let mut buf = [0; 64]; - buf[12..32].copy_from_slice(holder.as_fixed_bytes()); - slot.to_big_endian(&mut buf[32..64]); - H256(signing::keccak256(&buf)) - } - Self::SoladyMapping => { - let mut buf = [0; 32]; - buf[0..20].copy_from_slice(holder.as_fixed_bytes()); - buf[28..32].copy_from_slice(&[0x87, 0xa2, 0x11, 0xa2]); - H256(signing::keccak256(&buf)) - } - }; - - let value = { - let mut buf = [0; 32]; - amount.to_big_endian(&mut buf); - H256(buf) - }; - - (key, value) - } -} - -type DetectorCache = Mutex>>; - -/// The default balance override provider. -#[derive(Debug, Default)] -pub struct BalanceOverrides { - /// The configured balance override strategies for tokens. - /// - /// These take priority over the auto-detection mechanism and are excluded - /// from the cache in order to prevent them from getting cleaned up by - /// the caching policy. - hardcoded: HashMap, - /// The balance override detector and its cache. Set to `None` if - /// auto-detection is not enabled. - detector: Option<(Detector, DetectorCache)>, -} - -impl BalanceOverrides { - /// Creates a new instance with sensible defaults. - pub fn new(web3: ethrpc::Web3) -> Self { - Self { - hardcoded: Default::default(), - detector: Some(( - Detector::new(web3, 60), - Mutex::new(SizedCache::with_size(1000)), - )), - } - } - - async fn cached_detection(&self, token: Address) -> Option { - let (detector, cache) = self.detector.as_ref()?; - tracing::trace!(?token, "attempting to auto-detect"); - - { - let mut cache = cache.lock().unwrap(); - if let Some(strategy) = cache.cache_get(&token) { - tracing::trace!(?token, "cache hit"); - return strategy.clone(); - } - } - - let strategy = detector.detect(token).await; - - // Only cache when we successfully detect the token, or we can't find - // it. Anything else is likely a temporary simulator (i.e. node) failure - // which we don't want to cache. - if matches!(&strategy, Ok(_) | Err(DetectionError::NotFound)) { - tracing::debug!(?token, ?strategy, "caching auto-detected strategy"); - let cached_strategy = strategy.as_ref().ok().cloned(); - cache.lock().unwrap().cache_set(token, cached_strategy); - } else { - tracing::warn!( - ?token, - ?strategy, - "error auto-detecting token balance override strategy" - ); - } - - strategy.ok() - } -} - -#[async_trait::async_trait] -impl BalanceOverriding for BalanceOverrides { - async fn state_override( - &self, - request: BalanceOverrideRequest, - ) -> Option<(Address, StateOverride)> { - let strategy = if let Some(strategy) = self.hardcoded.get(&request.token) { - tracing::trace!(token = ?request.token, "using pre-configured balance override strategy"); - Some(strategy.clone()) - } else { - self.cached_detection(request.token).await - }?; - - let (key, value) = strategy.state_override(&request.holder, &request.amount); - tracing::trace!(?strategy, ?key, ?value, "overriding token balance"); - - Some(( - request.token, - StateOverride { - state_diff: Some(hashmap! { key => value }), - ..Default::default() - }, - )) - } -} - -/// Balance overrider that always returns `None`. That can be -/// useful for testing. -pub struct DummyOverrider; - -#[async_trait::async_trait] -impl BalanceOverriding for DummyOverrider { - async fn state_override( - &self, - _request: BalanceOverrideRequest, - ) -> Option<(Address, StateOverride)> { - None - } -} - -#[cfg(test)] -mod tests { - use {super::*, hex_literal::hex}; - - #[tokio::test] - async fn balance_override_computation() { - let cow = addr!("DEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"); - let balance_overrides = BalanceOverrides { - hardcoded: hashmap! { - cow => Strategy::SolidityMapping { - slot: U256::from(0), - }, - }, - ..Default::default() - }; - - assert_eq!( - balance_overrides - .state_override(BalanceOverrideRequest { - token: cow, - holder: addr!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), - amount: 0x42_u64.into(), - }) - .await, - Some(( - cow, - StateOverride { - state_diff: Some(hashmap! { - H256(hex!("fca351f4d96129454cfc8ef7930b638ac71fea35eb69ee3b8d959496beb04a33")) => - H256(hex!("0000000000000000000000000000000000000000000000000000000000000042")), - }), - ..Default::default() - } - )), - ); - - // You can verify the state override computation is correct by running: - // ``` - // curl -X POST $RPC -H 'Content-Type: application/json' --data '{ - // "jsonrpc": "2.0", - // "id": 0, - // "method": "eth_call", - // "params": [ - // { - // "to": "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB", - // "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045" - // }, - // "latest", - // { - // "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB": { - // "stateDiff": { - // "0xfca351f4d96129454cfc8ef7930b638ac71fea35eb69ee3b8d959496beb04a33": - // "0x0000000000000000000000000000000000000000000000000000000000000042" - // } - // } - // } - // ] - // }' - // ``` - } - - #[tokio::test] - async fn balance_overrides_none_for_unknown_tokens() { - let balance_overrides = BalanceOverrides::default(); - assert_eq!( - balance_overrides - .state_override(BalanceOverrideRequest { - token: addr!("0000000000000000000000000000000000000000"), - holder: addr!("0000000000000000000000000000000000000001"), - amount: U256::zero(), - }) - .await, - None, - ); - } - - #[tokio::test] - async fn balance_override_computation_solady() { - let token = addr!("0000000000c5dc95539589fbd24be07c6c14eca4"); - let balance_overrides = BalanceOverrides { - hardcoded: hashmap! { - token => Strategy::SoladyMapping, - }, - ..Default::default() - }; - - assert_eq!( - balance_overrides - .state_override(BalanceOverrideRequest { - token, - holder: addr!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), - amount: 0x42_u64.into(), - }) - .await, - Some(( - token, - StateOverride { - state_diff: Some(hashmap! { - H256(hex!("f6a6656ed2d14bad3cdd3e8871db3f535a136a1b6cd5ae2dced8eb813f3d4e4f")) => - H256(hex!("0000000000000000000000000000000000000000000000000000000000000042")), - }), - ..Default::default() - } - )), - ); - - // You can verify the state override computation is correct by running: - // ``` - // curl -X POST $RPC -H 'Content-Type: application/json' --data '{ - // "jsonrpc": "2.0", - // "id": 0, - // "method": "eth_call", - // "params": [ - // { - // "to": "0x0000000000c5dc95539589fbd24be07c6c14eca4", - // "data": "0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045" - // }, - // "latest", - // { - // "0x0000000000c5dc95539589fbd24be07c6c14eca4": { - // "stateDiff": { - // "f6a6656ed2d14bad3cdd3e8871db3f535a136a1b6cd5ae2dced8eb813f3d4e4f": - // "0x0000000000000000000000000000000000000000000000000000000000000042" - // } - // } - // } - // ] - // }' - // ``` - } -} diff --git a/crates/shared/src/price_estimation/trade_verifier/mod.rs b/crates/shared/src/price_estimation/trade_verifier/mod.rs deleted file mode 100644 index 6702bc5108..0000000000 --- a/crates/shared/src/price_estimation/trade_verifier/mod.rs +++ /dev/null @@ -1,1044 +0,0 @@ -pub mod balance_overrides; - -use { - self::balance_overrides::{BalanceOverrideRequest, BalanceOverriding}, - super::{Estimate, Verification}, - crate::{ - code_fetching::CodeFetching, - encoded_settlement::{EncodedSettlement, EncodedTrade, encode_trade}, - interaction::EncodedInteraction, - tenderly_api::TenderlyCodeSimulator, - trade_finding::{ - Interaction, - QuoteExecution, - TradeKind, - external::dto::{self, JitOrder}, - map_interactions_data, - }, - }, - ::alloy::sol_types::SolCall, - alloy::primitives::{Address, address}, - anyhow::{Context, Result, anyhow}, - bigdecimal::BigDecimal, - contracts::alloy::{ - GPv2Settlement, - WETH9, - support::{AnyoneAuthenticator, Solver, Spardose, Trader}, - }, - ethcontract::{H160, U256, state_overrides::StateOverride}, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, - model::{ - DomainSeparator, - order::{BUY_ETH_ADDRESS, OrderData, OrderKind}, - signature::{Signature, SigningScheme}, - }, - num::BigRational, - number::{ - conversions::{big_decimal_to_big_rational, u256_to_big_rational}, - nonzero::U256 as NonZeroU256, - }, - std::{ - collections::{HashMap, HashSet}, - sync::Arc, - }, - tracing::instrument, -}; - -#[async_trait::async_trait] -pub trait TradeVerifying: Send + Sync + 'static { - /// Verifies if the proposed [`TradeKind`] actually fulfills the - /// [`PriceQuery`]. - async fn verify( - &self, - query: &PriceQuery, - verification: &Verification, - trade: TradeKind, - ) -> Result; -} - -/// Component that verifies a trade is actually executable by simulating it -/// and determines a price estimate based off of that simulation. -#[derive(Clone)] -pub struct TradeVerifier { - web3: Web3, - simulator: Option>, - code_fetcher: Arc, - balance_overrides: Arc, - block_stream: CurrentBlockWatcher, - settlement: GPv2Settlement::Instance, - native_token: H160, - quote_inaccuracy_limit: BigRational, - domain_separator: DomainSeparator, - tokens_without_verification: HashSet, -} - -impl TradeVerifier { - const DEFAULT_GAS: u64 = 12_000_000; - const SPARDOSE: Address = address!("0000000000000000000000000000000000020000"); - const TRADER_IMPL: H160 = addr!("0000000000000000000000000000000000010000"); - - #[expect(clippy::too_many_arguments)] - pub async fn new( - web3: Web3, - simulator: Option>, - code_fetcher: Arc, - balance_overrides: Arc, - block_stream: CurrentBlockWatcher, - settlement: H160, - native_token: H160, - quote_inaccuracy_limit: BigDecimal, - tokens_without_verification: HashSet, - ) -> Result { - let settlement_contract = - GPv2Settlement::GPv2Settlement::new(settlement.into_alloy(), web3.alloy.clone()); - let domain_separator = - DomainSeparator(settlement_contract.domainSeparator().call().await?.0); - Ok(Self { - simulator, - code_fetcher, - balance_overrides, - block_stream, - settlement: settlement_contract, - native_token, - quote_inaccuracy_limit: big_decimal_to_big_rational("e_inaccuracy_limit), - web3, - domain_separator, - tokens_without_verification, - }) - } - - async fn verify_inner( - &self, - query: &PriceQuery, - mut verification: Verification, - trade: &TradeKind, - out_amount: &U256, - ) -> Result { - let start = std::time::Instant::now(); - - // this may change the `verification` parameter (to make more - // quotes verifiable) so we do it as the first thing to ensure - // that all the following code uses the updated value - let overrides = self - .prepare_state_overrides(&mut verification, query, trade) - .await - .map_err(Error::SimulationFailed)?; - - // Use `tx_origin` if response indicates that a special address is needed for - // the simulation to pass. Otherwise just use the solver address. - let solver_address = trade.tx_origin().unwrap_or(trade.solver()); - - let (tokens, clearing_prices) = match trade { - TradeKind::Legacy(_) => { - let tokens = vec![query.sell_token, query.buy_token]; - let prices = match query.kind { - OrderKind::Sell => vec![*out_amount, query.in_amount.get()], - OrderKind::Buy => vec![query.in_amount.get(), *out_amount], - }; - (tokens, prices) - } - TradeKind::Regular(trade) => trade - .clearing_prices - .iter() - .map(|(addr, value)| (addr.into_legacy(), value.into_legacy())) - .unzip(), - }; - - let settlement = encode_settlement( - query, - &verification, - trade, - &tokens, - &clearing_prices, - out_amount, - self.native_token, - &self.domain_separator, - self.settlement.address().into_legacy(), - )?; - let settlement = add_balance_queries(settlement, query, &verification, solver_address); - - let settle_call = legacy_settlement_to_alloy(settlement).abi_encode(); - let block = *self.block_stream.borrow(); - - let solver = Solver::Instance::new(solver_address, self.web3.alloy.clone()); - let swap_simulation = solver.swap( - *self.settlement.address(), - tokens.iter().cloned().map(IntoAlloy::into_alloy).collect(), - verification.receiver.into_alloy(), - settle_call.into(), - ) - // Initiate tx as solver so gas doesn't get deducted from user's ETH. - .from(solver_address) - .to(solver_address) - .gas(Self::DEFAULT_GAS) - .gas_price( - u128::try_from(block.gas_price) - .map_err(|err| anyhow!(err)) - .context("converting gas price to u128")? - ); - - if let Some(tenderly) = &self.simulator - && let Err(err) = tenderly.log_simulation_command( - swap_simulation.clone().into_transaction_request(), - overrides.clone(), - Some(block.number), - ) - { - tracing::debug!(?err, "could not log tenderly simulation command"); - } - - let output = swap_simulation - .call() - .overrides(overrides) - .await - .context("failed to simulate quote") - .map_err(Error::SimulationFailed); - - // TODO remove when quoters stop signing zeroex RFQ orders for `tx.origin: - // 0x0000` (#2693) - if let Err(err) = &output { - // Currently we know that if a trade requests to be simulated from `tx.origin: - // 0x0000` it's because the solver signs zeroex RFQ orders which - // require that origin. However, setting this `tx.origin` actually - // results in invalid RFQ orders and until the solver signs orders - // for a different `tx.origin` we need to pretend these - // quotes actually simulated successfully to not lose these competitive quotes - // when we enable quote verification in prod. - if trade.tx_origin() == Some(Address::ZERO) { - let estimate = Estimate { - out_amount: *out_amount, - gas: trade.gas_estimate().context("no gas estimate")?, - solver: trade.solver().into_legacy(), - verified: true, - execution: QuoteExecution { - interactions: map_interactions_data(&trade.interactions()), - pre_interactions: map_interactions_data(&trade.pre_interactions()), - jit_orders: trade.jit_orders(), - }, - }; - tracing::warn!( - ?estimate, - ?err, - "quote used invalid zeroex RFQ order; pass verification anyway" - ); - return Ok(estimate); - } - }; - - let mut summary = SettleOutput::from_swap(output?, query.kind, &tokens)?; - - { - // Quote accuracy gets determined by how many tokens had to be paid out of the - // settlement buffers to make the quote happen. When the settlement contract - // itself is the trader or receiver these values need to be adjusted slightly. - let (sell_amount, buy_amount) = match query.kind { - OrderKind::Sell => (query.in_amount.get(), summary.out_amount), - OrderKind::Buy => (summary.out_amount, query.in_amount.get()), - }; - - // It looks like the contract lost a lot of sell tokens but only because it was - // the trader and had to pay for the trade. Adjust tokens lost downward. - if verification.from == self.settlement.address().into_legacy() { - summary - .tokens_lost - .entry(query.sell_token) - .and_modify(|balance| *balance -= u256_to_big_rational(&sell_amount)); - } - // It looks like the contract gained a lot of buy tokens (negative loss) but - // only because it was the receiver and got the payout. Adjust the tokens lost - // upward. - if verification.receiver == self.settlement.address().into_legacy() { - summary - .tokens_lost - .entry(query.buy_token) - .and_modify(|balance| *balance += u256_to_big_rational(&buy_amount)); - } - } - - tracing::debug!( - tokens_lost = ?summary.tokens_lost, - gas_diff = ?trade.gas_estimate().unwrap_or_default().abs_diff(summary.gas_used.as_u64()), - time = ?start.elapsed(), - promised_out_amount = ?out_amount, - verified_out_amount = ?summary.out_amount, - promised_gas = trade.gas_estimate(), - verified_gas = ?summary.gas_used, - out_diff = ?out_amount.abs_diff(summary.out_amount), - ?query, - ?verification, - "verified quote", - ); - - ensure_quote_accuracy(&self.quote_inaccuracy_limit, query, trade, &summary) - } - - /// Configures all the state overrides that are needed to mock the given - /// trade. - async fn prepare_state_overrides( - &self, - verification: &mut Verification, - query: &PriceQuery, - trade: &TradeKind, - ) -> Result { - let mut overrides = HashMap::with_capacity(6); - - // Provide mocked balances if possible to the spardose to allow it to - // give some balances to the trader in order to verify trades even for - // owners without balances. Note that we use a separate account for - // funding to not interfere with the settlement process. This allows the - // simulation to conditionally transfer the balance only when it is - // safe to mock the trade pre-conditions on behalf of the user and to - // not alter solver balances which may be used during settlement. We use - // a similar strategy for determining whether or not to set approvals on - // behalf of the trader. - match self - .balance_overrides - .state_override(BalanceOverrideRequest { - token: query.sell_token, - holder: Self::SPARDOSE.into_legacy(), - amount: match query.kind { - OrderKind::Sell => query.in_amount.get(), - OrderKind::Buy => trade - .out_amount( - &query.buy_token.into_alloy(), - &query.sell_token.into_alloy(), - &query.in_amount.get().into_alloy(), - &query.kind, - )? - .into_legacy(), - }, - }) - .await - { - Some((token, solver_balance_override)) => { - tracing::trace!(?solver_balance_override, "solver balance override enabled"); - overrides.insert(token, solver_balance_override); - - if verification.from.is_zero() { - verification.from = H160::random(); - tracing::debug!( - trader = ?verification.from, - "use random trader address with fake balances" - ); - } - } - _ => { - if verification.from.is_zero() { - anyhow::bail!("trader is zero address and balances can not be faked"); - } - } - } - - // Set up mocked trader. - overrides.insert( - verification.from, - StateOverride { - code: Some(Trader::Trader::DEPLOYED_BYTECODE.clone().into_legacy()), - ..Default::default() - }, - ); - - // If the trader is a smart contract we also need to store its implementation - // to proxy into it during the simulation. - let trader_impl = self - .code_fetcher - .code(verification.from) - .await - .context("failed to fetch trader code")?; - if !trader_impl.0.is_empty() { - overrides.insert( - Self::TRADER_IMPL, - StateOverride { - code: Some(trader_impl), - ..Default::default() - }, - ); - } - - // Setup the funding contract override. Regardless of whether or not the - // contract has funds, it needs to exist in order to not revert - // simulations (Solidity reverts on attempts to call addresses without - // any code). - overrides.insert( - Self::SPARDOSE.into_legacy(), - StateOverride { - code: Some(Spardose::Spardose::DEPLOYED_BYTECODE.clone().into_legacy()), - ..Default::default() - }, - ); - - // Set up mocked solver. - let solver_override = StateOverride { - code: Some(Solver::Solver::DEPLOYED_BYTECODE.clone().into()), - // Allow solver simulations to proceed even if the real account holds no ETH. - balance: Some(U256::exp10(18)), - ..Default::default() - }; - - // If the trade requires a special tx.origin we also need to fake the - // authenticator. - if trade - .tx_origin() - .is_some_and(|origin| origin != trade.solver()) - { - let authenticator = self - .settlement - .authenticator() - .call() - .await - .context("could not fetch authenticator")?; - overrides.insert( - authenticator.into_legacy(), - StateOverride { - code: Some(web3::types::Bytes::from( - AnyoneAuthenticator::AnyoneAuthenticator::DEPLOYED_BYTECODE.to_vec(), - )), - ..Default::default() - }, - ); - } - overrides.insert( - trade.tx_origin().unwrap_or(trade.solver()).into_legacy(), - solver_override, - ); - - Ok(overrides.into_alloy()) - } -} - -fn legacy_settlement_to_alloy( - settlement: EncodedSettlement, -) -> GPv2Settlement::GPv2Settlement::settleCall { - GPv2Settlement::GPv2Settlement::settleCall { - tokens: settlement - .tokens - .into_iter() - .map(|t| t.into_alloy()) - .collect(), - clearingPrices: settlement - .clearing_prices - .into_iter() - .map(|p| p.into_alloy()) - .collect(), - interactions: settlement.interactions.map(|interactions| { - interactions - .into_iter() - .map(|i| GPv2Settlement::GPv2Interaction::Data { - target: i.0, - value: i.1, - callData: i.2.0.into(), - }) - .collect() - }), - trades: settlement - .trades - .into_iter() - .map(|t| GPv2Settlement::GPv2Trade::Data { - sellTokenIndex: t.0.into_alloy(), - buyTokenIndex: t.1.into_alloy(), - receiver: t.2.into_alloy(), - sellAmount: t.3.into_alloy(), - buyAmount: t.4.into_alloy(), - validTo: t.5, - appData: t.6.0.into(), - feeAmount: t.7.into_alloy(), - flags: t.8.into_alloy(), - executedAmount: t.9.into_alloy(), - signature: t.10.into_alloy(), - }) - .collect(), - } -} - -#[async_trait::async_trait] -impl TradeVerifying for TradeVerifier { - #[instrument(skip_all)] - async fn verify( - &self, - query: &PriceQuery, - verification: &Verification, - trade: TradeKind, - ) -> Result { - let out_amount = trade - .out_amount( - &query.buy_token.into_alloy(), - &query.sell_token.into_alloy(), - &query.in_amount.get().into_alloy(), - &query.kind, - ) - .context("failed to compute trade out amount")?; - - let unverified_result = trade - .gas_estimate() - .map(|gas| Estimate { - out_amount: out_amount.into_legacy(), - gas, - solver: trade.solver().into_legacy(), - verified: false, - execution: QuoteExecution { - interactions: map_interactions_data(&trade.interactions()), - pre_interactions: map_interactions_data(&trade.pre_interactions()), - jit_orders: trade.jit_orders(), - }, - }) - .context("solver provided no gas estimate"); - - let skip_verification = [&query.buy_token, &query.sell_token] - .iter() - .any(|token| self.tokens_without_verification.contains(token)); - if skip_verification { - tracing::debug!(estimate = ?unverified_result, "quote verification skipped"); - return unverified_result; - } - - match self - .verify_inner( - query, - verification.clone(), - &trade, - &out_amount.into_legacy(), - ) - .await - { - Ok(verified) => Ok(verified), - Err(Error::SimulationFailed(err)) => { - tracing::debug!(estimate = ?unverified_result, ?err, "quote verification failed"); - unverified_result - } - Err(err @ Error::TooInaccurate) => { - tracing::debug!("discarding quote because it's too inaccurate"); - Err(err.into()) - } - } - } -} - -fn encode_interactions(interactions: &[Interaction]) -> Vec { - interactions.iter().map(|i| i.encode()).collect() -} - -#[expect(clippy::too_many_arguments)] -fn encode_settlement( - query: &PriceQuery, - verification: &Verification, - trade: &TradeKind, - tokens: &[H160], - clearing_prices: &[U256], - out_amount: &U256, - native_token: H160, - domain_separator: &DomainSeparator, - settlement: H160, -) -> Result { - let mut trade_interactions = encode_interactions(&trade.interactions()); - if query.buy_token == BUY_ETH_ADDRESS { - // Because the `driver` manages `WETH` unwraps under the hood the `TradeFinder` - // does not have to emit unwraps to pay out `ETH` in a trade. - // However, for the simulation to be successful this has to happen so we do it - // ourselves here. - let buy_amount = match query.kind { - OrderKind::Sell => *out_amount, - OrderKind::Buy => query.in_amount.get(), - }; - trade_interactions.push(( - native_token.into_alloy(), - alloy::primitives::U256::ZERO, - WETH9::WETH9::withdrawCall { - wad: buy_amount.into_alloy(), - } - .abi_encode() - .into(), - )); - tracing::trace!("adding unwrap interaction for paying out ETH"); - } - - let fake_trade = encode_fake_trade(query, verification, out_amount, tokens)?; - let mut trades = vec![fake_trade]; - if let TradeKind::Regular(trade) = trade { - trades.extend(encode_jit_orders( - &trade.jit_orders, - tokens, - domain_separator, - )?); - } - - // Execute interaction to set up trade right before transfering funds. - // This interaction does nothing if the user-provided pre-interactions - // already set everything up (e.g. approvals, balances). That way we can - // correctly verify quotes with or without these user pre-interactions - // with helpful error messages. - let trade_setup_interaction = { - let sell_amount = match query.kind { - OrderKind::Sell => query.in_amount.get(), - OrderKind::Buy => *out_amount, - }; - let solver_address = trade.solver(); - let setup_call = Solver::Solver::ensureTradePreconditionsCall { - trader: verification.from.into_alloy(), - settlementContract: settlement.into_alloy(), - sellToken: query.sell_token.into_alloy(), - sellAmount: sell_amount.into_alloy(), - nativeToken: native_token.into_alloy(), - spardose: TradeVerifier::SPARDOSE, - } - .abi_encode(); - Interaction { - target: solver_address, - value: alloy::primitives::U256::ZERO, - data: setup_call, - } - }; - - let user_interactions = verification.pre_interactions.iter().cloned(); - let pre_interactions: Vec<_> = user_interactions - .chain(trade.pre_interactions()) - .chain([trade_setup_interaction]) - .collect(); - - Ok(EncodedSettlement { - tokens: tokens.to_vec(), - clearing_prices: clearing_prices.to_vec(), - trades, - interactions: [ - encode_interactions(&pre_interactions), - trade_interactions, - encode_interactions(&verification.post_interactions), - ], - }) -} - -fn encode_fake_trade( - query: &PriceQuery, - verification: &Verification, - out_amount: &U256, - tokens: &[H160], -) -> Result { - // Configure the most disadvantageous trade possible (while taking possible - // overflows into account). Should the trader not receive the amount promised by - // the [`Trade`] the simulation will still work and we can compute the actual - // [`Trade::out_amount`] afterwards. - let (sell_amount, buy_amount) = match query.kind { - OrderKind::Sell => (query.in_amount.get(), 0.into()), - OrderKind::Buy => ( - (*out_amount).max(U256::from(u128::MAX)), - query.in_amount.get(), - ), - }; - let fake_order = OrderData { - sell_token: query.sell_token.into_alloy(), - sell_amount: sell_amount.into_alloy(), - buy_token: query.buy_token.into_alloy(), - buy_amount: buy_amount.into_alloy(), - receiver: Some(verification.receiver.into_alloy()), - valid_to: u32::MAX, - app_data: Default::default(), - fee_amount: alloy::primitives::U256::ZERO, - kind: query.kind, - partially_fillable: false, - sell_token_balance: verification.sell_token_source, - buy_token_balance: verification.buy_token_destination, - }; - - let fake_signature = Signature::default_with(SigningScheme::Eip1271); - let encoded_trade = encode_trade( - &fake_order, - &fake_signature, - verification.from, - // the tokens set length is small so the linear search is acceptable - tokens - .iter() - .position(|token| token == &query.sell_token) - .context("missing sell token index")?, - tokens - .iter() - .position(|token| token == &query.buy_token) - .context("missing buy token index")?, - &query.in_amount.get(), - ); - - Ok(encoded_trade) -} - -fn encode_jit_orders( - jit_orders: &[dto::JitOrder], - tokens: &[H160], - domain_separator: &DomainSeparator, -) -> Result, Error> { - jit_orders - .iter() - .map(|jit_order| { - let order_data = OrderData { - sell_token: jit_order.sell_token.into_alloy(), - buy_token: jit_order.buy_token.into_alloy(), - receiver: Some(jit_order.receiver.into_alloy()), - sell_amount: jit_order.sell_amount.into_alloy(), - buy_amount: jit_order.buy_amount.into_alloy(), - valid_to: jit_order.valid_to, - app_data: jit_order.app_data, - fee_amount: alloy::primitives::U256::ZERO, - kind: match &jit_order.side { - dto::Side::Buy => OrderKind::Buy, - dto::Side::Sell => OrderKind::Sell, - }, - partially_fillable: jit_order.partially_fillable, - sell_token_balance: jit_order.sell_token_source, - buy_token_balance: jit_order.buy_token_destination, - }; - let (owner, signature) = - recover_jit_order_owner(jit_order, &order_data, domain_separator)?; - - Ok(encode_trade( - &order_data, - &signature, - owner, - // the tokens set length is small so the linear search is acceptable - tokens - .iter() - .position(|token| token == &jit_order.sell_token) - .context("missing jit order sell token index")?, - tokens - .iter() - .position(|token| token == &jit_order.buy_token) - .context("missing jit order buy token index")?, - &jit_order.executed_amount, - )) - }) - .collect::, Error>>() -} - -/// Recovers the owner and signature from a `JitOrder`. -fn recover_jit_order_owner( - jit_order: &JitOrder, - order_data: &OrderData, - domain_separator: &DomainSeparator, -) -> Result<(H160, Signature), Error> { - let (owner, signature) = match jit_order.signing_scheme { - SigningScheme::Eip1271 => { - let (owner, signature) = jit_order.signature.split_at(20); - let owner = H160::from_slice(owner); - let signature = Signature::from_bytes(jit_order.signing_scheme, signature)?; - (owner, signature) - } - SigningScheme::PreSign => { - let owner = H160::from_slice(&jit_order.signature); - let signature = Signature::from_bytes(jit_order.signing_scheme, Vec::new().as_slice())?; - (owner, signature) - } - _ => { - let signature = Signature::from_bytes(jit_order.signing_scheme, &jit_order.signature)?; - let owner = signature - .recover(domain_separator, &order_data.hash_struct())? - .context("could not recover the owner")? - .signer; - (owner, signature) - } - }; - Ok((owner, signature)) -} - -/// Adds the interactions that are only needed to query important balances -/// throughout the simulation. -/// These balances will get used to compute an accurate price for the trade. -fn add_balance_queries( - mut settlement: EncodedSettlement, - query: &PriceQuery, - verification: &Verification, - solver_address: Address, -) -> EncodedSettlement { - let (token, owner) = match query.kind { - // track how much `buy_token` the `receiver` actually got - OrderKind::Sell => { - let receiver = match verification.receiver == H160::zero() { - // Settlement contract sends fund to owner if receiver is the 0 address. - true => verification.from, - false => verification.receiver, - }; - - (query.buy_token, receiver) - } - // track how much `sell_token` the `from` address actually spent - OrderKind::Buy => (query.sell_token, verification.from), - }; - let query_balance_call = Solver::Solver::storeBalanceCall { - token: token.into_alloy(), - owner: owner.into_alloy(), - countGas: true, - } - .abi_encode(); - - let interaction = ( - solver_address, - alloy::primitives::U256::ZERO, - query_balance_call.into(), - ); - // query balance query at the end of pre-interactions - settlement.interactions[0].push(interaction.clone()); - // query balance right after we payed out all `buy_token` - settlement.interactions[2].insert(0, interaction); - settlement -} - -/// Analyzed output of `Solver::settle` smart contract call. -#[derive(Debug)] -struct SettleOutput { - /// Gas used for the `settle()` call. - gas_used: U256, - /// `out_amount` perceived by the trader (sell token for buy orders or buy - /// token for sell order) - out_amount: U256, - /// Tokens difference of the settlement contract before and after the trade. - tokens_lost: HashMap, -} - -impl SettleOutput { - fn from_swap( - Solver::Solver::swapReturn { - gasUsed, - queriedBalances, - }: Solver::Solver::swapReturn, - kind: OrderKind, - tokens_vec: &[H160], - ) -> Result { - // The balances are stored in the following order: - // [...tokens_before, user_balance_before, user_balance_after, ...tokens_after] - let mut i = 0; - let mut tokens_lost = HashMap::new(); - // Get settlement contract balances before the trade - for token in tokens_vec.iter() { - // TODO: add alloy support to the numeric functions - let balance_before = u256_to_big_rational(&queriedBalances[i].into_legacy()); - tokens_lost.insert(*token, balance_before); - i += 1; - } - - let trader_balance_before = queriedBalances[i]; - let trader_balance_after = queriedBalances[i + 1]; - i += 2; - - // Get settlement contract balances after the trade - for token in tokens_vec.iter() { - let balance_after = u256_to_big_rational(&queriedBalances[i].into_legacy()); - tokens_lost - .entry(*token) - .and_modify(|balance_before| *balance_before -= balance_after); - i += 1; - } - - let out_amount = match kind { - // for sell orders we track the buy_token amount which increases during the settlement - OrderKind::Sell => trader_balance_after.checked_sub(trader_balance_before), - // for buy orders we track the sell_token amount which decreases during the settlement - OrderKind::Buy => trader_balance_before.checked_sub(trader_balance_after), - }; - let out_amount = out_amount.context("underflow during out_amount computation")?; - - Ok(SettleOutput { - gas_used: gasUsed.into_legacy(), - out_amount: out_amount.into_legacy(), - tokens_lost, - }) - } -} - -/// Returns an error if settling the quote would require using too much of the -/// settlement contract buffers. -fn ensure_quote_accuracy( - inaccuracy_limit: &BigRational, - query: &PriceQuery, - trade: &TradeKind, - summary: &SettleOutput, -) -> std::result::Result { - // amounts verified by the simulation - let (sell_amount, buy_amount) = match query.kind { - OrderKind::Buy => (summary.out_amount, query.in_amount.get()), - OrderKind::Sell => (query.in_amount.get(), summary.out_amount), - }; - let (sell_amount, buy_amount) = ( - u256_to_big_rational(&sell_amount), - u256_to_big_rational(&buy_amount), - ); - let sell_token_lost_limit = inaccuracy_limit * &sell_amount; - let buy_token_lost_limit = inaccuracy_limit * &buy_amount; - - let sell_token_lost = summary - .tokens_lost - .get(&query.sell_token) - .context("summary sell token is missing")?; - let buy_token_lost = summary - .tokens_lost - .get(&query.buy_token) - .context("summary buy token is missing")?; - - if *sell_token_lost >= sell_token_lost_limit || *buy_token_lost >= buy_token_lost_limit { - return Err(Error::TooInaccurate); - } - - Ok(Estimate { - out_amount: summary.out_amount, - gas: summary.gas_used.as_u64(), - solver: trade.solver().into_legacy(), - verified: true, - execution: QuoteExecution { - interactions: map_interactions_data(&trade.interactions()), - pre_interactions: map_interactions_data(&trade.pre_interactions()), - jit_orders: trade.jit_orders(), - }, - }) -} - -#[derive(Debug)] -pub struct PriceQuery { - pub sell_token: H160, - // This should be `BUY_ETH_ADDRESS` if you actually want to trade `ETH` - pub buy_token: H160, - pub kind: OrderKind, - pub in_amount: NonZeroU256, -} - -#[derive(thiserror::Error, Debug)] -enum Error { - /// Verification logic ran successfully but the quote was deemed too - /// inaccurate to be usable. - #[error("too inaccurate")] - TooInaccurate, - /// Some error caused the simulation to not finish successfully. - #[error("quote could not be simulated")] - SimulationFailed(#[from] anyhow::Error), -} - -#[cfg(test)] -mod tests { - use {super::*, maplit::hashmap, std::str::FromStr}; - - #[test] - fn discards_inaccurate_quotes() { - // let's use 0.5 as the base case to avoid rounding issues introduced by float - // conversion - let low_threshold = big_decimal_to_big_rational(&BigDecimal::from_str("0.5").unwrap()); - let high_threshold = big_decimal_to_big_rational(&BigDecimal::from_str("0.51").unwrap()); - - let sell_token = H160([1u8; 20]); - let buy_token = H160([2u8; 20]); - - let query = PriceQuery { - in_amount: 1_000.try_into().unwrap(), - kind: OrderKind::Sell, - sell_token, - buy_token, - }; - - // buy token is lost - let tokens_lost = hashmap! { - sell_token => BigRational::from_integer(500.into()), - }; - let summary = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), - tokens_lost, - }; - let estimate = - ensure_quote_accuracy(&low_threshold, &query, &TradeKind::default(), &summary); - assert!(matches!(estimate, Err(Error::SimulationFailed(_)))); - - // sell token is lost - let tokens_lost = hashmap! { - buy_token => BigRational::from_integer(0.into()), - }; - let summary = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), - tokens_lost, - }; - - let estimate = - ensure_quote_accuracy(&low_threshold, &query, &TradeKind::default(), &summary); - assert!(matches!(estimate, Err(Error::SimulationFailed(_)))); - - // everything is in-place - let tokens_lost = hashmap! { - sell_token => BigRational::from_integer(400.into()), - buy_token => BigRational::from_integer(0.into()), - }; - let summary = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), - tokens_lost, - }; - let estimate = - ensure_quote_accuracy(&low_threshold, &query, &TradeKind::default(), &summary); - assert!(estimate.is_ok()); - - let tokens_lost = hashmap! { - sell_token => BigRational::from_integer(500.into()), - buy_token => BigRational::from_integer(0.into()), - }; - - let sell_more = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), - tokens_lost, - }; - - let estimate = - ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &sell_more); - assert!(matches!(estimate, Err(Error::TooInaccurate))); - - // passes with slightly higher tolerance - let estimate = - ensure_quote_accuracy(&high_threshold, &query, &Default::default(), &sell_more); - assert!(estimate.is_ok()); - - let tokens_lost = hashmap! { - sell_token => BigRational::from_integer(0.into()), - buy_token => BigRational::from_integer(1_000.into()), - }; - - let pay_out_more = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), - tokens_lost, - }; - - let estimate = - ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &pay_out_more); - assert!(matches!(estimate, Err(Error::TooInaccurate))); - - // passes with slightly higher tolerance - let estimate = - ensure_quote_accuracy(&high_threshold, &query, &Default::default(), &pay_out_more); - assert!(estimate.is_ok()); - - let tokens_lost = hashmap! { - sell_token => BigRational::from_integer((-500).into()), - buy_token => BigRational::from_integer(0.into()), - }; - - let sell_less = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), - tokens_lost, - }; - // Ending up with surplus in the buffers is always fine - let estimate = - ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &sell_less); - assert!(estimate.is_ok()); - - let tokens_lost = hashmap! { - sell_token => BigRational::from_integer(0.into()), - buy_token => BigRational::from_integer((-1_000).into()), - }; - - let pay_out_less = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), - tokens_lost, - }; - // Ending up with surplus in the buffers is always fine - let estimate = - ensure_quote_accuracy(&low_threshold, &query, &Default::default(), &pay_out_less); - assert!(estimate.is_ok()); - } -} diff --git a/crates/shared/src/remaining_amounts.rs b/crates/shared/src/remaining_amounts.rs index e62480bd55..2d51b67359 100644 --- a/crates/shared/src/remaining_amounts.rs +++ b/crates/shared/src/remaining_amounts.rs @@ -1,11 +1,12 @@ use { + alloy::primitives::U256, anyhow::{Context, Result}, - ethrpc::alloy::conversions::IntoLegacy, model::order::{Order as ModelOrder, OrderKind}, - num::rational::Ratio, - primitive_types::U256, + number::{conversions::big_uint_to_u256, ratio_ext::RatioExt}, }; +type Ratio = num::rational::Ratio; + /// Calculates the remaining amounts for an order. /// /// For example, when a sell order has half of its sell amount already executed @@ -19,7 +20,7 @@ pub struct Remaining { /// 75, this ratio will be `25/100`. /// /// This is always `0/1` or `1/1` for fill or kill orders. - execution: Ratio, + execution: Ratio, /// The ratio of a order that is available based on user balance. That is, /// if a partially fillable order selling 90 DAI with a fee of 10 DAI where @@ -34,45 +35,7 @@ pub struct Remaining { /// not concern itself with overflows WRT to user balances, so we compute /// remaining order amount from user balances separately and without /// overflow checks in the intermediate operations. - balance: Ratio, -} - -pub struct Order { - pub kind: OrderKind, - pub buy_amount: U256, - pub sell_amount: U256, - pub fee_amount: U256, - // For a buy order this is in the buy token and for a sell order in the sell token and - // excluding the fee amount. - pub executed_amount: U256, - pub partially_fillable: bool, -} - -impl From<&ModelOrder> for Order { - fn from(o: &ModelOrder) -> Self { - Self { - kind: o.data.kind, - buy_amount: o.data.buy_amount.into_legacy(), - sell_amount: o.data.sell_amount.into_legacy(), - fee_amount: o.data.fee_amount.into_legacy(), - executed_amount: match o.data.kind { - // A real buy order cannot execute more than U256::MAX so in order to make this - // function infallible we treat a larger amount as a full execution. - OrderKind::Buy => { - number::conversions::big_uint_to_u256(&o.metadata.executed_buy_amount) - .unwrap_or(o.data.buy_amount.into_legacy()) - } - OrderKind::Sell => o.metadata.executed_sell_amount_before_fees, - }, - partially_fillable: o.data.partially_fillable, - } - } -} - -impl From for Order { - fn from(o: ModelOrder) -> Self { - (&o).into() - } + balance: Ratio, } impl Remaining { @@ -96,9 +59,11 @@ impl Remaining { total, ); - let sell_amount = ratio::scalar_mul(&execution, order.sell_amount) + let sell_amount = execution + .scalar_mul(order.sell_amount) .context("overflow scaling sell amount for execution")?; - let fee_amount = ratio::scalar_mul(&execution, order.fee_amount) + let fee_amount = execution + .scalar_mul(order.fee_amount) .context("overflow scaling fee amount for execution")?; let need = sell_amount @@ -108,7 +73,7 @@ impl Remaining { let balance = if sell_balance < need { Ratio::new_raw(sell_balance, need) } else { - ratio::one() + Ratio::ONE }; Ok(Self { execution, balance }) @@ -119,15 +84,15 @@ impl Remaining { .context("overflow sell + fee amount")?; let execution = if order.executed_amount.is_zero() { - ratio::one() + Ratio::ONE } else { - ratio::zero() + Ratio::ZERO }; let balance = if sell_balance >= sell { - ratio::one() + Ratio::ONE } else { - ratio::zero() + Ratio::ZERO }; Ok(Self { execution, balance }) @@ -136,43 +101,50 @@ impl Remaining { /// Returns Err if the contract would error due to intermediate overflow. pub fn remaining(&self, total: U256) -> Result { - ratio::full_scalar_mul( - &self.balance, - ratio::scalar_mul(&self.execution, total) - .context("overflow scaling for order execution")?, - ) - .context("overflow scaling for available balance") + let order_execution = self + .execution + .scalar_mul(total) + .context("overflow scaling for order execution")?; + self.balance + .full_scalar_mul(order_execution) + .context("overflow scaling for available balance") } } -mod ratio { - use {ethcontract::U256, num::rational::Ratio}; - - pub fn one() -> Ratio { - Ratio::new_raw(1.into(), 1.into()) - } - - pub fn zero() -> Ratio { - Ratio::new_raw(0.into(), 1.into()) - } +pub struct Order { + pub kind: OrderKind, + pub buy_amount: U256, + pub sell_amount: U256, + pub fee_amount: U256, + // For a buy order this is in the buy token and for a sell order in the sell token and + // excluding the fee amount. + pub executed_amount: U256, + pub partially_fillable: bool, +} - /// Multiplies a ratio by a scalar, returning `None` if the result or any - /// intermediate operation would overflow a `U256`. - pub fn scalar_mul(ratio: &Ratio, scalar: U256) -> Option { - scalar - .checked_mul(*ratio.numer())? - .checked_div(*ratio.denom()) +impl From<&ModelOrder> for Order { + fn from(o: &ModelOrder) -> Self { + Self { + kind: o.data.kind, + buy_amount: o.data.buy_amount, + sell_amount: o.data.sell_amount, + fee_amount: o.data.fee_amount, + executed_amount: match o.data.kind { + // A real buy order cannot execute more than U256::MAX so in order to make this + // function infallible we treat a larger amount as a full execution. + OrderKind::Buy => { + big_uint_to_u256(&o.metadata.executed_buy_amount).unwrap_or(o.data.buy_amount) + } + OrderKind::Sell => o.metadata.executed_sell_amount_before_fees, + }, + partially_fillable: o.data.partially_fillable, + } } +} - /// Multiplies a ratio by a scalar, returning `None` only if the result - /// would overflow a `U256`, but intermediate operations are allowed to - /// overflow. - pub fn full_scalar_mul(ratio: &Ratio, scalar: U256) -> Option { - scalar - .full_mul(*ratio.numer()) - .checked_div(ratio.denom().into())? - .try_into() - .ok() +impl From for Order { + fn from(o: ModelOrder) -> Self { + (&o).into() } } @@ -201,7 +173,10 @@ mod tests { } .into(); let remaining = Remaining::from_order(&order).unwrap(); - assert_eq!(remaining.remaining(1000.into()).unwrap(), 1000.into()); + assert_eq!( + remaining.remaining(U256::from(1000)).unwrap(), + U256::from(1000) + ); assert_eq!(remaining.remaining(U256::MAX).unwrap(), U256::MAX); // For partially fillable orders that are untouched, returns the full @@ -216,15 +191,15 @@ mod tests { ..Default::default() }, metadata: OrderMetadata { - executed_sell_amount_before_fees: 0.into(), + executed_sell_amount_before_fees: U256::ZERO, ..Default::default() }, ..Default::default() } .into(); let remaining = Remaining::from_order(&order).unwrap(); - assert_eq!(remaining.remaining(10.into()).unwrap(), 10.into()); - assert_eq!(remaining.remaining(13.into()).unwrap(), 13.into()); + assert_eq!(remaining.remaining(U256::from(10)).unwrap(), U256::from(10)); + assert_eq!(remaining.remaining(U256::from(13)).unwrap(), U256::from(13)); // Scales amounts by how much has been executed. Rounds down like the // settlement contract. @@ -238,16 +213,25 @@ mod tests { ..Default::default() }, metadata: OrderMetadata { - executed_sell_amount_before_fees: 90.into(), + executed_sell_amount_before_fees: U256::from(90), ..Default::default() }, ..Default::default() } .into(); let remaining = Remaining::from_order(&order).unwrap(); - assert_eq!(remaining.remaining(100.into()).unwrap(), 10.into()); - assert_eq!(remaining.remaining(101.into()).unwrap(), 10.into()); - assert_eq!(remaining.remaining(200.into()).unwrap(), 20.into()); + assert_eq!( + remaining.remaining(U256::from(100)).unwrap(), + U256::from(10) + ); + assert_eq!( + remaining.remaining(U256::from(101)).unwrap(), + U256::from(10) + ); + assert_eq!( + remaining.remaining(U256::from(200)).unwrap(), + U256::from(20) + ); let order = ModelOrder { data: OrderData { @@ -266,10 +250,19 @@ mod tests { } .into(); let remaining = Remaining::from_order(&order).unwrap(); - assert_eq!(remaining.remaining(100.into()).unwrap(), 10.into()); - assert_eq!(remaining.remaining(10.into()).unwrap(), 1.into()); - assert_eq!(remaining.remaining(101.into()).unwrap(), 10.into()); - assert_eq!(remaining.remaining(200.into()).unwrap(), 20.into()); + assert_eq!( + remaining.remaining(U256::from(100)).unwrap(), + U256::from(10) + ); + assert_eq!(remaining.remaining(U256::from(10)).unwrap(), U256::ONE); + assert_eq!( + remaining.remaining(U256::from(101)).unwrap(), + U256::from(10) + ); + assert_eq!( + remaining.remaining(U256::from(200)).unwrap(), + U256::from(20) + ); } #[test] @@ -315,7 +308,7 @@ mod tests { ..Default::default() }, metadata: OrderMetadata { - executed_sell_amount_before_fees: 2.into(), + executed_sell_amount_before_fees: U256::from(2), ..Default::default() }, ..Default::default() @@ -353,8 +346,9 @@ mod tests { ..Default::default() } .into(); - let remaining = Remaining::from_order_with_balance(&order, order.sell_amount - 1).unwrap(); - assert_eq!(remaining.remaining(1000.into()).unwrap(), 0.into()); + let remaining = + Remaining::from_order_with_balance(&order, order.sell_amount - U256::ONE).unwrap(); + assert!(remaining.remaining(U256::from(1000)).unwrap().is_zero()); // A partially fillable order that has not been executed at all scales // to the available balance. @@ -372,28 +366,34 @@ mod tests { .into(); { // More than enough balance for the full order. - let remaining = Remaining::from_order_with_balance(&order, 5000.into()).unwrap(); - assert_eq!(remaining.remaining(800.into()).unwrap(), 800.into()); + let remaining = Remaining::from_order_with_balance(&order, U256::from(5000)).unwrap(); + assert_eq!( + remaining.remaining(U256::from(800)).unwrap(), + U256::from(800) + ); } { // Not enough balance for the full order. - let remaining = Remaining::from_order_with_balance(&order, 500.into()).unwrap(); - assert_eq!(remaining.remaining(800.into()).unwrap(), 400.into()); + let remaining = Remaining::from_order_with_balance(&order, U256::from(500)).unwrap(); + assert_eq!( + remaining.remaining(U256::from(800)).unwrap(), + U256::from(400) + ); } // A partially fillable order that has has been partially executed scales // to the remaining execution and available balance. let order = ModelOrder { data: OrderData { - sell_amount: alloy::primitives::U256::from(800), - buy_amount: alloy::primitives::U256::from(2000), - fee_amount: alloy::primitives::U256::from(200), + sell_amount: U256::from(800), + buy_amount: U256::from(2000), + fee_amount: U256::from(200), kind: OrderKind::Sell, partially_fillable: true, ..Default::default() }, metadata: OrderMetadata { - executed_sell_amount_before_fees: 400.into(), + executed_sell_amount_before_fees: U256::from(400), ..Default::default() }, ..Default::default() @@ -401,13 +401,19 @@ mod tests { .into(); { // More than enough balance for the full order. - let remaining = Remaining::from_order_with_balance(&order, 5000.into()).unwrap(); - assert_eq!(remaining.remaining(800.into()).unwrap(), 400.into()); + let remaining = Remaining::from_order_with_balance(&order, U256::from(5000)).unwrap(); + assert_eq!( + remaining.remaining(U256::from(800)).unwrap(), + U256::from(400) + ); } { // Not enough balance for the full order. - let remaining = Remaining::from_order_with_balance(&order, 250.into()).unwrap(); - assert_eq!(remaining.remaining(800.into()).unwrap(), 200.into()); + let remaining = Remaining::from_order_with_balance(&order, U256::from(250)).unwrap(); + assert_eq!( + remaining.remaining(U256::from(800)).unwrap(), + U256::from(200) + ); } } @@ -415,9 +421,8 @@ mod tests { fn support_scaling_for_large_orders_with_partial_balance() { let order: Order = ModelOrder { data: OrderData { - sell_amount: alloy::primitives::U256::from(10) - .pow(alloy::primitives::U256::from(30)), - buy_amount: alloy::primitives::U256::ONE, + sell_amount: U256::from(10).pow(U256::from(30)), + buy_amount: U256::ONE, kind: OrderKind::Sell, partially_fillable: true, ..Default::default() @@ -425,7 +430,7 @@ mod tests { ..Default::default() } .into(); - let balance = order.sell_amount - 1; + let balance = order.sell_amount - U256::ONE; // Note that we need to scale because of remaining balance, and that // we would overflow with these numbers: diff --git a/crates/shared/src/retry.rs b/crates/shared/src/retry.rs new file mode 100644 index 0000000000..9cc603002d --- /dev/null +++ b/crates/shared/src/retry.rs @@ -0,0 +1,43 @@ +use { + rand::Rng, + std::{future::Future, time::Duration}, +}; + +const MAX_RETRIES: usize = 5; + +/// Retry on every error. +pub async fn retry_with_sleep(future: impl Fn() -> F) -> Result> +where + F: Future>, + E: std::fmt::Debug, +{ + retry_with_sleep_if(future, |_| true).await +} + +/// Retry only when `should_retry(&err)` returns true. +pub async fn retry_with_sleep_if( + future: impl Fn() -> F, + should_retry: P, +) -> Result> +where + F: Future>, + E: std::fmt::Debug, + P: Fn(&E) -> bool, +{ + let mut errors = Vec::new(); + for attempt in 1..=MAX_RETRIES { + match future().await { + Ok(value) => return Ok(value), + Err(err) => { + let retryable = should_retry(&err); + errors.push(err); + if !retryable || attempt == MAX_RETRIES { + return Err(errors); + } + let timeout_with_jitter = 50u64 + rand::rng().random_range(0..=50); + tokio::time::sleep(Duration::from_millis(timeout_with_jitter)).await; + } + } + } + Err(errors) +} diff --git a/crates/shared/src/sources/uniswap_v3/mod.rs b/crates/shared/src/sources/uniswap_v3/mod.rs deleted file mode 100644 index 6e90557757..0000000000 --- a/crates/shared/src/sources/uniswap_v3/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Uniswap V3 baseline liquidity source implementation. -pub mod event_fetching; -pub mod graph_api; -pub mod pool_fetching; diff --git a/crates/shared/src/submitter_constants.rs b/crates/shared/src/submitter_constants.rs deleted file mode 100644 index ec3848a207..0000000000 --- a/crates/shared/src/submitter_constants.rs +++ /dev/null @@ -1,16 +0,0 @@ -/// Error messages which suggest that the node is already aware of the submitted -/// tx thus prompting us to increase the replacement gas price. -pub const TX_ALREADY_KNOWN: &[&str] = &[ - "Transaction gas price supplied is too low", //openethereum - "already known", //infura, erigon, eden - "INTERNAL_ERROR: existing tx with same hash", //erigon - "replacement transaction underpriced", //eden -]; - -/// Error messages suggesting that the transaction we tried to submit has -/// already been mined because its nonce is suddenly too low. -pub const TX_ALREADY_MINED: &[&str] = &[ - "Transaction nonce is too low", //openethereum - "nonce too low", //infura, erigon - "OldNonce", //erigon -]; diff --git a/crates/shared/src/tenderly_api.rs b/crates/shared/src/tenderly_api.rs deleted file mode 100644 index aec7db7e9b..0000000000 --- a/crates/shared/src/tenderly_api.rs +++ /dev/null @@ -1,511 +0,0 @@ -//! Module containing Tenderly API implementation. - -use { - crate::{ - arguments::{display_option, display_secret_option}, - http_client::HttpClientFactory, - }, - alloy::{ - primitives::TxKind, - rpc::types::{TransactionRequest, state::StateOverride as AlloyStateOverride}, - }, - anyhow::{Result, ensure}, - bytes_hex::BytesHex, - clap::Parser, - contracts::errors::EthcontractErrorType, - ethcontract::{errors::ExecutionError, state_overrides::StateOverride}, - ethrpc::alloy::conversions::IntoLegacy, - prometheus::IntGaugeVec, - reqwest::{ - Url, - header::{HeaderMap, HeaderValue}, - }, - serde::{Deserialize, Serialize}, - std::{ - collections::HashMap, - fmt::{self, Display, Formatter}, - sync::Arc, - }, - thiserror::Error, - tracing::instrument, - web3::types::{Bytes, H160, H256, U256}, -}; -/// Trait for abstracting Tenderly API. -#[async_trait::async_trait] -pub trait TenderlyApi: Send + Sync + 'static { - async fn simulate(&self, simulation: SimulationRequest) -> Result; - fn log(&self, simulation: SimulationRequest) -> Result<()>; - fn simulation_url(&self, id: &str) -> Url; -} - -const API_URL: &str = "https://api.tenderly.co"; -const DASHBOARD_URL: &str = "https://dashboard.tenderly.co"; - -/// Tenderly HTTP API. -pub struct TenderlyHttpApi { - api: Url, - dashboard: Url, - client: reqwest::Client, -} - -impl TenderlyHttpApi { - /// Creates a new Tenderly API - pub fn new( - http_factory: &HttpClientFactory, - user: &str, - project: &str, - api_key: &str, - ) -> Result { - let mut api_key = HeaderValue::from_str(api_key)?; - api_key.set_sensitive(true); - - let mut headers = HeaderMap::new(); - headers.insert("x-access-key", api_key); - - Ok(Self { - api: Url::parse(&format!( - "{API_URL}/api/v1/account/{user}/project/{project}/" - ))?, - dashboard: Url::parse(&format!("{DASHBOARD_URL}/{user}/{project}/"))?, - client: http_factory.configure(|builder| builder.default_headers(headers)), - }) - } - - /// Creates a Tenderly API from the environment for testing. - pub fn test_from_env() -> Arc { - Arc::new( - Self::new( - &HttpClientFactory::default(), - &std::env::var("TENDERLY_USER").unwrap(), - &std::env::var("TENDERLY_PROJECT").unwrap(), - &std::env::var("TENDERLY_API_KEY").unwrap(), - ) - .unwrap(), - ) - } -} - -#[async_trait::async_trait] -impl TenderlyApi for TenderlyHttpApi { - #[instrument(skip_all)] - async fn simulate(&self, simulation: SimulationRequest) -> Result { - let url = crate::url::join(&self.api, "simulate"); - let body = serde_json::to_string(&simulation)?; - - let response = self - .client - .post(url) - .header("content-type", "application/json") - .body(body) - .send() - .await?; - - let ok = response.error_for_status_ref().map(|_| ()); - let status = response.status(); - let body = response.text().await?; - // NOTE: Turn these logs on at your own risk... The Tenderly response - // objects are huge (order of ~3M). - tracing::trace!(status =% status.as_u16(), %body, "simulated"); - - ok?; - Ok(serde_json::from_str(&body)?) - } - - fn log(&self, simulation: SimulationRequest) -> Result<()> { - let request_url = crate::url::join(&self.api, "simulate"); - let simulation_url = - crate::url::join(&self.dashboard, "simulator/$SIMULATION_ID").to_string(); - let body = serde_json::to_string(&simulation)?; - - #[rustfmt::skip] - tracing::debug!( - "resimulate by setting TENDERLY_API_KEY environment variable and running: \ - curl -X POST -H \"X-ACCESS-KEY: $TENDERLY_API_KEY\" -H \"Content-Type: application/json\" --data '{body}' {request_url} \ - | jq -r \".simulation.id\" \ - | read SIMULATION_ID; \ - echo {simulation_url} \ - | xargs xdg-open", - ); - - Ok(()) - } - - fn simulation_url(&self, id: &str) -> Url { - crate::url::join(&self.dashboard, &format!("simulator/{id}")) - } -} - -/// Instrumented Tenderly HTTP API. -pub struct Instrumented { - inner: TenderlyHttpApi, - name: String, -} - -#[async_trait::async_trait] -impl TenderlyApi for Instrumented { - async fn simulate(&self, simulation: SimulationRequest) -> Result { - let result = self.inner.simulate(simulation).await; - - Metrics::get() - .tenderly_simulations - .with_label_values(&[ - &self.name, - match &result { - Ok(_) => "ok", - Err(_) => "err", - }, - ]) - .inc(); - - result - } - - fn log(&self, simulation: SimulationRequest) -> Result<()> { - self.inner.log(simulation) - } - - fn simulation_url(&self, id: &str) -> Url { - self.inner.simulation_url(id) - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -pub struct SimulationRequest { - pub network_id: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub block_number: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub transaction_index: Option, - pub from: H160, - pub to: H160, - #[serde(with = "bytes_hex")] - pub input: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub gas: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub gas_price: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub value: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub simulation_kind: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub save: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub save_if_fails: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub generate_access_list: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub state_objects: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub access_list: Option>, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum SimulationKind { - Full, - Quick, -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] -pub struct StateObject { - /// Fake balance to set for the account before executing the call. - #[serde(skip_serializing_if = "Option::is_none")] - pub balance: Option, - - /// Fake EVM bytecode to inject into the account before executing the call. - #[serde(skip_serializing_if = "Option::is_none")] - pub code: Option, - - /// Fake key-value mapping to override **individual** slots in the account - /// storage before executing the call. - #[serde(skip_serializing_if = "Option::is_none")] - pub storage: Option>, -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -pub struct SimulationResponse { - pub transaction: Transaction, - pub generated_access_list: Option>, - pub simulation: Simulation, -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -pub struct Transaction { - pub status: bool, - pub gas_used: u64, - pub call_trace: Vec, -} - -#[serde_with::serde_as] -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -pub struct CallTrace { - #[serde(default)] - #[serde_as(as = "Option")] - pub output: Option>, - pub error: Option, -} - -// Had to introduce copy of the web3 AccessList because tenderly responds with -// snake_case fields and tenderly storage_keys field does not exist if empty (it -// should be empty Vec instead) -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -pub struct AccessListItem { - /// Accessed address - pub address: H160, - /// Accessed storage keys - #[serde(default)] - pub storage_keys: Vec, -} - -impl From for web3::types::AccessListItem { - fn from(item: AccessListItem) -> Self { - Self { - address: item.address, - storage_keys: item.storage_keys, - } - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -pub struct Simulation { - pub id: String, -} - -/// Tenderly API arguments. -#[derive(Debug, Parser)] -#[group(skip)] -pub struct Arguments { - /// The Tenderly user associated with the API key. - #[clap(long, env)] - pub tenderly_user: Option, - - /// The Tenderly project associated with the API key. - #[clap(long, env)] - pub tenderly_project: Option, - - /// Tenderly requires api key to work. Optional since Tenderly could be - /// skipped in access lists estimators. - #[clap(long, env)] - pub tenderly_api_key: Option, -} - -impl Arguments { - pub fn get_api_instance( - &self, - http_factory: &HttpClientFactory, - name: String, - ) -> Result>> { - Some(()) - .and_then(|_| { - Some( - TenderlyHttpApi::new( - http_factory, - self.tenderly_user.as_deref()?, - self.tenderly_project.as_deref()?, - self.tenderly_api_key.as_deref()?, - ) - .map(|inner| Arc::new(Instrumented { inner, name }) as _), - ) - }) - .transpose() - } -} - -impl Display for Arguments { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Self { - tenderly_user, - tenderly_project, - tenderly_api_key, - } = self; - - display_option(f, "tenderly_user", tenderly_user)?; - display_option(f, "tenderly_project", tenderly_project)?; - display_secret_option(f, "tenderly_api_key", tenderly_api_key.as_ref())?; - - Ok(()) - } -} - -#[derive(prometheus_metric_storage::MetricStorage)] -struct Metrics { - /// Tenderly simulations. - #[metric(labels("name", "result"))] - tenderly_simulations: IntGaugeVec, -} - -impl Metrics { - fn get() -> &'static Metrics { - Metrics::instance(observe::metrics::get_storage_registry()).unwrap() - } -} - -#[derive(Debug, Error)] -pub enum SimulationError { - #[error("simulation reverted {0:?}")] - Revert(Option), - #[error(transparent)] - Other(#[from] anyhow::Error), -} - -impl Clone for SimulationError { - fn clone(&self) -> Self { - match self { - Self::Revert(message) => Self::Revert(message.clone()), - Self::Other(err) => Self::Other(crate::clone_anyhow_error(err)), - } - } -} - -impl From for SimulationError { - fn from(err: web3::Error) -> Self { - let err = ExecutionError::from(err); - match EthcontractErrorType::classify(&err) { - EthcontractErrorType::Node => Self::Other(err.into()), - EthcontractErrorType::Contract => match err { - ExecutionError::Revert(message) => Self::Revert(message), - _ => Self::Revert(None), - }, - } - } -} - -pub struct TenderlyCodeSimulator { - tenderly: Arc, - network_id: String, -} - -impl TenderlyCodeSimulator { - pub fn new(tenderly: Arc, network_id: impl ToString) -> Self { - Self { - tenderly, - network_id: network_id.to_string(), - } - } - - fn prepare_request( - &self, - tx: TransactionRequest, - overrides: AlloyStateOverride, - block: Option, - ) -> Result { - Ok(SimulationRequest { - block_number: block, - // By default, tenderly simulates on the top of the specified block, whereas regular - // nodes simulate at the end of the specified block. This is to make - // simulation results match in case critical state changed within the block. - transaction_index: Some(-1), - network_id: self.network_id.clone(), - from: tx.from.map(IntoLegacy::into_legacy).unwrap_or_default(), - to: tx - .to - .and_then(TxKind::into_to) - .map(IntoLegacy::into_legacy) - .unwrap_or_default(), - input: tx - .input - .into_input() - .map(IntoLegacy::into_legacy) - .unwrap_or_default() - .0, - gas: tx.gas, - gas_price: tx - .gas_price - .map(TryInto::try_into) - .map(|gas_price| gas_price.unwrap()), - value: tx.value.map(IntoLegacy::into_legacy), - simulation_kind: Some(SimulationKind::Quick), - state_objects: Some( - overrides - .into_iter() - .map(|(key, value)| Ok((key.into_legacy(), value.into_legacy().try_into()?))) - .collect::>()?, - ), - ..Default::default() - }) - } - - pub fn log_simulation_command( - &self, - tx: TransactionRequest, - overrides: AlloyStateOverride, - block: Option, - ) -> Result<()> { - let request = SimulationRequest { - save: Some(true), - save_if_fails: Some(true), - ..self.prepare_request(tx, overrides, block)? - }; - self.tenderly.log(request) - } -} - -impl TryFrom for StateObject { - type Error = anyhow::Error; - - fn try_from(value: StateOverride) -> Result { - ensure!( - value.nonce.is_none() && value.state.is_none(), - "full state and nonce overrides not supported on Tenderly", - ); - - Ok(StateObject { - balance: value.balance, - code: value.code, - storage: value.state_diff, - }) - } -} - -#[cfg(test)] -mod tests { - use {super::*, hex_literal::hex, serde_json::json, testlib::assert_json_matches}; - - #[test] - fn serialize_deserialize_simulation_request() { - let request = SimulationRequest { - network_id: "1".to_string(), - block_number: Some(14122310), - from: addr!("e92f359e6f05564849afa933ce8f62b8007a1d5d"), - input: hex!("13d79a0b00000000000000000000000000000000000000000000").into(), - to: addr!("9008d19f58aabd9ed0d60971565aa8510560ab41"), - generate_access_list: Some(true), - transaction_index: None, - gas: None, - ..Default::default() - }; - - let json = json!({ - "network_id": "1", - "block_number": 14122310, - "from": "0xe92f359e6f05564849afa933ce8f62b8007a1d5d", - "input": "0x13d79a0b00000000000000000000000000000000000000000000", - "to": "0x9008d19f58aabd9ed0d60971565aa8510560ab41", - "generate_access_list": true - }); - - assert_json_matches!(serde_json::to_value(&request).unwrap(), json); - assert_eq!( - serde_json::from_value::(json).unwrap(), - request - ); - } - - #[tokio::test] - #[ignore] - async fn simulate_transaction() { - let tenderly = TenderlyHttpApi::test_from_env(); - let result = tenderly - .simulate(SimulationRequest { - network_id: "1".to_string(), - to: addr!("9008d19f58aabd9ed0d60971565aa8510560ab41"), - simulation_kind: Some(SimulationKind::Quick), - ..Default::default() - }) - .await - .unwrap(); - - assert!(result.transaction.status); - } -} diff --git a/crates/shared/src/trace_many.rs b/crates/shared/src/trace_many.rs deleted file mode 100644 index 93875234f5..0000000000 --- a/crates/shared/src/trace_many.rs +++ /dev/null @@ -1,106 +0,0 @@ -use { - crate::ethrpc::Web3, - anyhow::{Context, Result}, - web3::{ - Error, - Transport, - types::{BlockNumber, BlockTrace, CallRequest, TraceType}, - }, -}; - -// Use the trace_callMany api https://openethereum.github.io/JSONRPC-trace-module#trace_callmany -// api to simulate these call requests applied together one after another. -// Err if communication with the node failed. -pub async fn trace_many(requests: Vec, web3: &Web3) -> Result, Error> { - let transport = web3.transport(); - let requests = requests - .into_iter() - .map(|request| { - Ok(vec![ - serde_json::to_value(request)?, - serde_json::to_value(vec![TraceType::Trace])?, - ]) - }) - .collect::>>() - .map_err(|e| Error::Decoder(e.to_string()))?; - let block = BlockNumber::Latest; - let params = vec![ - serde_json::to_value(requests)?, - serde_json::to_value(block)?, - ]; - let response = transport.execute("trace_callMany", params).await?; - serde_json::from_value(response).map_err(|e| Error::Decoder(e.to_string())) -} - -// Check the return value of trace_many for whether all top level transactions -// succeeded (did not revert). -// Err if the response is missing trace data. -// Ok(true) if transactions simulate without reverting -// Ok(false) if transactions simulate with at least one revert. -pub fn all_calls_succeeded(traces: &[BlockTrace]) -> Result { - for trace in traces { - let transaction_trace = trace.trace.as_ref().context("trace not set")?; - let first = transaction_trace - .first() - .context("expected at least one trace")?; - if first.error.is_some() { - return Ok(false); - } - } - Ok(true) -} - -#[cfg(test)] -mod tests { - use {super::*, serde_json::json}; - - #[test] - fn ok_true() { - let response: Vec = serde_json::from_value(json!( - [{ - "output": "0x", - "trace": [{ - "traceAddress": [], - "subtraces": 0, - "action": { - "callType": "call", - "from": "0x0000000000000000000000000000000000000000", - "gas": "0x00", - "input": "0x", - "to": "0x0000000000000000000000000000000000000000", - "value": "0x00" - }, - "type": "call" - }], - }])) - .unwrap(); - let result = all_calls_succeeded(&response); - assert!(result.unwrap()); - } - - #[test] - fn ok_false() { - let response: Vec = serde_json::from_value(json!( - [{ - "output": "0x", - "trace": [{ - "traceAddress": [], - "subtraces": 0, - "action": { - "callType": "call", - "from": "0x0000000000000000000000000000000000000000", - "gas": "0x00", - "input": "0x", - "to": "0x0000000000000000000000000000000000000000", - "value": "0x00" - }, - "type": "call", - "error": "Reverted" - }], - }])) - .unwrap(); - - let result = all_calls_succeeded(&response); - assert!(!result.unwrap()); - } -} diff --git a/crates/shared/src/ethrpc.rs b/crates/shared/src/web3.rs similarity index 74% rename from crates/shared/src/ethrpc.rs rename to crates/shared/src/web3.rs index 2bf9993ba2..d1aaa7c636 100644 --- a/crates/shared/src/ethrpc.rs +++ b/crates/shared/src/web3.rs @@ -1,11 +1,10 @@ -pub use ethrpc::{Web3, Web3CallBatch, Web3Transport}; +pub use ethrpc::Web3; use { - crate::http_client::HttpClientFactory, - reqwest::Url, std::{ fmt::{self, Display, Formatter}, time::Duration, }, + url::Url, }; pub const MAX_BATCH_SIZE: usize = 100; @@ -59,13 +58,18 @@ impl Arguments { } } -/// Create a Web3 instance. -pub fn web3( - args: &Arguments, - http_factory: &HttpClientFactory, - url: &Url, - name: impl ToString, -) -> Web3 { - let http_builder = http_factory.builder(); - ethrpc::web3(args.ethrpc(), http_builder, url, name) +impl From<&configs::shared::EthRpcConfig> for Arguments { + fn from(config: &configs::shared::EthRpcConfig) -> Self { + Self { + ethrpc_max_batch_size: config.max_batch_size, + ethrpc_max_concurrent_requests: config.max_concurrent_requests, + ethrpc_batch_delay: config.batch_delay, + } + } +} + +/// Create a Web3 instance with a label for observability. +pub fn web3(args: &Arguments, url: &Url, name: impl ToString) -> Web3 { + let label = name.to_string(); + ethrpc::web3(args.ethrpc(), url, Some(&label)) } diff --git a/crates/signature-validator/Cargo.toml b/crates/signature-validator/Cargo.toml new file mode 100644 index 0000000000..d65e31ec2c --- /dev/null +++ b/crates/signature-validator/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "signature-validator" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-contract = { workspace = true } +alloy-dyn-abi = { workspace = true } +alloy-primitives = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-sol-types = { workspace = true } +alloy-transport = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +balance-overrides = { workspace = true } +const-hex = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +hex-literal = { workspace = true } +mockall = { workspace = true, optional = true } +model = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +mockall = { workspace = true } + +[features] +test-util = ["dep:mockall"] + +[lints] +workspace = true diff --git a/crates/shared/src/signature_validator/mod.rs b/crates/signature-validator/src/lib.rs similarity index 82% rename from crates/shared/src/signature_validator/mod.rs rename to crates/signature-validator/src/lib.rs index a415ba3347..770f0ab25b 100644 --- a/crates/shared/src/signature_validator/mod.rs +++ b/crates/signature-validator/src/lib.rs @@ -1,14 +1,10 @@ use { - crate::price_estimation::trade_verifier::balance_overrides::{ - BalanceOverrideRequest, - BalanceOverriding, - }, - alloy::primitives::FixedBytes, - contracts::alloy::GPv2Settlement, - ethrpc::{Web3, alloy::conversions::IntoAlloy}, + alloy_primitives::{Address, FixedBytes}, + balance_overrides::{BalanceOverrideRequest, StateOverriding}, + contracts::GPv2Settlement, + ethrpc::Web3, hex_literal::hex, model::interaction::InteractionData, - primitive_types::H160, std::sync::Arc, thiserror::Error, }; @@ -18,7 +14,7 @@ mod simulation; /// Structure used to represent a signature. #[derive(Clone, Eq, PartialEq)] pub struct SignatureCheck { - pub signer: H160, + pub signer: Address, pub hash: [u8; 32], pub signature: Vec, pub interactions: Vec, @@ -26,6 +22,22 @@ pub struct SignatureCheck { } impl SignatureCheck { + pub fn new( + signer: Address, + hash: [u8; 32], + signature: Vec, + interactions: Vec, + balance_override: Option, + ) -> Self { + Self { + signer, + hash, + signature, + interactions, + balance_override, + } + } + /// A signature check requires setup when there are interactions to be taken /// into account or when the balance override is set. /// @@ -96,21 +108,21 @@ pub fn check_erc1271_result(result: FixedBytes<4>) -> Result<(), SignatureValida /// Contracts required for signature verification simulation. pub struct Contracts { pub settlement: GPv2Settlement::Instance, - pub signatures: contracts::alloy::support::Signatures::Instance, - pub vault_relayer: H160, + pub signatures: contracts::support::Signatures::Instance, + pub vault_relayer: Address, } /// Creates the default [`SignatureValidating`] instance. pub fn validator( web3: &Web3, contracts: Contracts, - balance_overrider: Arc, + balance_overrider: Arc, ) -> Arc { Arc::new(simulation::Validator::new( web3, contracts.settlement, *contracts.signatures.address(), - contracts.vault_relayer.into_alloy(), + contracts.vault_relayer, balance_overrider, )) } diff --git a/crates/shared/src/signature_validator/simulation.rs b/crates/signature-validator/src/simulation.rs similarity index 81% rename from crates/shared/src/signature_validator/simulation.rs rename to crates/signature-validator/src/simulation.rs index 4b1c56817f..281bcf2259 100644 --- a/crates/shared/src/signature_validator/simulation.rs +++ b/crates/signature-validator/src/simulation.rs @@ -5,26 +5,20 @@ use { super::{SignatureCheck, SignatureValidating, SignatureValidationError}, - crate::price_estimation::trade_verifier::balance_overrides::BalanceOverriding, - alloy::{ - dyn_abi::SolType, - primitives::Address, - sol_types::{SolCall, sol_data}, - transports::RpcError, - }, + alloy_dyn_abi::SolType, + alloy_primitives::{Address, U256}, + alloy_rpc_types::state::StateOverride, + alloy_sol_types::{SolCall, sol_data}, + alloy_transport::RpcError, anyhow::{Context, Result}, - contracts::alloy::{ + balance_overrides::StateOverriding, + contracts::{ ERC1271SignatureValidator::ERC1271SignatureValidator, GPv2Settlement, support::Signatures, }, - ethcontract::state_overrides::StateOverrides, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - }, - primitive_types::U256, - std::sync::Arc, + ethrpc::{Web3, alloy::ProviderLabelingExt}, + std::sync::{Arc, LazyLock}, tracing::instrument, }; @@ -33,7 +27,7 @@ pub struct Validator { settlement: GPv2Settlement::Instance, vault_relayer: Address, web3: Web3, - balance_overrider: Arc, + balance_overrider: Arc, } impl Validator { @@ -45,9 +39,9 @@ impl Validator { settlement: GPv2Settlement::Instance, signatures_address: Address, vault_relayer: Address, - balance_overrider: Arc, + balance_overrider: Arc, ) -> Self { - let web3 = ethrpc::instrumented::instrument_with_label(web3, "signatureValidation".into()); + let web3 = web3.labeled("signatureValidation"); Self { signatures_address, settlement, @@ -67,14 +61,14 @@ impl Validator { // change), the order's validity can be directly determined by whether // the signature matches the expected hash of the order data, checked // with isValidSignature method called on the owner's contract - let contract = ERC1271SignatureValidator::new(check.signer.into_alloy(), &self.web3.alloy); + let contract = ERC1271SignatureValidator::new(check.signer, &self.web3.provider); let magic_bytes = contract .isValidSignature(check.hash.into(), check.signature.clone().into()) .call() .await .map(|value| const_hex::encode(value.0)) .map_err(|err| match err { - alloy::contract::Error::TransportError(RpcError::ErrorResp(err)) => { + alloy_contract::Error::TransportError(RpcError::ErrorResp(err)) => { tracing::error!(?err, "failed to call isValidSignature"); SignatureValidationError::Invalid } @@ -99,10 +93,10 @@ impl Validator { &self, check: SignatureCheck, ) -> Result { - let overrides: StateOverrides = match &check.balance_override { + let overrides: StateOverride = match &check.balance_override { Some(overrides) => self .balance_overrider - .state_override(overrides.clone()) + .balance_override(overrides.clone()) .await .into_iter() .collect(), @@ -118,7 +112,7 @@ impl Validator { settlement: *self.settlement.address(), vaultRelayer: self.vault_relayer, }, - signer: check.signer.into_alloy(), + signer: check.signer, order: check.hash.into(), signature: check.signature.clone().into(), interactions: check @@ -131,11 +125,15 @@ impl Validator { }) .collect(), }; + + // ZKSync-based chains don't use the default 0x0 account when `tx.from` is not + // specified, so we need to use a random account when sending a simulation tx. + static SIMULATION_ACCOUNT: LazyLock
= LazyLock::new(|| Address::random()); let simulation = self .settlement .simulateDelegatecall(self.signatures_address, validate_call.abi_encode().into()) - .state(overrides.clone().into_alloy()) - .from(crate::SIMULATION_ACCOUNT.address().into_alloy()); + .state(overrides.clone()) + .from(*SIMULATION_ACCOUNT); let result = simulation.clone().call().await; @@ -151,14 +149,12 @@ impl Validator { }) .map_err(|_| SignatureValidationError::Invalid)?; - let gas_used = >::abi_decode(&response_bytes.0) - .with_context(|| { - format!( - "could not decode signature check result: {}", - const_hex::encode(&response_bytes.0) - ) - })? - .into_legacy(); + let gas_used = >::abi_decode(&response_bytes.0).with_context(|| { + format!( + "could not decode signature check result: {}", + const_hex::encode(&response_bytes.0) + ) + })?; Ok(Simulation { gas_used }) } diff --git a/crates/simulator/Cargo.toml b/crates/simulator/Cargo.toml new file mode 100644 index 0000000000..3218091311 --- /dev/null +++ b/crates/simulator/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "simulator" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-contract = { workspace = true } +alloy-eips = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-sol-types = { workspace = true } +alloy-transport = { workspace = true } +anyhow = { workspace = true } +app-data = { workspace = true } +async-trait = { workspace = true } +balance-overrides = { workspace = true } +cached = { workspace = true } +chain = { workspace = true } +configs = { workspace = true } +const-hex = { workspace = true } +contracts = { workspace = true } +derive_more = { workspace = true } +eth-domain-types = { workspace = true } +ethrpc = { workspace = true } +futures = { workspace = true } +gas-price-estimation = { workspace = true } +hex-literal = { workspace = true } +http-client = { workspace = true } +mockall = { workspace = true, optional = true } +model = { workspace = true } +number = { workspace = true } +observe = { workspace = true } +prometheus = { workspace = true } +prometheus-metric-storage = { workspace = true } +reqwest = { workspace = true } +serde = { workspace = true } +serde-ext = { workspace = true } +serde_json = { workspace = true } +serde_with = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } +url = { workspace = true } + +[dev-dependencies] +mockall = { workspace = true } +testlib = { workspace = true } +tokio = { workspace = true } + +[features] +test-util = ["dep:mockall"] diff --git a/crates/simulator/src/encoding.rs b/crates/simulator/src/encoding.rs new file mode 100644 index 0000000000..4e6c02ce60 --- /dev/null +++ b/crates/simulator/src/encoding.rs @@ -0,0 +1,731 @@ +use { + crate::simulation_builder::{ + AccountOverrideRequest, + Block, + BuildError, + EthCallInputs, + ExecutionAmount, + MergeConflict, + Order, + PriceEncoding, + SimulationBuilder, + Solver, + WrapperConfig, + }, + alloy_primitives::{Address, B256, Bytes, U256, b256, keccak256}, + alloy_rpc_types::state::{AccountOverride, StateOverride}, + alloy_sol_types::SolCall, + app_data::AppDataHash, + balance_overrides::{ApprovalOverrideRequest, BalanceOverrideRequest, StateOverriding}, + contracts::GPv2Settlement, + derive_more::Debug, + model::{ + interaction::InteractionData, + order::{BuyTokenDestination, OrderData, OrderKind, SellTokenSource}, + signature::{Signature, SigningScheme}, + }, + number::serialization::HexOrDecimalU256, + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +pub type EncodedTrade = ( + U256, // sellTokenIndex + U256, // buyTokenIndex + Address, // receiver + U256, // sellAmount + U256, // buyAmount + u32, // validTo + B256, // appData + U256, // feeAmount + U256, // flags + U256, // executedAmount + Bytes, // signature +); + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct Interactions { + pub pre: Vec, + pub main: Vec, + pub post: Vec, +} + +impl Interactions { + pub fn into_array(self) -> [Vec; 3] { + [self.pre, self.main, self.post] + } +} + +impl IntoIterator for Interactions { + type IntoIter = std::array::IntoIter, 3>; + type Item = Vec; + + fn into_iter(self) -> Self::IntoIter { + [self.pre, self.main, self.post].into_iter() + } +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct EncodedSettlement { + pub tokens: Vec
, + pub clearing_prices: Vec, + pub trades: Vec, + pub interactions: Interactions, +} + +impl EncodedSettlement { + pub fn into_settle_call(&self) -> Bytes { + GPv2Settlement::GPv2Settlement::settleCall { + tokens: self.tokens.clone(), + clearingPrices: self.clearing_prices.clone(), + interactions: self.interactions.clone().into_array().map(|interactions| { + interactions + .into_iter() + .map(|i| GPv2Settlement::GPv2Interaction::Data { + target: i.0, + value: i.1, + callData: i.2.0.into(), + }) + .collect() + }), + trades: self + .trades + .iter() + .map(|t| GPv2Settlement::GPv2Trade::Data { + sellTokenIndex: t.0, + buyTokenIndex: t.1, + receiver: t.2, + sellAmount: t.3, + buyAmount: t.4, + validTo: t.5, + appData: t.6, + feeAmount: t.7, + flags: t.8, + executedAmount: t.9, + signature: t.10.clone(), + }) + .collect(), + } + .abi_encode() + .into() + } +} + +pub type EncodedInteraction = ( + Address, // target + U256, // value + Bytes, // callData +); + +#[serde_as] +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct JitOrder { + pub buy_token: Address, + pub sell_token: Address, + #[serde_as(as = "HexOrDecimalU256")] + pub sell_amount: U256, + #[serde_as(as = "HexOrDecimalU256")] + pub buy_amount: U256, + #[serde_as(as = "HexOrDecimalU256")] + pub executed_amount: U256, + pub receiver: Address, + pub valid_to: u32, + pub app_data: AppDataHash, + pub side: Side, + pub partially_fillable: bool, + pub sell_token_source: SellTokenSource, + pub buy_token_destination: BuyTokenDestination, + #[serde_as(as = "serde_ext::Hex")] + pub signature: Vec, + pub signing_scheme: SigningScheme, +} + +#[serde_as] +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum Side { + Buy, + Sell, +} + +/// Creates the data which the smart contract's `decodeTrade` expects. +pub fn encode_trade( + order: &OrderData, + signature: &Signature, + owner: Address, + sell_token_index: usize, + buy_token_index: usize, + executed_amount: U256, +) -> EncodedTrade { + ( + U256::from(sell_token_index), + U256::from(buy_token_index), + order.receiver.unwrap_or(Address::ZERO), + order.sell_amount, + order.buy_amount, + order.valid_to, + B256::new(order.app_data.0), + order.fee_amount, + order_flags(order, signature), + executed_amount, + Bytes::from(signature.encode_for_settlement(owner)), + ) +} + +fn order_flags(order: &OrderData, signature: &Signature) -> U256 { + let mut result = 0u8; + // The kind is encoded as 1 bit in position 0. + result |= match order.kind { + OrderKind::Sell => 0b0, + OrderKind::Buy => 0b1, + }; + // The order fill kind is encoded as 1 bit in position 1. + result |= (order.partially_fillable as u8) << 1; + // The order sell token balance is encoded as 2 bits in position 2. + result |= match order.sell_token_balance { + SellTokenSource::Erc20 => 0b00, + SellTokenSource::External => 0b10, + SellTokenSource::Internal => 0b11, + } << 2; + // The order buy token balance is encoded as 1 bit in position 4. + result |= match order.buy_token_balance { + BuyTokenDestination::Erc20 => 0b0, + BuyTokenDestination::Internal => 0b1, + } << 4; + // The signing scheme is encoded as a 2 bits in position 5. + result |= match signature.scheme() { + SigningScheme::Eip712 => 0b00, + SigningScheme::EthSign => 0b01, + SigningScheme::Eip1271 => 0b10, + SigningScheme::PreSign => 0b11, + } << 5; + U256::from(result) +} + +/// Data for a raw GPv2 interaction. +#[derive(Clone, PartialEq, Eq, Hash, Default, Serialize, Debug)] +pub struct Interaction { + pub target: Address, + pub value: U256, + #[debug("{}", const_hex::encode_prefixed::<&[u8]>(data.as_ref()))] + pub data: Vec, +} + +pub trait InteractionEncoding { + fn encode(&self) -> EncodedInteraction; +} + +impl Interaction { + pub fn to_interaction_data(&self) -> InteractionData { + InteractionData { + target: self.target, + value: self.value, + call_data: self.data.clone(), + } + } +} + +impl InteractionEncoding for Interaction { + fn encode(&self) -> EncodedInteraction { + ( + self.target, + self.value, + Bytes::copy_from_slice(self.data.as_slice()), + ) + } +} + +impl InteractionEncoding for InteractionData { + fn encode(&self) -> EncodedInteraction { + ( + self.target, + self.value, + Bytes::copy_from_slice(&self.call_data), + ) + } +} + +impl From for Interaction { + fn from(interaction: InteractionData) -> Self { + Self { + target: interaction.target, + value: interaction.value, + data: interaction.call_data, + } + } +} + +pub fn encode_interactions<'a, I>( + interactions: impl IntoIterator, +) -> Vec +where + I: InteractionEncoding + 'a, +{ + interactions.into_iter().map(|i| i.encode()).collect() +} + +#[derive(Clone, Debug)] +pub struct WrapperCall { + pub address: Address, + pub data: Bytes, +} + +/// Encodes a settlement transaction that uses wrapper contracts. +/// +/// Takes the base settlement calldata and wraps it in a wrappedSettleCall +/// with encoded wrapper metadata. Since wrappers are a chain, the wrapper +/// address to call is also processed by this function. +/// +/// Returns (first_wrapper_address, wrapped_calldata) +pub fn encode_wrapper_settlement( + wrappers: &[WrapperCall], + settle_calldata: Bytes, +) -> Option<(Address, Bytes)> { + if wrappers.is_empty() { + return None; + }; + let wrapper_data = encode_wrapper_data(wrappers); + + // Create wrappedSettleCall + let calldata = contracts::ICowWrapper::ICowWrapper::wrappedSettleCall { + settleData: settle_calldata, + wrapperData: wrapper_data, + } + .abi_encode(); + + Some((wrappers[0].address, calldata.into())) +} + +/// Encodes wrapper metadata for wrapper settlement calls. +/// As wrappers are called, each wrapper reads from wrapper calldata and +/// consumes only their needed portion (however much data that is). Once wrapper +/// is ready to call the settlement contract (or downstream wrapper) it calls +/// the _internalSettle function provided in the CowWrapper abstract contract +/// +/// Generally wrappers are encoded with a pair of Address (20 bytes) and then +/// calldata (u16 length + data itself). +/// +/// Since the first wrapper's address is the target of the transaction, it is +/// not encoded. +/// +/// The encoding format thus is: +/// - The calldata of the first wrapper. +/// - The address and calldata for each subsequent wrapper +/// +/// Example: Encoding of 2 wrapper calls, the wrappers are named A, B and are +/// called in the order A -> B +/// +/// | A calldata length | A calldata | B address | B calldata length | B calldata | +/// | u16 | &[u8] | [u8; 20] | u16 | &[u8] | +/// +/// Any additional wrappers will follow the same scheme: (address, length, +/// calldata) +/// +/// More information about wrapper encoding: +/// https://docs.cow.fi/cow-protocol/integrate/wrappers#manual-encoding +pub fn encode_wrapper_data(wrappers: &[WrapperCall]) -> Bytes { + let mut wrapper_data = Vec::new(); + + for (index, w) in wrappers.iter().enumerate() { + // Skip first wrapper's address (it's the transaction target) + if index != 0 { + wrapper_data.extend(w.address.as_slice()); + } + + // Encode data length as u16 in native endian, then the data itself + wrapper_data.extend((w.data.len() as u16).to_be_bytes().to_vec()); + wrapper_data.extend(w.data.clone()); + } + + wrapper_data.into() +} + +pub(crate) async fn finish_simulation_builder( + mut builder: SimulationBuilder, +) -> Result { + if builder.orders.is_empty() { + return Err(BuildError::NoOrder); + } + + let block = match builder.block { + Block::Latest => builder.simulator.0.current_block.borrow().number, + Block::Number(n) => n, + }; + + let executed_amounts = futures::future::try_join_all( + builder + .orders + .iter() + .map(|o| executed_amount(&builder, o, block)), + ) + .await?; + + // Each order occupies exactly 2 consecutive slots in the token/price + // vectors: [2*i] = sell_token, [2*i+1] = buy_token. + // This lets every order be encoded independently without requiring a shared + // global token list. + let n = builder.orders.len(); + let mut tokens = Vec::with_capacity(n * 2); + let mut clearing_prices = Vec::with_capacity(n * 2); + for order in &builder.orders { + let (sell_price, buy_price) = match &order.price_encoding { + PriceEncoding::LimitPrice => (order.data.buy_amount, order.data.sell_amount), + PriceEncoding::Custom { + sell_price, + buy_price, + } => (*sell_price, *buy_price), + }; + tokens.push(order.data.sell_token); + tokens.push(order.data.buy_token); + clearing_prices.push(sell_price); + clearing_prices.push(buy_price); + } + + if builder.provide_buy_tokens { + let settlement = *builder.simulator.0.settlement.address(); + for (i, (order, &exec)) in builder.orders.iter().zip(&executed_amounts).enumerate() { + let sell_price = clearing_prices[2 * i]; + let buy_price = clearing_prices[2 * i + 1]; + let amount = match order.data.kind { + OrderKind::Sell => sell_price + .saturating_mul(exec) + .checked_div(buy_price) + .unwrap_or(U256::MAX), + OrderKind::Buy => exec, + } + // give 1 wei extra to avoid issues with rounding divisions + .saturating_add(U256::ONE); + builder + .account_override_requests + .push(AccountOverrideRequest::Balance { + holder: settlement, + token: order.data.buy_token, + amount, + }); + } + } + + if builder.presign_orders { + builder.account_override_requests.extend( + builder + .orders + .iter() + .filter(|o| matches!(o.signature, Signature::PreSign)) + .map(|o| { + let uid = o.data.uid(&builder.simulator.0.domain_separator, o.owner); + AccountOverrideRequest::PreSignature(uid) + }), + ); + } + + // Encode every order as a trade, then collect all their interactions. + let mut trades = Vec::with_capacity(n); + for (i, (order, exec)) in builder.orders.iter().zip(&executed_amounts).enumerate() { + trades.push(encode_trade( + &order.data, + &order.signature, + order.owner, + 2 * i, + 2 * i + 1, + *exec, + )); + } + + let settlement = EncodedSettlement { + tokens, + clearing_prices, + trades, + interactions: Interactions { + pre: encode_interactions(&builder.pre_interactions), + main: encode_interactions(&builder.main_interactions), + post: encode_interactions(&builder.post_interactions), + }, + }; + + let settle_calldata = { + let mut bytes = settlement.into_settle_call().to_vec(); + if let Some(id) = builder.auction_id { + bytes.extend_from_slice(&id.to_be_bytes()); + } + bytes.into() + }; + + let wrapper = builder.wrapper; + let (to, calldata) = match wrapper { + WrapperConfig::Custom(wrappers) if !wrappers.is_empty() => { + encode_wrapper_settlement(&wrappers, settle_calldata).expect("wrappers is non-empty") + } + WrapperConfig::Flashloan(loans) => { + let calldata = contracts::FlashLoanRouter::FlashLoanRouter::flashLoanAndSettleCall { + loans: loans + .into_iter() + .map(|l| contracts::FlashLoanRouter::LoanRequest::Data { + amount: l.amount, + borrower: l.borrower, + lender: l.lender, + token: l.token, + }) + .collect(), + settlement: settle_calldata, + } + .abi_encode() + .into(); + (builder.simulator.0.flash_loan_router, calldata) + } + _ => (*builder.simulator.0.settlement.address(), settle_calldata), + }; + + let from = match builder.solver { + Some(Solver::OriginUnaltered(addr)) => addr, + Some(Solver::Fake(opt)) => { + let addr = opt.unwrap_or_else(Address::random); + builder + .account_override_requests + .push(AccountOverrideRequest::SufficientEthBalance(addr)); + builder + .account_override_requests + .push(AccountOverrideRequest::AuthenticateAsSolver(addr)); + addr + } + None => return Err(BuildError::NoSolver), + }; + let state_overrides = build_final_state_overrides( + builder.account_override_requests, + builder.simulator.0.state_overrides.as_ref(), + builder.simulator.0.authenticator, + *builder.simulator.0.settlement.address(), + ) + .await; + + Ok(EthCallInputs { + from, + to, + calldata, + state_overrides, + block, + simulator: builder.simulator, + }) +} + +/// Computes the exact amount the order should be filled with +/// based on the configured [`ExecutionAmount`]. +/// If `Remaining` is configured we look up how much the order +/// was already filled in the settlement contract and deduct +/// that from the full amount. +async fn executed_amount( + builder: &SimulationBuilder, + order: &Order, + block: u64, +) -> Result { + let full = match order.data.kind { + OrderKind::Sell => order.data.sell_amount, + OrderKind::Buy => order.data.buy_amount, + }; + + Ok(match order.executed_amount { + ExecutionAmount::Full => full, + ExecutionAmount::Explicit(amount) => amount, + ExecutionAmount::Remaining => { + let uid = order + .data + .uid(&builder.simulator.0.domain_separator, order.owner); + let filled_amount = builder + .simulator + .0 + .settlement + .filledAmount(Bytes::from(uid.0)) + .block(block.into()) + .call() + .await + .map_err(|err| BuildError::FilledAmountQuery(err.into()))?; + full.saturating_sub(filled_amount) + } + }) +} + +/// Resolves all [`AccountOverrideRequest`]s concurrently on a best-effort +/// basis. Failures are logged and the corresponding override is skipped rather +/// than aborting the whole build. +async fn build_final_state_overrides( + requests: Vec, + state_overrides: &dyn StateOverriding, + authenticator: Address, + settlement_contract: Address, +) -> StateOverride { + let futures = requests.into_iter().map(|request| async move { + match request { + AccountOverrideRequest::SufficientEthBalance(addr) => Some(( + addr, + AccountOverride::default().with_balance(U256::MAX / U256::from(2)), + )), + AccountOverrideRequest::AuthenticateAsSolver(addr) => { + // GPv2AllowListAuthentication stores `mapping(address => bool) solvers` + // at storage slot 1. Solidity mapping key: keccak256(address_padded ++ + // slot_padded). + // + let mut buf = [0u8; 64]; + buf[12..32].copy_from_slice(addr.as_slice()); + buf[32..64].copy_from_slice(&U256::ONE.to_be_bytes::<32>()); + let slot = keccak256(buf); + Some(( + authenticator, + AccountOverride::default() + .with_state_diff(std::iter::once((slot, B256::with_last_byte(1)))), + )) + } + AccountOverrideRequest::Balance { + holder, + token, + amount, + } => { + let result = state_overrides + .balance_override(BalanceOverrideRequest { + token, + holder, + amount, + }) + .await; + if result.is_none() { + tracing::warn!(%token, %holder, "failed to compute balance state override, skipping"); + } + result + } + AccountOverrideRequest::Code { account, code } => Some(( + account, + AccountOverride { + code: Some(code), + ..Default::default() + }, + )), + AccountOverrideRequest::PreSignature(order) => { + // GPv2Settlement stores the `mapping(bytes => uint256) public preSignature` at + // storage slot 0. + // Solidity mapping key: keccak256(order_uid_without_padding ++ slot_padded). + // + let mut buf = [0u8; 56 + 32]; + buf[0..56].copy_from_slice(order.0.as_slice()); + // no need to copy anything for storage slot 0 since the array gets 0 initialized. + let slot = keccak256(buf); + + // Sentinel value expected by the settlement contract to indicate that the order + // was pre-signed by the user. + // See + const PRE_SIGN_SENTINEL: B256 = b256!("f59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f"); + Some(( + settlement_contract, + AccountOverride::default() + .with_state_diff(std::iter::once((slot, PRE_SIGN_SENTINEL))), + )) + } + AccountOverrideRequest::Approval { + owner, + token, + spender, + amount, + } => { + let result = state_overrides + .approval_override(ApprovalOverrideRequest { + token, + owner, + spender, + amount, + }) + .await; + if result.is_none() { + tracing::warn!(%token, %owner, %spender, "failed to compute approval state override, skipping"); + } + result + } + AccountOverrideRequest::Custom { account, state } => Some((account, state)), + } + }); + + let mut state_overrides = StateOverride::default(); + for (address, account_override) in futures::future::join_all(futures) + .await + .into_iter() + .flatten() + { + if let Err(err) = apply_account_override(&mut state_overrides, address, account_override) { + tracing::warn!(?err, %address, "conflicting state overrides for address, skipping"); + } + } + state_overrides +} + +/// Merges `new` into `existing` field by field. +/// +/// Returns [`MergeConflict`] if both overrides write the same field. +/// Non-conflicting `state_diff` entries are combined into a single map. +fn merge_account_override( + existing: &mut AccountOverride, + new: AccountOverride, +) -> Result<(), MergeConflict> { + if new.balance.is_some() { + if existing.balance.is_some() { + return Err(MergeConflict::Balance); + } + existing.balance = new.balance; + } + if new.nonce.is_some() { + if existing.nonce.is_some() { + return Err(MergeConflict::Nonce); + } + existing.nonce = new.nonce; + } + if new.code.is_some() { + if existing.code.is_some() { + return Err(MergeConflict::Code); + } + existing.code = new.code; + } + match (new.state, new.state_diff) { + (Some(new_state), None) => { + if existing.state.is_some() { + return Err(MergeConflict::State); + } + if existing.state_diff.is_some() { + return Err(MergeConflict::StateAndStateDiff); + } + existing.state = Some(new_state); + } + (None, Some(new_diff)) => { + if existing.state.is_some() { + return Err(MergeConflict::StateAndStateDiff); + } + match &mut existing.state_diff { + None => existing.state_diff = Some(new_diff), + Some(existing_diff) => { + for (slot, value) in new_diff { + if existing_diff.contains_key(&slot) { + return Err(MergeConflict::StateDiffSlot(slot)); + } + existing_diff.insert(slot, value); + } + } + } + } + (None, None) => {} + // alloy does not allow both simultaneously, treat as incompatible + (Some(_), Some(_)) => return Err(MergeConflict::StateAndStateDiff), + } + Ok(()) +} + +/// Applies `new` to the override map for `address`. +/// +/// If `address` already has an entry, the overrides are merged via +/// [`merge_account_override`]. Returns an error on conflict. +fn apply_account_override( + overrides: &mut StateOverride, + address: Address, + new: AccountOverride, +) -> Result<(), MergeConflict> { + if let Some(existing) = overrides.get_mut(&address) { + merge_account_override(existing, new) + } else { + overrides.insert(address, new); + Ok(()) + } +} diff --git a/crates/simulator/src/ethereum/contracts.rs b/crates/simulator/src/ethereum/contracts.rs new file mode 100644 index 0000000000..55069f8c45 --- /dev/null +++ b/crates/simulator/src/ethereum/contracts.rs @@ -0,0 +1,33 @@ +use { + chain::Chain, + configs::simulator::Addresses, + contracts::{GPv2Settlement, WETH9}, + ethrpc::Web3, +}; + +#[derive(Debug, Clone)] +pub struct Contracts { + pub settlement: GPv2Settlement::Instance, + pub weth: WETH9::Instance, +} + +impl Contracts { + pub fn new(web3: Web3, chain: Chain, addresses: Addresses) -> Self { + let settlement = GPv2Settlement::Instance::new( + addresses + .settlement + .or_else(|| GPv2Settlement::deployment_address(&chain.id())) + .unwrap(), + web3.provider.clone(), + ); + let weth = WETH9::Instance::new( + addresses + .weth + .or_else(|| WETH9::deployment_address(&chain.id())) + .unwrap(), + web3.provider.clone(), + ); + + Self { settlement, weth } + } +} diff --git a/crates/simulator/src/ethereum/mod.rs b/crates/simulator/src/ethereum/mod.rs new file mode 100644 index 0000000000..447aafa0ab --- /dev/null +++ b/crates/simulator/src/ethereum/mod.rs @@ -0,0 +1,159 @@ +use { + crate::ethereum::contracts::Contracts, + alloy_primitives::U256, + alloy_provider::{Provider, network::TransactionBuilder}, + alloy_rpc_types::TransactionRequest, + anyhow::{Result, anyhow}, + chain::Chain, + eth_domain_types::AccessList, + ethrpc::{Web3, alloy::ProviderLabelingExt, block_stream::CurrentBlockWatcher}, + gas_price_estimation::{Eip1559EstimationExt, GasPriceEstimating}, + std::sync::Arc, + thiserror::Error, + tracing::{Level, instrument}, +}; + +pub mod contracts; + +#[derive(Clone)] +pub struct Ethereum { + web3: Web3, + inner: Arc, +} + +struct Inner { + chain: Chain, + contracts: Contracts, + gas: Arc, + current_block: CurrentBlockWatcher, + tx_gas_limit: U256, +} + +impl Ethereum { + pub fn new( + web3: Web3, + chain: Chain, + addresses: configs::simulator::Addresses, + gas: Arc, + current_block: CurrentBlockWatcher, + tx_gas_limit: U256, + ) -> Self { + Self { + web3: web3.clone(), + inner: Arc::new(Inner { + chain, + contracts: Contracts::new(web3.clone(), chain, addresses), + gas, + current_block, + tx_gas_limit, + }), + } + } + + #[instrument(skip(self), ret(level = Level::DEBUG))] + pub(super) async fn simulation_gas_price(&self) -> Option { + let base_fee = self.inner.current_block.borrow().base_fee; + // Some nodes don't pick a reasonable default value when you don't specify a gas + // price and default to 0. Additionally some sneaky tokens have special code + // paths that detect that case to try to behave differently during simulations + // than they normally would. To not rely on the node picking a reasonable + // default value we estimate the current gas price upfront. But because it's + // extremely rare that tokens behave that way we are fine with falling back to + // the node specific fallback value instead of failing the whole call. + Some(self.inner.gas.estimate().await.ok()?.effective(base_fee)) + } + + pub fn chain(&self) -> Chain { + self.inner.chain + } + + pub fn current_block(&self) -> &CurrentBlockWatcher { + &self.inner.current_block + } + + pub fn web3(&self) -> &Web3 { + &self.web3 + } + + /// Clones self and returns an instance that captures metrics extended with + /// the provided label. + pub fn with_metric_label(&self, label: String) -> Self { + Self { + web3: self.web3.labeled(label), + ..self.clone() + } + } + + pub async fn create_access_list(&self, tx: T) -> Result + where + T: Into, + { + let gas_limit = self.inner.tx_gas_limit.try_into().map_err(|err| { + Error::GasPrice(anyhow!("failed to convert gas_limit to u64: {err:?}")) + })?; + let tx = tx.into().with_gas_limit(gas_limit); + let tx = match self.simulation_gas_price().await { + Some(gas_price) => tx.with_gas_price(gas_price), + _ => tx, + }; + let access_list = self + .web3 + .provider + .create_access_list(&tx) + .pending() + .await + .map_err(Error::Rpc)?; + Ok(access_list + .ensure_ok() + .map_err(Error::AccessList)? + .access_list + .into()) + } + + pub async fn estimate_gas(&self, tx: T) -> Result + where + T: Into, + { + let tx = tx.into(); + let tx = match self.simulation_gas_price().await { + Some(gas_price) => tx.with_gas_price(gas_price), + _ => tx, + }; + + let estimated_gas = self + .web3 + .provider + .estimate_gas(tx) + .pending() + .await + .map_err(Error::Rpc)? + .into(); + + Ok(estimated_gas) + } +} + +impl std::fmt::Debug for Ethereum { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("Ethereum") + .field("web3", &self.web3) + .field("chain", &self.inner.chain) + .field("contracts", &self.inner.contracts) + .field("gas", &"Arc") + .finish() + } +} + +#[derive(Debug, Error)] +pub enum Error { + #[error("method error: {0:?}")] + ContractRpc(#[from] alloy_contract::Error), + #[error("alloy rpc error: {0:?}")] + Rpc(#[from] alloy_transport::RpcError), + #[error("gas price estimation error: {0}")] + GasPrice(anyhow::Error), + #[error("access list estimation error: {0:?}")] + AccessList(String), + #[error("other error: {0:?}")] + Other(anyhow::Error), +} diff --git a/crates/driver/src/infra/simulator/mod.rs b/crates/simulator/src/lib.rs similarity index 56% rename from crates/driver/src/infra/simulator/mod.rs rename to crates/simulator/src/lib.rs index 8fa919f31e..d094b60888 100644 --- a/crates/driver/src/infra/simulator/mod.rs +++ b/crates/simulator/src/lib.rs @@ -1,45 +1,49 @@ +pub mod encoding; +pub mod ethereum; +pub mod simulation_builder; +pub mod tenderly; +mod utils; + use { - crate::{ - domain::eth, - infra::blockchain::{self, Ethereum}, - }, + eth_domain_types::{self as eth, AccessList, Tx}, + http_client::HttpClientFactory, observe::future::Measure, }; +pub use {ethereum::Ethereum, tenderly::Tenderly}; -pub mod enso; -pub mod tenderly; - -/// Ethereum transaction simulator. #[derive(Debug, Clone)] pub struct Simulator { inner: Inner, eth: Ethereum, disable_access_lists: bool, - /// If this is [`Some`], every gas estimate will return this fixed - /// gas value. disable_gas: Option, } -/// Configuration of the transaction simulator. -#[derive(Debug)] -pub enum Config { - Tenderly(tenderly::Config), - Enso(enso::Config), +#[derive(Debug, Clone)] +enum Inner { + Tenderly(Box), + Ethereum, } impl Simulator { - /// Simulate transactions on [Tenderly](https://tenderly.co/). - pub fn tenderly(config: tenderly::Config, eth: Ethereum) -> Self { + pub fn tenderly( + config: &configs::simulator::TenderlyConfig, + eth: Ethereum, + http_factory: &HttpClientFactory, + ) -> Self { let eth = eth.with_metric_label("tenderlySimulator".into()); Self { - inner: Inner::Tenderly(tenderly::Tenderly::new(config, eth.clone())), + inner: Inner::Tenderly(Box::new(tenderly::Tenderly::new( + config, + eth.clone(), + http_factory, + ))), eth, disable_access_lists: false, disable_gas: None, } } - /// Simulate transactions using the Ethereum RPC API. pub fn ethereum(eth: Ethereum) -> Self { let eth = eth.with_metric_label("web3Simulator".into()); Self { @@ -50,22 +54,6 @@ impl Simulator { } } - /// Simulate transactions using the [Enso Simulator](https://github.com/EnsoFinance/transaction-simulator). - /// Uses Ethereum RPC API to generate access lists. - pub fn enso(config: enso::Config, eth: Ethereum) -> Self { - let eth = eth.with_metric_label("ensoSimulator".into()); - Self { - inner: Inner::Enso(enso::Enso::new( - config, - eth.chain(), - eth.current_block().clone(), - )), - eth, - disable_access_lists: false, - disable_gas: None, - } - } - /// Disable access list simulation. Some environments, such as less popular /// blockchains, don't support access list simulation. pub fn disable_access_lists(&mut self) { @@ -81,7 +69,7 @@ impl Simulator { /// Simulate the access list needed by a transaction. If the transaction /// already has an access list, the returned access list will be a /// superset of the existing one. - pub async fn access_list(&self, tx: ð::Tx) -> Result { + pub async fn access_list(&self, tx: &Tx) -> Result { if self.disable_access_lists { return Ok(tx.access_list.clone()); } @@ -89,7 +77,7 @@ impl Simulator { let access_list = match &self.inner { Inner::Tenderly(tenderly) => { tenderly - .simulate(tx, tenderly::GenerateAccessList::Yes) + .simulate(tx.clone(), block, tenderly::GenerateAccessList::Yes) .await .map_err(with(tx.clone(), block))? .access_list @@ -99,17 +87,12 @@ impl Simulator { .create_access_list(tx.clone()) .await .map_err(with(tx.clone(), block))?, - Inner::Enso(_) => self - .eth - .create_access_list(tx.clone()) - .await - .map_err(with(tx.clone(), block))?, }; Ok(tx.access_list.clone().merge(access_list)) } /// Simulate the gas needed by a transaction. - pub async fn gas(&self, tx: ð::Tx) -> Result { + pub async fn gas(&self, tx: eth::Tx) -> Result { if let Some(gas) = self.disable_gas { return Ok(gas); } @@ -117,50 +100,36 @@ impl Simulator { Ok(match &self.inner { Inner::Tenderly(tenderly) => { tenderly - .simulate(tx, tenderly::GenerateAccessList::No) + .simulate(tx.clone(), block, tenderly::GenerateAccessList::No) .measure("tenderly_simulate_gas") .await - .map_err(with(tx.clone(), block))? + .map_err(with(tx, block))? .gas } Inner::Ethereum => self .eth - .estimate_gas(tx) - .await - .map_err(with(tx.clone(), block))?, - Inner::Enso(enso) => enso - .simulate(tx.clone()) - .measure("enso_simulate_gas") + .estimate_gas(tx.clone()) .await - .map_err(with(tx.clone(), block))?, + .map_err(with(tx, block))?, }) } } -#[derive(Debug, Clone)] -enum Inner { - Tenderly(tenderly::Tenderly), - Ethereum, - Enso(enso::Enso), -} - #[derive(Debug, thiserror::Error)] pub enum SimulatorError { #[error("tenderly error: {0:?}")] Tenderly(#[from] tenderly::Error), - #[error("blockchain error: {0:?}")] - Blockchain(#[from] blockchain::Error), - #[error("enso error: {0:?}")] - Enso(#[from] enso::Error), + #[error("ethereum error: {0:?}")] + Ethereum(#[from] ethereum::Error), #[error("the simulated gas {0} exceeded the gas limit {1} provided in the solution")] GasExceeded(eth::Gas, eth::Gas), } #[derive(Debug, thiserror::Error)] -#[error("block: {block:?}, err: {err:?}, tx: {tx:?}")] +#[error("block: {block}, err: {err:?}, tx: {tx:?}")] pub struct RevertError { pub err: SimulatorError, - pub tx: eth::Tx, + pub tx: Tx, pub block: eth::BlockNo, } @@ -176,7 +145,7 @@ pub enum Error { Other(#[from] SimulatorError), } -fn with(tx: eth::Tx, block: eth::BlockNo) -> impl FnOnce(E) -> Error +fn with(tx: Tx, block: eth::BlockNo) -> impl FnOnce(E) -> Error where E: Into, { @@ -184,20 +153,17 @@ where let err: SimulatorError = err.into(); let tx = match &err { SimulatorError::Tenderly(tenderly::Error::Http(_)) => None, - SimulatorError::Tenderly(tenderly::Error::Revert(_)) => Some(tx), - SimulatorError::Blockchain(error) => { - if error.is_revert() { - Some(tx) - } else { - None - } - } - SimulatorError::Enso(enso::Error::Http(_)) => None, - SimulatorError::Enso(enso::Error::Revert(_)) => Some(tx), - SimulatorError::GasExceeded(..) => Some(tx), + SimulatorError::Tenderly(tenderly::Error::Revert(_)) => Some(tx.clone()), + SimulatorError::Tenderly(tenderly::Error::Other(_)) => None, + SimulatorError::Ethereum(_) => Some(tx.clone()), + SimulatorError::GasExceeded(..) => Some(tx.clone()), }; match tx { - Some(tx) => Error::Revert(RevertError { err, tx, block }), + Some(tx) => Error::Revert(RevertError { + err, + tx: tx.clone(), + block, + }), None => Error::Other(err), } } diff --git a/crates/simulator/src/simulation_builder.rs b/crates/simulator/src/simulation_builder.rs new file mode 100644 index 0000000000..9700b1c97c --- /dev/null +++ b/crates/simulator/src/simulation_builder.rs @@ -0,0 +1,713 @@ +use { + crate::{encoding::WrapperCall, tenderly}, + alloy_primitives::{Address, B256, Bytes, U256, address, b256, keccak256}, + alloy_provider::{DynProvider, Provider}, + alloy_rpc_types::{ + TransactionRequest, + state::{AccountOverride, StateOverride}, + }, + alloy_sol_types::SolCall, + alloy_transport::RpcError, + anyhow::{Context, Result}, + balance_overrides::StateOverriding, + ethrpc::block_stream::CurrentBlockWatcher, + model::{ + DomainSeparator, + interaction::InteractionData, + order::{OrderData, OrderUid}, + signature::{Signature, SigningScheme}, + }, + std::sync::Arc, +}; + +/// Holds the settlement contract and its authenticator address, and acts as a +/// factory for [`SimulationBuilder`] instances that are pre-configured with +/// these values. +#[derive(Clone)] +pub struct SettlementSimulator(pub(crate) Arc); + +pub(crate) struct Inner { + pub(crate) settlement: contracts::GPv2Settlement::Instance, + pub(crate) authenticator: Address, + pub(crate) vault_relayer: Address, + pub(crate) flash_loan_router: Address, + pub(crate) hooks_trampoline: Address, + pub(crate) native_token: Address, + pub(crate) max_gas_limit: u64, + pub(crate) state_overrides: Arc, + pub(crate) provider: DynProvider, + pub(crate) domain_separator: DomainSeparator, + pub(crate) chain_id: u64, + pub(crate) current_block: CurrentBlockWatcher, + pub(crate) tenderly: Option>, +} + +impl SettlementSimulator { + #[expect(clippy::too_many_arguments)] + pub async fn new( + settlement: contracts::GPv2Settlement::Instance, + flash_loan_router: Address, + hooks_trampoline: Address, + native_token: Address, + max_gas_limit: u64, + state_overrides: Arc, + current_block: CurrentBlockWatcher, + tenderly: Option>, + ) -> Result { + let authenticator = settlement.authenticator().call().await?; + let vault_relayer = Address(settlement.vaultRelayer().call().await?.0); + let domain_separator = DomainSeparator(settlement.domainSeparator().call().await?.0); + let provider = settlement.provider().clone(); + let chain_id = provider.get_chain_id().await?; + Ok(Self(Arc::new(Inner { + settlement, + authenticator, + vault_relayer, + flash_loan_router, + hooks_trampoline, + native_token, + max_gas_limit, + state_overrides, + provider, + domain_separator, + chain_id, + current_block, + tenderly, + }))) + } + + pub fn native_token(&self) -> Address { + self.0.native_token + } + + pub fn max_gas_limit(&self) -> u64 { + self.0.max_gas_limit + } + + pub fn provider(&self) -> DynProvider { + self.0.provider.clone() + } + + pub fn settlement_address(&self) -> Address { + *self.0.settlement.address() + } + + pub fn authenticator_address(&self) -> Address { + self.0.authenticator + } + + pub fn vault_relayer_address(&self) -> Address { + self.0.vault_relayer + } + + pub fn tenderly(&self) -> Option> { + self.0.tenderly.clone() + } + + pub fn new_simulation_builder(&self) -> SimulationBuilder { + SimulationBuilder { + simulator: self.clone(), + orders: vec![], + pre_interactions: vec![], + main_interactions: vec![], + post_interactions: vec![], + wrapper: WrapperConfig::NoWrapper, + solver: None, + auction_id: None, + account_override_requests: vec![], + provide_buy_tokens: false, + presign_orders: false, + block: Block::Latest, + } + } + + pub fn domain_separator(&self) -> DomainSeparator { + self.0.domain_separator + } +} + +/// Which block to simulate against. +pub enum Block { + /// Use the current head block from the block stream, pinning the + /// simulation to a concrete number at build time. + Latest, + Number(u64), +} + +/// Assembles a GPv2 settlement call for simulation purposes. +/// +/// Call [`SimulationBuilder::build`] when done to produce a [`SettlementCall`]. +pub struct SimulationBuilder { + pub(crate) orders: Vec, + pub(crate) pre_interactions: Vec, + pub(crate) main_interactions: Vec, + pub(crate) post_interactions: Vec, + pub(crate) wrapper: WrapperConfig, + pub(crate) solver: Option, + pub(crate) auction_id: Option, + pub(crate) simulator: SettlementSimulator, + pub(crate) account_override_requests: Vec, + pub(crate) provide_buy_tokens: bool, + pub(crate) presign_orders: bool, + pub(crate) block: Block, +} + +impl SimulationBuilder { + pub fn with_orders(mut self, orders: impl IntoIterator) -> Self { + self.orders = orders.into_iter().collect(); + self + } + + pub fn append_pre_interactions( + mut self, + interactions: impl IntoIterator, + ) -> Self { + self.pre_interactions.extend(interactions); + self + } + + pub fn append_main_interactions( + mut self, + interactions: impl IntoIterator, + ) -> Self { + self.main_interactions.extend(interactions); + self + } + + pub fn append_post_interactions( + mut self, + interactions: impl IntoIterator, + ) -> Self { + self.post_interactions.extend(interactions); + self + } + + pub fn with_wrapper(mut self, wrapper: WrapperConfig) -> Self { + self.wrapper = wrapper; + self + } + + pub fn from_solver(mut self, solver: Solver) -> Self { + self.solver = Some(solver); + self + } + + pub fn with_auction_id(mut self, id: i64) -> Self { + self.auction_id = Some(id); + self + } + + pub fn at_block(mut self, block: Block) -> Self { + self.block = block; + self + } + + /// Parses the app data JSON and configures the builder accordingly: + /// - Pre/post hooks are encoded as interactions via the [`HooksTrampoline`] + /// - Flashloan/wrapper fields set the [`WrapperConfig`]. + pub fn parameters_from_app_data(mut self, app_data: &str) -> Result { + let protocol = app_data::parse(app_data.as_bytes()).map_err(BuildError::AppDataParse)?; + + self.pre_interactions + .extend(self.encode_hooks(&protocol.hooks.pre)); + self.post_interactions + .extend(self.encode_hooks(&protocol.hooks.post)); + + match (protocol.wrappers.is_empty(), protocol.flashloan) { + (false, Some(_)) => return Err(BuildError::FlashloanWrappersIncompatible), + (false, None) => { + let mut wrapper_calls = Vec::with_capacity(protocol.wrappers.len()); + for w in protocol.wrappers { + // TODO: REMOVE THIS HACK! + // Unconditionally add state override for euler compatibility. + // If this state override gets added to calls that don't need it + // it will not interfere with the simulation. + self.account_override_requests + .extend(compute_euler_override(&w)); + + wrapper_calls.push(WrapperCall { + address: w.address, + data: w.data.into(), + }); + } + self.wrapper = WrapperConfig::Custom(wrapper_calls); + } + (true, Some(flashloan)) => { + self.wrapper = WrapperConfig::Flashloan(vec![FlashloanRequest { + amount: flashloan.amount, + borrower: flashloan.protocol_adapter, + lender: flashloan.liquidity_provider, + token: flashloan.token, + }]); + } + (true, None) => {} + } + + Ok(self) + } + + /// Generates 1 interaction executing the given hooks via the trampoline + /// contract since executing hooks directly from the settlement contract + /// context would give them elevated privileges that put funds at risk. + fn encode_hooks(&self, hooks: &[app_data::Hook]) -> Option { + if hooks.is_empty() { + return None; + } + Some(InteractionData { + target: self.simulator.0.hooks_trampoline, + value: U256::ZERO, + call_data: contracts::HooksTrampoline::HooksTrampoline::executeCall { + hooks: hooks + .iter() + .map(|h| contracts::HooksTrampoline::HooksTrampoline::Hook { + target: h.target, + callData: Bytes::copy_from_slice(&h.call_data), + gasLimit: U256::from(h.gas_limit), + }) + .collect(), + } + .abi_encode(), + }) + } + + /// Instructs the builder to override the settlement contract's buy-token + /// balances so it can pay out every order. The exact amounts are derived + /// from the clearing prices and executed amounts once + /// [`build`](Self::build) is called. + pub fn provide_sufficient_buy_tokens(mut self) -> Self { + self.provide_buy_tokens = true; + self + } + + /// For every order with signature scheme presign the simulation will + /// contains state overrides to provide the signatures. + /// This is useful when you have to author an order on behalf of an account + /// you don't control. + pub fn presign_orders(mut self) -> Self { + self.presign_orders = true; + self + } + + /// Queues [`AccountOverrideRequest`]s to be resolved and applied during + /// [`build`](Self::build). Multiple requests may target the same address + /// and will be applied on a best-effort basis (failure to compute balance + /// overrides or conflicting state overrides will get logged but do not + /// lead to an error). + pub fn with_overrides( + mut self, + requests: impl IntoIterator, + ) -> Self { + self.account_override_requests.extend(requests); + self + } + + /// Finishes the simulation struct based on the configuration thus far. + pub async fn build(self) -> Result { + // Forward to a helper function to split the boring repetitive builder + // code from the non-trivial code that actually does the encoding. + crate::encoding::finish_simulation_builder(self).await + } +} + +/// Euler is the only integration for now using wrappers and they have a +/// chicken and egg problem when quoting. They need a quote to know the +/// things they have to make the user sign to make the resulting order +/// work. But for the quote to be accurate we already need to have this +/// setup done. +/// To get around this we introduce this temporary hack of +/// assuming this is an euler wrapper and unconditionally setting up the +/// requirements using state overrides. +/// +/// For that we need to write `U256::MAX` to this mapping which lives in +/// storage slot 24 of contract 0x0C9a3dd6b8F28529d72d7f9cE918D493519EE383: +/// mapping(bytes19 addressPrefix => mapping(address operator => uint256 +/// operatorBitField)) internal operatorLookup; +fn compute_euler_override(wrapper: &app_data::WrapperCall) -> Vec { + let mut overrides = vec![]; + + let ethereum_vault_connector = address!("0x0C9a3dd6b8F28529d72d7f9cE918D493519EE383"); + let permission_value = B256::from([0xFF_u8; 32]); + let slot_24 = B256::with_last_byte(24); + let Some(address_prefix) = wrapper.data.get(0..32) else { + return overrides; + }; + let address_prefix: [u8; 32] = address_prefix.try_into().unwrap(); + + let operator = wrapper.address; + + // Outer slot: keccak256(bytes19_address_prefix ++ slot_24) + let outer_slot = { + let mut buf = [0u8; 64]; + // take first 19 populated bytes from the padded address and write + // them to the first 19 bytes of the buffer (to "cast" an + // `address` to a `bytes19` mapping key). + buf[0..19].copy_from_slice(&address_prefix[12..31]); + buf[32..64].copy_from_slice(slot_24.as_slice()); + keccak256(buf) + }; + // Final slot: keccak256(operator ++ outer_slot) + let permission_slot = { + let mut buf = [0u8; 64]; + buf[12..32].copy_from_slice(operator.as_slice()); + buf[32..64].copy_from_slice(outer_slot.as_slice()); + keccak256(buf) + }; + + overrides.push(AccountOverrideRequest::Custom { + account: ethereum_vault_connector, + state: AccountOverride::default().with_state_diff([(permission_slot, permission_value)]), + }); + + let (domain_separator, type_hash) = match wrapper.address { + // open position wrapper + x if x == address!("0x59684A689D4a1CAc0f0632F54ec8cDd42612D728") => ( + b256!("0x0af97cc7912b08e2bc78d17603f600b75eb0759236a4591930fc1e0192c042ff"), + b256!("0x37458bde9202dec258a12cf2bc8b4ac302a61cf842bbe3a2bb921d968507d3bf"), + ), + // close position wrapper + x if x == address!("0xa18c87849ef90190117ff1e1e8b4ace6dac7a54b") => ( + b256!("0xffa38a994108ca56910187ade1b200aca3f27ac295ac150bde63a9b5783af04f"), + b256!("0x3cdbf47d3b4f755805c36069980ae18f367b382cf0593fa0378ad50c1c5d1fd8"), + ), + // collateral swap wrapper + x if x == address!("0x175fbd01874e92c9b081f493371fefe009760a42") => ( + b256!("0xfac3fa57d73575d8f9df481fc13e23240d08bfc183e56bd289a69521402ab2dc"), + b256!("0x82f0a6a70fe8cb4c350f918378cd06594e0307d840ad296019fa47d796428016"), + ), + _ => return Default::default(), + }; + + let Some(struct_hash_input) = wrapper + .data + .len() + .checked_sub(64) + .and_then(|offset| wrapper.data.get(..offset)) + else { + return vec![]; + }; + + let struct_hash = keccak256( + type_hash + .into_iter() + .chain(struct_hash_input.iter().copied()) + .collect::>(), + ); + let map_key = keccak256( + [0x19, 0x01] + .into_iter() + .chain(domain_separator) + .chain(struct_hash) + .collect::>(), + ); + + // mapping(address => mapping(bytes32 => uint256)) public preApprovedHashes; + let first_map_slot = { + let mut buf = [0u8; 64]; + buf[0..32].copy_from_slice(address_prefix.as_slice()); + // nothing to copy since mapping lives at storage slot 0 + keccak256(buf) + }; + + let preapprove_hash_slot = { + let mut buf = [0u8; 64]; + buf[0..32].copy_from_slice(map_key.as_slice()); + buf[32..64].copy_from_slice(first_map_slot.as_slice()); + keccak256(buf) + }; + + // keccak256("PreApprovedHashes.PreApproved") + let preapprove_value = + b256!("0xfdeb67b02819f1ab9c0e57355ac925e9fe35883f75ef41b364cd780799c5998a"); + + overrides.push(AccountOverrideRequest::Custom { + account: wrapper.address, + state: AccountOverride::default() + .with_state_diff([(preapprove_hash_slot, preapprove_value)]), + }); + + overrides +} + +/// The output of [`SimulationBuilder::build`]: inputs ready to be passed to an +/// alloy provider for simulation. +pub struct EthCallInputs { + pub from: Address, + pub to: Address, + pub calldata: Bytes, + pub state_overrides: StateOverride, + pub simulator: SettlementSimulator, + pub block: u64, +} + +impl EthCallInputs { + pub fn as_transaction_request(&self) -> TransactionRequest { + TransactionRequest { + from: Some(self.from), + to: Some(self.to.into()), + input: self.calldata.clone().into(), + gas: Some(self.simulator.0.max_gas_limit), + ..Default::default() + } + } + + /// Runs the generated simulation using an `eth_call` and returns the + /// response bytes if there are any. + pub async fn simulate(self) -> Result> { + self.simulator + .0 + .provider + .clone() + .call(self.as_transaction_request()) + .overrides(self.state_overrides) + .block(self.block.into()) + .await + } + + /// Same as [`EthCallInputs::simulate`] but also generates a tenderly + /// request in case one wants to re-simulate with tenderly. If tenderly + /// credentials are configured this even generates a shareable link for + /// the simulation. + pub async fn simulate_with_tenderly_report(self) -> Result { + let tenderly_request = self + .to_tenderly_request() + .context("failed to convert to tenderly request")?; + + let tenderly_url = if let Some(api) = &self.simulator.0.tenderly { + api.simulate_and_share(tenderly_request.clone()) + .await + .inspect_err(|err| tracing::warn!(?err, "failed to simulate via tenderly")) + .ok() + } else { + None + }; + + Ok(TenderlyReport { + tenderly_request, + tenderly_url, + error: self.simulate().await.err().map(|err| err.to_string()), + }) + } + + /// Converts the simulation into a request that can be simulated with + /// tenderly. + pub fn to_tenderly_request(&self) -> Result { + Ok(tenderly::dto::Request { + // By default, tenderly simulates the given transaction as if it happened somewhere in + // the given block number, while nodes simulate the transaction as if it + // happened at the very end of the given block. This could be achieved in + // tenderly with `transaction_index: -1` but this is extremely costly to + // simulate which is why we craft the request to simulate the tx on the very + // first index of the **next** block. In practice the different will be that + // tenderly's simulation will already use the block number and timestamp of + // the **next** block that would be mined which is arguably more correct than + // the original simulation. + block_number: Some(self.block + 1), + transaction_index: Some(0), + network_id: self.simulator.0.chain_id.to_string(), + from: self.from, + to: self.to, + input: self.calldata.to_vec(), + gas: Some(self.simulator.0.max_gas_limit), + value: None, + simulation_type: Some(tenderly::dto::SimulationType::Full), + state_objects: Some( + self.state_overrides + .iter() + .map(|(key, value)| { + Ok(( + *key, + tenderly::dto::StateObject::try_from(value.clone()) + .map_err(|_| ConversionError::StateOverrides)?, + )) + }) + .collect::>()?, + ), + access_list: None, + save: Some(true), + gas_price: None, + save_if_fails: Some(true), + generate_access_list: None, + }) + } +} + +/// The result of Order simulation, contains the error (if any) +/// and full Tenderly API request that can be used to resimulate +/// and debug using Tenderly +#[derive(Clone, Debug)] +pub struct TenderlyReport { + /// Full request object that can be used directly with the Tenderly API + pub tenderly_request: tenderly::dto::Request, + /// Shared Tenderly simulation URL for debugging in the dashboard + pub tenderly_url: Option, + /// Any error that might have been reported during order simulation + pub error: Option, +} + +pub enum Solver { + /// Simulation assumes this is an actual solver so no state overrides will + /// be applied to allow list it explicitly. + /// If you need a very specific solver setup for your simulation consider + /// using this and explicitly adding the necessary + /// [`AccountOverrideRequest`]s using with + /// [`SimulationBuilder::with_overrides()`]. + OriginUnaltered(Address), + /// A fake solver for simulation. Uses the provided address or generates a + /// random one. The simulation builder will automatically set the required + /// state overrides to give it enough ETH and allow list it as a solver. + Fake(Option
), +} + +/// How much of an order should be filled during simulation. +pub enum ExecutionAmount { + /// Fill the full order amount (sell_amount for sell orders, buy_amount for + /// buy orders), ignoring any on-chain filled state. + Full, + /// Fill whatever is still remaining on-chain (queries the settlement + /// contract for the already-filled amount and subtracts it). Building the + /// simulation will throw an error if the RPC call to fetch the current fill + /// state fails. + Remaining, + /// Use an explicit fill amount. + Explicit(U256), +} + +/// How clearing prices are determined for the encoded settlement. +pub enum PriceEncoding { + /// Derive clearing prices directly from the order's limit price. + /// + /// Sets `price[sell_token] = buy_amount` and `price[buy_token] = + /// sell_amount`, exactly satisfying the order's limit with no surplus. + LimitPrice, + /// Explicit clearing prices for the order's sell and buy token. Use this + /// when the prices differ from the order's limit — e.g. in trade + /// verification where the order amounts are set to always pass the limit + /// check and the solver's quoted prices are supplied separately. + Custom { sell_price: U256, buy_price: U256 }, +} + +/// A simulator-specific order that bundles the data needed to encode a trade. +/// +/// Construct with [`Order::new`] and add optional fields via the builder +/// methods. Defaults to the [`PreSign`] signing scheme as that is the easiest +/// to fake during simulations. Note that [`SimulationBuilder::presign_orders`] +/// needs to be called to generate the required state overrides to set the +/// pre-signature. +pub struct Order { + pub(crate) data: OrderData, + pub(crate) owner: Address, + pub(crate) signature: Signature, + pub(crate) executed_amount: ExecutionAmount, + pub(crate) price_encoding: PriceEncoding, +} + +impl Order { + pub fn new(data: OrderData) -> Self { + Self { + data, + owner: Address::ZERO, + signature: Signature::default_with(SigningScheme::PreSign), + executed_amount: ExecutionAmount::Remaining, + price_encoding: PriceEncoding::LimitPrice, + } + } + + pub fn with_signature(mut self, owner: Address, signature: Signature) -> Self { + self.owner = owner; + self.signature = signature; + self + } + + pub fn fill_at(mut self, execution: ExecutionAmount, price: PriceEncoding) -> Self { + self.executed_amount = execution; + self.price_encoding = price; + self + } +} + +/// Configuration for wrapping the settlement in a flashloan or custom wrapper +/// contract chain. +pub enum WrapperConfig { + Flashloan(Vec), + Custom(Vec), + NoWrapper, +} + +pub struct FlashloanRequest { + pub amount: U256, + pub borrower: Address, + pub lender: Address, + pub token: Address, +} + +#[derive(Debug)] +pub enum AccountOverrideRequest { + /// Gives the address a huge amount of ETH. + SufficientEthBalance(Address), + /// Allowlists an address as a solver to let it settle orders. + AuthenticateAsSolver(Address), + /// Computes necessary state overrides for the requested balance. + Balance { + holder: Address, + token: Address, + amount: U256, + }, + /// Deploys the provided code at the requested address. + Code { account: Address, code: Bytes }, + /// Allows to build fully custom overrides for the most exotic use cases. + Custom { + account: Address, + state: AccountOverride, + }, + /// Sets the given Erc20 token approval. + Approval { + owner: Address, + token: Address, + spender: Address, + amount: U256, + }, + /// Pre-signs the given order such that the pre-sign signature check passes. + PreSignature(OrderUid), +} + +/// Error returned when a built eth_call simulation could not be converted +/// into a tenderly simulation request. +#[derive(Debug, thiserror::Error)] +pub enum ConversionError { + #[error("could not convert state overrides")] + StateOverrides, +} + +/// Error returned when data needed to build the final simulation was missing, +/// incompatible, or could not be computed ad-hoc. +#[derive(Debug, thiserror::Error)] +pub enum BuildError { + #[error("no order was added")] + NoOrder, + #[error("no solver was set")] + NoSolver, + #[error("failed to query filled amount from settlement contract: {0}")] + FilledAmountQuery(#[from] anyhow::Error), + #[error("failed to parse app data: {0}")] + AppDataParse(#[from] serde_json::Error), + #[error("both wrappers and flashloans cannot be encoded in the same settlement")] + FlashloanWrappersIncompatible, +} + +/// Error returned when two [`AccountOverride`]s set the same field for the same +/// address and cannot be merged. +#[derive(Debug, thiserror::Error)] +pub(crate) enum MergeConflict { + #[error("both overrides set the ETH balance")] + Balance, + #[error("both overrides set the nonce")] + Nonce, + #[error("both overrides set the contract code")] + Code, + #[error("both overrides replace the full storage state")] + State, + #[error("overrides use incompatible storage strategies (state vs state_diff)")] + StateAndStateDiff, + #[error("both overrides write storage slot {0}")] + StateDiffSlot(B256), +} diff --git a/crates/simulator/src/tenderly/dto.rs b/crates/simulator/src/tenderly/dto.rs new file mode 100644 index 0000000000..0800e57281 --- /dev/null +++ b/crates/simulator/src/tenderly/dto.rs @@ -0,0 +1,205 @@ +use { + alloy_primitives::{Address, B256, U256, map::B256Map}, + eth_domain_types as eth, + serde::{Deserialize, Serialize}, + serde_with::serde_as, + std::collections::HashMap, +}; + +/// Tenderly API simulation request +/// https://docs.tenderly.co/reference/api#/operations/simulateTransaction#request-body +#[serde_as] +#[derive(Clone, Deserialize, Serialize, Debug, Default)] +pub struct Request { + /// ID of the network on which the simulation is being run. + pub network_id: String, + /// Number of the block to be used for the simulation. + #[serde(skip_serializing_if = "Option::is_none")] + pub block_number: Option, + /// Index of the transaction within the block. + #[serde(skip_serializing_if = "Option::is_none")] + pub transaction_index: Option, + /// Address initiating the transaction. + pub from: Address, + /// The recipient address of the transaction. + pub to: Address, + /// Encoded contract method call data. + #[serde_as(as = "serde_ext::Hex")] + pub input: Vec, + /// Amount of gas provided for the simulation. + #[serde(skip_serializing_if = "Option::is_none")] + pub gas: Option, + /// String representation of a number that represents price of the gas in + /// Wei. + #[serde(skip_serializing_if = "Option::is_none")] + pub gas_price: Option, + /// Amount of Ether (in Wei) sent along with the transaction. + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub simulation_type: Option, + /// Flag indicating whether to save the simulation in dashboard UI. + #[serde(skip_serializing_if = "Option::is_none")] + pub save: Option, + /// Flag indicating whether to save failed simulation in dashboard UI. + #[serde(skip_serializing_if = "Option::is_none")] + pub save_if_fails: Option, + /// Flag that enables returning the access list in a response. + #[serde(skip_serializing_if = "Option::is_none")] + pub generate_access_list: Option, + /// Overrides for a given contract. + #[serde(skip_serializing_if = "Option::is_none")] + pub state_objects: Option>, + /// EIP-2930 access list used by the transaction. + #[serde(skip_serializing_if = "Option::is_none")] + pub access_list: Option, +} + +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct Response { + pub transaction: Transaction, + pub generated_access_list: Option, + pub simulation: Simulation, +} + +/// EIP-2930 access list used by the transaction. +/// https://docs.tenderly.co/reference/api#/operations/simulateTransaction#response-body:~:text=0x-,access_list,-array%20or%20null +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct AccessListItem { + /// Accessed address + pub address: Address, + /// Accessed storage keys + #[serde(default)] + pub storage_keys: Vec, +} + +/// Tenderly requires access lists to be serialized with `snake_case` instead +/// of the standard `camelCase`. +#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] +#[serde(transparent)] +pub struct AccessList(Vec); + +impl From<&alloy_rpc_types::AccessList> for AccessList { + fn from(value: &alloy_rpc_types::AccessList) -> Self { + AccessList( + value + .iter() + .map(|item| AccessListItem { + address: item.address, + storage_keys: item.storage_keys.clone(), + }) + .collect(), + ) + } +} + +impl From for alloy_rpc_types::AccessList { + fn from(value: AccessList) -> Self { + value + .0 + .iter() + .map(|item| alloy_rpc_types::AccessListItem { + address: item.address, + storage_keys: item.storage_keys.clone(), + }) + .collect::>() + .into() + } +} + +impl From for AccessList { + fn from(value: eth::AccessList) -> Self { + Self( + value + .into_iter() + .map(|(address, storage_keys)| AccessListItem { + address, + storage_keys: storage_keys.into_iter().map(|k| k.0).collect(), + }) + .collect(), + ) + } +} + +impl From for eth::AccessList { + fn from(value: AccessList) -> Self { + Self::from_iter( + value + .0 + .into_iter() + .map(|item| (item.address, item.storage_keys)), + ) + } +} +/// Overrides for a given contract. In this mapping, the key is the contract +/// address, and the value is an object that contains overrides of nonce, code, +/// balance, or state. https://docs.tenderly.co/reference/api#/operations/simulateTransaction#response-body:~:text=null%2C%22uncles%22%3Anull%7D-,state_objects,-dictionary%5Bstring%2C%20object +#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] +pub struct StateObject { + /// Fake balance to set for the account before executing the call. + #[serde(skip_serializing_if = "Option::is_none")] + pub balance: Option, + + /// Fake EVM bytecode to inject into the account before executing the call. + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, + + /// Fake key-value mapping to override **individual** slots in the account + /// storage before executing the call. + #[serde(skip_serializing_if = "Option::is_none")] + pub storage: Option>, +} + +impl TryFrom for StateObject { + type Error = anyhow::Error; + + fn try_from( + value: alloy_rpc_types::eth::state::AccountOverride, + ) -> std::result::Result { + anyhow::ensure!( + value.nonce.is_none() && value.state.is_none(), + "full state and nonce overrides not supported on Tenderly", + ); + + Ok(StateObject { + balance: value.balance, + code: value.code, + storage: value.state_diff, + }) + } +} +/// Opt for quick, abi, or full simulation API mode. +/// https://docs.tenderly.co/reference/api#/operations/simulateTransaction#response-body:~:text=true-,simulation_type,-string +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum SimulationType { + /// Detailed decoded output — call trace, function + /// inputs/outputs, state diffs, and logs with Solidity types. + Full, + /// Raw, minimal output only. Fastest option; no decoding. + Quick, + /// Decoded function inputs/outputs and logs, but no state diffs. Middle + /// ground between quick and full. + Abi, +} + +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct Transaction { + pub status: bool, + pub gas_used: u64, + pub call_trace: Vec, +} + +#[serde_with::serde_as] +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct CallTrace { + #[serde(default)] + #[serde_as(as = "Option")] + pub output: Option>, + pub error: Option, +} + +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct Simulation { + pub id: String, +} diff --git a/crates/simulator/src/tenderly/mod.rs b/crates/simulator/src/tenderly/mod.rs new file mode 100644 index 0000000000..2f4ad46e21 --- /dev/null +++ b/crates/simulator/src/tenderly/mod.rs @@ -0,0 +1,357 @@ +use { + crate::ethereum::Ethereum, + alloy_primitives::TxKind, + alloy_rpc_types::{TransactionRequest, state::StateOverride}, + anyhow::{Result, anyhow}, + configs::simulator::TenderlyConfig, + eth_domain_types::{AccessList, BlockNo, Gas}, + http_client::HttpClientFactory, + prometheus::IntGaugeVec, + reqwest::header::HeaderValue, + thiserror::Error, + url::Url, +}; + +pub mod dto; + +const API_URL: &str = "https://api.tenderly.co/api"; +const DASHBOARD_URL: &str = "https://dashboard.tenderly.co"; +// We want the string to be printed together with a simulation so we +// don't care that it's not used for anything else. +#[derive(Debug)] +pub struct SimulationId(#[allow(dead_code, reason = "intended for Debug implementation")] String); + +#[derive(Debug, Clone)] +pub struct Tenderly { + api: TenderlyApi, + eth: Ethereum, + save: bool, + save_if_fails: bool, +} + +#[derive(Debug, Clone)] +pub struct TenderlyApi { + /// Base URL for the Tenderly API project, e.g. + /// `https://api.tenderly.co/api/v1/account/{user}/project/{project}` + api_base: Url, + client: reqwest::Client, + dashboard: Url, + chain_id: String, +} + +#[async_trait::async_trait] +pub trait Api: Send + Sync + 'static { + fn log_simulation_command( + &self, + tx: TransactionRequest, + overrides: StateOverride, + block: BlockNo, + ) -> Result<()>; + + async fn simulate(&self, request: dto::Request) -> Result; + + /// Submits a simulation, shares it, and returns the shared Tenderly URL. + async fn simulate_and_share(&self, request: dto::Request) -> Result; +} + +impl Tenderly { + pub fn new(config: &TenderlyConfig, eth: Ethereum, http_factory: &HttpClientFactory) -> Self { + Self { + api: TenderlyApi::new(config, http_factory, eth.chain().id().to_string()), + eth, + save_if_fails: config.save_if_fails, + save: config.save, + } + } + + pub async fn simulate( + &self, + tx: T, + block: BlockNo, + generate_access_list: GenerateAccessList, + ) -> Result + where + T: Into, + { + let tx = tx.into(); + let request = dto::Request { + generate_access_list: match generate_access_list { + GenerateAccessList::Yes => Some(true), + GenerateAccessList::No => None, + }, + save_if_fails: self.save_if_fails.then_some(true), + save: self.save.then_some(true), + ..prepare_request( + self.eth.chain().id().to_string(), + &tx, + Default::default(), + block, + )? + }; + + Ok(self + .api + .simulate(request) + .await + .map_err(|err| Error::Other(anyhow!(err)))? + .into()) + } +} + +impl TenderlyApi { + pub fn new( + config: &configs::simulator::TenderlyConfig, + http_factory: &HttpClientFactory, + chain_id: String, + ) -> Self { + let mut headers = reqwest::header::HeaderMap::new(); + let mut api_key = + HeaderValue::from_str(&config.api_key).expect("api key is correct header value"); + api_key.set_sensitive(true); + headers.insert("x-access-key", api_key); + + headers.insert(reqwest::header::ACCEPT, "application/json".parse().unwrap()); + headers.insert( + reqwest::header::CONTENT_TYPE, + "application/json".parse().unwrap(), + ); + Self { + api_base: Url::parse(&format!( + "{url}/v1/account/{user}/project/{project}/", + url = config + .url + .as_ref() + .map(ToString::to_string) + .unwrap_or_else(|| API_URL.to_owned()), + user = config.user, + project = config.project + )) + .expect("api url is valid Url"), + dashboard: Url::parse(&format!( + "{dashboard}/{user}/{project}/", + dashboard = config + .dashboard + .as_ref() + .map(ToString::to_string) + .unwrap_or_else(|| DASHBOARD_URL.to_owned()), + user = config.user, + project = config.project + )) + .expect("dashboard url is valid Url"), + client: http_factory.configure(|builder| builder.default_headers(headers)), + chain_id, + } + } + + pub fn new_instrumented( + name: String, + config: &configs::simulator::TenderlyConfig, + http_factory: &HttpClientFactory, + chain_id: String, + ) -> Instrumented { + Instrumented { + inner: Self::new(config, http_factory, chain_id), + name, + } + } +} + +#[async_trait::async_trait] +impl Api for TenderlyApi { + fn log_simulation_command( + &self, + tx: TransactionRequest, + overrides: StateOverride, + block: BlockNo, + ) -> Result<()> { + let request = dto::Request { + save: Some(true), + save_if_fails: Some(true), + ..prepare_request(self.chain_id.clone(), &tx, overrides, block)? + }; + let simulate_url = crate::utils::join_url(&self.api_base, "simulate"); + log_simulation_request(&simulate_url, &self.dashboard, request) + } + + async fn simulate(&self, request: dto::Request) -> Result { + let body = serde_json::to_string(&request).map_err(|err| Error::Other(anyhow!(err)))?; + + let simulate_url = crate::utils::join_url(&self.api_base, "simulate"); + let response = self.client.post(simulate_url).body(body).send().await?; + + let ok = response.error_for_status_ref().map(|_| ()); + let status = response.status(); + let body = response.text().await?; + // NOTE: Turn these logs on at your own risk... The Tenderly response + // objects are huge (order of ~3M). + tracing::trace!(status =% status.as_u16(), %body, "simulated"); + + ok?; + + Ok(serde_json::from_str::(&body)?) + } + + async fn simulate_and_share(&self, request: dto::Request) -> Result { + let response = self.simulate(request).await?; + let id = &response.simulation.id; + self.share_simulation(id).await?; + Ok(shared_simulation_url(id)) + } +} + +impl TenderlyApi { + async fn share_simulation(&self, id: &str) -> Result<()> { + let url = crate::utils::join_url(&self.api_base, &format!("simulations/{id}/share")); + self.client.post(url).send().await?.error_for_status()?; + Ok(()) + } +} + +fn shared_simulation_url(id: &str) -> String { + format!("{DASHBOARD_URL}/shared/simulation/{id}") +} + +pub fn prepare_request( + chain_id: String, + tx: &TransactionRequest, + overrides: StateOverride, + block: BlockNo, +) -> Result { + Ok(dto::Request { + // By default, tenderly simulates the given transaction as if it happened somewhere in + // the given block number, while nodes simulate the transaction as if it + // happened at the very end of the given block. This could be achieved in + // tenderly with `transaction_index: -1` but this is extremely costly to + // simulate which is why we craft the request to simulate the tx on the very + // first index of the **next** block. In practice the different will be that + // tenderly's simulation will already use the block number and timestamp of + // the **next** block that would be mined which is arguably more correct than + // the original simulation. + block_number: Some(block.0 + 1), + transaction_index: Some(0), + network_id: chain_id, + from: tx.from.unwrap_or_default(), + to: tx.to.and_then(TxKind::into_to).unwrap_or_default(), + input: tx.input.clone().into_input().unwrap_or_default().to_vec(), + gas: tx.gas, + gas_price: tx + .gas_price + .map(TryInto::try_into) + .map(|gas_price| gas_price.unwrap()), + value: tx.value, + simulation_type: Some(dto::SimulationType::Full), + state_objects: Some( + overrides + .into_iter() + .map(|(key, value)| Ok((key, value.try_into()?))) + .collect::>()?, + ), + access_list: tx.access_list.as_ref().map(Into::into), + ..Default::default() + }) +} + +pub fn log_simulation_request( + simulation_endpoint: &Url, + dashboard: &Url, + simulation: dto::Request, +) -> Result<()> { + let simulation_url = crate::utils::join_url(dashboard, "simulator/$SIMULATION_ID").to_string(); + let body = serde_json::to_string(&simulation)?; + + #[rustfmt::skip] + tracing::debug!( + "resimulate by setting TENDERLY_API_KEY environment variable and running: \ + curl -X POST -H \"X-ACCESS-KEY: $TENDERLY_API_KEY\" -H \"Content-Type: application/json\" --data '{body}' {simulation_endpoint} \ + | jq -r \".simulation.id\" \ + | read SIMULATION_ID; \ + echo {simulation_url} \ + | xargs xdg-open", + simulation_url = simulation_url + ); + + Ok(()) +} + +#[derive(Debug)] +pub struct Simulation { + pub id: SimulationId, + pub gas: Gas, + pub access_list: AccessList, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum GenerateAccessList { + Yes, + No, +} + +impl From for Simulation { + fn from(value: dto::Response) -> Self { + Simulation { + id: SimulationId(value.simulation.id), + gas: value.transaction.gas_used.into(), + access_list: value.generated_access_list.unwrap_or_default().into(), + } + } +} + +/// Instrumented Tenderly HTTP API. +pub struct Instrumented { + inner: TenderlyApi, + name: String, +} + +#[async_trait::async_trait] +impl Api for Instrumented { + async fn simulate(&self, simulation: dto::Request) -> Result { + let result = self.inner.simulate(simulation).await; + + Metrics::get() + .tenderly_simulations + .with_label_values(&[ + self.name.as_str(), + match &result { + Ok(_) => "ok", + Err(_) => "err", + }, + ]) + .inc(); + + result + } + + fn log_simulation_command( + &self, + tx: TransactionRequest, + overrides: StateOverride, + block: BlockNo, + ) -> Result<()> { + self.inner.log_simulation_command(tx, overrides, block) + } + + async fn simulate_and_share(&self, request: dto::Request) -> Result { + self.inner.simulate_and_share(request).await + } +} + +#[derive(prometheus_metric_storage::MetricStorage)] +struct Metrics { + /// Tenderly simulations. + #[metric(labels("name", "result"))] + tenderly_simulations: IntGaugeVec, +} + +impl Metrics { + fn get() -> &'static Metrics { + Metrics::instance(observe::metrics::get_storage_registry()).unwrap() + } +} + +#[derive(Debug, Error)] +#[error("tenderly error")] +pub enum Error { + Http(#[from] reqwest::Error), + Revert(SimulationId), + Other(#[from] anyhow::Error), +} diff --git a/crates/simulator/src/utils/mod.rs b/crates/simulator/src/utils/mod.rs new file mode 100644 index 0000000000..43d2b15c96 --- /dev/null +++ b/crates/simulator/src/utils/mod.rs @@ -0,0 +1,14 @@ +use url::Url; + +/// Join a path with a URL, ensuring that there is only one slash between them. +/// It doesn't matter if the URL ends with a slash or the path starts with one. +pub fn join_url(url: &Url, mut path: &str) -> Url { + let mut url = url.to_string(); + while url.ends_with('/') { + url.pop(); + } + while path.starts_with('/') { + path = &path[1..] + } + Url::parse(&format!("{url}/{path}")).expect("\"path\" contains a valid path segement") +} diff --git a/crates/simulator/tests/aave_replay.rs b/crates/simulator/tests/aave_replay.rs new file mode 100644 index 0000000000..a6e4bec6f3 --- /dev/null +++ b/crates/simulator/tests/aave_replay.rs @@ -0,0 +1,318 @@ +use { + alloy_primitives::{U256, address, hex}, + app_data::{AppDataHash, hash_full_app_data}, + model::{ + order::{BuyTokenDestination, OrderData, OrderKind, SellTokenSource}, + signature::Signature, + }, + simulator::simulation_builder::{ + self, + Block, + EthCallInputs, + ExecutionAmount, + PriceEncoding, + SettlementSimulator, + Solver, + }, + std::{str::FromStr, sync::Arc}, +}; + +/// Full `app_data` JSON the trader signed for the replayed Aave v3 debt-swap +/// order. Source-level whitespace is for readability only - run through +/// `canonicalise_app_data` before hashing or passing downstream. +const APP_DATA: &str = r#"{ + "appCode": "aave-v3-interface-debt-swap", + "metadata": { + "flashloan": { + "amount": "4475596734006878742", + "liquidityProvider": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", + "protocolAdapter": "0xdeCC46a4b09162F5369c5C80383AAa9159bCf192", + "receiver": "0xdeCC46a4b09162F5369c5C80383AAa9159bCf192", + "token": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + }, + "hooks": { + "post": [{ + "callData": "0xad3da559000000000000000000000000000000000000000000000000444d51cbc68377680000000000000000000000000000000000000000000000000000000069f323f8000000000000000000000000000000000000000000000000000000000000001c445675473b3e0941842eb5405ec1d9cb93c7d64b513b30d928d7ea42067440cb00fbafa80085d754964d5d70f616d899049f4e75c240fda7c2f108a99c882e8b", + "dappId": "cow-sdk://flashloans/aave/v3/debt-swap", + "gasLimit": "1000000", + "target": "0xe58aCB86761699c1cBC665e6b7E0271503f6336C" + }], + "pre": [{ + "callData": "0xb1b6308b00000000000000000000000073e7af13ef172f13d8fefebfd90c7a65300963440000000000000000000000006276ac03090f2bb8be680178343ac368f713b4e8000000000000000000000000e58acb86761699c1cbc665e6b7e0271503f6336c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f0000000000000000000000000000000000000000000000003e14904047a25ee600000000000000000000000000000000000000000000021e4382edd5a86c00006ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc0000000000000000000000000000000000000000000000000000000069f323f80000000000000000000000000000000000000000000000003e1c83845060e2160000000000000000000000000000000000000000000000000007f34408be83300000000000000000000000000000000000000000000000003e1c83845060e21600000000000000000000000000000000000000000000021e4382edd5a86c0000", + "dappId": "cow-sdk://flashloans/aave/v3/debt-swap", + "gasLimit": "300000", + "target": "0xdeCC46a4b09162F5369c5C80383AAa9159bCf192" + }] + }, + "orderClass": {"orderClass": "market"}, + "partnerFee": {"recipient": "0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c", "volumeBps": 0}, + "quote": {"slippageBips": 140, "smartSlippage": true}, + "utm": { + "utmCampaign": "developer-cohort", + "utmContent": "", + "utmMedium": "cow-sdk@7.3.4", + "utmSource": "cowmunity", + "utmTerm": "js" + } + }, + "version": "1.14.0" +}"#; + +/// Minifies `app_data` with keys sorted alphabetically. +fn canonicalise_app_data(app_data: &str) -> String { + let value: serde_json::Value = + serde_json::from_str(app_data).expect("APP_DATA must be valid JSON"); + serde_json::to_string(&value).expect("re-serialising must succeed") +} + +/// Production EIP-1271 signature blob for the replayed order. +const SIGNATURE_HEX: &str = "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000e58acb86761699c1cbc665e6b7e0271503f6336c0000000000000000000000000000000000000000000000003e14904047a25ee600000000000000000000000000000000000000000000021e4382edd5a86c00000000000000000000000000000000000000000000000000000000000069f323f8a1435054976e030f531f620f051bbabe34ef387901808b8677cf7c9304c21f3c00000000000000000000000000000000000000000000000000000000000000006ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc00000000000000000000000000000000000000000000000000000000000000005a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc95a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc900000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000041bb5488854dd5149f8843514851b7e25499917ca742af77061d2355681f3b608157bb34a59f9632e2228ea869c6d571f822295ee2eb03904dd8dd874245478f3b1b00000000000000000000000000000000000000000000000000000000000000"; + +/// AAVE v3 debt-swap order +/// `0x7f5df255b55f5eba3034f74acb8e91a04aaf61a755b88c61ad7c61068856f3b2e58acb86761699c1cbc665e6b7e0271503f6336c69f323f8`, +/// owner is an EIP-1167 minimal proxy the pre-hook deploys JIT. +/// +/// We exercise `SettlementSimulator` directly instead of going through +/// `OrderValidator::validate_and_construct_order`, which bounds `valid_to` +/// by `SystemTime::now()` and would make this test rot. +#[tokio::test] +#[ignore] +async fn aave_debt_swap_replay() { + let Ok(rpc_url) = std::env::var("MAINNET_RPC_URL") else { + eprintln!("MAINNET_RPC_URL not set - skipping replay test"); + return; + }; + + let canonical_app_data = canonicalise_app_data(APP_DATA); + let inputs = build_replay_simulation(&rpc_url, &canonical_app_data).await; + + inputs + .simulate() + .await + .expect("simulation must not revert for a healthy production order"); +} + +/// Same order, but the `flashloan.amount` in `app_data` is rewritten to a +/// value Aave's WETH pool cannot satisfy. The wrapper call to the Aave Pool +/// must revert, and the simulation must propagate that revert. +/// +/// This proves the prototype actually executes the flashloan path: if the +/// wrapper call were a silent no-op (e.g. wrong router address), the +/// simulation would not depend on Aave's liquidity at all and would not +/// fail here. +#[tokio::test] +#[ignore] +async fn aave_debt_swap_replay_fails_when_flashloan_oversubscribed() { + let Ok(rpc_url) = std::env::var("MAINNET_RPC_URL") else { + eprintln!("MAINNET_RPC_URL not set - skipping replay test"); + return; + }; + + let mut value: serde_json::Value = + serde_json::from_str(APP_DATA).expect("APP_DATA must be valid JSON"); + // Way more WETH than Aave can lend. Aave reverts with insufficient + // liquidity (or similar) before any settlement runs. + value["metadata"]["flashloan"]["amount"] = serde_json::Value::String(U256::MAX.to_string()); + let tampered_app_data = serde_json::to_string(&value).unwrap(); + + let inputs = build_replay_simulation(&rpc_url, &tampered_app_data).await; + + let err = inputs + .simulate() + .await + .expect_err("simulation must revert when the flashloan exceeds Aave liquidity"); + let msg = format!("{err:?}"); + assert!( + msg.contains("execution reverted"), + "expected an EVM revert, got: {msg}", + ); +} + +/// Shared builder for the positive replay (`APP_DATA`) and the +/// flashloan-tampered negative replay. +async fn build_replay_simulation(rpc_url: &str, full_app_data: &str) -> EthCallInputs { + // Pinned one block before the on-chain settlement: pre-hook hasn't + // yet deployed the owner contract, Aave has WETH liquidity. + let fork_block_mainnet = 24_992_051u64; + let order_owner = address!("e58aCB86761699c1cBC665e6b7E0271503f6336C"); + let sell_token_weth = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); + let buy_token_gho = address!("40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f"); + let sell_amount = U256::from_str("4473358935639875302").unwrap(); + let buy_amount = U256::from_str("10003000000000000000000").unwrap(); + let valid_to = 1_777_542_136u32; // 2026-04-30 09:42:16 UTC + + let web3 = ethrpc::Web3::new_from_url(rpc_url); + let provider = web3.provider.clone(); + let chain_id = 1u64; + + let settlement = contracts::GPv2Settlement::Instance::deployed(&provider) + .await + .expect("settlement contract not deployed on mainnet?"); + + let flash_loan_router = contracts::FlashLoanRouter::deployment_address(&chain_id) + .expect("FlashLoanRouter deployment address"); + let hooks_trampoline = contracts::HooksTrampoline::deployment_address(&chain_id) + .expect("HooksTrampoline deployment address"); + + let balance_overrider = Arc::new(balance_overrides::StateOverrides::new(web3)); + let block_stream = ethrpc::block_stream::mock_single_block(Default::default()); + + let simulator = SettlementSimulator::new( + settlement, + flash_loan_router, + hooks_trampoline, + sell_token_weth, + 30_000_000u64, + balance_overrider, + block_stream, + None, + ) + .await + .expect("failed to create SettlementSimulator"); + + let signature_bytes = hex::decode(SIGNATURE_HEX.trim_start_matches("0x")) + .expect("SIGNATURE_HEX must be valid hex"); + let app_data_hash = AppDataHash(hash_full_app_data(full_app_data.as_bytes())); + + let order_data = OrderData { + sell_token: sell_token_weth, + buy_token: buy_token_gho, + receiver: Some(order_owner), + sell_amount, + buy_amount, + valid_to, + app_data: app_data_hash, + fee_amount: U256::ZERO, + kind: OrderKind::Buy, + partially_fillable: false, + sell_token_balance: SellTokenSource::Erc20, + buy_token_balance: BuyTokenDestination::Erc20, + }; + + let sim_order = simulation_builder::Order::new(order_data) + .with_signature(order_owner, Signature::Eip1271(signature_bytes)) + .fill_at(ExecutionAmount::Full, PriceEncoding::LimitPrice); + + simulator + .new_simulation_builder() + .with_orders([sim_order]) + .parameters_from_app_data(full_app_data) + .expect("parameters_from_app_data should parse the app data") + .from_solver(Solver::Fake(None)) + .provide_sufficient_buy_tokens() + .at_block(Block::Number(fork_block_mainnet)) + .build() + .await + .expect("failed to build simulation") +} + +/// AAVE v3 collateral-swap order +/// `0x441ad034a3c8cd9ad0fc9a9d143c8201bc92d62851a8428997c36a89a03ee2ad4caea9074f2897a3a4ac173c4e5b5bd8b7e3dc976b5f9c6f` +/// which reverts onchain due to corrupted hooks +const NATURALLY_FAILING_APP_DATA: &str = r#"{"appCode":"aave-v3-interface-collateral-swap","metadata":{"flashloan":{"amount":"6136714","liquidityProvider":"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2","protocolAdapter":"0xdeCC46a4b09162F5369c5C80383AAa9159bCf192","receiver":"0xdeCC46a4b09162F5369c5C80383AAa9159bCf192","token":"0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"},"hooks":{"post":[{"callData":"0x398925de00000000000000000000000000000000000000000000000000000000006700b10000000000000000000000000000000000000000000000000000000069850ebf000000000000000000000000000000000000000000000000000000000000001bb32da7ed8403b8369956ffc15f4c1295953004866fa786c0162d28bea3d18b3b08466a876f9a0cb5d1175ef44838426558b19d64b48002231a8c1c90821e08a4","dappId":"cow-sdk://flashloans/aave/v3/collateral-swap","gasLimit":"700000","target":"0x4CAea9074f2897a3A4ac173C4E5b5Bd8b7E3Dc97"}],"pre":[{"callData":"0xb1b6308b000000000000000000000000029d584e847373b6373b01dfad1a0c9bfb9163820000000000000000000000004ec7efb8c873f54c5f62830ec5ecc2362580bdfe0000000000000000000000004caea9074f2897a3a4ac173c4e5b5bd8b7e3dc970000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000005d978d00000000000000000000000000000000000000000000000000000000c9f769e0f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775000000000000000000000000000000000000000000000000000000006b5f9c6f00000000000000000000000000000000000000000000000000000000005da38a0000000000000000000000000000000000000000000000000000000000000bfd00000000000000000000000000000000000000000000000000000000005da38a00000000000000000000000000000000000000000000000000000000c9f769e0","dappId":"cow-sdk://flashloans/aave/v3/collateral-swap","gasLimit":"300000","target":"0xdeCC46a4b09162F5369c5C80383AAa9159bCf192"}]},"orderClass":{"orderClass":"limit"},"partnerFee":{"recipient":"0xC542C2F197c4939154017c802B0583C596438380","volumeBps":25},"quote":{"slippageBips":0,"smartSlippage":true},"utm":{"utmCampaign":"developer-cohort","utmContent":"","utmMedium":"cow-sdk@7.3.4","utmSource":"cowmunity","utmTerm":"js"}},"version":"1.14.0"}"#; + +const NATURALLY_FAILING_SIGNATURE_HEX: &str = "0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000004caea9074f2897a3a4ac173c4e5b5bd8b7e3dc9700000000000000000000000000000000000000000000000000000000005d978d00000000000000000000000000000000000000000000000000000000c9f769e0000000000000000000000000000000000000000000000000000000006b5f9c6f4223823feadc36c4373c9d88ac1e9875d067e3df5ced70c0a1fedcec396f34d10000000000000000000000000000000000000000000000000000000000000000f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677500000000000000000000000000000000000000000000000000000000000000005a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc95a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc900000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000041dd46f4ee5ab3d65846780582c116a93cf37d99be5c87ed1638e3f52bc39861b91595d66c1afd17d585d6ccdbe7b643a2d44b46d1a919f479224e49934c293f231c00000000000000000000000000000000000000000000000000000000000000"; + +/// Replay of a real production order that the mainnet driver was repeatedly +/// dropping with `Simulation(Revert(_))`. The pre-hook reverts because the +/// trader's aToken balance is insufficient for the collateral swap. +#[tokio::test] +#[ignore] +async fn aave_collateral_swap_replay_fails_naturally() { + let Ok(rpc_url) = std::env::var("MAINNET_RPC_URL") else { + eprintln!("MAINNET_RPC_URL not set - skipping replay test"); + return; + }; + + let canonical_app_data = canonicalise_app_data(NATURALLY_FAILING_APP_DATA); + let inputs = build_naturally_failing_replay_simulation(&rpc_url, &canonical_app_data).await; + + let err = inputs + .simulate() + .await + .expect_err("simulation must revert: pre-hook moves aToken the trader no longer holds"); + let msg = format!("{err:?}"); + assert!( + msg.contains("execution reverted"), + "expected an EVM revert, got: {msg}", + ); +} + +async fn build_naturally_failing_replay_simulation( + rpc_url: &str, + full_app_data: &str, +) -> EthCallInputs { + // Block taken from a `BlockNo(...)` embedded in one of the dropped- + // solution events for this order on 2026-05-05. + let fork_block_mainnet = 25_028_258u64; + let chain_id = 1u64; + let order_owner = address!("4caea9074f2897a3a4ac173c4e5b5bd8b7e3dc97"); + let sell_token_a_wbtc = address!("2260fac5e5542a773aa44fbcfedf7c193bc2c599"); + let buy_token_usdt = address!("dac17f958d2ee523a2206206994597c13d831ec7"); + let sell_amount = U256::from_str("6133645").unwrap(); + let buy_amount = U256::from_str("3388434912").unwrap(); + let valid_to = 1_801_428_079u32; // 2027-01-31 ish + + let web3 = ethrpc::Web3::new_from_url(rpc_url); + let provider = web3.provider.clone(); + + let settlement = contracts::GPv2Settlement::Instance::deployed(&provider) + .await + .expect("settlement contract not deployed on mainnet?"); + + let flash_loan_router = contracts::FlashLoanRouter::deployment_address(&chain_id) + .expect("FlashLoanRouter deployment address"); + let hooks_trampoline = contracts::HooksTrampoline::deployment_address(&chain_id) + .expect("HooksTrampoline deployment address"); + + let balance_overrider = Arc::new(balance_overrides::StateOverrides::new(web3)); + let block_stream = ethrpc::block_stream::mock_single_block(Default::default()); + + let simulator = SettlementSimulator::new( + settlement, + flash_loan_router, + hooks_trampoline, + sell_token_a_wbtc, + 30_000_000u64, + balance_overrider, + block_stream, + None, + ) + .await + .expect("failed to create SettlementSimulator"); + + let signature_bytes = hex::decode(NATURALLY_FAILING_SIGNATURE_HEX.trim_start_matches("0x")) + .expect("NATURALLY_FAILING_SIGNATURE_HEX must be valid hex"); + let app_data_hash = AppDataHash(hash_full_app_data(full_app_data.as_bytes())); + + let order_data = OrderData { + sell_token: sell_token_a_wbtc, + buy_token: buy_token_usdt, + receiver: Some(order_owner), + sell_amount, + buy_amount, + valid_to, + app_data: app_data_hash, + fee_amount: U256::ZERO, + kind: OrderKind::Sell, + partially_fillable: false, + sell_token_balance: SellTokenSource::Erc20, + buy_token_balance: BuyTokenDestination::Erc20, + }; + + let sim_order = simulation_builder::Order::new(order_data) + .with_signature(order_owner, Signature::Eip1271(signature_bytes)) + .fill_at(ExecutionAmount::Full, PriceEncoding::LimitPrice); + + simulator + .new_simulation_builder() + .with_orders([sim_order]) + .parameters_from_app_data(full_app_data) + .expect("parameters_from_app_data should parse the app data") + .from_solver(Solver::Fake(None)) + .provide_sufficient_buy_tokens() + .at_block(Block::Number(fork_block_mainnet)) + .build() + .await + .expect("failed to build simulation") +} diff --git a/crates/solana-indexer/Cargo.toml b/crates/solana-indexer/Cargo.toml new file mode 100644 index 0000000000..36f20d9afa --- /dev/null +++ b/crates/solana-indexer/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "solana-indexer" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "GPL-3.0-or-later" +description = "Solana settlement indexer for CoW Protocol" +repository = "https://github.com/cowprotocol/services" + +[lib] +name = "solana_indexer" +path = "src/lib.rs" + +[[bin]] +name = "solana-indexer" +path = "src/main.rs" + +[lints] +workspace = true diff --git a/crates/solana-indexer/src/lib.rs b/crates/solana-indexer/src/lib.rs new file mode 100644 index 0000000000..621806e9a0 --- /dev/null +++ b/crates/solana-indexer/src/lib.rs @@ -0,0 +1 @@ +//! `solana-indexer` — Solana settlement indexer. diff --git a/crates/solana-indexer/src/main.rs b/crates/solana-indexer/src/main.rs new file mode 100644 index 0000000000..b937447eca --- /dev/null +++ b/crates/solana-indexer/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("solana-indexer starting"); +} diff --git a/crates/solver/Cargo.toml b/crates/solver/Cargo.toml index 0f6e8d6f23..89a0ca60af 100644 --- a/crates/solver/Cargo.toml +++ b/crates/solver/Cargo.toml @@ -6,44 +6,43 @@ edition = "2024" license = "GPL-3.0-or-later" [lib] +doctest = false name = "solver" path = "src/lib.rs" -doctest = false [dependencies] alloy = { workspace = true } anyhow = { workspace = true } arc-swap = { workspace = true } async-trait = { workspace = true } +const-hex = { workspace = true } contracts = { workspace = true } -ethcontract = { workspace = true } ethrpc = { workspace = true } futures = { workspace = true } -observe = { workspace = true } -const-hex = { workspace = true } hex-literal = { workspace = true } itertools = { workspace = true } -maplit = { workspace = true } +liquidity-sources = { workspace = true } model = { workspace = true } num = { workspace = true } number = { workspace = true } -primitive-types = { workspace = true } +observe = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } serde_json = { workspace = true } shared = { workspace = true } +simulator = { workspace = true } strum = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } tracing = { workspace = true } -web3 = { workspace = true } [dev-dependencies] -derivative = { workspace = true } -tokio = { workspace = true, features = ["test-util"] } -testlib = { workspace = true } +ethrpc = { workspace = true, features = ["test-util"] } +liquidity-sources = { workspace = true, features = ["test-util"] } +maplit = { workspace = true } mockall = { workspace = true } shared = { workspace = true, features = ["test-util"] } -ethrpc = {workspace = true, features = ["test-util"]} +testlib = { workspace = true } +tokio = { workspace = true, features = ["test-util"] } [lints] workspace = true diff --git a/crates/solver/src/interactions/allowances.rs b/crates/solver/src/interactions/allowances.rs deleted file mode 100644 index 3808a9da08..0000000000 --- a/crates/solver/src/interactions/allowances.rs +++ /dev/null @@ -1,431 +0,0 @@ -//! Module containing a general ERC20 allowance manager that allows components -//! and interactions to query allowances to various contracts as well as keep -//! generate interactions for them. - -use { - crate::interactions::Erc20ApproveInteraction, - ::alloy::sol_types::SolCall, - anyhow::{Context as _, Result, anyhow, ensure}, - contracts::alloy::ERC20, - ethcontract::{H160, U256}, - ethrpc::{Web3, alloy::conversions::IntoAlloy}, - maplit::hashmap, - shared::{ - http_solver::model::TokenAmount, - interaction::{EncodedInteraction, Interaction}, - }, - std::{ - collections::{HashMap, HashSet}, - slice, - }, - web3::types::CallRequest, -}; - -#[cfg_attr(test, mockall::automock)] -#[async_trait::async_trait] -pub trait AllowanceManaging: Send + Sync { - /// Retrieves allowances of the specified tokens for a given spender. - /// - /// This can be used to cache allowances for a bunch of tokens so that they - /// can be used within a context that doesn't allow `async` or errors. - async fn get_allowances(&self, tokens: HashSet, spender: H160) -> Result; - - /// Returns the approval interaction for the specified token and spender for - /// at least the specified amount, if an approval is required. - async fn get_approval(&self, request: &ApprovalRequest) -> Result> { - Ok(self.get_approvals(slice::from_ref(request)).await?.pop()) - } - - /// Returns the requried approval interaction for the requests. - /// Does not return approvals when they aren't required. - async fn get_approvals(&self, requests: &[ApprovalRequest]) -> Result>; -} - -#[derive(Debug, Eq, PartialEq)] -pub struct ApprovalRequest { - pub token: H160, - pub spender: H160, - pub amount: U256, -} - -#[derive(Debug, Eq, PartialEq)] -pub struct Allowances { - spender: H160, - allowances: HashMap, -} - -impl Allowances { - pub fn new(spender: H160, allowances: HashMap) -> Self { - Self { - spender, - allowances, - } - } - - pub fn empty(spender: H160) -> Self { - Self::new(spender, HashMap::new()) - } - - /// Gets the approval interaction for the specified token and amount. - pub fn approve_token(&self, token_amount: TokenAmount) -> Result> { - let allowance = self - .allowances - .get(&token_amount.token) - .copied() - .ok_or_else(|| anyhow!("missing allowance for token {:?}", token_amount.token))?; - - Ok(if allowance < token_amount.amount { - Some(Approval { - token: token_amount.token, - spender: self.spender, - }) - } else { - None - }) - } - - /// Gets the token approval, unconditionally approving in case the token - /// allowance is missing. - pub fn approve_token_or_default(&self, token_amount: TokenAmount) -> Option { - let token = token_amount.token; - - self.approve_token(token_amount).unwrap_or(Some(Approval { - token, - spender: self.spender, - })) - } - - /// Extends the allowance cache with another. - pub fn extend(&mut self, other: Self) -> Result<()> { - ensure!( - self.spender == other.spender, - "failed to extend allowance cache for different spender" - ); - self.allowances.extend(other.allowances); - - Ok(()) - } -} - -/// An ERC20 approval interaction. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Approval { - pub token: H160, - pub spender: H160, -} - -impl Interaction for Approval { - fn encode(&self) -> EncodedInteraction { - let approve = Erc20ApproveInteraction { - token: self.token.into_alloy(), - spender: self.spender.into_alloy(), - amount: alloy::primitives::U256::MAX, - }; - - approve.encode() - } -} - -/// An allowance manager that retrive approval interactions for a given owner -/// address. -pub struct AllowanceManager { - web3: Web3, - owner: H160, -} - -impl AllowanceManager { - pub fn new(web3: Web3, owner: H160) -> Self { - Self { web3, owner } - } -} - -#[async_trait::async_trait] -impl AllowanceManaging for AllowanceManager { - async fn get_allowances(&self, tokens: HashSet, spender: H160) -> Result { - Ok(fetch_allowances( - self.web3.clone(), - self.owner, - hashmap! { spender => tokens }, - ) - .await? - .remove(&spender) - .unwrap_or_else(|| Allowances::empty(spender))) - } - - async fn get_approvals(&self, requests: &[ApprovalRequest]) -> Result> { - let mut spender_tokens = HashMap::<_, HashSet<_>>::new(); - for request in requests { - spender_tokens - .entry(request.spender) - .or_default() - .insert(request.token); - } - - let allowances = fetch_allowances(self.web3.clone(), self.owner, spender_tokens).await?; - let mut result = Vec::new(); - for request in requests { - let allowance = allowances - .get(&request.spender) - .with_context(|| format!("no allowances found for spender {}", request.spender))? - .approve_token(TokenAmount::new(request.token, request.amount))?; - result.extend(allowance); - } - Ok(result) - } -} - -async fn fetch_allowances( - web3: Web3, - owner: H160, - spender_tokens: HashMap>, -) -> Result> -where - T: ethcontract::web3::BatchTransport + Send + Sync + 'static, - T::Batch: Send, - T::Out: Send, -{ - let futures = spender_tokens - .into_iter() - .flat_map(|(spender, tokens)| tokens.into_iter().map(move |token| (spender, token))) - .map(|(spender, token)| { - let web3 = web3.clone(); - - async move { - let calldata = ERC20::ERC20::allowanceCall { - owner: owner.into_alloy(), - spender: spender.into_alloy(), - } - .abi_encode(); - let req = CallRequest::builder() - .to(token) - .data(calldata.into()) - .build(); - let allowance = web3.eth().call(req, None).await; - (spender, token, allowance) - } - }); - let results: Vec<_> = futures::future::join_all(futures).await; - - let mut allowances = HashMap::new(); - for (spender, token, allowance) in results { - let allowance = match allowance { - Ok(value) => U256::from(value.0.as_slice()), - Err(err) => { - tracing::warn!("error retrieving allowance for token {:?}: {}", token, err); - continue; - } - }; - - allowances - .entry(spender) - .or_insert_with(|| Allowances::empty(spender)) - .allowances - .insert(token, allowance); - } - - Ok(allowances) -} - -#[cfg(test)] -mod tests { - use { - super::*, - alloy::sol_types::SolCall, - ethcontract::{ - common::abi::{self, Token}, - web3::types::CallRequest, - }, - ethrpc::mock, - maplit::{hashmap, hashset}, - serde_json::{Value, json}, - shared::addr, - }; - - #[test] - fn approval_when_allowance_is_sufficient() { - let token = H160([0x02; 20]); - let allowances = Allowances::new( - H160([0x01; 20]), - hashmap! { - token => U256::from(100), - }, - ); - - assert_eq!( - allowances - .approve_token(TokenAmount::new(token, 42)) - .unwrap(), - None - ); - assert_eq!( - allowances - .approve_token(TokenAmount::new(token, 100)) - .unwrap(), - None - ); - } - - #[test] - fn approval_when_allowance_is_insufficient() { - let spender = H160([0x01; 20]); - let token = H160([0x02; 20]); - let allowances = Allowances::new( - spender, - hashmap! { - token => U256::from(100), - }, - ); - - assert_eq!( - allowances - .approve_token(TokenAmount::new(token, 1337)) - .unwrap(), - Some(Approval { token, spender }) - ); - } - - #[test] - fn approval_for_missing_token() { - let allowances = Allowances::new( - H160([0x01; 20]), - hashmap! { - H160([0x02; 20]) => U256::from(100), - }, - ); - - assert!( - allowances - .approve_token(TokenAmount::new(H160([0x03; 20]), 0)) - .is_err() - ); - } - - #[test] - fn approval_or_default_for_missing_token() { - let spender = H160([0x01; 20]); - let token = H160([0x02; 20]); - let allowances = Allowances::new(spender, hashmap! {}); - - assert_eq!( - allowances.approve_token_or_default(TokenAmount::new(token, 1337)), - Some(Approval { token, spender }) - ); - } - - #[test] - fn extend_allowances_cache() { - let mut allowances = Allowances::new( - H160([0x01; 20]), - hashmap! { - H160([0x11; 20]) => U256::from(1), - H160([0x12; 20]) => U256::from(2), - }, - ); - allowances - .extend(Allowances::new( - H160([0x01; 20]), - hashmap! { - H160([0x11; 20]) => U256::from(42), - H160([0x13; 20]) => U256::from(3), - }, - )) - .unwrap(); - - assert_eq!( - allowances.allowances, - hashmap! { - H160([0x11; 20]) => U256::from(42), - H160([0x12; 20]) => U256::from(2), - H160([0x13; 20]) => U256::from(3), - }, - ); - } - - #[test] - fn error_extending_allowances_for_different_spenders() { - let mut allowances = Allowances::empty(H160([0x01; 20])); - assert!( - allowances - .extend(Allowances::empty(H160([0x02; 20]))) - .is_err() - ); - } - - #[test] - fn approval_encode_interaction() { - let token = H160([0x01; 20]); - let spender = H160([0x02; 20]); - assert_eq!( - Approval { token, spender }.encode(), - ( - token.into_alloy(), - alloy::primitives::U256::ZERO, - const_hex::decode( - "095ea7b3\ - 0000000000000000000000000202020202020202020202020202020202020202\ - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - ) - .unwrap().into() - ) - ); - } - - fn allowance_call_data(owner: H160, spender: H160) -> web3::types::Bytes { - contracts::alloy::ERC20::ERC20::allowanceCall { - owner: owner.into_alloy(), - spender: spender.into_alloy(), - } - .abi_encode() - .into() - } - - fn allowance_return_data(value: U256) -> Value { - json!(web3::types::Bytes(abi::encode(&[Token::Uint(value)]))) - } - - #[tokio::test] - async fn fetch_skips_failed_allowance_calls() { - let owner = H160([1; 20]); - let spender = H160([2; 20]); - - let web3 = mock::web3(); - web3.transport() - .mock() - .expect_execute() - .returning(move |method, params| { - assert_eq!(method, "eth_call"); - - let call = serde_json::from_value::(params[0].clone()).unwrap(); - assert_eq!(call.data.unwrap(), allowance_call_data(owner, spender)); - let to = call.to.unwrap(); - - if to == addr!("1111111111111111111111111111111111111111") { - Ok(allowance_return_data(1337.into())) - } else if to == addr!("2222222222222222222222222222222222222222") { - Err(web3::Error::Decoder("test error".to_string())) - } else { - panic!("call to unexpected token {to:?}") - } - }); - - let allowances = fetch_allowances( - web3, - owner, - hashmap! { - spender => hashset![H160([0x11; 20]), H160([0x22; 20])], - }, - ) - .await - .unwrap(); - - assert_eq!( - allowances, - hashmap! { - spender => Allowances { - spender, - allowances: hashmap! { H160([0x11; 20]) => 1337.into() }, - }, - }, - ); - } -} diff --git a/crates/solver/src/interactions/balancer_v2.rs b/crates/solver/src/interactions/balancer_v2.rs index f66b32d8c4..e94a748292 100644 --- a/crates/solver/src/interactions/balancer_v2.rs +++ b/crates/solver/src/interactions/balancer_v2.rs @@ -1,11 +1,9 @@ use { alloy::{ - primitives::{Address, U256}, + primitives::{Address, B256, Bytes, U256}, sol_types::SolCall, }, - contracts::alloy::BalancerV2Vault::{BalancerV2Vault::swapCall, IVault}, - ethcontract::{Bytes, H256}, - ethrpc::alloy::conversions::IntoAlloy, + contracts::BalancerV2Vault::{BalancerV2Vault::swapCall, IVault}, shared::{ http_solver::model::TokenAmount, interaction::{EncodedInteraction, Interaction}, @@ -17,10 +15,10 @@ use { pub struct BalancerSwapGivenOutInteraction { pub settlement: Address, pub vault: Address, - pub pool_id: H256, + pub pool_id: B256, pub asset_in_max: TokenAmount, pub asset_out: TokenAmount, - pub user_data: Bytes>, + pub user_data: Bytes, } /// An impossibly distant future timestamp. Note that we use `0x80000...00` @@ -31,12 +29,12 @@ pub static NEVER: LazyLock = LazyLock::new(|| U256::from(1) << 255); impl BalancerSwapGivenOutInteraction { pub fn encode_swap(&self) -> EncodedInteraction { let single_swap = IVault::SingleSwap { - poolId: self.pool_id.into_alloy(), + poolId: self.pool_id, kind: 1, // GivenOut - assetIn: self.asset_in_max.token.into_alloy(), - assetOut: self.asset_out.token.into_alloy(), - amount: self.asset_out.amount.into_alloy(), - userData: self.user_data.clone().into_alloy(), + assetIn: self.asset_in_max.token, + assetOut: self.asset_out.token, + amount: self.asset_out.amount, + userData: self.user_data.clone(), }; let funds = IVault::FundManagement { sender: self.settlement, @@ -48,7 +46,7 @@ impl BalancerSwapGivenOutInteraction { let method = swapCall { singleSwap: single_swap, funds, - limit: self.asset_in_max.amount.into_alloy(), + limit: self.asset_in_max.amount, deadline: *NEVER, } .abi_encode(); @@ -65,7 +63,7 @@ impl Interaction for BalancerSwapGivenOutInteraction { #[cfg(test)] mod tests { - use {super::*, primitive_types::H160}; + use super::*; #[test] fn encode_unwrap_weth() { @@ -73,9 +71,15 @@ mod tests { let interaction = BalancerSwapGivenOutInteraction { settlement: Address::from_slice(&[0x02; 20]), vault: vault_address, - pool_id: H256([0x03; 32]), - asset_in_max: TokenAmount::new(H160([0x04; 20]), 1_337_000_000_000_000_000_000u128), - asset_out: TokenAmount::new(H160([0x05; 20]), 42_000_000_000_000_000_000u128), + pool_id: B256::repeat_byte(0x03), + asset_in_max: TokenAmount::new( + Address::repeat_byte(0x04), + alloy::primitives::U256::from(1_337_000_000_000_000_000_000u128), + ), + asset_out: TokenAmount::new( + Address::repeat_byte(0x05), + alloy::primitives::U256::from(42_000_000_000_000_000_000u128), + ), user_data: Bytes::default(), }; @@ -122,7 +126,8 @@ mod tests { 00000000000000000000000000000000000000000000000000000000000000c0\ 0000000000000000000000000000000000000000000000000000000000000000" ) - .unwrap().into() + .unwrap() + .into() ) ); } diff --git a/crates/solver/src/interactions/erc20.rs b/crates/solver/src/interactions/erc20.rs index 975467d403..a52e42c2ad 100644 --- a/crates/solver/src/interactions/erc20.rs +++ b/crates/solver/src/interactions/erc20.rs @@ -5,7 +5,7 @@ use { primitives::{Address, U256}, sol_types::SolCall, }, - contracts::alloy::ERC20, + contracts::ERC20, shared::interaction::{EncodedInteraction, Interaction}, }; diff --git a/crates/solver/src/interactions/mod.rs b/crates/solver/src/interactions/mod.rs index 288f9932ed..08f9098962 100644 --- a/crates/solver/src/interactions/mod.rs +++ b/crates/solver/src/interactions/mod.rs @@ -1,4 +1,3 @@ -pub mod allowances; mod balancer_v2; mod erc20; mod uniswap_v2; diff --git a/crates/solver/src/interactions/uniswap_v2.rs b/crates/solver/src/interactions/uniswap_v2.rs index c5fe8acd97..6e7e69c08f 100644 --- a/crates/solver/src/interactions/uniswap_v2.rs +++ b/crates/solver/src/interactions/uniswap_v2.rs @@ -1,8 +1,9 @@ use { - alloy::{primitives::Address, sol_types::SolCall}, - contracts::alloy::IUniswapLikeRouter, - ethrpc::alloy::conversions::IntoAlloy, - primitive_types::{H160, U256}, + alloy::{ + primitives::{Address, U256}, + sol_types::SolCall, + }, + contracts::IUniswapLikeRouter, shared::interaction::{EncodedInteraction, Interaction}, }; @@ -12,8 +13,8 @@ pub struct UniswapInteraction { pub settlement: Address, pub amount_out: U256, pub amount_in_max: U256, - pub token_in: H160, - pub token_out: H160, + pub token_in: Address, + pub token_out: Address, } impl Interaction for UniswapInteraction { @@ -25,9 +26,9 @@ impl Interaction for UniswapInteraction { impl UniswapInteraction { pub fn encode_swap(&self) -> EncodedInteraction { let calldata = IUniswapLikeRouter::IUniswapLikeRouter::swapTokensForExactTokensCall { - amountOut: self.amount_out.into_alloy(), - amountInMax: self.amount_in_max.into_alloy(), - path: vec![self.token_in.into_alloy(), self.token_out.into_alloy()], + amountOut: self.amount_out, + amountInMax: self.amount_in_max, + path: vec![self.token_in, self.token_out], to: self.settlement, deadline: ::alloy::primitives::U256::MAX, } @@ -50,19 +51,19 @@ mod tests { fn encode_uniswap_call() { let amount_out = 5; let amount_in_max = 6; - let token_in = H160::from_low_u64_be(7); + let token_in = Address::with_last_byte(7); let token_out = 8; let payout_to = 9u8; let router_address = Address::from(&[1u8; 20]); - let settlement = H160::from_low_u64_be(payout_to as u64).into_alloy(); + let settlement = Address::with_last_byte(payout_to); let interaction = UniswapInteraction { router: router_address, settlement, - amount_out: amount_out.into(), - amount_in_max: amount_in_max.into(), + amount_out: U256::from(amount_out), + amount_in_max: U256::from(amount_in_max), token_in, - token_out: H160::from_low_u64_be(token_out as u64), + token_out: Address::with_last_byte(token_out), }; let swap_call = interaction.encode(); @@ -73,6 +74,7 @@ mod tests { let path_offset = 160; let path_size = 2; let deadline = [0xffu8; 32]; + assert_eq!(call[0..4], swap_signature); assert_eq!(call[4..36], u8_as_32_bytes_be(amount_out)); assert_eq!(call[36..68], u8_as_32_bytes_be(amount_in_max)); @@ -80,7 +82,7 @@ mod tests { assert_eq!(call[100..132], u8_as_32_bytes_be(payout_to)); assert_eq!(call[132..164], deadline); assert_eq!(call[164..196], u8_as_32_bytes_be(path_size)); - assert_eq!(&call[208..228], token_in.as_fixed_bytes()); + assert_eq!(&call[208..228], &token_in); assert_eq!(call[228..260], u8_as_32_bytes_be(token_out)); } } diff --git a/crates/solver/src/interactions/uniswap_v3.rs b/crates/solver/src/interactions/uniswap_v3.rs index 2552a77569..3cdeb8f852 100644 --- a/crates/solver/src/interactions/uniswap_v3.rs +++ b/crates/solver/src/interactions/uniswap_v3.rs @@ -3,7 +3,7 @@ use { primitives::{Address, U256}, sol_types::SolCall, }, - contracts::alloy::UniswapV3SwapRouterV2::{ + contracts::UniswapV3SwapRouterV2::{ IV3SwapRouter::ExactOutputSingleParams, UniswapV3SwapRouterV2::exactOutputSingleCall, }, diff --git a/crates/solver/src/interactions/weth.rs b/crates/solver/src/interactions/weth.rs index 97016384a1..79e27af0c9 100644 --- a/crates/solver/src/interactions/weth.rs +++ b/crates/solver/src/interactions/weth.rs @@ -1,7 +1,7 @@ use { alloy::primitives::U256, anyhow::{Result, ensure}, - contracts::alloy::WETH9, + contracts::WETH9, shared::interaction::{EncodedInteraction, Interaction}, }; @@ -46,7 +46,7 @@ mod tests { #[test] fn encode_unwrap_weth() { - let weth = WETH9::Instance::new([0x42; 20].into(), ethrpc::mock::web3().alloy); + let weth = WETH9::Instance::new([0x42; 20].into(), ethrpc::mock::web3().provider); let amount = U256::from(13_370_000_000_000_000_000u128); let interaction = UnwrapWethInteraction { weth: weth.clone(), @@ -66,11 +66,11 @@ mod tests { #[test] fn merge_same_native_token() { let mut unwrap0 = UnwrapWethInteraction { - weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().alloy), + weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().provider), amount: U256::ONE, }; let unwrap1 = UnwrapWethInteraction { - weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().alloy), + weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().provider), amount: U256::from(2), }; @@ -81,11 +81,11 @@ mod tests { #[test] fn merge_different_native_token() { let mut unwrap0 = UnwrapWethInteraction { - weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().alloy), + weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().provider), amount: U256::ONE, }; let unwrap1 = UnwrapWethInteraction { - weth: WETH9::Instance::new([0x02; 20].into(), ethrpc::mock::web3().alloy), + weth: WETH9::Instance::new([0x02; 20].into(), ethrpc::mock::web3().provider), amount: U256::from(2), }; @@ -97,11 +97,11 @@ mod tests { #[should_panic] fn merge_u256_overflow() { let mut unwrap0 = UnwrapWethInteraction { - weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().alloy), + weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().provider), amount: U256::ONE, }; let unwrap1 = UnwrapWethInteraction { - weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().alloy), + weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().provider), amount: U256::MAX, }; diff --git a/crates/solver/src/interactions/zeroex.rs b/crates/solver/src/interactions/zeroex.rs index 388acc79e6..445e48364c 100644 --- a/crates/solver/src/interactions/zeroex.rs +++ b/crates/solver/src/interactions/zeroex.rs @@ -1,10 +1,7 @@ use { - contracts::alloy::IZeroex, - ethrpc::alloy::conversions::IntoAlloy, - shared::{ - interaction::{EncodedInteraction, Interaction}, - zeroex_api::Order, - }, + contracts::IZeroex, + liquidity_sources::zeroex::Order, + shared::interaction::{EncodedInteraction, Interaction}, std::sync::Arc, }; @@ -20,24 +17,24 @@ impl Interaction for ZeroExInteraction { fn encode(&self) -> EncodedInteraction { let method = self.zeroex.fillOrKillLimitOrder( IZeroex::LibNativeOrder::LimitOrder { - makerToken: self.order.maker_token.into_alloy(), - takerToken: self.order.taker_token.into_alloy(), + makerToken: self.order.maker_token, + takerToken: self.order.taker_token, makerAmount: self.order.maker_amount, takerAmount: self.order.taker_amount, takerTokenFeeAmount: self.order.taker_token_fee_amount, - maker: self.order.maker.into_alloy(), - taker: self.order.taker.into_alloy(), - sender: self.order.sender.into_alloy(), - feeRecipient: self.order.fee_recipient.into_alloy(), - pool: self.order.pool.into_alloy(), + maker: self.order.maker, + taker: self.order.taker, + sender: self.order.sender, + feeRecipient: self.order.fee_recipient, + pool: self.order.pool, expiry: self.order.expiry, - salt: self.order.salt.into_alloy(), + salt: self.order.salt, }, IZeroex::LibSignature::Signature { signatureType: self.order.signature.signature_type, v: self.order.signature.v, - r: self.order.signature.r.into_alloy(), - s: self.order.signature.s.into_alloy(), + r: self.order.signature.r, + s: self.order.signature.s, }, self.taker_token_fill_amount, ); diff --git a/crates/solver/src/liquidity/balancer_v2.rs b/crates/solver/src/liquidity/balancer_v2.rs index bfae4f8b79..72391abcbe 100644 --- a/crates/solver/src/liquidity/balancer_v2.rs +++ b/crates/solver/src/liquidity/balancer_v2.rs @@ -2,10 +2,7 @@ use { crate::{ - interactions::{ - BalancerSwapGivenOutInteraction, - allowances::{AllowanceManager, AllowanceManaging, Allowances}, - }, + interactions::BalancerSwapGivenOutInteraction, liquidity::{ AmmOrderExecution, Liquidity, @@ -16,17 +13,14 @@ use { liquidity_collector::LiquidityCollecting, settlement::SettlementEncoder, }, - alloy::primitives::Address, + alloy::primitives::{Address, B256}, anyhow::Result, - ethcontract::H256, - ethrpc::alloy::conversions::IntoLegacy, - model::TokenPair, - shared::{ - ethrpc::Web3, - http_solver::model::TokenAmount, + liquidity_sources::{ + balancer_v2::pool_fetching::BalancerPoolFetching, recent_block_cache::Block, - sources::balancer_v2::pool_fetching::BalancerPoolFetching, }, + model::TokenPair, + shared::http_solver::model::TokenAmount, std::{collections::HashSet, sync::Arc}, tracing::instrument, }; @@ -36,22 +30,18 @@ pub struct BalancerV2Liquidity { settlement: Address, vault: Address, pool_fetcher: Arc, - allowance_manager: Box, } impl BalancerV2Liquidity { pub fn new( - web3: Web3, pool_fetcher: Arc, settlement: Address, vault: Address, ) -> Self { - let allowance_manager = AllowanceManager::new(web3, settlement.into_legacy()); Self { settlement, vault, pool_fetcher, - allowance_manager: Box::new(allowance_manager), } } @@ -62,15 +52,7 @@ impl BalancerV2Liquidity { ) -> Result<(Vec, Vec)> { let pools = self.pool_fetcher.fetch(pairs, block).await?; - let tokens = pools.relevant_tokens(); - - let allowances = self - .allowance_manager - .get_allowances(tokens, self.vault.into_legacy()) - .await?; - let inner = Arc::new(Inner { - allowances, settlement: self.settlement, vault: self.vault, }); @@ -129,25 +111,20 @@ impl LiquidityCollecting for BalancerV2Liquidity { } pub struct SettlementHandler { - pool_id: H256, + pool_id: B256, inner: Arc, } struct Inner { settlement: Address, vault: Address, - allowances: Allowances, } impl SettlementHandler { - pub fn new(pool_id: H256, settlement: Address, vault: Address, allowances: Allowances) -> Self { + pub fn new(pool_id: B256, settlement: Address, vault: Address) -> Self { SettlementHandler { pool_id, - inner: Arc::new(Inner { - settlement, - vault, - allowances, - }), + inner: Arc::new(Inner { settlement, vault }), } } @@ -155,7 +132,7 @@ impl SettlementHandler { &self.inner.vault } - pub fn pool_id(&self) -> H256 { + pub fn pool_id(&self) -> B256 { self.pool_id } @@ -204,16 +181,6 @@ impl SettlementHandler { execution: AmmOrderExecution, encoder: &mut SettlementEncoder, ) -> Result<()> { - if let Some(approval) = self - .inner - .allowances - .approve_token(execution.input_max.clone())? - { - encoder.append_to_execution_plan_internalizable( - Arc::new(approval), - execution.internalizable, - ); - } encoder.append_to_execution_plan_internalizable( Arc::new(self.swap(execution.input_max, execution.output)), execution.internalizable, @@ -227,17 +194,10 @@ impl SettlementHandler { mod tests { use { super::*, - crate::interactions::allowances::{Approval, MockAllowanceManaging}, - contracts::alloy::BalancerV2Vault, - maplit::{btreemap, hashmap, hashset}, - mockall::predicate::*, - model::TokenPair, - primitive_types::H160, - shared::{ - baseline_solver::BaseTokens, - http_solver::model::{InternalizationStrategy, TokenAmount}, - interaction::Interaction, - sources::balancer_v2::{ + alloy::primitives::U256, + contracts::BalancerV2Vault, + liquidity_sources::{ + balancer_v2::{ pool_fetching::{ AmplificationParameter, CommonPoolState, @@ -251,13 +211,21 @@ mod tests { }, swap::fixed_point::Bfp, }, + base_tokens::BaseTokens, + }, + maplit::{btreemap, hashset}, + mockall::predicate::*, + model::TokenPair, + shared::{ + http_solver::model::{InternalizationStrategy, TokenAmount}, + interaction::Interaction, }, }; fn dummy_contracts() -> (Address, BalancerV2Vault::Instance) { ( Address::from_slice(&[0xc0; 20]), - BalancerV2Vault::Instance::new([0xc1; 20].into(), ethrpc::mock::web3().alloy), + BalancerV2Vault::Instance::new([0xc1; 20].into(), ethrpc::mock::web3().provider), ) } @@ -272,34 +240,33 @@ mod tests { #[tokio::test] async fn fetches_liquidity() { let mut pool_fetcher = MockBalancerPoolFetching::new(); - let mut allowance_manager = MockAllowanceManaging::new(); let weighted_pools = vec![ WeightedPool { common: CommonPoolState { - id: H256([0x90; 32]), - address: H160([0x90; 20]), + id: B256::repeat_byte(0x90), + address: Address::repeat_byte(0x90), swap_fee: "0.002".parse().unwrap(), paused: true, }, reserves: btreemap! { - H160([0x70; 20]) => WeightedTokenState { + Address::repeat_byte(0x70) => WeightedTokenState { common: TokenState { - balance: 100.into(), + balance: U256::from(100), scaling_factor: Bfp::exp10(16), }, weight: "0.25".parse().unwrap(), }, - H160([0x71; 20]) => WeightedTokenState { + Address::repeat_byte(0x71) => WeightedTokenState { common: TokenState { - balance: 1_000_000.into(), + balance: U256::from(1_000_000), scaling_factor: Bfp::exp10(12), }, weight: "0.25".parse().unwrap(), }, - H160([0xb0; 20]) => WeightedTokenState { + Address::repeat_byte(0xb0) => WeightedTokenState { common: TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, weight: "0.5".parse().unwrap(), @@ -309,22 +276,22 @@ mod tests { }, WeightedPool { common: CommonPoolState { - id: H256([0x91; 32]), - address: H160([0x91; 20]), + id: B256::repeat_byte(0x91), + address: Address::repeat_byte(0x91), swap_fee: "0.001".parse().unwrap(), paused: true, }, reserves: btreemap! { - H160([0x73; 20]) => WeightedTokenState { + Address::repeat_byte(0x73) => WeightedTokenState { common: TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, weight: "0.5".parse().unwrap(), }, - H160([0xb0; 20]) => WeightedTokenState { + Address::repeat_byte(0xb0) => WeightedTokenState { common: TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, weight: "0.5".parse().unwrap(), @@ -336,19 +303,19 @@ mod tests { let stable_pools = vec![StablePool { common: CommonPoolState { - id: H256([0x92; 32]), - address: H160([0x92; 20]), + id: B256::repeat_byte(0x92), + address: Address::repeat_byte(0x92), swap_fee: "0.002".parse().unwrap(), paused: true, }, - amplification_parameter: AmplificationParameter::try_new(1.into(), 1.into()).unwrap(), + amplification_parameter: AmplificationParameter::try_new(U256::ONE, U256::ONE).unwrap(), reserves: btreemap! { - H160([0x73; 20]) => TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + Address::repeat_byte(0x73) => TokenState { + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, - H160([0xb0; 20]) => TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + Address::repeat_byte(0xb0) => TokenState { + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), } }, @@ -380,21 +347,7 @@ mod tests { } }); - // Fetches allowances for all tokens in pools. - allowance_manager - .expect_get_allowances() - .with( - eq(hashset![ - H160([0x70; 20]), - H160([0x71; 20]), - H160([0x73; 20]), - H160([0xb0; 20]), - ]), - always(), - ) - .returning(|_, _| Ok(Allowances::empty(H160([0xc1; 20])))); - - let base_tokens = BaseTokens::new(H160([0xb0; 20]), &[]); + let base_tokens = BaseTokens::new(Address::repeat_byte(0xb0), &[]); let traded_pairs = [ TokenPair::new( Address::from_slice(&[0x70; 20]), @@ -419,7 +372,6 @@ mod tests { settlement, vault: *vault.address(), pool_fetcher: Arc::new(pool_fetcher), - allowance_manager: Box::new(allowance_manager), }; let (stable_orders, weighted_orders) = liquidity_provider .get_orders(pairs, Block::Recent) @@ -465,16 +417,9 @@ mod tests { let inner = Arc::new(Inner { settlement, vault: *vault.address(), - allowances: Allowances::new( - vault.address().into_legacy(), - hashmap! { - H160([0x70; 20]) => 0.into(), - H160([0x71; 20]) => 100.into(), - }, - ), }); let handler = SettlementHandler { - pool_id: H256([0x90; 32]), + pool_id: B256::repeat_byte(0x90), inner, }; @@ -482,8 +427,8 @@ mod tests { SettlementHandling::::encode( &handler, AmmOrderExecution { - input_max: TokenAmount::new(H160([0x70; 20]), 10), - output: TokenAmount::new(H160([0x71; 20]), 11), + input_max: TokenAmount::new(Address::repeat_byte(0x70), U256::from(10)), + output: TokenAmount::new(Address::repeat_byte(0x71), U256::from(11)), internalizable: false, }, &mut encoder, @@ -492,8 +437,8 @@ mod tests { SettlementHandling::::encode( &handler, AmmOrderExecution { - input_max: TokenAmount::new(H160([0x71; 20]), 12), - output: TokenAmount::new(H160([0x72; 20]), 13), + input_max: TokenAmount::new(Address::repeat_byte(0x71), U256::from(12)), + output: TokenAmount::new(Address::repeat_byte(0x72), U256::from(13)), internalizable: false, }, &mut encoder, @@ -502,30 +447,26 @@ mod tests { let [_, interactions, _] = encoder .finish(InternalizationStrategy::SkipInternalizableInteraction) - .interactions; + .interactions + .into_array(); assert_eq!( interactions, [ - Approval { - token: H160([0x70; 20]), - spender: vault.address().into_legacy(), - } - .encode(), BalancerSwapGivenOutInteraction { settlement, vault: *vault.address(), - pool_id: H256([0x90; 32]), - asset_in_max: TokenAmount::new(H160([0x70; 20]), 10), - asset_out: TokenAmount::new(H160([0x71; 20]), 11), + pool_id: B256::repeat_byte(0x90), + asset_in_max: TokenAmount::new(Address::repeat_byte(0x70), U256::from(10)), + asset_out: TokenAmount::new(Address::repeat_byte(0x71), U256::from(11)), user_data: Default::default(), } .encode(), BalancerSwapGivenOutInteraction { settlement, vault: *vault.address(), - pool_id: H256([0x90; 32]), - asset_in_max: TokenAmount::new(H160([0x71; 20]), 12), - asset_out: TokenAmount::new(H160([0x72; 20]), 13), + pool_id: B256::repeat_byte(0x90), + asset_in_max: TokenAmount::new(Address::repeat_byte(0x71), U256::from(12)), + asset_out: TokenAmount::new(Address::repeat_byte(0x72), U256::from(13)), user_data: Default::default(), } .encode(), diff --git a/crates/solver/src/liquidity/mod.rs b/crates/solver/src/liquidity/mod.rs index f5774f9592..140cce6df3 100644 --- a/crates/solver/src/liquidity/mod.rs +++ b/crates/solver/src/liquidity/mod.rs @@ -4,33 +4,29 @@ pub mod uniswap_v2; pub mod uniswap_v3; pub mod zeroex; -#[cfg(test)] -use derivative::Derivative; use { crate::settlement::SettlementEncoder, + alloy::primitives::{Address, U256}, anyhow::Result, + liquidity_sources::{ + balancer_v2::{ + pool_fetching::{ + AmplificationParameter, + TokenState, + WeightedPoolVersion, + WeightedTokenState, + }, + swap::fixed_point::Bfp, + }, + uniswap_v2::pool_fetching::Pool, + uniswap_v3::pool_fetching::PoolInfo, + }, model::{ TokenPair, order::{Order, OrderKind, OrderUid}, }, num::rational::Ratio, - primitive_types::{H160, U256}, - shared::{ - http_solver::model::TokenAmount, - sources::{ - balancer_v2::{ - pool_fetching::{ - AmplificationParameter, - TokenState, - WeightedPoolVersion, - WeightedTokenState, - }, - swap::fixed_point::Bfp, - }, - uniswap_v2::pool_fetching::Pool, - uniswap_v3::pool_fetching::PoolInfo, - }, - }, + shared::http_solver::model::TokenAmount, std::{collections::BTreeMap, sync::Arc}, strum::IntoStaticStr, }; @@ -85,8 +81,7 @@ pub enum Exchange { /// solvers. User orders (market + limit) containing OrderUid are the orders /// from the orderbook. #[derive(Debug, Clone)] -#[cfg_attr(test, derive(Derivative))] -#[cfg_attr(test, derivative(PartialEq))] +#[cfg_attr(test, derive(PartialEq))] pub enum LimitOrderId { Market(OrderUid), Limit(OrderUid), @@ -102,8 +97,7 @@ pub enum LimitOrderId { /// (1) and (2) are gathered when the auction is cut and they are sent to /// searchers (3) are received from searchers as part of the solution. #[derive(Debug, Clone)] -#[cfg_attr(test, derive(Derivative))] -#[cfg_attr(test, derivative(PartialEq))] +#[cfg_attr(test, derive(PartialEq))] pub enum LiquidityOrderId { /// TODO: Split into different variants once we have a DTO of order model /// for `driver` in driver solver colocation TODO: The only reason why @@ -130,13 +124,11 @@ impl From for LimitOrderId { /// Basic limit sell and buy orders #[derive(Clone)] -#[cfg_attr(test, derive(Derivative))] -#[cfg_attr(test, derivative(PartialEq))] pub struct LimitOrder { // Opaque Identifier for debugging purposes pub id: LimitOrderId, - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, /// The amount that can be sold to acquire the required `buy_token`. pub sell_amount: U256, pub buy_amount: U256, @@ -144,11 +136,25 @@ pub struct LimitOrder { pub partially_fillable: bool, /// Takes partiall fill into account. pub user_fee: U256, - #[cfg_attr(test, derivative(PartialEq = "ignore"))] pub settlement_handling: Arc>, pub exchange: Exchange, } +#[cfg(test)] +impl PartialEq for LimitOrder { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.sell_token == other.sell_token + && self.buy_token == other.buy_token + && self.sell_amount == other.sell_amount + && self.buy_amount == other.buy_amount + && self.kind == other.kind + && self.partially_fillable == other.partially_fillable + && self.user_fee == other.user_fee + && self.exchange == other.exchange + } +} + impl LimitOrder { /// Returns the full execution amount for the specified limit order. pub fn full_execution_amount(&self) -> U256 { @@ -239,17 +245,24 @@ impl Default for LimitOrder { /// 2 sided constant product automated market maker with equal reserve value and /// a trading fee (e.g. Uniswap, Sushiswap) #[derive(Clone)] -#[cfg_attr(test, derive(Derivative))] -#[cfg_attr(test, derivative(PartialEq))] pub struct ConstantProductOrder { - pub address: H160, + pub address: Address, pub tokens: TokenPair, pub reserves: (u128, u128), pub fee: Ratio, - #[cfg_attr(test, derivative(PartialEq = "ignore"))] pub settlement_handling: Arc>, } +#[cfg(test)] +impl PartialEq for ConstantProductOrder { + fn eq(&self, other: &Self) -> bool { + self.address == other.address + && self.tokens == other.tokens + && self.reserves == other.reserves + && self.fee == other.fee + } +} + impl ConstantProductOrder { /// Creates a new constant product order from a Uniswap V2 pool and a /// settlement handler implementation. @@ -280,17 +293,24 @@ impl From for ConstantProductOrder { /// 2 sided weighted product automated market maker with weighted reserves and a /// trading fee (e.g. BalancerV2) #[derive(Clone)] -#[cfg_attr(test, derive(Derivative))] -#[cfg_attr(test, derivative(PartialEq))] pub struct WeightedProductOrder { - pub address: H160, - pub reserves: BTreeMap, + pub address: Address, + pub reserves: BTreeMap, pub fee: Bfp, pub version: WeightedPoolVersion, - #[cfg_attr(test, derivative(PartialEq = "ignore"))] pub settlement_handling: Arc>, } +#[cfg(test)] +impl PartialEq for WeightedProductOrder { + fn eq(&self, other: &Self) -> bool { + self.address == other.address + && self.reserves == other.reserves + && self.fee == other.fee + && self.version == other.version + } +} + impl std::fmt::Debug for WeightedProductOrder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Weighted Product AMM {:?}", self.reserves.keys()) @@ -298,17 +318,24 @@ impl std::fmt::Debug for WeightedProductOrder { } #[derive(Clone)] -#[cfg_attr(test, derive(Derivative))] -#[cfg_attr(test, derivative(PartialEq))] pub struct StablePoolOrder { - pub address: H160, - pub reserves: BTreeMap, + pub address: Address, + pub reserves: BTreeMap, pub fee: Bfp, pub amplification_parameter: AmplificationParameter, - #[cfg_attr(test, derivative(PartialEq = "ignore"))] pub settlement_handling: Arc>, } +#[cfg(test)] +impl PartialEq for StablePoolOrder { + fn eq(&self, other: &Self) -> bool { + self.address == other.address + && self.reserves == other.reserves + && self.fee == other.fee + && self.amplification_parameter == other.amplification_parameter + } +} + impl std::fmt::Debug for StablePoolOrder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Stable Pool AMM {:?}", self.reserves.keys()) @@ -348,15 +375,19 @@ impl Settleable for StablePoolOrder { /// Concentrated type of liquidity with ticks (e.g. UniswapV3) #[derive(Clone)] -#[cfg_attr(test, derive(Derivative))] -#[cfg_attr(test, derivative(PartialEq))] pub struct ConcentratedLiquidity { pub tokens: TokenPair, - pub pool: PoolInfo, - #[cfg_attr(test, derivative(PartialEq = "ignore"))] + pub pool: Arc, pub settlement_handling: Arc>, } +#[cfg(test)] +impl PartialEq for ConcentratedLiquidity { + fn eq(&self, other: &Self) -> bool { + self.tokens == other.tokens && self.pool == other.pool + } +} + impl std::fmt::Debug for ConcentratedLiquidity { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Concentrated liquidity {:?}", self.pool) @@ -426,26 +457,22 @@ pub mod tests { #[test] fn limit_order_full_execution_amounts() { - fn simple_limit_order( - kind: OrderKind, - sell_amount: impl Into, - buy_amount: impl Into, - ) -> LimitOrder { + fn simple_limit_order(kind: OrderKind, sell_amount: U256, buy_amount: U256) -> LimitOrder { LimitOrder { - sell_amount: sell_amount.into(), - buy_amount: buy_amount.into(), + sell_amount, + buy_amount, kind, ..Default::default() } } assert_eq!( - simple_limit_order(OrderKind::Sell, 1, 2).full_execution_amount(), - 1.into(), + simple_limit_order(OrderKind::Sell, U256::ONE, U256::from(2)).full_execution_amount(), + U256::from(1), ); assert_eq!( - simple_limit_order(OrderKind::Buy, 1, 2).full_execution_amount(), - 2.into(), + simple_limit_order(OrderKind::Buy, U256::ONE, U256::from(2)).full_execution_amount(), + U256::from(2), ); } } diff --git a/crates/solver/src/liquidity/slippage.rs b/crates/solver/src/liquidity/slippage.rs index a9ca38d7b8..f57b6f9ec1 100644 --- a/crates/solver/src/liquidity/slippage.rs +++ b/crates/solver/src/liquidity/slippage.rs @@ -2,9 +2,10 @@ use { super::AmmOrderExecution, + alloy::primitives::U256, anyhow::{Context as _, Result}, - ethcontract::U256, num::{BigInt, BigRational, CheckedDiv, Integer as _, ToPrimitive as _}, + number::conversions::{big_int_to_u256, u256_to_big_int}, shared::{external_prices::ExternalPrices, http_solver::model::TokenAmount}, std::{borrow::Cow, cmp, sync::LazyLock}, }; @@ -30,7 +31,7 @@ impl SlippageContext<'_> { let relative_ratio = |token_amount: &TokenAmount| -> Result> { let (relative, _) = self.calculator.compute( self.prices.price(&token_amount.token), - number::conversions::u256_to_big_int(&token_amount.amount), + u256_to_big_int(&token_amount.amount), )?; Ok(relative) }; @@ -68,10 +69,8 @@ impl SlippageContext<'_> { }, }; - let absolute = absolute_slippage_amount( - &relative, - &number::conversions::u256_to_big_int(&execution.input_max.amount), - ); + let absolute = + absolute_slippage_amount(&relative, &u256_to_big_int(&execution.input_max.amount)); let slippage = SlippageAmount::from_num(&relative, &absolute)?; if *relative < self.calculator.relative { @@ -113,7 +112,7 @@ impl SlippageCalculator { pub fn from_bps(relative_bps: u32, absolute: Option) -> Self { Self { relative: BigRational::new(relative_bps.into(), BPS_BASE.into()), - absolute: absolute.map(|value| number::conversions::u256_to_big_int(&value)), + absolute: absolute.map(|value| u256_to_big_int(&value)), } } @@ -178,7 +177,7 @@ impl SlippageAmount { let relative = relative .to_f64() .context("relative slippage ratio is not a number")?; - let absolute = number::conversions::big_int_to_u256(absolute)?; + let absolute = big_int_to_u256(absolute)?; Ok(Self { relative, absolute }) } @@ -199,47 +198,44 @@ fn absolute_slippage_amount(relative: &BigRational, amount: &BigInt) -> BigInt { mod tests { use { super::*, - ethrpc::alloy::conversions::IntoLegacy, shared::externalprices, testlib::tokens::{GNO, USDC, WETH}, }; #[test] fn amm_execution_slippage() { - let calculator = SlippageCalculator::from_bps(100, Some(U256::exp10(18))); - let prices = externalprices! { native_token: WETH.into_legacy() }; + let calculator = + SlippageCalculator::from_bps(100, Some(U256::from(10).pow(U256::from(18)))); + let prices = externalprices! { native_token: WETH }; let slippage = calculator.context(&prices); let cases = [ ( AmmOrderExecution { - input_max: TokenAmount::new(WETH.into_legacy(), 1_000_000_000_000_000_000_u128), - output: TokenAmount::new(GNO.into_legacy(), 10_000_000_000_000_000_000_u128), + input_max: TokenAmount::new(WETH, U256::from(1_000_000_000_000_000_000_u128)), + output: TokenAmount::new(GNO, U256::from(10_000_000_000_000_000_000_u128)), internalizable: false, }, - 1_010_000_000_000_000_000_u128.into(), + U256::from(1_010_000_000_000_000_000_u128), ), ( AmmOrderExecution { input_max: TokenAmount::new( - GNO.into_legacy(), - 10_000_000_000_000_000_000_000_u128, - ), - output: TokenAmount::new( - WETH.into_legacy(), - 1_000_000_000_000_000_000_000_u128, + GNO, + U256::from(10_000_000_000_000_000_000_000_u128), ), + output: TokenAmount::new(WETH, U256::from(1_000_000_000_000_000_000_000_u128)), internalizable: false, }, - 10_010_000_000_000_000_000_000_u128.into(), + U256::from(10_010_000_000_000_000_000_000_u128), ), ( AmmOrderExecution { - input_max: TokenAmount::new(USDC.into_legacy(), 200_000_000_u128), - output: TokenAmount::new(GNO.into_legacy(), 2_000_000_000_000_000_000_u128), + input_max: TokenAmount::new(USDC, U256::from(200_000_000_u128)), + output: TokenAmount::new(GNO, U256::from(2_000_000_000_000_000_000_u128)), internalizable: false, }, - 202_000_000_u128.into(), + U256::from(202_000_000_u128), ), ]; diff --git a/crates/solver/src/liquidity/uniswap_v2.rs b/crates/solver/src/liquidity/uniswap_v2.rs index 35008fa947..88ba3fa375 100644 --- a/crates/solver/src/liquidity/uniswap_v2.rs +++ b/crates/solver/src/liquidity/uniswap_v2.rs @@ -1,90 +1,44 @@ use { super::{AmmOrderExecution, ConstantProductOrder, SettlementHandling}, crate::{ - interactions::{ - UniswapInteraction, - allowances::{AllowanceManager, AllowanceManaging, Allowances, Approval}, - }, + interactions::UniswapInteraction, liquidity::Liquidity, liquidity_collector::LiquidityCollecting, settlement::SettlementEncoder, }, alloy::primitives::Address, anyhow::Result, - ethrpc::alloy::conversions::IntoLegacy, + liquidity_sources::{recent_block_cache::Block, uniswap_v2::pool_fetching::PoolFetching}, model::TokenPair, - primitive_types::H160, - shared::{ - ethrpc::Web3, - http_solver::model::TokenAmount, - recent_block_cache::Block, - sources::uniswap_v2::pool_fetching::PoolFetching, - }, - std::{ - collections::HashSet, - sync::{Arc, Mutex}, - }, + shared::http_solver::model::TokenAmount, + std::{collections::HashSet, sync::Arc}, tracing::instrument, }; pub struct UniswapLikeLiquidity { inner: Arc, pool_fetcher: Arc, - settlement_allowances: Box, } pub struct Inner { router: Address, gpv2_settlement: Address, - // Mapping of how much allowance the router has per token to spend on behalf of the settlement - // contract - allowances: Mutex, } impl UniswapLikeLiquidity { pub fn new( router: Address, gpv2_settlement: Address, - web3: Web3, - pool_fetcher: Arc, - ) -> Self { - let settlement_allowances = - Box::new(AllowanceManager::new(web3, gpv2_settlement.into_legacy())); - Self::with_allowances(router, gpv2_settlement, settlement_allowances, pool_fetcher) - } - - pub fn with_allowances( - router: Address, - gpv2_settlement: Address, - settlement_allowances: Box, pool_fetcher: Arc, ) -> Self { Self { inner: Arc::new(Inner { router, gpv2_settlement, - allowances: Mutex::new(Allowances::empty(router.into_legacy())), }), pool_fetcher, - settlement_allowances, } } - - async fn cache_allowances(&self, tokens: HashSet) -> Result<()> { - let router = self.inner.router.into_legacy(); - let allowances = self - .settlement_allowances - .get_allowances(tokens, router) - .await?; - - self.inner - .allowances - .lock() - .expect("Thread holding mutex panicked") - .extend(allowances)?; - - Ok(()) - } } #[async_trait::async_trait] @@ -100,8 +54,8 @@ impl LiquidityCollecting for UniswapLikeLiquidity { let mut tokens = HashSet::new(); let mut result = Vec::new(); for pool in self.pool_fetcher.fetch(pairs, at_block).await? { - tokens.insert(pool.tokens.get().0.into_legacy()); - tokens.insert(pool.tokens.get().1.into_legacy()); + tokens.insert(pool.tokens.get().0); + tokens.insert(pool.tokens.get().1); result.push(Liquidity::ConstantProduct(ConstantProductOrder { address: pool.address, @@ -111,17 +65,15 @@ impl LiquidityCollecting for UniswapLikeLiquidity { settlement_handling: self.inner.clone(), })) } - self.cache_allowances(tokens).await?; Ok(result) } } impl Inner { - pub fn new(router: Address, gpv2_settlement: Address, allowances: Mutex) -> Self { + pub fn new(router: Address, gpv2_settlement: Address) -> Self { Inner { router, gpv2_settlement, - allowances, } } @@ -129,24 +81,15 @@ impl Inner { &self, token_amount_in_max: TokenAmount, token_amount_out: TokenAmount, - ) -> (Option, UniswapInteraction) { - let approval = self - .allowances - .lock() - .expect("Thread holding mutex panicked") - .approve_token_or_default(token_amount_in_max.clone()); - - ( - approval, - UniswapInteraction { - router: self.router, - settlement: self.gpv2_settlement, - amount_out: token_amount_out.amount, - amount_in_max: token_amount_in_max.amount, - token_in: token_amount_in_max.token, - token_out: token_amount_out.token, - }, - ) + ) -> UniswapInteraction { + UniswapInteraction { + router: self.router, + settlement: self.gpv2_settlement, + amount_out: token_amount_out.amount, + amount_in_max: token_amount_in_max.amount, + token_in: token_amount_in_max.token, + token_out: token_amount_out.token, + } } pub fn router(&self) -> Address { @@ -162,74 +105,8 @@ impl SettlementHandling for Inner { // Creates the required interaction to convert the given input into output. // Assumes slippage is already applied to `input_max`. fn encode(&self, execution: AmmOrderExecution, encoder: &mut SettlementEncoder) -> Result<()> { - let (approval, swap) = self.settle(execution.input_max, execution.output); - if let Some(approval) = approval { - encoder.append_to_execution_plan_internalizable( - Arc::new(approval), - execution.internalizable, - ); - } - encoder.append_to_execution_plan_internalizable(Arc::new(swap), execution.internalizable); + let swap = Arc::new(self.settle(execution.input_max, execution.output)); + encoder.append_to_execution_plan_internalizable(swap, execution.internalizable); Ok(()) } } - -#[cfg(test)] -mod tests { - use {super::*, alloy::primitives::Address, primitive_types::U256, std::collections::HashMap}; - - impl Inner { - fn new_dummy(allowances: HashMap) -> Self { - Self { - router: Address::default(), - gpv2_settlement: Default::default(), - allowances: Mutex::new(Allowances::new(H160::zero(), allowances)), - } - } - } - - #[test] - fn test_should_set_allowance() { - let token_a = H160::from_low_u64_be(1); - let token_b = H160::from_low_u64_be(2); - let allowances = maplit::hashmap! { - token_a => 100.into(), - token_b => 200.into(), - }; - - let inner = Inner::new_dummy(allowances); - - // Token A below, equal, above - let (approval, _) = inner.settle( - TokenAmount::new(token_a, 50), - TokenAmount::new(token_b, 100), - ); - assert_eq!(approval, None); - - let (approval, _) = inner.settle( - TokenAmount::new(token_a, 99), - TokenAmount::new(token_b, 100), - ); - assert_eq!(approval, None); - - // Token B below, equal, above - let (approval, _) = inner.settle( - TokenAmount::new(token_b, 150), - TokenAmount::new(token_a, 100), - ); - assert_eq!(approval, None); - - let (approval, _) = inner.settle( - TokenAmount::new(token_b, 199), - TokenAmount::new(token_a, 100), - ); - assert_eq!(approval, None); - - // Untracked token - let (approval, _) = inner.settle( - TokenAmount::new(H160::from_low_u64_be(3), 1), - TokenAmount::new(token_a, 100), - ); - assert_ne!(approval, None); - } -} diff --git a/crates/solver/src/liquidity/uniswap_v3.rs b/crates/solver/src/liquidity/uniswap_v3.rs index ee8211a171..8c67b98126 100644 --- a/crates/solver/src/liquidity/uniswap_v3.rs +++ b/crates/solver/src/liquidity/uniswap_v3.rs @@ -1,45 +1,29 @@ use { super::{AmmOrderExecution, ConcentratedLiquidity, SettlementHandling}, crate::{ - interactions::{ - UniswapV3Interaction, - allowances::{AllowanceManager, AllowanceManaging, Allowances, Approval}, - }, + interactions::UniswapV3Interaction, liquidity::Liquidity, liquidity_collector::LiquidityCollecting, settlement::SettlementEncoder, }, alloy::primitives::Address, anyhow::{Context, Result, ensure}, - contracts::alloy::UniswapV3SwapRouterV2::IV3SwapRouter::ExactOutputSingleParams, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + contracts::UniswapV3SwapRouterV2::IV3SwapRouter::ExactOutputSingleParams, + liquidity_sources::{recent_block_cache::Block, uniswap_v3::pool_fetching::PoolFetching}, model::TokenPair, num::{CheckedMul, rational::Ratio}, - primitive_types::H160, - shared::{ - ethrpc::Web3, - http_solver::model::TokenAmount, - recent_block_cache::Block, - sources::uniswap_v3::pool_fetching::PoolFetching, - }, - std::{ - collections::HashSet, - sync::{Arc, Mutex}, - }, + shared::http_solver::model::TokenAmount, + std::{collections::HashSet, sync::Arc}, tracing::instrument, }; pub struct UniswapV3Liquidity { inner: Arc, pool_fetcher: Arc, - settlement_allowances: Box, } pub struct Inner { pub router: Address, gpv2_settlement: Address, - // Mapping of how much allowance the router has per token to spend on behalf of the settlement - // contract - allowances: Mutex, } pub struct UniswapV3SettlementHandler { @@ -48,17 +32,11 @@ pub struct UniswapV3SettlementHandler { } impl UniswapV3SettlementHandler { - pub fn new( - router: Address, - gpv2_settlement: Address, - allowances: Mutex, - fee: Ratio, - ) -> Self { + pub fn new(router: Address, gpv2_settlement: Address, fee: Ratio) -> Self { Self { inner: Arc::new(Inner { router, gpv2_settlement, - allowances, }), fee: ratio_to_u32(fee).unwrap(), } @@ -82,37 +60,16 @@ impl UniswapV3Liquidity { pub fn new( router: Address, gpv2_settlement: Address, - web3: Web3, pool_fetcher: Arc, ) -> Self { - let settlement_allowances = - Box::new(AllowanceManager::new(web3, gpv2_settlement.into_legacy())); Self { inner: Arc::new(Inner { router, gpv2_settlement, - allowances: Mutex::new(Allowances::empty(router.into_legacy())), }), pool_fetcher, - settlement_allowances, } } - - async fn cache_allowances(&self, tokens: HashSet) -> Result<()> { - let router = self.inner.router; - let allowances = self - .settlement_allowances - .get_allowances(tokens, router.into_legacy()) - .await?; - - self.inner - .allowances - .lock() - .expect("Thread holding mutex panicked") - .extend(allowances)?; - - Ok(()) - } } #[async_trait::async_trait] @@ -132,11 +89,8 @@ impl LiquidityCollecting for UniswapV3Liquidity { pool.tokens.len() == 2, "two tokens required for uniswap v3 pools" ); - let token_pair = TokenPair::new( - pool.tokens[0].id.into_alloy(), - pool.tokens[1].id.into_alloy(), - ) - .context("cant create pair")?; + let token_pair = + TokenPair::new(pool.tokens[0].id, pool.tokens[1].id).context("cant create pair")?; tokens.insert(pool.tokens[0].id); tokens.insert(pool.tokens[1].id); @@ -150,7 +104,6 @@ impl LiquidityCollecting for UniswapV3Liquidity { pool, })) } - self.cache_allowances(tokens).await?; Ok(result) } } @@ -160,31 +113,21 @@ impl UniswapV3SettlementHandler { &self, token_amount_in_max: TokenAmount, token_amount_out: TokenAmount, - ) -> (Option, UniswapV3Interaction) { - let approval = self - .inner - .allowances - .lock() - .expect("Thread holding mutex panicked") - .approve_token_or_default(token_amount_in_max.clone()); - + ) -> UniswapV3Interaction { let fee = self.fee.try_into().expect("fee < (1 << 24)"); - ( - approval, - UniswapV3Interaction { - router: self.inner.router, - params: ExactOutputSingleParams { - tokenIn: token_amount_in_max.token.into_alloy(), - tokenOut: token_amount_out.token.into_alloy(), - fee, - recipient: self.inner.gpv2_settlement, - amountOut: token_amount_out.amount.into_alloy(), - amountInMaximum: token_amount_in_max.amount.into_alloy(), - sqrtPriceLimitX96: alloy::primitives::U160::ZERO, - }, + UniswapV3Interaction { + router: self.inner.router, + params: ExactOutputSingleParams { + tokenIn: token_amount_in_max.token, + tokenOut: token_amount_out.token, + fee, + recipient: self.inner.gpv2_settlement, + amountOut: token_amount_out.amount, + amountInMaximum: token_amount_in_max.amount, + sqrtPriceLimitX96: alloy::primitives::U160::ZERO, }, - ) + } } } @@ -196,109 +139,15 @@ impl SettlementHandling for UniswapV3SettlementHandler { // Creates the required interaction to convert the given input into output. // Assumes slippage is already applied to the `input_max` field. fn encode(&self, execution: AmmOrderExecution, encoder: &mut SettlementEncoder) -> Result<()> { - let (approval, swap) = self.settle(execution.input_max, execution.output); - if let Some(approval) = approval { - encoder.append_to_execution_plan_internalizable( - Arc::new(approval), - execution.internalizable, - ); - } - encoder.append_to_execution_plan_internalizable(Arc::new(swap), execution.internalizable); + let swap = Arc::new(self.settle(execution.input_max, execution.output)); + encoder.append_to_execution_plan_internalizable(swap, execution.internalizable); Ok(()) } } #[cfg(test)] mod tests { - use {super::*, ethcontract::U256, num::rational::Ratio, std::collections::HashMap}; - - impl UniswapV3SettlementHandler { - fn new_dummy(allowances: HashMap, fee: u32) -> Self { - Self { - inner: Arc::new(Inner { - router: Default::default(), - gpv2_settlement: Default::default(), - allowances: Mutex::new(Allowances::new(H160::zero(), allowances)), - }), - fee, - } - } - } - - #[test] - fn test_should_set_allowance() { - let token_a = H160::from_low_u64_be(1); - let token_b = H160::from_low_u64_be(2); - let allowances = maplit::hashmap! { - token_a => 100.into(), - token_b => 200.into(), - }; - - let settlement_handler = UniswapV3SettlementHandler::new_dummy(allowances, 10); - - // Token A below, equal, above - let (approval, _) = settlement_handler.settle( - TokenAmount { - token: token_a, - amount: 50.into(), - }, - TokenAmount { - token: token_b, - amount: 100.into(), - }, - ); - assert_eq!(approval, None); - - let (approval, _) = settlement_handler.settle( - TokenAmount { - token: token_a, - amount: 99.into(), - }, - TokenAmount { - token: token_b, - amount: 100.into(), - }, - ); - assert_eq!(approval, None); - - // Token B below, equal, above - let (approval, _) = settlement_handler.settle( - TokenAmount { - token: token_b, - amount: 150.into(), - }, - TokenAmount { - token: token_a, - amount: 100.into(), - }, - ); - assert_eq!(approval, None); - - let (approval, _) = settlement_handler.settle( - TokenAmount { - token: token_b, - amount: 199.into(), - }, - TokenAmount { - token: token_a, - amount: 100.into(), - }, - ); - assert_eq!(approval, None); - - // Untracked token - let (approval, _) = settlement_handler.settle( - TokenAmount { - token: H160::from_low_u64_be(3), - amount: 1.into(), - }, - TokenAmount { - token: token_a, - amount: 100.into(), - }, - ); - assert_ne!(approval, None); - } + use {super::*, num::rational::Ratio}; #[test] fn test_ratio_to_u32() { diff --git a/crates/solver/src/liquidity/zeroex.rs b/crates/solver/src/liquidity/zeroex.rs index 3bbc64f1b5..de138a47b1 100644 --- a/crates/solver/src/liquidity/zeroex.rs +++ b/crates/solver/src/liquidity/zeroex.rs @@ -1,32 +1,23 @@ use { super::{LimitOrderExecution, LimitOrderId, LiquidityOrderId, SettlementHandling}, crate::{ - interactions::{ - ZeroExInteraction, - allowances::{AllowanceManager, AllowanceManaging, Allowances}, - }, + interactions::ZeroExInteraction, liquidity::{Exchange, LimitOrder, Liquidity}, liquidity_collector::LiquidityCollecting, settlement::SettlementEncoder, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, anyhow::Result, arc_swap::ArcSwap, - contracts::alloy::IZeroex, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::{CurrentBlockWatcher, into_stream}, - }, + contracts::IZeroex, + ethrpc::block_stream::{CurrentBlockWatcher, into_stream}, futures::StreamExt, itertools::Itertools, - model::{TokenPair, order::OrderKind}, - primitive_types::{H160, U256}, - shared::{ - ethrpc::Web3, - http_solver::model::TokenAmount, + liquidity_sources::{ recent_block_cache::Block, - zeroex_api::{OrderRecord, OrdersQuery, ZeroExApi}, + zeroex::{OrderRecord, OrdersQuery, ZeroExApi}, }, + model::{TokenPair, order::OrderKind}, std::{ collections::{HashMap, HashSet}, sync::Arc, @@ -34,25 +25,22 @@ use { tracing::instrument, }; -type OrderBuckets = HashMap<(H160, H160), Vec>; +type OrderBuckets = HashMap<(Address, Address), Vec>; type OrderbookCache = ArcSwap; pub struct ZeroExLiquidity { // todo: remove Arc pub zeroex: Arc, - pub allowance_manager: Box, pub orderbook_cache: Arc, } impl ZeroExLiquidity { pub async fn new( - web3: Web3, api: Arc, zeroex: IZeroex::Instance, gpv2: Address, blocks_stream: CurrentBlockWatcher, ) -> Self { - let allowance_manager = AllowanceManager::new(web3, gpv2.into_legacy()); let orderbook_cache: Arc = Default::default(); let cache = orderbook_cache.clone(); tokio::spawn( @@ -61,18 +49,13 @@ impl ZeroExLiquidity { Self { zeroex: Arc::new(zeroex), - allowance_manager: Box::new(allowance_manager), orderbook_cache, } } /// Turns 0x OrderRecord into liquidity which solvers can use. - fn record_into_liquidity( - &self, - record: OrderRecord, - allowances: Arc, - ) -> Option { - let sell_amount: U256 = record.remaining_maker_amount().ok()?.into(); + fn record_into_liquidity(&self, record: OrderRecord) -> Option { + let sell_amount = U256::from(record.remaining_maker_amount().ok()?); if sell_amount.is_zero() || record.metadata().remaining_fillable_taker_amount == 0 { // filter out orders with 0 amounts to prevent errors in the solver return None; @@ -85,14 +68,13 @@ impl ZeroExLiquidity { sell_token: record.order().maker_token, buy_token: record.order().taker_token, sell_amount, - buy_amount: record.metadata().remaining_fillable_taker_amount.into(), + buy_amount: U256::from(record.metadata().remaining_fillable_taker_amount), kind: OrderKind::Buy, partially_fillable: true, - user_fee: U256::zero(), + user_fee: U256::ZERO, settlement_handling: Arc::new(OrderSettlementHandler { order_record: record, zeroex: self.zeroex.clone(), - allowances, }), exchange: Exchange::ZeroEx, }; @@ -112,7 +94,7 @@ impl ZeroExLiquidity { OrdersQuery::default(), // orders fillable only by our settlement contract OrdersQuery { - sender: Some(gpv2_address.into_legacy()), + sender: Some(gpv2_address), ..Default::default() }, ]; @@ -141,20 +123,10 @@ impl LiquidityCollecting for ZeroExLiquidity { ) -> Result> { let zeroex_order_buckets = self.orderbook_cache.load(); let filtered_zeroex_orders = get_useful_orders(zeroex_order_buckets.as_ref(), &pairs, 5); - let tokens: HashSet<_> = filtered_zeroex_orders - .iter() - .map(|o| o.order().taker_token) - .collect(); - - let allowances = Arc::new( - self.allowance_manager - .get_allowances(tokens, self.zeroex.address().into_legacy()) - .await?, - ); let zeroex_liquidity_orders: Vec<_> = filtered_zeroex_orders .into_iter() - .flat_map(|order| self.record_into_liquidity(order, allowances.clone())) + .flat_map(|order| self.record_into_liquidity(order)) .collect(); Ok(zeroex_liquidity_orders) @@ -163,14 +135,10 @@ impl LiquidityCollecting for ZeroExLiquidity { fn group_by_token_pair( orders: impl Iterator, -) -> HashMap<(H160, H160), Vec> { +) -> HashMap<(Address, Address), Vec> { orders .filter_map(|record| { - TokenPair::new( - record.order().taker_token.into_alloy(), - record.order().maker_token.into_alloy(), - ) - .map(|_| { + TokenPair::new(record.order().taker_token, record.order().maker_token).map(|_| { ( (record.order().taker_token, record.order().maker_token), record, @@ -190,7 +158,7 @@ fn get_useful_orders( for orders in order_buckets .iter() .filter_map(|((token_a, token_b), record)| { - TokenPair::new(token_a.into_alloy(), token_b.into_alloy()) + TokenPair::new(*token_a, *token_b) .is_some_and(|pair| relevant_pairs.contains(&pair)) .then_some(record) }) @@ -221,7 +189,6 @@ pub struct OrderSettlementHandler { pub order_record: OrderRecord, // todo: remove Arc pub zeroex: Arc, - allowances: Arc, } impl SettlementHandling for OrderSettlementHandler { @@ -234,18 +201,11 @@ impl SettlementHandling for OrderSettlementHandler { execution: LimitOrderExecution, encoder: &mut SettlementEncoder, ) -> Result<()> { - if execution.filled > u128::MAX.into() { + let Ok(execution_filled) = u128::try_from(execution.filled) else { anyhow::bail!("0x only supports executed amounts of size u128"); - } - let approval = self.allowances.approve_token(TokenAmount::new( - self.order_record.order().taker_token, - execution.filled, - ))?; - if let Some(approval) = approval { - encoder.append_to_execution_plan(Arc::new(approval)); - } + }; encoder.append_to_execution_plan(Arc::new(ZeroExInteraction { - taker_token_fill_amount: execution.filled.as_u128(), + taker_token_fill_amount: execution_filled, order: self.order_record.order().clone(), zeroex: self.zeroex.clone(), })); @@ -257,39 +217,35 @@ impl SettlementHandling for OrderSettlementHandler { pub mod tests { use { super::*, - crate::interactions::allowances::Approval, - ethrpc::alloy::conversions::IntoAlloy, - maplit::hashmap, - shared::{ - baseline_solver::BaseTokens, - http_solver::model::InternalizationStrategy, - interaction::Interaction, - zeroex_api::{self, OrderMetadata}, + liquidity_sources::{ + base_tokens::BaseTokens, + zeroex::{self, OrderMetadata}, }, + shared::{http_solver::model::InternalizationStrategy, interaction::Interaction}, }; - fn get_relevant_pairs(token_a: H160, token_b: H160) -> HashSet { - let base_tokens = Arc::new(BaseTokens::new(H160::zero(), &[])); - let fake_order = - [TokenPair::new(token_a.into_alloy(), token_b.into_alloy()).unwrap()].into_iter(); + fn get_relevant_pairs(token_a: Address, token_b: Address) -> HashSet { + let base_tokens = Arc::new(BaseTokens::new(Address::ZERO, &[])); + let fake_order = [TokenPair::new(token_a, token_b).unwrap()].into_iter(); base_tokens.relevant_pairs(fake_order) } + fn order_with_tokens(token_a: Address, token_b: Address) -> OrderRecord { + OrderRecord::new( + zeroex::Order { + taker_token: token_a, + maker_token: token_b, + ..Default::default() + }, + OrderMetadata::default(), + ) + } + #[test] fn order_buckets_get_created() { - let token_a = H160([0x00; 20]); - let token_b = H160([0xff; 20]); + let token_a = Address::repeat_byte(0x00); + let token_b = Address::repeat_byte(0xff); let relevant_pairs = get_relevant_pairs(token_a, token_b); - let order_with_tokens = |token_a, token_b| { - OrderRecord::new( - zeroex_api::Order { - taker_token: token_a, - maker_token: token_b, - ..Default::default() - }, - OrderMetadata::default(), - ) - }; let order_1 = order_with_tokens(token_a, token_b); let order_2 = order_with_tokens(token_b, token_a); let order_3 = order_with_tokens(token_b, token_a); @@ -301,20 +257,10 @@ pub mod tests { #[test] fn empty_bucket_no_relevant_orders() { - let token_a = H160([0x00; 20]); - let token_b = H160([0xff; 20]); - let token_ignore = H160([0x11; 20]); + let token_a = Address::repeat_byte(0x00); + let token_b = Address::repeat_byte(0xff); + let token_ignore = Address::repeat_byte(0x11); let relevant_pairs = get_relevant_pairs(token_a, token_b); - let order_with_tokens = |token_a, token_b| { - OrderRecord::new( - zeroex_api::Order { - taker_token: token_a, - maker_token: token_b, - ..Default::default() - }, - OrderMetadata::default(), - ) - }; let order_1 = order_with_tokens(token_ignore, token_b); let order_2 = order_with_tokens(token_a, token_ignore); let order_3 = order_with_tokens(token_ignore, token_ignore); @@ -325,12 +271,12 @@ pub mod tests { #[test] fn biggest_volume_orders_get_selected() { - let token_a = H160([0x00; 20]); - let token_b = H160([0xff; 20]); + let token_a = Address::repeat_byte(0x00); + let token_b = Address::repeat_byte(0xff); let relevant_pairs = get_relevant_pairs(token_a, token_b); let order_with_fillable_amount = |remaining_fillable_taker_amount| { OrderRecord::new( - zeroex_api::Order { + zeroex::Order { taker_token: token_a, maker_token: token_b, taker_amount: 100_000_000, @@ -365,12 +311,12 @@ pub mod tests { #[test] fn best_priced_orders_get_selected() { - let token_a = H160([0x00; 20]); - let token_b = H160([0xff; 20]); + let token_a = Address::repeat_byte(0x00); + let token_b = Address::repeat_byte(0xff); let relevant_pairs = get_relevant_pairs(token_a, token_b); let order_with_amount = |taker_amount, remaining_fillable_taker_amount| { OrderRecord::new( - zeroex_api::Order { + zeroex::Order { taker_token: token_a, maker_token: token_b, taker_amount, @@ -398,66 +344,14 @@ pub mod tests { } #[tokio::test] - async fn interaction_encodes_approval_when_insufficient() { - let sell_token = H160::from_low_u64_be(1); - let zeroex = Arc::new(IZeroex::Instance::new( - H160::default().into_alloy(), - ethrpc::mock::web3().alloy, - )); - let allowances = Allowances::new( - zeroex.address().into_legacy(), - hashmap! { sell_token => 99.into() }, - ); - let order_record = OrderRecord::new( - zeroex_api::Order { - taker_amount: 100, - taker_token: sell_token, - ..Default::default() - }, - OrderMetadata::default(), - ); - let handler = OrderSettlementHandler { - order_record: order_record.clone(), - zeroex: zeroex.clone(), - allowances: Arc::new(allowances), - }; - let mut encoder = SettlementEncoder::default(); - let execution = LimitOrderExecution::new(100.into(), 0.into()); - handler.encode(execution, &mut encoder).unwrap(); - let [_, interactions, _] = encoder - .finish(InternalizationStrategy::SkipInternalizableInteraction) - .interactions; - assert_eq!( - interactions, - [ - Approval { - token: sell_token, - spender: zeroex.address().into_legacy(), - } - .encode(), - ZeroExInteraction { - order: order_record.order().clone(), - taker_token_fill_amount: 100, - zeroex: zeroex.clone(), - } - .encode(), - ], - ); - } - - #[tokio::test] - async fn interaction_encodes_no_approval_when_sufficient() { - let sell_token = H160::from_low_u64_be(1); + async fn interaction_encoding() { + let sell_token = Address::with_last_byte(1); let zeroex = Arc::new(IZeroex::Instance::new( - H160::default().into_alloy(), - ethrpc::mock::web3().alloy, + Default::default(), + ethrpc::mock::web3().provider, )); - let allowances = Allowances::new( - zeroex.address().into_legacy(), - hashmap! { sell_token => 100.into() }, - ); let order_record = OrderRecord::new( - zeroex_api::Order { + zeroex::Order { taker_amount: 100, taker_token: sell_token, ..Default::default() @@ -467,14 +361,14 @@ pub mod tests { let handler = OrderSettlementHandler { order_record: order_record.clone(), zeroex: zeroex.clone(), - allowances: Arc::new(allowances), }; let mut encoder = SettlementEncoder::default(); - let execution = LimitOrderExecution::new(100.into(), 0.into()); + let execution = LimitOrderExecution::new(U256::from(100), U256::ZERO); handler.encode(execution, &mut encoder).unwrap(); let [_, interactions, _] = encoder .finish(InternalizationStrategy::SkipInternalizableInteraction) - .interactions; + .interactions + .into_array(); assert_eq!( interactions, [ZeroExInteraction { diff --git a/crates/solver/src/liquidity_collector.rs b/crates/solver/src/liquidity_collector.rs index 05a8b1b751..1be0b58f69 100644 --- a/crates/solver/src/liquidity_collector.rs +++ b/crates/solver/src/liquidity_collector.rs @@ -1,8 +1,8 @@ use { crate::liquidity::Liquidity, anyhow::Result, + liquidity_sources::{base_tokens::BaseTokens, recent_block_cache::Block}, model::TokenPair, - shared::{baseline_solver::BaseTokens, recent_block_cache::Block}, std::{collections::HashSet, future::Future, sync::Arc, time::Duration}, tokio::sync::RwLock, tracing::{Instrument, instrument}, @@ -146,7 +146,7 @@ mod test { use { super::*, futures::FutureExt, - shared::recent_block_cache::Block, + liquidity_sources::recent_block_cache::Block, std::sync::atomic::{AtomicUsize, Ordering}, }; @@ -184,11 +184,15 @@ mod test { } }; - let source = - BackgroundInitLiquiditySource::new("fake", init, Duration::from_millis(10), None); + let source = BackgroundInitLiquiditySource::new( + "fake_delayed_init", + init, + Duration::from_millis(10), + None, + ); let gauge = Metrics::get() .liquidity_enabled - .with_label_values(&["fake"]); + .with_label_values(&["fake_delayed_init"]); assert_eq!(gauge.get(), 0); let liquidity = source @@ -226,7 +230,7 @@ mod test { }; let source = BackgroundInitLiquiditySource::new( - "fake", + "fake_reinit", init, Duration::from_millis(10), Some(Duration::from_millis(10)), @@ -245,7 +249,7 @@ mod test { let gauge = Metrics::get() .liquidity_enabled - .with_label_values(&["fake"]); + .with_label_values(&["fake_reinit"]); assert!((5..=6).contains(&gauge.get())); } } diff --git a/crates/solver/src/settlement/mod.rs b/crates/solver/src/settlement/mod.rs index 5228053081..a7c1439a90 100644 --- a/crates/solver/src/settlement/mod.rs +++ b/crates/solver/src/settlement/mod.rs @@ -2,15 +2,12 @@ mod settlement_encoder; use { crate::liquidity::Settleable, + alloy::primitives::{Address, U256}, anyhow::Result, - ethrpc::alloy::conversions::IntoLegacy, model::order::{Order, OrderKind}, - primitive_types::{H160, U256}, - shared::{ - conversions::U256Ext as _, - encoded_settlement::{EncodedSettlement, EncodedTrade, encode_trade}, - http_solver::model::InternalizationStrategy, - }, + number::u256_ext::U256Ext, + shared::http_solver::model::InternalizationStrategy, + simulator::encoding::{EncodedSettlement, EncodedTrade, encode_trade}, std::collections::HashMap, }; @@ -25,8 +22,8 @@ pub struct Trade { #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct TradeExecution { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, pub sell_amount: U256, pub buy_amount: U256, pub fee_amount: U256, @@ -36,7 +33,7 @@ impl Trade { // Returns the executed fee amount (prorated of executed amount) // cf. https://github.com/cowprotocol/contracts/blob/v1.1.2/src/contracts/GPv2Settlement.sol#L383-L385 fn executed_fee(&self) -> Option { - self.scale_amount(self.order.data.fee_amount.into_legacy()) + self.scale_amount(self.order.data.fee_amount) } /// Scales the passed `amount` based on the `executed_amount`. @@ -44,10 +41,10 @@ impl Trade { match self.order.data.kind { model::order::OrderKind::Buy => amount .checked_mul(self.executed_amount)? - .checked_div(self.order.data.buy_amount.into_legacy()), + .checked_div(self.order.data.buy_amount), model::order::OrderKind::Sell => amount .checked_mul(self.executed_amount)? - .checked_div(self.order.data.sell_amount.into_legacy()), + .checked_div(self.order.data.sell_amount), } } @@ -75,8 +72,8 @@ impl Trade { }; Some(TradeExecution { - sell_token: order.sell_token.into_legacy(), - buy_token: order.buy_token.into_legacy(), + sell_token: order.sell_token, + buy_token: order.buy_token, sell_amount, buy_amount, fee_amount: self.executed_fee()?, @@ -91,10 +88,10 @@ impl Trade { encode_trade( &self.order.data, &self.order.signature, - self.order.metadata.owner.into_legacy(), + self.order.metadata.owner, sell_token_index, buy_token_index, - &self.executed_amount, + self.executed_amount, ) } } @@ -112,7 +109,7 @@ pub enum Revertable { impl Settlement { /// Creates a new settlement builder for the specified clearing prices. - pub fn new(clearing_prices: HashMap) -> Self { + pub fn new(clearing_prices: HashMap) -> Self { Self { encoder: SettlementEncoder::new(clearing_prices), } @@ -128,7 +125,7 @@ impl Settlement { } /// Returns the clearing prices map. - pub fn clearing_prices(&self) -> &HashMap { + pub fn clearing_prices(&self) -> &HashMap { self.encoder.clearing_prices() } @@ -157,13 +154,12 @@ pub mod tests { use { super::*, crate::liquidity::SettlementHandling, - ethrpc::alloy::conversions::IntoAlloy, maplit::hashmap, model::order::{OrderClass, OrderData, OrderKind, OrderMetadata}, }; pub fn assert_settlement_encoded_with( - prices: HashMap, + prices: HashMap, handler: S, execution: L::Execution, exec: impl FnOnce(&mut SettlementEncoder), @@ -187,7 +183,10 @@ pub mod tests { /// Helper function for creating a settlement for the specified prices and /// trades for testing objective value computations. - fn test_settlement(prices: HashMap, trades: Vec) -> Settlement { + fn test_settlement( + prices: HashMap, + trades: Vec, + ) -> Settlement { Settlement { encoder: SettlementEncoder::with_trades(prices, trades), } @@ -205,15 +204,15 @@ pub mod tests { }, ..Default::default() }, - executed_amount: 5.into(), + executed_amount: U256::from(5), ..Default::default() }; - let sell_price = 3.into(); - let buy_price = 4.into(); + let sell_price = U256::from(3); + let buy_price = U256::from(4); let execution = trade.executed_amounts(sell_price, buy_price).unwrap(); - assert_eq!(execution.sell_amount, 5.into()); - assert_eq!(execution.buy_amount, 4.into()); // round up! + assert_eq!(execution.sell_amount, U256::from(5)); + assert_eq!(execution.buy_amount, U256::from(4)); // round up! } #[test] @@ -228,15 +227,15 @@ pub mod tests { }, ..Default::default() }, - executed_amount: 5.into(), + executed_amount: U256::from(5), ..Default::default() }; - let sell_price = 3.into(); - let buy_price = 4.into(); + let sell_price = U256::from(3); + let buy_price = U256::from(4); let execution = trade.executed_amounts(sell_price, buy_price).unwrap(); - assert_eq!(execution.sell_amount, 6.into()); // round down! - assert_eq!(execution.buy_amount, 5.into()); + assert_eq!(execution.sell_amount, U256::from(6)); // round down! + assert_eq!(execution.buy_amount, U256::from(5)); } #[test] @@ -257,17 +256,17 @@ pub mod tests { ..Default::default() }; let sell_price = U256::from(2); - let buy_price = U256::one(); + let buy_price = U256::ONE; assert!(trade.executed_amounts(sell_price, buy_price).is_none()); // div let trade = Trade { order, - executed_amount: U256::one(), + executed_amount: U256::ONE, ..Default::default() }; - let sell_price = U256::one(); - let buy_price = U256::zero(); + let sell_price = U256::ONE; + let buy_price = U256::ZERO; assert!(trade.executed_amounts(sell_price, buy_price).is_none()); } } @@ -277,13 +276,13 @@ pub mod tests { // Test if passing a clearing price of zero makes it not possible to add // trades. - let token0 = H160::from_low_u64_be(0); - let token1 = H160::from_low_u64_be(1); + let token0 = Address::with_last_byte(0); + let token1 = Address::with_last_byte(1); let order = Order { data: OrderData { - sell_token: token0.into_alloy(), - buy_token: token1.into_alloy(), + sell_token: token0, + buy_token: token1, sell_amount: alloy::primitives::U256::from(10), buy_amount: alloy::primitives::U256::from(9), kind: OrderKind::Sell, @@ -293,24 +292,24 @@ pub mod tests { }; let mut settlement = Settlement::new(hashmap! { - token0 => 1.into(), - token1 => 1.into(), + token0 => U256::ONE, + token1 => U256::ONE, }); assert!( settlement .encoder - .add_trade(order.clone(), 10.into(), 0.into()) + .add_trade(order.clone(), U256::from(10), U256::ZERO) .is_ok() ); let mut settlement = Settlement::new(hashmap! { - token0 => 1.into(), - token1 => 0.into(), + token0 => U256::ONE, + token1 => U256::ZERO, }); assert!( settlement .encoder - .add_trade(order, 10.into(), 0.into()) + .add_trade(order, U256::from(10), U256::ZERO) .is_err() ); } @@ -327,10 +326,10 @@ pub mod tests { }, ..Default::default() }, - executed_amount: 100.into(), + executed_amount: U256::from(100), ..Default::default() }; - assert_eq!(fully_filled_sell.executed_fee().unwrap(), 5.into()); + assert_eq!(fully_filled_sell.executed_fee().unwrap(), U256::from(5)); let partially_filled_sell = Trade { order: Order { @@ -342,10 +341,10 @@ pub mod tests { }, ..Default::default() }, - executed_amount: 50.into(), + executed_amount: U256::from(50), ..Default::default() }; - assert_eq!(partially_filled_sell.executed_fee().unwrap(), 2.into()); + assert_eq!(partially_filled_sell.executed_fee().unwrap(), U256::from(2)); let fully_filled_buy = Trade { order: Order { @@ -357,10 +356,10 @@ pub mod tests { }, ..Default::default() }, - executed_amount: 100.into(), + executed_amount: U256::from(100), ..Default::default() }; - assert_eq!(fully_filled_buy.executed_fee().unwrap(), 5.into()); + assert_eq!(fully_filled_buy.executed_fee().unwrap(), U256::from(5)); let partially_filled_buy = Trade { order: Order { @@ -372,10 +371,10 @@ pub mod tests { }, ..Default::default() }, - executed_amount: 50.into(), + executed_amount: U256::from(50), ..Default::default() }; - assert_eq!(partially_filled_buy.executed_fee().unwrap(), 2.into()); + assert_eq!(partially_filled_buy.executed_fee().unwrap(), U256::from(2)); } #[test] @@ -390,7 +389,7 @@ pub mod tests { }, ..Default::default() }, - executed_amount: U256::max_value(), + executed_amount: U256::MAX, ..Default::default() }; assert_eq!(large_amounts.executed_fee(), None); @@ -405,7 +404,7 @@ pub mod tests { }, ..Default::default() }, - executed_amount: U256::zero(), + executed_amount: U256::ZERO, ..Default::default() }; assert_eq!(zero_amounts.executed_fee(), None); @@ -413,19 +412,19 @@ pub mod tests { #[test] fn includes_limit_order_ucp() { - let sell_token = H160([1; 20]); - let buy_token = H160([2; 20]); + let sell_token = alloy::primitives::Address::repeat_byte(1); + let buy_token = alloy::primitives::Address::repeat_byte(2); let settlement = test_settlement( hashmap! { - sell_token => 100_000_u128.into(), - buy_token => 100_000_u128.into(), + sell_token => U256::from(100_000_u128), + buy_token => U256::from(100_000_u128), }, vec![Trade { order: Order { data: OrderData { - sell_token: sell_token.into_alloy(), - buy_token: buy_token.into_alloy(), + sell_token, + buy_token, sell_amount: alloy::primitives::U256::from(100_000_u128), buy_amount: alloy::primitives::U256::from(99_000_u128), kind: OrderKind::Sell, @@ -437,8 +436,8 @@ pub mod tests { }, ..Default::default() }, - executed_amount: 99_000_u128.into(), - fee: 1_000_u128.into(), + executed_amount: U256::from(99_000_u128), + fee: U256::from(1_000_u128), }], ) .encode(InternalizationStrategy::SkipInternalizableInteraction); @@ -453,10 +452,10 @@ pub mod tests { assert_eq!( settlement.clearing_prices, [ - 100_000_u128.into(), - 100_000_u128.into(), - 99_000_u128.into(), - 100_000_u128.into(), + alloy::primitives::U256::from(100_000_u128), + alloy::primitives::U256::from(100_000_u128), + alloy::primitives::U256::from(99_000_u128), + alloy::primitives::U256::from(100_000_u128), ], ); } diff --git a/crates/solver/src/settlement/settlement_encoder.rs b/crates/solver/src/settlement/settlement_encoder.rs index bc37bd788d..12d9d0b130 100644 --- a/crates/solver/src/settlement/settlement_encoder.rs +++ b/crates/solver/src/settlement/settlement_encoder.rs @@ -1,20 +1,16 @@ use { super::{Trade, TradeExecution}, crate::interactions::UnwrapWethInteraction, + alloy::primitives::{Address, U256}, anyhow::{Context as _, Result, ensure}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, itertools::Either, model::{ interaction::InteractionData, order::{Order, OrderClass, OrderKind}, }, - primitive_types::{H160, U256}, - shared::{ - conversions::U256Ext, - encoded_settlement::EncodedSettlement, - http_solver::model::InternalizationStrategy, - interaction::Interaction, - }, + number::u256_ext::U256Ext, + shared::{http_solver::model::InternalizationStrategy, interaction::Interaction}, + simulator::encoding::{EncodedSettlement, Interactions}, std::{ collections::{HashMap, HashSet}, iter, @@ -39,8 +35,8 @@ pub struct SettlementEncoder { // Make sure to update the `merge` method when adding new fields. // Invariant: tokens is all keys in clearing_prices sorted. - tokens: Vec, - clearing_prices: HashMap, + tokens: Vec
, + clearing_prices: HashMap, trades: Vec, // This is an Arc so that this struct is Clone. Cannot require `Interaction: Clone` because it // would make the trait not be object safe which prevents using it through `dyn`. @@ -92,7 +88,7 @@ impl SettlementEncoder { /// /// The prices must be provided up front in order to ensure that all tokens /// included in the settlement are known when encoding trades. - pub(crate) fn new(clearing_prices: HashMap) -> Self { + pub(crate) fn new(clearing_prices: HashMap) -> Self { // Explicitly define a token ordering based on the supplied clearing // prices. This is done since `HashMap::keys` returns an iterator in // arbitrary order ([1]), meaning that we can't rely that the ordering @@ -116,7 +112,7 @@ impl SettlementEncoder { } #[cfg(test)] - pub fn with_trades(clearing_prices: HashMap, trades: Vec) -> Self { + pub fn with_trades(clearing_prices: HashMap, trades: Vec) -> Self { let mut result = Self::new(clearing_prices); for trade in trades { result @@ -126,7 +122,7 @@ impl SettlementEncoder { result } - pub(crate) fn clearing_prices(&self) -> &HashMap { + pub(crate) fn clearing_prices(&self) -> &HashMap { &self.clearing_prices } @@ -170,18 +166,18 @@ impl SettlementEncoder { verify_executed_amount(&order, executed_amount)?; let sell_price = self .clearing_prices - .get(&order.data.sell_token.into_legacy()) + .get(&order.data.sell_token) .context("settlement missing sell token")?; let sell_token_index = self - .token_index(order.data.sell_token.into_legacy()) + .token_index(order.data.sell_token) .expect("missing sell token with price"); let buy_price = self .clearing_prices - .get(&order.data.buy_token.into_legacy()) + .get(&order.data.buy_token) .context("settlement missing buy token")?; let buy_token_index = self - .token_index(order.data.buy_token.into_legacy()) + .token_index(order.data.buy_token) .expect("missing buy token with price"); let trade = EncoderTrade { @@ -217,13 +213,7 @@ impl SettlementEncoder { OrderClass::Market => self.add_market_trade(order, executed_amount, fee)?, OrderClass::Liquidity => { let (sell_price, buy_price) = (order.data.buy_amount, order.data.sell_amount); - self.add_custom_price_trade( - order, - executed_amount, - fee, - sell_price.into_legacy(), - buy_price.into_legacy(), - )? + self.add_custom_price_trade(order, executed_amount, fee, sell_price, buy_price)? } OrderClass::Limit => { let surplus_fee = fee; @@ -271,9 +261,8 @@ impl SettlementEncoder { OrderKind::Sell => order.data.sell_amount, }; anyhow::ensure!( - (order.data.partially_fillable && executed_amount <= target_amount.into_legacy()) - || (!order.data.partially_fillable - && executed_amount == target_amount.into_legacy()), + (order.data.partially_fillable && executed_amount <= target_amount) + || (!order.data.partially_fillable && executed_amount == target_amount), "this function should only be called with valid executed amounts" ); @@ -286,11 +275,11 @@ impl SettlementEncoder { // while pocketing the `surplus_fee` from the `sell_token`s. let uniform_buy_price = *self .clearing_prices - .get(&order.data.buy_token.into_legacy()) + .get(&order.data.buy_token) .context("buy token price is missing")?; let uniform_sell_price = *self .clearing_prices - .get(&order.data.sell_token.into_legacy()) + .get(&order.data.sell_token) .context("sell token price is missing")?; let (sell_amount, buy_amount) = match order.data.kind { @@ -384,7 +373,11 @@ impl SettlementEncoder { } #[cfg(test)] - pub(crate) fn add_token_equivalency(&mut self, token_a: H160, token_b: H160) -> Result<()> { + pub(crate) fn add_token_equivalency( + &mut self, + token_a: Address, + token_b: Address, + ) -> Result<()> { let (new_token, existing_price) = match ( self.clearing_prices.get(&token_a), self.clearing_prices.get(&token_b), @@ -421,10 +414,10 @@ impl SettlementEncoder { self.trades[i].tokens = match self.trades[i].tokens { TokenReference::Indexed { .. } => TokenReference::Indexed { sell_token_index: self - .token_index(self.trades[i].data.order.data.sell_token.into_legacy()) + .token_index(self.trades[i].data.order.data.sell_token) .expect("missing sell token for existing trade"), buy_token_index: self - .token_index(self.trades[i].data.order.data.buy_token.into_legacy()) + .token_index(self.trades[i].data.order.data.buy_token) .expect("missing buy token for existing trade"), }, original @ TokenReference::CustomPrice { .. } => original, @@ -432,7 +425,7 @@ impl SettlementEncoder { } } - fn token_index(&self, token: H160) -> Option { + fn token_index(&self, token: Address) -> Option { self.tokens.binary_search(&token).ok() } @@ -457,10 +450,9 @@ impl SettlementEncoder { }) .collect(); - self.tokens - .retain(|token| traded_tokens.contains(&token.into_alloy())); + self.tokens.retain(|token| traded_tokens.contains(token)); self.clearing_prices - .retain(|token, _| traded_tokens.contains(&token.into_alloy())); + .retain(|token, _| traded_tokens.contains(token)); self.sort_tokens_and_update_indices(); } @@ -473,7 +465,7 @@ impl SettlementEncoder { let uniform_clearing_price_vec_length = self.tokens.len(); let mut tokens = self.tokens.clone(); - let mut clearing_prices: Vec = self + let mut clearing_prices: Vec<_> = self .tokens .iter() .map(|token| { @@ -487,10 +479,7 @@ impl SettlementEncoder { { // add tokens/prices for custom price orders, since they are not contained in // the UCP vector - let (mut custom_price_order_tokens, mut custom_price_order_prices): ( - Vec, - Vec, - ) = self + let (mut custom_price_order_tokens, mut custom_price_order_prices) = self .trades .iter() .filter_map(|trade| match trade.tokens { @@ -498,14 +487,8 @@ impl SettlementEncoder { sell_token_price, buy_token_price, } => Some(vec![ - ( - trade.data.order.data.sell_token.into_legacy(), - sell_token_price, - ), - ( - trade.data.order.data.buy_token.into_legacy(), - buy_token_price, - ), + (trade.data.order.data.sell_token, sell_token_price), + (trade.data.order.data.buy_token, buy_token_price), ]), _ => None, }) @@ -540,12 +523,13 @@ impl SettlementEncoder { tokens, clearing_prices, trades, - interactions: [ - self.pre_interactions + interactions: Interactions { + pre: self + .pre_interactions .into_iter() .map(|interaction| interaction.encode()) .collect(), - iter::empty() + main: iter::empty() .chain( self.execution_plan .iter() @@ -565,11 +549,12 @@ impl SettlementEncoder { ) .chain(self.unwraps.iter().map(|unwrap| unwrap.encode())) .collect(), - self.post_interactions + post: self + .post_interactions .into_iter() .map(|interaction| interaction.encode()) .collect(), - ], + }, } } } @@ -585,18 +570,10 @@ impl PricedTrade<'_> { pub(crate) fn verify_executed_amount(order: &Order, executed: U256) -> Result<()> { let remaining = shared::remaining_amounts::Remaining::from_order(&order.into())?; let valid_executed_amount = match (order.data.partially_fillable, order.data.kind) { - (true, OrderKind::Sell) => { - executed <= remaining.remaining(order.data.sell_amount.into_legacy())? - } - (true, OrderKind::Buy) => { - executed <= remaining.remaining(order.data.buy_amount.into_legacy())? - } - (false, OrderKind::Sell) => { - executed == remaining.remaining(order.data.sell_amount.into_legacy())? - } - (false, OrderKind::Buy) => { - executed == remaining.remaining(order.data.buy_amount.into_legacy())? - } + (true, OrderKind::Sell) => executed <= remaining.remaining(order.data.sell_amount)?, + (true, OrderKind::Buy) => executed <= remaining.remaining(order.data.buy_amount)?, + (false, OrderKind::Sell) => executed == remaining.remaining(order.data.sell_amount)?, + (false, OrderKind::Buy) => executed == remaining.remaining(order.data.buy_amount)?, }; ensure!(valid_executed_amount, "invalid executed amount"); Ok(()) @@ -607,8 +584,7 @@ pub mod tests { use { super::*, alloy::primitives::Address, - contracts::alloy::WETH9, - ethrpc::alloy::conversions::IntoAlloy, + contracts::WETH9, maplit::hashmap, model::order::{Interactions, OrderBuilder, OrderData}, shared::interaction::{EncodedInteraction, Interaction}, @@ -621,9 +597,9 @@ pub mod tests { let order0 = Order { data: OrderData { sell_token: token0, - sell_amount: alloy::primitives::U256::ONE, + sell_amount: U256::ONE, buy_token: token1, - buy_amount: alloy::primitives::U256::ONE, + buy_amount: U256::ONE, ..Default::default() }, ..Default::default() @@ -631,44 +607,45 @@ pub mod tests { let order1 = Order { data: OrderData { sell_token: token1, - sell_amount: alloy::primitives::U256::ONE, + sell_amount: U256::ONE, buy_token: token0, - buy_amount: alloy::primitives::U256::ONE, + buy_amount: U256::ONE, ..Default::default() }, ..Default::default() }; let mut settlement = SettlementEncoder::new(maplit::hashmap! { - token0.into_legacy() => 1.into(), - token1.into_legacy() => 1.into(), + token0 => U256::ONE, + token1 => U256::ONE, }); - assert!(settlement.add_trade(order0, 1.into(), 1.into()).is_ok()); - assert!(settlement.add_trade(order1, 1.into(), 0.into()).is_ok()); + settlement.add_trade(order0, U256::ONE, U256::ONE).unwrap(); + settlement.add_trade(order1, U256::ONE, U256::ZERO).unwrap(); } #[test] fn settlement_merges_unwraps_for_same_token() { - let weth = WETH9::Instance::new([0x42; 20].into(), ethrpc::mock::web3().alloy); + let weth = WETH9::Instance::new([0x42; 20].into(), ethrpc::mock::web3().provider); let mut encoder = SettlementEncoder::new(HashMap::new()); encoder.add_unwrap(UnwrapWethInteraction { weth: weth.clone(), - amount: alloy::primitives::U256::ONE, + amount: U256::ONE, }); encoder.add_unwrap(UnwrapWethInteraction { weth: weth.clone(), - amount: alloy::primitives::U256::from(2), + amount: U256::from(2), }); assert_eq!( encoder .finish(InternalizationStrategy::SkipInternalizableInteraction) - .interactions[1], + .interactions + .main, [UnwrapWethInteraction { weth, - amount: alloy::primitives::U256::from(3), + amount: U256::from(3), } .encode()], ); @@ -677,88 +654,102 @@ pub mod tests { #[test] fn settlement_reflects_different_price_for_normal_and_liquidity_order() { let mut settlement = SettlementEncoder::new(maplit::hashmap! { - token(0) => 3.into(), - token(1) => 10.into(), + Address::with_last_byte(0) => U256::from(3), + Address::with_last_byte(1) => U256::from(10), }); let order01 = OrderBuilder::default() .with_sell_token(Address::with_last_byte(0)) - .with_sell_amount(alloy::primitives::U256::from(30)) + .with_sell_amount(U256::from(30)) .with_buy_token(Address::with_last_byte(1)) - .with_buy_amount(alloy::primitives::U256::from(10)) + .with_buy_amount(U256::from(10)) .build(); let order10 = OrderBuilder::default() .with_sell_token(Address::with_last_byte(1)) - .with_sell_amount(alloy::primitives::U256::from(10)) + .with_sell_amount(U256::from(10)) .with_buy_token(Address::with_last_byte(0)) - .with_buy_amount(alloy::primitives::U256::from(20)) + .with_buy_amount(U256::from(20)) .with_class(OrderClass::Liquidity) .build(); - assert!(settlement.add_trade(order01, 10.into(), 0.into()).is_ok()); - assert!(settlement.add_trade(order10, 20.into(), 0.into()).is_ok()); + settlement + .add_trade(order01, U256::from(10), U256::from(0)) + .unwrap(); + settlement + .add_trade(order10, U256::from(20), U256::from(0)) + .unwrap(); let finished_settlement = settlement.finish(InternalizationStrategy::SkipInternalizableInteraction); assert_eq!( finished_settlement.tokens, - vec![token(0), token(1), token(1), token(0)] + vec![ + Address::with_last_byte(0), + Address::with_last_byte(1), + Address::with_last_byte(1), + Address::with_last_byte(0) + ] ); assert_eq!( finished_settlement.clearing_prices, - vec![3.into(), 10.into(), 20.into(), 10.into()] + vec![ + U256::from(3), + U256::from(10), + U256::from(20), + U256::from(10) + ] ); assert_eq!( finished_settlement.trades[1].1, // <-- is the buy token index of liquidity order - 3.into() + U256::from(3) ); assert_eq!( finished_settlement.trades[0].1, // <-- is the buy token index of normal order - 1.into() + U256::ONE ); } #[test] fn settlement_inserts_sell_price_for_new_liquidity_order_if_price_did_not_exist() { let mut settlement = SettlementEncoder::new(maplit::hashmap! { - token(1) => 9.into(), + Address::with_last_byte(1) => U256::from(9), }); let order01 = OrderBuilder::default() .with_sell_token(Address::with_last_byte(0)) - .with_sell_amount(alloy::primitives::U256::from(30)) + .with_sell_amount(U256::from(30)) .with_buy_token(Address::with_last_byte(1)) - .with_buy_amount(alloy::primitives::U256::from(10)) + .with_buy_amount(U256::from(10)) .with_class(OrderClass::Liquidity) .build(); assert!( settlement - .add_trade(order01.clone(), 10.into(), 0.into()) + .add_trade(order01.clone(), U256::from(10), U256::ZERO) .is_ok() ); // ensures that the output of add_liquidity_order is not changed after adding // liquidity order - assert_eq!(settlement.tokens, vec![token(1)]); + assert_eq!(settlement.tokens, vec![Address::with_last_byte(1)]); let finished_settlement = settlement.finish(InternalizationStrategy::SkipInternalizableInteraction); // the initial price from:SettlementEncoder::new(maplit::hashmap! { // token(1) => 9.into(), // }); // gets dropped and replaced by the liquidity price - assert_eq!(finished_settlement.tokens, vec![token(0), token(1)]); + assert_eq!( + finished_settlement.tokens, + vec![Address::with_last_byte(0), Address::with_last_byte(1)] + ); assert_eq!( finished_settlement.clearing_prices, - vec![ - order01.data.buy_amount.into_legacy(), - order01.data.sell_amount.into_legacy() - ] + vec![order01.data.buy_amount, order01.data.sell_amount] ); assert_eq!( finished_settlement.trades[0].0, // <-- is the sell token index of liquidity order - 0.into() + U256::ZERO ); assert_eq!( finished_settlement.trades[0].1, // <-- is the buy token index of liquidity order - 1.into() + U256::ONE ); } @@ -766,12 +757,12 @@ pub mod tests { fn settlement_encoder_appends_unwraps_for_different_tokens() { let mut encoder = SettlementEncoder::new(HashMap::new()); encoder.add_unwrap(UnwrapWethInteraction { - weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().alloy), - amount: alloy::primitives::U256::ONE, + weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().provider), + amount: U256::ONE, }); encoder.add_unwrap(UnwrapWethInteraction { - weth: WETH9::Instance::new([0x02; 20].into(), ethrpc::mock::web3().alloy), - amount: alloy::primitives::U256::from(2), + weth: WETH9::Instance::new([0x02; 20].into(), ethrpc::mock::web3().provider), + amount: U256::from(2), }); assert_eq!( @@ -781,8 +772,8 @@ pub mod tests { .map(|unwrap| (*unwrap.weth.address(), unwrap.amount)) .collect::>(), vec![ - ([0x01; 20].into(), alloy::primitives::U256::ONE), - ([0x02; 20].into(), alloy::primitives::U256::from(2)) + ([0x01; 20].into(), U256::ONE), + ([0x02; 20].into(), U256::from(2)) ], ); } @@ -791,12 +782,12 @@ pub mod tests { fn settlement_unwraps_after_execution_plan() { let interaction: EncodedInteraction = ( Address::new([0x01; 20]), - alloy::primitives::U256::ZERO, + U256::ZERO, alloy::primitives::Bytes::default(), ); let unwrap = UnwrapWethInteraction { - weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().alloy), - amount: alloy::primitives::U256::ONE, + weth: WETH9::Instance::new([0x01; 20].into(), ethrpc::mock::web3().provider), + amount: U256::ONE, }; let mut encoder = SettlementEncoder::new(HashMap::new()); @@ -806,33 +797,34 @@ pub mod tests { assert_eq!( encoder .finish(InternalizationStrategy::SkipInternalizableInteraction) - .interactions[1], + .interactions + .main, [interaction.encode(), unwrap.encode()], ); } #[test] fn settlement_encoder_add_token_equivalency() { - let token_a = H160([0x00; 20]); - let token_b = H160([0xff; 20]); + let token_a = Address::repeat_byte(0x00); + let token_b = Address::repeat_byte(0xff); let mut encoder = SettlementEncoder::new(hashmap! { - token_a => 1.into(), - token_b => 2.into(), + token_a => U256::ONE, + token_b => U256::from(2), }); encoder .add_trade( Order { data: OrderData { - sell_token: token_a.into_alloy(), - sell_amount: alloy::primitives::U256::from(6), - buy_token: token_b.into_alloy(), - buy_amount: alloy::primitives::U256::from(3), + sell_token: token_a, + sell_amount: U256::from(6), + buy_token: token_b, + buy_amount: U256::from(3), ..Default::default() }, ..Default::default() }, - 3.into(), - 0.into(), + U256::from(3), + U256::ZERO, ) .unwrap(); @@ -845,7 +837,7 @@ pub mod tests { } ); - let token_c = H160([0xee; 20]); + let token_c = Address::repeat_byte(0xee); encoder.add_token_equivalency(token_a, token_c).unwrap(); assert_eq!(encoder.tokens, [token_a, token_c, token_b]); @@ -867,38 +859,34 @@ pub mod tests { let mut encoder = SettlementEncoder::new(HashMap::new()); assert!( encoder - .add_token_equivalency(H160([0; 20]), H160([1; 20])) + .add_token_equivalency(Address::repeat_byte(0), Address::repeat_byte(1)) .is_err() ); } #[test] fn settlement_encoder_non_equivalent_tokens() { - let token_a = H160([1; 20]); - let token_b = H160([2; 20]); + let token_a = Address::repeat_byte(1); + let token_b = Address::repeat_byte(2); let mut encoder = SettlementEncoder::new(hashmap! { - token_a => 1.into(), - token_b => 2.into(), + token_a => U256::ONE, + token_b => U256::from(2), }); assert!(encoder.add_token_equivalency(token_a, token_b).is_err()); } - fn token(number: u64) -> H160 { - H160::from_low_u64_be(number) - } - #[test] fn trades_add_interactions_to_the_encoded_and_later_get_encoded() { - let prices = hashmap! { token(1) => 1.into(), token(3) => 3.into() }; + let prices = hashmap! { Address::with_last_byte(1) => U256::ONE, Address::with_last_byte(3) => U256::from(3) }; let mut encoder = SettlementEncoder::new(prices); let i1 = InteractionData { target: Address::from_slice(&[12; 20]), - value: alloy::primitives::U256::from(321), + value: U256::from(321), call_data: vec![1, 2, 3, 4], }; let i2 = InteractionData { target: Address::from_slice(&[42; 20]), - value: alloy::primitives::U256::from(1212), + value: U256::from(1212), call_data: vec![4, 3, 2, 1], }; encoder @@ -906,9 +894,9 @@ pub mod tests { Order { data: OrderData { sell_token: Address::with_last_byte(1), - sell_amount: alloy::primitives::U256::from(33), + sell_amount: U256::from(33), buy_token: Address::with_last_byte(3), - buy_amount: alloy::primitives::U256::from(11), + buy_amount: U256::from(11), kind: OrderKind::Sell, ..Default::default() }, @@ -918,8 +906,8 @@ pub mod tests { }, ..Default::default() }, - 33.into(), - 5.into(), + U256::from(33), + U256::from(5), ) .unwrap(); @@ -929,9 +917,9 @@ pub mod tests { Order { data: OrderData { sell_token: Address::with_last_byte(1), - sell_amount: alloy::primitives::U256::from(66), + sell_amount: U256::from(66), buy_token: Address::with_last_byte(3), - buy_amount: alloy::primitives::U256::from(22), + buy_amount: U256::from(22), kind: OrderKind::Sell, ..Default::default() }, @@ -941,8 +929,8 @@ pub mod tests { }, ..Default::default() }, - 66.into(), - 5.into(), + U256::from(66), + U256::from(5), ) .unwrap(); @@ -953,36 +941,42 @@ pub mod tests { let i2 = (i2.target, i2.value, i2.call_data.into()); let encoded = encoder.finish(InternalizationStrategy::EncodeAllInteractions); assert_eq!( - encoded.interactions, + encoded.interactions.into_array(), [vec![i1.clone(), i1], vec![], vec![i2.clone(), i2]] ); } #[test] fn encoding_strips_unnecessary_tokens_and_prices() { - let prices = hashmap! {token(1) => 7.into(), token(2) => 2.into(), - token(3) => 9.into(), token(4) => 44.into()}; + let prices = hashmap! { + Address::with_last_byte(1) => U256::from(7), + Address::with_last_byte(2) => U256::from(2), + Address::with_last_byte(3) => U256::from(9), + Address::with_last_byte(4) => U256::from(44), + }; let mut encoder = SettlementEncoder::new(prices); let order_1_3 = OrderBuilder::default() .with_sell_token(Address::with_last_byte(1)) - .with_sell_amount(alloy::primitives::U256::from(33)) + .with_sell_amount(U256::from(33)) .with_buy_token(Address::with_last_byte(3)) - .with_buy_amount(alloy::primitives::U256::from(11)) + .with_buy_amount(U256::from(11)) .build(); - encoder.add_trade(order_1_3, 11.into(), 0.into()).unwrap(); + encoder + .add_trade(order_1_3, U256::from(11), U256::ZERO) + .unwrap(); - let weth = WETH9::Instance::new(token(2).into_alloy(), ethrpc::mock::web3().alloy); + let weth = WETH9::Instance::new(Address::with_last_byte(2), ethrpc::mock::web3().provider); encoder.add_unwrap(UnwrapWethInteraction { weth, - amount: alloy::primitives::U256::from(12), + amount: U256::from(12), }); let encoded = encoder.finish(InternalizationStrategy::SkipInternalizableInteraction); // only token 1 and 2 have been included in orders by traders - let expected_tokens: Vec<_> = [1, 3].into_iter().map(token).collect(); + let expected_tokens: Vec<_> = [1, 3].into_iter().map(Address::with_last_byte).collect(); assert_eq!(expected_tokens, encoded.tokens); // only the prices for token 1 and 2 remain and they are in the correct order @@ -993,11 +987,11 @@ pub mod tests { // dropping unnecessary tokens did not change the sell_token_index let updated_sell_token_index = encoded_trade.0; - assert_eq!(updated_sell_token_index, 0.into()); + assert_eq!(updated_sell_token_index, U256::ZERO); // dropping unnecessary tokens decreased the buy_token_index by one let updated_buy_token_index = encoded_trade.1; - assert_eq!(updated_buy_token_index, 1.into()); + assert_eq!(updated_buy_token_index, U256::ONE); } #[derive(Debug)] @@ -1006,7 +1000,7 @@ pub mod tests { fn encode(&self) -> EncodedInteraction { ( Address::ZERO, - alloy::primitives::U256::ZERO, + U256::ZERO, alloy::primitives::Bytes::default(), ) } @@ -1014,7 +1008,7 @@ pub mod tests { #[test] fn optionally_encodes_internalizable_transactions() { - let prices = hashmap! {token(1) => 7.into() }; + let prices = hashmap! {Address::with_last_byte(1) => U256::from(7) }; let mut encoder = SettlementEncoder::new(prices); encoder.append_to_execution_plan_internalizable(Arc::new(TestInteraction), true); @@ -1023,44 +1017,48 @@ pub mod tests { let encoded = encoder .clone() .finish(InternalizationStrategy::SkipInternalizableInteraction); - assert_eq!(encoded.interactions[1].len(), 1); + assert_eq!(encoded.interactions.main.len(), 1); let encoded = encoder.finish(InternalizationStrategy::EncodeAllInteractions); - assert_eq!(encoded.interactions[1].len(), 2); + assert_eq!(encoded.interactions.main.len(), 2); } #[test] fn computes_custom_price_for_sell_limit_order_correctly() { - let weth = token(1); - let usdc = token(2); + let weth = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); let prices = hashmap! { // assumption 1 WETH == 1_000 USDC (all prices multiplied by 10^18) - weth => U256::exp10(18), - usdc => U256::exp10(27) // 1 ETH buys 1_000 * 10^6 units of USDC + weth => U256::from(10).pow(U256::from(18)), + usdc => U256::from(10).pow(U256::from(27)) // 1 ETH buys 1_000 * 10^6 units of USDC }; let mut encoder = SettlementEncoder::new(prices); // sell 1.01 WETH for 1_000 USDC with a fee of 0.01 WETH (or 10 USDC) let order = OrderBuilder::default() .with_class(OrderClass::Limit) - .with_sell_token(weth.into_alloy()) - .with_sell_amount(alloy::primitives::U256::from(1_010_000_000_000_000_000u128)) // 1.01 WETH - .with_buy_token(usdc.into_alloy()) - .with_buy_amount(alloy::primitives::U256::from(10).pow(alloy::primitives::U256::from(9))) // 1_000 USDC - .with_fee_amount(alloy::primitives::U256::ZERO) + .with_sell_token(weth) + .with_sell_amount(U256::from(1_010_000_000_000_000_000u128)) // 1.01 WETH + .with_buy_token(usdc) + .with_buy_amount(U256::from(10).pow(U256::from(9))) // 1_000 USDC + .with_fee_amount(U256::ZERO) .with_kind(OrderKind::Sell) .build(); let execution = encoder - .add_trade(order.clone(), U256::exp10(18), U256::exp10(16)) + .add_trade( + order.clone(), + U256::from(10).pow(U256::from(18)), + U256::from(10).pow(U256::from(16)), + ) .unwrap(); assert_eq!( TradeExecution { sell_token: weth, buy_token: usdc, - sell_amount: 1_010_000_000_000_000_000u128.into(), // 1.01 WETH - buy_amount: U256::exp10(9), // 1_000 USDC - fee_amount: 0.into(), + sell_amount: U256::from(1_010_000_000_000_000_000u128), // 1.01 WETH + buy_amount: U256::from(10).pow(U256::from(9)), // 1_000 USDC + fee_amount: U256::ZERO, }, execution ); @@ -1068,15 +1066,16 @@ pub mod tests { EncoderTrade { data: Trade { order, - executed_amount: 1_010_000_000_000_000_000u128.into(), // 1.01 WETH - fee: U256::exp10(16) // 0.01 WETH (10 USDC) + executed_amount: U256::from(1_010_000_000_000_000_000u128), // 1.01 WETH + fee: U256::from(10).pow(U256::from(16)), /* 0.01 WETH (10 + * USDC) */ }, tokens: TokenReference::CustomPrice { - sell_token_price: U256::exp10(9), + sell_token_price: U256::from(10).pow(U256::from(9)), // Instead of the (solver) anticipated 1 WETH required to buy 1_000 USDC we had // to sell 1.01 WETH (to pocket the fee). This caused the // USDC price to increase by 1%. - buy_token_price: 1_010_000_000_000_000_000u128.into() + buy_token_price: U256::from(1_010_000_000_000_000_000u128) }, }, encoder.trades[0] @@ -1085,28 +1084,32 @@ pub mod tests { #[test] fn computes_custom_price_for_buy_limit_order_correctly() { - let weth = token(1); - let usdc = token(2); + let weth = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); // assuming 1 WETH == 1_000 USDC let prices = hashmap! { - weth => U256::exp10(18), - usdc => U256::exp10(27) // 1 ETH buys 1_000 * 10^6 units of USDC + weth => U256::from(10).pow(U256::from(18)), + usdc => U256::from(10).pow(U256::from(27)) // 1 ETH buys 1_000 * 10^6 units of USDC }; let mut encoder = SettlementEncoder::new(prices); // buy 1 WETH for 1_010 USDC with a fee of 10 USDC let order = OrderBuilder::default() .with_class(OrderClass::Limit) - .with_buy_token(weth.into_alloy()) - .with_buy_amount(alloy::primitives::U256::from(10).pow(alloy::primitives::U256::from(18))) // 1 WETH - .with_sell_token(usdc.into_alloy()) - .with_sell_amount(alloy::primitives::U256::from(1_010_000_000u128)) // 1_010 USDC - .with_fee_amount(alloy::primitives::U256::ZERO) + .with_buy_token(weth) + .with_buy_amount(U256::from(10).pow(U256::from(18))) // 1 WETH + .with_sell_token(usdc) + .with_sell_amount(U256::from(1_010_000_000u128)) // 1_010 USDC + .with_fee_amount(U256::ZERO) .with_kind(OrderKind::Buy) .build(); let execution = encoder - .add_trade(order.clone(), U256::exp10(18), U256::exp10(7)) + .add_trade( + order.clone(), + U256::from(10).pow(U256::from(18)), + U256::from(10).pow(U256::from(7)), + ) .unwrap(); assert_eq!( TradeExecution { @@ -1114,9 +1117,9 @@ pub mod tests { buy_token: weth, // With the original price selling 1_000 USDC would have been enough. // With the adjusted price we actually have to sell all 1_010 USDC. - sell_amount: 1_010_000_000u128.into(), // 1_010 USDC - buy_amount: U256::exp10(18), // 1 WETH - fee_amount: 0.into(), + sell_amount: U256::from(1_010_000_000u128), // 1_010 USDC + buy_amount: U256::from(10).pow(U256::from(18)), // 1 WETH + fee_amount: U256::ZERO, }, execution ); @@ -1124,15 +1127,15 @@ pub mod tests { EncoderTrade { data: Trade { order, - executed_amount: U256::exp10(18), // 1 WETH - fee: U256::exp10(7) // 10 USDC + executed_amount: U256::from(10).pow(U256::from(18)), // 1 WETH + fee: U256::from(10).pow(U256::from(7)) // 10 USDC }, tokens: TokenReference::CustomPrice { - sell_token_price: U256::exp10(18), + sell_token_price: U256::from(10).pow(U256::from(18)), // Instead of the (solver) anticipated 1_000 USDC required to buy 1 WETH we had // to sell 1_010 USDC (to pocket the fee). This caused the // WETH price to increase by 1%. - buy_token_price: 1_010_000_000u128.into() + buy_token_price: U256::from(1_010_000_000u128) } }, encoder.trades[0] diff --git a/crates/solver/src/solver.rs b/crates/solver/src/solver.rs index c592ab0f71..6c7091efdc 100644 --- a/crates/solver/src/solver.rs +++ b/crates/solver/src/solver.rs @@ -1,10 +1,11 @@ use { crate::liquidity::{ConstantProductOrder, WeightedProductOrder}, + alloy::primitives::{Address, U256}, anyhow::anyhow, - ethcontract::{H160, U256}, - shared::{ - baseline_solver::BaselineSolvable, - sources::{balancer_v2::swap::WeightedPoolRef, uniswap_v2::pool_fetching::Pool}, + liquidity_sources::{ + balancer_v2::swap::WeightedPoolRef, + baseline_solvable::BaselineSolvable, + uniswap_v2::pool_fetching::Pool, }, std::{fmt::Debug, str::FromStr}, }; @@ -28,11 +29,11 @@ impl FromStr for Arn { } impl BaselineSolvable for ConstantProductOrder { - async fn get_amount_out(&self, out_token: H160, input: (U256, H160)) -> Option { + async fn get_amount_out(&self, out_token: Address, input: (U256, Address)) -> Option { amm_to_pool(self).get_amount_out(out_token, input).await } - async fn get_amount_in(&self, in_token: H160, output: (U256, H160)) -> Option { + async fn get_amount_in(&self, in_token: Address, output: (U256, Address)) -> Option { amm_to_pool(self).get_amount_in(in_token, output).await } @@ -42,13 +43,13 @@ impl BaselineSolvable for ConstantProductOrder { } impl BaselineSolvable for WeightedProductOrder { - async fn get_amount_out(&self, out_token: H160, input: (U256, H160)) -> Option { + async fn get_amount_out(&self, out_token: Address, input: (U256, Address)) -> Option { amm_to_weighted_pool(self) .get_amount_out(out_token, input) .await } - async fn get_amount_in(&self, in_token: H160, output: (U256, H160)) -> Option { + async fn get_amount_in(&self, in_token: Address, output: (U256, Address)) -> Option { amm_to_weighted_pool(self) .get_amount_in(in_token, output) .await diff --git a/crates/solvers-dto/Cargo.toml b/crates/solvers-dto/Cargo.toml index 8860a4e0bb..d24f0b1ae7 100644 --- a/crates/solvers-dto/Cargo.toml +++ b/crates/solvers-dto/Cargo.toml @@ -6,15 +6,19 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] +alloy-primitives = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-rpc-types-eth = { workspace = true } app-data = { workspace = true } bigdecimal = { workspace = true, features = ["serde"] } -bytes-hex = { workspace = true } # may get marked as unused but it's used with serde +bytes-hex = { workspace = true } # may get marked as unused but it's used with serde chrono = { workspace = true, features = ["serde"] } const-hex = { workspace = true } number = { workspace = true } serde = { workspace = true } +serde-ext = { workspace = true } +serde_json = { workspace = true } serde_with = { workspace = true } -web3 = { workspace = true } [lints] workspace = true diff --git a/crates/solvers-dto/src/auction.rs b/crates/solvers-dto/src/auction.rs index 0f2ab355ec..632ce71b6c 100644 --- a/crates/solvers-dto/src/auction.rs +++ b/crates/solvers-dto/src/auction.rs @@ -1,12 +1,11 @@ use { - super::serialize, + alloy_primitives::{Address, B256, U256}, app_data::AppDataHash, bigdecimal::BigDecimal, number::serialization::HexOrDecimalU256, serde::{Deserialize, Serialize}, serde_with::{DisplayFromStr, serde_as}, std::collections::HashMap, - web3::types::{H160, H256, U256}, }; #[serde_as] @@ -15,23 +14,23 @@ use { pub struct Auction { #[serde_as(as = "Option")] pub id: Option, - pub tokens: HashMap, + pub tokens: HashMap, pub orders: Vec, pub liquidity: Vec, #[serde_as(as = "HexOrDecimalU256")] pub effective_gas_price: U256, pub deadline: chrono::DateTime, - pub surplus_capturing_jit_order_owners: Vec, + pub surplus_capturing_jit_order_owners: Vec
, } #[serde_as] #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Order { - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] pub uid: [u8; 56], - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, #[serde_as(as = "HexOrDecimalU256")] pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] @@ -45,8 +44,8 @@ pub struct Order { pub valid_to: u32, pub kind: Kind, #[serde(skip_serializing_if = "Option::is_none")] - pub receiver: Option, - pub owner: H160, + pub receiver: Option
, + pub owner: Address, pub partially_fillable: bool, pub pre_interactions: Vec, pub post_interactions: Vec, @@ -90,7 +89,7 @@ pub enum SellTokenSource { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct InteractionData { - pub target: H160, + pub target: Address, #[serde_as(as = "HexOrDecimalU256")] pub value: U256, #[serde(with = "bytes_hex")] @@ -175,11 +174,11 @@ pub enum Liquidity { #[serde(rename_all = "camelCase")] pub struct ConstantProductPool { pub id: String, - pub address: H160, - pub router: H160, + pub address: Address, + pub router: Address, #[serde_as(as = "HexOrDecimalU256")] pub gas_estimate: U256, - pub tokens: HashMap, + pub tokens: HashMap, pub fee: BigDecimal, } @@ -196,11 +195,11 @@ pub struct ConstantProductReserve { #[serde(rename_all = "camelCase")] pub struct WeightedProductPool { pub id: String, - pub address: H160, - pub balancer_pool_id: H256, + pub address: Address, + pub balancer_pool_id: B256, #[serde_as(as = "HexOrDecimalU256")] pub gas_estimate: U256, - pub tokens: HashMap, + pub tokens: HashMap, pub fee: BigDecimal, pub version: WeightedProductVersion, } @@ -227,11 +226,11 @@ pub enum WeightedProductVersion { #[serde(rename_all = "camelCase")] pub struct StablePool { pub id: String, - pub address: H160, - pub balancer_pool_id: H256, + pub address: Address, + pub balancer_pool_id: B256, #[serde_as(as = "HexOrDecimalU256")] pub gas_estimate: U256, - pub tokens: HashMap, + pub tokens: HashMap, pub amplification_parameter: BigDecimal, pub fee: BigDecimal, } @@ -250,11 +249,11 @@ pub struct StableReserve { #[serde(rename_all = "camelCase")] pub struct ConcentratedLiquidityPool { pub id: String, - pub address: H160, - pub router: H160, + pub address: Address, + pub router: Address, #[serde_as(as = "HexOrDecimalU256")] pub gas_estimate: U256, - pub tokens: Vec, + pub tokens: Vec
, #[serde_as(as = "HexOrDecimalU256")] pub sqrt_price: U256, #[serde_as(as = "DisplayFromStr")] @@ -270,13 +269,13 @@ pub struct ConcentratedLiquidityPool { #[serde(rename_all = "camelCase")] pub struct ForeignLimitOrder { pub id: String, - pub address: H160, + pub address: Address, #[serde_as(as = "HexOrDecimalU256")] pub gas_estimate: U256, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] pub hash: [u8; 32], - pub maker_token: H160, - pub taker_token: H160, + pub maker_token: Address, + pub taker_token: Address, #[serde_as(as = "HexOrDecimalU256")] pub maker_amount: U256, #[serde_as(as = "HexOrDecimalU256")] @@ -289,10 +288,10 @@ pub struct ForeignLimitOrder { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct FlashloanHint { - pub liquidity_provider: H160, - pub protocol_adapter: H160, - pub receiver: H160, - pub token: H160, + pub liquidity_provider: Address, + pub protocol_adapter: Address, + pub receiver: Address, + pub token: Address, #[serde_as(as = "HexOrDecimalU256")] pub amount: U256, } @@ -300,7 +299,7 @@ pub struct FlashloanHint { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WrapperCall { - pub address: H160, + pub address: Address, #[serde(with = "bytes_hex")] pub data: Vec, /// Declares whether this wrapper (and its data) needs to be included diff --git a/crates/solvers-dto/src/lib.rs b/crates/solvers-dto/src/lib.rs index 2fe62793e6..d7c9d518dc 100644 --- a/crates/solvers-dto/src/lib.rs +++ b/crates/solvers-dto/src/lib.rs @@ -4,109 +4,3 @@ pub mod auction; pub mod notification; pub mod solution; - -mod serialize { - use { - serde::{Deserializer, Serializer, de}, - serde_with::{DeserializeAs, SerializeAs}, - }; - - /// Serialize and deserialize binary data as a hexadecimal string. - #[derive(Debug)] - pub struct Hex; - - impl<'de> DeserializeAs<'de, Vec> for Hex { - fn deserialize_as>(deserializer: D) -> Result, D::Error> { - struct Visitor; - - impl de::Visitor<'_> for Visitor { - type Value = Vec; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(formatter, "a hex-encoded string starting with \"0x\"") - } - - fn visit_str(self, s: &str) -> Result - where - E: de::Error, - { - if !s.starts_with("0x") { - return Err(de::Error::custom(format!( - "failed to decode {s:?} as a hex string: missing \"0x\" prefix", - ))); - } - const_hex::decode(&s[2..]).map_err(|err| { - de::Error::custom(format!("failed to decode {s:?} as a hex string: {err}",)) - }) - } - } - - deserializer.deserialize_str(Visitor) - } - } - - impl SerializeAs> for Hex { - fn serialize_as(source: &Vec, serializer: S) -> Result { - serializer.serialize_str(&bytes_to_hex_string(source.as_ref())) - } - } - - impl<'de, const N: usize> DeserializeAs<'de, [u8; N]> for Hex { - fn deserialize_as>(deserializer: D) -> Result<[u8; N], D::Error> { - struct Visitor { - result: [u8; N], - } - - impl de::Visitor<'_> for Visitor { - type Value = [u8; N]; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - formatter, - "a hex-encoded string starting with \"0x\" containing {N} bytes", - ) - } - - fn visit_str(mut self, s: &str) -> Result - where - E: de::Error, - { - if !s.starts_with("0x") { - return Err(de::Error::custom(format!( - "failed to decode {s:?} as a hex string: missing \"0x\" prefix", - ))); - } - let decoded = const_hex::decode(&s[2..]).map_err(|err| { - de::Error::custom(format!("failed to decode {s:?} as a hex string: {err}",)) - })?; - if decoded.len() != N { - return Err(de::Error::custom(format!( - "failed to decode {s:?} as a hex string: expected {N} bytes, got {}", - decoded.len() - ))); - } - self.result.copy_from_slice(&decoded); - Ok(self.result) - } - } - - deserializer.deserialize_str(Visitor { result: [0; N] }) - } - } - - impl SerializeAs<[u8; N]> for Hex { - fn serialize_as(source: &[u8; N], serializer: S) -> Result { - serializer.serialize_str(&bytes_to_hex_string(source)) - } - } - - fn bytes_to_hex_string(bytes: &[u8]) -> String { - let mut v = vec![0u8; 2 + bytes.len() * 2]; - v[0] = b'0'; - v[1] = b'x'; - // Unwrap because only possible error is vector wrong size which cannot happen. - const_hex::encode_to_slice(bytes, &mut v[2..]).unwrap(); - // Unwrap because encoded data is always valid utf8. - String::from_utf8(v).unwrap() - } -} diff --git a/crates/solvers-dto/src/notification.rs b/crates/solvers-dto/src/notification.rs index eac6d75fb1..dbbff28c23 100644 --- a/crates/solvers-dto/src/notification.rs +++ b/crates/solvers-dto/src/notification.rs @@ -1,11 +1,10 @@ use { - super::serialize, - chrono::{DateTime, Utc}, + alloy_primitives::{Address, B256, U256}, + alloy_rpc_types_eth::AccessList, number::serialization::HexOrDecimalU256, serde::{Deserialize, Serialize}, serde_with::{DisplayFromStr, serde_as}, std::collections::BTreeSet, - web3::types::{AccessList, H160, H256, U256}, }; #[serde_as] @@ -43,21 +42,22 @@ pub enum Kind { InvalidClearingPrices, #[serde(rename_all = "camelCase")] MissingPrice { - token_address: H160, + token_address: Address, }, InvalidExecutedAmount, NonBufferableTokensUsed { - tokens: BTreeSet, + tokens: BTreeSet
, }, SolverAccountInsufficientBalance { #[serde_as(as = "HexOrDecimalU256")] required: U256, }, + SettlementStarted, Success { - transaction: H256, + transaction: B256, }, Revert { - transaction: H256, + transaction: B256, }, DriverError { reason: String, @@ -66,10 +66,6 @@ pub enum Kind { Expired, Fail, PostprocessingTimedOut, - Banned { - reason: BanReason, - until: DateTime, - }, DeserializationError { reason: String, }, @@ -81,18 +77,11 @@ type BlockNo = u64; #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Tx { - pub from: H160, - pub to: H160, - #[serde_as(as = "serialize::Hex")] + pub from: Address, + pub to: Address, + #[serde_as(as = "serde_ext::Hex")] pub input: Vec, #[serde_as(as = "HexOrDecimalU256")] pub value: U256, pub access_list: AccessList, } - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", tag = "reason")] -pub enum BanReason { - UnsettledConsecutiveAuctions, - HighSettleFailureRate, -} diff --git a/crates/solvers-dto/src/solution.rs b/crates/solvers-dto/src/solution.rs index 2037117c3f..0a9d1b5ba7 100644 --- a/crates/solvers-dto/src/solution.rs +++ b/crates/solvers-dto/src/solution.rs @@ -1,16 +1,45 @@ use { - super::serialize, + alloy_primitives::{Address, U256}, number::serialization::HexOrDecimalU256, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::HashMap, - web3::types::{H160, U256}, }; -#[derive(Debug, Serialize, Deserialize, Default)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] -pub struct Solutions { - pub solutions: Vec, +pub struct SolverError { + pub code: SolverErrorCode, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub enum SolverErrorCode { + /// Token can only be traded during specific time windows (e.g., RWA tokens) + TradingOutsideAllowedWindow, + /// Token is temporarily suspended from trading + TokenTemporarilySuspended, + /// Insufficient liquidity for the requested trade size + InsufficientLiquidity, + /// Generic solver error with custom message + Other, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum SolverResponse { + Solutions { solutions: Vec }, + Error { error: SolverError }, +} + +impl Default for SolverResponse { + fn default() -> Self { + Self::Solutions { + solutions: Vec::new(), + } + } } #[serde_as] @@ -19,7 +48,7 @@ pub struct Solutions { pub struct Solution { pub id: u64, #[serde_as(as = "HashMap<_, HexOrDecimalU256>")] - pub prices: HashMap, + pub prices: HashMap, pub trades: Vec, #[serde(default)] pub pre_interactions: Vec, @@ -28,6 +57,8 @@ pub struct Solution { pub post_interactions: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub gas: Option, + #[serde(flatten)] + pub gas_fee_override: Option, #[serde(skip_serializing_if = "Option::is_none", default)] pub flashloans: Option>, #[serde(skip_serializing_if = "Vec::is_empty", default)] @@ -36,7 +67,7 @@ pub struct Solution { #[serde_as] #[derive(Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq)] -pub struct OrderUid(#[serde_as(as = "serialize::Hex")] pub [u8; 56]); +pub struct OrderUid(#[serde_as(as = "serde_ext::Hex")] pub [u8; 56]); #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "camelCase")] @@ -73,9 +104,9 @@ pub struct JitTrade { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct JitOrder { - pub sell_token: H160, - pub buy_token: H160, - pub receiver: H160, + pub sell_token: Address, + pub buy_token: Address, + pub receiver: Address, #[serde_as(as = "HexOrDecimalU256")] pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] @@ -83,13 +114,13 @@ pub struct JitOrder { #[serde(default)] pub partially_fillable: bool, pub valid_to: u32, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] pub app_data: [u8; 32], pub kind: Kind, pub sell_token_balance: SellTokenBalance, pub buy_token_balance: BuyTokenBalance, pub signing_scheme: SigningScheme, - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] pub signature: Vec, } @@ -111,10 +142,10 @@ pub enum Interaction { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "camelCase")] pub struct Call { - pub target: H160, + pub target: Address, pub value: U256, #[serde(rename = "callData")] - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] pub calldata: Vec, } @@ -124,8 +155,8 @@ pub struct Call { pub struct LiquidityInteraction { pub internalize: bool, pub id: String, - pub input_token: H160, - pub output_token: H160, + pub input_token: Address, + pub output_token: Address, #[serde_as(as = "HexOrDecimalU256")] pub input_amount: U256, #[serde_as(as = "HexOrDecimalU256")] @@ -137,11 +168,11 @@ pub struct LiquidityInteraction { #[serde(rename_all = "camelCase")] pub struct CustomInteraction { pub internalize: bool, - pub target: H160, + pub target: Address, #[serde_as(as = "HexOrDecimalU256")] pub value: U256, #[serde(rename = "callData")] - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] pub calldata: Vec, pub allowances: Vec, pub inputs: Vec, @@ -154,11 +185,11 @@ pub struct CustomInteraction { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct OrderInteraction { - pub target: H160, + pub target: Address, #[serde_as(as = "HexOrDecimalU256")] pub value: U256, #[serde(rename = "callData")] - #[serde_as(as = "serialize::Hex")] + #[serde_as(as = "serde_ext::Hex")] pub calldata: Vec, } @@ -166,7 +197,7 @@ pub struct OrderInteraction { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Asset { - pub token: H160, + pub token: Address, #[serde_as(as = "HexOrDecimalU256")] pub amount: U256, } @@ -175,8 +206,8 @@ pub struct Asset { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Allowance { - pub token: H160, - pub spender: H160, + pub token: Address, + pub spender: Address, #[serde_as(as = "HexOrDecimalU256")] pub amount: U256, } @@ -207,14 +238,25 @@ pub enum SigningScheme { Eip1271, } +/// Solver-provided gas fee overrides for the settlement transaction. +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GasFeeOverride { + #[serde_as(as = "HexOrDecimalU256")] + pub max_fee_per_gas: U256, + #[serde_as(as = "HexOrDecimalU256")] + pub max_priority_fee_per_gas: U256, +} + #[serde_as] #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Flashloan { - pub liquidity_provider: H160, - pub protocol_adapter: H160, - pub receiver: H160, - pub token: H160, + pub liquidity_provider: Address, + pub protocol_adapter: Address, + pub receiver: Address, + pub token: Address, #[serde_as(as = "HexOrDecimalU256")] pub amount: U256, } @@ -223,8 +265,72 @@ pub struct Flashloan { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WrapperCall { - pub address: H160, - #[serde_as(as = "serialize::Hex")] + pub address: Address, + #[serde_as(as = "serde_ext::Hex")] #[serde(default)] pub data: Vec, } + +#[cfg(test)] +mod tests { + use {super::*, serde_json::json}; + + #[test] + fn serializes_empty_solutions_response() { + let response = SolverResponse::default(); + + let value = serde_json::to_value(response).unwrap(); + assert_eq!( + value, + json!({ + "solutions": [], + }) + ); + } + + #[test] + fn serializes_and_deserializes_error_responses() { + let cases = vec![ + ( + SolverErrorCode::TradingOutsideAllowedWindow, + "tradingOutsideAllowedWindow", + ), + ( + SolverErrorCode::TokenTemporarilySuspended, + "tokenTemporarilySuspended", + ), + ( + SolverErrorCode::InsufficientLiquidity, + "insufficientLiquidity", + ), + (SolverErrorCode::Other, "other"), + ]; + + for (code, expected_code) in cases { + let response = SolverResponse::Error { + error: SolverError { + code: code.clone(), + message: Some("custom message".to_string()), + }, + }; + + let value = serde_json::to_value(response).unwrap(); + assert_eq!( + value, + json!({ + "error": { + "code": expected_code, + "message": "custom message", + }, + }) + ); + + let decoded: SolverResponse = serde_json::from_value(value).unwrap(); + assert!(matches!( + decoded, + SolverResponse::Error { error } + if error.code == code && error.message.as_deref() == Some("custom message") + )); + } + } +} diff --git a/crates/solvers/Cargo.toml b/crates/solvers/Cargo.toml index 184331fce1..513a8fb8e2 100644 --- a/crates/solvers/Cargo.toml +++ b/crates/solvers/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2024" [lib] +doctest = false name = "solvers" path = "src/lib.rs" -doctest = false [[bin]] name = "solvers" @@ -15,52 +15,66 @@ path = "src/main.rs" [dependencies] alloy = { workspace = true } axum = { workspace = true } +base64 = { workspace = true } bigdecimal = { workspace = true, features = ["serde"] } +bytes-hex = { workspace = true } chain = { workspace = true } -chrono = { workspace = true, features = ["serde"], default-features = false } +chrono = { workspace = true, default-features = false, features = ["serde"] } clap = { workspace = true, features = ["derive", "env"] } +configs = { workspace = true } +const-hex = { workspace = true } derive_more = { workspace = true } -ethereum-types = { workspace = true } ethrpc = { workspace = true } futures = { workspace = true } -const-hex = { workspace = true } -hex-literal = { workspace = true } -hyper = { workspace = true } -ethcontract = { workspace = true } +hmac = { workspace = true } +humantime-serde = { workspace = true } itertools = { workspace = true } -mimalloc = { workspace = true } +liquidity-sources = { workspace = true } +mimalloc = { workspace = true, optional = true } +moka = { workspace = true, features = ["future"] } num = { workspace = true } +number = { workspace = true } +price-estimation = { workspace = true } prometheus = { workspace = true } prometheus-metric-storage = { workspace = true } +rate-limit = { workspace = true } reqwest = { workspace = true } -url = { workspace = true, features = ["serde"] } serde = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } +sha2 = { workspace = true } solvers-dto = { workspace = true } +thiserror = { workspace = true } +tikv-jemallocator = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "time"] } toml = { workspace = true } tower = { workspace = true } tower-http = { workspace = true, features = ["limit", "trace"] } -web3 = { workspace = true } +url = { workspace = true, features = ["serde"] } # TODO Once solvers are ported and E2E tests set up, slowly migrate code and # remove/re-evaluate these dependencies. anyhow = { workspace = true } contracts = { workspace = true } model = { workspace = true } -observe = { workspace = true, features = ["axum-tracing"] } +observe = { workspace = true } shared = { workspace = true } solver = { workspace = true } tracing = { workspace = true } [dev-dependencies] +glob = "0.3" +maplit = { workspace = true } tempfile = { workspace = true } -ethcontract = { workspace = true } +testlib = { workspace = true } [build-dependencies] anyhow = { workspace = true } vergen = { workspace = true, features = ["git", "gitcl"] } +[features] +mimalloc-allocator = ["dep:mimalloc"] +tokio-console = ["observe/tokio-console"] + [lints] workspace = true diff --git a/crates/solvers/config/example.baseline.toml b/crates/solvers/config/example.baseline.toml index cf4197a0c0..c67b622866 100644 --- a/crates/solvers/config/example.baseline.toml +++ b/crates/solvers/config/example.baseline.toml @@ -1,6 +1,6 @@ chain-id = "1" # Alternatively, you can manually specify a WETH contract address: -#weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" +# weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" base-tokens = [] max-hops = 0 max-partial-attempts = 5 diff --git a/crates/solvers/config/example.bitget.toml b/crates/solvers/config/example.bitget.toml new file mode 100644 index 0000000000..3e400a0fd7 --- /dev/null +++ b/crates/solvers/config/example.bitget.toml @@ -0,0 +1,19 @@ +node-url = "http://localhost:8545" + +[dex] +# Specify which chain to use, 1 for Ethereum. +# Supported chains: eth (1), bsc (56), base (8453) +chain-id = "1" + +# Optionally specify a custom Bitget swap API endpoint +# endpoint = "https://bopenapi.bgwapi.io/bgw-pro/swapx/pro/" + +[dex.credentials] +# Bitget API key (obtain from Bitget integration team) +api-key = "$BITGET_API_KEY" + +# Bitget API secret for signing requests +api-secret = "$BITGET_API_SECRET" + +# Partner code sent in the Partner-Code header (defaults to "cowswap") +# partner-code = "cowswap" diff --git a/crates/solvers/config/example.okx.toml b/crates/solvers/config/example.okx.toml new file mode 100644 index 0000000000..a0236d7ece --- /dev/null +++ b/crates/solvers/config/example.okx.toml @@ -0,0 +1,51 @@ +node-url = "http://localhost:8545" + +[dex] +# Specify which chain to use, 1 for Ethereum. +# More info here: https://www.okx.com/en-au/web3/build/docs/waas/walletapi-resources-supported-networks +chain-id = "1" + +# Optionally specify custom OKX Swap API endpoints +# Sell orders endpoint (exactIn mode, uses V6 API by default) +# sell-orders-endpoint = "https://web3.okx.com/api/v6/dex/aggregator/" + +# Buy orders endpoint (exactOut mode, uses V5 API, only supports Ethereum, Base, BSC, and Arbitrum chains and only Uni v2 and v3 protocols) +# If not specified, buy orders will be ignored. +# buy-orders-endpoint = "https://www.okx.com/api/v5/dex/aggregator/" + +# Optional: When using a proxy, specify the original OKX API URLs for signature generation +# These URLs are used only for generating the request signature, while the actual requests +# are sent to the endpoints configured above (sell-orders-endpoint and buy-orders-endpoint). +# If not specified, the signature is generated using the endpoint URLs. +# +# Example proxy configuration: +# sell-orders-endpoint = "https://your-proxy.example.com/okx/v6/" +# sell-orders-signature-base-url = "https://web3.okx.com/api/v6/dex/aggregator/" +# buy-orders-endpoint = "https://your-proxy.example.com/okx/v5/" +# buy-orders-signature-base-url = "https://www.okx.com/api/v5/dex/aggregator/" + +# OKX Project ID. Instruction on how to create a project: +# https://www.okx.com/en-au/web3/build/docs/waas/introduction-to-developer-portal-interface#create-project +api-project-id = "$OKX_PROJECT_ID" + +# OKX API Key. Instruction on how to generate an API key: +# https://www.okx.com/en-au/web3/build/docs/waas/introduction-to-developer-portal-interface#generate-api-keys +api-key = "$OKX_API_KEY" + +# OKX Secret key used for signing request. Instruction on how to get a security token: +# https://www.okx.com/en-au/web3/build/docs/waas/introduction-to-developer-portal-interface#view-the-secret-key +api-secret-key = "$OKX_SECRET_KEY" + +# OKX Secret key passphrase. Instruction on how to get a passphrase: +# https://www.okx.com/en-au/web3/build/docs/waas/introduction-to-developer-portal-interface#generate-api-keys +api-passphrase = "$OKX_PASSPHRASE" + +# Optional: Price impact protection percentage (between 0.0 - 1.0). +# OKX API documentation: https://web3.okx.com/build/dev-docs/wallet-api/dex-swap +# +# When set to 1.0 (100%), the feature is disabled - all trades are allowed. +# Note: If this field is omitted entirely, OKX API defaults to 0.9 (90% protection), +# but this config defaults to 1.0 to disable the feature by default. +# +# Examples: +# price-impact-protection-percent = 1.0 # Disabled (default) - allow all trades diff --git a/crates/solvers/openapi.yml b/crates/solvers/openapi.yml index 24025a7123..98232cf589 100644 --- a/crates/solvers/openapi.yml +++ b/crates/solvers/openapi.yml @@ -1014,6 +1014,24 @@ components: gas: type: integer description: How many units of gas this solution is estimated to cost. + maxFeePerGas: + description: | + Optional maximum fee per gas for the settlement transaction. + Overrides the driver's default gas price estimation. + Must be provided together with maxPriorityFeePerGas. + Note: the driver may raise this value if a pending replacement + transaction requires a higher gas price. + allOf: + - $ref: "#/components/schemas/U256" + maxPriorityFeePerGas: + description: | + Optional maximum priority fee (tip) per gas for the settlement + transaction. Overrides the driver's default gas price estimation. + Must be provided together with maxFeePerGas. + Note: the driver may raise this value if a pending replacement + transaction requires a higher gas price. + allOf: + - $ref: "#/components/schemas/U256" flashloans: description: | Flashloans that are provided for this solution, mapping order UIDs to flashloan details. diff --git a/crates/solvers/src/api/mod.rs b/crates/solvers/src/api/mod.rs index 734365291c..7a866e3082 100644 --- a/crates/solvers/src/api/mod.rs +++ b/crates/solvers/src/api/mod.rs @@ -2,7 +2,7 @@ use { crate::domain::solver::Solver, - observe::distributed_tracing::tracing_axum::{make_span, record_trace_id}, + observe::tracing::distributed::axum::{make_span, record_trace_id}, std::{future::Future, net::SocketAddr, sync::Arc}, tokio::sync::oneshot, }; @@ -21,7 +21,7 @@ impl Api { self, bind: Option>, shutdown: impl Future + Send + 'static, - ) -> Result<(), hyper::Error> { + ) -> Result<(), std::io::Error> { let app = axum::Router::new() .layer(tower::ServiceBuilder::new().layer( tower_http::limit::RequestBodyLimitLayer::new(REQUEST_BODY_LIMIT), @@ -38,11 +38,13 @@ impl Api { // axum's default body limit needs to be disabled to not have the default limit on top of our custom limit .layer(axum::extract::DefaultBodyLimit::disable()); - let server = axum::Server::bind(&self.addr).serve(app.into_make_service()); + let listener = tokio::net::TcpListener::bind(self.addr).await?; if let Some(bind) = bind { - let _ = bind.send(server.local_addr()); + let _ = bind.send(listener.local_addr()?); } - server.with_graceful_shutdown(shutdown).await + axum::serve(listener, app) + .with_graceful_shutdown(shutdown) + .await } } diff --git a/crates/solvers/src/api/routes/healthz.rs b/crates/solvers/src/api/routes/healthz.rs index 7e39e585dc..fc34fe28c8 100644 --- a/crates/solvers/src/api/routes/healthz.rs +++ b/crates/solvers/src/api/routes/healthz.rs @@ -1,5 +1,8 @@ -use axum::{http::StatusCode, response::IntoResponse}; +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; -pub async fn healthz() -> impl IntoResponse { - StatusCode::OK +pub async fn healthz() -> Response { + StatusCode::OK.into_response() } diff --git a/crates/solvers/src/api/routes/solve/dto/auction.rs b/crates/solvers/src/api/routes/solve/dto/auction.rs index 3bbc635716..6b4116d5a8 100644 --- a/crates/solvers/src/api/routes/solve/dto/auction.rs +++ b/crates/solvers/src/api/routes/solve/dto/auction.rs @@ -63,9 +63,9 @@ pub fn into_domain(auction: Auction) -> Result { .flashloan_hint .clone() .map(|hint| order::FlashloanHint { - liquidity_provider: eth::Address(hint.liquidity_provider), - protocol_adapter: eth::Address(hint.protocol_adapter), - receiver: eth::Address(hint.receiver), + liquidity_provider: hint.liquidity_provider, + protocol_adapter: hint.protocol_adapter, + receiver: hint.receiver, token: eth::TokenAddress(hint.token), amount: hint.amount, }), diff --git a/crates/solvers/src/api/routes/solve/dto/mod.rs b/crates/solvers/src/api/routes/solve/dto/mod.rs index bbe9069a97..003b32c44e 100644 --- a/crates/solvers/src/api/routes/solve/dto/mod.rs +++ b/crates/solvers/src/api/routes/solve/dto/mod.rs @@ -1,4 +1,4 @@ pub mod auction; pub mod solution; -pub use solvers_dto::{auction::Auction, solution::Solutions}; +pub use solvers_dto::{auction::Auction, solution::SolverResponse}; diff --git a/crates/solvers/src/api/routes/solve/dto/solution.rs b/crates/solvers/src/api/routes/solve/dto/solution.rs index 206a9428c2..c4da3dc843 100644 --- a/crates/solvers/src/api/routes/solve/dto/solution.rs +++ b/crates/solvers/src/api/routes/solve/dto/solution.rs @@ -4,8 +4,8 @@ use { }; /// Creates a new solution DTO from its domain object. -pub fn from_domain(solutions: &[solution::Solution]) -> super::Solutions { - super::Solutions { +pub fn from_domain(solutions: &[solution::Solution]) -> super::SolverResponse { + SolverResponse::Solutions { solutions: solutions .iter() .map(|solution| Solution { @@ -115,14 +115,17 @@ pub fn from_domain(solutions: &[solution::Solution]) -> super::Solutions { } }) .collect(), - gas: solution.gas.map(|gas| gas.0.as_u64()), + gas: solution + .gas + .map(|gas| u64::try_from(gas.0).unwrap_or(u64::MAX)), + gas_fee_override: None, // rely on driver to fill in the blanks flashloans: None, wrappers: solution .wrappers .iter() .map(|w| solvers_dto::solution::WrapperCall { - address: w.target.0, + address: w.target, data: w.data.clone(), }) .collect(), @@ -135,7 +138,7 @@ fn interaction_data_from_domain(interaction_data: &[eth::Interaction]) -> Vec, ) -> ( axum::http::StatusCode, - axum::response::Json>, + axum::response::Json>, ) { let handle_request = async { let auction = match dto::auction::into_domain(auction) { diff --git a/crates/solvers/src/boundary/baseline.rs b/crates/solvers/src/boundary/baseline.rs index c023e21461..394d758e49 100644 --- a/crates/solvers/src/boundary/baseline.rs +++ b/crates/solvers/src/boundary/baseline.rs @@ -2,14 +2,16 @@ use { crate::{ - boundary, + boundary::{ + self, + routing::{estimate_buy_amount, estimate_sell_amount}, + }, domain::{eth, liquidity, order, solver}, }, - contracts::alloy::UniswapV3QuoterV2, - ethereum_types::{H160, U256}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + alloy::primitives::{Address, U256}, + contracts::UniswapV3QuoterV2, + liquidity_sources::{base_tokens::BaseTokens, baseline_solvable::BaselineSolvable}, model::TokenPair, - shared::baseline_solver::{self, BaseTokens, BaselineSolvable}, std::{ collections::{HashMap, HashSet}, sync::Arc, @@ -53,12 +55,10 @@ impl<'a> Solver<'a> { let (segments, _) = match request.side { order::Side::Buy => { let futures = candidates.iter().map(|path| async { - let sell = baseline_solver::estimate_sell_amount( - request.buy.amount, - path, - &self.onchain_liquidity, - ) - .await?; + let sell = + estimate_sell_amount(request.buy.amount, path, &self.onchain_liquidity) + .await?; + let segments = self .traverse_path(&sell.path, request.sell.token.0, sell.value) .await?; @@ -83,12 +83,10 @@ impl<'a> Solver<'a> { } order::Side::Sell => { let futures = candidates.iter().map(|path| async { - let buy = baseline_solver::estimate_buy_amount( - request.sell.amount, - path, - &self.onchain_liquidity, - ) - .await?; + let buy = + estimate_buy_amount(request.sell.amount, path, &self.onchain_liquidity) + .await?; + let segments = self .traverse_path(&buy.path, request.sell.token.0, request.sell.amount) .await?; @@ -119,7 +117,7 @@ impl<'a> Solver<'a> { async fn traverse_path( &self, path: &[&OnchainLiquidity], - mut sell_token: H160, + mut sell_token: Address, mut sell_amount: U256, ) -> Option>> { let mut segments = Vec::new(); @@ -131,10 +129,10 @@ impl<'a> Solver<'a> { let buy_token = liquidity .token_pair - .other(&sell_token.into_alloy()) + .other(&sell_token) .expect("Inconsistent path"); let buy_amount = liquidity - .get_amount_out(buy_token.into_legacy(), (sell_amount, sell_token)) + .get_amount_out(buy_token, (sell_amount, sell_token)) .await?; segments.push(solver::Segment { @@ -144,13 +142,13 @@ impl<'a> Solver<'a> { amount: sell_amount, }, output: eth::Asset { - token: eth::TokenAddress(buy_token.into_legacy()), + token: eth::TokenAddress(buy_token), amount: buy_amount, }, - gas: eth::Gas(liquidity.gas_cost().await.into()), + gas: eth::Gas(U256::from(liquidity.gas_cost().await)), }); - sell_token = buy_token.into_legacy(); + sell_token = buy_token; sell_amount = buy_amount; } Some(segments) @@ -159,7 +157,7 @@ impl<'a> Solver<'a> { fn to_boundary_liquidity( liquidity: &[liquidity::Liquidity], - uni_v3_quoter_v2: Option>, + uni_v3_quoter_v2: Option>, ) -> HashMap> { liquidity .iter() @@ -218,10 +216,9 @@ fn to_boundary_liquidity( } } liquidity::State::LimitOrder(limit_order) => { - if let Some(token_pair) = TokenPair::new( - limit_order.maker.token.0.into_alloy(), - limit_order.taker.token.0.into_alloy(), - ) { + if let Some(token_pair) = + TokenPair::new(limit_order.maker.token.0, limit_order.taker.token.0) + { onchain_liquidity .entry(token_pair) .or_default() @@ -278,7 +275,11 @@ enum LiquiditySource { } impl BaselineSolvable for OnchainLiquidity { - async fn get_amount_out(&self, out_token: H160, input: (U256, H160)) -> Option { + async fn get_amount_out( + &self, + out_token: Address, + input: (alloy::primitives::U256, Address), + ) -> Option { match &self.source { LiquiditySource::ConstantProduct(pool) => pool.get_amount_out(out_token, input).await, LiquiditySource::WeightedProduct(pool) => pool.get_amount_out(out_token, input).await, @@ -290,7 +291,11 @@ impl BaselineSolvable for OnchainLiquidity { } } - async fn get_amount_in(&self, in_token: H160, out: (U256, H160)) -> Option { + async fn get_amount_in( + &self, + in_token: Address, + out: (alloy::primitives::U256, Address), + ) -> Option { match &self.source { LiquiditySource::ConstantProduct(pool) => pool.get_amount_in(in_token, out).await, LiquiditySource::WeightedProduct(pool) => pool.get_amount_in(in_token, out).await, @@ -323,5 +328,5 @@ fn to_boundary_base_tokens( fn to_boundary_token_pair(pair: &liquidity::TokenPair) -> TokenPair { let (a, b) = pair.get(); - TokenPair::new(a.0.into_alloy(), b.0.into_alloy()).unwrap() + TokenPair::new(a.0, b.0).unwrap() } diff --git a/crates/solvers/src/boundary/liquidity/concentrated.rs b/crates/solvers/src/boundary/liquidity/concentrated.rs index 51227e3148..e9ad48cba3 100644 --- a/crates/solvers/src/boundary/liquidity/concentrated.rs +++ b/crates/solvers/src/boundary/liquidity/concentrated.rs @@ -1,22 +1,18 @@ use { - alloy::primitives::aliases::U24, - contracts::{ - alloy::UniswapV3QuoterV2::IQuoterV2::{ - QuoteExactInputSingleParams, - QuoteExactOutputSingleParams, - }, - ethcontract::{H160, U256}, + alloy::primitives::{Address, U256, aliases::U24}, + contracts::UniswapV3QuoterV2::IQuoterV2::{ + QuoteExactInputSingleParams, + QuoteExactOutputSingleParams, }, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + liquidity_sources::baseline_solvable::BaselineSolvable, model::TokenPair, - shared::baseline_solver::BaselineSolvable, std::sync::Arc, }; #[derive(Debug)] pub struct Pool { - pub uni_v3_quoter_contract: Arc, - pub address: H160, + pub uni_v3_quoter_contract: Arc, + pub address: Address, pub tokens: TokenPair, pub fee: U24, } @@ -31,49 +27,49 @@ impl Pool { impl BaselineSolvable for Pool { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { - if TokenPair::new(out_token.into_alloy(), in_token.into_alloy()) != Some(self.tokens) { + if TokenPair::new(out_token, in_token) != Some(self.tokens) { // The pool has wrong tokens or input amount would overflow return None; } self.uni_v3_quoter_contract .quoteExactInputSingle(QuoteExactInputSingleParams { - tokenIn: in_token.into_alloy(), - tokenOut: out_token.into_alloy(), - amountIn: in_amount.into_alloy(), + tokenIn: in_token, + tokenOut: out_token, + amountIn: in_amount, fee: self.fee, sqrtPriceLimitX96: alloy::primitives::U160::ZERO, }) .call() .await - .map(|result| result.amountOut.into_legacy()) + .map(|result| result.amountOut) .ok() } async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { - if TokenPair::new(out_token.into_alloy(), in_token.into_alloy()) != Some(self.tokens) { + if TokenPair::new(out_token, in_token) != Some(self.tokens) { // The pool has wrong tokens or out amount would overflow return None; } self.uni_v3_quoter_contract .quoteExactOutputSingle(QuoteExactOutputSingleParams { - tokenIn: in_token.into_alloy(), - tokenOut: out_token.into_alloy(), - amount: out_amount.into_alloy(), + tokenIn: in_token, + tokenOut: out_token, + amount: out_amount, fee: self.fee, sqrtPriceLimitX96: alloy::primitives::U160::ZERO, }) .call() .await - .map(|result| result.amountIn.into_legacy()) + .map(|result| result.amountIn) .ok() } diff --git a/crates/solvers/src/boundary/liquidity/constant_product.rs b/crates/solvers/src/boundary/liquidity/constant_product.rs index a8fd170d28..4d4dbecf6b 100644 --- a/crates/solvers/src/boundary/liquidity/constant_product.rs +++ b/crates/solvers/src/boundary/liquidity/constant_product.rs @@ -1,28 +1,48 @@ -pub use shared::sources::uniswap_v2::pool_fetching::Pool; -use { - crate::domain::liquidity, - ethereum_types::H160, - ethrpc::alloy::conversions::IntoAlloy, - model::TokenPair, -}; +pub use liquidity_sources::uniswap_v2::pool_fetching::Pool; +use {crate::domain::liquidity, alloy::primitives::Address, model::TokenPair}; /// Converts a domain pool into a [`shared`] Uniswap V2 pool. Returns `None` if /// the domain pool cannot be represented as a boundary pool. -pub fn to_boundary_pool(address: H160, pool: &liquidity::constant_product::Pool) -> Option { +pub fn to_boundary_pool( + address: Address, + pool: &liquidity::constant_product::Pool, +) -> Option { let reserves = pool.reserves.get(); - let tokens = TokenPair::new( - reserves.0.token.0.into_alloy(), - reserves.1.token.0.into_alloy(), - ) - .expect("tokens are distinct by construction"); + let tokens = TokenPair::new(reserves.0.token.0, reserves.1.token.0) + .expect("tokens are distinct by construction"); // reserves are ordered by construction. - let reserves = (reserves.0.amount.as_u128(), reserves.1.amount.as_u128()); + let reserves = ( + u128::try_from(reserves.0.amount) + .inspect_err(|_| { + tracing::debug!( + address = %reserves.0.token.0, + "asset 0 amount > u128" + ); + }) + .ok()?, + u128::try_from(reserves.1.amount) + .inspect_err(|_| { + tracing::debug!( + address = %reserves.1.token.0, + "asset 1 amount > u128" + ); + }) + .ok()?, + ); - if *pool.fee.numer() > u32::MAX.into() || *pool.fee.denom() > u32::MAX.into() { - return None; - } - let fee = num::rational::Ratio::new(pool.fee.numer().as_u32(), pool.fee.denom().as_u32()); + let fee = num::rational::Ratio::new( + u32::try_from(pool.fee.numer()) + .inspect_err( + |_| tracing::debug!(pool = ?pool.reserves, "pool fee numerator > u32::MAX"), + ) + .ok()?, + u32::try_from(pool.fee.denom()) + .inspect_err( + |_| tracing::debug!(pool = ?pool.reserves, "pool fee denominator > u32::MAX"), + ) + .ok()?, + ); Some(Pool { address, diff --git a/crates/solvers/src/boundary/liquidity/limit_order.rs b/crates/solvers/src/boundary/liquidity/limit_order.rs index 892729859f..5d2e5d25cb 100644 --- a/crates/solvers/src/boundary/liquidity/limit_order.rs +++ b/crates/solvers/src/boundary/liquidity/limit_order.rs @@ -1,15 +1,16 @@ use { crate::domain::liquidity::limit_order::LimitOrder, - contracts::ethcontract::{H160, U256}, - shared::{baseline_solver::BaselineSolvable, price_estimation::gas::GAS_PER_ZEROEX_ORDER}, + alloy::primitives::{Address, U256}, + liquidity_sources::baseline_solvable::BaselineSolvable, + price_estimation::gas::GAS_PER_ZEROEX_ORDER, }; // Follows 0x's contract implementation: impl BaselineSolvable for LimitOrder { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { if in_token != self.taker.token.0 || out_token != self.maker.token.0 @@ -25,8 +26,8 @@ impl BaselineSolvable for LimitOrder { async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { if out_token != self.maker.token.0 || in_token != self.taker.token.0 @@ -50,18 +51,18 @@ mod tests { use { super::*, crate::domain::{eth, liquidity::limit_order::TakerAmount}, - contracts::ethcontract::U256, - shared::addr, + alloy::primitives::address, + number::units::EthUnit, }; fn create_limit_order(maker_amount: U256, taker_amount: U256, fee_amount: U256) -> LimitOrder { let maker = eth::Asset { amount: maker_amount, - token: eth::TokenAddress(addr!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + token: eth::TokenAddress(address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), }; let taker = eth::Asset { amount: taker_amount, - token: eth::TokenAddress(addr!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), + token: eth::TokenAddress(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), }; let fee = TakerAmount(fee_amount); @@ -70,10 +71,10 @@ mod tests { #[tokio::test] async fn amount_out_in_round_trip() { - let maker_amount = to_wei(300); - let taker_amount = to_wei(100); - let fee_amount = to_wei(10); - let desired_in_amount = to_wei(50); + let maker_amount = 300u64.eth(); + let taker_amount = 100u64.eth(); + let fee_amount = 10u64.eth(); + let desired_in_amount = 50u64.eth(); let order = create_limit_order(maker_amount, taker_amount, fee_amount); let out_token = order.maker.token.0; @@ -93,10 +94,10 @@ mod tests { #[tokio::test] async fn amount_in_out_round_trip() { - let maker_amount = to_wei(100); - let taker_amount = to_wei(300); - let fee_amount = to_wei(10); - let desired_out_amount = to_wei(50); + let maker_amount = 100u64.eth(); + let taker_amount = 300u64.eth(); + let fee_amount = 10u64.eth(); + let desired_out_amount = 50u64.eth(); let order = create_limit_order(maker_amount, taker_amount, fee_amount); let out_token = order.maker.token.0; @@ -116,9 +117,9 @@ mod tests { #[tokio::test] async fn too_high_in_amount() { - let maker_amount = to_wei(300); - let taker_amount = to_wei(100); - let fee_amount = to_wei(10); + let maker_amount = 300u64.eth(); + let taker_amount = 100u64.eth(); + let fee_amount = 10u64.eth(); let order = create_limit_order(maker_amount, taker_amount, fee_amount); let out_token = order.maker.token.0; @@ -131,9 +132,9 @@ mod tests { #[tokio::test] async fn too_high_out_amount() { - let maker_amount = to_wei(100); - let taker_amount = to_wei(300); - let fee_amount = to_wei(10); + let maker_amount = 100u64.eth(); + let taker_amount = 300u64.eth(); + let fee_amount = 10u64.eth(); let order = create_limit_order(maker_amount, taker_amount, fee_amount); let out_token = order.maker.token.0; @@ -146,22 +147,18 @@ mod tests { #[tokio::test] async fn wrong_tokens() { - let maker_amount = to_wei(100); - let taker_amount = to_wei(100); - let fee_amount = to_wei(10); + let maker_amount = 100u64.eth(); + let taker_amount = 100u64.eth(); + let fee_amount = 10u64.eth(); let order = create_limit_order(maker_amount, taker_amount, fee_amount); let out_token = order.maker.token.0; let in_token = order.taker.token.0; - let amount = to_wei(1); + let amount = 1u64.eth(); let amount_in = order.get_amount_in(out_token, (amount, in_token)).await; let amount_out = order.get_amount_out(in_token, (amount, out_token)).await; assert!(amount_in.is_none()); assert!(amount_out.is_none()); } - - fn to_wei(base: u32) -> U256 { - U256::from(base) * U256::exp10(18) - } } diff --git a/crates/solvers/src/boundary/liquidity/stable.rs b/crates/solvers/src/boundary/liquidity/stable.rs index 7a634ab2b0..db404fea1b 100644 --- a/crates/solvers/src/boundary/liquidity/stable.rs +++ b/crates/solvers/src/boundary/liquidity/stable.rs @@ -1,8 +1,8 @@ -pub use shared::sources::balancer_v2::pool_fetching::StablePool as Pool; +pub use liquidity_sources::balancer_v2::pool_fetching::StablePool as Pool; use { crate::domain::{eth, liquidity}, - ethereum_types::{H160, H256, U256}, - shared::sources::balancer_v2::{ + alloy::primitives::{Address, B256, U256}, + liquidity_sources::balancer_v2::{ pool_fetching::{AmplificationParameter, CommonPoolState, TokenState}, swap::fixed_point::Bfp, }, @@ -10,16 +10,12 @@ use { /// Converts a domain pool into a [`shared`] Balancer V2 stable pool. Returns /// `None` if the domain pool cannot be represented as a boundary pool. -pub fn to_boundary_pool(address: H160, pool: &liquidity::stable::Pool) -> Option { +pub fn to_boundary_pool(address: Address, pool: &liquidity::stable::Pool) -> Option { // NOTE: this is only used for encoding and not for solving, so it's OK to // use this an approximate value for now. In fact, Balancer V2 pool IDs // are `pool address || pool kind || pool index`, so this approximation is // pretty good. - let id = { - let mut buf = [0_u8; 32]; - buf[..20].copy_from_slice(address.as_bytes()); - H256(buf) - }; + let id = B256::right_padding_from(address.as_slice()); let swap_fee = to_fixed_point(&pool.fee)?; let reserves = pool @@ -58,7 +54,7 @@ fn to_fixed_point(ratio: ð::Rational) -> Option { // Balancer "fixed point numbers" are in a weird decimal FP format (instead // of a base 2 FP format you typically see). Just convert our ratio into // this format. - let base = U256::exp10(18); + let base = U256::from(10).pow(U256::from(18)); let wei = ratio.numer().checked_mul(base)? / ratio.denom(); Some(Bfp::from_wei(wei)) } diff --git a/crates/solvers/src/boundary/liquidity/weighted_product.rs b/crates/solvers/src/boundary/liquidity/weighted_product.rs index f7da6004da..bceb8633c3 100644 --- a/crates/solvers/src/boundary/liquidity/weighted_product.rs +++ b/crates/solvers/src/boundary/liquidity/weighted_product.rs @@ -1,8 +1,8 @@ -pub use shared::sources::balancer_v2::pool_fetching::WeightedPool as Pool; +pub use liquidity_sources::balancer_v2::pool_fetching::WeightedPool as Pool; use { crate::domain::{eth, liquidity}, - ethereum_types::{H160, H256, U256}, - shared::sources::balancer_v2::{ + alloy::primitives::{Address, B256, U256}, + liquidity_sources::balancer_v2::{ pool_fetching::{CommonPoolState, TokenState, WeightedPoolVersion, WeightedTokenState}, swap::fixed_point::Bfp, }, @@ -10,16 +10,15 @@ use { /// Converts a domain pool into a [`shared`] Balancer V2 weighted pool. Returns /// `None` if the domain pool cannot be represented as a boundary pool. -pub fn to_boundary_pool(address: H160, pool: &liquidity::weighted_product::Pool) -> Option { +pub fn to_boundary_pool( + address: Address, + pool: &liquidity::weighted_product::Pool, +) -> Option { // NOTE: this is only used for encoding and not for solving, so it's OK to // use this an approximate value for now. In fact, Balancer V2 pool IDs // are `pool address || pool kind || pool index`, so this approximation is // pretty good. - let id = { - let mut buf = [0_u8; 32]; - buf[..20].copy_from_slice(address.as_bytes()); - H256(buf) - }; + let id = B256::right_padding_from(address.as_slice()); let swap_fee = to_fixed_point(&pool.fee)?; let reserves = pool @@ -59,7 +58,7 @@ fn to_fixed_point(ratio: ð::Rational) -> Option { // Balancer "fixed point numbers" are in a weird decimal FP format (instead // of a base 2 FP format you typically see). Just convert our ratio into // this format. - let base = U256::exp10(18); + let base = U256::from(10).pow(U256::from(18)); let wei = ratio.numer().checked_mul(base)? / ratio.denom(); Some(Bfp::from_wei(wei)) } diff --git a/crates/solvers/src/boundary/mod.rs b/crates/solvers/src/boundary/mod.rs index 3be2864e8d..4878e80991 100644 --- a/crates/solvers/src/boundary/mod.rs +++ b/crates/solvers/src/boundary/mod.rs @@ -3,5 +3,6 @@ pub mod baseline; pub mod liquidity; +pub mod routing; pub type Result = anyhow::Result; diff --git a/crates/shared/src/baseline_solver.rs b/crates/solvers/src/boundary/routing.rs similarity index 51% rename from crates/shared/src/baseline_solver.rs rename to crates/solvers/src/boundary/routing.rs index d6614f366b..02ac3faf42 100644 --- a/crates/shared/src/baseline_solver.rs +++ b/crates/solvers/src/boundary/routing.rs @@ -2,8 +2,8 @@ //! onchain liquidity. use { - ethcontract::{H160, U256}, - ethrpc::alloy::conversions::IntoAlloy, + alloy::primitives::{Address, U256}, + liquidity_sources::baseline_solvable::BaselineSolvable, model::TokenPair, std::collections::{HashMap, HashSet}, }; @@ -11,35 +11,7 @@ use { /// The maximum number of hops to use when trading with AMMs along a path. const DEFAULT_MAX_HOPS: usize = 2; -type PathCandidate = Vec; - -/// Note that get_amount_out and get_amount_in are not always symmetrical. That -/// is for some AMMs it is possible that get_amount_out returns an amount for -/// which get_amount_in returns None when trying to go the reverse direction. Or -/// that the resulting amount is different from the original. This situation is -/// rare and resulting amounts should usually be identical or very close but it -/// can occur. -pub trait BaselineSolvable { - /// Given the desired output token, the amount and token input, return the - /// expected amount of output token. - fn get_amount_out( - &self, - out_token: H160, - input: (U256, H160), - ) -> impl Future> + Send; - - /// Given the input token, the amount and token we want output, return the - /// required amount of input token that needs to be provided. - fn get_amount_in( - &self, - in_token: H160, - out: (U256, H160), - ) -> impl Future> + Send; - - /// Returns the approximate amount of gas that using this piece of liquidity - /// would incur - fn gas_cost(&self) -> impl Future + Send; -} +type PathCandidate = Vec
; pub struct Estimate<'a, V, L> { // The result amount of the estimate @@ -65,7 +37,7 @@ impl Estimate<'_, V, L> { // result Returns None if the path is invalid or pool information doesn't exist. pub async fn estimate_buy_amount<'a, L: BaselineSolvable>( sell_amount: U256, - path: &[H160], + path: &[Address], liquidity: &'a HashMap>, ) -> Option> { let sell_token = path.first()?; @@ -74,10 +46,7 @@ pub async fn estimate_buy_amount<'a, L: BaselineSolvable>( for current in path.iter().skip(1) { let (amount, previous_token, mut path) = previous; - let pools = liquidity.get(&TokenPair::new( - current.into_alloy(), - previous_token.into_alloy(), - )?)?; + let pools = liquidity.get(&TokenPair::new(*current, previous_token)?)?; let outputs = futures::future::join_all(pools.iter().map(|liquidity| async move { let output = liquidity .get_amount_out(*current, (amount, previous_token)) @@ -105,7 +74,7 @@ pub async fn estimate_buy_amount<'a, L: BaselineSolvable>( // result Returns None if the path is invalid or pool information doesn't exist. pub async fn estimate_sell_amount<'a, L: BaselineSolvable>( buy_amount: U256, - path: &[H160], + path: &[Address], liquidity: &'a HashMap>, ) -> Option> { let buy_token = path.last()?; @@ -114,10 +83,7 @@ pub async fn estimate_sell_amount<'a, L: BaselineSolvable>( for current in path.iter().rev().skip(1) { let (amount, previous_token, mut path) = previous; - let pools = liquidity.get(&TokenPair::new( - current.into_alloy(), - previous_token.into_alloy(), - )?)?; + let pools = liquidity.get(&TokenPair::new(*current, previous_token)?)?; let outputs = futures::future::join_all(pools.iter().map(|liquidity| async move { let output = liquidity .get_amount_in(*current, (amount, previous_token)) @@ -148,13 +114,13 @@ pub struct BaseTokens { /// solver. /// /// Always includes the native token. - tokens: HashSet, + tokens: HashSet
, /// All pairs of above. pairs: HashSet, } impl BaseTokens { - pub fn new(native_token: H160, base_tokens: &[H160]) -> Self { + pub fn new(native_token: Address, base_tokens: &[Address]) -> Self { let mut tokens = base_tokens.to_vec(); tokens.push(native_token); tokens.sort(); @@ -166,7 +132,7 @@ impl BaseTokens { } } - pub fn tokens(&self) -> &HashSet { + pub fn tokens(&self) -> &HashSet
{ &self.tokens } @@ -180,8 +146,7 @@ impl BaseTokens { result.extend( self.tokens .iter() - .map(|base_token| base_token.into_alloy()) - .filter_map(move |base_token| TokenPair::new(base_token, token)), + .filter_map(move |base_token| TokenPair::new(*base_token, token)), ); } } @@ -197,7 +162,11 @@ impl BaseTokens { // potential intermediate base tokens and a maximum number of intermediate // steps. Can contain token pairs between base tokens or a base token and // the sell or buy token. - pub fn path_candidates(&self, sell_token: H160, buy_token: H160) -> HashSet { + pub fn path_candidates( + &self, + sell_token: Address, + buy_token: Address, + ) -> HashSet { self.path_candidates_with_hops(sell_token, buy_token, DEFAULT_MAX_HOPS) } @@ -205,8 +174,8 @@ impl BaseTokens { /// hops. pub fn path_candidates_with_hops( &self, - sell_token: H160, - buy_token: H160, + sell_token: Address, + buy_token: Address, max_hops: usize, ) -> HashSet { path_candidates(sell_token, buy_token, &self.tokens, max_hops) @@ -214,9 +183,9 @@ impl BaseTokens { } fn path_candidates( - sell_token: H160, - buy_token: H160, - base_tokens: &HashSet, + sell_token: Address, + buy_token: Address, + base_tokens: &HashSet
, max_hops: usize, ) -> HashSet { if sell_token == buy_token { @@ -252,7 +221,7 @@ fn path_candidates( } /// All token pairs between base tokens. -fn base_token_pairs(base_tokens: &[H160]) -> impl Iterator + '_ { +fn base_token_pairs(base_tokens: &[Address]) -> impl Iterator + '_ { base_tokens .iter() .copied() @@ -262,7 +231,7 @@ fn base_token_pairs(base_tokens: &[H160]) -> impl Iterator + ' .iter() .copied() .skip(index) - .filter_map(move |token_| TokenPair::new(token.into_alloy(), token_.into_alloy())) + .filter_map(move |token_| TokenPair::new(token, token_)) }) } @@ -270,107 +239,34 @@ fn base_token_pairs(base_tokens: &[H160]) -> impl Iterator + ' mod tests { use { super::*, - crate::sources::uniswap_v2::pool_fetching::Pool, - ethcontract::H160, - maplit::{hashmap, hashset}, + liquidity_sources::uniswap_v2::pool_fetching::Pool, + maplit::hashmap, model::TokenPair, }; - #[test] - fn path_candidates_empty_when_same_token() { - let base = BaseTokens::new(H160::from_low_u64_be(0), &[H160::from_low_u64_be(1)]); - let sell_token = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(2); - - assert!(base.path_candidates(sell_token, buy_token).is_empty()); - } - - #[test] - fn test_path_candidates() { - let base_tokens = [ - H160::from_low_u64_be(0), - H160::from_low_u64_be(1), - H160::from_low_u64_be(2), - ]; - let base_token_set: HashSet = base_tokens.iter().copied().collect(); - - let sell_token = H160::from_low_u64_be(4); - let buy_token = H160::from_low_u64_be(5); - - // 0 hops - assert_eq!( - path_candidates(sell_token, buy_token, &base_token_set, 0), - hashset! {vec![sell_token, buy_token]} - ); - - // 1 hop with all permutations - assert_eq!( - path_candidates(sell_token, buy_token, &base_token_set, 1), - hashset! { - vec![sell_token, buy_token], - vec![sell_token, base_tokens[0], buy_token], - vec![sell_token, base_tokens[1], buy_token], - vec![sell_token, base_tokens[2], buy_token], - - } - ); - - // 2 & 3 hops check count - assert_eq!( - path_candidates(sell_token, buy_token, &base_token_set, 2).len(), - 10 - ); - assert_eq!( - path_candidates(sell_token, buy_token, &base_token_set, 3).len(), - 16 - ); - - // 4 hops should not yield any more permutations since we used all base tokens - assert_eq!( - path_candidates(sell_token, buy_token, &base_token_set, 4).len(), - 16 - ); - - // Ignores base token if part of buy or sell - assert_eq!( - path_candidates(base_tokens[0], buy_token, &base_token_set, 1), - hashset! { - vec![base_tokens[0], buy_token], - vec![base_tokens[0], base_tokens[1], buy_token], - vec![base_tokens[0], base_tokens[2], buy_token], - - } - ); - assert_eq!( - path_candidates(sell_token, base_tokens[0], &base_token_set, 1), - hashset! { - vec![sell_token, base_tokens[0]], - vec![sell_token, base_tokens[1], base_tokens[0]], - vec![sell_token, base_tokens[2], base_tokens[0]], - - } - ); - } - #[tokio::test] async fn test_estimate_amount_returns_none_if_it_contains_pair_without_pool() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let path = vec![sell_token, intermediate, buy_token]; let pools = [Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(path[0], path[1]).unwrap(), (100, 100), )]; let pools = hashmap! { pools[0].tokens => vec![pools[0]], }; - assert!(estimate_buy_amount(1.into(), &path, &pools).await.is_none()); assert!( - estimate_sell_amount(1.into(), &path, &pools) + estimate_buy_amount(U256::ONE, &path, &pools) + .await + .is_none() + ); + assert!( + estimate_sell_amount(U256::ONE, &path, &pools) .await .is_none() ); @@ -378,20 +274,20 @@ mod tests { #[tokio::test] async fn test_estimate_amount() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let path = vec![sell_token, intermediate, buy_token]; let pools = [ Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(path[0], path[1]).unwrap(), (100, 100), ), Pool::uniswap( - H160::from_low_u64_be(2), - TokenPair::new(path[1].into_alloy(), path[2].into_alloy()).unwrap(), + Address::with_last_byte(2), + TokenPair::new(path[1], path[2]).unwrap(), (200, 50), ), ]; @@ -401,38 +297,38 @@ mod tests { }; assert_eq!( - estimate_buy_amount(10.into(), &path, &pools) + estimate_buy_amount(U256::from(10), &path, &pools) .await .unwrap() .value, - 2.into() + U256::from(2) ); assert_eq!( - estimate_sell_amount(10.into(), &path, &pools) + estimate_sell_amount(U256::from(10), &path, &pools) .await .unwrap() .value, - 105.into() + U256::from(105) ); } #[tokio::test] async fn test_estimate_sell_amount_returns_none_buying_too_much() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let path = vec![sell_token, intermediate, buy_token]; let pools = [ Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(path[0], path[1]).unwrap(), (100, 100), ), Pool::uniswap( - H160::from_low_u64_be(2), - TokenPair::new(path[1].into_alloy(), path[2].into_alloy()).unwrap(), + Address::with_last_byte(2), + TokenPair::new(path[1], path[2]).unwrap(), (200, 50), ), ]; @@ -442,7 +338,7 @@ mod tests { }; assert!( - estimate_sell_amount(100.into(), &path, &pools) + estimate_sell_amount(U256::from(100), &path, &pools) .await .is_none() ); @@ -450,22 +346,22 @@ mod tests { #[tokio::test] async fn test_estimate_amount_multiple_pools() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let mut path = vec![sell_token, intermediate, buy_token]; - let first_pair = TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(); - let second_pair = TokenPair::new(path[1].into_alloy(), path[2].into_alloy()).unwrap(); + let first_pair = TokenPair::new(path[0], path[1]).unwrap(); + let second_pair = TokenPair::new(path[1], path[2]).unwrap(); let first_hop_high_price = - Pool::uniswap(H160::from_low_u64_be(1), first_pair, (101_000, 100_000)); + Pool::uniswap(Address::with_last_byte(1), first_pair, (101_000, 100_000)); let first_hop_low_price = - Pool::uniswap(H160::from_low_u64_be(1), first_pair, (100_000, 101_000)); + Pool::uniswap(Address::with_last_byte(1), first_pair, (100_000, 101_000)); let second_hop_high_slippage = - Pool::uniswap(H160::from_low_u64_be(2), second_pair, (200_000, 50_000)); + Pool::uniswap(Address::with_last_byte(2), second_pair, (200_000, 50_000)); let second_hop_low_slippage = Pool::uniswap( - H160::from_low_u64_be(2), + Address::with_last_byte(2), second_pair, (200_000_000, 50_000_000), ); @@ -474,7 +370,7 @@ mod tests { second_pair => vec![second_hop_high_slippage, second_hop_low_slippage], }; - let buy_estimate = estimate_buy_amount(1000.into(), &path, &pools) + let buy_estimate = estimate_buy_amount(U256::from(1000), &path, &pools) .await .unwrap(); assert_eq!( @@ -482,7 +378,7 @@ mod tests { [&first_hop_low_price, &second_hop_low_slippage] ); - let sell_estimate = estimate_sell_amount(1000.into(), &path, &pools) + let sell_estimate = estimate_sell_amount(U256::from(1000), &path, &pools) .await .unwrap(); assert_eq!( @@ -493,7 +389,7 @@ mod tests { // For the reverse path we now expect to use the higher price for the first hop, // but still low slippage for the second path.reverse(); - let buy_estimate = estimate_buy_amount(1000.into(), &path, &pools) + let buy_estimate = estimate_buy_amount(U256::from(1000), &path, &pools) .await .unwrap(); assert_eq!( @@ -501,7 +397,7 @@ mod tests { [&second_hop_low_slippage, &first_hop_high_price] ); - let sell_estimate = estimate_sell_amount(1000.into(), &path, &pools) + let sell_estimate = estimate_sell_amount(U256::from(1000), &path, &pools) .await .unwrap(); assert_eq!( @@ -512,96 +408,25 @@ mod tests { #[tokio::test] async fn test_estimate_amount_invalid_pool() { - let sell_token = H160::from_low_u64_be(1); - let buy_token = H160::from_low_u64_be(2); - let pair = TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(); + let sell_token = Address::with_last_byte(1); + let buy_token = Address::with_last_byte(2); + let pair = TokenPair::new(sell_token, buy_token).unwrap(); let path = vec![sell_token, buy_token]; - let valid_pool = Pool::uniswap(H160::from_low_u64_be(1), pair, (100_000, 100_000)); - let invalid_pool = Pool::uniswap(H160::default(), pair, (0, 0)); + let valid_pool = Pool::uniswap(Address::with_last_byte(1), pair, (100_000, 100_000)); + let invalid_pool = Pool::uniswap(Default::default(), pair, (0, 0)); let pools = hashmap! { pair => vec![valid_pool, invalid_pool], }; - let buy_estimate = estimate_buy_amount(1000.into(), &path, &pools) + let buy_estimate = estimate_buy_amount(U256::from(1000), &path, &pools) .await .unwrap(); assert_eq!(buy_estimate.path, [&valid_pool]); - let sell_estimate = estimate_sell_amount(1000.into(), &path, &pools) + let sell_estimate = estimate_sell_amount(U256::from(1000), &path, &pools) .await .unwrap(); assert_eq!(sell_estimate.path, [&valid_pool]); } - - #[test] - fn base_token_pairs_() { - let base_tokens: Vec = [0, 1, 2] - .iter() - .copied() - .map(H160::from_low_u64_le) - .collect(); - let pairs: Vec = base_token_pairs(&base_tokens).collect(); - assert_eq!(pairs.len(), 3); - assert!(pairs.contains( - &TokenPair::new(base_tokens[0].into_alloy(), base_tokens[1].into_alloy()).unwrap() - )); - assert!(pairs.contains( - &TokenPair::new(base_tokens[0].into_alloy(), base_tokens[2].into_alloy()).unwrap() - )); - assert!(pairs.contains( - &TokenPair::new(base_tokens[1].into_alloy(), base_tokens[2].into_alloy()).unwrap() - )); - } - - #[test] - fn relevant_pairs() { - let tokens: Vec = [0, 1, 2, 3, 4] - .iter() - .copied() - .map(H160::from_low_u64_le) - .collect(); - let base = BaseTokens::new(tokens[0], &tokens[1..2]); - - let pairs = base.relevant_pairs(&mut std::iter::empty()); - assert!(pairs.is_empty()); - - let pairs = base.relevant_pairs( - &mut TokenPair::new(tokens[0].into_alloy(), tokens[1].into_alloy()).into_iter(), - ); - assert_eq!(pairs.len(), 1); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[1].into_alloy()).unwrap()) - ); - - let pairs = base.relevant_pairs( - &mut TokenPair::new(tokens[3].into_alloy(), tokens[4].into_alloy()).into_iter(), - ); - assert_eq!(pairs.len(), 6); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[1].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[3].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[4].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[1].into_alloy(), tokens[3].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[1].into_alloy(), tokens[4].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[3].into_alloy(), tokens[4].into_alloy()).unwrap()) - ); - } } diff --git a/crates/solvers/src/domain/auction.rs b/crates/solvers/src/domain/auction.rs index dcfc26e09f..b73340aaa8 100644 --- a/crates/solvers/src/domain/auction.rs +++ b/crates/solvers/src/domain/auction.rs @@ -1,6 +1,5 @@ use { crate::domain::{eth, liquidity, order}, - ethereum_types::U256, std::{ collections::HashMap, fmt::{self, Display, Formatter}, @@ -58,7 +57,7 @@ pub struct Token { pub decimals: Option, pub symbol: Option, pub reference_price: Option, - pub available_balance: U256, + pub available_balance: eth::U256, pub trusted: bool, } @@ -73,8 +72,10 @@ impl Price { /// Computes an amount equivalent in value to the specified [`eth::Ether`] /// at the given price. - pub fn ether_value(&self, eth: eth::Ether) -> Option { - eth.0.checked_mul(Self::BASE.into())?.checked_div(self.0.0) + pub fn ether_value(&self, eth: eth::Ether) -> Option { + eth.0 + .checked_mul(eth::U256::from(Self::BASE))? + .checked_div(self.0.0) } } diff --git a/crates/solvers/src/domain/dex/minimum_surplus.rs b/crates/solvers/src/domain/dex/minimum_surplus.rs new file mode 100644 index 0000000000..0e7de404f5 --- /dev/null +++ b/crates/solvers/src/domain/dex/minimum_surplus.rs @@ -0,0 +1,141 @@ +//! Minimum surplus requirements for DEX swaps. + +use { + crate::domain::{auction, dex::shared, eth}, + alloy::primitives::U256, + bigdecimal::{BigDecimal, Zero}, + std::cmp, +}; + +/// DEX swap minimum surplus limits. +#[derive(Clone, Debug)] +pub struct MinimumSurplusLimits { + /// The relative minimum surplus (percent) required for swaps. + relative: BigDecimal, + /// The absolute minimum surplus required for swaps. + absolute: Option, +} + +impl MinimumSurplusLimits { + /// Creates a new minimum surplus limits configuration. + pub fn new(relative: BigDecimal, absolute: Option) -> Result { + anyhow::ensure!( + relative >= BigDecimal::zero(), + "minimum surplus relative tolerance must be non-negative" + ); + Ok(Self { relative, absolute }) + } + + /// Returns the minimum surplus for the specified token amount. + pub fn relative(&self, asset: ð::Asset, tokens: &auction::Tokens) -> MinimumSurplus { + let absolute_as_relative = shared::absolute_to_relative(self.absolute, asset, tokens); + + MinimumSurplus::new(cmp::max( + self.relative.clone(), + absolute_as_relative.unwrap_or(BigDecimal::zero()), + )) + } +} + +/// A relative minimum surplus requirement. +#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct MinimumSurplus(BigDecimal); + +impl MinimumSurplus { + /// Creates a new minimum surplus from a decimal value. + fn new(value: BigDecimal) -> Self { + Self(value) + } + + /// Adds minimum surplus to the specified amount. + pub fn add(&self, amount: U256) -> U256 { + let tolerance_amount = shared::compute_absolute_tolerance(amount, &self.0); + amount.saturating_add(tolerance_amount) + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + domain::{auction, eth}, + util::conv, + }, + }; + + #[test] + fn minimum_surplus_requirement() { + let token = |t: &str| eth::TokenAddress(t.parse().unwrap()); + let ether = |e: &str| conv::decimal_to_ether(&e.parse().unwrap()).unwrap(); + let price = |e: &str| auction::Token { + decimals: Default::default(), + symbol: Default::default(), + reference_price: Some(auction::Price(ether(e))), + available_balance: Default::default(), + trusted: Default::default(), + }; + + let tokens = auction::Tokens( + [ + // WETH + ( + token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + price("1.0"), + ), + // USDC + ( + token("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), + price("589783000.0"), + ), + ] + .into_iter() + .collect(), + ); + let minimum_surplus = MinimumSurplusLimits::new( + "0.01".parse().unwrap(), // 1% + Some(ether("0.02")), + ) + .unwrap(); + + for (asset, relative, min_buy) in [ + // Small amount: absolute minimum surplus dominates + // 0.5 WETH * 0.02/0.5 = 0.02 WETH absolute = 4% > 1% relative + ( + eth::Asset { + token: token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + amount: U256::from(500_000_000_000_000_000_u128), // 0.5 WETH + }, + "0.04", + 520_000_000_000_000_000_u128, + ), + // Medium amount: relative minimum surplus dominates + // 5 WETH * 1% = 0.05 WETH > 0.02 WETH absolute + ( + eth::Asset { + token: token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + amount: U256::from(5_000_000_000_000_000_000_u128), // 5 WETH + }, + "0.01", + 5_050_000_000_000_000_000_u128, + ), + // For USDC: relative dominates for this amount + ( + eth::Asset { + token: token("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), + amount: U256::from(10_000_000_000_u128), // 10K USDC + }, + "0.01", + 10_100_000_000_u128, + ), + ] { + let relative = MinimumSurplus::new(relative.parse().unwrap()); + let min_buy = U256::from(min_buy); + + let computed = minimum_surplus.relative(&asset, &tokens); + + assert_eq!(computed, relative); + assert_eq!(computed.add(asset.amount), min_buy); + } + } +} diff --git a/crates/solvers/src/domain/dex/mod.rs b/crates/solvers/src/domain/dex/mod.rs new file mode 100644 index 0000000000..a5e34c63aa --- /dev/null +++ b/crates/solvers/src/domain/dex/mod.rs @@ -0,0 +1,204 @@ +//! Various solver implementations rely on quoting APIs from DEXs and DEX +//! aggregators. This domain module models the various types around quoting +//! single orders with DEXs and turning swaps into single order solutions. + +use { + crate::{ + domain::{self, auction, eth, order, solution}, + infra, + }, + alloy::primitives::{Address, U256}, + std::fmt::{self, Debug, Formatter}, +}; + +pub mod minimum_surplus; +mod shared; +pub mod slippage; + +pub use self::slippage::Slippage; + +/// An order for quoting with an external DEX or DEX aggregator. This is a +/// simplified representation of a CoW Protocol order. +#[derive(Debug)] +pub struct Order { + pub sell: eth::TokenAddress, + pub buy: eth::TokenAddress, + pub side: order::Side, + pub amount: Amount, + pub owner: eth::Address, +} + +impl Order { + pub fn new(order: &order::Order) -> Self { + Self { + sell: order.sell.token, + buy: order.buy.token, + side: order.side, + amount: Amount(match order.side { + order::Side::Buy => order.buy.amount, + order::Side::Sell => order.sell.amount, + }), + owner: order.owner(), + } + } + + /// Returns the order swapped amount as an asset. The token associated with + /// the asset is dependent on the side of the DEX order. + pub fn amount(&self) -> eth::Asset { + eth::Asset { + token: match self.side { + order::Side::Buy => self.buy, + order::Side::Sell => self.sell, + }, + amount: self.amount.0, + } + } +} + +/// An on-chain Ethereum call for executing a DEX swap. +pub struct Call { + /// The address that gets called on-chain. + pub to: Address, + /// The associated calldata for the on-chain call. + pub calldata: Vec, +} + +impl Debug for Call { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct("Call") + .field("to", &self.to) + .field( + "calldata", + &format_args!("{}", const_hex::encode_prefixed(&self.calldata)), + ) + .finish() + } +} + +/// A DEX swap. +#[derive(Debug)] +pub struct Swap { + /// The Ethereum calls for executing the swap. + pub calls: Vec, + /// The expected input asset for the swap. The executed input may end up + /// being different because of slippage. + pub input: eth::Asset, + /// The expected output asset for the swap. The executed output may end up + /// being different because of slippage. + pub output: eth::Asset, + /// The minimum allowance that is required for executing the swap. + pub allowance: Allowance, + /// The gas guesstimate in gas units for the swap. + /// + /// This estimate is **not** expected to be accurate, and is purely + /// indicative. + pub gas: eth::Gas, +} + +impl Swap { + pub fn allowance(&self) -> solution::Allowance { + solution::Allowance { + spender: self.allowance.spender, + asset: eth::Asset { + token: self.input.token, + amount: self.allowance.amount.0, + }, + } + } + + /// Constructs a single order `solution::Solution` for this swap. Returns + /// `None` if the swap is not valid for the specified order. + pub async fn into_solution( + self, + order: order::Order, + gas_price: auction::GasPrice, + sell_token: Option, + simulator: &infra::dex::Simulator, + gas_offset: eth::Gas, + ) -> Option { + let gas = if order.class == order::Class::Limit { + match simulator.gas(order.owner(), &self).await { + Ok(value) => value, + Err(infra::dex::simulator::Error::SettlementContractIsOwner) => self.gas, + Err(err) => { + tracing::warn!(?err, "gas simulation failed"); + return None; + } + } + } else { + // We are fine with just using heuristic gas for market orders, + // since it doesn't really play a role in the final solution. + self.gas + }; + + let allowance = self.allowance(); + let interactions = self + .calls + .into_iter() + .map(|call| { + solution::Interaction::Custom(solution::CustomInteraction { + target: call.to, + value: eth::Ether::default(), + calldata: call.calldata, + inputs: vec![self.input], + outputs: vec![self.output], + internalize: false, + allowances: vec![allowance.clone()], + }) + }) + .collect(); + + solution::Single { + order, + input: self.input, + output: self.output, + interactions, + gas, + wrappers: vec![], + } + .into_dex_solution(gas_price, sell_token, gas_offset) + } + + pub fn satisfies(&self, order: &domain::order::Order) -> bool { + self.output + .amount + .widening_mul::<_, _, 512, 8>(order.sell.amount) + >= self.input.amount.widening_mul(order.buy.amount) + } + + pub fn satisfies_with_minimum_surplus( + &self, + order: &domain::order::Order, + minimum_surplus: &minimum_surplus::MinimumSurplus, + ) -> bool { + let required_buy_amount = minimum_surplus.add(order.buy.amount); + self.output + .amount + .widening_mul::<_, _, 512, 8>(order.sell.amount) + >= self.input.amount.widening_mul(required_buy_amount) + } +} + +/// A swap allowance. +#[derive(Debug)] +pub struct Allowance { + /// The spender address that requires an allowance in order to execute a + /// swap. + pub spender: Address, + /// The amount, in tokens, of the required allowance. + pub amount: Amount, +} + +/// A token amount. +#[derive(Debug)] +pub struct Amount(U256); + +impl Amount { + pub fn new(value: U256) -> Self { + Self(value) + } + + pub fn get(&self) -> U256 { + self.0 + } +} diff --git a/crates/solvers/src/domain/dex/shared.rs b/crates/solvers/src/domain/dex/shared.rs new file mode 100644 index 0000000000..7604a40c62 --- /dev/null +++ b/crates/solvers/src/domain/dex/shared.rs @@ -0,0 +1,54 @@ +//! Shared mathematical functions for slippage and minimum surplus calculations. + +use { + crate::{ + domain::{auction, eth}, + util::conv, + }, + alloy::primitives::U256, + bigdecimal::{BigDecimal, Zero}, + num::{BigUint, Integer}, + number::conversions::{big_uint_to_u256, u256_to_big_uint}, +}; + +/// Computes the absolute tolerance amount from a relative factor. +pub fn compute_absolute_tolerance(amount: U256, factor: &BigDecimal) -> U256 { + let amount = u256_to_big_uint(&amount); + let (int, exp) = factor.as_bigint_and_exponent(); + + let numer = amount * int.to_biguint().expect("positive by construction"); + let denom = BigUint::from(10_u8).pow(exp.unsigned_abs().try_into().unwrap_or(u32::MAX)); + + let abs = numer.div_ceil(&denom); + big_uint_to_u256(&abs).unwrap_or(U256::MAX) +} + +/// Converts an absolute slippage value to a relative slippage value based on +/// the amount and asset's price. +pub fn absolute_to_relative( + absolute: Option, + asset: ð::Asset, + tokens: &auction::Tokens, +) -> Option { + let price = tokens.reference_price(&asset.token)?; + if price.0.0.is_zero() { + return None; + } + + // Convert absolute slippage and asset value to ETH using BigDecimal + let absolute = conv::ether_to_decimal(&absolute?); + let amount_in_token = conv::ether_to_decimal(ð::Ether(asset.amount)); + let price_in_eth = conv::ether_to_decimal(&price.0); + + // Calculate asset value in ETH: amount * price + let amount_in_eth = amount_in_token * price_in_eth; + + // Check if amount_in_eth is zero to prevent division by zero + if amount_in_eth.is_zero() { + return None; + } + + // Calculate absolute as relative: absolute_eth / asset_value_in_eth + let absolute_as_relative = absolute / amount_in_eth; + Some(absolute_as_relative) +} diff --git a/crates/solvers/src/domain/dex/slippage.rs b/crates/solvers/src/domain/dex/slippage.rs new file mode 100644 index 0000000000..02e0541150 --- /dev/null +++ b/crates/solvers/src/domain/dex/slippage.rs @@ -0,0 +1,268 @@ +//! Slippage tolerance computation for DEX swaps. + +use { + crate::domain::{auction, dex::shared, eth}, + alloy::primitives::U256, + bigdecimal::{BigDecimal, One, ToPrimitive, Zero}, + std::cmp, +}; + +/// DEX swap slippage limits. +#[derive(Clone, Debug)] +pub struct SlippageLimits { + /// The relative slippage (percent) allowed for swaps. + relative: BigDecimal, + /// The maximum absolute slippage allowed for swaps. + absolute: Option, +} + +impl SlippageLimits { + /// Creates a new slippage limits configuration. + pub fn new(relative: BigDecimal, absolute: Option) -> Result { + anyhow::ensure!( + relative >= BigDecimal::zero() && relative <= BigDecimal::one(), + "slippage relative tolerance must be in the range [0, 1]" + ); + Ok(Self { relative, absolute }) + } + + /// Returns the slippage for the specified token amount. + pub fn relative(&self, asset: ð::Asset, tokens: &auction::Tokens) -> Slippage { + let absolute_as_relative = shared::absolute_to_relative(self.absolute, asset, tokens); + + Slippage::new(cmp::min( + self.relative.clone(), + absolute_as_relative.unwrap_or(BigDecimal::one()), + )) + } +} + +/// A relative slippage tolerance. +#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct Slippage(BigDecimal); + +impl Slippage { + /// Creates a new slippage from a decimal value. + fn new(value: BigDecimal) -> Self { + Self(value) + } + + /// Returns 1% slippage. + #[cfg(test)] + pub fn one_percent() -> Self { + Self::new("0.01".parse().unwrap()) + } + + /// Returns a zero slippage. + pub fn zero() -> Self { + Self::new(BigDecimal::zero()) + } + + /// Adds slippage to the specified amount. + pub fn add(&self, amount: U256) -> U256 { + let tolerance_amount = shared::compute_absolute_tolerance(amount, &self.0); + amount.saturating_add(tolerance_amount) + } + + /// Subtracts slippage from the specified amount. + pub fn sub(&self, amount: U256) -> U256 { + let tolerance_amount = shared::compute_absolute_tolerance(amount, &self.0); + amount.saturating_sub(tolerance_amount) + } + + /// Returns the slippage as a decimal factor. + pub fn as_factor(&self) -> &BigDecimal { + &self.0 + } + + /// Converts the slippage to basis points. + pub fn as_bps(&self) -> Option { + let bps = &self.0 * BigDecimal::from(10_000); + bps.to_u32().and_then(|v| v.try_into().ok()) + } + + /// Returns the slippage as a percentage. e.g. 0.01 → 1.0. + pub fn as_percent(&self) -> Option { + (&self.0 * BigDecimal::from(100)).to_f64() + } + + /// Rounds the slippage to the specified number of decimal places. + pub fn round(&self, decimals: i64) -> Self { + Self(self.0.round(decimals)) + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::{ + domain::{auction, eth}, + util::conv, + }, + }; + + #[test] + fn slippage_tolerance() { + let token = |t: &str| eth::TokenAddress(t.parse().unwrap()); + let ether = |e: &str| conv::decimal_to_ether(&e.parse().unwrap()).unwrap(); + let price = |e: &str| auction::Token { + decimals: Default::default(), + symbol: Default::default(), + reference_price: Some(auction::Price(ether(e))), + available_balance: Default::default(), + trusted: Default::default(), + }; + + let tokens = auction::Tokens( + [ + // WETH + ( + token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + price("1.0"), + ), + // USDC + ( + token("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), + price("589783000.0"), + ), + // COW + ( + token("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), + price("0.000057"), + ), + ] + .into_iter() + .collect(), + ); + let slippage = SlippageLimits::new( + "0.01".parse().unwrap(), // 1% + Some(ether("0.02")), + ) + .unwrap(); + + for (asset, relative, min, max) in [ + // tolerance defined by relative slippage + ( + eth::Asset { + token: token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + amount: U256::from(1_000_000_000_000_000_000_u128), + }, + "0.01", + 990_000_000_000_000_000_u128, + 1_010_000_000_000_000_000_u128, + ), + // tolerance capped by absolute slippage + ( + eth::Asset { + token: token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + amount: U256::from(100_000_000_000_000_000_000_u128), + }, + "0.0002", + 99_980_000_000_000_000_000_u128, + 100_020_000_000_000_000_000_u128, + ), + // tolerance defined by relative slippage + ( + eth::Asset { + token: token("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), + amount: U256::from(1_000_000_000_u128), // 1K USDC + }, + "0.01", + 990_000_000_u128, + 1_010_000_000_u128, + ), + // tolerance capped by absolute slippage + // 0.02 WETH <=> 33.91 USDC, and ~0.0033910778% of 1M + ( + eth::Asset { + token: token("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), + amount: U256::from(1_000_000_000_000_u128), // 1M USDC + }, + "0.000033911", + 999_966_089_222_u128, + 1_000_033_910_778_u128, + ), + // tolerance defined by relative slippage + ( + eth::Asset { + token: token("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), + amount: U256::from(1_000_000_000_000_000_000_000_u128), // 1K COW + }, + "0.01", + 990_000_000_000_000_000_000_u128, + 1_010_000_000_000_000_000_000_u128, + ), + // tolerance capped by absolute slippage + // 0.02 WETH <=> 350.88 COW, and ~0.0350877192982456140351% of 1M + ( + eth::Asset { + token: token("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), + amount: U256::from(1_000_000_000_000_000_000_000_000_u128), // 1M COW + }, + "0.000350877", + 999_649_122_807_017_543_859_649_u128, + 1_000_350_877_192_982_456_140_351_u128, + ), + ] { + let relative = Slippage::new(relative.parse().unwrap()); + let min = U256::from(min); + let max = U256::from(max); + + let computed = slippage.relative(&asset, &tokens); + + assert_eq!(computed.round(9), relative); + assert_eq!(computed.sub(asset.amount), min); + assert_eq!(computed.add(asset.amount), max); + } + } + + #[test] + fn round_does_not_panic() { + let slippage = Slippage::new( + "42.115792089237316195423570985008687907853269984665640564039457584007913129639935" + .parse() + .unwrap(), + ); + + assert_eq!(slippage.round(4), Slippage::new("42.1158".parse().unwrap())); + } + + #[test] + fn handles_zero_amount_without_panic() { + let token = |t: &str| eth::TokenAddress(t.parse().unwrap()); + let ether = |e: &str| conv::decimal_to_ether(&e.parse().unwrap()).unwrap(); + let price = |e: &str| auction::Token { + decimals: Default::default(), + symbol: Default::default(), + reference_price: Some(auction::Price(ether(e))), + available_balance: Default::default(), + trusted: Default::default(), + }; + + let tokens = auction::Tokens( + [( + token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + price("1.0"), + )] + .into_iter() + .collect(), + ); + + let slippage = SlippageLimits::new( + "0.01".parse().unwrap(), // 1% + Some(ether("0.02")), + ) + .unwrap(); + + // Test with zero amount - should not panic and use relative slippage fallback + let asset_with_zero_amount = eth::Asset { + token: token("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + amount: U256::ZERO, // Zero amount + }; + + // This should not panic and should return the relative slippage (1%) + let computed = slippage.relative(&asset_with_zero_amount, &tokens); + assert_eq!(computed.as_factor(), &"0.01".parse::().unwrap()); + } +} diff --git a/crates/solvers/src/domain/eth/chain.rs b/crates/solvers/src/domain/eth/chain.rs new file mode 100644 index 0000000000..56aeed2c94 --- /dev/null +++ b/crates/solvers/src/domain/eth/chain.rs @@ -0,0 +1,186 @@ +use {serde::Deserialize, std::str::FromStr}; + +/// A supported Ethereum Chain ID. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ChainId { + Mainnet = 1, + Gnosis = 100, + Base = 8453, + ArbitrumOne = 42161, + Bnb = 56, + Avalanche = 43114, + Optimism = 10, + Polygon = 137, + Linea = 59144, + Plasma = 9745, + Ink = 57073, +} + +impl ChainId { + pub fn new(value: u64) -> Result { + match value { + 1 => Ok(Self::Mainnet), + 100 => Ok(Self::Gnosis), + 8453 => Ok(Self::Base), + 42161 => Ok(Self::ArbitrumOne), + 56 => Ok(Self::Bnb), + 43114 => Ok(Self::Avalanche), + 10 => Ok(Self::Optimism), + 137 => Ok(Self::Polygon), + 59144 => Ok(Self::Linea), + 9745 => Ok(Self::Plasma), + 57073 => Ok(Self::Ink), + _ => Err(UnsupportedChain), + } + } + + /// Returns the network ID for the chain. + pub fn network_id(self) -> &'static str { + match self { + ChainId::Mainnet => "1", + ChainId::Gnosis => "100", + ChainId::Base => "8453", + ChainId::ArbitrumOne => "42161", + ChainId::Bnb => "56", + ChainId::Avalanche => "43114", + ChainId::Optimism => "10", + ChainId::Polygon => "137", + ChainId::Linea => "59144", + ChainId::Plasma => "9745", + ChainId::Ink => "57073", + } + } +} + +impl<'de> Deserialize<'de> for ChainId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct ChainIdVisitor; + + impl<'de> serde::de::Visitor<'de> for ChainIdVisitor { + type Value = ChainId; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a chain ID as a string or number") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + let chain_id = u64::from_str(v).map_err(E::custom)?; + ChainId::new(chain_id).map_err(E::custom) + } + + fn visit_u64(self, v: u64) -> Result + where + E: serde::de::Error, + { + ChainId::new(v).map_err(E::custom) + } + } + + deserializer.deserialize_any(ChainIdVisitor) + } +} + +#[derive(Debug, thiserror::Error)] +#[error("unsupported chain")] +pub struct UnsupportedChain; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn supported_chains_number() { + assert_eq!( + serde_json::from_value::(1.into()).unwrap(), + ChainId::Mainnet + ); + assert_eq!( + serde_json::from_value::(100.into()).unwrap(), + ChainId::Gnosis + ); + assert_eq!( + serde_json::from_value::(8453.into()).unwrap(), + ChainId::Base + ); + assert_eq!( + serde_json::from_value::(42161.into()).unwrap(), + ChainId::ArbitrumOne + ); + assert_eq!( + serde_json::from_value::(56.into()).unwrap(), + ChainId::Bnb + ); + assert_eq!( + serde_json::from_value::(43114.into()).unwrap(), + ChainId::Avalanche + ); + assert_eq!( + serde_json::from_value::(10.into()).unwrap(), + ChainId::Optimism + ); + assert_eq!( + serde_json::from_value::(137.into()).unwrap(), + ChainId::Polygon + ); + assert_eq!( + serde_json::from_value::(59144.into()).unwrap(), + ChainId::Linea + ); + assert_eq!( + serde_json::from_value::(9745.into()).unwrap(), + ChainId::Plasma + ); + } + + #[test] + fn supported_chains_str() { + assert_eq!( + serde_json::from_str::("1").unwrap(), + ChainId::Mainnet + ); + assert_eq!( + serde_json::from_str::("100").unwrap(), + ChainId::Gnosis + ); + assert_eq!( + serde_json::from_str::("8453").unwrap(), + ChainId::Base + ); + assert_eq!( + serde_json::from_str::("42161").unwrap(), + ChainId::ArbitrumOne + ); + assert_eq!(serde_json::from_str::("56").unwrap(), ChainId::Bnb); + assert_eq!( + serde_json::from_str::("43114").unwrap(), + ChainId::Avalanche + ); + assert_eq!( + serde_json::from_str::("10").unwrap(), + ChainId::Optimism + ); + assert_eq!( + serde_json::from_str::("137").unwrap(), + ChainId::Polygon + ); + assert_eq!( + serde_json::from_str::("59144").unwrap(), + ChainId::Linea + ); + assert_eq!( + serde_json::from_str::("9745").unwrap(), + ChainId::Plasma + ); + } + + #[test] + fn unsupported_chains() { + serde_json::from_str::("0").unwrap_err(); + } +} diff --git a/crates/solvers/src/domain/eth/mod.rs b/crates/solvers/src/domain/eth/mod.rs index 41de18f275..8b976fd0bb 100644 --- a/crates/solvers/src/domain/eth/mod.rs +++ b/crates/solvers/src/domain/eth/mod.rs @@ -1,25 +1,30 @@ -pub use ethereum_types::{H160, H256, U256}; -use {crate::util::bytes::Bytes, derive_more::From, web3::types::AccessList}; +pub mod chain; + +pub use { + alloy::primitives::{Address, B256, U256}, + chain::ChainId, +}; +use {alloy::rpc::types::AccessList, derive_more::From}; /// A contract address. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct ContractAddress(pub H160); +pub struct ContractAddress(pub Address); /// An ERC20 token address. /// /// https://eips.ethereum.org/EIPS/eip-20 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct TokenAddress(pub H160); +pub struct TokenAddress(pub Address); -impl From for TokenAddress { - fn from(inner: H160) -> Self { +impl From
for TokenAddress { + fn from(inner: Address) -> Self { Self(inner) } } /// The WETH token (or equivalent) for the EVM compatible network. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct WethAddress(pub H160); +pub struct WethAddress(pub Address); /// An asset on the Ethereum blockchain. Represents a particular amount of a /// particular token. @@ -51,14 +56,22 @@ impl From for SignedGas { #[derive(Clone, Copy, Debug, Default)] pub struct Gas(pub U256); +impl std::ops::Add for Gas { + type Output = Self; + + fn add(self, rhs: Gas) -> Self::Output { + Self(self.0.saturating_add(rhs.0)) + } +} + impl std::ops::Add for Gas { type Output = Self; fn add(self, rhs: SignedGas) -> Self::Output { if rhs.0.is_positive() { - Self(self.0.saturating_add(rhs.0.into())) + Self(self.0.saturating_add(U256::from(rhs.0))) } else { - Self(self.0.saturating_sub(rhs.0.abs().into())) + Self(self.0.saturating_sub(U256::from(rhs.0.abs()))) } } } @@ -66,17 +79,13 @@ impl std::ops::Add for Gas { /// A 256-bit rational type. pub type Rational = num::rational::Ratio; -/// An address. Can be an EOA or a smart contract address. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Address(pub H160); - /// An onchain transaction. #[derive(Debug, Clone)] pub struct Tx { pub from: Address, pub to: Address, pub value: Ether, - pub input: Bytes>, + pub input: alloy::primitives::Bytes, pub access_list: AccessList, } diff --git a/crates/solvers/src/domain/liquidity/constant_product.rs b/crates/solvers/src/domain/liquidity/constant_product.rs index 14842109fd..c63015aaaf 100644 --- a/crates/solvers/src/domain/liquidity/constant_product.rs +++ b/crates/solvers/src/domain/liquidity/constant_product.rs @@ -2,7 +2,7 @@ use { crate::domain::{eth, liquidity}, - ethereum_types::U256, + alloy::primitives::U256, std::cmp::Ordering, }; diff --git a/crates/solvers/src/domain/liquidity/limit_order.rs b/crates/solvers/src/domain/liquidity/limit_order.rs index d2065f7a22..94a1463a45 100644 --- a/crates/solvers/src/domain/liquidity/limit_order.rs +++ b/crates/solvers/src/domain/liquidity/limit_order.rs @@ -1,4 +1,4 @@ -use {crate::domain::eth, ethereum_types::U256}; +use crate::domain::eth; /// A 0x-like foreign limit order. #[derive(Clone, Debug)] @@ -10,4 +10,4 @@ pub struct LimitOrder { /// An amount denominated in the taker token of a [`LimitOrder`]. #[derive(Debug, Clone, Copy)] -pub struct TakerAmount(pub U256); +pub struct TakerAmount(pub eth::U256); diff --git a/crates/solvers/src/domain/liquidity/mod.rs b/crates/solvers/src/domain/liquidity/mod.rs index eb7c265702..7a0075bee8 100644 --- a/crates/solvers/src/domain/liquidity/mod.rs +++ b/crates/solvers/src/domain/liquidity/mod.rs @@ -6,13 +6,13 @@ pub mod limit_order; pub mod stable; pub mod weighted_product; -use {crate::domain::eth, ethereum_types::H160, std::cmp::Ordering}; +use {crate::domain::eth, std::cmp::Ordering}; /// A source of liquidity which can be used by the solver. #[derive(Clone, Debug)] pub struct Liquidity { pub id: Id, - pub address: H160, + pub address: eth::Address, /// Estimation of gas needed to use this liquidity on-chain. pub gas: eth::Gas, pub state: State, @@ -74,6 +74,6 @@ impl ScalingFactor { impl Default for ScalingFactor { fn default() -> Self { - Self(eth::Rational::new_raw(1.into(), 1.into())) + Self(eth::Rational::new_raw(eth::U256::ONE, eth::U256::ONE)) } } diff --git a/crates/solvers/src/domain/mod.rs b/crates/solvers/src/domain/mod.rs index afd4300eed..414298a9de 100644 --- a/crates/solvers/src/domain/mod.rs +++ b/crates/solvers/src/domain/mod.rs @@ -1,6 +1,7 @@ //! Core solver engine logic. pub mod auction; +pub mod dex; pub mod eth; pub mod liquidity; pub mod notification; diff --git a/crates/solvers/src/domain/notification.rs b/crates/solvers/src/domain/notification.rs index 83b255931d..2a33d5ef49 100644 --- a/crates/solvers/src/domain/notification.rs +++ b/crates/solvers/src/domain/notification.rs @@ -9,7 +9,7 @@ use { type RequiredEther = Ether; type TokensUsed = BTreeSet; -type TransactionHash = eth::H256; +type TransactionHash = eth::B256; type Transaction = eth::Tx; type BlockNo = u64; pub type SimulationSucceededAtLeastOnce = bool; diff --git a/crates/solvers/src/domain/order.rs b/crates/solvers/src/domain/order.rs index 026cd07679..97b78c961c 100644 --- a/crates/solvers/src/domain/order.rs +++ b/crates/solvers/src/domain/order.rs @@ -1,9 +1,9 @@ //! The domain object representing a CoW Protocol order. use { - crate::{domain::eth, util}, - ethcontract::H160, - ethereum_types::{Address, H256}, + crate::domain::eth, + alloy::primitives::B256, + eth::Address, std::fmt::{self, Debug, Display, Formatter}, }; @@ -25,6 +25,13 @@ impl Order { pub fn solver_determines_fee(&self) -> bool { self.class == Class::Limit } + + /// Returns the owner address of the order extracted from the UID. + pub fn owner(&self) -> eth::Address { + let mut bytes = [0u8; 20]; + bytes.copy_from_slice(&self.uid.0[32..52]); + eth::Address::from(bytes) + } } /// UID of an order. @@ -34,19 +41,19 @@ pub struct Uid(pub [u8; 56]); impl Debug for Uid { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_tuple("Uid") - .field(&util::fmt::Hex(&self.0)) + .field(&format_args!("{}", const_hex::encode_prefixed(self.0))) .finish() } } impl Display for Uid { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(&util::fmt::Hex(&self.0), f) + f.write_str(&const_hex::encode_prefixed(self.0)) } } /// The trading side of an order. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub enum Side { /// An order with a fixed buy amount and maximum sell amount. Buy, @@ -108,16 +115,16 @@ pub enum Signature { #[derive(Clone, Copy, Debug, Default)] pub struct EcdsaSignature { - pub r: H256, - pub s: H256, + pub r: B256, + pub s: B256, pub v: u8, } impl EcdsaSignature { pub fn to_bytes(self) -> [u8; 65] { let mut bytes = [0u8; 65]; - bytes[..32].copy_from_slice(self.r.as_bytes()); - bytes[32..64].copy_from_slice(self.s.as_bytes()); + bytes[..32].copy_from_slice(self.r.as_slice()); + bytes[32..64].copy_from_slice(self.s.as_slice()); bytes[64] = self.v; bytes } @@ -132,7 +139,7 @@ pub struct AppData(pub [u8; 32]); impl Debug for AppData { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_tuple("AppData") - .field(&util::fmt::Hex(&self.0)) + .field(&format_args!("{}", const_hex::encode_prefixed(self.0))) .finish() } } @@ -149,6 +156,6 @@ pub struct FlashloanHint { #[derive(Debug, Clone)] pub struct WrapperCall { - pub address: H160, + pub address: eth::Address, pub data: Vec, } diff --git a/crates/solvers/src/domain/solution.rs b/crates/solvers/src/domain/solution.rs index ae81bb227b..373563b33a 100644 --- a/crates/solvers/src/domain/solution.rs +++ b/crates/solvers/src/domain/solution.rs @@ -1,6 +1,7 @@ use { crate::domain::{auction, eth, liquidity, order}, - ethereum_types::{Address, U256}, + eth::{Address, U256}, + number::u256_ext::U256Ext, std::{collections::HashMap, slice}, }; @@ -193,7 +194,107 @@ impl Single { wrappers: wrappers .iter() .map(|w| WrapperCall { - target: eth::Address(w.address), + target: w.address, + data: w.data.clone(), + }) + .collect(), + }) + } + + /// Creates a full solution for a single order solution given gas and sell + /// token prices. Computes the fee internally from the gas parameters. + pub fn into_dex_solution( + self, + gas_price: auction::GasPrice, + sell_token: Option, + gas_offset: eth::Gas, + ) -> Option { + let Self { + order, + input, + output, + interactions, + gas: swap, + wrappers, + } = self; + + if (order.sell.token, order.buy.token) != (input.token, output.token) { + tracing::debug!( + swap = ?(input.token, output.token), + order = ?(order.sell.token, order.buy.token), + "input/output tokens do not match", + ); + return None; + } + + let fee = if order.solver_determines_fee() { + // TODO: If the order has signed `fee` amount already, we should + // discount it from the surplus fee. ATM, users would pay both a + // full order fee as well as a solver computed fee. Note that this + // is fine for now, since there is no way to create limit orders + // with non-zero fees. + Fee::Surplus(eth::SellTokenAmount( + sell_token?.ether_value(eth::Ether( + swap.0 + .checked_add(gas_offset.0)? + .checked_mul(gas_price.0.0)?, + ))?, + )) + } else { + Fee::Protocol + }; + let surplus_fee = fee.surplus().unwrap_or_default(); + + // Compute total executed sell and buy amounts accounting for solver + // fees. That is, the total amount of sell tokens transferred into the + // contract and the total buy tokens transferred out of the contract. + let (sell, buy) = match order.side { + order::Side::Buy => (input.amount.checked_add(surplus_fee)?, output.amount), + order::Side::Sell => { + // We want to collect fees in the sell token, so we need to sell + // `fee` more than the DEX swap. However, we don't allow + // transferring more than `order.sell.amount` (guaranteed by the + // Smart Contract), so we need to cap our executed amount to the + // order's limit sell amount and compute the executed buy amount + // accordingly. + let sell = input + .amount + .checked_add(surplus_fee)? + .min(order.sell.amount); + let buy = sell + .checked_sub(surplus_fee)? + .checked_mul(output.amount)? + .checked_ceil_div(&input.amount)?; + (sell, buy) + } + }; + + // Check order's limit price is satisfied accounting for solver + // specified fees. + if order.sell.amount.checked_mul(buy)? < order.buy.amount.checked_mul(sell)? { + tracing::debug!(?buy, ?sell, ?order, "order limit price not satisfied",); + return None; + } + + let executed = match order.side { + order::Side::Buy => buy, + order::Side::Sell => sell.checked_sub(surplus_fee)?, + }; + Some(Solution { + id: Default::default(), + prices: ClearingPrices::new([ + (order.sell.token, buy), + (order.buy.token, sell.checked_sub(surplus_fee)?), + ]), + pre_interactions: Default::default(), + interactions, + post_interactions: Default::default(), + gas: Some(gas_offset + swap), + trades: vec![Trade::Fulfillment(Fulfillment::new(order, executed, fee)?)], + wrappers: wrappers + .iter() + .map(|w| WrapperCall { + target: w.address, data: w.data.clone(), }) .collect(), @@ -367,7 +468,7 @@ pub struct CustomInteraction { } /// Approval required to make some `[CustomInteraction]` possible. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Allowance { pub spender: Address, pub asset: eth::Asset, diff --git a/crates/solvers/src/domain/solver.rs b/crates/solvers/src/domain/solver/baseline.rs similarity index 75% rename from crates/solvers/src/domain/solver.rs rename to crates/solvers/src/domain/solver/baseline.rs index 1c612b3cec..1ee13045e7 100644 --- a/crates/solvers/src/domain/solver.rs +++ b/crates/solvers/src/domain/solver/baseline.rs @@ -13,13 +13,12 @@ use { auction, eth, liquidity, - order::{self, Order}, + order::{self, Order, Side}, solution, }, infra::metrics, }, - contracts::alloy::InstanceExt, - ethereum_types::U256, + alloy::primitives::U256, reqwest::Url, std::{cmp, collections::HashSet, sync::Arc}, tracing::Instrument, @@ -72,7 +71,7 @@ struct Inner { native_token_price_estimation_amount: eth::U256, /// If provided, the solver can rely on Uniswap V3 LPs - uni_v3_quoter_v2: Option>, + uni_v3_quoter_v2: Option>, } impl Solver { @@ -80,8 +79,8 @@ impl Solver { pub async fn new(config: Config) -> Self { let uni_v3_quoter_v2 = match config.uni_v3_node_url { Some(url) => { - let web3 = ethrpc::web3(Default::default(), Default::default(), &url, "baseline"); - contracts::alloy::UniswapV3QuoterV2::Instance::deployed(&web3.alloy) + let web3 = ethrpc::web3(Default::default(), &url, Some("baseline")); + contracts::UniswapV3QuoterV2::Instance::deployed(&web3.provider) .await .map(Arc::new) .inspect_err(|err| { @@ -162,7 +161,7 @@ impl Inner { Some(price) => price, None if sell_token == self.weth.0.into() => { // Early return if the sell token is native token - auction::Price(eth::Ether(eth::U256::exp10(18))) + auction::Price(eth::Ether(eth::U256::from(10).pow(eth::U256::from(18)))) } None => { // Estimate the price of the sell token in the native token @@ -174,8 +173,8 @@ impl Inner { Some(route) => { // how many units of buy_token are bought for one unit of sell_token // (buy_amount / sell_amount). - let price = self.native_token_price_estimation_amount.to_f64_lossy() - / route.input().amount.to_f64_lossy(); + let price = f64::from(self.native_token_price_estimation_amount) + / f64::from(route.input().amount); let Some(price) = to_normalized_price(price) else { continue; }; @@ -193,38 +192,53 @@ impl Inner { let compute_solution = async |request: Request| -> Option { let wrappers = request.wrappers.clone(); - let route = boundary_solver.route(request, self.max_hops).await?; - let interactions = route - .segments - .iter() - .map(|segment| { - solution::Interaction::Liquidity(Box::new(solution::LiquidityInteraction { - liquidity: segment.liquidity.clone(), - input: segment.input, - output: segment.output, - // TODO does the baseline solver know about this optimization? - internalize: false, - })) - }) - .collect(); - - // The baseline solver generates a path with swapping - // for exact output token amounts. This leads to - // potential rounding errors for buy orders, where we - // can buy slightly more than intended. Fix this by - // capping the output amount to the order's buy amount - // for buy orders. - let mut output = route.output(); - if let order::Side::Buy = order.side { - output.amount = cmp::min(output.amount, order.buy.amount); - } - - let gas = route.gas() + self.solution_gas_offset; - let fee = sell_token_price - .ether_value(eth::Ether(gas.0.checked_mul(auction.gas_price.0.0)?))? - .into(); + let solution = if order.sell.token == order.buy.token { + // When sell and buy tokens are the same, the solution does not require routing + // and incurs no additional gas since the liquidity comes from the user + let (input, mut output) = match order.side { + Side::Sell => (order.sell, order.buy), + Side::Buy => (order.buy, order.sell), + }; + output.amount = input.amount; + solution::Single { + order: order.clone(), + input, + output, + interactions: Vec::default(), + gas: eth::Gas(U256::ZERO) + self.solution_gas_offset, + wrappers, + } + } else { + let route = boundary_solver.route(request, self.max_hops).await?; + let interactions = route + .segments + .iter() + .map(|segment| { + solution::Interaction::Liquidity(Box::new( + solution::LiquidityInteraction { + liquidity: segment.liquidity.clone(), + input: segment.input, + output: segment.output, + // NOTE(m-sz): does the baseline solver know about this + // optimization? + internalize: false, + }, + )) + }) + .collect(); + let gas = route.gas() + self.solution_gas_offset; + let mut output = route.output(); + + // The baseline solver generates a path with swapping + // for exact output token amounts. This leads to + // potential rounding errors for buy orders, where we + // can buy slightly more than intended. Fix this by + // capping the output amount to the order's buy amount + // for buy orders. + if let order::Side::Buy = order.side { + output.amount = cmp::min(output.amount, order.buy.amount); + } - Some( solution::Single { order: order.clone(), input: route.input(), @@ -233,9 +247,19 @@ impl Inner { gas, wrappers, } - .into_solution(fee)? - .with_id(solution::Id(i as u64)) - .with_buffers_internalizations(&auction.tokens), + }; + + let fee = sell_token_price + .ether_value(eth::Ether( + solution.gas.0.checked_mul(auction.gas_price.0.0)?, + ))? + .into(); + + Some( + solution + .into_solution(fee)? + .with_id(solution::Id(i as u64)) + .with_buffers_internalizations(&auction.tokens), ) }; @@ -268,7 +292,7 @@ impl Inner { (0..n) .map(move |i| { - let divisor = U256::one() << i; + let divisor = U256::ONE << i; Request { sell: eth::Asset { token: sell.token, @@ -297,7 +321,7 @@ impl Inner { // `type(uint112).max` without overflowing a `uint256` on the smart // contract level. Requiring to trade more than `type(uint112).max` // is unlikely and would not work with Uniswap V2 anyway. - amount: eth::U256::one() << 144, + amount: eth::U256::ONE << 144, }; let buy = eth::Asset { @@ -319,7 +343,7 @@ fn to_normalized_price(price: f64) -> Option { let price_in_eth = 1e18 * price; if price_in_eth.is_normal() && price_in_eth >= 1. && price_in_eth < uint_max { - Some(U256::from_f64_lossy(price_in_eth)) + Some(U256::from(price_in_eth)) } else { None } @@ -375,8 +399,10 @@ impl<'a> Route<'a> { } fn gas(&self) -> eth::Gas { - eth::Gas(self.segments.iter().fold(U256::zero(), |acc, segment| { - acc.saturating_add(segment.gas.0) - })) + eth::Gas( + self.segments + .iter() + .fold(U256::ZERO, |acc, segment| acc.saturating_add(segment.gas.0)), + ) } } diff --git a/crates/solvers/src/domain/solver/dex/fills.rs b/crates/solvers/src/domain/solver/dex/fills.rs new file mode 100644 index 0000000000..c9ad659dcc --- /dev/null +++ b/crates/solvers/src/domain/solver/dex/fills.rs @@ -0,0 +1,180 @@ +use { + crate::{ + domain::{auction, dex, eth, order}, + util::conv, + }, + alloy::primitives::{U256, U512, ruint::UintTryFrom}, + bigdecimal::BigDecimal, + number::conversions::{big_decimal_to_u256, u256_to_big_decimal}, + std::{ + collections::HashMap, + sync::Mutex, + time::{Duration, Instant}, + }, +}; + +/// Manages the search for a fillable amount for all order types but +/// specifically for partially fillable orders. +#[derive(Debug)] +pub struct Fills { + /// Maps which fill amount should be tried next for a given order. For sell + /// orders the amount refers to the `sell` asset and for buy orders it + /// refers to the `buy` asset. + amounts: Mutex>, + /// The smallest value in ETH we consider trying a partially fillable order + /// with. If we move below this threshold we'll restart from 100% fill + /// amount to not eventually converge at 0. + smallest_fill: BigDecimal, +} + +const ETH: eth::TokenAddress = eth::TokenAddress(eth::Address::repeat_byte(0xee)); + +impl Fills { + pub fn new(smallest_fill: eth::Ether) -> Self { + Self { + amounts: Default::default(), + smallest_fill: u256_to_big_decimal(&smallest_fill.0), + } + } + + /// Returns which dex query should be tried for the given order. Takes + /// information of previous partial fill attempts into account. + pub fn dex_order(&self, order: &order::Order, tokens: &auction::Tokens) -> Option { + // Do not attempt solving for same sell and buy token + if order.sell.token == order.buy.token { + return None; + } + if !order.partially_fillable { + return Some(dex::Order::new(order)); + } + + let (token, total_amount) = match order.side { + order::Side::Buy => (order.buy.token, order.buy.amount), + order::Side::Sell => (order.sell.token, order.sell.amount), + }; + + let smallest_fill = self.smallest_fill.clone() + * conv::ether_to_decimal(&tokens.reference_price(Ð)?.0) + / conv::ether_to_decimal(&tokens.reference_price(&token)?.0); + let smallest_fill = big_decimal_to_u256(&smallest_fill)?; + + let now = Instant::now(); + + let amount = match self.amounts.lock().unwrap().entry(order.uid) { + std::collections::hash_map::Entry::Vacant(entry) => { + entry.insert(CacheEntry { + next_amount: total_amount, + last_requested: now, + total_amount, + }); + total_amount + } + std::collections::hash_map::Entry::Occupied(mut entry) => { + let entry = entry.get_mut(); + entry.last_requested = now; + entry.total_amount = total_amount; + + if entry.next_amount < smallest_fill { + tracing::trace!( + ?smallest_fill, + target =? entry.next_amount, + "target fill got too small; starting over" + ); + entry.next_amount = total_amount; + } else if entry.next_amount > total_amount { + tracing::trace!("partially filled; adjusting to new total amount"); + entry.next_amount = total_amount; + } + + entry.next_amount + } + }; + + if amount < smallest_fill || amount.is_zero() { + tracing::trace!(?amount, "order no longer worth filling"); + return None; + } + + // Scale amounts according to the limit price and the chosen fill. + let (sell_amount, buy_amount) = match order.side { + order::Side::Buy => { + let sell_amount = U256::uint_try_from( + order + .sell + .amount + .widening_mul(amount) + .checked_div(U512::from(order.buy.amount))?, + ) + .unwrap(); + (sell_amount, amount) + } + order::Side::Sell => { + let buy_amount = U256::uint_try_from( + order + .buy + .amount + .widening_mul(amount) + .checked_div(U512::from(order.sell.amount))?, + ) + .unwrap(); + (amount, buy_amount) + } + }; + + tracing::trace!(?amount, "trying to partially fill order"); + Some(dex::Order::new(&order::Order { + sell: eth::Asset { + token: order.sell.token, + amount: sell_amount, + }, + buy: eth::Asset { + token: order.buy.token, + amount: buy_amount, + }, + ..order.clone() + })) + } + + /// Adjusts the next fill amount that should be tried. Always halves the + /// last tried amount. + pub fn reduce_next_try(&self, uid: order::Uid) { + self.amounts.lock().unwrap().entry(uid).and_modify(|entry| { + entry.next_amount /= U256::from(2); + tracing::trace!(next_try =? entry.next_amount, "reduced next fill amount"); + }); + } + + /// Adjusts the next fill amount that should be tried. Doubles the amount to + /// try. This is useful in case the onchain liquidity changed and now + /// allows for bigger fills. + pub fn increase_next_try(&self, uid: order::Uid) { + self.amounts.lock().unwrap().entry(uid).and_modify(|entry| { + entry.next_amount = entry + .next_amount + .checked_mul(U256::from(2)) + .unwrap_or(entry.total_amount) + .min(entry.total_amount); + tracing::trace!(next_try =? entry.next_amount, "increased next fill amount"); + }); + } + + /// Removes entries that have not been requested for a long time. This + /// allows us to remove orders that got settled by other solvers which + /// we are not able to notice. + pub fn collect_garbage(&self) { + const MAX_AGE: Duration = Duration::from_secs(60 * 10); + let now = Instant::now(); + + self.amounts + .lock() + .unwrap() + .retain(|_, entry| now.duration_since(entry.last_requested) < MAX_AGE) + } +} + +#[derive(Debug)] +struct CacheEntry { + next_amount: eth::U256, + total_amount: eth::U256, + last_requested: Instant, +} diff --git a/crates/solvers/src/domain/solver/dex/mod.rs b/crates/solvers/src/domain/solver/dex/mod.rs new file mode 100644 index 0000000000..775c375151 --- /dev/null +++ b/crates/solvers/src/domain/solver/dex/mod.rs @@ -0,0 +1,231 @@ +//! A simple solver that matches orders directly with swaps from the external +//! DEX and DEX aggregator APIs. + +use { + crate::{ + domain::{ + auction, + dex::{self, minimum_surplus::MinimumSurplusLimits, slippage::SlippageLimits}, + eth, + order::{self, Order}, + solution, + solver::dex::fills::Fills, + }, + infra, + }, + futures::{FutureExt, StreamExt, future, stream}, + std::num::NonZeroUsize, + tracing::Instrument, +}; + +mod fills; + +pub struct Dex { + /// The DEX API client. + dex: infra::dex::Dex, + + /// A DEX swap gas simulator for computing limit order fees. + simulator: infra::dex::Simulator, + + /// The slippage configuration to use for the solver. + slippage: SlippageLimits, + + /// The minimum surplus configuration to use for the solver. + minimum_surplus: MinimumSurplusLimits, + + /// The number of concurrent requests to make. + concurrent_requests: NonZeroUsize, + + /// Helps to manage the strategy to fill orders (especially partially + /// fillable orders). + fills: Fills, + + /// Handles 429 Too Many Requests error with a retry mechanism + rate_limiter: rate_limit::RateLimiter, + + /// Amount of gas that gets added to each swap to tweak the cost coverage of + /// the solver. + gas_offset: eth::Gas, + + /// Whether to internalize the solution interactions using the Settlement + /// contract buffer. + internalize_interactions: bool, +} + +/// The amount of time we aim the solver to finish before the final deadline is +/// reached. +const DEADLINE_SLACK: chrono::Duration = chrono::Duration::milliseconds(500); + +impl Dex { + pub fn new(dex: infra::dex::Dex, config: infra::config::dex::Config) -> Self { + let rate_limiter = rate_limit::RateLimiter::from_strategy( + config.rate_limiting_strategy, + "dex_api".to_string(), + ); + Self { + dex, + simulator: infra::dex::Simulator::new( + &config.node_url, + config.contracts.settlement, + config.contracts.authenticator, + ), + slippage: config.slippage, + minimum_surplus: config.minimum_surplus, + concurrent_requests: config.concurrent_requests, + fills: Fills::new(config.smallest_partial_fill), + rate_limiter, + gas_offset: config.gas_offset, + internalize_interactions: config.internalize_interactions, + } + } + + pub async fn solve(&self, auction: auction::Auction) -> Vec { + let mut solutions = Vec::new(); + let solve_orders = async { + let mut stream = self.solution_stream(&auction); + while let Some(solution) = stream.next().await { + solutions.push(solution); + } + }; + + let deadline = auction + .deadline + .clone() + .reduce(DEADLINE_SLACK) + .remaining() + .unwrap_or_default(); + if tokio::time::timeout(deadline, solve_orders).await.is_err() { + tracing::debug!("reached deadline; stopping to solve"); + } + + self.fills.collect_garbage(); + + solutions + } + + fn solution_stream<'a>( + &'a self, + auction: &'a auction::Auction, + ) -> impl stream::Stream + 'a { + stream::iter(auction.orders.iter()) + .enumerate() + .map(|(i, order)| { + let span = tracing::info_span!("solve", order = %order.uid); + self.solve_order(order, &auction.tokens, auction.gas_price) + .map(move |solution| solution.map(|s| s.with_id(solution::Id(i as u64)))) + .instrument(span) + }) + .buffer_unordered(self.concurrent_requests.get()) + .filter_map(future::ready) + } + + async fn try_solve( + &self, + order: &Order, + dex_order: &dex::Order, + tokens: &auction::Tokens, + ) -> Option { + let dex_err_handler = |err: infra::dex::Error| { + infra::metrics::solve_error(err.format_variant()); + match &err { + err @ infra::dex::Error::NotFound => { + if order.partially_fillable { + // Only adjust the amount to try next if we are sure the API + // worked correctly yet still wasn't able to provide a swap. + self.fills.reduce_next_try(order.uid); + } else { + tracing::debug!(?err, "skipping order"); + } + } + err @ infra::dex::Error::OrderNotSupported => { + tracing::debug!(?err, "skipping order") + } + err @ infra::dex::Error::BadRequest => { + tracing::warn!(?err, "bad request") + } + err @ infra::dex::Error::RateLimited => { + tracing::debug!(?err, "encountered rate limit") + } + err @ infra::dex::Error::UnavailableForLegalReasons => { + tracing::debug!(?err, "unavailable for legal reasons") + } + infra::dex::Error::Other(err) => { + tracing::warn!(?err, "failed to get swap") + } + } + err + }; + let swap = async { + let slippage = self.slippage.relative(&dex_order.amount(), tokens); + self.dex + .swap(dex_order, &slippage, tokens) + .await + .inspect(|_| infra::metrics::request_sent()) + .map_err(dex_err_handler) + }; + self.rate_limiter + .execute_with_back_off(swap, |result| { + matches!(result, Err(infra::dex::Error::RateLimited)) + }) + .await + .map_err(|err| match err { + rate_limit::Error::RateLimited => infra::dex::Error::RateLimited, + }) + .and_then(|result| result) + .ok() + .filter(|swap| { + if !swap.satisfies(order) { + tracing::debug!("swap does not satisfy order"); + if order.partially_fillable { + self.fills.reduce_next_try(order.uid); + } + return false; + } + + // Check minimum surplus requirement + let minimum_surplus = self.minimum_surplus.relative(&dex_order.amount(), tokens); + let valid_surplus = swap.satisfies_with_minimum_surplus(order, &minimum_surplus); + if !valid_surplus { + tracing::debug!("swap does not meet minimum surplus requirement"); + if order.partially_fillable { + self.fills.reduce_next_try(order.uid); + } + } + valid_surplus + }) + } + + async fn solve_order( + &self, + order: &order::Order, + tokens: &auction::Tokens, + gas_price: auction::GasPrice, + ) -> Option { + let dex_order = self.fills.dex_order(order, tokens)?; + let swap = self.try_solve(order, &dex_order, tokens).await?; + let sell = tokens.reference_price(&order.sell.token); + let Some(solution) = swap + .into_solution( + order.clone(), + gas_price, + sell, + &self.simulator, + self.gas_offset, + ) + .await + else { + tracing::debug!("no solution for swap"); + return None; + }; + + tracing::debug!("solved"); + // Maybe some liquidity appeared that enables a bigger fill. + self.fills.increase_next_try(order.uid); + + if self.internalize_interactions { + Some(solution.with_buffers_internalizations(tokens)) + } else { + Some(solution) + } + } +} diff --git a/crates/solvers/src/domain/solver/mod.rs b/crates/solvers/src/domain/solver/mod.rs new file mode 100644 index 0000000000..6df8177037 --- /dev/null +++ b/crates/solvers/src/domain/solver/mod.rs @@ -0,0 +1,22 @@ +pub mod baseline; +pub mod dex; + +pub use self::{ + baseline::{Config, Request, Route, Segment, Solver as Baseline}, + dex::Dex, +}; +use crate::domain::{auction, solution}; + +pub enum Solver { + Baseline(Baseline), + Dex(Box), +} + +impl Solver { + pub async fn solve(&self, auction: auction::Auction) -> Vec { + match self { + Solver::Baseline(s) => s.solve(auction).await, + Solver::Dex(s) => s.solve(auction).await, + } + } +} diff --git a/crates/solvers/src/infra/blockchain.rs b/crates/solvers/src/infra/blockchain.rs new file mode 100644 index 0000000000..c90bfed091 --- /dev/null +++ b/crates/solvers/src/infra/blockchain.rs @@ -0,0 +1,4 @@ +/// Creates a node RPC instance. +pub fn rpc(url: &reqwest::Url) -> ethrpc::Web3 { + ethrpc::web3(Default::default(), url, Some("base")) +} diff --git a/crates/solvers/src/infra/cli.rs b/crates/solvers/src/infra/cli.rs index 601690a51e..e439cdc14e 100644 --- a/crates/solvers/src/infra/cli.rs +++ b/crates/solvers/src/infra/cli.rs @@ -2,6 +2,7 @@ use { clap::{Parser, Subcommand}, + shared::arguments::TracingArguments, std::{net::SocketAddr, path::PathBuf}, }; @@ -21,6 +22,9 @@ pub struct Args { #[clap(long, env, default_value = "false")] pub use_json_logs: bool, + #[clap(flatten)] + pub tracing: TracingArguments, + /// The socket address to bind to. #[arg(long, env, default_value = "127.0.0.1:7872")] pub addr: SocketAddr, @@ -39,4 +43,14 @@ pub enum Command { #[clap(long, env)] config: PathBuf, }, + /// solve individual orders via the OKX DEX aggregator API + Okx { + #[clap(long, env)] + config: PathBuf, + }, + /// solve individual orders using Bitget API + Bitget { + #[clap(long, env)] + config: PathBuf, + }, } diff --git a/crates/solvers/src/infra/config.rs b/crates/solvers/src/infra/config/baseline.rs similarity index 77% rename from crates/solvers/src/infra/config.rs rename to crates/solvers/src/infra/config/baseline.rs index 09efc92453..f2ce0053b0 100644 --- a/crates/solvers/src/infra/config.rs +++ b/crates/solvers/src/infra/config/baseline.rs @@ -2,19 +2,15 @@ use { crate::{ domain::{eth, solver}, infra::contracts, - util::serialize, }, chain::Chain, - ethereum_types::H160, + price_estimation::gas::SETTLEMENT_OVERHEAD, reqwest::Url, serde::Deserialize, - serde_with::serde_as, - shared::price_estimation::gas::SETTLEMENT_OVERHEAD, - std::{fmt::Debug, path::Path}, + std::path::Path, tokio::fs, }; -#[serde_as] #[derive(Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] struct Config { @@ -25,12 +21,12 @@ struct Config { /// Optional WETH contract address. This can be used to specify a manual /// value **instead** of using the canonical WETH contract for the /// configured chain. - weth: Option, + weth: Option, /// List of base tokens to use when path finding. This defines the tokens /// that can appear as intermediate "hops" within a trading route. Note that /// WETH is always considered as a base token. - base_tokens: Vec, + base_tokens: Vec, /// The maximum number of hops to consider when finding the optimal trading /// path. @@ -47,7 +43,6 @@ struct Config { /// The amount of the native token to use to estimate native price of a /// token - #[serde_as(as = "serialize::U256")] native_token_price_estimation_amount: eth::U256, /// If this is configured the solver will also use the Uniswap V3 liquidity @@ -65,7 +60,7 @@ pub async fn load(path: &Path) -> solver::Config { .await .unwrap_or_else(|e| panic!("I/O error while reading {path:?}: {e:?}")); // Not printing detailed error because it could potentially leak secrets. - let config = unwrap_or_log(toml::de::from_str::(&data), &path); + let config = super::unwrap_or_log(toml::de::from_str::(&data), &path); let weth = match (config.chain_id, config.weth) { (Some(chain_id), None) => contracts::Contracts::for_chain(chain_id).weth, (None, Some(weth)) => eth::WethAddress(weth), @@ -93,24 +88,6 @@ pub async fn load(path: &Path) -> solver::Config { } } -/// Unwraps result or logs a `TOML` parsing error. -fn unwrap_or_log(result: Result, path: &P) -> T -where - E: Debug, - P: Debug, -{ - result.unwrap_or_else(|err| { - if std::env::var("TOML_TRACE_ERROR").is_ok_and(|v| v == "1") { - panic!("failed to parse TOML config at {path:?}: {err:#?}") - } else { - panic!( - "failed to parse TOML config at: {path:?}. Set TOML_TRACE_ERROR=1 to print \ - parsing error but this may leak secrets." - ) - } - }) -} - /// Returns minimum gas used for settling a single order. /// (not accounting for the cost of additional interactions) fn default_gas_offset() -> i64 { diff --git a/crates/solvers/src/infra/config/dex/bitget/file.rs b/crates/solvers/src/infra/config/dex/bitget/file.rs new file mode 100644 index 0000000000..3367739088 --- /dev/null +++ b/crates/solvers/src/infra/config/dex/bitget/file.rs @@ -0,0 +1,85 @@ +use { + crate::{ + domain::eth, + infra::{config::dex::file, dex::bitget}, + }, + serde::Deserialize, + serde_with::serde_as, + std::path::Path, +}; + +#[serde_as] +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +struct Config { + /// The base URL for the Bitget swap API. + #[serde(default = "default_endpoint")] + #[serde_as(as = "serde_with::DisplayFromStr")] + endpoint: reqwest::Url, + + /// Chain ID used to automatically determine contract addresses. + chain_id: eth::ChainId, + + /// Bitget API credentials. + credentials: BitgetCredentialsConfig, + + /// Partner code sent in the `Partner-Code` header. + #[serde(default = "default_partner_code")] + partner_code: String, + + /// Whether buy orders should be served via the reverse-quote endpoint. + /// Off by default, see [`bitget::Config::enable_buy_orders`] for + /// caveats. + #[serde(default)] + enable_buy_orders: bool, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +struct BitgetCredentialsConfig { + /// Bitget API key. + api_key: String, + + /// Bitget API secret for signing requests. + api_secret: String, +} + +#[allow(clippy::from_over_into)] +impl Into for BitgetCredentialsConfig { + fn into(self) -> bitget::BitgetCredentialsConfig { + bitget::BitgetCredentialsConfig { + api_key: self.api_key, + api_secret: self.api_secret, + } + } +} + +fn default_partner_code() -> String { + "cowswap".to_string() +} + +fn default_endpoint() -> reqwest::Url { + bitget::DEFAULT_ENDPOINT.parse().unwrap() +} + +/// Load the Bitget solver configuration from a TOML file. +/// +/// # Panics +/// +/// This method panics if the config is invalid or on I/O errors. +pub async fn load(path: &Path) -> super::Config { + let (base, config) = file::load::(path).await; + + super::Config { + bitget: bitget::Config { + endpoint: config.endpoint, + chain_id: config.chain_id, + credentials: config.credentials.into(), + partner_code: config.partner_code, + block_stream: base.block_stream.clone(), + settlement_contract: base.contracts.settlement, + enable_buy_orders: config.enable_buy_orders, + }, + base, + } +} diff --git a/crates/solvers/src/infra/config/dex/bitget/mod.rs b/crates/solvers/src/infra/config/dex/bitget/mod.rs new file mode 100644 index 0000000000..5d630fac91 --- /dev/null +++ b/crates/solvers/src/infra/config/dex/bitget/mod.rs @@ -0,0 +1,6 @@ +pub mod file; + +pub struct Config { + pub bitget: crate::infra::dex::bitget::Config, + pub base: super::Config, +} diff --git a/crates/solvers/src/infra/config/dex/file.rs b/crates/solvers/src/infra/config/dex/file.rs new file mode 100644 index 0000000000..c88f216940 --- /dev/null +++ b/crates/solvers/src/infra/config/dex/file.rs @@ -0,0 +1,206 @@ +//! Configuration parameters that get shared across all dex solvers. + +use { + crate::{ + domain::{ + dex::{minimum_surplus::MinimumSurplusLimits, slippage::SlippageLimits}, + eth, + }, + infra::{blockchain, config::unwrap_or_log, contracts}, + }, + bigdecimal::{BigDecimal, Zero}, + number::serialization::HexOrDecimalU256, + serde::{Deserialize, de::DeserializeOwned}, + serde_with::serde_as, + std::{num::NonZeroUsize, path::Path, time::Duration}, + tokio::fs, +}; + +#[serde_as] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +struct Config { + /// The node URL to use for simulations. + #[serde_as(as = "serde_with::DisplayFromStr")] + node_url: reqwest::Url, + + /// Optional CoW Protocol Settlement contract address. If not specified, + /// the default Settlement contract address will be used. + settlement: Option, + + /// The relative slippage allowed by the solver. + #[serde(default = "default_relative_slippage")] + #[serde_as(as = "serde_with::DisplayFromStr")] + relative_slippage: BigDecimal, + + /// The absolute slippage allowed by the solver. + #[serde_as(as = "Option")] + absolute_slippage: Option, + + /// The relative minimum surplus required by the solver. + #[serde(default = "default_relative_minimum_surplus")] + #[serde_as(as = "serde_with::DisplayFromStr")] + relative_minimum_surplus: BigDecimal, + + /// The absolute minimum surplus required by the solver. + #[serde_as(as = "Option")] + absolute_minimum_surplus: Option, + + /// The number of concurrent requests to make to the DEX aggregator API. + #[serde(default = "default_concurrent_requests")] + concurrent_requests: NonZeroUsize, + + /// The amount of Ether a partially fillable order should be filled for at + /// least. + #[serde(default = "default_smallest_partial_fill")] + #[serde_as(as = "HexOrDecimalU256")] + smallest_partial_fill: eth::U256, + + /// Back-off growth factor for rate limiting. + #[serde(default = "default_back_off_growth_factor")] + back_off_growth_factor: f64, + + /// Minimum back-off time in seconds for rate limiting. + #[serde(with = "humantime_serde", default = "default_min_back_off")] + min_back_off: Duration, + + /// Maximum back-off time in seconds for rate limiting. + #[serde(with = "humantime_serde", default = "default_max_back_off")] + max_back_off: Duration, + + /// Settings specific to the wrapped dex API. + dex: toml::Value, + + /// Amount of gas that gets added to each swap to adjust the cost coverage + /// of the solver. + #[serde(default = "default_gas_offset")] + #[serde_as(as = "HexOrDecimalU256")] + gas_offset: eth::U256, + + /// How often the solver should poll the current block. If this value + /// is set each request will also have the `X-CURRENT-BLOCK-HASH` header set + /// updated based on the configured polling interval. + /// This is useful for caching requests on an egress proxy. + #[serde(with = "humantime_serde", default)] + current_block_poll_interval: Option, + + /// Whether to internalize the solution interactions using the Settlement + /// contract buffers. + #[serde(default = "default_internalize_interactions")] + internalize_interactions: bool, +} + +fn default_relative_slippage() -> BigDecimal { + BigDecimal::new(1.into(), 2) // 1% +} + +fn default_relative_minimum_surplus() -> BigDecimal { + BigDecimal::zero() // 0% +} + +fn default_concurrent_requests() -> NonZeroUsize { + NonZeroUsize::new(1).unwrap() +} + +fn default_smallest_partial_fill() -> eth::U256 { + eth::U256::from(10).pow(eth::U256::from(16)) // 0.01 ETH +} + +fn default_back_off_growth_factor() -> f64 { + 2.0 +} + +fn default_min_back_off() -> Duration { + Duration::from_secs(1) +} + +fn default_max_back_off() -> Duration { + Duration::from_secs(8) +} + +fn default_gas_offset() -> eth::U256 { + // Rough estimation of the gas overhead of settling a single + // trade via the settlement contract. + eth::U256::from(106_391) +} + +fn default_internalize_interactions() -> bool { + true +} + +/// Loads the base solver configuration from a TOML file. +/// +/// # Panics +/// +/// This method panics if the config is invalid or on I/O errors. +pub async fn load(path: &Path) -> (super::Config, T) { + let data = fs::read_to_string(path) + .await + .unwrap_or_else(|e| panic!("I/O error while reading {path:?}: {e:?}")); + + // Not printing detailed error because it could potentially leak secrets. + let config = unwrap_or_log(toml::de::from_str::(&data), &path); + + let dex: T = unwrap_or_log(config.dex.try_into(), &path); + + // Take advantage of the fact that deterministic deployment means that all + // CoW Protocol contracts have the same address. + let default_contracts = contracts::Contracts::for_chain_id(eth::ChainId::Mainnet); + let (settlement, authenticator) = if let Some(settlement) = config.settlement { + let authenticator = + { + let web3 = blockchain::rpc(&config.node_url); + let settlement = + ::contracts::GPv2Settlement::Instance::new(settlement, web3.provider.clone()); + settlement.authenticator().call().await.unwrap_or_else(|e| { + panic!("error reading authenticator contract address: {e:?}") + }) + }; + (settlement, authenticator) + } else { + ( + default_contracts.settlement, + default_contracts.authenticator, + ) + }; + + let block_stream = match config.current_block_poll_interval { + Some(interval) => Some( + #[allow(deprecated)] + ethrpc::block_stream::current_block_stream(config.node_url.clone(), interval) + .await + .unwrap(), + ), + None => None, + }; + + let config = super::Config { + node_url: config.node_url, + contracts: super::Contracts { + settlement, + authenticator, + }, + slippage: SlippageLimits::new( + config.relative_slippage, + config.absolute_slippage.map(eth::Ether), + ) + .expect("invalid slippage limits"), + minimum_surplus: MinimumSurplusLimits::new( + config.relative_minimum_surplus, + config.absolute_minimum_surplus.map(eth::Ether), + ) + .expect("invalid minimum surplus limits"), + concurrent_requests: config.concurrent_requests, + smallest_partial_fill: eth::Ether(config.smallest_partial_fill), + rate_limiting_strategy: configs::rate_limit::Strategy::try_new( + config.back_off_growth_factor, + config.min_back_off, + config.max_back_off, + ) + .unwrap(), + gas_offset: eth::Gas(config.gas_offset), + block_stream, + internalize_interactions: config.internalize_interactions, + }; + (config, dex) +} diff --git a/crates/solvers/src/infra/config/dex/mod.rs b/crates/solvers/src/infra/config/dex/mod.rs new file mode 100644 index 0000000000..be5ad1b97c --- /dev/null +++ b/crates/solvers/src/infra/config/dex/mod.rs @@ -0,0 +1,33 @@ +pub mod bitget; +pub mod file; +pub mod okx; + +use { + crate::domain::{ + dex::{minimum_surplus::MinimumSurplusLimits, slippage::SlippageLimits}, + eth, + }, + alloy::primitives::Address, + ethrpc::block_stream::CurrentBlockWatcher, + std::num::NonZeroUsize, +}; + +#[derive(Clone)] +pub struct Contracts { + pub settlement: Address, + pub authenticator: Address, +} + +#[derive(Clone)] +pub struct Config { + pub node_url: reqwest::Url, + pub contracts: Contracts, + pub slippage: SlippageLimits, + pub minimum_surplus: MinimumSurplusLimits, + pub concurrent_requests: NonZeroUsize, + pub smallest_partial_fill: eth::Ether, + pub rate_limiting_strategy: configs::rate_limit::Strategy, + pub gas_offset: eth::Gas, + pub block_stream: Option, + pub internalize_interactions: bool, +} diff --git a/crates/solvers/src/infra/config/dex/okx/file.rs b/crates/solvers/src/infra/config/dex/okx/file.rs new file mode 100644 index 0000000000..5e96a860b9 --- /dev/null +++ b/crates/solvers/src/infra/config/dex/okx/file.rs @@ -0,0 +1,115 @@ +use { + crate::{ + domain::eth, + infra::{config::dex::file, dex::okx}, + }, + serde::Deserialize, + serde_with::serde_as, + std::path::Path, +}; + +#[serde_as] +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +struct Config { + /// The URL endpoint for the OKX swap API for sell orders (exactIn mode). + /// Uses V6 API by default. + #[serde(default = "default_sell_orders_endpoint")] + #[serde_as(as = "serde_with::DisplayFromStr")] + sell_orders_endpoint: reqwest::Url, + + /// The URL endpoint for the OKX swap API for buy orders (exactOut mode). + /// If specified, the URL must point to the V5 API. Otherwise, buy orders + /// will be ignored. + #[serde(default)] + #[serde_as(as = "Option")] + buy_orders_endpoint: Option, + + /// Optional base URL to use for signature generation for sell orders. + /// This is useful when requests go through a proxy but signatures must be + /// generated using the original OKX API URL path. + /// If not specified, uses sell_orders_endpoint for signature generation. + #[serde(default)] + #[serde_as(as = "Option")] + sell_orders_signature_base_url: Option, + + /// Optional base URL to use for signature generation for buy orders. + /// This is useful when requests go through a proxy but signatures must be + /// generated using the original OKX API URL path. + /// If not specified, uses buy_orders_endpoint for signature generation. + #[serde(default)] + #[serde_as(as = "Option")] + buy_orders_signature_base_url: Option, + + /// Chain ID used to automatically determine contract addresses. + chain_id: eth::ChainId, + + /// OKX API credentials + #[serde(flatten)] + okx_credentials: OkxCredentialsConfig, + + /// The percentage of the price impact allowed. + /// When set to 100%, the feature is disabled (default). + /// Note: OKX API default is 90% if this parameter is NOT sent. + #[serde(default = "default_price_impact_protection_percent")] + price_impact_protection_percent: f64, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +struct OkxCredentialsConfig { + /// OKX Project ID. + api_project_id: String, + + /// OKX API Key. + api_key: String, + + /// OKX Secret key used for signing request. + api_secret_key: String, + + /// OKX Secret key passphrase. + api_passphrase: String, +} + +impl From for okx::OkxCredentialsConfig { + fn from(value: OkxCredentialsConfig) -> Self { + Self { + project_id: value.api_project_id, + api_key: value.api_key, + api_secret_key: value.api_secret_key, + api_passphrase: value.api_passphrase, + } + } +} + +fn default_sell_orders_endpoint() -> reqwest::Url { + okx::DEFAULT_SELL_ORDERS_ENDPOINT.parse().unwrap() +} + +fn default_price_impact_protection_percent() -> f64 { + 1.0 // 100% - feature disabled by default +} + +/// Load the OKX solver configuration from a TOML file. +/// +/// # Panics +/// +/// This method panics if the config is invalid or on I/O errors. +pub async fn load(path: &Path) -> super::Config { + let (base, config) = file::load::(path).await; + + super::Config { + okx: okx::Config { + sell_orders_endpoint: config.sell_orders_endpoint, + buy_orders_endpoint: config.buy_orders_endpoint, + sell_orders_signature_base_url: config.sell_orders_signature_base_url, + buy_orders_signature_base_url: config.buy_orders_signature_base_url, + chain_id: config.chain_id, + okx_credentials: config.okx_credentials.into(), + block_stream: base.block_stream.clone(), + settlement_contract: base.contracts.settlement, + price_impact_protection_percent: config.price_impact_protection_percent, + }, + base, + } +} diff --git a/crates/solvers/src/infra/config/dex/okx/mod.rs b/crates/solvers/src/infra/config/dex/okx/mod.rs new file mode 100644 index 0000000000..df781cf15e --- /dev/null +++ b/crates/solvers/src/infra/config/dex/okx/mod.rs @@ -0,0 +1,6 @@ +pub mod file; + +pub struct Config { + pub okx: crate::infra::dex::okx::Config, + pub base: super::Config, +} diff --git a/crates/solvers/src/infra/config/mod.rs b/crates/solvers/src/infra/config/mod.rs new file mode 100644 index 0000000000..18c0e2dc40 --- /dev/null +++ b/crates/solvers/src/infra/config/mod.rs @@ -0,0 +1,22 @@ +pub mod baseline; +pub mod dex; + +use std::fmt::Debug; + +/// Unwraps result or logs a `TOML` parsing error. +pub(crate) fn unwrap_or_log(result: Result, path: &P) -> T +where + E: Debug, + P: Debug, +{ + result.unwrap_or_else(|err| { + if std::env::var("TOML_TRACE_ERROR").is_ok_and(|v| v == "1") { + panic!("failed to parse TOML config at {path:?}: {err:#?}") + } else { + panic!( + "failed to parse TOML config at: {path:?}. Set TOML_TRACE_ERROR=1 to print \ + parsing error but this may leak secrets." + ) + } + }) +} diff --git a/crates/solvers/src/infra/contracts.rs b/crates/solvers/src/infra/contracts.rs index 0b159ca085..8f4cd3abf0 100644 --- a/crates/solvers/src/infra/contracts.rs +++ b/crates/solvers/src/infra/contracts.rs @@ -1,23 +1,43 @@ use { crate::domain::eth, + alloy::primitives::Address, chain::Chain, - contracts::alloy::WETH9, - ethrpc::alloy::conversions::IntoLegacy, + contracts::{GPv2AllowListAuthentication, GPv2Settlement, WETH9}, }; #[derive(Clone, Debug)] pub struct Contracts { pub weth: eth::WethAddress, + pub settlement: Address, + pub authenticator: Address, } impl Contracts { pub fn for_chain(chain: Chain) -> Self { + let chain_id = chain.id(); Self { weth: eth::WethAddress( - WETH9::deployment_address(&chain.id()) - .expect("there should be a contract address for all supported chains") - .into_legacy(), + WETH9::deployment_address(&chain_id) + .expect("there should be a contract address for all supported chains"), ), + settlement: GPv2Settlement::deployment_address(&chain_id) + .expect("there should be a contract address for all supported chains"), + authenticator: GPv2AllowListAuthentication::deployment_address(&chain_id) + .expect("there should be a contract address for all supported chains"), + } + } + + pub fn for_chain_id(chain_id: eth::ChainId) -> Self { + let id = chain_id as u64; + Self { + weth: eth::WethAddress( + WETH9::deployment_address(&id) + .expect("there should be a contract address for all supported chains"), + ), + settlement: GPv2Settlement::deployment_address(&id) + .expect("there should be a contract address for all supported chains"), + authenticator: GPv2AllowListAuthentication::deployment_address(&id) + .expect("there should be a contract address for all supported chains"), } } } diff --git a/crates/solvers/src/infra/dex/bitget/dto.rs b/crates/solvers/src/infra/dex/bitget/dto.rs new file mode 100644 index 0000000000..b108467aa2 --- /dev/null +++ b/crates/solvers/src/infra/dex/bitget/dto.rs @@ -0,0 +1,271 @@ +//! DTOs for the Bitget swap API. +//! Full documentation: https://web3.bitget.com/en/docs/swap/ + +use { + crate::domain::{dex, eth}, + bigdecimal::BigDecimal, + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +/// Bitget chain name used in API requests. +#[derive(Clone, Copy, Serialize)] +pub enum ChainName { + #[serde(rename = "eth")] + Mainnet, + #[serde(rename = "bnb")] + Bnb, + #[serde(rename = "base")] + Base, + #[serde(rename = "matic")] + Polygon, + #[serde(rename = "arbitrum")] + ArbitrumOne, +} + +impl ChainName { + pub fn new(chain_id: eth::ChainId) -> Self { + match chain_id { + eth::ChainId::Mainnet => Self::Mainnet, + eth::ChainId::Bnb => Self::Bnb, + eth::ChainId::Base => Self::Base, + eth::ChainId::Polygon => Self::Polygon, + eth::ChainId::ArbitrumOne => Self::ArbitrumOne, + _ => panic!("unsupported Bitget chain: {chain_id:?}"), + } + } +} + +/// A Bitget API swap request with enriched response (`requestMod = "rich"`). +/// +/// See [API](https://web3.bitget.com/en/docs/swap/) +/// documentation for more detailed information on each parameter. +#[serde_as] +#[derive(Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SwapRequest { + /// Source token contract address. + pub from_contract: eth::Address, + + /// Input amount in human-readable decimal units (e.g. "1" for 1 WETH). + #[serde_as(as = "serde_with::DisplayFromStr")] + pub from_amount: BigDecimal, + + /// Source chain name. + pub from_chain: ChainName, + + /// Target token contract address. + pub to_contract: eth::Address, + + /// Target chain name. + pub to_chain: ChainName, + + /// Debit address. + pub from_address: eth::Address, + + /// Recipient address. + pub to_address: eth::Address, + + /// Optimal channel - hardcoded to "bgwevmaggregator" for EVM chains. + pub market: String, + + /// Slippage tolerance as a percentage (e.g. 1.0 for 1%). + pub slippage: f64, + + /// Request mode - "rich" returns quote data alongside swap calldata. + pub request_mod: String, + + /// Fee rate in per mille. 0 for no fee. + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_rate: Option, +} + +impl SwapRequest { + pub fn from_order( + order: &dex::Order, + chain_name: ChainName, + settlement_contract: eth::Address, + slippage: &dex::Slippage, + sell_decimals: u8, + ) -> Self { + Self { + from_contract: order.sell.0, + from_amount: super::wei_to_decimal(order.amount.get(), sell_decimals), + from_chain: chain_name, + to_contract: order.buy.0, + to_chain: chain_name, + from_address: settlement_contract, + to_address: settlement_contract, + // as per a suggestion by the BitGet team for the best routes on EVM chains + market: "bgwevmaggregator".to_string(), + slippage: slippage.as_percent().unwrap_or_default(), + request_mod: "rich".to_string(), + fee_rate: Some(0.0), + } + } +} + +/// A Bitget API enriched swap response (returned when `requestMod = "rich"`). +#[serde_as] +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SwapResponse { + /// Output amount in decimal units. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub out_amount: BigDecimal, + + /// Gas fee information. + pub gas_fee: GasFee, + + /// Transaction data for the swap. + pub swap_transaction: SwapTransaction, +} + +#[serde_as] +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GasFee { + #[serde_as(as = "serde_with::DisplayFromStr")] + pub gas_limit: u64, +} + +#[derive(Deserialize, Clone, Debug)] +pub struct SwapTransaction { + /// Contract address (router/spender). + pub to: eth::Address, + /// Decoded calldata bytes (Bitget sends a `"0x..."` hex string). + #[serde(deserialize_with = "bytes_hex::deserialize")] + pub data: Vec, +} + +/// A Bitget API reverse-swap request (`requestMode = "minAmountOut"`). +/// +/// Used for buy orders. The `amount` field carries the desired minimum amount +/// of `to_contract` to receive, and the API returns the input amount of +/// `from_contract` required (computed via reverse quoting). +/// +/// See [API](https://web3.bitget.com/en/docs/trading/instruction-mode#reverse-quote-swap-api). +#[serde_as] +#[derive(Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReverseSwapRequest { + /// Source token contract address. + pub from_contract: eth::Address, + + /// Target token contract address. + pub to_contract: eth::Address, + + /// Source chain name. The reverse-quote endpoint is single-chain only. + pub from_chain: ChainName, + + /// For `requestMode = "minAmountOut"` this is the desired minimum output + /// amount in human-readable decimal units of `to_contract`. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub amount: BigDecimal, + + /// Always `"minAmountOut"` here. We do not use this endpoint in + /// `"exactIn"` mode since the dedicated `/swap` endpoint covers that. + pub request_mode: String, + + /// Debit address. + pub from_address: eth::Address, + + /// Recipient address. + pub to_address: eth::Address, + + /// Slippage tolerance percentage, sent as a string per the docs (e.g. + /// `"0.5"` for 0.5%). + #[serde_as(as = "serde_with::DisplayFromStr")] + pub slippage: f64, + + /// Fee rate in per mille. Must be 0 or between 0.001 and 0.2. + pub fee_rate: f64, +} + +impl ReverseSwapRequest { + pub fn from_order( + order: &dex::Order, + chain_name: ChainName, + settlement_contract: eth::Address, + slippage: &dex::Slippage, + buy_decimals: u8, + ) -> Self { + Self { + from_contract: order.sell.0, + to_contract: order.buy.0, + from_chain: chain_name, + amount: super::wei_to_decimal(order.amount.get(), buy_decimals), + request_mode: "minAmountOut".to_string(), + from_address: settlement_contract, + to_address: settlement_contract, + slippage: slippage.as_percent().unwrap_or_default(), + fee_rate: 0.0, + } + } +} + +/// A Bitget API reverse-swap response. +#[serde_as] +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ReverseSwapResponse { + /// Input amount the recursion converged on, in decimal units of the + /// `from_contract` token. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub amount_in: BigDecimal, + + /// Expected output amount, in decimal units of the `to_contract` token. + /// Slightly above the requested `amount` (the on-chain minimum). + #[serde_as(as = "serde_with::DisplayFromStr")] + pub expected_amount_out: BigDecimal, + + /// Transactions to execute. Typically a single entry. + pub txs: Vec, +} + +#[serde_as] +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ReverseSwapTx { + /// Target contract address (router/spender). + pub to: eth::Address, + + /// Decoded calldata bytes (Bitget sends a `"0x..."` hex string). + #[serde(deserialize_with = "bytes_hex::deserialize")] + pub calldata: Vec, + + /// Function name. Observed values include `"swap"`. Other values + /// (e.g. `"approve"`) likely appear for setup transactions in + /// multi-tx responses. + #[serde(default)] + pub function: String, + + /// Gas limit estimate. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub gas_limit: u64, +} + +/// A Bitget API response wrapper. +/// +/// On success `status` is 0 and `data` contains the result. +/// On error `status` is 1, `error_code` identifies the failure, and `data` is +/// null. +/// +/// See +#[derive(Deserialize, Clone, Debug)] +pub struct Response { + /// Response status code (0 = success, 1 = failure). + pub status: i64, + + /// Bitget error code (e.g. 80005 for insufficient liquidity). + /// Only present when `status` is non-zero. + #[serde(default)] + pub error_code: Option, + + /// Human-readable error description. + #[serde(default)] + pub message: Option, + + /// Response data — `None` when the API returns an error. + pub data: Option, +} diff --git a/crates/solvers/src/infra/dex/bitget/mod.rs b/crates/solvers/src/infra/dex/bitget/mod.rs new file mode 100644 index 0000000000..f9b964efc8 --- /dev/null +++ b/crates/solvers/src/infra/dex/bitget/mod.rs @@ -0,0 +1,468 @@ +use { + crate::{ + domain::{auction, dex, eth, order}, + util, + }, + alloy::primitives::{Address, U256}, + base64::prelude::*, + bigdecimal::{BigDecimal, RoundingMode}, + ethrpc::block_stream::CurrentBlockWatcher, + hmac::{Hmac, Mac}, + number::conversions::{big_decimal_to_u256, u256_to_big_uint}, + sha2::Sha256, + std::{ + collections::BTreeMap, + sync::atomic::{self, AtomicU64}, + }, + tracing::Instrument, +}; + +/// Convert a U256 wei amount to a decimal string using the token's decimals. +/// e.g., 1000000000000000000 with 18 decimals → "1" +fn wei_to_decimal(amount: U256, decimals: u8) -> BigDecimal { + BigDecimal::new(u256_to_big_uint(&amount).into(), i64::from(decimals)).normalized() +} + +/// Rounding direction for converting Bitget's decimal responses to wei. +/// +/// Bitget can return more decimal digits than the token has (e.g. +/// `"1.1234567"` for 6-decimal USDC), so we have to round to the nearest +/// base unit. We pick the direction that, when our reported amount and +/// the swap's actual amount disagree, leaves the GPv2Settlement contract +/// holding *more* tokens than it owes (rather than fewer). Holding fewer +/// would cause an ERC20 transfer to revert during settlement. +#[derive(Clone, Copy)] +enum Round { + /// For input amounts (what we pay/approve). Rounds 1.1234567 USDC up + /// to 1123457 base units (vs. 1123456 for `Down`), so the allowance + /// and pulled funds cover the swap's actual input. Under-pulling + /// causes a settlement revert. + Up, + /// For output amounts (what we report as received). Rounds 1.1234567 + /// USDC down to 1123456 base units (vs. 1123457 for `Up`), so we + /// don't claim more buy tokens than the swap delivered. Over-claiming + /// causes a settlement revert. + Down, +} + +/// Convert a decimal amount (from an API response) to U256 wei using the +/// given rounding direction. e.g. +/// `decimal_to_wei("1964.365496", 6, Down) → 1964365496`. +fn decimal_to_wei(amount: &BigDecimal, decimals: u8, round: Round) -> Result { + let scaled = amount * BigDecimal::new(1.into(), -i64::from(decimals)); + let mode = match round { + Round::Up => RoundingMode::Up, + Round::Down => RoundingMode::Down, + }; + big_decimal_to_u256(&scaled.with_scale_round(0, mode)).ok_or(Error::AmountConversionFailed) +} + +mod dto; + +/// Default Bitget swap API base endpoint. +pub const DEFAULT_ENDPOINT: &str = "https://bopenapi.bgwapi.io/bgw-pro/swapx/pro/"; + +/// Default API path used for signature computation. When a proxy endpoint is +/// configured, the request URL differs from the canonical path that Bitget +/// expects in the signature. +const SIGNATURE_API_PATH: &str = "/bgw-pro/swapx/pro/"; + +/// Bitget API path for getting swap calldata (sell orders, exact-in). +const SWAP_PATH: &str = "swap"; + +/// Bitget API path for the reverse-quote swap endpoint (buy orders, +/// `requestMode = "minAmountOut"`). +const SWAP_REVERSE_PATH: &str = "swapr"; + +/// Bindings to the Bitget swap API. +pub struct Bitget { + client: super::Client, + endpoint: reqwest::Url, + api_key: String, + api_secret: String, + partner_code: String, + chain_name: dto::ChainName, + settlement_contract: Address, + enable_buy_orders: bool, +} + +pub struct Config { + /// The base URL for the Bitget swap API. + pub endpoint: reqwest::Url, + + pub chain_id: eth::ChainId, + + pub settlement_contract: Address, + + /// Credentials used to access Bitget API. + pub credentials: BitgetCredentialsConfig, + + /// Partner code sent in the `Partner-Code` header. + pub partner_code: String, + + /// The stream that yields every new block. + pub block_stream: Option, + + /// Whether to serve buy orders via the reverse-quote endpoint. Off by + /// default so operators can keep the new path opt-in until they're + /// confident in it. See [`Bitget::handle_buy_order`] for behavior. + pub enable_buy_orders: bool, +} + +pub struct BitgetCredentialsConfig { + /// Bitget API key. + pub api_key: String, + + /// Bitget API secret for signing requests. + pub api_secret: String, +} + +impl Bitget { + pub fn try_new(config: Config) -> Result { + let client = { + let client = reqwest::Client::builder().build()?; + super::Client::new(client, config.block_stream) + }; + + let chain_name = dto::ChainName::new(config.chain_id); + + Ok(Self { + client, + endpoint: config.endpoint, + api_key: config.credentials.api_key, + api_secret: config.credentials.api_secret, + partner_code: config.partner_code, + chain_name, + settlement_contract: config.settlement_contract, + enable_buy_orders: config.enable_buy_orders, + }) + } + + pub async fn swap( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + tokens: &auction::Tokens, + ) -> Result { + if order.side == order::Side::Buy && !self.enable_buy_orders { + return Err(Error::OrderNotSupported); + } + + let sell_decimals = tokens + .get(&order.sell) + .and_then(|t| t.decimals) + .ok_or(Error::MissingDecimals)?; + let buy_decimals = tokens + .get(&order.buy) + .and_then(|t| t.decimals) + .ok_or(Error::MissingDecimals)?; + + // Set up a tracing span to make debugging of API requests easier. + static ID: AtomicU64 = AtomicU64::new(0); + let id = ID.fetch_add(1, atomic::Ordering::Relaxed); + let span = tracing::trace_span!("swap", id = %id); + + match order.side { + order::Side::Sell => { + self.handle_sell_order(order, slippage, sell_decimals, buy_decimals) + .instrument(span) + .await + } + order::Side::Buy => { + self.handle_buy_order(order, slippage, sell_decimals, buy_decimals) + .instrument(span) + .await + } + } + } + + /// Handle sell orders with a single enriched swap API call. + /// + /// Uses `requestMod = "rich"` so `/swap` returns the quote (output + /// amount, gas) and the swap calldata in the same response. Quoting + /// and calldata-building share the same block, so the price the + /// solver scores is the same price the calldata would execute at. + async fn handle_sell_order( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + sell_decimals: u8, + buy_decimals: u8, + ) -> Result { + let swap_request = dto::SwapRequest::from_order( + order, + self.chain_name, + self.settlement_contract, + slippage, + sell_decimals, + ); + let response: dto::SwapResponse = self.send_post_request(SWAP_PATH, &swap_request).await?; + + let calldata = response.swap_transaction.data; + let contract = response.swap_transaction.to; + + // Increase gas estimate by 50% for safety margin, similar to OKX. + let gas_limit = U256::from(response.gas_fee.gas_limit); + let gas = gas_limit + .checked_add(gas_limit / U256::from(2)) + .ok_or(Error::GasCalculationFailed)?; + + let output_amount = decimal_to_wei(&response.out_amount, buy_decimals, Round::Down)?; + + Ok(dex::Swap { + calls: vec![dex::Call { + to: contract, + calldata, + }], + input: eth::Asset { + token: order.sell, + amount: order.amount.get(), + }, + output: eth::Asset { + token: order.buy, + amount: output_amount, + }, + allowance: dex::Allowance { + spender: contract, + amount: dex::Amount::new(order.amount.get()), + }, + gas: eth::Gas(gas), + }) + } + + /// Handle buy orders via the reverse-quote endpoint. + /// + /// Bitget computes the required input amount server-side using a + /// recursive search on top of sell quotes. The response calldata + /// enforces `minAmountOut` on chain, so the swap reverts if it + /// underdelivers. + /// + /// Note that Bitget's recursion typically converges from above, so + /// the swap usually delivers slightly more than the requested buy + /// amount. CoW exact-out semantics still deliver the user only what + /// they signed for, and the overshoot accrues to GPv2Settlement's + /// internal token balance (the "buffer", reused to internalize + /// future swaps). + /// + /// This path is feature-gated via `enable_buy_orders` so it can be + /// turned off quickly if anything misbehaves on Bitget's side. + async fn handle_buy_order( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + sell_decimals: u8, + buy_decimals: u8, + ) -> Result { + let swap_request = dto::ReverseSwapRequest::from_order( + order, + self.chain_name, + self.settlement_contract, + slippage, + buy_decimals, + ); + let response: dto::ReverseSwapResponse = self + .send_post_request(SWAP_REVERSE_PATH, &swap_request) + .await?; + + // Bitget's reverse-quote builds an EOA-style flow: a typical + // multi-tx response is `[approve(router, amountIn), swap(...)]`. + // The CoW settlement contract handles its own approvals via + // `dex::Allowance`, so we pick the actual swap tx by function + // name and ignore everything else. Positive match on `"swap"` so + // that any future setup tx types (`permit`, `wrap`, etc.) are + // dropped automatically instead of silently picked up. + let tx = response + .txs + .iter() + .rev() + .find(|tx| tx.function.eq_ignore_ascii_case("swap")) + .ok_or(Error::NotFound)?; + let calldata = tx.calldata.clone(); + let contract = tx.to; + + // Increase gas estimate by 50% for safety margin, similar to OKX. + let gas_limit = U256::from(tx.gas_limit); + let gas = gas_limit + .checked_add(gas_limit / U256::from(2)) + .ok_or(Error::GasCalculationFailed)?; + + let input_amount = decimal_to_wei(&response.amount_in, sell_decimals, Round::Up)?; + + // Sanity check: if Bitget's own estimated output is below what we + // asked for, the recursion under-converged and the on-chain swap + // (which strictly enforces the requested `minAmountOut`) would + // revert. Bail early so we don't waste a simulator roundtrip. + // Compare the raw BigDecimals so the check doesn't depend on + // rounding direction. + let requested_out = wei_to_decimal(order.amount.get(), buy_decimals); + if response.expected_amount_out < requested_out { + return Err(Error::NotFound); + } + + // CoW buy orders require the executed buy amount to equal the order's + // buy amount exactly. Bitget's calldata enforces this on chain, and + // any overshoot accrues to the settlement buffer. + let output_amount = order.amount.get(); + + Ok(dex::Swap { + calls: vec![dex::Call { + to: contract, + calldata, + }], + input: eth::Asset { + token: order.sell, + amount: input_amount, + }, + output: eth::Asset { + token: order.buy, + amount: output_amount, + }, + allowance: dex::Allowance { + spender: contract, + amount: dex::Amount::new(input_amount), + }, + gas: eth::Gas(gas), + }) + } + + /// Generate HMAC-SHA256 signature for the Bitget API. + /// + /// The signature is computed over a JSON object with alphabetically sorted + /// keys containing: the API path, body, API key, and timestamp. + pub(crate) fn generate_signature( + &self, + api_path: &str, + body: &str, + timestamp: &str, + ) -> Result { + // Use `BTreeMap` for alphabetical ordering required by API (see ). + let mut content = BTreeMap::new(); + content.insert("apiPath", api_path); + content.insert("body", body); + content.insert("x-api-key", &self.api_key); + content.insert("x-api-timestamp", timestamp); + + let content_str = serde_json::to_string(&content).map_err(|_| Error::SignRequestFailed)?; + + let mut mac = Hmac::::new_from_slice(self.api_secret.as_bytes()) + .map_err(|_| Error::SignRequestFailed)?; + mac.update(content_str.as_bytes()); + let signature = mac.finalize().into_bytes(); + + Ok(BASE64_STANDARD.encode(signature)) + } + + /// Bitget error handling based on `error_code`. + /// + /// See + fn handle_api_error( + status: i64, + error_code: Option, + message: String, + ) -> Result<(), Error> { + if status == 0 { + return Ok(()); + } + + Err(match error_code.unwrap_or(80000) { + 80001 // Insufficient token balance + | 80004 // Order expired + | 80005 // Insufficient liquidity + | 80008 // Reverse quote did not converge + | 80009 // Token info not found + | 80010 // Price/gas price not found + | 80011 // Failed to generate calldata + | 80012 // Quote failed + | 80014 // Order not found + => Error::NotFound, + 80002 // Amount below minimum + | 80003 // Amount above maximum + | 80006 // Illegal request + | 80013 // Unsupported chain + => Error::BadRequest, + code => Error::Api { code, message }, + }) + } + + async fn send_post_request(&self, endpoint: &str, body: &T) -> Result + where + T: serde::Serialize, + U: serde::de::DeserializeOwned, + { + let url = self + .endpoint + .join(endpoint) + .map_err(|_| Error::RequestBuildFailed)?; + + let body_str = serde_json::to_string(body).map_err(|_| Error::RequestBuildFailed)?; + let timestamp = chrono::Utc::now().timestamp_millis().to_string(); + let signature_path = format!("{SIGNATURE_API_PATH}{endpoint}"); + let signature = self.generate_signature(&signature_path, &body_str, ×tamp)?; + + let request_builder = self + .client + .request(reqwest::Method::POST, url.clone()) + .header("Content-Type", "application/json") + .header("Partner-Code", &self.partner_code) + .header("x-api-key", &self.api_key) + .header("x-api-timestamp", ×tamp) + .header("x-api-signature", &signature) + .body(body_str); + + let response = request_builder + .send() + .await + .map_err(util::http::Error::from)?; + let status = response.status(); + let body = response.text().await.map_err(util::http::Error::from)?; + + if status == reqwest::StatusCode::TOO_MANY_REQUESTS { + return Err(Error::RateLimited); + } + if !status.is_success() { + return Err(util::http::Error::Status(status, body).into()); + } + + let response: dto::Response = + serde_json::from_str(&body).map_err(util::http::Error::from)?; + + Self::handle_api_error( + response.status, + response.error_code, + response.message.unwrap_or_default(), + )?; + response.data.ok_or(Error::NotFound) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum CreationError { + #[error(transparent)] + Client(#[from] reqwest::Error), +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("failed to build the request")] + RequestBuildFailed, + #[error("failed to sign the request")] + SignRequestFailed, + #[error("calculating output gas failed")] + GasCalculationFailed, + #[error("unable to find a quote")] + NotFound, + #[error("order type is not supported")] + OrderNotSupported, + #[error("rate limited")] + RateLimited, + #[error("failed to convert amount between decimal and U256")] + AmountConversionFailed, + #[error("decimals are missing for the swapped tokens")] + MissingDecimals, + #[error("bad request")] + BadRequest, + #[error("api error code {code}: {message}")] + Api { code: i64, message: String }, + #[error(transparent)] + Http(#[from] util::http::Error), +} diff --git a/crates/solvers/src/infra/dex/mod.rs b/crates/solvers/src/infra/dex/mod.rs new file mode 100644 index 0000000000..22c11a6973 --- /dev/null +++ b/crates/solvers/src/infra/dex/mod.rs @@ -0,0 +1,121 @@ +use { + crate::domain::{auction, dex}, + ethrpc::block_stream::CurrentBlockWatcher, + reqwest::RequestBuilder, +}; + +pub mod bitget; +pub mod okx; +pub mod simulator; + +pub use self::simulator::Simulator; + +/// A supported external DEX/DEX aggregator API. +pub enum Dex { + Bitget(bitget::Bitget), + Okx(Box), +} + +impl Dex { + /// Computes a swap (including calldata, estimated input and output amounts + /// and the required allowance) for the specified order. + /// + /// These computed swaps can be used to generate single order solutions. + pub async fn swap( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + tokens: &auction::Tokens, + ) -> Result { + let swap = match self { + Dex::Bitget(bitget) => bitget.swap(order, slippage, tokens).await?, + Dex::Okx(okx) => okx.swap(order, slippage).await?, + }; + Ok(swap) + } +} + +/// A categorized error that occurred building a swap with an external DEX/DEX +/// aggregator. +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("order type is not supported")] + OrderNotSupported, + #[error("no valid swap interaction could be found")] + NotFound, + #[error("invalid request")] + BadRequest, + #[error("rate limited")] + RateLimited, + #[error("unavailable for legal reasons, banned tokens or similar")] + UnavailableForLegalReasons, + #[error(transparent)] + Other(Box), +} + +/// A wrapper around [`reqwest::Client`] to pre-set commonly used headers +/// and other properties on each request. +pub(crate) struct Client { + /// Client to send requests. + client: reqwest::Client, + + /// Block stream to read the current block. + block_stream: Option, +} + +impl Client { + pub fn new(client: reqwest::Client, block_stream: Option) -> Self { + Self { + client, + block_stream, + } + } + + /// Prepares a request builder which already has additional headers set. + pub fn request(&self, method: reqwest::Method, url: reqwest::Url) -> RequestBuilder { + let request = self.client.request(method, url); + if let Some(stream) = &self.block_stream { + // Set this header to easily support caching in an egress proxy. + request.header("X-CURRENT-BLOCK-HASH", stream.borrow().hash.to_string()) + } else { + request + } + } +} + +impl Error { + /// for instrumentization purposes + pub fn format_variant(&self) -> &'static str { + match self { + Self::OrderNotSupported => "OrderNotSupported", + Self::NotFound => "NotFound", + Self::BadRequest => "BadRequest", + Self::RateLimited => "RateLimited", + Self::UnavailableForLegalReasons => "UnavailableForLegalReasons", + Self::Other(_) => "Other", + } + } +} + +impl From for Error { + fn from(err: okx::Error) -> Self { + match err { + okx::Error::OrderNotSupported => Self::OrderNotSupported, + okx::Error::NotFound => Self::NotFound, + okx::Error::RateLimited => Self::RateLimited, + _ => Self::Other(Box::new(err)), + } + } +} + +impl From for Error { + fn from(err: bitget::Error) -> Self { + match err { + bitget::Error::OrderNotSupported => Self::OrderNotSupported, + bitget::Error::NotFound => Self::NotFound, + bitget::Error::MissingDecimals | bitget::Error::BadRequest => Self::BadRequest, + bitget::Error::RateLimited => Self::RateLimited, + _ => Self::Other(Box::new(err)), + } + } +} diff --git a/crates/solvers/src/infra/dex/okx/dto.rs b/crates/solvers/src/infra/dex/okx/dto.rs new file mode 100644 index 0000000000..6a72481069 --- /dev/null +++ b/crates/solvers/src/infra/dex/okx/dto.rs @@ -0,0 +1,312 @@ +//! DTOs for the OKX swap API. Full documentation for the API can be found +//! [here](https://web3.okx.com/build/dev-docs/wallet-api/dex-swap). + +use { + crate::domain::{ + dex, + eth::{self, TokenAddress}, + order, + }, + alloy::primitives::U256, + bigdecimal::BigDecimal, + bytes_hex::BytesHex, + number::serialization::HexOrDecimalU256, + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +/// A OKX API swap request parameters (only mandatory fields). +/// OKX v6 supports both sell orders (exactIn) and buy orders (exactOut). +/// +/// See [API](https://web3.okx.com/build/dev-docs/wallet-api/dex-swap) +/// documentation for more detailed information on each parameter. +#[serde_as] +#[derive(Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SwapRequest { + /// Chain ID + #[serde_as(as = "serde_with::DisplayFromStr")] + pub chain_index: u64, + + /// Input amount of a token to be sold or bought set in minimal divisible + /// units. + #[serde_as(as = "HexOrDecimalU256")] + pub amount: U256, + + /// Contract address of a token to be sent + pub from_token_address: eth::Address, + + /// Contract address of a token to be received + pub to_token_address: eth::Address, + + /// Limit of price slippage you are willing to accept + pub slippage_percent: Slippage, + + /// User's wallet address. Where the sell tokens will be taken from. + pub user_wallet_address: eth::Address, + + /// Where the buy tokens get sent to. + pub swap_receiver_address: eth::Address, + + /// Swap mode: "exactIn" for sell orders (default), "exactOut" for buy + /// orders + pub swap_mode: SwapMode, + + /// The percentage of the price impact allowed. + /// When set to 100%, the feature is disabled. + /// OKX API default is 90% if this parameter is not sent. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub price_impact_protection_percent: BigDecimal, +} + +/// A OKX slippage amount. +#[derive(Clone, Debug, Default, Serialize)] +pub struct Slippage(BigDecimal); + +/// A OKX swap mode. +#[derive(Clone, Debug, Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub enum SwapMode { + #[default] + ExactIn, + ExactOut, +} + +impl SwapRequest { + pub fn with_domain(self, order: &dex::Order, slippage: &dex::Slippage) -> Self { + let swap_mode = match order.side { + order::Side::Sell => SwapMode::ExactIn, + order::Side::Buy => SwapMode::ExactOut, + }; + + Self { + from_token_address: order.sell.0, + to_token_address: order.buy.0, + amount: order.amount.get(), + slippage_percent: Slippage(slippage.as_factor().clone()), + swap_mode, + ..self + } + } +} + +/// A OKX API V5 swap request parameters (only mandatory fields). +/// Currently, only V5 API supports buy orders. +#[serde_as] +#[derive(Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SwapRequestV5 { + /// Chain ID (V5 uses chainId instead of chainIndex) + #[serde_as(as = "serde_with::DisplayFromStr")] + pub chain_id: u64, + + /// Input amount of a token to be sold or bought set in minimal divisible + /// units. + #[serde_as(as = "HexOrDecimalU256")] + pub amount: U256, + + /// Contract address of a token to be sent + pub from_token_address: eth::Address, + + /// Contract address of a token to be received + pub to_token_address: eth::Address, + + /// Limit of price slippage you are willing to accept (V5 uses slippage + /// instead of slippagePercent) + pub slippage: Slippage, + + /// User's wallet address. Where the sell tokens will be taken from. + pub user_wallet_address: eth::Address, + + /// Where the buy tokens get sent to. + pub swap_receiver_address: eth::Address, + + /// Swap mode: "exactIn" for sell orders (default), "exactOut" for buy + /// orders + pub swap_mode: SwapMode, + + /// The percentage of the price impact allowed. + /// When set to 100%, the feature is disabled. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub price_impact_protection_percent: BigDecimal, +} + +impl From<&SwapRequest> for SwapRequestV5 { + fn from(v6_request: &SwapRequest) -> Self { + Self { + chain_id: v6_request.chain_index, + amount: v6_request.amount, + from_token_address: v6_request.from_token_address, + to_token_address: v6_request.to_token_address, + slippage: v6_request.slippage_percent.clone(), + user_wallet_address: v6_request.user_wallet_address, + swap_receiver_address: v6_request.swap_receiver_address, + swap_mode: v6_request.swap_mode.clone(), + price_impact_protection_percent: v6_request.price_impact_protection_percent.clone(), + } + } +} + +/// A OKX API swap response. +/// +/// See [API](https://web3.okx.com/build/dev-docs/wallet-api/dex-swap) +/// documentation for more detailed information on each parameter. +#[serde_as] +#[derive(Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SwapResponse { + /// Quote execution path. + pub router_result: SwapResponseRouterResult, + + /// Contract related response. + pub tx: SwapResponseTx, +} + +/// A OKX API swap response - quote execution path. +/// Deserializing fields which are only used by the implementation. +/// For all possible fields look into the documentation: +/// [API](https://web3.okx.com/build/dev-docs/wallet-api/dex-swap) +#[serde_as] +#[derive(Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SwapResponseRouterResult { + /// The information of a token to be sold. + pub from_token: SwapResponseFromToToken, + + /// The information of a token to be bought. + pub to_token: SwapResponseFromToToken, + + /// The input amount of a token to be sold. + #[serde_as(as = "HexOrDecimalU256")] + pub from_token_amount: U256, + + /// The resulting amount of a token to be bought. + #[serde_as(as = "HexOrDecimalU256")] + pub to_token_amount: U256, +} + +/// A OKX API swap response - token information. +/// Deserializing fields which are only used by the implementation. +/// For all possible fields look into the documentation: +/// [API](https://web3.okx.com/build/dev-docs/wallet-api/dex-swap) +#[serde_as] +#[derive(Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SwapResponseFromToToken { + /// Address of the token smart contract. + pub token_contract_address: eth::Address, +} + +/// A OKX API swap response - contract related information. +/// Deserializing fields which are only used by the implementation. +/// For all possible fields look into the documentation: +/// [API](https://web3.okx.com/build/dev-docs/wallet-api/dex-swap) +#[serde_as] +#[derive(Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SwapResponseTx { + /// Estimated amount of the gas limit. + #[serde_as(as = "HexOrDecimalU256")] + pub gas: U256, + + /// The contract address of OKX DEX router. + pub to: eth::Address, + + /// Call data. + #[serde_as(as = "BytesHex")] + pub data: Vec, +} + +/// A OKX API approve transaction request. +/// +/// See [API](https://web3.okx.com/build/dev-docs/wallet-api/dex-approve-transaction) +/// documentation for more detailed information on each parameter. +#[serde_as] +#[derive(Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApproveTransactionRequest { + /// Chain ID + #[serde_as(as = "serde_with::DisplayFromStr")] + pub chain_index: u64, + + /// Contract address of a token to be permitted. + pub token_contract_address: eth::Address, + + /// The amount of token that needs to be permitted (in minimal divisible + /// units). + #[serde_as(as = "HexOrDecimalU256")] + pub approve_amount: U256, +} + +impl ApproveTransactionRequest { + pub fn new(chain_index: u64, token: TokenAddress, amount: U256) -> Self { + Self { + chain_index, + token_contract_address: token.0, + approve_amount: amount, + } + } +} + +/// A OKX API V5 approve transaction request. +#[serde_as] +#[derive(Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApproveTransactionRequestV5 { + /// Chain ID (V5 uses chainId instead of chainIndex) + #[serde_as(as = "serde_with::DisplayFromStr")] + pub chain_id: u64, + + /// Contract address of a token to be permitted. + pub token_contract_address: eth::Address, + + /// The amount of token that needs to be permitted (in minimal divisible + /// units). + #[serde_as(as = "HexOrDecimalU256")] + pub approve_amount: U256, +} + +impl From<&ApproveTransactionRequest> for ApproveTransactionRequestV5 { + fn from(v6_request: &ApproveTransactionRequest) -> Self { + Self { + chain_id: v6_request.chain_index, + token_contract_address: v6_request.token_contract_address, + approve_amount: v6_request.approve_amount, + } + } +} + +/// A OKX API approve transaction response. +/// Deserializing fields which are only used by the implementation. +/// See [API](https://web3.okx.com/build/dev-docs/wallet-api/dex-approve-transaction) +/// documentation for more detailed information on each parameter. +#[serde_as] +#[derive(Clone, Default, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ApproveTransactionResponse { + /// The contract address of OKX DEX approve. + pub dex_contract_address: eth::Address, +} + +/// A OKX API response - generic wrapper for success and failure cases. +#[serde_as] +#[derive(Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Response { + /// Error code, 0 for success, otherwise one of: + /// [error codes](https://web3.okx.com/build/dev-docs/wallet-api/dex-error-code) + #[serde_as(as = "serde_with::DisplayFromStr")] + pub code: i64, + + /// Response data. + pub data: Vec, + + /// Error code text message. + pub msg: String, +} + +#[derive(Deserialize)] +pub struct Error { + pub code: i64, + pub reason: String, +} diff --git a/crates/solvers/src/infra/dex/okx/mod.rs b/crates/solvers/src/infra/dex/okx/mod.rs new file mode 100644 index 0000000000..90049352bd --- /dev/null +++ b/crates/solvers/src/infra/dex/okx/mod.rs @@ -0,0 +1,516 @@ +use { + crate::{ + domain::{dex, eth, order}, + util, + }, + alloy::primitives::{Address, U256}, + base64::prelude::*, + bigdecimal::FromPrimitive, + chrono::SecondsFormat, + ethrpc::block_stream::CurrentBlockWatcher, + hmac::{Hmac, Mac}, + moka::future::Cache, + reqwest::{StatusCode, header::HeaderValue}, + serde::{Serialize, de::DeserializeOwned}, + sha2::Sha256, + std::sync::atomic::{self, AtomicU64}, + tracing::Instrument, +}; + +mod dto; + +/// Default OKX v6 DEX aggregator API endpoint (for sell orders - exactIn). +pub const DEFAULT_SELL_ORDERS_ENDPOINT: &str = "https://web3.okx.com/api/v6/dex/aggregator/"; + +const DEFAULT_DEX_APPROVED_ADDRESSES_CACHE_SIZE: u64 = 100; + +/// Cache key for OKX DEX approve contract addresses. +/// V5 and V6 APIs may return different contract addresses for the same token, +/// so we need to cache separately by order side. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +struct ApprovalCacheKey { + token: eth::TokenAddress, + side: order::Side, +} + +/// Bindings to the OKX swap API. +pub struct Okx { + client: super::Client, + sell_orders_endpoint: reqwest::Url, + buy_orders_endpoint: Option, + sell_orders_signature_base_url: reqwest::Url, + buy_orders_signature_base_url: Option, + api_secret_key: String, + defaults: dto::SwapRequest, + /// Cache which stores a map of (Token Address, Order Side) to contract + /// address of OKX DEX approve contract. Separate caching by side is + /// needed because V5 API (buy orders) and V6 API (sell orders) return + /// different addresses. + dex_approved_addresses: Cache, +} + +pub struct Config { + /// The URL for the OKX swap API for sell orders (exactIn mode). + /// Uses V6 API by default. + pub sell_orders_endpoint: reqwest::Url, + + /// The URL for the OKX swap API for buy orders (exactOut mode). + /// If specified, the URL must point to the V5 API. Otherwise, buy orders + /// will be ignored. + pub buy_orders_endpoint: Option, + + /// Optional base URL to use for signature generation for sell orders. + /// This is useful when requests go through a proxy but signatures must be + /// generated using the original OKX API URL path. + /// If not specified, uses sell_orders_endpoint for signature generation. + pub sell_orders_signature_base_url: Option, + + /// Optional base URL to use for signature generation for buy orders. + /// This is useful when requests go through a proxy but signatures must be + /// generated using the original OKX API URL path. + /// If not specified, uses buy_orders_endpoint for signature generation. + pub buy_orders_signature_base_url: Option, + + pub chain_id: eth::ChainId, + + pub settlement_contract: Address, + + /// Credentials used to access OKX API. + pub okx_credentials: OkxCredentialsConfig, + + /// The stream that yields every new block. + pub block_stream: Option, + + /// The percentage of the price impact allowed. + /// When set to 100%, the feature is disabled. + pub price_impact_protection_percent: f64, +} + +pub struct OkxCredentialsConfig { + /// OKX project ID to use. + pub project_id: String, + + /// OKX API key. + pub api_key: String, + + /// OKX API key additional security token. + pub api_secret_key: String, + + /// OKX API key passphrase used to encrypt secret key. + pub api_passphrase: String, +} + +impl Okx { + pub fn try_new(config: Config) -> Result { + let client = { + let mut api_key = + reqwest::header::HeaderValue::from_str(&config.okx_credentials.api_key)?; + api_key.set_sensitive(true); + let mut api_passphrase = + reqwest::header::HeaderValue::from_str(&config.okx_credentials.api_passphrase)?; + api_passphrase.set_sensitive(true); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert( + "OK-ACCESS-PROJECT", + reqwest::header::HeaderValue::from_str(&config.okx_credentials.project_id)?, + ); + headers.insert("OK-ACCESS-KEY", api_key); + headers.insert("OK-ACCESS-PASSPHRASE", api_passphrase); + + let client = reqwest::Client::builder() + .default_headers(headers) + .build()?; + super::Client::new(client, config.block_stream) + }; + + if config.price_impact_protection_percent < 0.0 + || config.price_impact_protection_percent > 100.0 + { + return Err(CreationError::InvalidPriceImpactProtection( + config.price_impact_protection_percent, + )); + } + let price_impact_protection = + bigdecimal::BigDecimal::from_f64(config.price_impact_protection_percent) + .ok_or_else(|| { + CreationError::InvalidPriceImpactProtection( + config.price_impact_protection_percent, + ) + })? + .normalized(); + + let defaults = dto::SwapRequest { + chain_index: config.chain_id as u64, + // Funds first get moved in and out of the settlement contract so we + // have use that address here to generate the correct calldata. + swap_receiver_address: config.settlement_contract, + user_wallet_address: config.settlement_contract, + price_impact_protection_percent: price_impact_protection, + ..Default::default() + }; + + Ok(Self { + client, + sell_orders_endpoint: config.sell_orders_endpoint.clone(), + buy_orders_endpoint: config.buy_orders_endpoint.clone(), + sell_orders_signature_base_url: config + .sell_orders_signature_base_url + .unwrap_or(config.sell_orders_endpoint), + buy_orders_signature_base_url: config + .buy_orders_signature_base_url + .or(config.buy_orders_endpoint), + api_secret_key: config.okx_credentials.api_secret_key, + defaults, + dex_approved_addresses: Cache::new(DEFAULT_DEX_APPROVED_ADDRESSES_CACHE_SIZE), + }) + } + + pub async fn swap( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + ) -> Result { + // Set up a tracing span to make debugging of API requests easier. + static ID: AtomicU64 = AtomicU64::new(0); + let id = ID.fetch_add(1, atomic::Ordering::Relaxed); + + let (swap_response, dex_contract_address) = self + .handle_api_requests(order, slippage) + .instrument(tracing::trace_span!("swap", id = %id)) + .await?; + + // Increasing returned gas by 50% according to the documentation: + // https://web3.okx.com/build/dev-docs/wallet-api/dex-swap (gas field description in Response param) + let gas = swap_response + .tx + .gas + .checked_add(swap_response.tx.gas / U256::from(2)) + .ok_or(Error::GasCalculationFailed)?; + + // For buy orders (ExactOut mode), the slippage is on the input token, + // so we need to use U256::MAX allowance to cover the maximum possible + // input. + let allowance_amount = + if self.buy_orders_endpoint.is_some() && order.side == order::Side::Buy { + eth::U256::MAX + } else { + swap_response.router_result.from_token_amount + }; + + Ok(dex::Swap { + calls: vec![dex::Call { + to: swap_response.tx.to, + calldata: swap_response.tx.data.clone(), + }], + input: eth::Asset { + token: swap_response + .router_result + .from_token + .token_contract_address + .into(), + amount: swap_response.router_result.from_token_amount, + }, + output: eth::Asset { + token: swap_response + .router_result + .to_token + .token_contract_address + .into(), + amount: swap_response.router_result.to_token_amount, + }, + allowance: dex::Allowance { + spender: dex_contract_address.0, + amount: dex::Amount::new(allowance_amount), + }, + gas: eth::Gas(gas), + }) + } + + /// Routes API requests based on order side. + /// + /// - Sell orders: Parallel execution of /swap and /approve-transaction + /// - Buy orders: Sequential execution (swap first, then approval with exact + /// amount) + async fn handle_api_requests( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + ) -> Result<(dto::SwapResponse, eth::ContractAddress), Error> { + match order.side { + order::Side::Sell => self.handle_sell_order(order, slippage).await, + order::Side::Buy => self.handle_buy_order(order, slippage).await, + } + } + + /// Handle sell orders with parallel API requests. + /// + /// Since the approval amount is known upfront from `order.amount`, + /// we can execute `/swap` and `/approve-transaction` in parallel for better + /// performance. + async fn handle_sell_order( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + ) -> Result<(dto::SwapResponse, eth::ContractAddress), Error> { + let swap_future = async { + let swap_request = self.defaults.clone().with_domain(order, slippage); + self.send_get_request( + &self.sell_orders_endpoint, + &self.sell_orders_signature_base_url, + "swap", + &swap_request, + ) + .await + }; + + let approve_future = async { + let approve_request = dto::ApproveTransactionRequest::new( + self.defaults.chain_index, + order.sell, + order.amount.get(), + ); + + let approve_tx: dto::ApproveTransactionResponse = self + .send_get_request( + &self.sell_orders_endpoint, + &self.sell_orders_signature_base_url, + "approve-transaction", + &approve_request, + ) + .await?; + + Ok(eth::ContractAddress(approve_tx.dex_contract_address)) + }; + + tokio::try_join!( + swap_future, + self.cache_approval_address(order, approve_future) + ) + } + + /// Handle buy orders with sequential API requests. + /// + /// Since the approval amount depends on the swap response + /// (`from_token_amount`), we must execute `/swap` first, then + /// `/approve-transaction`. + async fn handle_buy_order( + &self, + order: &dex::Order, + slippage: &dex::Slippage, + ) -> Result<(dto::SwapResponse, eth::ContractAddress), Error> { + let endpoint = self + .buy_orders_endpoint + .as_ref() + .ok_or(Error::OrderNotSupported)?; + + let signature_base_url = self + .buy_orders_signature_base_url + .as_ref() + .ok_or(Error::OrderNotSupported)?; + + let swap_request_v6 = self.defaults.clone().with_domain(order, slippage); + let swap_request_v5: dto::SwapRequestV5 = (&swap_request_v6).into(); + let swap_response: dto::SwapResponse = self + .send_get_request(endpoint, signature_base_url, "swap", &swap_request_v5) + .await?; + + let approve_future = async { + let approve_request = dto::ApproveTransactionRequest::new( + self.defaults.chain_index, + order.sell, + swap_response.router_result.from_token_amount, + ); + let approve_request_v5: dto::ApproveTransactionRequestV5 = (&approve_request).into(); + + let approve_tx: dto::ApproveTransactionResponse = self + .send_get_request( + endpoint, + signature_base_url, + "approve-transaction", + &approve_request_v5, + ) + .await?; + + Ok(eth::ContractAddress(approve_tx.dex_contract_address)) + }; + + let dex_approved_address = self.cache_approval_address(order, approve_future).await?; + + Ok((swap_response, dex_approved_address)) + } + + /// Helper to cache approval addresses. + async fn cache_approval_address( + &self, + order: &dex::Order, + future: F, + ) -> Result + where + F: Future>, + { + self.dex_approved_addresses + .try_get_with( + ApprovalCacheKey { + token: order.sell, + side: order.side, + }, + future, + ) + .await + .map_err(|_: std::sync::Arc| Error::ApproveTransactionRequestFailed(order.sell)) + } + + /// OKX requires signature of the request to be added as dedicated HTTP + /// Header. More information on generating the signature can be found in + /// OKX documentation: https://web3.okx.com/build/dev-docs/wallet-api/rest-authentication + fn generate_signature( + &self, + request: &reqwest::Request, + signature_base_url: &reqwest::Url, + timestamp: &str, + ) -> Result { + let mut data = String::new(); + data.push_str(timestamp); + data.push_str(request.method().as_str()); + data.push_str(signature_base_url.path()); + data.push('?'); + data.push_str(request.url().query().ok_or(Error::SignRequestFailed)?); + + let mut mac = Hmac::::new_from_slice(self.api_secret_key.as_bytes()) + .map_err(|_| Error::SignRequestFailed)?; + mac.update(data.as_bytes()); + let signature = mac.finalize().into_bytes(); + + Ok(BASE64_STANDARD.encode(signature)) + } + + /// OKX Error codes: [link](https://web3.okx.com/build/dev-docs/wallet-api/dex-error-code) + fn handle_api_error(code: i64, message: &str) -> Result<(), Error> { + Err(match code { + 0 => return Ok(()), + 51005 // Honeypot or leveraged token (undocumented) + | 82000 // Insufficient liquidity + | 82104 // Token not supported + | 82112 // Internal OKX risk validation failed + => Error::NotFound, + 50011 => Error::RateLimited, + _ => Error::Api { + code, + reason: message.to_string(), + }, + }) + } + + async fn send_get_request( + &self, + base_url: &reqwest::Url, + signature_base_url: &reqwest::Url, + endpoint: &str, + query: &T, + ) -> Result + where + T: Serialize, + U: DeserializeOwned + Clone, + { + let mut request_builder = self + .client + .request( + reqwest::Method::GET, + base_url + .join(endpoint) + .map_err(|_| Error::RequestBuildFailed)?, + ) + .query(query); + + let request = request_builder + .try_clone() + .ok_or(Error::RequestBuildFailed)? + .build() + .map_err(|_| Error::RequestBuildFailed)?; + + let signature_url = signature_base_url + .join(endpoint) + .map_err(|_| Error::RequestBuildFailed)?; + + let timestamp = &chrono::Utc::now() + .to_rfc3339_opts(SecondsFormat::Millis, true) + .to_string(); + let signature = self.generate_signature(&request, &signature_url, timestamp)?; + + request_builder = request_builder.header( + "OK-ACCESS-TIMESTAMP", + reqwest::header::HeaderValue::from_str(timestamp) + .map_err(|_| Error::RequestBuildFailed)?, + ); + request_builder = request_builder.header( + "OK-ACCESS-SIGN", + HeaderValue::from_str(&signature).map_err(|_| Error::RequestBuildFailed)?, + ); + + let response = util::http::roundtrip!( + , dto::Error>; + request_builder + ) + .await?; + + Self::handle_api_error(response.code, &response.msg)?; + response.data.first().cloned().ok_or(Error::NotFound) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum CreationError { + #[error(transparent)] + Header(#[from] reqwest::header::InvalidHeaderValue), + #[error(transparent)] + Client(#[from] reqwest::Error), + #[error("invalid price impact protection percent {0}, must be between 0.0 and 1.0")] + InvalidPriceImpactProtection(f64), +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("failed to build the request")] + RequestBuildFailed, + #[error("failed to sign the request")] + SignRequestFailed, + #[error("calculating output gas failed")] + GasCalculationFailed, + #[error("unable to find a quote")] + NotFound, + #[error("order type is not supported")] + OrderNotSupported, + #[error("rate limited")] + RateLimited, + #[error("failed to get approve-transaction response for token address: {0:?}")] + ApproveTransactionRequestFailed(eth::TokenAddress), + #[error("api error code {code}: {reason}")] + Api { code: i64, reason: String }, + #[error(transparent)] + Http(util::http::Error), +} + +impl From> for Error { + fn from(err: util::http::RoundtripError) -> Self { + match err { + util::http::RoundtripError::Http(err) => { + if let util::http::Error::Status(code, _) = err { + match code { + StatusCode::TOO_MANY_REQUESTS => Self::RateLimited, + _ => Self::Http(err), + } + } else { + Self::Http(err) + } + } + util::http::RoundtripError::Api(err) => match err.code { + 429 => Self::RateLimited, + _ => Self::Api { + code: err.code, + reason: err.reason, + }, + }, + } + } +} diff --git a/crates/solvers/src/infra/dex/simulator.rs b/crates/solvers/src/infra/dex/simulator.rs new file mode 100644 index 0000000000..6ce7046e5d --- /dev/null +++ b/crates/solvers/src/infra/dex/simulator.rs @@ -0,0 +1,120 @@ +use { + crate::{ + domain::{dex, eth}, + infra::blockchain, + }, + alloy::{ + primitives::{Address, U256}, + providers::DynProvider, + rpc::types::state::{AccountOverride, StateOverridesBuilder}, + }, + contracts::support::{ + AnyoneAuthenticator, + Swapper::{ + self, + Swapper::{Allowance, Asset, Interaction}, + }, + }, +}; + +/// A DEX swap simulator. +#[derive(Debug, Clone)] +pub struct Simulator { + web3: DynProvider, + settlement: Address, + authenticator: Address, +} + +impl Simulator { + /// Create a new simulator for computing DEX swap gas usage. + pub fn new(url: &reqwest::Url, settlement: Address, authenticator: Address) -> Self { + Self { + web3: blockchain::rpc(url).provider, + settlement, + authenticator, + } + } + + /// Simulate the gas needed by a single order DEX swap. + /// + /// This will return a `None` if the gas simulation is unavailable. + pub async fn gas(&self, owner: Address, swap: &dex::Swap) -> Result { + if owner == self.settlement { + // we can't have both the settlement and swapper contracts at the + // same address + return Err(Error::SettlementContractIsOwner); + } + + let swapper = Swapper::Instance::new(owner, self.web3.clone()); + let overrides = StateOverridesBuilder::with_capacity(2) + // Setup up our trader code that actually executes the settlement + .append( + *swapper.address(), + AccountOverride { + code: Some(Swapper::Swapper::DEPLOYED_BYTECODE.clone()), + ..Default::default() + }, + ) + // Override the CoW protocol solver authenticator with one that + // allows any address to solve + .append( + self.authenticator, + AccountOverride { + code: Some( + AnyoneAuthenticator::AnyoneAuthenticator::DEPLOYED_BYTECODE.clone(), + ), + ..Default::default() + }, + ); + + let swapper_calls_arg = swap + .calls + .iter() + .map(|call| Interaction { + target: call.to, + value: U256::ZERO, + callData: alloy::primitives::Bytes::copy_from_slice(&call.calldata), + }) + .collect(); + let sell = Asset { + token: swap.input.token.0, + amount: swap.input.amount, + }; + let buy = Asset { + token: swap.output.token.0, + amount: swap.output.amount, + }; + let allowance = Allowance { + spender: swap.allowance.spender, + amount: swap.allowance.amount.get(), + }; + let gas = swapper + .swap(self.settlement, sell, buy, allowance, swapper_calls_arg) + .call() + .overrides(overrides) + .await?; + + // `gas == 0` means that the simulation is not possible. See + // `Swapper.sol` contract for more details. In this case, use the + // heuristic gas amount from the swap. + Ok(if gas.is_zero() { + tracing::info!( + gas = ?swap.gas, + "could not simulate dex swap to get gas used; fall back to gas estimate provided \ + by dex API" + ); + swap.gas + } else { + eth::Gas(gas) + }) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("contract call error: {0:?}")] + ContractCall(#[from] alloy::contract::Error), + + #[error("can't simulate gas for an order for which the settlement contract is the owner")] + SettlementContractIsOwner, +} diff --git a/crates/solvers/src/infra/metrics.rs b/crates/solvers/src/infra/metrics.rs index 509c8893a0..fc7027509f 100644 --- a/crates/solvers/src/infra/metrics.rs +++ b/crates/solvers/src/infra/metrics.rs @@ -12,6 +12,9 @@ struct Metrics { #[metric(buckets(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))] remaining_time: prometheus::Histogram, + /// Total number of requests that got sent to the DEX API. + solve_requests: prometheus::IntCounter, + /// Errors that occurred during solving. #[metric(labels("reason"))] solve_errors: prometheus::IntCounterVec, @@ -42,6 +45,14 @@ pub fn solved(deadline: &auction::Deadline, solutions: &[solution::Solution]) { get().solutions.inc_by(solutions.len() as u64); } +pub fn solve_error(reason: &str) { + get().solve_errors.with_label_values(&[reason]).inc(); +} + +pub fn request_sent() { + get().solve_requests.inc(); +} + /// Get the metrics instance. fn get() -> &'static Metrics { Metrics::instance(observe::metrics::get_storage_registry()) diff --git a/crates/solvers/src/infra/mod.rs b/crates/solvers/src/infra/mod.rs index 792a13c703..e3585bfc7e 100644 --- a/crates/solvers/src/infra/mod.rs +++ b/crates/solvers/src/infra/mod.rs @@ -1,4 +1,6 @@ +pub mod blockchain; pub mod cli; pub mod config; pub mod contracts; +pub mod dex; pub mod metrics; diff --git a/crates/solvers/src/lib.rs b/crates/solvers/src/lib.rs index 23c05bfa77..d584acabe7 100644 --- a/crates/solvers/src/lib.rs +++ b/crates/solvers/src/lib.rs @@ -3,12 +3,12 @@ #![recursion_limit = "256"] mod api; -mod boundary; -mod domain; +pub mod boundary; +pub mod domain; mod infra; mod run; #[cfg(test)] mod tests; -mod util; +pub mod util; pub use self::run::{run, start}; diff --git a/crates/solvers/src/main.rs b/crates/solvers/src/main.rs index 09c582b3eb..03f6db6ca7 100644 --- a/crates/solvers/src/main.rs +++ b/crates/solvers/src/main.rs @@ -1,6 +1,11 @@ +#[cfg(feature = "mimalloc-allocator")] #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +#[cfg(not(feature = "mimalloc-allocator"))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + #[tokio::main] async fn main() { solvers::start(std::env::args()).await; diff --git a/crates/solvers/src/run.rs b/crates/solvers/src/run.rs index b3a0f803e7..861f055715 100644 --- a/crates/solvers/src/run.rs +++ b/crates/solvers/src/run.rs @@ -3,9 +3,10 @@ use tokio::signal::unix::{self, SignalKind}; use { crate::{ domain::solver, - infra::{cli, config}, + infra::{cli, config, dex}, }, clap::Parser, + shared::arguments::tracing_config, std::net::SocketAddr, tokio::sync::oneshot, }; @@ -29,18 +30,39 @@ async fn run_with(args: cli::Args, bind: Option>) { &args.log, tracing::Level::ERROR.into(), args.use_json_logs, - None, + tracing_config(&args.tracing, "solvers".into()), ); - observe::tracing::initialize_reentrant(&obs_config); + observe::tracing::init::initialize_reentrant(&obs_config); + #[cfg(unix)] + observe::heap_dump_handler::spawn_heap_dump_handler(); let commit_hash = option_env!("VERGEN_GIT_SHA").unwrap_or("COMMIT_INFO_NOT_FOUND"); tracing::info!(%commit_hash, "running solver engine with {args:#?}"); let solver = match args.command { - cli::Command::Baseline { config } => { - let config = config::load(&config).await; - solver::Solver::new(config).await + cli::Command::Baseline { config: path } => { + let config = config::baseline::load(&path).await; + solver::Solver::Baseline(solver::Baseline::new(config).await) + } + cli::Command::Okx { config: path } => { + let config = config::dex::okx::file::load(&path).await; + solver::Solver::Dex(Box::new(solver::Dex::new( + dex::Dex::Okx(Box::new( + dex::okx::Okx::try_new(config.okx).expect("invalid OKX configuration"), + )), + config.base, + ))) + } + cli::Command::Bitget { config: path } => { + let config = config::dex::bitget::file::load(&path).await; + solver::Solver::Dex(Box::new(solver::Dex::new( + dex::Dex::Bitget( + dex::bitget::Bitget::try_new(config.bitget) + .expect("invalid Bitget configuration"), + ), + config.base, + ))) } }; diff --git a/crates/solvers/src/tests/bitget/api_calls.rs b/crates/solvers/src/tests/bitget/api_calls.rs new file mode 100644 index 0000000000..8adef702b0 --- /dev/null +++ b/crates/solvers/src/tests/bitget/api_calls.rs @@ -0,0 +1,282 @@ +use { + crate::{ + domain::{auction, dex::*, eth::*}, + infra::dex::bitget as bitget_dex, + }, + alloy::primitives::{Address, address}, + std::{collections::HashMap, env, time::Duration}, +}; + +/// Pause between chain iterations to stay under Bitget's per-IP rate limit. +const RATE_LIMIT_PAUSE: Duration = Duration::from_secs(1); + +/// CoW Protocol GPv2Settlement contract, same address on every supported +/// chain. +const SETTLEMENT: Address = address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"); + +struct TestCase { + name: &'static str, + chain_id: ChainId, + sell_token: Address, + buy_token: Address, + sell_amount: u128, + sell_decimals: u8, + buy_decimals: u8, +} + +const TEST_CASES: &[TestCase] = &[ + TestCase { + name: "Mainnet: 0.1 WETH → USDC", + chain_id: ChainId::Mainnet, + sell_token: address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + buy_token: address!("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), + sell_amount: 100_000_000_000_000_000, + sell_decimals: 18, + buy_decimals: 6, + }, + TestCase { + name: "Base: 0.1 WETH → USDC", + chain_id: ChainId::Base, + sell_token: address!("0x4200000000000000000000000000000000000006"), + buy_token: address!("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"), + sell_amount: 100_000_000_000_000_000, + sell_decimals: 18, + buy_decimals: 6, + }, + TestCase { + name: "Arbitrum: 0.1 WETH → USDC", + chain_id: ChainId::ArbitrumOne, + sell_token: address!("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), + buy_token: address!("0xaf88d065e77c8cC2239327C5EDb3A432268e5831"), + sell_amount: 100_000_000_000_000_000, + sell_decimals: 18, + buy_decimals: 6, + }, + TestCase { + name: "BNB: 1 WBNB → USDC", + chain_id: ChainId::Bnb, + sell_token: address!("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), + buy_token: address!("0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"), + sell_amount: 1_000_000_000_000_000_000, + sell_decimals: 18, + buy_decimals: 18, + }, + TestCase { + name: "Polygon: 100 WPOL → USDC", + chain_id: ChainId::Polygon, + sell_token: address!("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"), + buy_token: address!("0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"), + sell_amount: 100_000_000_000_000_000_000, + sell_decimals: 18, + buy_decimals: 6, + }, +]; + +// To run this test, set the following environment variables accordingly to your +// Bitget setup: BITGET_API_KEY, BITGET_API_SECRET +#[ignore] +#[tokio::test] +async fn swap_sell_all_chains() { + let api_key = env::var("BITGET_API_KEY").unwrap(); + let api_secret = env::var("BITGET_API_SECRET").unwrap(); + let endpoint = reqwest::Url::parse(bitget_dex::DEFAULT_ENDPOINT).unwrap(); + + for tc in TEST_CASES { + let config = bitget_dex::Config { + endpoint: endpoint.clone(), + chain_id: tc.chain_id, + credentials: bitget_dex::BitgetCredentialsConfig { + api_key: api_key.clone(), + api_secret: api_secret.clone(), + }, + partner_code: "cowswap".to_string(), + settlement_contract: SETTLEMENT, + block_stream: None, + enable_buy_orders: false, + }; + + let order = Order { + sell: TokenAddress::from(tc.sell_token), + buy: TokenAddress::from(tc.buy_token), + side: crate::domain::order::Side::Sell, + amount: Amount::new(U256::from(tc.sell_amount)), + owner: address!("0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let mut token_map = HashMap::new(); + token_map.insert( + order.sell, + auction::Token { + decimals: Some(tc.sell_decimals), + symbol: None, + reference_price: None, + available_balance: U256::ZERO, + trusted: false, + }, + ); + token_map.insert( + order.buy, + auction::Token { + decimals: Some(tc.buy_decimals), + symbol: None, + reference_price: None, + available_balance: U256::ZERO, + trusted: false, + }, + ); + let tokens = auction::Tokens(token_map); + + let bitget = bitget_dex::Bitget::try_new(config).unwrap(); + let swap = bitget + .swap(&order, &slippage, &tokens) + .await + .unwrap_or_else(|e| panic!("[{}] swap failed: {e}", tc.name)); + + assert_eq!( + swap.input.token, + order.amount().token, + "[{}] input token mismatch", + tc.name + ); + assert_eq!( + swap.input.amount, + order.amount().amount, + "[{}] input amount mismatch", + tc.name + ); + assert_eq!( + swap.output.token, order.buy, + "[{}] output token mismatch", + tc.name + ); + + tokio::time::sleep(RATE_LIMIT_PAUSE).await; + } +} + +// To run this test, set the following environment variables accordingly to your +// Bitget setup: BITGET_API_KEY, BITGET_API_SECRET +#[ignore] +#[tokio::test] +async fn swap_buy_all_chains() { + let api_key = env::var("BITGET_API_KEY").unwrap(); + let api_secret = env::var("BITGET_API_SECRET").unwrap(); + let endpoint = reqwest::Url::parse(bitget_dex::DEFAULT_ENDPOINT).unwrap(); + + for tc in TEST_CASES { + let config = bitget_dex::Config { + endpoint: endpoint.clone(), + chain_id: tc.chain_id, + credentials: bitget_dex::BitgetCredentialsConfig { + api_key: api_key.clone(), + api_secret: api_secret.clone(), + }, + partner_code: "cowswap".to_string(), + settlement_contract: SETTLEMENT, + block_stream: None, + enable_buy_orders: true, + }; + + // Flip sell/buy so that we probe `buy_token = WETH` for a fixed amount, + // mirroring the native-price probe shape. + let buy_amount = tc.sell_amount; + let order = Order { + sell: TokenAddress::from(tc.buy_token), + buy: TokenAddress::from(tc.sell_token), + side: crate::domain::order::Side::Buy, + amount: Amount::new(U256::from(buy_amount)), + owner: address!("0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let mut token_map = HashMap::new(); + token_map.insert( + order.sell, + auction::Token { + decimals: Some(tc.buy_decimals), + symbol: None, + reference_price: None, + available_balance: U256::ZERO, + trusted: false, + }, + ); + token_map.insert( + order.buy, + auction::Token { + decimals: Some(tc.sell_decimals), + symbol: None, + reference_price: None, + available_balance: U256::ZERO, + trusted: false, + }, + ); + let tokens = auction::Tokens(token_map); + + let bitget = bitget_dex::Bitget::try_new(config).unwrap(); + let swap = bitget + .swap(&order, &slippage, &tokens) + .await + .unwrap_or_else(|e| panic!("[{}] swap failed: {e}", tc.name)); + + assert_eq!( + swap.input.token, order.sell, + "[{}] input token mismatch", + tc.name + ); + assert_eq!( + swap.output.token, order.buy, + "[{}] output token mismatch", + tc.name + ); + // Reverse-quote should produce a swap whose expected output meets or + // exceeds the requested buy amount. + assert!( + swap.output.amount >= order.amount().amount, + "[{}] expected output {} < requested {}", + tc.name, + swap.output.amount, + order.amount().amount + ); + + tokio::time::sleep(RATE_LIMIT_PAUSE).await; + } +} + +#[tokio::test] +async fn swap_buy_disabled() { + // With `enable_buy_orders` off (the default), buy orders must short-circuit + // to `OrderNotSupported` without touching the API. + let config = bitget_dex::Config { + endpoint: reqwest::Url::parse(bitget_dex::DEFAULT_ENDPOINT).unwrap(), + chain_id: crate::domain::eth::ChainId::Mainnet, + credentials: bitget_dex::BitgetCredentialsConfig { + api_key: String::new(), + api_secret: String::new(), + }, + partner_code: "cowswap".to_string(), + settlement_contract: address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + block_stream: None, + enable_buy_orders: false, + }; + + let order = Order { + buy: TokenAddress::from(address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), + sell: TokenAddress::from(address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + side: crate::domain::order::Side::Buy, + amount: Amount::new(U256::from(1000000000_u128)), + owner: address!("0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + let tokens = auction::Tokens(HashMap::new()); + + let bitget = bitget_dex::Bitget::try_new(config).unwrap(); + let swap_response = bitget.swap(&order, &slippage, &tokens).await; + assert!(matches!( + swap_response.unwrap_err(), + bitget_dex::Error::OrderNotSupported + )); +} diff --git a/crates/solvers/src/tests/bitget/market_order.rs b/crates/solvers/src/tests/bitget/market_order.rs new file mode 100644 index 0000000000..05a6053556 --- /dev/null +++ b/crates/solvers/src/tests/bitget/market_order.rs @@ -0,0 +1,382 @@ +//! This test ensures that the Bitget solver properly handles market sell +//! orders, turning Bitget swap responses into CoW Protocol solutions. + +use { + crate::tests::{self, mock}, + serde_json::json, +}; + +#[tokio::test] +async fn sell() { + let api = mock::http::setup(vec![ + mock::http::Expectation::Post { + path: mock::http::Path::exact("bgw-pro/swapx/pro/swap"), + req: mock::http::RequestBody::Partial( + json!({ + "fromContract": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "fromAmount": "1", + "fromChain": "eth", + "toContract": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "toChain": "eth", + "market": "bgwevmaggregator", + "slippage": 1.0, + "requestMod": "rich", + "feeRate": 0.0 + }), + vec!["fromAddress", "toAddress"], + ), + res: json!({ + "status": 0, + "data": { + "outAmount": "6556.259156432631386442", + "minAmount": "6490.696564868305072577", + "gasFee": { + "gasLimit": "202500" + }, + "swapTransaction": { + "to": "0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "data": "0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 0000000000000000000000000000000000000000000000000de0b6b3a7640000\ + 00000000000000000000000000000000000000000000015fdc8278903f7f31c1\ + 0000000000000000000000000000000000000000000000000000000000000080\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 00000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539" + } + } + }), + }, + ]) + .await; + + let engine = tests::SolverEngine::new("bitget", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!( + solution, + json!({ + "solutions":[ + { + "gas": 410141, + "id": 0, + "interactions":[ + { + "allowances":[ + { + "amount": "1000000000000000000", + "spender": "0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "token": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "callData": "0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "inputs":[ + { + "amount": "1000000000000000000", + "token": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "internalize": false, + "kind": "custom", + "outputs":[ + { + "amount": "6556259156432631386442", + "token": "0xe41d2489571d322189246dafa5ebde1f4699f498" + } + ], + "target": "0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "value": "0" + } + ], + "postInteractions": [], + "preInteractions": [], + "prices":{ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "6556259156432631386442", + "0xe41d2489571d322189246dafa5ebde1f4699f498": "1000000000000000000" + }, + "trades":[ + { + "executedAmount": "1000000000000000000", + "kind": "fulfillment", + "order": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + ] + } + ] + }), + ); +} + +#[tokio::test] +async fn buy() { + let api = mock::http::setup(vec![ + mock::http::Expectation::Post { + path: mock::http::Path::exact("bgw-pro/swapx/pro/swapr"), + req: mock::http::RequestBody::Partial( + json!({ + "fromContract": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "toContract": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "fromChain": "eth", + "amount": "200", + "requestMode": "minAmountOut", + "slippage": "1", + "feeRate": 0.0 + }), + vec!["fromAddress", "toAddress"], + ), + // Mock the reverse-quote response. `expectedAmountOut` is a small + // overshoot above the requested 200, simulating BitGet's recursion + // landing slightly above the target. We report the exact buy + // amount in the solution (CoW exact-out semantics) and the + // overshoot becomes positive surplus on chain. + res: json!({ + "status": 0, + "data": { + "amountIn": "0.99", + "expectedAmountOut": "200.5", + "minAmountOut": "200", + "priceImpact": "0", + "recommendSlippage": 0.5, + "expiresAt": 0, + "market": "bgwevmaggregator", + "txs": [ + { + "chainId": 1, + "to": "0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "calldata": "0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 0000000000000000000000000000000000000000000000000de0b6b3a7640000\ + 00000000000000000000000000000000000000000000015fdc8278903f7f31c1\ + 0000000000000000000000000000000000000000000000000000000000000080\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 00000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "function": "swap", + "gasLimit": "202500", + "gasPrice": "0", + "nonce": 0, + "value": "0" + } + ], + "fee": {} + } + }), + }, + ]) + .await; + + let engine = + tests::SolverEngine::new("bitget", super::config_with_buy_orders(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "buy", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!( + solution, + json!({ + "solutions":[ + { + "gas": 410141, + "id": 0, + "interactions":[ + { + "allowances":[ + { + "amount": "990000000000000000", + "spender": "0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "token": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "callData": "0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "inputs":[ + { + "amount": "990000000000000000", + "token": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "internalize": true, + "kind": "custom", + "outputs":[ + { + "amount": "200000000000000000000", + "token": "0xe41d2489571d322189246dafa5ebde1f4699f498" + } + ], + "target": "0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "value": "0" + } + ], + "postInteractions": [], + "preInteractions": [], + "prices":{ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "200000000000000000000", + "0xe41d2489571d322189246dafa5ebde1f4699f498": "990000000000000000" + }, + "trades":[ + { + "executedAmount": "200000000000000000000", + "kind": "fulfillment", + "order": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + ] + } + ] + }), + ); +} + +#[tokio::test] +async fn buy_disabled() { + // Default config has `enable-buy-orders` off, so the solver must not call + // either swap endpoint and must produce no solution for a buy order. + let api = mock::http::setup(vec![]).await; + + let engine = tests::SolverEngine::new("bitget", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "buy", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!(solution, json!({ "solutions": [] })); +} diff --git a/crates/solvers/src/tests/bitget/mod.rs b/crates/solvers/src/tests/bitget/mod.rs new file mode 100644 index 0000000000..96c8db9a37 --- /dev/null +++ b/crates/solvers/src/tests/bitget/mod.rs @@ -0,0 +1,38 @@ +use {crate::tests, std::net::SocketAddr}; + +mod api_calls; +mod market_order; +mod not_found; +mod out_of_price; + +/// Creates a temporary file containing the default config (buy orders +/// disabled). +pub fn config(solver_addr: &SocketAddr) -> tests::Config { + tests::Config::String(format!( + r" +node-url = 'http://localhost:8545' +[dex] +chain-id = '1' +endpoint = 'http://{solver_addr}/bgw-pro/swapx/pro/' +[dex.credentials] +api-key = 'test-api-key' +api-secret = 'test-api-secret-1234' +", + )) +} + +/// Creates a config with buy orders enabled via the reverse-quote endpoint. +pub fn config_with_buy_orders(solver_addr: &SocketAddr) -> tests::Config { + tests::Config::String(format!( + r" +node-url = 'http://localhost:8545' +[dex] +chain-id = '1' +endpoint = 'http://{solver_addr}/bgw-pro/swapx/pro/' +enable-buy-orders = true +[dex.credentials] +api-key = 'test-api-key' +api-secret = 'test-api-secret-1234' +", + )) +} diff --git a/crates/solvers/src/tests/bitget/not_found.rs b/crates/solvers/src/tests/bitget/not_found.rs new file mode 100644 index 0000000000..e99f5005b3 --- /dev/null +++ b/crates/solvers/src/tests/bitget/not_found.rs @@ -0,0 +1,80 @@ +//! This test ensures that the Bitget solver properly handles cases where no +//! swap was found for the specified order. + +use { + crate::tests::{self, mock}, + serde_json::json, +}; + +#[tokio::test] +async fn sell_no_liquidity() { + let api = mock::http::setup(vec![ + // Swap request returns an error status (insufficient liquidity). + mock::http::Expectation::Post { + path: mock::http::Path::exact("bgw-pro/swapx/pro/swap"), + req: mock::http::RequestBody::Any, + res: json!({ + "status": 1, + "error_code": 80005, + "message": "Insufficient liquidity; transaction cannot be completed at this time.", + "data": null + }), + }, + ]) + .await; + + let engine = tests::SolverEngine::new("bitget", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF": { + "decimals": 18, + "symbol": "TETH", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF", + "buyToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!(solution, json!({ "solutions": [] }),); +} diff --git a/crates/solvers/src/tests/bitget/out_of_price.rs b/crates/solvers/src/tests/bitget/out_of_price.rs new file mode 100644 index 0000000000..041149dfb0 --- /dev/null +++ b/crates/solvers/src/tests/bitget/out_of_price.rs @@ -0,0 +1,96 @@ +//! This test verifies that the Bitget solver does not generate solutions when +//! the swap returned from the API does not satisfy an order's limit price. +//! +//! The actual test case is a modified version of the [`super::market_order`] +//! test with an exuberant buy amount. + +use { + crate::tests::{self, mock}, + serde_json::json, +}; + +#[tokio::test] +async fn sell() { + let api = mock::http::setup(vec![ + mock::http::Expectation::Post { + path: mock::http::Path::exact("bgw-pro/swapx/pro/swap"), + req: mock::http::RequestBody::Any, + res: json!({ + "status": 0, + "data": { + "outAmount": "6556.259156432631386442", + "minAmount": "6490.696564868305072577", + "gasFee": { + "gasLimit": "202500" + }, + "swapTransaction": { + "to": "0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "data": "0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 0000000000000000000000000000000000000000000000000de0b6b3a7640000\ + 00000000000000000000000000000000000000000000015fdc8278903f7f31c1\ + 0000000000000000000000000000000000000000000000000000000000000080\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 00000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539" + } + } + }), + }, + ]) + .await; + + let engine = tests::SolverEngine::new("bitget", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + // Way too much... + "buyAmount": "1000000000000000000000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "1000000000000000000000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!(solution, json!({ "solutions": [] }),); +} diff --git a/crates/solvers/src/tests/mock/http.rs b/crates/solvers/src/tests/mock/http.rs new file mode 100644 index 0000000000..238afe9158 --- /dev/null +++ b/crates/solvers/src/tests/mock/http.rs @@ -0,0 +1,278 @@ +use { + std::{ + fmt::{self, Debug, Formatter}, + net::SocketAddr, + sync::{ + Arc, + Mutex, + atomic::{AtomicBool, Ordering}, + }, + }, + testlib::assert_json_matches_excluding, + tokio::task::JoinHandle, +}; + +#[derive(Clone)] +pub enum Path { + Any, + Exact(String), + Glob(glob::Pattern), +} + +impl Path { + pub fn exact(s: impl ToString) -> Self { + Self::Exact(s.to_string()) + } + + #[allow(dead_code)] + pub fn glob(s: impl AsRef) -> Self { + Self::Glob(glob::Pattern::new(s.as_ref()).unwrap()) + } +} + +impl PartialEq for String { + fn eq(&self, path: &Path) -> bool { + match path { + Path::Any => true, + Path::Exact(exact) => exact == self, + Path::Glob(glob) => glob.matches(self), + } + } +} + +impl Debug for Path { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Path::Any => f.debug_tuple("Any").finish(), + Path::Exact(exact) => f + .debug_tuple("Exact") + .field(&format_args!("{exact}")) + .finish(), + Path::Glob(glob) => f + .debug_tuple("Glob") + .field(&format_args!("{}", glob.as_str())) + .finish(), + } + } +} + +#[derive(Clone, Debug)] +pub enum Expectation { + Get { + path: Path, + res: serde_json::Value, + }, + #[allow(dead_code)] + Post { + path: Path, + req: RequestBody, + res: serde_json::Value, + }, +} + +#[derive(Clone, Debug)] +pub enum RequestBody { + /// The received `[RequestBody]` has to match the provided value exactly. + #[allow(dead_code)] + Exact(serde_json::Value), + /// The received `[RequestBody]` has to match the provided value partially + /// excluding the specified paths which are represented as dot-separated + /// strings. + #[allow(dead_code)] + Partial(serde_json::Value, Vec<&'static str>), + /// Any `[RequestBody]` will be accepted. + #[allow(dead_code)] + Any, +} + +/// Drop handle that will verify that the server task didn't panic throughout +/// the test and that all the expectations have been met. +pub struct ServerHandle { + /// The address that handles requests to this server. + pub address: SocketAddr, + /// Handle to shut down the server task on drop. + handle: JoinHandle<()>, + /// Expectations that are left over after the test. + expectations: Arc>>, + /// Indicates if some assertion failed. + assert_failed: Arc, +} + +impl Drop for ServerHandle { + fn drop(&mut self) { + // Don't cause mass hysteria! + if std::thread::panicking() { + return; + } + + let server_panicked = self.assert_failed.load(std::sync::atomic::Ordering::SeqCst); + // Panics happening in the server task might not cause the test to fail + // and only show up if some assertion fails in the main task. + assert!(!server_panicked); + + assert!( + !self.handle.is_finished(), + "mock http server terminated before test ended" + ); + assert_eq!( + self.expectations.lock().unwrap().len(), + 0, + "mock server did not receive enough requests" + ); + self.handle.abort(); + } +} + +/// Set up a mock external HTTP API. +pub async fn setup(mut expectations: Vec) -> ServerHandle { + // Reverse expectations so test can specify them in natural order while + // allowing us to simply `.pop()` the last element. + expectations.reverse(); + + let expectations = Arc::new(Mutex::new(expectations)); + let failed_assert = Arc::new(AtomicBool::new(false)); + + let app = axum::Router::new() + .route( + "/{*path}", + axum::routing::get( + |axum::extract::State(state), + axum::extract::Path(path): axum::extract::Path, + axum::extract::RawQuery(query)| async move { + axum::response::Json(get(state, Some(path), query)) + }, + ) + .post( + |axum::extract::State(state), + axum::extract::Path(path): axum::extract::Path, + axum::extract::RawQuery(query), + axum::extract::Json(req)| async move { + axum::response::Json(post(state, Some(path), query, req)) + }, + ), + ) + // Annoying, but `axum` doesn't seem to match `/` with the above route, + // so explicitly mount `/`. + .route( + "/", + axum::routing::get( + |axum::extract::State(state), axum::extract::RawQuery(query)| async move { + axum::response::Json(get(state, None, query)) + }, + ) + .post( + |axum::extract::State(state), + axum::extract::RawQuery(query), + axum::extract::Json(req)| async move { + axum::response::Json(post(state, None, query, req)) + }, + ), + ) + .with_state(State { + expectations: expectations.clone(), + failed_assert: failed_assert.clone(), + }); + + let listener = tokio::net::TcpListener::bind("0.0.0.0:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let handle = tokio::spawn(async move { + axum::serve(listener, app).await.unwrap(); + }); + + ServerHandle { + handle, + expectations, + address, + assert_failed: failed_assert, + } +} + +#[derive(Clone)] +struct State { + /// Endpoint handler reads from here which request to expect and what to + /// respond. + expectations: Arc>>, + /// Request handler notifies test about failed assert via this mutex. + failed_assert: Arc, +} + +/// Runs the given closure and updates a flag if it panics. +fn assert_and_propagate_panics(assertions: F, flag: &AtomicBool) -> R +where + F: FnOnce() -> R + std::panic::UnwindSafe + 'static, +{ + std::panic::catch_unwind(assertions) + .map_err(|_| { + flag.store(true, Ordering::SeqCst); + }) + .expect("ignore this panic; it was caused by the previous panic") +} + +fn get(state: State, path: Option, query: Option) -> serde_json::Value { + let expectation = state.expectations.lock().unwrap().pop(); + let assertions = || { + let (expected_path, res) = match expectation { + Some(Expectation::Get { path, res }) => (path, res), + Some(other) => panic!("expected GET request but got {other:?}"), + None => panic!("got another GET request, but didn't expect any more"), + }; + + let full_path = full_path(path, query); + assert_eq!(full_path, expected_path, "GET request has unexpected path"); + res + }; + assert_and_propagate_panics(assertions, &state.failed_assert) +} + +fn post( + state: State, + path: Option, + query: Option, + req: serde_json::Value, +) -> serde_json::Value { + let expectation = state.expectations.lock().unwrap().pop(); + + let assertions = move || { + let (expected_path, expected_req, mut res) = match expectation { + Some(Expectation::Post { path, req, res }) => (path, req, res), + Some(other) => panic!("expected POST request but got {other:?}"), + None => panic!("got another POST request, but didn't expect any more"), + }; + + let full_path = full_path(path, query); + assert_eq!(full_path, expected_path, "POST request has unexpected path"); + match expected_req { + RequestBody::Exact(value) => { + assert_eq!(req, value, "POST request has unexpected body") + } + RequestBody::Partial(value, exclude_paths) => { + let exclude_paths = exclude_paths + .iter() + .map(AsRef::as_ref) + .collect::>(); + assert_json_matches_excluding!(req, value, &exclude_paths) + } + RequestBody::Any => (), + } + + // If this is a JSON-RPC request, echo the request ID back in the + // response + if let Some(req_id) = req.get("id") + && let Some(res_obj) = res.as_object_mut() + { + res_obj.insert("id".to_string(), req_id.clone()); + } + + res + }; + + assert_and_propagate_panics(assertions, &state.failed_assert) +} + +fn full_path(path: Option, query: Option) -> String { + let path = path.unwrap_or_default(); + match query { + Some(query) => format!("{path}?{query}"), + None => path, + } +} diff --git a/crates/solvers/src/tests/mock/mod.rs b/crates/solvers/src/tests/mock/mod.rs new file mode 100644 index 0000000000..3883215fcb --- /dev/null +++ b/crates/solvers/src/tests/mock/mod.rs @@ -0,0 +1 @@ +pub mod http; diff --git a/crates/solvers/src/tests/mod.rs b/crates/solvers/src/tests/mod.rs index fcf64af0e0..4fbf32c519 100644 --- a/crates/solvers/src/tests/mod.rs +++ b/crates/solvers/src/tests/mod.rs @@ -10,7 +10,10 @@ use { tokio::{sync::oneshot, task::JoinHandle}, }; +mod bitget; mod cases; +mod mock; +mod okx; /// A solver engine handle for E2E testing. pub struct SolverEngine { diff --git a/crates/solvers/src/tests/okx/api_calls.rs b/crates/solvers/src/tests/okx/api_calls.rs new file mode 100644 index 0000000000..b522f36fd4 --- /dev/null +++ b/crates/solvers/src/tests/okx/api_calls.rs @@ -0,0 +1,262 @@ +use { + crate::{ + domain::{dex::*, eth::*}, + infra::dex::okx as okx_dex, + }, + alloy::primitives::address, + std::env, +}; + +const DEFAULT_BUY_ORDERS_ENDPOINT: &str = "https://web3.okx.com/api/v5/dex/aggregator/"; + +#[ignore] +#[tokio::test] +// To run this test, set the following environment variables accordingly to your +// OKX setup: OKX_PROJECT_ID, OKX_API_KEY, OKX_SECRET_KEY, OKX_PASSPHRASE +async fn swap_sell_regular() { + let okx_config = okx_dex::Config { + sell_orders_endpoint: reqwest::Url::parse(okx_dex::DEFAULT_SELL_ORDERS_ENDPOINT).unwrap(), + buy_orders_endpoint: None, + sell_orders_signature_base_url: None, + buy_orders_signature_base_url: None, + chain_id: crate::domain::eth::ChainId::Mainnet, + okx_credentials: okx_dex::OkxCredentialsConfig { + project_id: env::var("OKX_PROJECT_ID").unwrap(), + api_key: env::var("OKX_API_KEY").unwrap(), + api_secret_key: env::var("OKX_SECRET_KEY").unwrap(), + api_passphrase: env::var("OKX_PASSPHRASE").unwrap(), + }, + settlement_contract: address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + block_stream: None, + price_impact_protection_percent: 1.0, + }; + + let order = Order { + sell: TokenAddress::from(address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), + buy: TokenAddress::from(address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + side: crate::domain::order::Side::Sell, + amount: Amount::new(U256::from(100000000000000000_u128)), + owner: address!("0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let okx = crate::infra::dex::okx::Okx::try_new(okx_config).unwrap(); + let swap_response = okx.swap(&order, &slippage).await; + let swap = swap_response.unwrap(); + + assert_eq!(swap.input.token, order.amount().token); + assert_eq!(swap.input.amount, order.amount().amount); + assert_eq!(swap.output.token, order.buy); + assert_eq!( + swap.allowance.spender, + address!("0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f") + ); +} + +#[tokio::test] +async fn swap_buy_disabled() { + let okx_config = okx_dex::Config { + sell_orders_endpoint: reqwest::Url::parse(okx_dex::DEFAULT_SELL_ORDERS_ENDPOINT).unwrap(), + buy_orders_endpoint: None, + sell_orders_signature_base_url: None, + buy_orders_signature_base_url: None, + chain_id: crate::domain::eth::ChainId::Mainnet, + okx_credentials: okx_dex::OkxCredentialsConfig { + project_id: String::new(), + api_key: String::new(), + api_secret_key: String::new(), + api_passphrase: String::new(), + }, + settlement_contract: address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + block_stream: None, + price_impact_protection_percent: 1.0, + }; + + let order = Order { + buy: TokenAddress::from(address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), + sell: TokenAddress::from(address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + side: crate::domain::order::Side::Buy, + amount: Amount::new(U256::from(1000000000_u128)), + owner: address!("0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let okx = crate::infra::dex::okx::Okx::try_new(okx_config).unwrap(); + let swap_response = okx.swap(&order, &slippage).await; + assert!(matches!( + swap_response.unwrap_err(), + crate::infra::dex::okx::Error::OrderNotSupported + )); +} + +#[ignore] +#[tokio::test] +// To run this test, set the following environment variables accordingly to your +// OKX setup: OKX_PROJECT_ID, OKX_API_KEY, OKX_SECRET_KEY, OKX_PASSPHRASE +async fn swap_buy_enabled() { + let okx_config = okx_dex::Config { + sell_orders_endpoint: reqwest::Url::parse(okx_dex::DEFAULT_SELL_ORDERS_ENDPOINT).unwrap(), + buy_orders_endpoint: Some(reqwest::Url::parse(DEFAULT_BUY_ORDERS_ENDPOINT).unwrap()), + sell_orders_signature_base_url: None, + buy_orders_signature_base_url: None, + chain_id: crate::domain::eth::ChainId::Mainnet, + okx_credentials: okx_dex::OkxCredentialsConfig { + project_id: env::var("OKX_PROJECT_ID").unwrap(), + api_key: env::var("OKX_API_KEY").unwrap(), + api_secret_key: env::var("OKX_SECRET_KEY").unwrap(), + api_passphrase: env::var("OKX_PASSPHRASE").unwrap(), + }, + settlement_contract: address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + block_stream: None, + price_impact_protection_percent: 1.0, + }; + + let order = Order { + sell: TokenAddress::from(address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")), + buy: TokenAddress::from(address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + side: crate::domain::order::Side::Buy, + amount: Amount::new(U256::from(1000000000_u128)), + owner: address!("0x6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let okx = crate::infra::dex::okx::Okx::try_new(okx_config).unwrap(); + let swap_response = okx.swap(&order, &slippage).await; + let swap = swap_response.unwrap(); + + assert_eq!(swap.output.token, order.amount().token); + assert_eq!(swap.output.amount, order.amount().amount); + assert_eq!(swap.input.token, order.sell); + assert_eq!( + swap.allowance.spender, + address!("0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f") + ); + // For buy orders, allowance should be U256::MAX + assert_eq!(swap.allowance.amount.get(), U256::MAX); +} + +#[ignore] +#[tokio::test] +// To run this test, set the following environment variables accordingly to your +// OKX setup: OKX_PROJECT_ID, OKX_API_KEY, OKX_SECRET_KEY, OKX_PASSPHRASE +async fn swap_api_error() { + let okx_config = okx_dex::Config { + sell_orders_endpoint: reqwest::Url::parse(okx_dex::DEFAULT_SELL_ORDERS_ENDPOINT).unwrap(), + buy_orders_endpoint: None, + sell_orders_signature_base_url: None, + buy_orders_signature_base_url: None, + chain_id: crate::domain::eth::ChainId::Mainnet, + okx_credentials: okx_dex::OkxCredentialsConfig { + project_id: env::var("OKX_PROJECT_ID").unwrap(), + api_key: env::var("OKX_API_KEY").unwrap(), + api_secret_key: env::var("OKX_SECRET_KEY").unwrap(), + api_passphrase: env::var("OKX_PASSPHRASE").unwrap(), + }, + settlement_contract: address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + block_stream: None, + price_impact_protection_percent: 1.0, + }; + + let order = Order { + sell: TokenAddress::from(address!("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")), + buy: TokenAddress::from(address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + side: crate::domain::order::Side::Sell, + amount: Amount::new(U256::ZERO), + owner: address!("6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let okx = crate::infra::dex::okx::Okx::try_new(okx_config).unwrap(); + let swap_response = okx.swap(&order, &slippage).await; + + assert!(matches!( + swap_response.unwrap_err(), + crate::infra::dex::okx::Error::Api { .. } + )); +} + +#[ignore] +#[tokio::test] +// To run this test, set the following environment variables accordingly to your +// OKX setup: OKX_PROJECT_ID, OKX_API_KEY, OKX_SECRET_KEY, OKX_PASSPHRASE +async fn swap_sell_insufficient_liquidity() { + let okx_config = okx_dex::Config { + sell_orders_endpoint: reqwest::Url::parse(okx_dex::DEFAULT_SELL_ORDERS_ENDPOINT).unwrap(), + buy_orders_endpoint: None, + sell_orders_signature_base_url: None, + buy_orders_signature_base_url: None, + chain_id: crate::domain::eth::ChainId::Mainnet, + okx_credentials: okx_dex::OkxCredentialsConfig { + project_id: env::var("OKX_PROJECT_ID").unwrap(), + api_key: env::var("OKX_API_KEY").unwrap(), + api_secret_key: env::var("OKX_SECRET_KEY").unwrap(), + api_passphrase: env::var("OKX_PASSPHRASE").unwrap(), + }, + settlement_contract: address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + block_stream: None, + price_impact_protection_percent: 1.0, + }; + + let order = Order { + sell: TokenAddress::from(address!("0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF")), + buy: TokenAddress::from(address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + side: crate::domain::order::Side::Sell, + amount: Amount::new(U256::from(10000000000000_u128)), + owner: address!("6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let okx = crate::infra::dex::okx::Okx::try_new(okx_config).unwrap(); + let swap_response = okx.swap(&order, &slippage).await; + + assert!(matches!( + swap_response.unwrap_err(), + crate::infra::dex::okx::Error::NotFound + )); +} + +#[ignore] +#[tokio::test] +// To run this test, set the following environment variables accordingly to your +// OKX setup: OKX_PROJECT_ID, OKX_API_KEY, OKX_SECRET_KEY, OKX_PASSPHRASE +async fn swap_buy_insufficient_liquidity() { + let okx_config = okx_dex::Config { + sell_orders_endpoint: reqwest::Url::parse(okx_dex::DEFAULT_SELL_ORDERS_ENDPOINT).unwrap(), + buy_orders_endpoint: Some(reqwest::Url::parse(DEFAULT_BUY_ORDERS_ENDPOINT).unwrap()), + sell_orders_signature_base_url: None, + buy_orders_signature_base_url: None, + chain_id: crate::domain::eth::ChainId::Mainnet, + okx_credentials: okx_dex::OkxCredentialsConfig { + project_id: env::var("OKX_PROJECT_ID").unwrap(), + api_key: env::var("OKX_API_KEY").unwrap(), + api_secret_key: env::var("OKX_SECRET_KEY").unwrap(), + api_passphrase: env::var("OKX_PASSPHRASE").unwrap(), + }, + settlement_contract: address!("0x9008d19f58aabd9ed0d60971565aa8510560ab41"), + block_stream: None, + price_impact_protection_percent: 1.0, + }; + + let order = Order { + sell: TokenAddress::from(address!("0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF")), + buy: TokenAddress::from(address!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")), + side: crate::domain::order::Side::Buy, + amount: Amount::new(U256::from(10000000000000_u128)), + owner: address!("6f9ffea7370310cd0f890dfde5e0e061059dcfb8"), + }; + + let slippage = Slippage::one_percent(); + + let okx = crate::infra::dex::okx::Okx::try_new(okx_config).unwrap(); + let swap_response = okx.swap(&order, &slippage).await; + + assert!(matches!( + swap_response.unwrap_err(), + crate::infra::dex::okx::Error::NotFound + )); +} diff --git a/crates/solvers/src/tests/okx/market_order.rs b/crates/solvers/src/tests/okx/market_order.rs new file mode 100644 index 0000000000..50ab660f1b --- /dev/null +++ b/crates/solvers/src/tests/okx/market_order.rs @@ -0,0 +1,1067 @@ +//! This test ensures that the OKX solver properly handles market sell +//! orders, turning OKX swap responses into CoW Protocol solutions. + +use { + crate::tests::{self, mock}, + serde_json::json, +}; + +#[tokio::test] +async fn sell() { + let api = mock::http::setup(vec![ + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "swap?chainIndex=1\ + &amount=1000000000000000000\ + &fromTokenAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &toTokenAddress=0xe41d2489571d322189246dafa5ebde1f4699f498\ + &slippagePercent=0.01\ + &userWalletAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapReceiverAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapMode=exactIn\ + &priceImpactProtectionPercent=1" + ), + res: json!( + { + "code":"0", + "data":[ + { + "routerResult":{ + "chainId":"1", + "dexRouterList":[ + { + "router":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2--0xe41d2489571d322189246dafa5ebde1f4699f498", + "routerPercent":"100", + "subRouterList":[ + { + "dexProtocol":[ + { + "dexName":"Uniswap V3", + "percent":"100" + } + ], + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + } + } + ] + } + ], + "estimateGasFee":"135000", + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "fromTokenAmount":"1000000000000000000", + "priceImpactPercentage":"-0.25", + "quoteCompareList":[ + { + "amountOut":"6556.259156432631386442", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V3", + "tradeFee":"2.3554356342513966" + }, + { + "amountOut":"6375.198002761542738881", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V2", + "tradeFee":"3.34995290204643072" + }, + { + "amountOut":"4456.799978982369793812", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V1", + "tradeFee":"4.64638467513839940864" + }, + { + "amountOut":"2771.072269036022134969", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/SUSHI.png", + "dexName":"SushiSwap", + "tradeFee":"3.34995290204643072" + } + ], + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + }, + "toTokenAmount":"6556259156432631386442", + "tradeFee":"2.3554356342513966" + }, + "tx":{ + "data":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "from":"0x9008d19f58aabd9ed0d60971565aa8510560ab41", + "gas":"202500", + "gasPrice":"6756286873", + "maxPriorityFeePerGas":"1000000000", + "minReceiveAmount":"6490696564868305072578", + "signatureData":[ + "" + ], + "slippage":"0.01", + "to":"0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "value":"0" + } + } + ], + "msg":"" + }), + }, + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "approve-transaction?chainIndex=1\ + &tokenContractAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &approveAmount=1000000000000000000" + ), + res: json!( + { + "code":"0", + "data":[{"data":"0x095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7f000000000000000000000000000000000000000000000000000009184e72a000","dexContractAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f","gasLimit":"70000","gasPrice":"7424402761"}], + "msg":"" + } + ) + }, + ]) + .await; + + let engine = tests::SolverEngine::new("okx", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!( + solution, + json!({ + "solutions":[ + { + "gas":410141, + "id":0, + "interactions":[ + { + "allowances":[ + { + "amount":"1000000000000000000", + "spender":"0x40aa958dd87fc8305b97f2ba922cddca374bcd7f", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "callData":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "inputs":[ + { + "amount":"1000000000000000000", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "internalize":false, + "kind":"custom", + "outputs":[ + { + "amount":"6556259156432631386442", + "token":"0xe41d2489571d322189246dafa5ebde1f4699f498" + } + ], + "target":"0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "value":"0" + } + ], + "postInteractions":[], + "preInteractions":[], + "prices":{ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2":"6556259156432631386442", + "0xe41d2489571d322189246dafa5ebde1f4699f498":"1000000000000000000" + }, + "trades":[ + { + "executedAmount":"1000000000000000000", + "kind":"fulfillment", + "order":"0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + ] + } + ] + }), + ); +} + +#[tokio::test] +async fn buy_disabled() { + let api = mock::http::setup(vec![]).await; + + let engine = tests::SolverEngine::new("okx", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "buy", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + // Buy order is not supported when enable-buy-orders is false (default). + assert_eq!(solution, json!({ "solutions": [] }),); +} + +#[tokio::test] +async fn buy_enabled() { + /// Config with buy orders enabled. + fn config_with_buy_orders(solver_addr: &std::net::SocketAddr) -> tests::Config { + tests::Config::String(format!( + r" +node-url = 'http://localhost:8545' +[dex] +chain-id = '1' +sell-orders-endpoint = 'http://{solver_addr}/' +buy-orders-endpoint = 'http://{solver_addr}/' +api-project-id = '1' +api-key = '1234' +api-secret-key = '1234567890123456' +api-passphrase = 'pass' +", + )) + } + + let api = mock::http::setup(vec![ + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "swap?chainId=1\ + &amount=200000000000000000000\ + &fromTokenAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &toTokenAddress=0xe41d2489571d322189246dafa5ebde1f4699f498\ + &slippage=0.01\ + &userWalletAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapReceiverAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapMode=exactOut\ + &priceImpactProtectionPercent=1" + ), + res: json!( + { + "code":"0", + "data":[ + { + "routerResult":{ + "chainId":"1", + "dexRouterList":[ + { + "router":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2--0xe41d2489571d322189246dafa5ebde1f4699f498", + "routerPercent":"100", + "subRouterList":[ + { + "dexProtocol":[ + { + "dexName":"Uniswap V3", + "percent":"100" + } + ], + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + } + } + ] + } + ], + "estimateGasFee":"135000", + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "fromTokenAmount":"30500000000000000", + "priceImpactPercentage":"-0.25", + "quoteCompareList":[ + { + "amountOut":"200000000000000000000", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V3", + "tradeFee":"2.3554356342513966" + } + ], + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + }, + "toTokenAmount":"200000000000000000000", + "tradeFee":"2.3554356342513966" + }, + "tx":{ + "data":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "from":"0x9008d19f58aabd9ed0d60971565aa8510560ab41", + "gas":"202500", + "gasPrice":"6756286873", + "maxPriorityFeePerGas":"1000000000", + "minReceiveAmount":"6490696564868305072578", + "signatureData":[ + "" + ], + "slippage":"0.01", + "to":"0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "value":"0" + } + } + ], + "msg":"" + }), + }, + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "approve-transaction?chainId=1\ + &tokenContractAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &approveAmount=30500000000000000" + ), + res: json!( + { + "code":"0", + "data":[{"data":"0x095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7f000000000000000000000000000000000000000000000000000009184e72a000","dexContractAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f","gasLimit":"70000","gasPrice":"7424402761"}], + "msg":"" + } + ) + }, + ]) + .await; + + let engine = tests::SolverEngine::new("okx", config_with_buy_orders(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "buy", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!( + solution, + json!({ + "solutions":[ + { + "gas":410141, + "id":0, + "interactions":[ + { + "allowances":[ + { + "amount":"115792089237316195423570985008687907853269984665640564039457584007913129639935", + "spender":"0x40aa958dd87fc8305b97f2ba922cddca374bcd7f", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "callData":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "inputs":[ + { + "amount":"30500000000000000", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "internalize":true, + "kind":"custom", + "outputs":[ + { + "amount":"200000000000000000000", + "token":"0xe41d2489571d322189246dafa5ebde1f4699f498" + } + ], + "target":"0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "value":"0" + } + ], + "postInteractions":[], + "preInteractions":[], + "prices":{ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2":"200000000000000000000", + "0xe41d2489571d322189246dafa5ebde1f4699f498":"30500000000000000" + }, + "trades":[ + { + "executedAmount":"200000000000000000000", + "kind":"fulfillment", + "order":"0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + ] + } + ] + }), + ); +} + +#[tokio::test] +async fn sell_twice() { + let mut http_requests = vec![ + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "swap?chainIndex=1&amount=1000000000000000000&\ + fromTokenAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&\ + toTokenAddress=0xe41d2489571d322189246dafa5ebde1f4699f498&slippagePercent=0.01&\ + userWalletAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41&\ + swapReceiverAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41&swapMode=exactIn&\ + priceImpactProtectionPercent=1", + ), + res: json!( + { + "code":"0", + "data":[ + { + "routerResult":{ + "chainId":"1", + "dexRouterList":[ + { + "router":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2--0xe41d2489571d322189246dafa5ebde1f4699f498", + "routerPercent":"100", + "subRouterList":[ + { + "dexProtocol":[ + { + "dexName":"Uniswap V3", + "percent":"100" + } + ], + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + } + } + ] + } + ], + "estimateGasFee":"135000", + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "fromTokenAmount":"1000000000000000000", + "priceImpactPercentage":"-0.25", + "quoteCompareList":[ + { + "amountOut":"6556.259156432631386442", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V3", + "tradeFee":"2.3554356342513966" + }, + { + "amountOut":"6375.198002761542738881", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V2", + "tradeFee":"3.34995290204643072" + }, + { + "amountOut":"4456.799978982369793812", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V1", + "tradeFee":"4.64638467513839940864" + }, + { + "amountOut":"2771.072269036022134969", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/SUSHI.png", + "dexName":"SushiSwap", + "tradeFee":"3.34995290204643072" + } + ], + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + }, + "toTokenAmount":"6556259156432631386442", + "tradeFee":"2.3554356342513966" + }, + "tx":{ + "data":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "from":"0x9008d19f58aabd9ed0d60971565aa8510560ab41", + "gas":"202500", + "gasPrice":"6756286873", + "maxPriorityFeePerGas":"1000000000", + "minReceiveAmount":"6490696564868305072578", + "signatureData":[ + "" + ], + "slippage":"0.01", + "to":"0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "value":"0" + } + } + ], + "msg":"" + }), + }, + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "approve-transaction?chainIndex=1&\ + tokenContractAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&\ + approveAmount=1000000000000000000", + ), + res: json!( + { + "code":"0", + "data":[{"data":"0x095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7f000000000000000000000000000000000000000000000000000009184e72a000","dexContractAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f","gasLimit":"70000","gasPrice":"7424402761"}], + "msg":"" + } + ), + }, + ]; + + // Prepare response for the 2nd swap request, only /swap is expected, + // /approve-transaction should not be sent instead cache should be used. + http_requests.push(http_requests[0].clone()); + + let api = mock::http::setup(http_requests).await; + + let engine = tests::SolverEngine::new("okx", super::config(&api.address)).await; + + let auction = json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + }); + + let solution = engine.solve(auction.clone()).await; + + assert_eq!( + solution, + json!({ + "solutions":[ + { + "gas":410141, + "id":0, + "interactions":[ + { + "allowances":[ + { + "amount":"1000000000000000000", + "spender":"0x40aa958dd87fc8305b97f2ba922cddca374bcd7f", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "callData":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "inputs":[ + { + "amount":"1000000000000000000", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "internalize":false, + "kind":"custom", + "outputs":[ + { + "amount":"6556259156432631386442", + "token":"0xe41d2489571d322189246dafa5ebde1f4699f498" + } + ], + "target":"0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "value":"0" + } + ], + "postInteractions":[], + "preInteractions":[], + "prices":{ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2":"6556259156432631386442", + "0xe41d2489571d322189246dafa5ebde1f4699f498":"1000000000000000000" + }, + "trades":[ + { + "executedAmount":"1000000000000000000", + "kind":"fulfillment", + "order":"0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + ] + } + ] + }), + ); + + // Make a second call to ensure cache is used (no http request is sent). + let solution = engine.solve(auction).await; + + let solutions_array = solution.as_object().unwrap().get("solutions").unwrap(); + + assert_eq!(solutions_array.as_array().unwrap().len(), 1); +} + +#[tokio::test] +async fn sell_twice_parallel() { + let mut http_requests = vec![ + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "swap?chainIndex=1&amount=1000000000000000000&\ + fromTokenAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&\ + toTokenAddress=0xe41d2489571d322189246dafa5ebde1f4699f498&slippagePercent=0.01&\ + userWalletAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41&\ + swapReceiverAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41&swapMode=exactIn&\ + priceImpactProtectionPercent=1", + ), + res: json!( + { + "code":"0", + "data":[ + { + "routerResult":{ + "chainId":"1", + "dexRouterList":[ + { + "router":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2--0xe41d2489571d322189246dafa5ebde1f4699f498", + "routerPercent":"100", + "subRouterList":[ + { + "dexProtocol":[ + { + "dexName":"Uniswap V3", + "percent":"100" + } + ], + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + } + } + ] + } + ], + "estimateGasFee":"135000", + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "fromTokenAmount":"1000000000000000000", + "priceImpactPercentage":"-0.25", + "quoteCompareList":[ + { + "amountOut":"6556.259156432631386442", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V3", + "tradeFee":"2.3554356342513966" + }, + { + "amountOut":"6375.198002761542738881", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V2", + "tradeFee":"3.34995290204643072" + }, + { + "amountOut":"4456.799978982369793812", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V1", + "tradeFee":"4.64638467513839940864" + }, + { + "amountOut":"2771.072269036022134969", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/SUSHI.png", + "dexName":"SushiSwap", + "tradeFee":"3.34995290204643072" + } + ], + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + }, + "toTokenAmount":"6556259156432631386442", + "tradeFee":"2.3554356342513966" + }, + "tx":{ + "data":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "from":"0x9008d19f58aabd9ed0d60971565aa8510560ab41", + "gas":"202500", + "gasPrice":"6756286873", + "maxPriorityFeePerGas":"1000000000", + "minReceiveAmount":"6490696564868305072578", + "signatureData":[ + "" + ], + "slippage":"0.01", + "to":"0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "value":"0" + } + } + ], + "msg":"" + }), + }, + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "approve-transaction?chainIndex=1&\ + tokenContractAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&\ + approveAmount=1000000000000000000", + ), + res: json!( + { + "code":"0", + "data":[{"data":"0x095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7f000000000000000000000000000000000000000000000000000009184e72a000","dexContractAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f","gasLimit":"70000","gasPrice":"7424402761"}], + "msg":"" + } + ), + }, + ]; + + // Prepare response for the 2nd swap request, only /swap is expected, + // /approve-transaction should not be sent instead cache should be used. + http_requests.push(http_requests[0].clone()); + + let api = mock::http::setup(http_requests).await; + + let engine = tests::SolverEngine::new("okx", super::config(&api.address)).await; + + let auction = json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + }); + + // Making two auction solve calls in parallel + // - 1st solve call will invoke okx /swap and /approve-transaction requests + // - 2nd solve call will also invoke okx /swap but should not invoke + // /approve-transaction instead it should wait for the 1st execution to finish + // (due to use of moka concurrent calls on the same key feature) + let (solution1, solution2) = tokio::join!(engine.solve(auction.clone()), engine.solve(auction)); + + assert_eq!( + solution1, + json!({ + "solutions":[ + { + "gas":410141, + "id":0, + "interactions":[ + { + "allowances":[ + { + "amount":"1000000000000000000", + "spender":"0x40aa958dd87fc8305b97f2ba922cddca374bcd7f", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "callData":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "inputs":[ + { + "amount":"1000000000000000000", + "token":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + ], + "internalize":false, + "kind":"custom", + "outputs":[ + { + "amount":"6556259156432631386442", + "token":"0xe41d2489571d322189246dafa5ebde1f4699f498" + } + ], + "target":"0x7d0ccaa3fac1e5a943c5168b6ced828691b46b36", + "value":"0" + } + ], + "postInteractions":[], + "preInteractions":[], + "prices":{ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2":"6556259156432631386442", + "0xe41d2489571d322189246dafa5ebde1f4699f498":"1000000000000000000" + }, + "trades":[ + { + "executedAmount":"1000000000000000000", + "kind":"fulfillment", + "order":"0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + ] + } + ] + }), + ); + + let solutions_array = solution2.as_object().unwrap().get("solutions").unwrap(); + + assert_eq!(solutions_array.as_array().unwrap().len(), 1); +} diff --git a/crates/solvers/src/tests/okx/mod.rs b/crates/solvers/src/tests/okx/mod.rs new file mode 100644 index 0000000000..e132d7ee5c --- /dev/null +++ b/crates/solvers/src/tests/okx/mod.rs @@ -0,0 +1,22 @@ +use {crate::tests, std::net::SocketAddr}; + +mod api_calls; +mod market_order; +mod not_found; +mod out_of_price; + +/// Creates a temporary file containing the config of the given solver. +pub fn config(solver_addr: &SocketAddr) -> tests::Config { + tests::Config::String(format!( + r" +node-url = 'http://localhost:8545' +[dex] +chain-id = '1' +sell-orders-endpoint = 'http://{solver_addr}/' +api-project-id = '1' +api-key = '1234' +api-secret-key = '1234567890123456' +api-passphrase = 'pass' +", + )) +} diff --git a/crates/solvers/src/tests/okx/not_found.rs b/crates/solvers/src/tests/okx/not_found.rs new file mode 100644 index 0000000000..ffe11f6607 --- /dev/null +++ b/crates/solvers/src/tests/okx/not_found.rs @@ -0,0 +1,287 @@ +//! This test ensures that the OKX solver properly handles cases where no swap +//! was found for the specified order. + +use { + crate::tests::{self, mock}, + serde_json::json, +}; + +#[tokio::test] +async fn sell() { + let api = mock::http::setup(vec![mock::http::Expectation::Get { + path: mock::http::Path::exact( + "swap?chainIndex=1&amount=1000000000000000000&\ + fromTokenAddress=0xc8cd2be653759aed7b0996315821aae71e1feadf&\ + toTokenAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&slippagePercent=0.01&\ + userWalletAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41&\ + swapReceiverAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41&\ + swapMode=exactIn&priceImpactProtectionPercent=1", + ), + res: json!({"code":"82000","data":[],"msg":"Insufficient liquidity."}), + }, + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "approve-transaction?chainIndex=1\ + &tokenContractAddress=0xc8cd2be653759aed7b0996315821aae71e1feadf\ + &approveAmount=1000000000000000000" + ), + res: json!( + { + "code":"0", + "data":[{"data":"0x095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7f000000000000000000000000000000000000000000000000000009184e72a000","dexContractAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f","gasLimit":"70000","gasPrice":"7424402761"}], + "msg":"" + } + ) + } + ]) + .await; + + let engine = tests::SolverEngine::new("okx", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF": { + "decimals": 18, + "symbol": "TETH", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC8CD2BE653759aed7B0996315821AAe71e1FEAdF", + "buyToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!(solution, json!({ "solutions": [] }),); +} + +#[tokio::test] +async fn sell_no_approve_transaction() { + let api = mock::http::setup(vec![ + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "swap?chainIndex=1\ + &amount=1000000000000000000\ + &fromTokenAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &toTokenAddress=0xe41d2489571d322189246dafa5ebde1f4699f498\ + &slippagePercent=0.01\ + &userWalletAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapReceiverAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapMode=exactIn\ + &priceImpactProtectionPercent=1" + ), + res: json!( + { + "code":"0", + "data":[ + { + "routerResult":{ + "chainId":"1", + "dexRouterList":[ + { + "router":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2--0xe41d2489571d322189246dafa5ebde1f4699f498", + "routerPercent":"100", + "subRouterList":[ + { + "dexProtocol":[ + { + "dexName":"Uniswap V3", + "percent":"100" + } + ], + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + } + } + ] + } + ], + "estimateGasFee":"135000", + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "fromTokenAmount":"1000000000000000000", + "priceImpactPercentage":"-0.25", + "quoteCompareList":[ + { + "amountOut":"6556.259156432631386442", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V3", + "tradeFee":"2.3554356342513966" + }, + { + "amountOut":"6375.198002761542738881", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V2", + "tradeFee":"3.34995290204643072" + }, + { + "amountOut":"4456.799978982369793812", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V1", + "tradeFee":"4.64638467513839940864" + }, + { + "amountOut":"2771.072269036022134969", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/SUSHI.png", + "dexName":"SushiSwap", + "tradeFee":"3.34995290204643072" + } + ], + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + }, + "toTokenAmount":"6556259156432631386442", + "tradeFee":"2.3554356342513966" + }, + "tx":{ + "data":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "from":"0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a", + "gas":"202500", + "gasPrice":"6756286873", + "maxPriorityFeePerGas":"1000000000", + "minReceiveAmount":"6490696564868305072578", + "signatureData":[ + "" + ], + "slippage":"0.01", + "to":"0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "value":"0" + } + } + ], + "msg":"" + }), + }, + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "approve-transaction?chainIndex=1\ + &tokenContractAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &approveAmount=1000000000000000000" + ), + res: json!( + { + "code":"50011", + "data":[], + "msg":"Rate limit reached" + } + ) + }, + ]) + .await; + + let engine = tests::SolverEngine::new("okx", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + "buyAmount": "200000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "200000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!(solution, json!({ "solutions": [] }),); +} diff --git a/crates/solvers/src/tests/okx/out_of_price.rs b/crates/solvers/src/tests/okx/out_of_price.rs new file mode 100644 index 0000000000..9ec12a33c1 --- /dev/null +++ b/crates/solvers/src/tests/okx/out_of_price.rs @@ -0,0 +1,205 @@ +//! This test verifies that the OKX solver does not generate solutions when +//! the swap returned from the API does not satisfy an order's limit price. +//! +//! The actual test case is a modified version of the [`super::market_order`] +//! test with an exuberant buy amount. + +use { + crate::tests::{self, mock}, + serde_json::json, +}; + +#[tokio::test] +async fn sell() { + let api = mock::http::setup(vec![ + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "swap?chainIndex=1\ + &amount=1000000000000000000\ + &fromTokenAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &toTokenAddress=0xe41d2489571d322189246dafa5ebde1f4699f498\ + &slippagePercent=0.01\ + &userWalletAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapReceiverAddress=0x9008d19f58aabd9ed0d60971565aa8510560ab41\ + &swapMode=exactIn\ + &priceImpactProtectionPercent=1" + ), + res: json!( + { + "code":"0", + "data":[ + { + "routerResult":{ + "chainId":"1", + "dexRouterList":[ + { + "router":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2--0xe41d2489571d322189246dafa5ebde1f4699f498", + "routerPercent":"100", + "subRouterList":[ + { + "dexProtocol":[ + { + "dexName":"Uniswap V3", + "percent":"100" + } + ], + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + } + } + ] + } + ], + "estimateGasFee":"135000", + "fromToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "tokenSymbol":"WETH", + "tokenUnitPrice":"3315.553196726842565048" + }, + "fromTokenAmount":"1000000000000000000", + "priceImpactPercentage":"-0.25", + "quoteCompareList":[ + { + "amountOut":"6556.259156432631386442", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V3", + "tradeFee":"2.3554356342513966" + }, + { + "amountOut":"6375.198002761542738881", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V2", + "tradeFee":"3.34995290204643072" + }, + { + "amountOut":"4456.799978982369793812", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/UNI.png", + "dexName":"Uniswap V1", + "tradeFee":"4.64638467513839940864" + }, + { + "amountOut":"2771.072269036022134969", + "dexLogo":"https://static.okx.com/cdn/wallet/logo/SUSHI.png", + "dexName":"SushiSwap", + "tradeFee":"3.34995290204643072" + } + ], + "toToken":{ + "decimal":"18", + "isHoneyPot":false, + "taxRate":"0", + "tokenContractAddress":"0xe41d2489571d322189246dafa5ebde1f4699f498", + "tokenSymbol":"ZRX", + "tokenUnitPrice":"0.504455838152300152" + }, + "toTokenAmount":"6556259156432631386442", + "tradeFee":"2.3554356342513966" + }, + "tx":{ + "data":"0x0d5f0e3b00000000000000000001a0cf2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000015fdc8278903f7f31c10000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000014424eeecbff345b38187d0b8b749e56faa68539", + "from":"0x9008d19f58aabd9ed0d60971565aa8510560ab41", + "gas":"202500", + "gasPrice":"6756286873", + "maxPriorityFeePerGas":"1000000000", + "minReceiveAmount":"6490696564868305072578", + "signatureData":[ + "" + ], + "slippage":"0.01", + "to":"0x7D0CcAa3Fac1e5A943c5168b6CEd828691b46B36", + "value":"0" + } + } + ], + "msg":"" + }), + }, + mock::http::Expectation::Get { + path: mock::http::Path::exact( + "approve-transaction?chainIndex=1\ + &tokenContractAddress=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\ + &approveAmount=1000000000000000000" + ), + res: json!( + { + "code":"0", + "data":[{"data":"0x095ea7b300000000000000000000000040aa958dd87fc8305b97f2ba922cddca374bcd7f000000000000000000000000000000000000000000000000000009184e72a000","dexContractAddress":"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f","gasLimit":"70000","gasPrice":"7424402761"}], + "msg":"" + } + ) + }, + ]) + .await; + + let engine = tests::SolverEngine::new("okx", super::config(&api.address)).await; + + let solution = engine + .solve(json!({ + "id": "1", + "tokens": { + "0xe41d2489571d322189246dafa5ebde1f4699f498": { + "decimals": 18, + "symbol": "ZRX", + "referencePrice": "4327903683155778", + "availableBalance": "1583034704488033979459", + "trusted": true, + }, + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { + "decimals": 18, + "symbol": "WETH", + "referencePrice": "1000000000000000000", + "availableBalance": "482725140468789680", + "trusted": true, + }, + }, + "orders": [ + { + "uid": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a\ + 2a2a2a2a", + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "sellAmount": "1000000000000000000", + // Way too much... + "buyAmount": "1000000000000000000000000000000000000", + "fullSellAmount": "1000000000000000000", + "fullBuyAmount": "1000000000000000000000000000000000000", + "kind": "sell", + "partiallyFillable": false, + "class": "market", + "sellTokenSource": "erc20", + "buyTokenDestination": "erc20", + "preInteractions": [], + "postInteractions": [], + "owner": "0x5b1e2c2762667331bc91648052f646d1b0d35984", + "validTo": 0, + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signingScheme": "presign", + "signature": "0x", + } + ], + "liquidity": [], + "effectiveGasPrice": "15000000000", + "deadline": "2106-01-01T00:00:00.000Z", + "surplusCapturingJitOrderOwners": [] + })) + .await; + + assert_eq!(solution, json!({ "solutions": [] }),); +} diff --git a/crates/solvers/src/util/bytes.rs b/crates/solvers/src/util/bytes.rs deleted file mode 100644 index b6e52c8a07..0000000000 --- a/crates/solvers/src/util/bytes.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// A thin wrapper around a collection of bytes. Provides hex debug formatting. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] -pub struct Bytes(pub T); - -impl std::fmt::Debug for Bytes -where - T: AsRef<[u8]>, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", const_hex::encode_prefixed(&self.0)) - } -} diff --git a/crates/solvers/src/util/conv.rs b/crates/solvers/src/util/conv.rs index a7d1bdb6b4..dba3233a90 100644 --- a/crates/solvers/src/util/conv.rs +++ b/crates/solvers/src/util/conv.rs @@ -1,50 +1,22 @@ -//! Conversion utilities. +//! Conversion utilities for `eth::Ether` and `eth::Rational`. use { crate::domain::eth, bigdecimal::BigDecimal, - ethereum_types::U256, - num::{BigInt, BigUint, One, rational::Ratio}, + num::{BigInt, One}, + number::conversions::{big_decimal_to_big_rational, big_int_to_u256, u256_to_big_uint}, }; /// Converts a `BigDecimal` value to a `eth::Rational` value. Returns `None` if /// the specified decimal value cannot be represented as a rational of `U256` /// integers. pub fn decimal_to_rational(d: &BigDecimal) -> Option { - let (int, exp) = d.as_bigint_and_exponent(); - - // First convert to a `Ratio`. This ensures that the ratio is - // normalized (i.e. GCD of numerator and denomninator is 1) before trying to - // convert the components to `U256`s. This allows values like `1.00...000` - // that would otherwise overflow a `U256` numerator. - let uint = int.to_biguint()?; - let factor = BigUint::from(10_u8).pow(exp.unsigned_abs().try_into().ok()?); - let ratio = if exp >= 0 { - Ratio::new(uint, factor) - } else { - Ratio::new(uint * factor, num::one()) - }; - - let numer = biguint_to_u256(ratio.numer())?; - let denom = biguint_to_u256(ratio.denom())?; - + let ratio = big_decimal_to_big_rational(d); + let numer = big_int_to_u256(ratio.numer()).ok()?; + let denom = big_int_to_u256(ratio.denom()).ok()?; Some(eth::Rational::new_raw(numer, denom)) } -pub fn biguint_to_u256(i: &BigUint) -> Option { - let bytes = i.to_bytes_be(); - if bytes.len() > 32 { - return None; - } - Some(U256::from_big_endian(&bytes)) -} - -pub fn u256_to_biguint(i: &U256) -> BigUint { - let mut bytes = [0_u8; 32]; - i.to_big_endian(&mut bytes); - BigUint::from_bytes_be(&bytes) -} - /// Converts a `BigDecimal` amount in Ether units to wei. pub fn decimal_to_ether(d: &BigDecimal) -> Option { let scaled = d * BigDecimal::new(BigInt::one(), -18); @@ -54,12 +26,12 @@ pub fn decimal_to_ether(d: &BigDecimal) -> Option { /// Converts an `eth::Ether` amount into a `BigDecimal` representation. pub fn ether_to_decimal(e: ð::Ether) -> BigDecimal { - BigDecimal::new(u256_to_biguint(&e.0).into(), 18) + BigDecimal::new(u256_to_big_uint(&e.0).into(), 18) } #[cfg(test)] mod tests { - use super::*; + use {super::*, alloy::primitives::U256}; #[test] fn decimal_to_rational_conversions() { @@ -74,8 +46,8 @@ mod tests { ("0.003", 3, 1000), ] { let result = decimal_to_rational(&value.parse().unwrap()).unwrap(); - assert_eq!(result.numer().as_u64(), numer); - assert_eq!(result.denom().as_u64(), denom); + assert_eq!(u64::try_from(result.numer()).unwrap(), numer); + assert_eq!(u64::try_from(result.denom()).unwrap(), denom); } } @@ -102,7 +74,7 @@ mod tests { ("10", 10_000_000_000_000_000_000), ] { let decimal = decimal.parse().unwrap(); - let ether = eth::Ether(ether.into()); + let ether = eth::Ether(U256::from(ether)); assert_eq!(decimal_to_ether(&decimal).unwrap(), ether); assert_eq!(ether_to_decimal(ðer), decimal); diff --git a/crates/solvers/src/util/fmt/hex.rs b/crates/solvers/src/util/fmt/hex.rs deleted file mode 100644 index 7d63c34b2b..0000000000 --- a/crates/solvers/src/util/fmt/hex.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::fmt::{self, Debug, Display, Formatter}; - -pub struct Hex<'a>(pub &'a [u8]); - -impl Debug for Hex<'_> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl Display for Hex<'_> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str(&const_hex::encode_prefixed(self.0)) - } -} diff --git a/crates/solvers/src/util/fmt/mod.rs b/crates/solvers/src/util/fmt/mod.rs deleted file mode 100644 index 876b089b6e..0000000000 --- a/crates/solvers/src/util/fmt/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod hex; - -pub use self::hex::Hex; diff --git a/crates/solvers/src/util/http.rs b/crates/solvers/src/util/http.rs new file mode 100644 index 0000000000..e214d7c738 --- /dev/null +++ b/crates/solvers/src/util/http.rs @@ -0,0 +1,152 @@ +//! Module containing utilities for round-tripping HTTP requests. +//! +//! Note that this helper is implemented as a macro. This is needed in order to +//! ensure that we preserve the module path in the log event from the original +//! callsite instead of all HTTP requests appearing as they are made from this +//! module. + +use { + reqwest::{Method, RequestBuilder, StatusCode, Url}, + serde::de::DeserializeOwned, + std::str, +}; + +/// Roundtrip an HTTP request. This will `TRACE` log the request and responses. +/// +/// This is a thin macro wrapper around [`roundtrip_internal`] that ensures that +/// logs are attributed from the callsite and not from this module. This allows +/// log filtering to be done in a more fine-grained manner and based on where +/// the HTTP roundtripping is happening. +macro_rules! roundtrip { + (<$t:ty, $e:ty>; $request:expr) => { + $crate::util::http::roundtrip_internal::<$t, $e>( + $request, + |method, url, body, message| { + if let Some(body) = body { + tracing::trace!(%method, %url, %body, "{message}"); + } else { + tracing::trace!(%method, %url, "{message}"); + } + }, + |status, body, message| { + tracing::trace!(%status, %body, "{message}"); + }, + ) + }; + ($request:expr) => { + $crate::util::http::roundtrip!(<_, _>; $request) + }; +} + +pub(crate) use roundtrip; + +#[doc(hidden)] +pub async fn roundtrip_internal( + mut request: RequestBuilder, + log_request: impl FnOnce(&Method, &Url, Option<&str>, &str), + log_response: impl FnOnce(StatusCode, &str, &str), +) -> Result> +where + T: DeserializeOwned, + E: DeserializeOwned, +{ + if let Some(id) = observe::request_id::from_current_span() { + request = request.header("X-REQUEST-ID", id); + } + let (client, request) = request.build_split(); + let request = request.map_err(Error::from)?; + + let body = request + .body() + .and_then(|body| str::from_utf8(body.as_bytes()?).ok()); + + log_request( + request.method(), + request.url(), + body, + "sending HTTP request", + ); + let response = client.execute(request).await.map_err(Error::from)?; + + let status = response.status(); + let body = response.text().await.map_err(Error::from)?; + log_response(status, &body, "received HTTP response"); + + match serde_json::from_str::(&body) { + Ok(data) => Ok(data), + // We failed to parse the body into the expected data, try to get an + // as accurate error as possible: + // 1. If the API returned a well-formed error that we can parse, then use that + // 2. Otherwise, if it returned a 2xx status code, then this means that we are unable to + // parse a successful response, so return a JSON error + // 3. Otherwise, return an HTTP status error with the raw body string. + Err(err) => Err(serde_json::from_str(&body) + .map(RoundtripError::Api) + .unwrap_or_else(|_| { + RoundtripError::Http(if status.is_success() { + Error::Json(err) + } else { + Error::Status(status, body) + }) + })), + } +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// An error occurred when parsing the JSON body from the HTTP response + /// into the expected result type. + #[error(transparent)] + Json(#[from] serde_json::Error), + /// A general HTTP error when sending a request or receiving a response. + /// + /// This is a protocol-level error, and can indicate a networking issue or + /// a misbehaving HTTP server. + #[error(transparent)] + Http(#[from] reqwest::Error), + /// An error indicating that the HTTP response contained a non-200 status + /// code indicating an application-level error. + #[error("HTTP {0}: {1}")] + Status(StatusCode, String), +} + +impl From> for Error { + fn from(value: RoundtripError) -> Self { + let RoundtripError::Http(err) = value else { + unreachable!(); + }; + err + } +} + +#[derive(Debug, thiserror::Error)] +pub enum RoundtripError { + #[error(transparent)] + Http(#[from] Error), + #[error("API error")] + Api(E), +} + +/// A type that never deserializes or serializes. +/// +/// This can be used in situations where a generic type that implements `serde` +/// traits is required, but you don't want it to actually represent any data. +pub struct Never; + +impl<'de> serde::Deserialize<'de> for Never { + fn deserialize(_: D) -> Result + where + D: serde::Deserializer<'de>, + { + Err(serde::de::Error::custom("neva eva eva")) + } +} + +impl serde::Serialize for Never { + fn serialize(&self, _: S) -> Result + where + S: serde::Serializer, + { + Err(serde::ser::Error::custom("neva eva eva")) + } +} diff --git a/crates/solvers/src/util/math.rs b/crates/solvers/src/util/math.rs deleted file mode 100644 index 96018c1e5f..0000000000 --- a/crates/solvers/src/util/math.rs +++ /dev/null @@ -1,20 +0,0 @@ -use ethereum_types::U256; - -/// Perform a ceiled U256 integer division. -/// -/// Returns `None` when dividing by `0`. -pub fn div_ceil(q: U256, d: U256) -> Option { - if d.is_zero() { - return None; - } - - let (r, rem) = q.div_mod(d); - if rem.is_zero() { - Some(r) - } else { - Some( - r.checked_add(U256::one()) - .expect("unexpected ceiled division overflow"), - ) - } -} diff --git a/crates/solvers/src/util/mod.rs b/crates/solvers/src/util/mod.rs index ce85e8add0..5a8b2816e3 100644 --- a/crates/solvers/src/util/mod.rs +++ b/crates/solvers/src/util/mod.rs @@ -1,5 +1,2 @@ -pub mod bytes; pub mod conv; -pub mod fmt; -pub mod math; -pub mod serialize; +pub mod http; diff --git a/crates/solvers/src/util/serialize/mod.rs b/crates/solvers/src/util/serialize/mod.rs deleted file mode 100644 index fdfefaeb6a..0000000000 --- a/crates/solvers/src/util/serialize/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod u256; - -pub use self::u256::U256; diff --git a/crates/solvers/src/util/serialize/u256.rs b/crates/solvers/src/util/serialize/u256.rs deleted file mode 100644 index ca196171a1..0000000000 --- a/crates/solvers/src/util/serialize/u256.rs +++ /dev/null @@ -1,19 +0,0 @@ -use { - serde::{Deserialize, Deserializer, de}, - serde_with::DeserializeAs, - std::borrow::Cow, -}; - -/// Serialize and deserialize [`ethereum_types::U256`] as a decimal string. -#[derive(Debug)] -pub struct U256; - -impl<'de> DeserializeAs<'de, ethereum_types::U256> for U256 { - fn deserialize_as>( - deserializer: D, - ) -> Result { - let s = Cow::::deserialize(deserializer)?; - ethereum_types::U256::from_dec_str(&s) - .map_err(|err| de::Error::custom(format!("failed to parse {s:?} as a U256: {err}"))) - } -} diff --git a/crates/solvers/src/util/url.rs b/crates/solvers/src/util/url.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/subsolver/Cargo.toml b/crates/subsolver/Cargo.toml new file mode 100644 index 0000000000..c81c685f89 --- /dev/null +++ b/crates/subsolver/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "subsolver" +version = "0.1.0" +edition = "2024" + +[[bin]] +name = "subsolver" +path = "src/main.rs" + +[dependencies] +alloy-primitives = { workspace = true } +alloy-signer = { workspace = true } +alloy-signer-local = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true } +byos = { workspace = true } +chain = { workspace = true } +chrono = { workspace = true, default-features = false } +clap = { workspace = true, features = ["derive", "env"] } +const-hex = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +humantime = { workspace = true } +model = { workspace = true } +number = { workspace = true } +observe = { workspace = true } +reqwest = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +serde-ext = { workspace = true } +serde_with = { workspace = true } +shared = { workspace = true } +solvers = { workspace = true } +solvers-dto = { workspace = true } +tikv-jemallocator = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "time"] } +toml = { workspace = true } +tracing = { workspace = true } +url = { workspace = true } + +[build-dependencies] +anyhow = { workspace = true } +vergen = { workspace = true, features = ["git", "gitcl"] } + +[lints] +workspace = true diff --git a/crates/subsolver/build.rs b/crates/subsolver/build.rs new file mode 100644 index 0000000000..4d2899eaf0 --- /dev/null +++ b/crates/subsolver/build.rs @@ -0,0 +1,5 @@ +fn main() { + if let Err(err) = vergen::EmitBuilder::builder().git_sha(true).emit() { + eprintln!("WARN: vergen failed: {err:?}"); + } +} diff --git a/crates/subsolver/config/example.toml b/crates/subsolver/config/example.toml new file mode 100644 index 0000000000..99ca5f36a1 --- /dev/null +++ b/crates/subsolver/config/example.toml @@ -0,0 +1,18 @@ +chain-id = 1 +orderbook-url = "https://api.cow.fi/mainnet" +byos-url = "http://127.0.0.1:7872" +node-url = "https://eth-mainnet.example.com" +poll-interval = "5s" +# Private key for signing proposals (hex with 0x prefix) +private-key = "0x0000000000000000000000000000000000000000000000000000000000000001" + +[solver] +base-tokens = [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", # WETH +] +max-hops = 1 +max-partial-attempts = 1 +native-token-price-estimation-amount = "100000000000000000" + +[uniswap-v2] +router = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" diff --git a/crates/subsolver/src/client.rs b/crates/subsolver/src/client.rs new file mode 100644 index 0000000000..c8f15b2d50 --- /dev/null +++ b/crates/subsolver/src/client.rs @@ -0,0 +1,44 @@ +use {crate::proposal::SignedProposal, url::Url}; + +pub struct ByosClient { + http: reqwest::Client, + base_url: Url, +} + +impl ByosClient { + pub fn new(base_url: Url) -> Self { + Self { + http: reqwest::Client::builder() + .timeout(std::time::Duration::from_secs(10)) + .build() + .expect("failed to build HTTP client"), + base_url, + } + } + + pub async fn submit_proposal(&self, proposal: &SignedProposal) -> anyhow::Result { + let url = self.base_url.join("/proposals").expect("valid url join"); + + let body = serde_json::json!({ + "orderUid": format!("0x{}", const_hex::encode(proposal.order_uid)), + "sellAmount": proposal.sell_amount.to_string(), + "buyAmount": proposal.buy_amount.to_string(), + "interactions": proposal.interactions, + "validUntil": proposal.valid_until, + "nonce": proposal.nonce.to_string(), + "signature": format!("0x{}", const_hex::encode(proposal.signature)), + }); + + let response = self.http.post(url).json(&body).send().await?; + + if !response.status().is_success() { + let status = response.status(); + let text = response.text().await.unwrap_or_default(); + anyhow::bail!("BYOS rejected proposal: {status} {text}"); + } + + let result: serde_json::Value = response.json().await?; + let id = result["id"].as_u64().unwrap_or(0); + Ok(id) + } +} diff --git a/crates/subsolver/src/config.rs b/crates/subsolver/src/config.rs new file mode 100644 index 0000000000..47274c6a9a --- /dev/null +++ b/crates/subsolver/src/config.rs @@ -0,0 +1,55 @@ +use {alloy_primitives::Address, serde::Deserialize, std::path::Path, tokio::fs, url::Url}; + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Config { + pub chain_id: u64, + pub orderbook_url: Url, + pub byos_url: Url, + pub node_url: Url, + #[serde(with = "humantime")] + pub poll_interval: std::time::Duration, + pub private_key: String, + pub solver: SolverConfig, + pub uniswap_v2: UniswapV2Config, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct SolverConfig { + pub base_tokens: Vec
, + pub max_hops: usize, + #[serde(default = "default_max_partial_attempts")] + pub max_partial_attempts: usize, + pub native_token_price_estimation_amount: alloy_primitives::U256, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct UniswapV2Config { + pub router: Address, +} + +pub async fn load(path: &Path) -> Config { + let data = fs::read_to_string(path) + .await + .unwrap_or_else(|e| panic!("I/O error while reading {path:?}: {e:?}")); + toml::de::from_str::(&data) + .unwrap_or_else(|e| panic!("invalid subsolver config {path:?}: {e:?}")) +} + +fn default_max_partial_attempts() -> usize { + 1 +} + +mod humantime { + use { + serde::{Deserialize, Deserializer}, + std::time::Duration, + }; + + pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result { + let s = String::deserialize(d)?; + humantime::parse_duration(&s).map_err(serde::de::Error::custom) + } +} diff --git a/crates/subsolver/src/liquidity.rs b/crates/subsolver/src/liquidity.rs new file mode 100644 index 0000000000..c4352dac79 --- /dev/null +++ b/crates/subsolver/src/liquidity.rs @@ -0,0 +1,62 @@ +use { + alloy_primitives::{Address, U256}, + solvers::domain::{eth, liquidity}, + std::collections::HashSet, +}; + +/// Converts a set of orders into the token pairs we need to fetch liquidity +/// for. +pub fn token_pairs_from_orders( + orders: &[crate::orderbook::Order], + base_tokens: &[Address], +) -> HashSet<(Address, Address)> { + let mut pairs = HashSet::new(); + for order in orders { + // Direct pair + pairs.insert(ordered_pair(order.sell_token, order.buy_token)); + + // Via base tokens (for multi-hop routing) + for &base in base_tokens { + if base != order.sell_token { + pairs.insert(ordered_pair(order.sell_token, base)); + } + if base != order.buy_token { + pairs.insert(ordered_pair(order.buy_token, base)); + } + } + } + pairs +} + +fn ordered_pair(a: Address, b: Address) -> (Address, Address) { + if a < b { (a, b) } else { (b, a) } +} + +/// Creates a domain liquidity entry from a Uniswap V2 pool. +pub fn constant_product_liquidity( + pool_address: Address, + token_a: Address, + reserve_a: U256, + token_b: Address, + reserve_b: U256, +) -> Option { + let asset_a = eth::Asset { + token: eth::TokenAddress(token_a), + amount: reserve_a, + }; + let asset_b = eth::Asset { + token: eth::TokenAddress(token_b), + amount: reserve_b, + }; + let reserves = liquidity::constant_product::Reserves::new(asset_a, asset_b)?; + + Some(liquidity::Liquidity { + id: liquidity::Id(format!("{pool_address:?}")), + address: pool_address, + gas: eth::Gas(U256::from(90_171u64)), + state: liquidity::State::ConstantProduct(liquidity::constant_product::Pool { + reserves, + fee: eth::Rational::new_raw(U256::from(3), U256::from(1000)), + }), + }) +} diff --git a/crates/subsolver/src/main.rs b/crates/subsolver/src/main.rs new file mode 100644 index 0000000000..7351d65560 --- /dev/null +++ b/crates/subsolver/src/main.rs @@ -0,0 +1,15 @@ +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +mod client; +mod config; +mod liquidity; +mod orderbook; +mod proposal; +mod run; +mod solver; + +#[tokio::main] +async fn main() { + run::start().await; +} diff --git a/crates/subsolver/src/orderbook.rs b/crates/subsolver/src/orderbook.rs new file mode 100644 index 0000000000..bb0b5670d9 --- /dev/null +++ b/crates/subsolver/src/orderbook.rs @@ -0,0 +1,80 @@ +use { + alloy_primitives::{Address, U256}, + number::serialization::HexOrDecimalU256, + serde::Deserialize, + serde_with::serde_as, + std::collections::BTreeMap, + url::Url, +}; + +pub struct OrderbookClient { + http: reqwest::Client, + base_url: Url, +} + +impl OrderbookClient { + pub fn new(base_url: Url) -> Self { + Self { + http: reqwest::Client::builder() + .timeout(std::time::Duration::from_secs(10)) + .build() + .expect("failed to build HTTP client"), + base_url, + } + } + + pub async fn get_auction(&self) -> anyhow::Result { + let url = self + .base_url + .join("/api/v1/auction") + .expect("valid url join"); + let response = self.http.get(url).send().await?; + let body = response.error_for_status()?.json().await?; + Ok(body) + } +} + +#[serde_as] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AuctionResponse { + pub id: i64, + pub block: u64, + pub orders: Vec, + #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] + pub prices: BTreeMap, +} + +#[serde_as] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Order { + #[serde_as(as = "serde_ext::Hex")] + pub uid: Vec, + pub sell_token: Address, + pub buy_token: Address, + #[serde_as(as = "HexOrDecimalU256")] + pub sell_amount: U256, + #[serde_as(as = "HexOrDecimalU256")] + pub buy_amount: U256, + pub kind: OrderKind, + pub class: OrderClass, + #[serde(default)] + pub partially_fillable: bool, + pub valid_to: u32, +} + +#[derive(Debug, Deserialize, Clone, Copy)] +#[serde(rename_all = "camelCase")] +pub enum OrderKind { + Sell, + Buy, +} + +#[derive(Debug, Deserialize, Clone, Copy)] +#[serde(rename_all = "camelCase")] +pub enum OrderClass { + Market, + Limit, + Liquidity, +} diff --git a/crates/subsolver/src/proposal.rs b/crates/subsolver/src/proposal.rs new file mode 100644 index 0000000000..2a1244d384 --- /dev/null +++ b/crates/subsolver/src/proposal.rs @@ -0,0 +1,155 @@ +use { + alloy_primitives::{Address, U256}, + alloy_signer::SignerSync, + alloy_signer_local::PrivateKeySigner, + alloy_sol_types::{Eip712Domain, SolStruct, sol}, + byos::domain::{ + eip712::{self, ProposalData}, + proposal::Interaction, + }, + solvers::domain::solution, +}; + +sol! { + /// IUniswapV2Router02 swap interface. + #[allow(missing_docs)] + interface IUniswapV2Router { + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to, + uint256 deadline + ) external returns (uint256[] memory amounts); + + function swapTokensForExactTokens( + uint256 amountOut, + uint256 amountInMax, + address[] calldata path, + address to, + uint256 deadline + ) external returns (uint256[] memory amounts); + } +} + +pub struct ProposalBuilder { + signer: PrivateKeySigner, + domain: Eip712Domain, + router: Address, + settlement: Address, +} + +impl ProposalBuilder { + pub fn new( + signer: PrivateKeySigner, + domain: Eip712Domain, + router: Address, + settlement: Address, + ) -> Self { + Self { + signer, + domain, + router, + settlement, + } + } + + pub fn build_and_sign( + &self, + order_uid: &[u8; 56], + sol: &solution::Solution, + ) -> anyhow::Result { + // Extract sell/buy tokens and amounts from clearing prices. + // The solution has exactly one trade (single order solutions). + let trade = sol + .trades + .first() + .ok_or_else(|| anyhow::anyhow!("solution has no trades"))?; + let (sell_token, buy_token) = match trade { + solution::Trade::Fulfillment(f) => (f.order().sell.token, f.order().buy.token), + _ => anyhow::bail!("unexpected JIT trade"), + }; + + let sell_price = sol.prices.0.get(&sell_token).copied().unwrap_or(U256::ZERO); + let buy_price = sol.prices.0.get(&buy_token).copied().unwrap_or(U256::ZERO); + + // Encode liquidity interactions as Uniswap V2 router calls. + let interactions = self.encode_interactions(&sol.interactions)?; + + let valid_until = (chrono::Utc::now() + chrono::Duration::minutes(5)).timestamp() as u64; + let nonce = U256::from(chrono::Utc::now().timestamp_millis() as u64); + + let proposal_data = ProposalData { + orderUidHash: eip712::order_uid_hash(order_uid), + sellAmount: buy_price, // clearing prices are cross-multiplied + buyAmount: sell_price, + validUntil: U256::from(valid_until), + nonce, + }; + + let signing_hash = proposal_data.eip712_signing_hash(&self.domain); + let sig = self.signer.sign_hash_sync(&signing_hash)?; + let signature: [u8; 65] = sig.as_bytes(); + + Ok(SignedProposal { + order_uid: *order_uid, + sell_amount: buy_price, + buy_amount: sell_price, + interactions, + valid_until, + nonce, + signature, + }) + } + + fn encode_interactions( + &self, + interactions: &[solution::Interaction], + ) -> anyhow::Result> { + let mut encoded = Vec::new(); + let deadline = U256::from(u64::MAX); // far future + + for interaction in interactions { + match interaction { + solution::Interaction::Liquidity(liq) => { + let input = liq.input; + let output = liq.output; + + // Encode router call based on whether it's sell-side or buy-side + let calldata = IUniswapV2Router::swapExactTokensForTokensCall { + amountIn: input.amount, + amountOutMin: output.amount, + path: vec![input.token.0, output.token.0], + to: self.settlement, + deadline, + }; + + encoded.push(Interaction { + target: self.router, + value: U256::ZERO, + calldata: alloy_sol_types::SolCall::abi_encode(&calldata), + }); + } + solution::Interaction::Custom(custom) => { + encoded.push(Interaction { + target: custom.target, + value: custom.value.0, + calldata: custom.calldata.clone(), + }); + } + } + } + + Ok(encoded) + } +} + +pub struct SignedProposal { + pub order_uid: [u8; 56], + pub sell_amount: U256, + pub buy_amount: U256, + pub interactions: Vec, + pub valid_until: u64, + pub nonce: U256, + pub signature: [u8; 65], +} diff --git a/crates/subsolver/src/run.rs b/crates/subsolver/src/run.rs new file mode 100644 index 0000000000..ad5efd2740 --- /dev/null +++ b/crates/subsolver/src/run.rs @@ -0,0 +1,166 @@ +use { + crate::{ + client::ByosClient, + config, + liquidity, + orderbook::OrderbookClient, + proposal::ProposalBuilder, + solver::BaselineWrapper, + }, + alloy_signer_local::PrivateKeySigner, + byos::domain::eip712, + clap::Parser, + contracts::{GPv2Settlement, WETH9}, + shared::arguments::tracing_config, +}; + +#[derive(Parser, Debug)] +#[command(version)] +struct Args { + #[arg(long, env, default_value = "warn,subsolver=debug")] + log: String, + + #[clap(long, env, default_value = "false")] + use_json_logs: bool, + + #[clap(flatten)] + tracing: shared::arguments::TracingArguments, + + #[arg(long, env)] + config: std::path::PathBuf, +} + +pub async fn start() { + observe::panic_hook::install(); + let args = Args::parse(); + + let obs_config = observe::Config::new( + &args.log, + tracing::Level::ERROR.into(), + args.use_json_logs, + tracing_config(&args.tracing, "subsolver".into()), + ); + observe::tracing::init::initialize_reentrant(&obs_config); + + let commit_hash = option_env!("VERGEN_GIT_SHA").unwrap_or("COMMIT_INFO_NOT_FOUND"); + tracing::info!(%commit_hash, "running subsolver with {args:#?}"); + + let config = config::load(&args.config).await; + + let chain_id = config.chain_id; + let weth = WETH9::deployment_address(&chain_id) + .unwrap_or_else(|| panic!("no WETH address for chain {chain_id}")); + let settlement = GPv2Settlement::deployment_address(&chain_id) + .unwrap_or_else(|| panic!("no settlement address for chain {chain_id}")); + + let orderbook = OrderbookClient::new(config.orderbook_url.clone()); + let byos = ByosClient::new(config.byos_url.clone()); + let solver = BaselineWrapper::new(&config.solver, weth).await; + + let signer: PrivateKeySigner = config.private_key.parse().expect("invalid private key"); + let domain = eip712::byos_domain(chain_id); + let proposal_builder = + ProposalBuilder::new(signer.clone(), domain, config.uniswap_v2.router, settlement); + + tracing::info!( + %chain_id, + signer = %signer.address(), + router = %config.uniswap_v2.router, + "subsolver configured", + ); + + loop { + match run_iteration( + &orderbook, + &byos, + &solver, + &proposal_builder, + &config.solver.base_tokens, + ) + .await + { + Ok(count) => { + if count > 0 { + tracing::info!(proposals = count, "submitted proposals"); + } + } + Err(err) => { + tracing::warn!(?err, "iteration failed"); + } + } + + tokio::time::sleep(config.poll_interval).await; + } +} + +async fn run_iteration( + orderbook: &OrderbookClient, + byos: &ByosClient, + solver: &BaselineWrapper, + proposal_builder: &ProposalBuilder, + base_tokens: &[alloy_primitives::Address], +) -> anyhow::Result { + let auction = orderbook.get_auction().await?; + tracing::debug!( + auction_id = auction.id, + orders = auction.orders.len(), + "polled orderbook", + ); + + if auction.orders.is_empty() { + return Ok(0); + } + + // For now, we construct empty pools since the full pool fetching + // infrastructure requires an RPC connection and pool cache. + // TODO: integrate shared::sources::uniswap_v2::pool_fetching + let _token_pairs = liquidity::token_pairs_from_orders(&auction.orders, base_tokens); + + // Use a default gas price (30 gwei) + let gas_price = alloy_primitives::U256::from(30_000_000_000u64); + + let pools = vec![]; // TODO: fetch real pools + let solutions = solver + .solve(&auction.orders, &pools, gas_price, &auction.prices) + .await; + + tracing::debug!(solutions = solutions.len(), "baseline solver returned"); + + let mut submitted = 0; + for sol in &solutions { + let trade = match sol.trades.first() { + Some(solvers::domain::solution::Trade::Fulfillment(f)) => f, + _ => continue, + }; + let uid = trade.order().uid.0; + + match proposal_builder.build_and_sign(&uid, sol) { + Ok(proposal) => match byos.submit_proposal(&proposal).await { + Ok(id) => { + tracing::debug!( + %id, + order_uid = %const_hex::encode_prefixed(uid), + "proposal submitted", + ); + submitted += 1; + } + Err(err) => { + tracing::warn!( + ?err, + order_uid = %const_hex::encode_prefixed(uid), + "failed to submit proposal", + ); + } + }, + Err(err) => { + tracing::warn!( + ?err, + order_uid = %const_hex::encode_prefixed(uid), + "failed to build proposal", + ); + } + } + } + + Ok(submitted) +} diff --git a/crates/subsolver/src/solver.rs b/crates/subsolver/src/solver.rs new file mode 100644 index 0000000000..b020be8c1b --- /dev/null +++ b/crates/subsolver/src/solver.rs @@ -0,0 +1,98 @@ +use { + crate::{config::SolverConfig, orderbook}, + alloy_primitives::U256, + solvers::domain::{auction, eth, liquidity as domain_liquidity, order, solution, solver}, +}; + +pub struct BaselineWrapper { + solver: solver::Baseline, +} + +impl BaselineWrapper { + pub async fn new(config: &SolverConfig, weth: alloy_primitives::Address) -> Self { + let solver_config = solver::Config { + weth: eth::WethAddress(weth), + base_tokens: config + .base_tokens + .iter() + .map(|a| eth::TokenAddress(*a)) + .collect(), + max_hops: config.max_hops, + max_partial_attempts: config.max_partial_attempts, + solution_gas_offset: eth::SignedGas::default(), + native_token_price_estimation_amount: config.native_token_price_estimation_amount, + uni_v3_node_url: None, + }; + Self { + solver: solver::Baseline::new(solver_config).await, + } + } + + pub async fn solve( + &self, + orders: &[orderbook::Order], + pools: &[domain_liquidity::Liquidity], + gas_price: U256, + prices: &std::collections::BTreeMap, + ) -> Vec { + let domain_orders: Vec = orders + .iter() + .filter_map(|o| { + let uid: [u8; 56] = o.uid.clone().try_into().ok()?; + Some(order::Order { + uid: order::Uid(uid), + sell: eth::Asset { + token: eth::TokenAddress(o.sell_token), + amount: o.sell_amount, + }, + buy: eth::Asset { + token: eth::TokenAddress(o.buy_token), + amount: o.buy_amount, + }, + side: match o.kind { + orderbook::OrderKind::Buy => order::Side::Buy, + orderbook::OrderKind::Sell => order::Side::Sell, + }, + class: match o.class { + orderbook::OrderClass::Market => order::Class::Market, + orderbook::OrderClass::Limit | orderbook::OrderClass::Liquidity => { + order::Class::Limit + } + }, + partially_fillable: o.partially_fillable, + flashloan_hint: None, + wrappers: vec![], + }) + }) + .collect(); + + let tokens = auction::Tokens( + prices + .iter() + .map(|(addr, price)| { + ( + eth::TokenAddress(*addr), + auction::Token { + decimals: None, + symbol: None, + reference_price: Some(auction::Price(eth::Ether(*price))), + available_balance: U256::ZERO, + trusted: false, + }, + ) + }) + .collect(), + ); + + let auction = auction::Auction { + id: auction::Id::Solve(0), + tokens, + orders: domain_orders, + liquidity: pools.to_vec(), + gas_price: auction::GasPrice(eth::Ether(gas_price)), + deadline: auction::Deadline(chrono::Utc::now() + chrono::Duration::seconds(10)), + }; + + self.solver.solve(auction).await + } +} diff --git a/crates/testlib/Cargo.toml b/crates/testlib/Cargo.toml index 5125466088..a2d47fe248 100644 --- a/crates/testlib/Cargo.toml +++ b/crates/testlib/Cargo.toml @@ -6,11 +6,12 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] -alloy = {workspace = true} +alloy-primitives = { workspace = true } anyhow = { workspace = true } -hex-literal = { workspace = true } -maplit = { workspace = true } serde_json = { workspace = true } +[dev-dependencies] +maplit = { workspace = true } + [lints] workspace = true diff --git a/crates/testlib/src/protocol.rs b/crates/testlib/src/protocol.rs index 73b2f51cb1..75fc245fbb 100644 --- a/crates/testlib/src/protocol.rs +++ b/crates/testlib/src/protocol.rs @@ -1,6 +1,6 @@ //! Mainnet addresses of protocol contracts. -use alloy::primitives::{Address, address}; +use alloy_primitives::{Address, address}; /// Address for the settlement contract. pub const SETTLEMENT: Address = address!("9008D19f58AAbD9eD0D60971565AA8510560ab41"); diff --git a/crates/testlib/src/tokens.rs b/crates/testlib/src/tokens.rs index 51a5ed2410..a7a12e7f19 100644 --- a/crates/testlib/src/tokens.rs +++ b/crates/testlib/src/tokens.rs @@ -1,6 +1,6 @@ //! Mainnet addresses of commonly used tokens. -use alloy::primitives::{Address, address}; +use alloy_primitives::{Address, address}; /// Address for the `WETH` token. pub const WETH: Address = address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"); @@ -34,3 +34,12 @@ pub const MKR: Address = address!("9f8F72aA9304c8B593d555F12eF6589cC3A579A2"); /// Address for the `WBTC` token. pub const WBTC: Address = address!("2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"); + +/// Address for the `BNT` (Bancor Network Token) token. +pub const BNT: Address = address!("1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C"); + +/// Address for the `stETH` (Lido Staked ETH) token. +pub const STETH: Address = address!("ae7ab96520DE3A18E5e111B5EaAb095312D7fE84"); + +/// Address for the `sUSDe` (Ethena Staked USDe) token, an EIP-4626 vault. +pub const SUSDE: Address = address!("9D39A5DE30e57443BfF2A8307A4256c8797A3497"); diff --git a/crates/token-info/Cargo.toml b/crates/token-info/Cargo.toml new file mode 100644 index 0000000000..5d6205af45 --- /dev/null +++ b/crates/token-info/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "token-info" +version = "0.1.0" +authors = ["Cow Protocol Developers "] +edition = "2024" +license = "MIT OR Apache-2.0" + +[dependencies] +alloy-primitives = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +contracts = { workspace = true } +ethrpc = { workspace = true } +futures = { workspace = true } +mockall = { workspace = true, optional = true } +model = { workspace = true } +tracing = { workspace = true } + +[dev-dependencies] +maplit = { workspace = true } +mockall = { workspace = true } +tokio = { workspace = true } + +[features] +test-util = ["dep:mockall"] + +[lints] +workspace = true diff --git a/crates/token-info/LICENSE-APACHE b/crates/token-info/LICENSE-APACHE new file mode 120000 index 0000000000..6b579aae20 --- /dev/null +++ b/crates/token-info/LICENSE-APACHE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/crates/token-info/LICENSE-MIT b/crates/token-info/LICENSE-MIT new file mode 120000 index 0000000000..7f9a88ec80 --- /dev/null +++ b/crates/token-info/LICENSE-MIT @@ -0,0 +1 @@ +LICENSE-MIT \ No newline at end of file diff --git a/crates/shared/src/token_info.rs b/crates/token-info/src/lib.rs similarity index 64% rename from crates/shared/src/token_info.rs rename to crates/token-info/src/lib.rs index a47c389d37..1580424764 100644 --- a/crates/shared/src/token_info.rs +++ b/crates/token-info/src/lib.rs @@ -1,23 +1,21 @@ use { + alloy_primitives::Address, anyhow::Result, async_trait::async_trait, - contracts::alloy::ERC20, - ethcontract::H160, - ethrpc::{ - Web3, - alloy::{conversions::IntoAlloy, errors::ignore_non_node_error}, - }, + contracts::ERC20, + ethrpc::{Web3, alloy::errors::ignore_non_node_error}, futures::{ FutureExt, + StreamExt, future::{BoxFuture, Shared}, }, model::order::BUY_ETH_ADDRESS, std::{ - collections::HashMap, + collections::{HashMap, HashSet}, sync::{Arc, Mutex}, }, - thiserror::Error, }; +const TOKEN_INFO_FETCH_CONCURRENCY: usize = 32; #[cfg_attr(test, derive(Eq, PartialEq))] #[derive(Clone, Debug, Default)] @@ -26,20 +24,27 @@ pub struct TokenInfo { pub symbol: Option, } -#[derive(Clone, Debug, Error)] -#[error("error fetching token info: {0}")] +#[derive(Clone, Debug)] pub struct Error(String); +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "error fetching token info: {}", self.0) + } +} + +impl std::error::Error for Error {} + #[cfg_attr(any(test, feature = "test-util"), mockall::automock)] #[async_trait] pub trait TokenInfoFetching: Send + Sync { /// Retrieves information for a token. - async fn get_token_info(&self, address: H160) -> Result; + async fn get_token_info(&self, address: Address) -> Result; /// Retrieves all token information. /// Default implementation calls get_token_info for each token and ignores /// errors. - async fn get_token_infos(&self, addresses: &[H160]) -> HashMap; + async fn get_token_infos(&self, addresses: &[Address]) -> HashMap; } pub struct TokenInfoFetcher { @@ -47,7 +52,7 @@ pub struct TokenInfoFetcher { } impl TokenInfoFetcher { - async fn fetch_token(&self, address: H160) -> Result { + async fn fetch_token(&self, address: Address) -> Result { if address == BUY_ETH_ADDRESS { return Ok(TokenInfo { decimals: Some(18), @@ -55,7 +60,7 @@ impl TokenInfoFetcher { }); } - let erc20 = ERC20::Instance::new(address.into_alloy(), self.web3.alloy.clone()); + let erc20 = ERC20::Instance::new(address, self.web3.provider.clone()); let (decimals, symbol) = { let decimals = erc20.decimals(); let symbol = erc20.symbol(); @@ -71,7 +76,7 @@ impl TokenInfoFetcher { #[async_trait] impl TokenInfoFetching for TokenInfoFetcher { - async fn get_token_info(&self, address: H160) -> Result { + async fn get_token_info(&self, address: Address) -> Result { let info = self.fetch_token(address).await; if let Err(err) = &info { tracing::debug!(?err, token = ?address, "failed to fetch token info"); @@ -80,18 +85,18 @@ impl TokenInfoFetching for TokenInfoFetcher { info } - async fn get_token_infos(&self, addresses: &[H160]) -> HashMap { - futures::future::join_all(addresses.iter().copied().map(|address| async move { - let info = self.fetch_token(address).await; - if let Err(err) = &info { - tracing::debug!(?err, token = ?address, "failed to fetch token info"); - } - - (address, info.unwrap_or_default()) - })) - .await - .into_iter() - .collect() + async fn get_token_infos(&self, addresses: &[Address]) -> HashMap { + futures::stream::iter(addresses.iter().copied().collect::>()) + .map(|address| async move { + let info = self.fetch_token(address).await; + if let Err(err) = &info { + tracing::debug!(?err, token = ?address, "failed to fetch token info"); + } + (address, info.unwrap_or_default()) + }) + .buffer_unordered(TOKEN_INFO_FETCH_CONCURRENCY) + .collect() + .await } } @@ -99,7 +104,7 @@ type SharedTokenInfo = Shared>>; pub struct CachedTokenInfoFetcher { inner: Arc, - cache: Arc>>, + cache: Arc>>, } impl CachedTokenInfoFetcher { @@ -112,7 +117,7 @@ impl CachedTokenInfoFetcher { } impl CachedTokenInfoFetcher { - async fn fetch_token(&self, address: H160) -> Result { + async fn fetch_token(&self, address: Address) -> Result { let fetch = { let mut cache = self.cache.lock().unwrap(); cache @@ -140,20 +145,21 @@ impl CachedTokenInfoFetcher { #[async_trait] impl TokenInfoFetching for CachedTokenInfoFetcher { - async fn get_token_info(&self, address: H160) -> Result { + async fn get_token_info(&self, address: Address) -> Result { self.fetch_token(address).await } - async fn get_token_infos(&self, addresses: &[H160]) -> HashMap { - futures::future::join_all(addresses.iter().copied().map(|address| async move { - ( - address, - self.get_token_info(address).await.unwrap_or_default(), - ) - })) - .await - .into_iter() - .collect() + async fn get_token_infos(&self, addresses: &[Address]) -> HashMap { + futures::stream::iter(addresses.iter().copied().collect::>()) + .map(|address| async move { + ( + address, + self.get_token_info(address).await.unwrap_or_default(), + ) + }) + .buffer_unordered(TOKEN_INFO_FETCH_CONCURRENCY) + .collect() + .await } } @@ -163,12 +169,10 @@ mod tests { #[tokio::test] async fn cached_token_info_fetcher() { - let address = H160::from_low_u64_be; - let mut mock_token_info_fetcher = MockTokenInfoFetching::new(); mock_token_info_fetcher .expect_get_token_info() - .with(eq(address(0))) + .with(eq(Address::with_last_byte(0))) .times(1) .return_once(move |_| { Ok(TokenInfo { @@ -178,7 +182,7 @@ mod tests { }); mock_token_info_fetcher .expect_get_token_info() - .with(eq(address(1))) + .with(eq(Address::with_last_byte(1))) .times(1) .return_once(move |_| { Ok(TokenInfo { @@ -188,7 +192,7 @@ mod tests { }); mock_token_info_fetcher .expect_get_token_info() - .with(eq(address(2))) + .with(eq(Address::with_last_byte(2))) .times(2) .returning(|_| Err(Error("some error".to_string()))); @@ -196,24 +200,28 @@ mod tests { CachedTokenInfoFetcher::new(Arc::new(mock_token_info_fetcher)); // Fetches tokens, using `TokenInfo::default()` for the failed token. - let addresses = [address(0), address(1), address(2)]; + let addresses = [ + Address::with_last_byte(0), + Address::with_last_byte(1), + Address::with_last_byte(2), + ]; let token_infos = cached_token_info_fetcher.get_token_infos(&addresses).await; assert_eq!( token_infos, hashmap! { - address(0) => TokenInfo { + Address::with_last_byte(0) => TokenInfo { decimals: Some(18), symbol: Some("CAT".to_string()), }, - address(1) => TokenInfo { + Address::with_last_byte(1) => TokenInfo { decimals: None, symbol: None, }, - address(2) => TokenInfo::default(), + Address::with_last_byte(2) => TokenInfo::default(), } ); - // Fetch again, if the the two token 0 and 1 are fetched again (i.e. the + // Fetch again, if the two token 0 and 1 are fetched again (i.e. the // cache is not working) then this will panic because of the `times(1)` // constraint on our mock fetcher. Note that token 2 gets fetched again // because it failed to fetch the first time. diff --git a/crates/winner-selection/Cargo.toml b/crates/winner-selection/Cargo.toml new file mode 100644 index 0000000000..d8e3f9f559 --- /dev/null +++ b/crates/winner-selection/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "winner-selection" +version = "0.1.0" +edition = "2024" + +[dependencies] +alloy-primitives = { workspace = true } +anyhow = { workspace = true } +itertools = { workspace = true } +number = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } diff --git a/crates/winner-selection/src/arbitrator.rs b/crates/winner-selection/src/arbitrator.rs new file mode 100644 index 0000000000..1dc4f7757e --- /dev/null +++ b/crates/winner-selection/src/arbitrator.rs @@ -0,0 +1,745 @@ +//! Winner selection arbitrator. +//! +//! Implements the auction winner selection algorithm that picks the set of +//! solutions which maximize surplus while enforcing uniform directional +//! clearing prices. + +use { + crate::{ + auction::AuctionContext, + primitives::{DirectedTokenPair, FeePolicy, Quote, Side, as_erc20, price_in_eth}, + solution::{Order, RankType, Ranked, Scored, Solution, Unscored}, + state::{RankedItem, ScoredItem, UnscoredItem}, + }, + alloy_primitives::{Address, U256}, + anyhow::{Context, Result}, + itertools::{Either, Itertools}, + number::u256_ext::U256Ext, + std::{ + cmp::Reverse, + collections::{HashMap, HashSet}, + }, + tracing::instrument, +}; + +/// Auction arbitrator responsible for selecting winning solutions. +pub struct Arbitrator { + /// Maximum number of winning solutions to select. + pub max_winners: usize, + /// Wrapped native token address (WETH on mainnet, WXDAI on Gnosis). + pub weth: Address, +} + +impl Arbitrator { + /// Runs the auction mechanism on solutions. + /// + /// Takes solutions and auction context, returns a ranking with winners. + #[instrument(skip_all)] + pub fn arbitrate( + &self, + solutions: Vec>, + context: &AuctionContext, + ) -> Ranking { + let partitioned = self.partition_unfair_solutions(solutions, context); + let filtered_out = partitioned + .discarded + .into_iter() + .map(|s| s.with_rank(RankType::FilteredOut)) + .collect(); + let mut ranked = self.mark_winners(partitioned.kept); + + ranked.sort_by_key(|solution| (Reverse(solution.is_winner()), Reverse(solution.score()))); + + Ranking { + filtered_out, + ranked, + } + } + + /// Removes unfair solutions from the set of all solutions. + #[instrument(skip_all)] + fn partition_unfair_solutions( + &self, + solutions: Vec>, + context: &AuctionContext, + ) -> PartitionedSolutions { + // Discard all solutions where we can't compute the aggregate scores + // accurately because the fairness guarantees heavily rely on them. + let (mut solutions, scores_by_solution) = + self.compute_scores_by_solution(solutions, context); + + // Discard any solutions with a score of 0 as they are invalid + solutions.retain(|solution| !solution.score().is_zero()); + + // Sort by score descending + solutions.sort_by_key(|solution| Reverse(solution.score())); + + let baseline_scores = compute_baseline_scores(&scores_by_solution); + + // Partition into fair and unfair solutions + let (kept, discarded): (Vec<_>, Vec<_>) = solutions.into_iter().partition_map(|solution| { + let aggregated_scores = scores_by_solution + .get(&SolutionKey { + solver: solution.solver(), + solution_id: solution.id(), + }) + .expect("every remaining solution has an entry"); + + // only keep solutions where each order execution is at least as good as + // the baseline solution. + // we only filter out unfair solutions with more than one token pair, + // to avoid reference scores set to 0. + // see https://github.com/fhenneke/comb_auctions/issues/2 + if aggregated_scores.len() == 1 + || aggregated_scores.iter().all(|(pair, score)| { + baseline_scores + .get(pair) + .is_none_or(|baseline| score >= baseline) + }) + { + Either::Left(solution) + } else { + Either::Right(solution) + } + }); + + PartitionedSolutions { kept, discarded } + } + + /// Picks winners and sorts all solutions where winners come before + /// non-winners and higher scores come before lower scores. + fn mark_winners(&self, solutions: Vec>) -> Vec> { + let winner_indices = self.pick_winners(solutions.iter()); + + solutions + .into_iter() + .enumerate() + .map(|(index, solution)| { + let rank_type = if winner_indices.contains(&index) { + RankType::Winner + } else { + RankType::NonWinner + }; + solution.with_rank(rank_type) + }) + .collect() + } + + /// Computes the `DirectionalScores` for all solutions and discards + /// solutions as invalid whenever that computation is not possible. + /// Solutions get discarded because fairness guarantees heavily + /// depend on these scores being accurate. + fn compute_scores_by_solution( + &self, + solutions: Vec>, + context: &AuctionContext, + ) -> (Vec>, ScoresBySolution) { + let mut scores_by_solution = HashMap::default(); + let mut scored_solutions = Vec::new(); + + for solution in solutions { + match self.score_by_token_pair(&solution, context) { + Ok(score) => { + let total_score = score + .values() + .fold(U256::ZERO, |acc, s| acc.saturating_add(*s)); + scores_by_solution.insert( + SolutionKey { + solver: solution.solver(), + solution_id: solution.id(), + }, + score, + ); + scored_solutions.push(solution.with_score(total_score)); + } + Err(err) => { + tracing::warn!( + solution_id = solution.id(), + ?err, + "discarding solution where scores could not be computed" + ); + } + } + } + + (scored_solutions, scores_by_solution) + } + + /// Returns the total scores for each directed token pair of the solution. + /// E.g. if a solution contains 3 orders like: + /// sell A for B with a score of 10 + /// sell A for B with a score of 5 + /// sell B for C with a score of 5 + /// it will return a map like: + /// (A, B) => 15 + /// (B, C) => 5 + fn score_by_token_pair( + &self, + solution: &Solution, + context: &AuctionContext, + ) -> Result> { + let mut scores: HashMap = HashMap::default(); + + for order in solution.orders() { + if !context.contributes_to_score(&order.uid) { + continue; + } + + let score = self.compute_order_score(order, context)?; + + let token_pair = DirectedTokenPair { + sell: order.sell_token, + buy: order.buy_token, + }; + + let entry = scores.entry(token_pair).or_default(); + *entry = entry.saturating_add(score); + } + + Ok(scores) + } + + /// Score defined as (surplus + protocol fees) first converted to buy + /// amounts and then converted to the native token. + /// + /// Follows CIP-38 as the base of the score computation. + /// + /// Denominated in NATIVE token. + fn compute_order_score(&self, order: &Order, context: &AuctionContext) -> Result { + let native_price_buy = context + .native_prices + .get(&order.buy_token) + .context("missing native price for buy token")?; + + let custom_prices = self.calculate_custom_prices_from_executed(order); + + // Calculate surplus in surplus token (buy token for sell orders, sell token for + // buy orders) + let surplus_in_surplus_token = { + let user_surplus = self.surplus_over_limit_price(order, &custom_prices)?; + let fees = self.protocol_fees(order, context, &custom_prices)?; + + user_surplus + .checked_add(fees) + .context("overflow adding fees to surplus")? + }; + + let score_eth = match order.side { + // `surplus` of sell orders is already in buy tokens so we simply convert it to ETH + Side::Sell => price_in_eth(*native_price_buy, surplus_in_surplus_token), + Side::Buy => { + // `surplus` of buy orders is in sell tokens. We start with following formula: + // buy_amount / sell_amount == buy_price / sell_price + // + // since `surplus` of buy orders is in sell tokens we convert to buy amount via: + // buy_amount == (buy_price / sell_price) * surplus + // + // to avoid loss of precision because we work with integers we first multiply + // and then divide: + // buy_amount = surplus * buy_price / sell_price + use alloy_primitives::{U512, ruint::UintTryFrom}; + + let surplus_in_buy_tokens = surplus_in_surplus_token + .widening_mul(order.buy_amount) + .checked_div(U512::from(order.sell_amount)) + .context("division by zero converting surplus to buy tokens")?; + let surplus_in_buy_tokens: U256 = U256::uint_try_from(surplus_in_buy_tokens) + .map_err(|_| anyhow::anyhow!("overflow converting surplus to buy tokens"))?; + + // Afterwards we convert the buy token surplus to the native token. + price_in_eth(*native_price_buy, surplus_in_buy_tokens) + } + }; + + Ok(score_eth) + } + + /// Calculate total protocol fees for an order. + /// + /// Returns the total fee in the surplus token. + fn protocol_fees( + &self, + order: &Order, + context: &AuctionContext, + base_prices: &ClearingPrices, + ) -> Result { + let policies = context + .fee_policies + .get(&order.uid) + .map(|v| v.as_slice()) + .unwrap_or_default(); + + let mut total_fee = U256::ZERO; + let mut current_prices = *base_prices; + + // Process policies in reverse order, updating custom prices as we go + for (i, policy) in policies.iter().enumerate().rev() { + let fee = self.protocol_fee(order, policy, ¤t_prices)?; + + total_fee = total_fee + .checked_add(fee) + .context("overflow adding protocol fees")?; + + // Update custom prices for next iteration (except last iteration) + if i != 0 { + current_prices = self.calculate_custom_prices(order, total_fee, base_prices)?; + } + } + + Ok(total_fee) + } + + /// Calculate a single protocol fee based on policy type. + fn protocol_fee( + &self, + order: &Order, + policy: &FeePolicy, + custom_prices: &ClearingPrices, + ) -> MathResult { + match policy { + FeePolicy::Surplus { + factor, + max_volume_factor, + } => { + let surplus = self.surplus_over_limit_price(order, custom_prices)?; + let surplus_fee = self.surplus_fee(surplus, *factor)?; + let volume_fee = self.volume_fee(order, custom_prices, *max_volume_factor)?; + Ok(surplus_fee.min(volume_fee)) + } + FeePolicy::PriceImprovement { + factor, + max_volume_factor, + quote, + } => { + let price_improvement = + self.price_improvement_over_quote(order, custom_prices, quote)?; + let surplus_fee = self.surplus_fee(price_improvement, *factor)?; + let volume_fee = self.volume_fee(order, custom_prices, *max_volume_factor)?; + Ok(surplus_fee.min(volume_fee)) + } + FeePolicy::Volume { factor } => self.volume_fee(order, custom_prices, *factor), + } + } + + /// Calculate surplus over limit price using custom clearing prices. + fn surplus_over_limit_price(&self, order: &Order, prices: &ClearingPrices) -> MathResult { + self.surplus_over( + order, + prices, + PriceLimits { + sell: order.sell_amount, + buy: order.buy_amount, + }, + ) + } + + /// Calculate surplus over arbitrary price limits. + fn surplus_over( + &self, + order: &Order, + prices: &ClearingPrices, + limits: PriceLimits, + ) -> MathResult { + let executed = match order.side { + Side::Buy => order.executed_buy, + Side::Sell => order.executed_sell, + }; + + match order.side { + Side::Buy => { + // Scale limit sell to support partially fillable orders + let limit_sell = limits + .sell + .checked_mul(executed) + .ok_or(MathError::Overflow)? + .checked_div(limits.buy) + .ok_or(MathError::DivisionByZero)?; + + let sold = executed + .checked_mul(prices.buy) + .ok_or(MathError::Overflow)? + .checked_div(prices.sell) + .ok_or(MathError::DivisionByZero)?; + + limit_sell.checked_sub(sold).ok_or(MathError::Negative) + } + Side::Sell => { + // Scale limit buy to support partially fillable orders (ceiling division) + let limit_buy = executed + .checked_mul(limits.buy) + .ok_or(MathError::Overflow)? + .checked_ceil_div(&limits.sell) + .ok_or(MathError::DivisionByZero)?; + + let bought = executed + .checked_mul(prices.sell) + .ok_or(MathError::Overflow)? + .checked_ceil_div(&prices.buy) + .ok_or(MathError::DivisionByZero)?; + + bought.checked_sub(limit_buy).ok_or(MathError::Negative) + } + } + } + + /// Calculate price improvement over quote. + /// + /// Returns 0 if there's no improvement (instead of error). + fn price_improvement_over_quote( + &self, + order: &Order, + prices: &ClearingPrices, + quote: &Quote, + ) -> MathResult { + let adjusted_quote = self.adjust_quote_to_order_limits(order, quote)?; + match self.surplus_over(order, prices, adjusted_quote) { + Ok(surplus) => Ok(surplus), + Err(MathError::Negative) => Ok(U256::ZERO), + Err(err) => Err(err), + } + } + + /// Adjust quote amounts to be comparable with order limits. + fn adjust_quote_to_order_limits( + &self, + order: &Order, + quote: &Quote, + ) -> MathResult { + match order.side { + Side::Sell => { + // Quote buy amount after fees + let quote_buy_amount = quote + .buy_amount + .checked_sub( + quote + .fee + .checked_mul(quote.buy_amount) + .ok_or(MathError::Overflow)? + .checked_div(quote.sell_amount) + .ok_or(MathError::DivisionByZero)?, + ) + .ok_or(MathError::Negative)?; + + // Scale to order's sell amount + let scaled_buy_amount = quote_buy_amount + .checked_mul(order.sell_amount) + .ok_or(MathError::Overflow)? + .checked_div(quote.sell_amount) + .ok_or(MathError::DivisionByZero)?; + + // Use max to handle out-of-market orders + let buy_amount = order.buy_amount.max(scaled_buy_amount); + + Ok(PriceLimits { + sell: order.sell_amount, + buy: buy_amount, + }) + } + Side::Buy => { + // Quote sell amount including fees + let quote_sell_amount = quote + .sell_amount + .checked_add(quote.fee) + .ok_or(MathError::Overflow)?; + + // Scale to order's buy amount + let scaled_sell_amount = quote_sell_amount + .checked_mul(order.buy_amount) + .ok_or(MathError::Overflow)? + .checked_div(quote.buy_amount) + .ok_or(MathError::DivisionByZero)?; + + // Use min to handle out-of-market orders + let sell_amount = order.sell_amount.min(scaled_sell_amount); + + Ok(PriceLimits { + sell: sell_amount, + buy: order.buy_amount, + }) + } + } + } + + /// Calculate surplus fee as a cut of surplus. + /// + /// Uses adjusted factor: fee = surplus * factor / (1 - factor) + fn surplus_fee(&self, surplus: U256, factor: f64) -> MathResult { + // Surplus fee is specified as a `factor` from raw surplus (before fee). + // Since we work with trades that already have the protocol fee applied, + // we need to calculate the protocol fee using an adjusted factor. + // + // fee = surplus_before_fee * factor + // surplus_after_fee = surplus_before_fee - fee + // fee = surplus_after_fee * factor / (1 - factor) + surplus + .checked_mul_f64(factor / (1.0 - factor)) + .ok_or(MathError::Overflow) + } + + /// Calculate volume fee as a cut of trade volume. + fn volume_fee(&self, order: &Order, prices: &ClearingPrices, factor: f64) -> MathResult { + // Volume fee is specified as a factor from raw volume (before fee). + // We need to calculate using an adjusted factor based on order side. + // + // Sell: fee = traded_buy_amount * factor / (1 - factor) + // Buy: fee = traded_sell_amount * factor / (1 + factor) + + let executed_in_surplus_token = match order.side { + Side::Sell => self.buy_amount(order, prices)?, + Side::Buy => self.sell_amount(order, prices)?, + }; + + let adjusted_factor = match order.side { + Side::Sell => factor / (1.0 - factor), + Side::Buy => factor / (1.0 + factor), + }; + + executed_in_surplus_token + .checked_mul_f64(adjusted_factor) + .ok_or(MathError::Overflow) + } + + /// Calculate custom clearing prices from executed amounts. + /// + /// Custom prices are derived from what was actually executed. + fn calculate_custom_prices_from_executed(&self, order: &Order) -> ClearingPrices { + ClearingPrices { + sell: order.executed_buy, + buy: order.executed_sell, + } + } + + /// Calculate custom clearing prices excluding protocol fees. + /// + /// This adjusts prices to reflect the trade without the accumulated fees. + fn calculate_custom_prices( + &self, + order: &Order, + protocol_fee: U256, + prices: &ClearingPrices, + ) -> MathResult { + let sell_amount = self.sell_amount(order, prices)?; + let buy_amount = self.buy_amount(order, prices)?; + + Ok(ClearingPrices { + sell: match order.side { + Side::Sell => buy_amount + .checked_add(protocol_fee) + .ok_or(MathError::Overflow)?, + Side::Buy => buy_amount, + }, + buy: match order.side { + Side::Sell => sell_amount, + Side::Buy => sell_amount + .checked_sub(protocol_fee) + .ok_or(MathError::Negative)?, + }, + }) + } + + /// Calculate effective sell amount (what left user's wallet). + fn sell_amount(&self, order: &Order, prices: &ClearingPrices) -> MathResult { + match order.side { + Side::Sell => Ok(order.executed_sell), + Side::Buy => order + .executed_buy + .checked_mul(prices.buy) + .ok_or(MathError::Overflow)? + .checked_div(prices.sell) + .ok_or(MathError::DivisionByZero), + } + } + + /// Calculate effective buy amount (what user received). + fn buy_amount(&self, order: &Order, prices: &ClearingPrices) -> MathResult { + match order.side { + Side::Sell => order + .executed_sell + .checked_mul(prices.sell) + .ok_or(MathError::Overflow)? + .checked_ceil_div(&prices.buy) + .ok_or(MathError::DivisionByZero), + Side::Buy => Ok(order.executed_buy), + } + } + + /// Returns indices of winning solutions. + /// Assumes that `solutions` is sorted by score descendingly. + /// This logic was moved into a helper function to avoid a ton of `.clone()` + /// operations in `compute_reference_scores()`. + fn pick_winners<'a, T: 'a>( + &self, + solutions: impl Iterator>, + ) -> HashSet { + // Winners are selected one by one, starting from the best solution, + // until `max_winners` are selected. A solution can only + // win if none of the (sell_token, buy_token) pairs of the executed + // orders have been covered by any previously selected winning solution. + // In other words this enforces a uniform **directional** clearing price. + let mut already_swapped_token_pairs = HashSet::new(); + let mut winners = HashSet::default(); + + for (index, solution) in solutions.enumerate() { + if winners.len() >= self.max_winners { + return winners; + } + + let swapped_token_pairs: HashSet = solution + .orders() + .iter() + .map(|order| DirectedTokenPair { + sell: as_erc20(order.sell_token, self.weth), + buy: as_erc20(order.buy_token, self.weth), + }) + .collect(); + + if swapped_token_pairs.is_disjoint(&already_swapped_token_pairs) { + winners.insert(index); + already_swapped_token_pairs.extend(swapped_token_pairs); + } + } + + winners + } + + /// Compute reference scores for winning solvers. + #[instrument(skip_all)] + pub fn compute_reference_scores(&self, ranking: &Ranking) -> HashMap { + let mut reference_scores = HashMap::default(); + + for ranked_solution in &ranking.ranked { + let solver = ranked_solution.solver(); + + if reference_scores.len() >= self.max_winners { + return reference_scores; + } + if reference_scores.contains_key(&solver) { + continue; + } + if !ranked_solution.is_winner() { + continue; + } + + // Compute score without this solver + let solutions_without_solver: Vec<_> = ranking + .ranked + .iter() + .filter(|s| s.solver() != solver) + .collect(); + + let winner_indices = self.pick_winners(solutions_without_solver.iter().copied()); + + let score = solutions_without_solver + .iter() + .enumerate() + .filter(|(index, _)| winner_indices.contains(index)) + .map(|(_, solution)| solution.score()) + .reduce(|acc, score| acc.saturating_add(score)) + .unwrap_or_default(); + + reference_scores.insert(solver, score); + } + + reference_scores + } +} + +/// Let's call a solution that only trades 1 directed token pair a baseline +/// solution. Returns the best baseline solution (highest score) for +/// each token pair if one exists. +fn compute_baseline_scores(scores_by_solution: &ScoresBySolution) -> ScoreByDirection { + let mut baseline_scores = HashMap::default(); + + for scores in scores_by_solution.values() { + let Ok((token_pair, score)) = scores.iter().exactly_one() else { + continue; + }; + + let current_best = baseline_scores.entry(token_pair.clone()).or_default(); + if score > current_best { + *current_best = *score; + } + } + + baseline_scores +} + +/// Result of partitioning solutions into fair and unfair. +struct PartitionedSolutions { + /// Solutions that passed fairness checks (with scores). + kept: Vec>, + /// Solutions that were filtered out as unfair (with scores). + discarded: Vec>, +} + +/// Final ranking of all solutions. +#[derive(Debug)] +pub struct Ranking { + /// Solutions that were filtered out as unfair (with scores and FilteredOut + /// rank). + pub filtered_out: Vec>, + /// Solutions that passed fairness checks, ordered by score (with + /// Winner/NonWinner ranks). + pub ranked: Vec>, +} + +impl Ranking { + /// All winning solutions. + pub fn winners(&self) -> impl Iterator> { + self.ranked.iter().filter(|s| s.is_winner()) + } + + /// All non-winning solutions that weren't filtered out. + pub fn non_winners(&self) -> impl Iterator> { + self.ranked.iter().filter(|s| !s.is_winner()) + } +} + +/// Clearing prices for a trade. +/// +/// These can be either uniform (same for all orders) or custom (adjusted for +/// protocol fees on a per-order basis). +#[derive(Debug, Clone, Copy)] +struct ClearingPrices { + /// Price of sell token in terms of buy token. + sell: U256, + /// Price of buy token in terms of sell token. + buy: U256, +} + +/// Price limits for an order or quote. +#[derive(Debug, Clone, Copy)] +struct PriceLimits { + /// Maximum sell amount. + sell: U256, + /// Minimum buy amount. + buy: U256, +} + +/// Key to uniquely identify every solution. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +struct SolutionKey { + solver: Address, + solution_id: u64, +} + +/// Scores of all trades in a solution aggregated by the directional +/// token pair. E.g. all trades (WETH -> USDC) are aggregated into +/// one value and all trades (USDC -> WETH) into another. +type ScoreByDirection = HashMap; + +/// Mapping from solution to `DirectionalScores` for all solutions +/// of the auction. +type ScoresBySolution = HashMap; + +type MathResult = std::result::Result; + +#[derive(Debug, thiserror::Error)] +enum MathError { + #[error("overflow")] + Overflow, + #[error("division by zero")] + DivisionByZero, + #[error("negative")] + Negative, +} diff --git a/crates/winner-selection/src/auction.rs b/crates/winner-selection/src/auction.rs new file mode 100644 index 0000000000..d60ad9c6d3 --- /dev/null +++ b/crates/winner-selection/src/auction.rs @@ -0,0 +1,51 @@ +//! Auction context for winner selection. +//! +//! The auction context provides additional data needed for winner selection +//! that isn't part of the solution itself. This data comes from the auction +//! and is the same for all solutions. + +use { + crate::primitives::{FeePolicy, OrderUid}, + alloy_primitives::{Address, U256}, + std::collections::{HashMap, HashSet}, +}; + +/// Auction context needed for winner selection. +/// +/// This contains auction-level data that's needed to run the winner selection +/// algorithm but isn't part of individual solutions. Both autopilot and driver +/// build this from their respective auction representations. +#[derive(Default)] +pub struct AuctionContext { + /// Fee policies for each order in the auction. + /// + /// Maps order UID to the list of fee policies that apply to that order. + /// Fee policies determine how protocol fees are calculated. + pub fee_policies: HashMap>, + + /// Addresses that are allowed to create JIT orders that count toward score. + /// + /// JIT (Just-In-Time) orders created by these addresses will contribute to + /// the solution's score during winner selection. + pub surplus_capturing_jit_order_owners: HashSet
, + + /// Native token prices for all tokens in the auction. + /// + /// These prices are used to convert token amounts to native token + /// for score calculation. Maps token address to its price in native token. + pub native_prices: HashMap, +} + +impl AuctionContext { + /// Check if an order contributes to the solution's score. + /// + /// An order contributes to score if: + /// 1. It has fee policies defined (it's a user order from the auction), OR + /// 2. It's a JIT order from an allowed surplus-capturing owner + pub fn contributes_to_score(&self, uid: &OrderUid) -> bool { + self.fee_policies.contains_key(uid) + || self + .surplus_capturing_jit_order_owners + .contains(&uid.owner()) + } +} diff --git a/crates/winner-selection/src/lib.rs b/crates/winner-selection/src/lib.rs new file mode 100644 index 0000000000..df1c34588f --- /dev/null +++ b/crates/winner-selection/src/lib.rs @@ -0,0 +1,20 @@ +//! Minimal winner selection data structures and algorithm. +//! +//! This crate defines minimal data structures that contain only what's needed +//! to run the winner selection algorithm. Both autopilot and driver convert +//! their full solution types to these minimal structs, which are then sent to +//! the Pod Service for storage and later retrieval. + +pub mod arbitrator; +pub mod auction; +pub mod primitives; +pub mod solution; +pub mod state; + +// Re-export key types for convenience +pub use { + arbitrator::{Arbitrator, Ranking}, + auction::AuctionContext, + primitives::{Address, DirectedTokenPair, OrderUid, Side, U256}, + solution::{Order, RankType, Ranked, Scored, Solution, Unscored}, +}; diff --git a/crates/winner-selection/src/primitives.rs b/crates/winner-selection/src/primitives.rs new file mode 100644 index 0000000000..c7aa78ef25 --- /dev/null +++ b/crates/winner-selection/src/primitives.rs @@ -0,0 +1,83 @@ +//! Primitive types for winner selection. + +pub use alloy_primitives::{Address, U256}; + +/// Native token constant. +pub const NATIVE_TOKEN: Address = Address::repeat_byte(0xee); + +/// If the token is native, return the ERC20 wrapped version. +pub fn as_erc20(token: Address, wrapped: Address) -> Address { + if token == NATIVE_TOKEN { + wrapped + } else { + token + } +} + +/// Convert a token amount to ETH using this price. +/// +/// Formula: `amount * price / 10^18` +pub fn price_in_eth(price: U256, amount: U256) -> U256 { + amount.saturating_mul(price) / U256::from(1_000_000_000_000_000_000u64) +} + +/// A directed token pair for tracking uniform clearing prices. +/// +/// The direction matters: selling token A to buy token B is different from +/// selling token B to buy token A for the purpose of uniform directional +/// clearing prices. +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct DirectedTokenPair { + pub sell: Address, + pub buy: Address, +} + +/// A unique identifier for an order. +/// +/// This is a 56-byte array consisting of: +/// - 32 bytes: order digest (hash of order parameters) +/// - 20 bytes: owner address +/// - 4 bytes: valid until timestamp +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct OrderUid(pub [u8; 56]); + +impl OrderUid { + /// Extract the owner address from the order UID. + pub fn owner(&self) -> Address { + // Bytes 32-51 contain the owner address (20 bytes) + let mut bytes = [0u8; 20]; + bytes.copy_from_slice(&self.0[32..52]); + Address::from(bytes) + } +} + +/// Order side (buy or sell). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Side { + Buy, + Sell, +} + +/// Protocol fee policy. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FeePolicy { + /// Fee as a percentage of surplus over limit price. + Surplus { factor: f64, max_volume_factor: f64 }, + /// Fee as a percentage of price improvement over quote. + PriceImprovement { + factor: f64, + max_volume_factor: f64, + quote: Quote, + }, + /// Fee as a percentage of order volume. + Volume { factor: f64 }, +} + +/// Quote data for price improvement fee calculation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Quote { + pub sell_amount: U256, + pub buy_amount: U256, + pub fee: U256, + pub solver: Address, +} diff --git a/crates/winner-selection/src/solution.rs b/crates/winner-selection/src/solution.rs new file mode 100644 index 0000000000..f3f816fa1b --- /dev/null +++ b/crates/winner-selection/src/solution.rs @@ -0,0 +1,123 @@ +//! Minimal solution and order data structures. +//! +//! These structs contain only the data needed for winner selection, +//! making them small enough to efficiently send to/from the Pod Service. + +pub use state::{RankType, Unscored}; +use { + crate::{ + primitives::{OrderUid, Side}, + state, + }, + alloy_primitives::{Address, U256}, +}; +pub type Scored = state::Scored; +pub type Ranked = state::Ranked; + +/// Minimal solution data needed for winner selection. +/// +/// This contains only what's absolutely necessary to run the winner selection +/// algorithm. +#[derive(Debug, Clone)] +pub struct Solution { + /// Solution ID from solver (unique per solver). + id: u64, + + /// Solver's submission address (used for identifying the solver). + solver: Address, + + /// Orders executed in this solution. + orders: Vec, + + /// State marker (score and ranking information). + state: State, +} + +impl Solution { + /// Get the solution ID. + pub fn id(&self) -> u64 { + self.id + } + + /// Get the solver address. + pub fn solver(&self) -> Address { + self.solver + } + + /// Get the orders. + pub fn orders(&self) -> &[Order] { + &self.orders + } +} + +impl state::HasState for Solution { + type Next = Solution; + type State = State; + + fn with_state(self, state: NewState) -> Self::Next { + Solution { + id: self.id, + solver: self.solver, + orders: self.orders, + state, + } + } + + fn state(&self) -> &Self::State { + &self.state + } +} + +impl Solution { + /// Create a new unscored solution. + pub fn new(id: u64, solver: Address, orders: Vec) -> Self { + Self { + id, + solver, + orders, + state: Unscored, + } + } +} + +/// Minimal order data needed for winner selection. +/// +/// Contains the essential information about how an order was executed, +/// including limit amounts (from the original order) and executed amounts +/// (what actually happened in this solution). +#[derive(Debug, Clone)] +pub struct Order { + /// Unique order identifier (56 bytes). + pub uid: OrderUid, + + /// Sell token address. + pub sell_token: Address, + + /// Buy token address. + pub buy_token: Address, + + /// Limit amount of sell token (from original order parameters). + /// + /// This is the maximum amount the user is willing to sell. + pub sell_amount: U256, + + /// Limit amount of buy token (from original order parameters). + /// + /// This is the minimum amount the user wants to receive. + pub buy_amount: U256, + + /// Amount of sell token that left the user's wallet (including fees). + /// + /// This is the actual executed amount in this solution. + pub executed_sell: U256, + + /// Amount of buy token the user received (after fees). + /// + /// This is the actual amount the user got in this solution. + pub executed_buy: U256, + + /// Order side (Buy or Sell). + /// + /// Determines how surplus is calculated. + pub side: Side, +} diff --git a/crates/winner-selection/src/state.rs b/crates/winner-selection/src/state.rs new file mode 100644 index 0000000000..7fdbaf8f21 --- /dev/null +++ b/crates/winner-selection/src/state.rs @@ -0,0 +1,155 @@ +//! Shared scoring and ranking state markers. +//! +//! This module provides the type-state pattern infrastructure for tracking +//! solutions through the winner selection process: +//! +//! ```text +//! Unscored → Scored → Ranked +//! ``` + +/// This is the initial state when a solution enters the winner selection +/// process. +#[derive(Debug, Clone, Copy)] +pub struct Unscored; + +/// This is the intermediate state after computing surplus and fees but before +/// ranking. +#[derive(Debug, Clone, Copy)] +pub struct Scored { + pub score: Score, +} + +/// This is the final state with complete information about whether the +/// solution is a winner or was filtered out. +#[derive(Debug, Clone, Copy)] +pub struct Ranked { + pub rank_type: RankType, + pub score: Score, +} + +/// The type of ranking assigned to a state. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RankType { + Winner, + NonWinner, + FilteredOut, +} + +impl RankType { + pub fn is_winner(self) -> bool { + matches!(self, RankType::Winner) + } + + pub fn is_filtered_out(self) -> bool { + matches!(self, RankType::FilteredOut) + } +} + +/// Base trait for types that use the type-state pattern. +/// +/// This trait provides the foundation for state transitions at compile time. +/// Types implementing this trait can transition between different states +/// (Unscored → Scored → Ranked) with compile-time guarantees. +/// +/// # Type Parameters +/// +/// - `State`: The current state of the type +/// - `Next`: The type after transitioning to a new state +pub trait HasState { + type State; + type Next; + + fn with_state(self, state: NewState) -> Self::Next; + fn state(&self) -> &Self::State; +} + +/// Trait for items in the Unscored state. +/// +/// Items with this trait haven't been scored yet. This represents the initial +/// state when a solution enters the winner selection process. +/// +/// # State Transition +/// +/// Unscored → Scored (via `with_score()`) +pub trait UnscoredItem: HasState { + fn with_score(self, score: Score) -> Self::Next>; +} + +impl UnscoredItem for T +where + T: HasState, +{ + fn with_score(self, score: Score) -> Self::Next> { + self.with_state(Scored { score }) + } +} + +/// Trait for items in the Scored state. +/// +/// Items with this trait have been scored but not yet ranked. This is the +/// intermediate state after computing surplus/fees but before winner selection. +/// +/// # State Transition +/// +/// Scored → Ranked (via `with_rank()`) +/// +/// # Methods +/// +/// - `score()`: Access the computed score +/// - `with_rank()`: Transition to Ranked state with a rank type +pub trait ScoredItem: HasState> { + fn score(&self) -> Score; + fn with_rank(self, rank_type: RankType) -> Self::Next> + where + Self: Sized; +} + +impl ScoredItem for T +where + Score: Copy, + T: HasState>, +{ + fn score(&self) -> Score { + self.state().score + } + + fn with_rank(self, rank_type: RankType) -> Self::Next> { + let score = self.state().score; + self.with_state(Ranked { rank_type, score }) + } +} + +/// Trait for items in the Ranked state. +/// +/// Items with this trait have been scored and ranked in the winner selection +/// process. This is the final state with complete information about whether +/// the solution is a winner or was filtered out. +/// +/// # Methods +/// +/// - `score()`: Access the computed score +/// - `is_winner()`: Check if this is a winning solution +/// - `is_filtered_out()`: Check if this was filtered out (unfair) +pub trait RankedItem: HasState> { + fn score(&self) -> Score; + fn is_winner(&self) -> bool; + fn is_filtered_out(&self) -> bool; +} + +impl RankedItem for T +where + Score: Copy, + T: HasState>, +{ + fn score(&self) -> Score { + self.state().score + } + + fn is_winner(&self) -> bool { + self.state().rank_type.is_winner() + } + + fn is_filtered_out(&self) -> bool { + self.state().rank_type.is_filtered_out() + } +} diff --git a/database/README.md b/database/README.md index d62b9bda99..4a4679f9e5 100644 --- a/database/README.md +++ b/database/README.md @@ -8,6 +8,7 @@ Some tables only store data emitted via smart contract events. Because we only h [CoWSwapEthFlow](https://github.com/cowprotocol/ethflowcontract/blob/main/src/CoWSwapEthFlow.sol) we actually deployed twice so events related to the staging environment should only show up in the staging DB and likewise for production. It's also important to note that we only index events from blocks that we are certain will not get reorged. That means specifically that events will be indexed with a block delay of at least 64. + ### app\_data Associates the 32 bytes contract app data with the corresponding full app data. @@ -64,6 +65,7 @@ Contains all auctions for which a valid solver competition exists. Indexes: - PRIMARY KEY: btree(`id`) +- competition_auction_deadline: btree(`deadline`) ### ethflow\_orders @@ -175,16 +177,18 @@ Indexes: - PRIMARY KEY: btree(`uid`) - event\_index: btree(`block_number`, `index`) - order\_sender: hash(sender) +- okay\_onchain\_orders: btree(`uid`) WHERE placement\_error IS NOT NULL ### order\_events Stores timestamped events throughout an order's life cycle. This information is used to get detailed metrics on a per order basis. - Column | Type | Nullable | Details -------------------|--------------------------|----------|-------- - order\_uid | bytea | not null | order this event belongs to - timestamp | timestamptz | not null | when the event was registered - label | [enum](#ordereventlabel) | not null | which event happened exactly + Column | Type | Nullable | Details +------------------|----------------------------|----------|-------- + order\_uid | bytea | not null | order this event belongs to + timestamp | timestamptz | not null | when the event was registered + label | [enum](#ordereventlabel) | not null | which event happened exactly + reason | [enum](#orderfilterreason) | nullable | why the order was filtered or marked invalid (only set for `filtered` and `invalid` labels) Indexes: - order\_events\_by\_uid: btree(`order_uid`, `timestamp`) @@ -234,6 +238,7 @@ Quotes that an order was created with. These quotes get stored persistently and Indexes: - PRIMARY KEY: btree(`order_uid`) +- order_quotes_creation_timestamp: btree(`creation_timestamp`) ### orders @@ -248,7 +253,7 @@ Column | Type | Nullable | Details buy\_token | bytea | not null | address of the token that will be bought sell\_amount | numeric | not null | amount in sell\_token that should be sold at most buy\_amount | numeric | not null | amount of buy\_token that should be bought at least - valid\_to | timestamptz | not null | point in time when the order can no longer be settled + valid\_to | timestamptz | not null | point in time when the order can no longer be settled as signed by the user. fee\_amount | numeric | not null | amount in sell\_token the owner agreed upfront as a fee to be taken for the trade kind | [enum](#orderkind) | not null | trade semantics of the order partially\_fillable | bool | not null | determines if the order can be executed in multiple smaller trades or if everything has to be executed at once (fill-or-kill) @@ -261,10 +266,20 @@ Column | Type | Nullable | Details sell\_token\_balance | [enum](#selltokensource) | not null | defines how sell\_tokens need to be transferred into the settlement contract buy\_token\_balance | [enum](#buytokendestination) | not null | defined how buy\_tokens need to be transferred back to the user class | [enum](#orderclass) | not null | determines which special trade semantics will apply to the execution of this order - + true_valid_to | timestamptz | not null | timestamp at which order is no longer executable. For regular orders it is the same value as valid_to. Some orders may have multiple valid_to values, such as ethflow: which is initially signed with u32::MAX. Their true validity comes from the Settlement contract's events which is used for liveness checks. Indexes: - PRIMARY KEY: btree(`uid`) +- order_cancellation_timestamp: btree(`cancellation_timestamp`) +- order_creation_timestamp: btree(`creation_timestamp`) +- order_owner: hash(`owner`) +- order_quoting_parameters: btree(`sell_token`, `buy_token`, `sell_amount`) +- order_sell_buy_tokens: btree(`sell_token`, `buy_token`) +- user_order_creation_timestamp: btree(`owner`, `creation_timestamp` DESC) +- version_idx: btree(`settlement_contract`) +- orders\_true\_valid\_to: btree(`true_valid_to`) +- orders_owner_covering: btree(`owner`) INCLUDE (`uid`, `kind`, `buy_amount`, `sell_amount`, `fee_amount`, `buy_token`, `sell_token`) +- orders_owner_class_valid_composite: btree(`owner`, `class`, `true_valid_to` DESC) WHERE cancellation_timestamp IS NULL ### fee_policies @@ -469,6 +484,7 @@ This table contains data of [`Trade`](https://github.com/cowprotocol/contracts/b Indexes: - PRIMARY KEY: btree(`block_number`, `log_index`) - trade\_order\_uid: btree (`order_uid`, `block_number`, `log_index`) +- trades_covering: btree(`order_uid`) INCLUDE (`buy_amount`, `sell_amount`, `fee_amount`) ### surplus\_capturing\_jit\_order\_owners @@ -516,6 +532,84 @@ Indexes: - jit\_user\_order\_creation\_timestamp: btree(`owner`, `creation_timestamp` DESC) - jit\_event\_id: btree(`block_number`, `log_index`) +### pool\_indexer\_checkpoints + +Highest finalized block processed per `contract_address` by `pool-indexer`. `contract_address` is the factory address. The indexer runs one process per network against its own DB, so there's no `chain_id` column. + + Column | Type | Nullable | Details +--------------------|--------|----------|-------- + contract\_address | bytea | not null | Factory address (20 bytes) + block\_number | bigint | not null | + +Indexes: +- PRIMARY KEY: btree (`contract_address`) + +### uniswap\_v3\_pools + +One row per pool discovered from a `PoolCreated` event. `token{0,1}_{decimals,symbol}` are nullable and filled in by the backfill task. `factory` partitions the table when multiple V3-compatible factories run on the same network so each indexer touches only its own rows. + + Column | Type | Nullable | Details +-------------------|----------|----------|-------- + address | bytea | not null | Pool address (20 bytes) + factory | bytea | not null | Address of the V3 factory that emitted `PoolCreated` + token0 | bytea | not null | + token1 | bytea | not null | + fee | int | not null | Hundredths of a basis point (500 = 0.05%, 3000 = 0.3%, 10000 = 1%). `CHECK (fee > 0)`. + token0\_decimals | smallint | nullable | `NULL` = not yet fetched. `-1` = sentinel for "fetched but call failed" + token1\_decimals | smallint | nullable | + token0\_symbol | text | nullable | `NULL` = not yet fetched. `""` = sentinel for "fetched but call failed" + token1\_symbol | text | nullable | + created\_block | bigint | not null | Block in which the pool was created on-chain + +Indexes: +- PRIMARY KEY: btree (`address`) +- Four partial indexes on `(token{0,1})` with predicate `token{0,1}_{symbol,decimals} IS NULL` to power the backfill scan. + +### uniswap\_v3\_pool\_states + +Current state per pool: `sqrt_price_x96` and `tick` come from the latest `Swap`/`Initialize`; `liquidity` and `block_number` also update on in-range `Mint`/`Burn`. FK → `uniswap_v3_pools`. + +**Uniswap V3 pool-state primer.** Three values capture a pool's instantaneous state: + +- `sqrt_price_x96` — `sqrt(price) * 2^96` where `price = token1/token0`, stored in Q64.96 fixed-point. The square-root form keeps swap math additive and bounds precision loss over the uint160 range. Mirrors on-chain `slot0.sqrtPriceX96`. +- `tick` — `floor(log_{1.0001}(price))`. Each tick is a ~0.01% price step; the current tick is the bucket the live price falls into. Routers use it to decide which positions are in-range. +- `liquidity` — sum of every position's liquidity whose `tickLower <= current_tick < tickUpper`. This is the `L` in V3's invariant `Δsqrt_price = Δamount / L`. Updates on `Swap` (the event carries the new value) and on `Mint`/`Burn` whose range spans the current tick. + +The per-tick deltas that move `liquidity` when the price crosses a tick boundary live in [`uniswap_v3_ticks`](#uniswap_v3_ticks). + + Column | Type | Nullable | Details +-------------------|---------|----------|-------- + pool\_address | bytea | not null | FK → `uniswap_v3_pools(address)` + block\_number | bigint | not null | Block of the most recent state-changing event (`Swap`, `Initialize`, or in-range `Mint`/`Burn`). + sqrt\_price\_x96 | numeric | not null | uint160 — see primer above + liquidity | numeric | not null | uint128 — see primer above + tick | int | not null | signed int24 — see primer above + +Indexes: +- PRIMARY KEY: btree (`pool_address`) + +### uniswap\_v3\_ticks + +Per-tick liquidity deltas. Rows with `liquidity_net = 0` are pruned. FK → `uniswap_v3_pools`. + +**Why deltas instead of per-tick totals.** A V3 position covers `[tickLower, tickUpper)` and contributes to pool liquidity only when the current tick is in that range. We store the entering / exiting deltas at the bounds: + +- At `tickLower`: `liquidity_net += position.liquidity` (entering) +- At `tickUpper`: `liquidity_net -= position.liquidity` (exiting) + +When a swap crosses a tick boundary, the pool's `liquidity` shifts by `± tick.liquidity_net`. This encoding makes the per-tick aggregate O(1) at swap time — no per-position iteration. + +Quoters consult these to predict liquidity changes at tick crossings during swap simulation. Without them, large swaps would be priced as if the liquidity stayed flat, producing wildy wrong quotes + + Column | Type | Nullable | Details +----------------|---------|----------|-------- + pool\_address | bytea | not null | FK → `uniswap_v3_pools(address)` + tick\_idx | int | not null | Tick coordinate (signed int24); same domain as [`uniswap_v3_pool_states.tick`](#uniswap_v3_pool_states) + liquidity\_net | numeric | not null | int128, signed — net liquidity entering (+) / exiting (-) at this tick + +Indexes: +- PRIMARY KEY: btree (`pool_address`, `tick_idx`) + ### cow\_amms Stores information about indexed CoW AMMs that have been discovered through blockchain events. Each row represents a CoW AMM pool with its associated factory contract and tradeable tokens. @@ -568,6 +662,18 @@ Indexes: traded | order was traded on-chain cancelled | user cancelled the order +#### orderfilterreason + + Value | Meaning +------------------------|-------- + in\_flight | order already won a previous auction and is being settled on-chain + banned\_user | order owner is on the ban list + invalid\_signature | presign or EIP-1271 signature is not yet valid + unsupported\_token | sell or buy token is on the deny list + insufficient\_balance | owner does not have enough sell token balance or allowance + dust\_order | order value is too small to be worth settling + missing\_native\_price | no native price available for the order's tokens + #### orderkind Value | Meaning @@ -616,3 +722,13 @@ We support different expiration times for orders with different signing schemes. market | Short lived order that may receive surplus. Users agree to a static fee upfront by signing it. liquidity | These orders must be traded at their limit price and may not receive any surplus. Violating this is a slashable offence. limit | Long lived order that may receive surplus. Users sign a static fee of 0 upfront and either the backend or the solvers compute a dynamic fee that gets taken from the surplus (while still respecting the user's limit price!). + +## Notes on Migrations + +Migrations that require a long running process *must* be done manually, this is due to the limitations the weekly release process imposes: +* The deployment must complete under 5 minutes +* The pod has a `processDeadlineSeconds` defaulting to 600 seconds + +To avoid extending the process, we resort to manually applying complicated migrations. + +The above also comes into play when dealing with indexes, as their construction with flyway may lock up rows, degrading SLI. diff --git a/database/conf/flyway.conf b/database/conf/flyway.conf index 4aaf24b886..b184936575 100644 --- a/database/conf/flyway.conf +++ b/database/conf/flyway.conf @@ -1,3 +1,5 @@ # Flyway was introduced after V003. Therefore assume this version if table is not empty and there is no version information flyway.baselineOnMigrate=true flyway.baselineVersion=3 +# required to allow building indexes concurrently within a migration +flyway.postgresql.transactional.lock=false diff --git a/database/sql/V094__add_order_notification_trigger.sql b/database/sql/V094__add_order_notification_trigger.sql new file mode 100644 index 0000000000..ca721454ce --- /dev/null +++ b/database/sql/V094__add_order_notification_trigger.sql @@ -0,0 +1,15 @@ +-- Create a trigger function that notifies on new orders +-- The notification payload contains the hex-encoded order UID +CREATE OR REPLACE FUNCTION notify_new_order() +RETURNS trigger AS $$ +BEGIN + PERFORM pg_notify('new_order', encode(NEW.uid, 'hex')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Create a trigger that fires after each insert on the orders table +CREATE TRIGGER order_insert_notify +AFTER INSERT ON orders +FOR EACH ROW +EXECUTE FUNCTION notify_new_order(); diff --git a/database/sql/V095__add_true_valid_to_for_orders.sql b/database/sql/V095__add_true_valid_to_for_orders.sql new file mode 100644 index 0000000000..975c6dc5f0 --- /dev/null +++ b/database/sql/V095__add_true_valid_to_for_orders.sql @@ -0,0 +1,19 @@ +--- Add true_valid_to column which will uniformly store all orders' validity +--- This will enable creating an index to speedup user_orders_with_quote and solvable_orders queries +--- which have increased in runtime since a big influx of ethflow orders +ALTER TABLE orders ADD COLUMN true_valid_to bigint; + +/* +The true_valid_to will have to be backfilled manually to ensure manageable load on db +using the following: +UPDATE orders +SET true_valid_to = COALESCE( + (SELECT ethflow_orders.valid_to FROM ethflow_orders WHERE ethflow_orders.uid = orders.uid), + orders.valid_to +) +WHERE uid IN ( + SELECT uid FROM orders + WHERE true_valid_to IS NULL + LIMIT 10000 +); +*/ \ No newline at end of file diff --git a/database/sql/V096__update_order_timestamp_indexes.sql b/database/sql/V096__update_order_timestamp_indexes.sql new file mode 100644 index 0000000000..7ed2cbae09 --- /dev/null +++ b/database/sql/V096__update_order_timestamp_indexes.sql @@ -0,0 +1,6 @@ +-- create a separate index for cancellation_timestamp to improve queries +-- filtering based on the cancellation_timestamp +-- no extra index with only the creation_timestamp needs to be created +-- since that already exists. +CREATE INDEX CONCURRENTLY order_cancellation_timestamp ON orders USING BTREE(cancellation_timestamp); + diff --git a/database/sql/V097__no_op_placeholder.sql b/database/sql/V097__no_op_placeholder.sql new file mode 100644 index 0000000000..e670655000 --- /dev/null +++ b/database/sql/V097__no_op_placeholder.sql @@ -0,0 +1 @@ +-- Migration was omitted to keep numbering continuity, for more information see PR #4096 \ No newline at end of file diff --git a/database/sql/V098__no_op_placeholder.sql b/database/sql/V098__no_op_placeholder.sql new file mode 100644 index 0000000000..e670655000 --- /dev/null +++ b/database/sql/V098__no_op_placeholder.sql @@ -0,0 +1 @@ +-- Migration was omitted to keep numbering continuity, for more information see PR #4096 \ No newline at end of file diff --git a/database/sql/V099__no_op_placeholder.sql b/database/sql/V099__no_op_placeholder.sql new file mode 100644 index 0000000000..e670655000 --- /dev/null +++ b/database/sql/V099__no_op_placeholder.sql @@ -0,0 +1 @@ +-- Migration was omitted to keep numbering continuity, for more information see PR #4096 \ No newline at end of file diff --git a/database/sql/V100__add_auction_deadline.sql b/database/sql/V100__add_auction_deadline.sql new file mode 100644 index 0000000000..629aa3cfc8 --- /dev/null +++ b/database/sql/V100__add_auction_deadline.sql @@ -0,0 +1,2 @@ +-- adds index on the deadline of an auction to quickly look up inflight orders from the db +CREATE INDEX CONCURRENTLY IF NOT EXISTS competition_auction_deadline ON competition_auctions USING BTREE(deadline); diff --git a/database/sql/V101__set_true_valid_to_non_null.sql b/database/sql/V101__set_true_valid_to_non_null.sql new file mode 100644 index 0000000000..a75a1afb7a --- /dev/null +++ b/database/sql/V101__set_true_valid_to_non_null.sql @@ -0,0 +1 @@ +ALTER TABLE orders ALTER COLUMN true_valid_to SET NOT NULL; diff --git a/database/sql/V102__create_true_valid_to_indexes.sql b/database/sql/V102__create_true_valid_to_indexes.sql new file mode 100644 index 0000000000..66baebc5be --- /dev/null +++ b/database/sql/V102__create_true_valid_to_indexes.sql @@ -0,0 +1,4 @@ +--index on `true_valid_to` for quickly discarding expired orders +CREATE INDEX CONCURRENTLY IF NOT EXISTS orders_true_valid_to ON orders USING btree (true_valid_to); +-- further drops the query from 100ms to 80ms (warmed cache) +CREATE INDEX CONCURRENTLY IF NOT EXISTS okay_onchain_orders ON onchain_placed_orders USING btree (uid) WHERE placement_error IS NOT NULL; diff --git a/database/sql/V103__create_convering_indexes_for_surplus.sql b/database/sql/V103__create_convering_indexes_for_surplus.sql new file mode 100644 index 0000000000..d6e783f055 --- /dev/null +++ b/database/sql/V103__create_convering_indexes_for_surplus.sql @@ -0,0 +1,3 @@ +-- covering indexes to avoid IO when calculating the total surplus for users +CREATE INDEX CONCURRENTLY IF NOT EXISTS trades_covering ON trades (order_uid) INCLUDE (buy_amount, sell_amount, fee_amount); +CREATE INDEX CONCURRENTLY IF NOT EXISTS orders_owner_covering ON orders (owner) INCLUDE (uid, kind, buy_amount, sell_amount, fee_amount, buy_token, sell_token); diff --git a/database/sql/V104__create_composite_index.sql b/database/sql/V104__create_composite_index.sql new file mode 100644 index 0000000000..25c8c3f57f --- /dev/null +++ b/database/sql/V104__create_composite_index.sql @@ -0,0 +1,2 @@ +-- composite index to speed up query for user orders with quote +CREATE INDEX CONCURRENTLY IF NOT EXISTS orders_owner_class_valid_composite ON orders (owner, class, true_valid_to DESC) WHERE cancellation_timestamp IS NULL; diff --git a/database/sql/V105__index_proposed_trade_executions_by_order_uid.sql b/database/sql/V105__index_proposed_trade_executions_by_order_uid.sql new file mode 100644 index 0000000000..f79842c6ef --- /dev/null +++ b/database/sql/V105__index_proposed_trade_executions_by_order_uid.sql @@ -0,0 +1,2 @@ +CREATE INDEX CONCURRENTLY IF NOT EXISTS proposed_trade_executions_by_order_uid +ON proposed_trade_executions (order_uid); diff --git a/database/sql/V106__create_auction_orders.sql b/database/sql/V106__create_auction_orders.sql new file mode 100644 index 0000000000..01fa889fab --- /dev/null +++ b/database/sql/V106__create_auction_orders.sql @@ -0,0 +1,8 @@ +-- Junction table mapping orders to auctions they participated in. +CREATE TABLE auction_orders ( + auction_id bigint NOT NULL, + order_uid bytea NOT NULL, + PRIMARY KEY (auction_id, order_uid) +); + +CREATE INDEX auction_orders_by_order_uid ON auction_orders (order_uid); diff --git a/database/sql/V107__add_reason_to_order_events.sql b/database/sql/V107__add_reason_to_order_events.sql new file mode 100644 index 0000000000..d7bf65ea61 --- /dev/null +++ b/database/sql/V107__add_reason_to_order_events.sql @@ -0,0 +1,11 @@ +CREATE TYPE OrderFilterReason AS ENUM ( + 'in_flight', + 'banned_user', + 'invalid_signature', + 'unsupported_token', + 'insufficient_balance', + 'dust_order', + 'missing_native_price' +); + +ALTER TABLE order_events ADD COLUMN reason OrderFilterReason; diff --git a/database/sql/V108__trade_owner_expression_index.sql b/database/sql/V108__trade_owner_expression_index.sql new file mode 100644 index 0000000000..70c9a738ad --- /dev/null +++ b/database/sql/V108__trade_owner_expression_index.sql @@ -0,0 +1,13 @@ +-- Creates an index optimized for searching trades of a given owner. +-- Instead of introducing a whole new owner field that would result +-- in a very expensive table rewrite we use the fact that the uid +-- already contains the owner address. +-- Since postgres supports expression based indexes we can just index +-- the owner slice of the uid. +-- Indexing the `block_number` and `log_index` is needed for postgres +-- to actually use this index in the account trades query. +CREATE INDEX CONCURRENTLY IF NOT EXISTS trades_order_uid_owner ON trades ( + substring(order_uid, 33, 20), + block_number DESC, + log_index DESC +); diff --git a/database/sql/V109__order_quotes_creation_timestamp_index.sql b/database/sql/V109__order_quotes_creation_timestamp_index.sql new file mode 100644 index 0000000000..fe5fac3418 --- /dev/null +++ b/database/sql/V109__order_quotes_creation_timestamp_index.sql @@ -0,0 +1,3 @@ +-- The job replicating data to the analytics DB fetches quotes based on the creation timestamp. +-- This query significantly speeds that up. +CREATE INDEX CONCURRENTLY IF NOT EXISTS order_quotes_creation_timestamp ON order_quotes USING BTREE(creation_timestamp); diff --git a/database/sql/V110__pool_indexer_uniswap_v3.sql b/database/sql/V110__pool_indexer_uniswap_v3.sql new file mode 100644 index 0000000000..0993d80e1d --- /dev/null +++ b/database/sql/V110__pool_indexer_uniswap_v3.sql @@ -0,0 +1,59 @@ +-- Tracks the highest finalized block fully processed per factory contract. +-- A DB instance hosts a single network, so no `chain_id` column is needed. +CREATE TABLE pool_indexer_checkpoints ( + contract_address BYTEA NOT NULL, -- factory address + block_number BIGINT NOT NULL, + PRIMARY KEY (contract_address) +); + +-- One row per pool, discovered from `PoolCreated` events. `factory` +-- partitions the table so multiple V3-compatible factories on the same +-- network can coexist (logs are fetched chain-wide, then partitioned at +-- the write boundary). +CREATE TABLE uniswap_v3_pools ( + address BYTEA NOT NULL, -- pool address + factory BYTEA NOT NULL, + token0 BYTEA NOT NULL, + token1 BYTEA NOT NULL, + fee INT NOT NULL CHECK (fee > 0), -- hundredths of a basis point (500 = 0.05%, 3000 = 0.3%, 10000 = 1%) + token0_decimals SMALLINT, + token1_decimals SMALLINT, + token0_symbol TEXT, + token1_symbol TEXT, + created_block BIGINT NOT NULL, + PRIMARY KEY (address) +); + +-- Current state per pool. `sqrt_price_x96` + `tick` come from the latest +-- Swap/Initialize; `liquidity` + `block_number` also update on in-range +-- Mint/Burn events. +CREATE TABLE uniswap_v3_pool_states ( + pool_address BYTEA NOT NULL, + block_number BIGINT NOT NULL, + sqrt_price_x96 NUMERIC NOT NULL, -- uint160 + liquidity NUMERIC NOT NULL, -- uint128 + -- `tick` here means the Uniswap V3 *price tick index* (signed + -- int24), not a database index. See `uniswap_v3_ticks.tick_idx`. + tick INT NOT NULL, + PRIMARY KEY (pool_address), + FOREIGN KEY (pool_address) REFERENCES uniswap_v3_pools(address) +); + +-- Active ticks per pool. Rows with `liquidity_net = 0` are pruned. +-- `tick_idx` is the price tick coordinate (signed int24) — same domain +-- as `uniswap_v3_pool_states.tick`, one row per active tick boundary. +CREATE TABLE uniswap_v3_ticks ( + pool_address BYTEA NOT NULL, + tick_idx INT NOT NULL, + liquidity_net NUMERIC NOT NULL, -- int128 (can be negative) + PRIMARY KEY (pool_address, tick_idx), + FOREIGN KEY (pool_address) REFERENCES uniswap_v3_pools(address) +); + +-- Symbol/decimals backfill hot paths. Partial on `IS NULL` so each +-- index shrinks to near-empty once most rows are populated (real value +-- or the `""` / `-1` "tried, failed" sentinel). +CREATE INDEX ON uniswap_v3_pools (token0) WHERE token0_symbol IS NULL; +CREATE INDEX ON uniswap_v3_pools (token1) WHERE token1_symbol IS NULL; +CREATE INDEX ON uniswap_v3_pools (token0) WHERE token0_decimals IS NULL; +CREATE INDEX ON uniswap_v3_pools (token1) WHERE token1_decimals IS NULL; diff --git a/docker-compose.yaml b/docker-compose.yaml index a29d1ac6e6..75b479a2a5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -32,6 +32,9 @@ services: - type: bind source: ./database/sql/ target: /flyway/sql + - type: bind + source: ./database/conf/ + target: /flyway/conf volumes: postgres: diff --git a/docs/COW_ORDER_DEBUG_SKILL.md b/docs/COW_ORDER_DEBUG_SKILL.md new file mode 100644 index 0000000000..387b8d66ae --- /dev/null +++ b/docs/COW_ORDER_DEBUG_SKILL.md @@ -0,0 +1,627 @@ +# CoW Protocol Order Debug Skill + +Debug why CoW Protocol orders fail to match. Requires DB access + Victoria Logs access (via CoW-Prod MCP). + +## Quick Checklist + +Run through these in order: + +1. [ ] **Order status** — Check API status first (cancelled/expired/fulfilled/open) +2. [ ] **User cancellation** — If cancelled, search logs for `"order cancelled" AND all:ORDER_UID` FIRST +3. [ ] **Order in auction** — Was order in autopilot auction? When? +4. [ ] **Solver bids** — Did any solver bid? What happened to their solution? +5. [ ] **Settlement outcome** — Did settlement succeed/fail/timeout? +6. [ ] **Limit price sanity** — Was quote reasonable? Check slippage, fees, gas +7. [ ] **Price movement** — Did price move between quote and expiry? + +--- + +## 1. Fetch Order Data + +```bash +# Replace $NETWORK (mainnet/gnosis/arbitrum) and $ORDER_UID +curl -s "https://api.cow.fi/$NETWORK/api/v1/orders/$ORDER_UID" | jq . + +# For staging orders: +curl -s "https://barn.api.cow.fi/$NETWORK/api/v1/orders/$ORDER_UID" | jq . +``` + +### GPV2Order Struct (Smart Contract Source of Truth) + +| Field | Meaning | Debug Notes | +|-------|---------|-------------| +| `sellToken` | Token being sold | | +| `buyToken` | Token being bought | | +| `sellAmount` | Amount to sell (wei) | For sell orders, this is exact | +| `buyAmount` | Min amount to receive | For buy orders, this is exact | +| `validTo` | Unix timestamp expiry | Check if expired | +| `appData` | Hash of metadata JSON | Contains hooks, partner fees, flash loan hints | +| `feeAmount` | **Legacy, always 0** | Fee now in limit price | +| `kind` | "sell" or "buy" | | +| `partiallyFillable` | bool | Swaps = false (fill-or-kill), limits can be true | +| `sellTokenBalance` | **Legacy, always "erc20"** | Balancer vault balances never took off | +| `buyTokenBalance` | **Legacy, always "erc20"** | | +| `signingScheme` | eip712/ethsign/presign/eip1271 | See signing section | +| `signature` | The actual signature bytes | | +| `receiver` | Who gets buy tokens | null = order owner | + +**Additional API fields:** +- `class`: "market" vs "limit" — see note below +- `status`: fulfilled/open/cancelled/expired +- `surplusFee`: Protocol's fee estimate for limit orders +- `surplusFeeTimestamp`: Must be <10 min old or order won't enter auction + +**Note on order class:** In the DB, almost every order is stored as `class = 'limit'`. The "market" vs "limit" distinction is about **fee policy**, not order type: +- **Market order**: Had a quote attached, and the order's limit price is within that quote (in-market). Gets market fee policy. +- **Limit order**: Either no quote, or limit price is outside the quote (out-of-market). Gets limit fee policy with surplus fee. + +The `appData.metadata.orderClass` field shows what the UI intended, but the actual classification is determined by comparing the order's price to the quote at placement time. + +--- + +## 2. Signing Schemes + +Orders can fail if signature validation fails. Different schemes have different failure modes: + +| Scheme | Type | Validation | Common Failures | +|--------|------|------------|-----------------| +| `eip712` | EOA | Static, checked once | Sig doesn't match order fields, or signed by unexpected user | +| `ethsign` | EOA (legacy) | Static, checked once | Same as above | + +**Note on unexpected signers:** The majority of signature issues are valid signatures but signed by an unexpected user. This causes the settlement contract to attempt transferring tokens from an account that doesn't have the necessary balance. +| `presign` | Smart contract | On-chain state (`setPreSignature`) | User called `setPreSignature(uid, false)` to cancel | +| `eip1271` | Smart contract | Calls `isValidSignature()` at settlement time | Contract state changed, Safe signer removed, custom logic rejects | + +**EIP-1271 is dynamic** — signature can be valid at order placement but invalid later. Autopilot re-checks these every auction. + +```bash +# Check if presign is set (returns signed boolean) +cast call $SETTLEMENT_CONTRACT "preSignature(bytes)" $ORDER_UID --rpc-url $RPC +``` + +--- + +## 3. Check Logs (Victoria Logs via MCP) + +Logs are stored in Victoria Logs and accessible via the `CoW-Prod` MCP tools. Use `mcp__CoW-Prod__victorialogs_query` for log searches. Timestamps must be RFC3339 format (compute from current date). + +**IMPORTANT — Protect context window**: Always append `| fields _time, _msg, all` to queries to strip kubernetes/ec2 metadata (~4KB per entry). Use small `limit` values (10-20). When you only need specific fields, use `| fields _time, _msg, parsed.fields.err, parsed.fields.driver` etc. + +**Example queries (use `victorialogs_query` tool):** +``` +# All order logs (exclude nginx controller, filter by network, strip metadata) +query: "container:!controller AND network:$NETWORK AND all:ORDER_UID | fields _time, _msg, all" +start: "<24h-ago-RFC3339>" +limit: 20 + +# Search by quote ID +query: "container:!controller AND network:$NETWORK AND all:22788649 | fields _time, _msg, all" + +# Search specific solver +query: "container:!controller AND network:$NETWORK AND baseline AND all:22788649 | fields _time, _msg, all" +``` + +**Useful filters (part of the LogsQL expression):** +- `container:!controller` — excludes nginx access logs (REQUIRED for order UID searches) +- `network:$NETWORK` — **always include when debugging an order** to filter by chain (mainnet, bnb, arbitrum-one, base, etc). Reduces noise and speeds up queries. +- `all:` — prefix for searching structured fields (order UIDs, auction IDs, quote IDs). Without a field prefix, Victoria Logs only searches the log message text, not structured fields. You can also use `parsed.fields.order_uid:0x...` for precise matching, but `all:` works universally. +- `| fields _time, _msg, all` — **always append** to strip k8s metadata and protect context window + +**Note:** Always use the **full order UID with 0x prefix** and the `all:` field prefix for reliable matching. + +**IMPORTANT - Run targeted lifecycle queries in parallel** (use FULL order UID with 0x). Call multiple `victorialogs_query` MCP tools simultaneously. Always include `network:$NETWORK` and `| fields` pipe: + +``` +# Order creation +query: "container:!controller AND network:$NETWORK AND \"order created\" AND all:ORDER_UID | fields _time, _msg, all" + +# Order cancellation +query: "container:!controller AND network:$NETWORK AND \"order cancelled\" AND all:ORDER_UID | fields _time, _msg, all" + +# Proposed solutions +query: "container:!controller AND network:$NETWORK AND \"proposed solution\" AND all:ORDER_UID | fields _time, _msg, all" + +# Settlement failures (use specific parsed fields for concise output) +query: "container:!controller AND network:$NETWORK AND \"settlement failed\" AND all:ORDER_UID | fields _time, _msg, parsed.fields.err, parsed.fields.driver, parsed.spans.auction.auction_id" + +# Filtering +query: "container:!controller AND network:$NETWORK AND filtered AND all:ORDER_UID | fields _time, _msg, all" + +# Find discarded solutions (use order UID bytes without 0x prefix) +query: "container:!controller AND network:$NETWORK AND discarded AND all:ORDER_UID_WITHOUT_0X | fields _time, _msg, all" +``` + +**What to look for:** +- `order created` — order placement with quote_id +- `New orders in auction` — order entered auction +- `computed solutions` — solver found a route +- `solved auction` — solver submitted winning bid +- `filtered out in-flight` — order being settled +- `order cancelled` — user cancelled via API + +**Get auction competition data:** +```bash +curl -s "https://api.cow.fi/$NETWORK/api/v1/solver_competition/$AUCTION_ID" | jq . +``` + +--- + +## 4. Common Log Patterns + +**IMPORTANT:** Many log messages use **spaces** not underscores (e.g., `order cancelled` not `order_cancelled`). + +**Order lifecycle (search by order UID):** +``` +orderbook::api::post_order: order created # Order placed +autopilot::run_loop::observe: New orders in auction # Added to auction +driver::infra::observe: computed solutions # Solver found route +driver::infra::observe: solved auction # Solver won +autopilot::run_loop: filtered out in-flight # Being settled +autopilot::run_loop: settlement failed # Settlement failed (check err=) +orderbook::orderbook: order cancelled # User cancelled via API +``` + +**Issues to watch for:** +- `order cancelled` — user cancelled the order (check timestamp vs settlement!) +- `settlement failed err=Timeout` — driver timed out during settlement +- `settlement failed` — settlement failed (other reasons) +- `filtered` — order excluded from auction (check reason) +- `error` or `Error` — something went wrong +- `revert` — simulation or settlement failed +- `insufficient_balance` / `insufficient_allowance` — user moved funds + +--- + +## 5. Quote History + +### Method 1: API response (easiest) +The order API response includes the quote that was used: + +```bash +curl -s "https://api.cow.fi/$NETWORK/api/v1/orders/$ORDER_UID" | jq '.quote' +``` + +Returns: +```json +{ + "sellAmount": "4300531427036176000", + "buyAmount": "16788289774218687968", + "feeAmount": "3270684063997860", + "solver": "0x3980daa7eaad0b7e0c53cfc5c2760037270da54d", + "verified": true, + ... +} +``` + +### Method 2: Database +```sql +SELECT q.id, q.sell_amount, q.buy_amount, q.gas_amount, q.solver, q.created +FROM quotes q +JOIN order_quotes oq ON oq.quote_id = q.id +WHERE oq.order_uid = '\x$ORDER_UID_HEX'; +``` + +### Method 3: Logs (fallback) +Find the quote_id from the "order created" log using `victorialogs_query`: + +``` +query: "container:!controller AND network:$NETWORK AND \"order created\" AND all:ORDER_UID | fields _time, _msg, all" +``` + +**Example log line:** +``` +orderbook::api::post_order: order created order_uid=0x... quote_id=Some(2720468) quote_solver=Some(0x3980...) +``` + +Then search for quote details by ID: +``` +query: "container:!controller AND network:$NETWORK AND all:$QUOTE_ID | fields _time, _msg, all" +``` + +--- + +## 6. Quoting Deep Dive + +Quotes determine the limit price users sign. Bad quotes = orders that can't fill. + +### Quote Process + +``` +UI requests quote → Orderbook sends "fake auction" (single order, infinite slippage) to all solvers + ↓ + Solvers return: exchange rate + calldata (recipe) + ↓ + In parallel, orderbook also fetches: + - Gas price estimate + - Native price of sell token (to convert gas cost) + - Native price of buy token (needed for surplus scoring later) + ↓ + Simulate winning solver's calldata → get gas units + ↓ + network_fee = gas_units × gas_price / sell_token_native_price + ↓ + Return quote with exchange rate + network fee +``` + +### Quote Types + +| Type | Behavior | Use Case | +|------|----------|----------| +| **Fast** | Returns after first 3 solver responses, always unverified | UI responsiveness | +| **Optimal** | Waits for all solvers (5s timeout), attempts verification | Actual order placement | +| **Native** | Cached quote for "buy 0.1 ETH with token X" | Native price lookups | + +**Verified vs Unverified:** +- Verified = simulation succeeded, high confidence quote is achievable +- Unverified = simulation failed or skipped, solver might have bad math + +### Limit Price Calculation + +``` +min_buy_amount = (sell_amount - network_fee) × exchange_rate × (1 - slippage) × (1 - partner_fee) +``` + +**Smart slippage**: Smaller orders get higher slippage bc network fee dominates. A 10% gas price spike on a $10 order (where fee is ~$2) eats way more than on a $1M order. + +--- + +## 7. Order Placement Validation + +Orderbook rejects orders that have no chance of executing. Checks: + +| Check | Failure Mode | +|-------|--------------| +| Signature valid | Bad sig, wrong signer | +| Balance sufficient | Fill-or-kill needs full amount, partial needs >0 | +| Approval set | Need approval on GPV2VaultRelayer (not settlement contract directly) | +| AppData pre-image exists | AppData JSON must be provided in full with order, or pre-image must be added to backend beforehand | +| Rate limit | Too many orders per trader | +| Quote attached + valid | If quote ID provided, must exist and match | + +**If order placed without quote** (common for bots): Orderbook re-quotes to classify as market vs limit order. + +--- + +## 8. Autopilot Filtering (Why Order Not In Auction) + +Even after placement, autopilot filters orders each auction. Current filters: + +| Filter | Why | +|--------|-----| +| Signature re-check | presign/eip1271 can become invalid | +| Balance re-check | User moved funds | +| Native price exists | Can't score surplus without ETH-denominated value | +| Fee policy applied | Protocol fee calculation | + +**Mainnet currently has ~6000 orders in auction** — drivers also do their own prioritization/filtering. + +--- + +## 9. Limit Order Specific Checks + +### 9.1 Surplus Fee Validation + +```bash +# From order JSON, verify: +surplusFee != null +surplusFeeTimestamp is within last 10 minutes +``` + +**If missing/stale, check surplus fee computation logs:** +``` +query: "network:$NETWORK AND surplus_fee AND all:ORDER_UID | fields _time, _msg, all" +``` + +**Surplus fee error logs:** +``` +query: "network:$NETWORK AND surplus_fee AND error | fields _time, _msg, all" +``` + +### 9.2 Auction Filtering Check + +```bash +# Check if order is in current auction: +curl -s "https://api.cow.fi/$NETWORK/api/v1/auction" | jq '.orders[] | select(.uid == "$ORDER_UID")' +``` + +If not present, order is filtered. Check filter logs: +``` +query: "network:$NETWORK AND filtered AND all:ORDER_UID | fields _time, _msg, all" +``` + +**Common filter reasons:** +- `insufficient_balance` +- `insufficient_allowance` +- `invalid_signature` (ERC-1271 state changed, presign cancelled) +- `pre_interaction_error` +- `no_native_price` (can't get ETH price for buy token) + +### 9.3 Market Price Verification + +Compute effective sell amount: +``` +effectiveSellAmount = sellAmount - surplusFee +``` + +**For SELL orders:** +```bash +curl -s -X POST "https://barn.api.cow.fi/$NETWORK/api/v1/quote" \ + -H 'content-type: application/json' \ + -d '{ + "from": "$OWNER", + "sellToken": "$SELL_TOKEN", + "buyToken": "$BUY_TOKEN", + "kind": "sell", + "sellAmountAfterFee": "$EFFECTIVE_SELL_AMOUNT" + }' | jq '.quote.buyAmount' +``` +→ Order's `buyAmount` should be **less than** this quote. + +**For BUY orders:** +```bash +curl -s -X POST "https://barn.api.cow.fi/$NETWORK/api/v1/quote" \ + -H 'content-type: application/json' \ + -d '{ + "from": "$OWNER", + "sellToken": "$SELL_TOKEN", + "buyToken": "$BUY_TOKEN", + "kind": "buy", + "buyAmountAfterFee": "$BUY_AMOUNT" + }' | jq '.quote.sellAmount' +``` +→ Order's `effectiveSellAmount` should be **greater than** this quote. + +--- + +## 10. Settlement Flow (On-Chain) + +When driver wins, it has 2-3 blocks to land the tx. + +### Settlement Contract Execution Order + +```solidity +settle( + IERC20[] tokens, // All tokens involved + uint256[] clearingPrices, // Exchange rates + Trade[] trades, // Orders being filled + Interaction[][3] interactions // [pre, main, post] +) +``` + +**Execution sequence:** +1. **Pre-interactions** — Solver prep + user pre-hooks (unstaking, approvals, etc) +2. **For each trade:** + - Convert Trade → Order struct + - Verify signature (presign/eip1271 checked NOW) + - Compute transfer amounts + - Update filledAmounts mapping (replay protection) + - Transfer sell tokens INTO settlement contract +3. **Main interactions** — The actual swaps/routing (Uniswap calls, etc) +4. **Pay out** — Transfer buy tokens to receivers, enforce min amounts +5. **Post-interactions** — Solver cleanup + user post-hooks (bridging, etc) + +### Driver Submission Behavior + +- Uses private RPCs (MEV Blocker) to avoid failed tx costs + get MEV protection +- Gas bumps on each block if not included +- Monitors chain state, cancels if settlement becomes invalid (liquidity moved, etc) +- **Penalty** if solution proposed but not settled + +--- + +## 11. Auction Runtime Issues + +Order is in auction but still not matching? + +**Auction orders log:** +``` +query: "network:$NETWORK AND all:$AUCTION_ID | fields _time, _msg, all" +``` + +**Specific auction run:** +``` +query: "network:$NETWORK AND all:$RUN_ID | fields _time, _msg, all" +``` + +### JIT Orders & CoW AMMs + +Solvers can inject "just-in-time" orders (e.g., from market makers). These normally don't count toward surplus scoring bc they're not public. + +**Exception:** CoW AMM contracts are whitelisted — autopilot includes "surplus capturing JIT order owners" in auction. Orders from these contracts DO count for surplus. + +If debugging a CoW AMM interaction, check if the AMM contract is in the whitelist. + +--- + +## 12. Circuit Breaker Monitoring + +The circuit breaker watches all on-chain settlements and compares against off-chain auction outcomes. + +**It enforces:** +- Winning solver is actually the one settling +- Settled amounts match reported amounts +- No protocol violations + +**Violations → solver jailed** (deny-listed until they contact team, explain, fix). + +Check circuit breaker logs if solver claims they won but settlement didn't happen or was rejected. + +--- + +## 13. DB Queries (Direct Access) + +### Check order state in DB: +```sql +SELECT + uid, creation_timestamp, owner, sell_token, buy_token, + sell_amount, buy_amount, valid_to, kind, class, + surplus_fee, surplus_fee_timestamp +FROM orders +WHERE uid = '\x$ORDER_UID_HEX'; +``` + +### Check order lifecycle events: +The `order_events` table tracks order state changes. This is often the fastest way to understand what happened. + +```sql +SELECT timestamp, label::text +FROM order_events +WHERE order_uid = '\x$ORDER_UID_HEX' +ORDER BY timestamp; +``` + +**Event labels:** +| Label | Meaning | +|-------|---------| +| `created` | Order was placed | +| `ready` | Order ready for auction inclusion | +| `considered` | Order was considered in an auction | +| `executing` | Order is being settled (in-flight) | +| `traded` | Order was filled on-chain | +| `cancelled` | User cancelled the order | +| `filtered` | Order was filtered out of auction | +| `invalid` | Order became invalid (balance/allowance/signature) | + +**Example lifecycle:** `created` → `ready` → `considered` → `executing` → `traded` + +### Check quotes for order: +```sql +SELECT + q.id, q.sell_token, q.buy_token, q.sell_amount, q.buy_amount, + q.gas_amount, q.solver, q.created +FROM quotes q +JOIN order_quotes oq ON oq.quote_id = q.id +WHERE oq.order_uid = '\x$ORDER_UID_HEX'; +``` + +### Check auction inclusion history: +```sql +SELECT + auction_id, order_uid, included, filtered_reason +FROM auction_orders +WHERE order_uid = '\x$ORDER_UID_HEX' +ORDER BY auction_id DESC +LIMIT 20; +``` + +You can also check attempts in `settlement_executions` tables. + +### Check successful settlements: +```sql +SELECT + tx_hash, solver, order_uid, executed_sell_amount, executed_buy_amount +FROM settlements s +JOIN trades t ON t.settlement_id = s.id +WHERE t.order_uid = '\x$ORDER_UID_HEX'; +``` + +### Check presignature events (for presign orders): +```sql +SELECT block_number, signed +FROM presignature_events +WHERE order_uid = '\x$ORDER_UID_HEX' +ORDER BY block_number; +``` +If `signed = false`, the user revoked their presignature on-chain. + +--- + +## 14. AppData Deep Dive + +AppData is a hash of a JSON document (the JSON must be provided in full or its pre-image registered beforehand). **Cannot be verified on-chain** (smart contract just sees hash), so all enforcement is off-chain/soft. + +### Common AppData Fields + +```json +{ + "version": "1.0.0", + "metadata": { + "partnerFee": { + "recipient": "0x...", + "bps": 30 + }, + "hooks": { + "pre": [{ "target": "0x...", "callData": "0x...", "gasLimit": "100000" }], + "post": [{ "target": "0x...", "callData": "0x...", "gasLimit": "100000" }] + }, + "flashLoan": { + "lender": "0x...", + "token": "0x...", + "amount": "1000000000000000000" + } + } +} +``` + +**Debug implications:** +- Partner fee misconfigured → order's effective price is wrong +- Pre-hook fails → settlement reverts at pre-interaction stage +- Post-hook fails → settlement reverts after swaps (user loses gas but trade doesn't complete) +- Flash loan hints help solver but don't guarantee execution + +```bash +# Fetch appData content +curl -s "https://api.cow.fi/$NETWORK/api/v1/app_data/$APP_DATA_HASH" +``` + +--- + +## 15. Useful Links + +| Resource | URL | +|----------|-----| +| Order Explorer | `https://explorer.cow.fi/orders/$ORDER_UID` | +| Victoria Logs | Via `CoW-Prod` MCP tools (`victorialogs_query`, etc.) | +| API Docs | `https://api.cow.fi/docs/` | +| Block-to-Date | `https://etherscan.io/blockdateconverter` | +| Barn (Staging) | `https://barn.cow.fi` | +| Settlement Contract | `0x9008D19f58AAbD9eD0D60971565AA8510560ab41` | + +--- + +## 16. Decision Tree + +``` +Order not matched? +│ +├─ Is order in auction? +│ ├─ NO → Check autopilot logs for filter reason +│ │ → Common: balance, allowance, signature, no native price +│ │ +│ └─ YES → Did solvers bid? +│ ├─ NO → Price probably out of market +│ │ → Verify with quote API +│ │ → Check price movement since quote +│ │ +│ └─ YES → What happened to winning bid? +│ → Check solver pod for revert/error +│ → Get auction_id, check competition endpoint +│ +├─ Is it a limit order? +│ └─ Has surplusFee? Is it fresh (<10min)? +│ → NO: Check surplus fee computation logs +│ +├─ Check signing scheme +│ └─ presign/eip1271? → State may have changed since placement +│ +└─ Check appData + └─ Hooks defined? → Pre/post hook might be failing +``` + +--- + +## 17. Common Root Causes + +| Symptom | Likely Cause | Fix | +|---------|--------------|-----| +| No surplusFee | Quote computation failed | Check estimator logs | +| surplusFee stale | Background task stuck | Escalate to #backend | +| Filtered: insufficient_balance | User moved funds | Wait for rebalance | +| Filtered: invalid_signature | ERC-1271/presign state changed | User must re-sign or re-presign | +| Filtered: no_native_price | Can't price buy token in ETH | Token has no liquidity path to ETH | +| No solver bids | Price out of market | User adjusts limit | +| Solver bid reverted | Liquidity changed between auction and settlement | Normal MEV/timing | +| Quote outlier | Single estimator gave bad price | Check if quote was verified | +| Unverified quote accepted | Simulation failed but UI showed price anyway | User signed bad limit price | +| Pre-hook revert | User's pre-hook call failed | Check hook calldata + target | +| Gas estimate too low | API gas estimation bug | Known issue, being fixed | diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md new file mode 100644 index 0000000000..77d24b3d85 --- /dev/null +++ b/docs/ONBOARDING.md @@ -0,0 +1,205 @@ +# Onboarding: CoW Protocol Services (this repo) + +This repository is a Rust workspace containing the core backend services that run the CoW Protocol off-chain system: + +- Users submit **signed orders** to the **orderbook** +- **autopilot** periodically creates **auctions** and sends them to **drivers** +- Each **driver** calls its **solver(s)** for solutions, then simulates + submits the winner to the on-chain **Settlement** contract + +For local end-to-end development, use the playground stack. See `playground/README.md`. + +## System context (big picture) + +```mermaid +flowchart LR + U["User / Wallet"] -->|signed order| OB["orderbook"] + UI["CoW Swap UI"] -->|quotes / orders| OB + OB <--> DB[("PostgreSQL")] + AP["autopilot"] <--> DB + AP -->|auction| DR["driver"] + AP -->|auction| CO["colocated solvers\n(own driver + solver)"] + + DR -->|auction request| IS["internal solvers"] + DR -->|auction request| ES["external solver APIs"] + + DR -->|simulate + submit tx| CH[("EVM chain\n+ Settlement contract")] + CO -->|submit tx| CH + AP -->|index events| CH +``` + +## Core "happy path" flow (order → auction → settlement) + +```mermaid +sequenceDiagram + autonumber + participant User + participant Orderbook as orderbook + participant DB as Postgres + participant Autopilot as autopilot + participant Driver as driver + participant Solver as solver(s) + participant Chain as EVM chain + Settlement contract + + User->>Orderbook: GET /quote (fee + price estimate) + Orderbook-->>User: quote response + User->>Orderbook: POST /orders (signed order) + Orderbook->>Orderbook: validate (signature, app-data, funding/approval, etc.) + Orderbook->>DB: persist order + order events + Orderbook-->>User: 201 Created (order uid) + + loop every new block (~12s on mainnet) + Autopilot->>DB: fetch eligible orders + state + Autopilot->>Autopilot: apply policies (fees, filtering, scoring inputs) + Autopilot->>DB: store current auction + competition metadata + Autopilot->>Driver: send auction (or make it available for fetch) + + Driver->>Solver: request solution(s) for auction + Solver-->>Driver: proposed solution(s) + Driver->>Driver: encode calldata + simulate + Driver-->>Autopilot: submit bid(s) + Autopilot->>Autopilot: rank bids, pick winner + Autopilot->>Driver: tell winner to execute + Driver->>Chain: submit transaction (time-bounded) + Chain-->>Chain: execute settle(...) + emit events + Autopilot->>Chain: fetch + index relevant events + Autopilot->>DB: update competition/settlement tables + order events + end +``` + +## Solver types + +- **Colocated**: External partners run their own driver + solver. Autopilot sends them the auction and they submit solutions independently. Full control, full responsibility. +- **Non-colocated**: We run the driver, configured with their solver API endpoint. We handle simulation and submission on their behalf. + +## Responsibilities by service (what to touch for what change) + +```mermaid +flowchart TB + subgraph OB["orderbook"] + OB1["HTTP API: orders, quotes, status"] + OB2["Validations: signatures, app-data, funding/approval checks"] + OB3["Persists orders + lifecycle events"] + end + + subgraph AP["autopilot"] + AP1["Auction cutting: boundaries + inclusion"] + AP2["Filtering + fee policies + scoring inputs"] + AP3["Event indexing + competition metadata"] + end + + subgraph DR["driver"] + DR1["Receive auction + fetch liquidity context"] + DR2["Call internal/external solvers"] + DR3["Encode solution to calldata, simulate"] + DR4["Submit tx, manage retries/time window"] + end + + subgraph S["solvers"] + S1["Pure routing/matching math"] + S2["Return solution objects/calldata recipe"] + end + + subgraph DBL["database layer"] + DBL1["migrations + schema"] + DBL2["typed query helpers used by services"] + end + + AP --> DR + OB --> DBL + AP --> DBL + DR --> S +``` + +## Key crates (where shared logic lives) + +- `crates/shared`: common utilities (order quoting/validation, fee logic, external prices, argument parsing) +- `crates/price-estimation`: price estimation strategies (onchain, trade-based, native) +- `crates/gas-price-estimation`: gas price estimation +- `crates/database`: schema + DB helpers used by `orderbook` and `autopilot` +- `crates/model`: API/data model types used across services +- `crates/contracts`: Alloy-based contract bindings for on-chain interaction +- `crates/ethrpc` + `crates/chain`: Ethereum RPC / chain interaction helpers +- `crates/observe`: logging/metrics initialization helpers +- `crates/app-data`: order app-data validation + +## Where to start reading code (practical entrypoints) + +Each service follows the same pattern: `main.rs` just sets up the allocator and calls `start()`, which lives in `run.rs`. The `run.rs` file parses CLI arguments, initializes logging/metrics, connects to the database and/or chain, and wires up the service components. + +- **Orderbook (HTTP API + order validation)** + - Start here: `crates/orderbook/src/run.rs` (initialization + service wiring) + - Typical changes: API endpoints, order validation, quoting, DB writes + +- **Autopilot (auction creation + policies + event indexing)** + - Start here: `crates/autopilot/src/run.rs` + - Typical changes: auction filtering/inclusion, fee policies, competition persistence, chain event indexing + +- **Driver (simulation + settlement submission + solver integration)** + - Start here: `crates/driver/README.md` for context, then `crates/driver/src/run.rs` + - Typical changes: solver API integration, encoding/calldata, simulation logic, submission strategy + +- **Solvers (internal solver engines)** + - Start here: `crates/solvers/src/run.rs` + - Typical changes: routing/matching math, solution generation + +- **On-chain bindings** + - Start here: `crates/contracts/README.md` + - Typical changes: adding new contract artifacts/bindings, updating ABIs, exposing bindings in `lib.rs` + +- **Database schema + migrations** + - Start here: `database/README.md` (schema overview) and `crates/database` (query code) + +- **End-to-end tests** + - Start here: `crates/e2e/tests/e2e/` (individual test scenarios) and `crates/e2e/src/setup/` (test harness) + - The e2e crate spins up a local Anvil node (optionally forking mainnet/Gnosis), deploys contracts, starts services (orderbook, autopilot, driver, solver), and runs full order→settlement flows + - Tests are split into `local_node` (clean chain) and `forked_node` (forking a real network via `FORK_URL_MAINNET` / `FORK_URL_GNOSIS`) + - Run local e2e tests: `cargo nextest run -p e2e local_node --test-threads 1 --failure-output final --run-ignored ignored-only` + - Run forked e2e tests: `cargo nextest run -p e2e forked_node --test-threads 1 --run-ignored ignored-only --failure-output final` + +## Local development (recommended path) + +### Run the full stack (best for onboarding) + +See `playground/README.md`. The short version is: + +```bash +docker compose -f playground/docker-compose.fork.yml up --build +``` + +You'll need to set `ETH_RPC_URL` in `playground/.env` first (an Ethereum RPC endpoint for anvil to fork from). This starts a forked chain + Postgres + services + UI/Explorer components with live-reload behavior. + +### Fast local compile / test loop (without running the stack) + +- **Check**: + +```bash +cargo check --workspace --all-targets +``` + +- **Unit tests (CI-compatible runner)**: + +```bash +cargo nextest run +``` + +### Formatting and linting + +This repo formats Rust code with nightly rustfmt (and TOML with Tombi). See `README.md` for the `just` commands. + +## Database mental model (what’s in Postgres) + +The DB stores orders, auctions, competitions, and indexed on-chain events. + +- For a guided schema overview, see `database/README.md`. + +```mermaid +flowchart LR + OB["orderbook"] -->|orders + order_events + quotes| DB[("Postgres")] + AP["autopilot"] -->|auctions + competitions + event-derived tables| DB + AP -->|fetch + index chain events| CH[("chain")] +``` + +## Debugging "why didn’t my order trade"? + +When you need to investigate an order lifecycle end-to-end (API → DB → logs → auction inclusion → solver bids → settlement), +see [`COW_ORDER_DEBUG_SKILL.md`](./COW_ORDER_DEBUG_SKILL.md). diff --git a/docs/QUOTE_VERIFICATION_DEBUG_SKILL.md b/docs/QUOTE_VERIFICATION_DEBUG_SKILL.md new file mode 100644 index 0000000000..d6f7c196de --- /dev/null +++ b/docs/QUOTE_VERIFICATION_DEBUG_SKILL.md @@ -0,0 +1,464 @@ +--- +name: debug-quote +description: Debugs why the backend returned a given quote. It does that by inspecting the quote competition as a whole and re-simulating individual quotes when it makes sense. +--- + +## When to use + +- User has a `quote_id`, `trace_id`, or `request_id` and asks why a quote failed / why a specific solver didn't verify. +- User wants per-estimator root-cause across all solvers that ran for one quote. +- User reports a class of failures ("lots of OOG on bitget today") and wants tracing. +- User wants to know **by how much** an `out_amount` claim missed reality (slippage / depth) or **by how much** balance/allowance was short. + +## Requirements + +| Need | For what | +|---|---| +| `CoW-Prod` MCP (VictoriaLogs) | All steps — pulling logs | +| `$ETH_MAINNET_RPC` env var | Replay options A (raw RPC) and C (cast) | +| `$TENDERLY_ACCESS_TOKEN` | Replay option B (Tenderly) — needed for the saved/shareable simulation link | +| `cast` (foundry, in `$PATH`) | Replay option C only | + +The replay node must support `debug_traceCall` with `stateOverrides`. + +## Inputs + +- **`quote_id`** (decimal, e.g. `1158617496`) — primary key for verification failures; resolve to `trace_id` in step 1. +- **`trace_id`** (32-hex) — direct. +- **`request_id`** (32-hex) — same per-quote, redundant but useful for cross-checking. +- **token pair** (sell + buy, symbol or address) and optionally the **trader wallet** — typical "Insufficient Liquidity" report has no quote_id (the orderbook returns an error instead of a quote). Resolve to `trace_id` in step 1b. +- network — this skill assumes mainnet; adapt the container name (`-api-prod`) for other chains. + +## What you'll find out + +For each failed estimator: the settle calldata the verifier asked the chain to execute (the `0x1d47e7f4` helper wraps `GPv2Settlement.settle()`), the full call tree, the deepest revert (selector + decoded data), and whether it's a real routing/liquidity bug, a verifier infra bug (gas cap, Permit2 override), or a solver-encoder bug (missing approve, empty interactions, wrong selector). + +--- + +## Step 1 — `quote_id` → `trace_id` + +If you only have a `quote_id`, look up the trace: + +``` +container:="mainnet-api-prod" AND all:"" AND _msg:="finished computing quote" +| fields _time, parsed.trace_id, parsed.fields.response +``` + +The `parsed.fields.response` field contains the `OrderQuoteResponse` (sell/buy tokens, amounts, the winning estimator's `verified:` flag, etc.). Save the `trace_id` for steps 2–4. + +## Step 1b — token pair (+ optionally wallet) → `trace_id` + +When the user reports "Insufficient Liquidity for X→Y" with no `quote_id` (no quote was produced, so no id was minted), find the trace from the token pair instead. + +### Resolve symbols to addresses + +If the user gave a *symbol* (e.g. `tGLD`): + +1. **First stop: cowprotocol/token-lists** — https://github.com/cowprotocol/token-lists is the canonical CoW Swap UI token list. Each chain has its own JSON; grep by `"symbol"`. Symbols are not unique (e.g. `tGLD` resolves to both Tenbin Gold *and* TempleGold on mainnet), so confirm against the address the user actually used if known. +2. Verify any candidate against the chain by probing `name()`/`symbol()`/`decimals()`: + ```bash + ETH_MAINNET_RPC=... + ADDR=0x... + for sel in 0x06fdde03 0x95d89b41 0x313ce567; do + curl -s -X POST -H 'Content-Type: application/json' \ + --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"'$ADDR'","data":"'$sel'"},"latest"],"id":1}' $ETH_MAINNET_RPC + done + ``` + ABI-decode each result (string for `name`/`symbol`, uint8 for `decimals`). +3. If the symbol isn't in the token list and you can't get it from the user, **ask** rather than guessing — many tokens share popular tickers, and a wrong address means an empty trace search and wasted effort. + +### Find the trace + +The `calculate_quote` span carries `sell_token` and `buy_token` directly on every `new price estimate` row. Filter on both, then group by `trace_id`: + +``` +container:="mainnet-api-prod" + AND _msg:="new price estimate" + AND parsed.spans.calculate_quote.sell_token:"" + AND parsed.spans.calculate_quote.buy_token:"" +| stats by (parsed.trace_id) count() as count +``` + +For a fully no-liquidity case, every estimator returned `Err(...)` and the request_summary status is **404** (the orderbook returns 404 for `OrderQuoteError::Estimator(NoLiquidity)` — *not* 400; 400 means validation/bad-input, which is a different failure mode). Cross-reference to confirm: + +``` +container:="mainnet-api-prod" + AND _msg:="request_summary" + AND parsed.fields.uri:"/api/v1/quote" + AND parsed.fields.status:"404" + AND parsed.trace_id:"" +``` + +A given UI usually fires both `priceQuality: optimal` *and* `priceQuality: fast` in parallel for the same pair, so expect two trace_ids per user attempt with the same sell/buy. The ones with optimal quality are preferred for the per-estimator analysis; pick the most recent. + +### Narrow by wallet (optional) + +If the user gave their wallet address, filter further on the `from` field. `from` is *not* on the `parsed.spans.calculate_quote` span — it lives inside the `Query { ... }` block stored in `parsed.fields.query` on each `new price estimate` row, formatted like `from: 0xabcd…`. Substring-match it: + +``` +container:="mainnet-api-prod" + AND _msg:="new price estimate" + AND parsed.spans.calculate_quote.sell_token:"" + AND parsed.spans.calculate_quote.buy_token:"" + AND parsed.fields.query:"from: 0xWALLET_LOWERCASE" +| stats by (parsed.trace_id) count() as count +``` + +When `from` is unknown, the orderbook substitutes the verifier-default placeholder `0xd711bd26bf5b153001a7c0accb289782b6f775e9` (or `0x0000…0000` for some `priceQuality: fast` paths) — matching that filters out user-specific traces but keeps default ones. Useful when distinguishing "user without wallet connected" from "user with a specific wallet". + +### Sanity check before continuing + +Pull the per-estimator results for the candidate trace (step 2's first query). The shape tells you which sub-flow to follow: + +- All estimators `Err(...)` → no-liquidity case; the diagnosis is "which native estimators were asked, what did they return, was the relevant solver wired in?" (see step 5 + the autopilot native-price audit pattern) +- One or more `Ok(... verified: true)` returned but the orderbook still 404'd → ranking-context failure (e.g. autopilot native price returned `Err(NoLiquidity)` for the buy token, short-circuiting `BestBangForBuck`). Search `mainnet-autopilot-prod` logs for the buy_token to see what each native estimator returned. +- `Ok(... verified: false)` with `quote verification failed` log lines → the regular per-estimator verification flow; jump to step 3. + +## Step 2 — Pull the quote envelope (per-estimator bids + which failed) + +``` +container:="mainnet-api-prod" + AND parsed.trace_id:="" + AND _msg:="new price estimate" +| fields _time, parsed.fields.estimator, parsed.fields.result +``` + +Each row: `estimator`, then `Ok(Estimate { out_amount, gas, solver, verified, .. })` or `Err(NoLiquidity | EstimatorInternal(...))`. Filter by `verified: false` for the candidates worth replaying. + +To list verification failures with their err selectors: + +``` +container:="mainnet-api-prod" + AND parsed.trace_id:="" + AND _msg:="quote verification failed" +| extract_regexp `data: "(?P0x[0-9a-f]{8})` from parsed.fields.err +| stats by (parsed.spans.estimator.name, sel) count() as count +``` + +A bare `execution reverted` (no `data:` field in the err) is its own failure mode — see the playbook in step 5. + +## Step 3 — Fetch each failed estimator's resimulate-curl + +``` +container:="mainnet-api-prod" + AND parsed.trace_id:="" + AND _msg:~"^resimulate by setting" + AND parsed.spans.estimator.name:="" +``` + +The `_msg` is a `curl` command with a `--data ''` payload (20–90 KB: calldata + state overrides). When the MCP response exceeds ~25k tokens it auto-saves under `.claude/projects/.../tool-results/`; note the path. + +Extract the JSON payload to `/tmp/cow-trace/.json`: + +```bash +SRC= +mkdir -p /tmp/cow-trace +for est in $(jq -r '.[0].text' "$SRC" | jq -sr '.[] | .["parsed.spans.estimator.name"]' | sort -u); do + jq -r '.[0].text' "$SRC" \ + | jq -sr --arg e "$est" '.[] | select(.["parsed.spans.estimator.name"]==$e) | ._msg' \ + | grep -oP "(?<=--data ').*?(?=' https://api\.tenderly)" \ + > /tmp/cow-trace/$est.json +done +``` + +Each `.json` is the Tenderly /simulate body — also the input to all three replay options below. + +## Step 4 — Replay (pick one per use case) + +### Option A — reth `debug_traceCall` + `run_sim.py` (programmatic; preferred for root-causing) + +Drop this at `/tmp/cow-trace/run_sim.py`: + +```python +#!/usr/bin/env python3 +"""Replay a Tenderly /simulate payload via debug_traceCall. +Usage: run_sim.py [gas-decimal-override] +Env: ETH_MAINNET_RPC (default: cow public proxy); ALL_CALLS=1 to show non-failing branches. +""" +import json, os, sys, urllib.request + +KNOWN = { + "0x9008d19f58aabd9ed0d60971565aa8510560ab41": "GPv2Settlement", + "0xc92e8bdf79f0507f65a392b0ab4667716bfe0110": "GPv2VaultRelayer", + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "WETH", + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "USDC", + "0xdac17f958d2ee523a2206206994597c13d831ec7": "USDT", + "0x000000000022d473030f116ddee9f6b43ac78ba3": "Permit2", + "0xd524f98f554bd34f4185678f64a85bb98971d314": "0x AllowanceHolder", + "0x699c5bd4d03d98dabe8ef94ce13ba0314e4d35c8": "0x Settler", + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": "Native ETH", + "0xe592427a0aece92de3edee1f18e0157c05861564": "UniV3 SwapRouter", + "0x66a9893cc07d91d95644aedd05d03f95e1dba8af": "Universal Router (V4)", + "0x000000000004444c5dc75cb358380d2e3de08a90": "UniV4 PoolManager", + "0x0000000000000000000000000000000000020000": "verifier-helper-precompile", +} +def label(a): return KNOWN.get((a or "").lower(), (a or "?")[:10] + "…" + (a or "")[-4:]) +def sel(s): return (s or "")[:10] + +def post(p, url, gas_override=None): + overrides = {} + for addr, obj in (p.get("state_objects") or {}).items(): + ov = {} + for k_in, k_out in (("balance","balance"), ("code","code"), + ("nonce","nonce"), ("storage","stateDiff")): + if k_in in obj: ov[k_out] = obj[k_in] + overrides[addr] = ov + call = {"from": p["from"], "to": p["to"], "data": p["input"]} + if gas_override is not None: call["gas"] = hex(gas_override) + elif p.get("gas"): call["gas"] = hex(p["gas"]) + if p.get("gas_price"): call["gasPrice"] = hex(p["gas_price"]) + block = hex(p["block_number"]) if p.get("block_number") else "latest" + rpc = {"jsonrpc":"2.0","method":"debug_traceCall","params":[call, block, + {"tracer":"callTracer","tracerConfig":{"withLog":True},"stateOverrides":overrides}], + "id":1} + req = urllib.request.Request(url, method="POST", + data=json.dumps(rpc).encode(), headers={"Content-Type":"application/json"}) + return json.loads(urllib.request.urlopen(req, timeout=180).read()) + +def has_err(c): return bool(c.get("error") or c.get("revertReason")) or any(has_err(x) for x in c.get("calls") or []) + +def walk(c, depth=0, only_failed=True, out=None): + if out is None: out = [] + err, rev = c.get("error"), c.get("revertReason") + suffix = f" ❌ {err or ''}{' / '+rev if rev else ''}" if (err or rev) else "" + out.append(f"{' '*depth}{c.get('type','CALL')} {label(c.get('from'))} -> " + f"{label(c.get('to'))} sel={sel(c.get('input',''))} gas={c.get('gasUsed','?')}{suffix}") + o = c.get("output") or "" + if err and o and o != "0x": out.append(f"{' '*(depth+1)}↳ revert_data={o[:266]}") + for child in c.get("calls") or []: + if only_failed and not has_err(child) and not err: continue + walk(child, depth+1, only_failed, out) + return out + +def deepest(c, path=None): + if path is None: path = [] + me = path + [c]; d = None + for child in c.get("calls") or []: + r = deepest(child, me) + if r and (d is None or len(r[0]) > len(d[0])): d = r + if c.get("error") and (d is None or len(me) > len(d[0])): d = (me, c) + return d + +if __name__ == "__main__": + p = json.load(open(sys.argv[1])) + g = int(sys.argv[2]) if len(sys.argv) > 2 else None + url = os.environ.get("ETH_MAINNET_RPC") + print(f"# block={p.get('block_number','latest')} gas={'override='+str(g) if g else hex(p.get('gas',0))}") + res = post(p, url, g) + if "error" in res and "result" not in res: + print("# rpc error:", res["error"]); sys.exit(1) + for line in walk(res["result"], only_failed=os.environ.get("ALL_CALLS")!="1"): print(line) + d = deepest(res["result"]) + if d: + path, leaf = d + print(f"\n# DEEPEST REVERT (depth={len(path)})") + print(f"# to: {leaf.get('to')} sel: {sel(leaf.get('input',''))}") + print(f"# error: {leaf.get('error')}") + if leaf.get('output') and leaf['output'] != '0x': + print(f"# revert_data: {leaf['output'][:266]}") + for i, c in enumerate(path): + print(f"# {i}. {c.get('type')} {label(c.get('from'))} -> " + f"{label(c.get('to'))} sel={sel(c.get('input',''))}") + else: + print("# ✅ no revert at any depth") +``` + +```bash +python3 /tmp/cow-trace/run_sim.py /tmp/cow-trace/tsolver.json +ALL_CALLS=1 python3 /tmp/cow-trace/run_sim.py /tmp/cow-trace/tsolver.json # full tree +python3 /tmp/cow-trace/run_sim.py /tmp/cow-trace/tsolver.json 100000000 # bumped gas +``` + +### Option B — Tenderly `/simulate` (saved, shareable UI; *finish here for human handoff*) + +```bash +# drop transaction_index — Tenderly rejects -1 with no block_number ("Transaction index is not allowed when block number is pending") +jq 'del(.transaction_index)' /tmp/cow-trace/tsolver.json > /tmp/cow-trace/tsolver_tenderly.json +source services/.env.claude +curl -sS -X POST \ + -H "X-ACCESS-KEY: $TENDERLY_ACCESS_TOKEN" -H "Content-Type: application/json" \ + --data @/tmp/cow-trace/tsolver_tenderly.json \ + https://api.tenderly.co/api/v1/account/cow-protocol/project/production/simulate \ +| jq -r '"https://dashboard.tenderly.co/cow-protocol/production/simulator/" + .simulation.id' +``` + +Tenderly upstream regularly times out on `$50M`-scale routes (`upstream request timeout`) — fall back to A or C. **Always paste a Tenderly link into the user-facing summary if possible** - it's how the user verifies the root cause. + +### Option C — `cast call --trace` (foundry one-liner; quick eyeball) + +```bash +python3 - /tmp/cow-trace/tsolver.json <<'PY' | bash +import json, shlex, sys +p = json.load(open(sys.argv[1])) +cmd = ["cast","call","--trace","--rpc-url","$ETH_MAINNET_RPC", + "--from", p["from"], "--gas-limit", str(p["gas"])] +if p.get("gas_price"): cmd += ["--gas-price", str(p["gas_price"])] +for addr, ov in (p.get("state_objects") or {}).items(): + if "balance" in ov: cmd += ["--override-balance", f"{addr}:{ov['balance']}"] + if "code" in ov: cmd += ["--override-code", f"{addr}:{ov['code']}"] + if "nonce" in ov: cmd += ["--override-nonce", f"{addr}:{ov['nonce']}"] + for slot, val in (ov.get("storage") or {}).items(): + cmd += ["--override-state-diff", f"{addr}:{slot}:{val}"] +cmd += [p["to"], p["input"]] +print("source services/.env.claude && \\\n" + " \\\n ".join(shlex.quote(x) for x in cmd)) +PY +``` + +Output is a human-readable call tree with selector decoding (uses 4byte). Bumped-gas re-runs need only `--gas-limit `. + +**Tool selection**: A for programmatic walking / decoding the settle calldata / gas binary search / cross-trace pattern checks; C for a fast one-shot decode; B at the end for the user-facing link. + +--- + +## Step 5 — Diagnose the revert + +### Step 5a — Reason from the trace (do this first; the table in 5b is a catalog of common patterns, NOT a substitute for thinking) + +The goal is not to match the deepest selector against a lookup table — the goal is to explain, frame by frame, **what each call was supposed to do, what it actually did, and where the divergence happened**. Most real failures don't fit one row of the catalog cleanly; they're a story across several frames. Walk the trace and *reason*. Concretely: + +1. **Anchor on the deepest reverting frame.** From `run_sim.py`'s output: which contract, which selector, what gas was used, what was the call depth, and what is the *parent frame* expecting back? A swap router reverting at depth 7 inside a Universal Router execute means something different than a top-level `WETH.transfer` reverting at depth 3. + +2. **Decode every unknown selector.** Function selectors: + ```bash + curl -s 'https://api.openchain.xyz/signature-database/v1/lookup?function=0xAAAA,0xBBBB&filter=true' | jq . + ``` + Error selectors live in the same database — the first 4 bytes of revert data is just another selector. Cross-check the cheat sheet first; if not there, *always* look it up rather than guessing. Also note: an unverified contract may still expose selectors you can dispatch (`eth_call` with `name()`/`symbol()`/`token0()`/`fee()` etc.) — use that to identify the target. + +3. **ABI-decode revert data, not just the selector.** The revert payload after the selector usually carries the diagnostic. `cast abi-decode 'TooMuchSlippage(address,uint256,uint256)' ` tells you which token, the minimum expected, and the actual delivered — which lets you state "missed by N basis points" instead of just "slippage." Same for `ERC20InsufficientBalance(address,uint256,uint256)`, `Error(string)` (`0x08c379a0`), `Panic(uint256)` (`0x4e487b71`), custom DEX errors. If `output` is `0x` (empty), that is itself diagnostic — see step 5e. + +4. **Read the parent chain.** From the failing leaf, walk up frame by frame. Annotate each: who called whom, with what selector, with what gas budget, what return path was expected. The story usually emerges between two adjacent frames where one expected a balance/return value the other didn't provide. + +5. **Identify the buy-token / sell-token flow.** Re-run with `ALL_CALLS=1` and grep every `transfer`/`transferFrom`/`approve` of the involved tokens. Did Settlement actually accumulate the buy amount before the pay-out? Did sell tokens leave Settlement to a router, and did anything come back? A net-zero buy-token flow before the final pay-out almost always means "the encoded swap didn't run" — but the *why* (empty interactions, wrong selector, OOG mid-route, pool rejected) needs upstream evidence. + +6. **Sanity-check gas.** Real swaps cost real gas. A `transferFromAccounts` taking 13k gas is not doing a $10M swap; a Universal Router `execute` taking 50k gas is suspect. Compare the solver's self-reported `gas` (from `new price estimate`) to the trace's `gasUsed`, and to the gas the *swap router* used. Cross-reference against the verifier's 16.78M outer cap (step 5d). + +7. **Decode the solver's encoded solution.** The verifier entry `0x1d47e7f4 swap(settlement, tokens[], receiver, settlementCall)` wraps `0x13d79a0b GPv2Settlement.settle(tokens[], clearingPrices[], trades[], interactions[3])`. `interactions[3]` is `(pre, intra, post)` — `pre`/`post` come from the verifier; **only `intra` is the solver's**. Decoding it answers questions like "did the solver even include a swap?", "what router was called?", "is there an `approve` before the transferFrom?". Step 5c walks this. + +8. **Account for the verifier's overrides.** The trader address gets a code override (helper contract that signs/approves), the trader's sell-token balance is seeded via a storage-slot override, and `0x…020000` is a precompile that wraps `safeTransferFrom`. A balance/allowance check that fails near the trader frequently traces to a slot mismatch in the storage override — verify the slot the token *actually reads* matches the override (mapping slot for `balanceOf` is `keccak256(addr . slot_index)` for the relevant slot index per token). + +9. **Form a hypothesis, then *test* it.** Useful experiments cheap enough to run: + - Re-run with `gas=100000000` — if it now passes, the failure was the verifier's gas cap, not a real revert. + - Decode `interactions[]` — if `interactions[1].length == 0`, you've found an empty-solution bug. + - Re-run with the storage override removed/extended — confirms whether a balance/allowance gap is real on chain or a verifier-setup artifact. + - Search VictoriaLogs for the same solver across recent quotes (`stats by selector count`) to see if the failure is a one-off or systemic. + +10. **Surface context, not labels, in the user-facing summary.** The user wants the *story* of the revert: which contract did what at each frame, what was missing, by how much, and which actor (solver / verifier / liquidity / pool policy / user wallet) is responsible. A one-liner like "TooMuchSlippage" is a label, not a root cause — the root cause is "0x Settler routed through the low-TVL UniV3 USDC/WETH 0.01% pool, which only quoted X but min-out demanded Y; missed by N bps." Always include the ABI-decoded revert args and the relevant parent-frame context in the report. + +### Step 5b — Common patterns (catalog of recurring failure modes; NOT exhaustive — always reason from the trace first) + +| Symptom on the deepest call | Diagnosis | Fix locus | +|---|---|---| +| `0x97a6f3b9 TooMuchSlippage(addr,uint,uint)` | Real liquidity miss. ABI-decode args: token, expected_min, actual; report the bps miss. | Solver routing | +| `0x39d35496 V3TooLittleReceived` / `0x8b063d73 V4TooLittleReceived` / `0xbb2875c3 InsufficientOutput` | min-out check failed | Solver routing | +| `out of gas: not enough gas for reentrancy sentry` (or pure `execution reverted` at depth 4+ with high gasUsed) | Verifier outer gas cap (`0xFFFFFF` = 16.78M) bites | Re-run with bumped gas (step 5d) | +| Bare `execution reverted` at the final `.transfer(trader, …)` (depth 3), no inner swap path | Likely empty-intra bug — solver returned `out_amount` but no swap calldata. Confirm by decoding `interactions[3]` (step 5c). | Solver settle-encoder | +| Bare `execution reverted` on a `transferFrom` mid-tree | Token's silent-revert path — usually missing `approve` or insufficient balance. Reconstruct ledger from prior calls (step 5e). | Solver settle-encoder | +| `0x08c379a0 Error("trader does not have enough sell token")` | Verifier's pre-check — quote requested by a wallet that doesn't hold the sell token | None — filter out before triaging | +| `0xd81b2f2e AllowanceExpired(uint256)` (Permit2) | Verifier's Permit2 storage override has stale/0 expiry | Verifier setup (services) | +| `0x5cd5d233 BadSignature()` (0x Settler / Permit2) | Permit2 signature crafted with wrong nonce or invalidated by chain state | Solver | +| `0x8a3b7ff1 MaxImbalanceRatioExceeded` / `0x27e92f0f maxTradeSizeRatioExceeded` | Pool refuses oversized trade | None — pool policy | + +If the trace doesn't match a row above, **don't force-fit it** — fall back to the reasoning steps in 5a, decode unknown selectors via openchain, and write the actual story. + +### Step 5c — Decode the solver's interactions + +Empty-interactions bugs (recently common in tsolver) are best confirmed by decoding `interactions[3]` in the settle calldata directly. The verifier wraps `swap(settlement, tokens[], receiver, settlementCall)` (selector `0x1d47e7f4`); inside `settlementCall` you'll find `GPv2Settlement.settle(tokens[], clearingPrices[], trades[], interactions[3])` (selector `0x13d79a0b`). The interactions are split into `(pre, intra, post)` — `pre` and `post` come from the verifier (preSwap hook + trackBalance), so `intra.length == 0` means the solver provided no swap. Read the JSON payload's `input` and walk offsets in Python. + +### Step 5d — OOG: bump gas, then binary search + +If the simualtion fails due to "out of gas", try to resimulate it with the maximum gas limit for the chain and compare the solver's self-reported `gas` (from the `new price estimate` log) to actual `gasUsed`. Keep in mind potential maximum block gas limits as well as maximum transaction gas limits for the given chain. + +### Step 5e — Balance/allowance forensics for silent reverts + +When a `transferFrom` reverts with no data, walk every prior call to that token, replay `transfer/transferFrom/approve` into a virtual ledger keyed on `(addr -> bal)` and `(owner, spender) -> allowance`. Apply only on calls that succeeded. At the failing call, compare the requested `dx` to balance(src) and allowance(src→spender) to see which (or both) is short. + +Worked example: kipseli's $50M USDC→ETH route routed through V2 to deliver 2,499,469 crvUSD into Settlement, then a Curve `exchange()` reverted because the encoder forgot a `crvUSD.approve(curvePool, …)` interaction — balance was exact, allowance was 0. + +--- + +## Step 6 — Report findings + +Default output for a per-quote multi-solver verification debug is **one sorted table covering every estimator that ran** — including the no-quote ones. Don't split into separate tables. + +Columns: + +| Column | Content | +|---|---| +| `#` | rank by `out_amount` descending; `—` for no-quote rows (placed at the bottom, alphabetic) | +| Estimator | name; mark the winner with ⭐ | +| `out_amount ()` | decimalized to the buy token's units (WETH 18 dp, USDC 6 dp, etc.); `—` for no-quote rows | +| `gas` | solver's self-reported (from the `new price estimate` log) | +| `verified` | ✅ / ❌ / `—` | +| Notes | for **non-verified** rows: a Tenderly simulation link (option B in step 4) plus a one-sentence root cause from the trace replay; for **no-quote** rows: the `Err(...)` reason verbatim from the `new price estimate` log (`NoLiquidity`, `EstimatorInternal(...)`); for verified rows: usually empty | + +Lead the response with this table. Place any cross-solver pattern analysis or longer narrative *after* it — the table is the primary artifact the user scans. + +Always POST the failed-estimator payload to Tenderly to produce the link, even when reth already gave you the root cause — the user needs the UI to verify against. Drop `transaction_index` from the payload before submitting (Tenderly rejects `-1` with no explicit `block_number`). + +--- + +## Cheat sheet — selectors + +| Selector | Meaning | +|---|---| +| `0x1d47e7f4` | verifier entry: `swap(settlement, tokens[], receiver, settlementCall)` | +| `0x2582edb4` | trader-side hook (preSwap helper) | +| `0x3bbb2e1d` | verifier `trackBalance(token, account)` | +| `0x494666b6` | helper `safeTransferFrom(token, amt)` (precompile at `0x…020000`) | +| `0x13d79a0b` | `GPv2Settlement.settle(...)` | +| `0x542eb77d` | trader-helper `preSwap(token,tokenSold,sellAmt,solver,solverAddr)` | +| `0xeb5625d9` | trader-helper approve | +| `0x70a08231` `0xa9059cbb` `0x23b872dd` `0x095ea7b3` `0xdd62ed3e` | ERC20 `balanceOf`/`transfer`/`transferFrom`/`approve`/`allowance` | +| `0x97a6f3b9` | `TooMuchSlippage(address,uint256,uint256)` (0x Settler) | +| `0x5cd5d233` | `BadSignature()` (0x / Permit2) | +| `0xd81b2f2e` | `AllowanceExpired(uint256)` (Permit2; uint = expiry) | +| `0x39d35496` `0x8b063d73` `0xbb2875c3` | V3/V4 too-little-received / `InsufficientOutput` | +| `0x064a4ec6` | `ReturnAmountIsNotEnough(uint256,uint256)` (1inch) | +| `0xe450d38c` | `ERC20InsufficientBalance(address,uint256,uint256)` (OZ v5) | +| `0x8a3b7ff1` `0x27e92f0f` | `MaxImbalanceRatioExceeded` / `maxTradeSizeRatioExceeded` (Balancer / pool) | +| `0xdee51a8a` `0xdcab82e2` `0x2fee3e0e` | Fluid `SafeTransferError` / `LiquidityError` / `DexError` | +| `0xf7bf5832` | `TychoRouter__AmountOutNotFullyReceived(uint256,uint256)` | +| `0x486aa307` | `PoolNotInitialized()` (UniV4) | +| `0x08c379a0` | `Error(string)` (string offset 0x60, length at 0x40) | +| `0x4e487b71` | `Panic(uint256)` | + +Decode unknown ones via: + +```bash +curl -s 'https://api.openchain.xyz/signature-database/v1/lookup?function=0xAAAA,0xBBBB&filter=true' | jq . +``` + +## Cheat sheet — addresses + +| Address | What | +|---|---| +| `0x9008d19f58aabd9ed0d60971565aa8510560ab41` | GPv2Settlement (mainnet) | +| `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` | GPv2VaultRelayer (pulls sell tokens from trader → Settlement; selector `0x7d10d11f transferFromAccounts(...)`) | +| `0x000000000022d473030f116ddee9f6b43ac78ba3` | Permit2 | +| `0xd524f98f554bd34f4185678f64a85bb98971d314` | 0x AllowanceHolder | +| `0x699c5bd4d03d98dabe8ef94ce13ba0314e4d35c8` | 0x Settler entry | +| `0xe592427a0aece92de3edee1f18e0157c05861564` | UniV3 SwapRouter | +| `0x66a9893cc07d91d95644aedd05d03f95e1dba8af` | Universal Router V4 (selector `0x24856bc3 execute(bytes,bytes[])`) | +| `0x000000000004444c5dc75cb358380d2e3de08a90` | UniV4 PoolManager | +| `0xc02aaa39…756cc2` `0xa0b86991…06eb48` `0xdac17f95…831ec7` `0xf939e0a0…ac1b4e` | WETH, USDC, USDT, crvUSD | +| `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` | Native ETH placeholder | +| `0x0000000000000000000000000000000000020000` | verifier-helper precompile (state-overridden each sim; empty on chain) | + +Identify unknowns via reth / cast: ERC20 (`0x06fdde03 name`, `0x95d89b41 symbol`), UniV3 (`0x0dfe1681 token0`, `0xd21220a7 token1`, `0xddca3f43 fee`), Curve (`0xc6610657 coins(i)`). + +--- + +## Source-of-truth pointers + +- Verifier setup + state overrides: `crates/price-estimation/src/trade_verifier/mod.rs` (`prepare_state_overrides`) +- Verifier helper Solidity: `contracts/solidity/Solver.sol` (the `swap` / `storeBalance` / `ensureTradePreconditions` functions) +- Resimulate-curl emitter: `crates/simulator/src/tenderly/mod.rs` (`log_simulation_request`) + +## Gotchas + +- **Tenderly upstream timeouts** for big trades — fall back to reth (option A) or cast (option C). Payload format is identical; only the wrapper and overrides-key naming differ (`storage` ↔ `stateDiff`). +- **Auto-saved MCP query results.** When a victorialogs response exceeds ~25k tokens, it's written under `.claude/projects/.../tool-results/`. Note the path; don't refetch. +- **`extract` is greedy.** If the captured field's delimiter (e.g. `,`) appears inside the value, the capture overflows. Anchor on a stable next-literal or use `extract_regexp`. +- **State-override of `0x000…020000`** is the verifier-helper precompile that wraps `safeTransferFrom`. It only exists inside the simulation — the address is empty on chain. +- **0x Settler revert bubbling** — `TooMuchSlippage` propagates through 4+ frames (settler → AllowanceHolder → settle → helper). The deepest frame is rarely where the revert was *raised*; look for the first frame with revert data, usually a CALL to a UniV3 pool (selector `0x128acb08`) followed by a balance check. +- **Universal Router V4** (`0x24856bc3 execute(bytes,bytes[])`) unpacks command bytes into many sub-calls; traces get deep. diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index be605f175e..0000000000 --- a/entrypoint.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# Check if heaptrack is enabled as the first argument -if [ "$1" = "heaptrack" ]; then - # Remove 'heaptrack' from the arguments - shift - # Execute the remaining command with heaptrack - exec heaptrack -o "/tmp/heaptrack/heaptrack.$(hostname).$(date +%s%N | cut -b1-13).gz" "$@" -else - # Execute the command normally - exec "$@" -fi diff --git a/playground/.env.example b/playground/.env.example index deb4362cd1..bb1dae5c47 100644 --- a/playground/.env.example +++ b/playground/.env.example @@ -6,3 +6,8 @@ POSTGRES_PASSWORD=123 TOML_TRACE_ERROR=1 CHAIN=1 ETHFLOW_CONTRACTS=0x04501b9b1d52e67f6862d157e00d13419d2d6e95 + +# Otterscan Sourcify source: "cloud" (default) or "local" +# - cloud: Shows publicly verified contracts from sourcify.dev +# - local: Shows contracts verified on the local Sourcify instance +SOURCIFY_MODE=cloud diff --git a/playground/Dockerfile b/playground/Dockerfile index fd05b0fef6..1b06e30873 100644 --- a/playground/Dockerfile +++ b/playground/Dockerfile @@ -1,6 +1,6 @@ FROM debian:bookworm AS chef WORKDIR /src/ -RUN apt-get update && apt-get install -y curl git clang mold libssl-dev pkg-config git && apt-get clean +RUN apt-get update && apt-get install -y curl git clang mold libssl-dev pkg-config git make && apt-get clean RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ENV PATH="$PATH:/root/.cargo/bin" RUN rustup component add clippy rustfmt @@ -31,7 +31,7 @@ CMD ["migrate"] FROM chef AS builder COPY --from=planner /src/recipe.json recipe.json COPY --from=chef /.cargo /.cargo -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo chef cook --release --recipe-path recipe.json +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo chef cook --release --features tokio-console --recipe-path recipe.json # Copy only the library crates for now COPY --from=chef /.cargo /.cargo @@ -48,9 +48,9 @@ COPY ./crates/chain/ ./crates/chain COPY ./crates/ethrpc/ ./crates/ethrpc COPY ./crates/observe/ ./crates/observe COPY ./crates/order-validation/ ./crates/order-validation -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package shared +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --features tokio-console --package shared COPY ./crates/solver/ ./crates/solver -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package solver +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --features tokio-console --package solver # Create an base image for all the binaries FROM docker.io/debian:bookworm-slim AS base @@ -58,17 +58,8 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked apt-get update && \ apt-get install -y ca-certificates tini gettext-base && \ apt-get clean -FROM builder AS alerter-build -COPY --from=chef /.cargo /.cargo -COPY ./crates/alerter/ ./crates/alerter -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package alerter - -FROM base AS alerter -COPY --from=alerter-build /src/target/release/alerter /usr/local/bin/alerter -ENTRYPOINT [ "alerter" ] - FROM builder AS autopilot-build -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package autopilot +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --features tokio-console --package autopilot FROM base AS autopilot COPY --from=chef /.cargo /.cargo @@ -78,7 +69,7 @@ ENTRYPOINT [ "autopilot" ] FROM builder AS driver-build COPY ./crates/driver/ ./crates/driver -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package driver +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --features tokio-console --package driver FROM base AS driver COPY --from=driver-build /src/target/release/driver /usr/local/bin/driver @@ -87,7 +78,7 @@ ENTRYPOINT [ "driver" ] FROM builder AS orderbook-build COPY --from=chef /.cargo /.cargo COPY ./crates/orderbook/ ./crates/orderbook -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package orderbook +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --features tokio-console --package orderbook FROM base AS orderbook COPY --from=orderbook-build /src/target/release/orderbook /usr/local/bin/orderbook @@ -96,7 +87,7 @@ ENTRYPOINT [ "orderbook" ] FROM builder AS refunder-build COPY --from=chef /.cargo /.cargo COPY ./crates/refunder/ ./crates/refunder -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package refunder +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --features tokio-console --package refunder FROM base AS refunder COPY --from=refunder-build /src/target/release/refunder /usr/local/bin/refunder @@ -105,7 +96,7 @@ ENTRYPOINT [ "refunder" ] FROM builder AS solvers-build COPY --from=chef /.cargo /.cargo COPY ./crates/solvers/ ./crates/solvers -RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --package solvers +RUN CARGO_PROFILE_RELEASE_DEBUG=1 cargo build --release --features tokio-console --package solvers FROM base AS solvers COPY --from=solvers-build /src/target/release/solvers /usr/local/bin/solvers @@ -113,22 +104,11 @@ ENTRYPOINT [ "solvers" ] # Extract Binary FROM base -RUN apt-get update && \ - apt-get install -y build-essential cmake git zlib1g-dev libelf-dev libdw-dev libboost-dev libboost-iostreams-dev libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libunwind-dev libzstd-dev git -RUN git clone https://invent.kde.org/sdk/heaptrack.git /heaptrack && \ - mkdir /heaptrack/build && cd /heaptrack/build && \ - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF .. && \ - make -j$(nproc) && \ - make install && \ - cd / && rm -rf /heaptrack -COPY --from=alerter-build /src/target/release/alerter /usr/local/bin/alerter +RUN apt-get update && apt-get install -y netcat-openbsd COPY --from=autopilot-build /src/target/release/autopilot /usr/local/bin/autopilot COPY --from=driver-build /src/target/release/driver /usr/local/bin/driver COPY --from=orderbook-build /src/target/release/orderbook /usr/local/bin/orderbook COPY --from=refunder-build /src/target/release/refunder /usr/local/bin/refunder COPY --from=solvers-build /src/target/release/solvers /usr/local/bin/solvers -COPY ./entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh ENTRYPOINT ["/usr/bin/tini", "--"] -CMD ["/entrypoint.sh"] diff --git a/playground/Dockerfile.cowswap b/playground/Dockerfile.cowswap index 7ba495ced9..cbbdf1da05 100644 --- a/playground/Dockerfile.cowswap +++ b/playground/Dockerfile.cowswap @@ -2,62 +2,69 @@ FROM docker.io/node:22-bookworm-slim AS node-build WORKDIR /usr/src/app +# Enable Corepack and prepare pnpm +RUN corepack enable \ + && corepack prepare pnpm@10.12.1 --activate + # RPC URL args ARG REACT_APP_NETWORK_URL_1=https://rpc.mevblocker.io -ARG REACT_APP_NETWORK_URL_5=https://ethereum-goerli.publicnode.com ARG REACT_APP_NETWORK_URL_100=https://gnosis.publicnode.com +ARG REACT_APP_EXPLORER_URL_DEV=http://localhost:8001 + +# Block explorer URL (Otterscan for local development) +ARG REACT_APP_BLOCK_EXPLORER_URL=http://localhost:8003 # Orderbook URL args -ARG REACT_APP_ORDER_BOOK_URLS='{"1":"https://api.cow.fi/mainnet","100":"https://api.cow.fi/goerli","5":"https://api.cow.fi/xdai"}' +ARG REACT_APP_ORDER_BOOK_URLS='{"1":"https://api.cow.fi/mainnet","100":"https://api.cow.fi/xdai"}' -# Install dependencies +# Install system dependencies RUN --mount=type=cache,target=/var/cache/apt,sharing=locked apt-get update && \ - apt-get install -y git libssl-dev pkg-config git jq python3 make g++ + apt-get install -y git libssl-dev pkg-config jq python3 make g++ && \ + rm -rf /var/lib/apt/lists/* -# Clone the repo to the present working directory -RUN git clone https://github.com/cowprotocol/cowswap . && \ - git submodule update --init --recursive +# Clone the repo, initialize submodules, and install dependencies +RUN git clone https://github.com/cowprotocol/cowswap . \ + && git submodule update --init --recursive \ + && pnpm install --frozen-lockfile -# Install npm dependencies -RUN yarn install --frozen-lockfile --no-cache - -# Set the environment variable "chain" +# Set environment variable "chain" ARG CHAIN -ENV CHAIN=$CHAIN +ENV CHAIN="$CHAIN" -# Set the environment variable "ETH_RPC_URL" +# Set environment variable "ETH_RPC_URL" ARG ETH_RPC_URL -ENV ETH_RPC_URL=$ETH_RPC_URL +ENV ETH_RPC_URL="$ETH_RPC_URL" -# Set the default environment variables -ENV REACT_APP_NETWORK_URL_1=$REACT_APP_NETWORK_URL_1 -ENV REACT_APP_NETWORK_URL_5=$REACT_APP_NETWORK_URL_5 -ENV REACT_APP_NETWORK_URL_100=$REACT_APP_NETWORK_URL_100 -ENV REACT_APP_ORDER_BOOK_URLS=$REACT_APP_ORDER_BOOK_URLS +# Set default environment variables for network and order book URLs +ENV REACT_APP_NETWORK_URL_1="$REACT_APP_NETWORK_URL_1" +ENV REACT_APP_NETWORK_URL_100="$REACT_APP_NETWORK_URL_100" +ENV REACT_APP_ORDER_BOOK_URLS="$REACT_APP_ORDER_BOOK_URLS" +ENV REACT_APP_EXPLORER_URL_DEV="$REACT_APP_EXPLORER_URL_DEV" +ENV REACT_APP_BLOCK_EXPLORER_URL="$REACT_APP_BLOCK_EXPLORER_URL" -# Update environment variables based on "chain" and "ETH_RPC_URL" and build the frontend -RUN if [ -n "$ETH_RPC_URL" ]; then \ +# Update environment variables based on "chain" and "ETH_RPC_URL", then build safely +RUN set -e; \ + if [ -n "$ETH_RPC_URL" ]; then \ case "$CHAIN" in \ 1) \ - REACT_APP_NETWORK_URL_1=$ETH_RPC_URL \ - REACT_APP_ORDER_BOOK_URLS=$(echo $REACT_APP_ORDER_BOOK_URLS | jq --arg chain "1" '.[$chain]="http://127.0.0.1:8080"') \ - ;; \ - 5) \ - REACT_APP_NETWORK_URL_5=$ETH_RPC_URL \ - REACT_APP_ORDER_BOOK_URLS=$(echo $REACT_APP_ORDER_BOOK_URLS | jq --arg chain "5" '.[$chain]="http://127.0.0.1:8080"') \ + REACT_APP_NETWORK_URL_1="$ETH_RPC_URL"; \ + REACT_APP_ORDER_BOOK_URLS=$(echo "$REACT_APP_ORDER_BOOK_URLS" | jq --arg chain "1" '.[$chain]="http://127.0.0.1:8080"'); \ ;; \ 100) \ - REACT_APP_NETWORK_URL_100=$ETH_RPC_URL \ - REACT_APP_ORDER_BOOK_URLS=$(echo $REACT_APP_ORDER_BOOK_URLS | jq --arg chain "100" '.[$chain]="http://127.0.0.1:8080"') \ + REACT_APP_NETWORK_URL_100="$ETH_RPC_URL"; \ + REACT_APP_ORDER_BOOK_URLS=$(echo "$REACT_APP_ORDER_BOOK_URLS" | jq --arg chain "100" '.[$chain]="http://127.0.0.1:8080"'); \ ;; \ esac; \ - NODE_OPTIONS="--max-old-space-size=4096" NX_NO_CLOUD=true yarn build --env REACT_APP_NETWORK_URL_1=$REACT_APP_NETWORK_URL_1 \ - --env REACT_APP_NETWORK_URL_5=$REACT_APP_NETWORK_URL_5 \ - --env REACT_APP_NETWORK_URL_100=$REACT_APP_NETWORK_URL_100 \ - --env REACT_APP_ORDER_BOOK_URLS="$REACT_APP_ORDER_BOOK_URLS"; \ - fi + fi; \ + export REACT_APP_NETWORK_URL_1 REACT_APP_NETWORK_URL_100 REACT_APP_ORDER_BOOK_URLS REACT_APP_EXPLORER_URL_DEV REACT_APP_BLOCK_EXPLORER_URL; \ + NODE_OPTIONS="--max-old-space-size=4096" NX_NO_CLOUD=true pnpm run build \ + --env REACT_APP_NETWORK_URL_1="$REACT_APP_NETWORK_URL_1" \ + --env REACT_APP_NETWORK_URL_100="$REACT_APP_NETWORK_URL_100" \ + --env REACT_APP_ORDER_BOOK_URLS="$REACT_APP_ORDER_BOOK_URLS" \ + --env REACT_APP_EXPLORER_URL_DEV="$REACT_APP_EXPLORER_URL_DEV" \ + --env REACT_APP_BLOCK_EXPLORER_URL="$REACT_APP_BLOCK_EXPLORER_URL" -# Stage 2: Copy the frontend to the nginx container +# Stage 2: Copy the frontend build to the nginx container FROM docker.io/nginx:1.21-alpine AS frontend COPY --from=node-build /usr/src/app/build/cowswap /usr/share/nginx/html EXPOSE 80 diff --git a/playground/Dockerfile.explorer b/playground/Dockerfile.explorer index 34a2929007..19d38cf664 100644 --- a/playground/Dockerfile.explorer +++ b/playground/Dockerfile.explorer @@ -2,24 +2,30 @@ FROM docker.io/node:22-bookworm-slim AS node-build WORKDIR /usr/src/app -# Install dependencies +# Install system dependencies needed for building RUN --mount=type=cache,target=/var/cache/apt,sharing=locked apt-get update && \ - apt-get install -y git libssl-dev pkg-config git autoconf automake file g++ libtool make python3 + apt-get install -y git libssl-dev pkg-config autoconf automake file g++ libtool make python3 && \ + rm -rf /var/lib/apt/lists/* -# Clone the repo to the present working directory -RUN git clone https://github.com/cowprotocol/cowswap . && \ - git submodule update --init --recursive +# Enable Corepack and prepare pnpm +RUN corepack enable \ + && corepack prepare pnpm@10.12.1 --activate -# Install npm dependencies -RUN yarn install --frozen-lockfile --no-cache +# Clone the repo, initialize submodules, and install dependencies +RUN git clone https://github.com/cowprotocol/cowswap . \ + && git submodule update --init --recursive \ + && pnpm install --frozen-lockfile +# Build environment variables ENV REACT_APP_ORDER_BOOK_URLS='{"1":"http://localhost:8080"}' +ENV REACT_APP_BLOCK_EXPLORER_URL=http://localhost:8003 # Build the frontend -RUN APP_ID=1 yarn build:explorer +RUN APP_ID=1 REACT_APP_BLOCK_EXPLORER_URL=$REACT_APP_BLOCK_EXPLORER_URL pnpm run build:explorer -# Stage 2: Copy the frontend to the nginx container +# Stage 2: Copy the frontend build to the nginx container FROM docker.io/nginx:1.21-alpine AS frontend COPY --from=node-build /usr/src/app/build/explorer /usr/share/nginx/html +COPY nginx-spa.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] diff --git a/playground/Dockerfile.otterscan b/playground/Dockerfile.otterscan new file mode 100644 index 0000000000..e850887ee8 --- /dev/null +++ b/playground/Dockerfile.otterscan @@ -0,0 +1,6 @@ +FROM otterscan/otterscan:latest + +COPY otterscan-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/playground/Dockerfile.sourcify b/playground/Dockerfile.sourcify new file mode 100644 index 0000000000..d75a8c089e --- /dev/null +++ b/playground/Dockerfile.sourcify @@ -0,0 +1,41 @@ +FROM node:24-bookworm-slim + +# Install dependencies (architecture-aware for ARM64/AMD64 compatibility) +RUN apt-get update && apt-get install -y git curl postgresql-client && \ + DPKG_ARCH=$(dpkg --print-architecture) && \ + case "${DPKG_ARCH}" in \ + amd64) DBMATE_ARCH="amd64" ;; \ + arm64) DBMATE_ARCH="arm64" ;; \ + i386) DBMATE_ARCH="386" ;; \ + armhf) DBMATE_ARCH="arm" ;; \ + *) echo "Unsupported architecture: ${DPKG_ARCH}" && exit 1 ;; \ + esac && \ + echo "Downloading dbmate for architecture: ${DBMATE_ARCH} (detected: ${DPKG_ARCH})" && \ + curl -fsSL -o /usr/local/bin/dbmate https://github.com/amacneil/dbmate/releases/download/v2.21.0/dbmate-linux-${DBMATE_ARCH} && \ + chmod +x /usr/local/bin/dbmate && \ + dbmate --version && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Clone Sourcify with submodules +RUN git clone --depth 1 --branch master --recurse-submodules https://github.com/argotorg/sourcify.git /sourcify + +WORKDIR /sourcify + +# Install dependencies and build +RUN npm install && npm run build:lerna + +# Prepare migrations +WORKDIR /sourcify/services/database +RUN mkdir -p /migrations && \ + cp -r database-specs/migrations/* /migrations/ 2>/dev/null || true && \ + cp -r migrations/* /migrations/ 2>/dev/null || true + +WORKDIR /sourcify/services/server + +# Copy custom entrypoint +COPY sourcify-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +EXPOSE 5555 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/playground/README.md b/playground/README.md index 44af35a9ae..572024a57a 100644 --- a/playground/README.md +++ b/playground/README.md @@ -42,7 +42,7 @@ Now with Rabby configured, and the services started, you can browse to http://lo > The EthFlow is not configured by default, the next section explains how to set it up. > You can follow along with watching the logs of the `autopilot`, `driver`, and `baseline` solver to see how the Protocol interacts. > If you make any changes to the files in your repo directory, services will automatically be recompiled and restarted. -> The CoW Explorer is avialable at http://localhost:8001 to see more information about transaction status +> The CoW Explorer is available at http://localhost:8001 to see more information about transaction status ### Resetting the playground @@ -115,6 +115,9 @@ await window.ethereum.request({ | Postgres | postgres | 5432 | 5432 | N/A | Local/Fork | | Adminer | adminer | 8082 | 8080 | N/A | Local/Fork | | Grafana | grafana | 3000 | 3000 | N/A | Local/Fork | +| Otterscan | otterscan | 8003 | 80 | N/A | Local/Fork | +| Sourcify | sourcify | 5555 | 5555 | N/A | Local/Fork | +| Sourcify DB | sourcify-db | N/A | 5432 | N/A | Local/Fork | **NOTE**: Currently only **FORK** mode is supported. @@ -137,16 +140,133 @@ In this mode, the stack will spin up: - Postgres (with migrations) - Adminer - RPC (forked from `reth` or `erigon` node) -- Otterscan (*not yet implemented*) +- Otterscan +- Sourcify (contract verification) - Orderbook - Autopilot - Driver - Baseline - Cow Swap -- Cow Explorer (*not yet implemented*) +- Cow Explorer ### Local **NOT YET IMPLEMENTED** - As per fork, but with a local node (not forked from Erigon) + +## Using Otterscan + +[Otterscan](https://github.com/otterscan/otterscan) is a local block explorer integrated into the playground. +It provides powerful transaction analysis tools that work with your local Anvil chain — no external services required. + +For more details, see the [Otterscan documentation](https://docs.otterscan.io/). + +**Access Otterscan at:** http://localhost:8003 + +### Inspecting Transactions + +When you make a swap in CoW Swap, all explorer links automatically point to your local Otterscan instance. You can: + +1. **View transaction overview**: See gas usage, status, block info, and decoded input data + + ![Transaction overview](docs/images/otterscan-tx-overview.png) + *Transaction overview showing gas usage, status, token transfers, and decoded input data.* + +2. **Analyze transaction traces**: Expand the full call tree to see every internal call, including: + - Contract-to-contract calls + - Token transfers (ERC20, ERC721) + - Value transfers + - Delegate calls and static calls + + ![Transaction trace](docs/images/otterscan-tx-trace.png) + *Full call trace of a `settle()` transaction showing internal calls, token transfers, and AMM interactions.* + +3. **View event logs**: See all emitted events with decoded parameters + + ![Transaction logs](docs/images/otterscan-tx-logs.png) + *Event logs tab with decoded parameters for a CoW Swap settlement.* + +4. **Check gas profiling**: Understand gas consumption per operation + +For more on transaction analysis, see the [Otterscan documentation](https://docs.otterscan.io/). + +### Debugging Failed Transactions + +Otterscan is especially useful for debugging failed transactions: + +1. Navigate to the failed transaction in Otterscan + + ![Failed transaction overview](docs/images/otterscan-failed-tx.png) + *Overview of a failed transaction showing the "Fail" status badge and decoded input data.* + +2. Check the **"Trace"** tab to see exactly where the transaction reverted + + ![Failed transaction trace](docs/images/otterscan-revert-trace.png) + *Trace tab showing the full call tree of a failed transaction with multiple internal calls.* + +3. Look for the revert reason in the trace output (e.g., `Error(string)` or custom errors) +4. For CoW Protocol transactions, you can trace the entire settlement flow including: + - Pre-interactions + - Token approvals and transfers + - AMM interactions (Uniswap, etc.) + - Post-interactions + +See the [Otterscan documentation](https://docs.otterscan.io/) for more details on trace analysis. + +### Example: Tracing a CoW Swap Settlement + +After executing a swap: + +1. Click the transaction link in the CoW Swap UI or CoW Explorer. This will open the transaction directly in your local Otterscan instance. +2. Click on **"Trace"** to see the full execution flow. +3. Expand the `settle()` call to see: + - How tokens flowed between parties + - Which liquidity sources were used + - Gas costs per operation + +> **Tip:** For details on how Otterscan displays verified source code, see the [Contract Verification with Sourcify](#contract-verification-with-sourcify) section below. + +## Contract Verification with Sourcify + +The playground includes a local [Sourcify](https://sourcify.dev/) instance for contract verification. Sourcify is a decentralized contract verification service that matches deployed bytecode with source code. Verified contracts display their source code in Otterscan. + +**How it works:** + +- **Cloud mode** (`SOURCIFY_MODE=cloud`): Otterscan fetches verified source code from the public Sourcify repository. This shows source code for well-known contracts (CoW Protocol, USDC, etc.) that have been publicly verified. +- **Local mode** (`SOURCIFY_MODE=local`): Otterscan fetches from your local Sourcify instance. Use this when testing contracts you deploy and verify locally. + +### Sourcify Sources Configuration + +Configure which Sourcify source Otterscan uses in your `.env` file: + +```bash +# Use public Sourcify (default) - shows publicly verified contracts +SOURCIFY_MODE=cloud + +# Use local Sourcify - shows contracts verified on your local instance +SOURCIFY_MODE=local +``` + +After changing this value, recreate the Otterscan container: + +```bash +docker compose -f docker-compose.fork.yml up -d otterscan +``` + +or + +```bash +docker compose -f docker-compose.non-interactive.yml up -d otterscan +``` + +> **Note**: A simple `docker compose restart` won't work because it doesn't re-read `.env` - you need to recreate the container. + +### Verifying Contracts + +You can verify contracts on the local Sourcify instance using: + +1. **Sourcify API**: POST to `http://localhost:5555/verify` with your contract address, chain ID, and source files +2. **Foundry**: Use `forge verify-contract` with `--verifier sourcify --verifier-url http://localhost:5555` + +After verification, view the contract source in Otterscan at `http://localhost:8003/address/`. diff --git a/playground/autopilot.toml b/playground/autopilot.toml new file mode 100644 index 0000000000..6566d9f5ac --- /dev/null +++ b/playground/autopilot.toml @@ -0,0 +1,37 @@ +node-url = "http://chain:8545" +simulation-node-url = "http://chain:8545" + +[logging] +filter = "warn,autopilot=debug,shared=info,price_estimation=info" + +[current-block] +poll-interval = "1s" + +[[gas-estimators]] +type = "Web3" + +[[gas-estimators]] +type = "Alloy" + +[[drivers]] +name = "baseline" +url = "http://driver/baseline" +address = "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" + +[fee-policies] + +[database] +write-url = "%DB_WRITE_URL" +read-url = "%DB_READ_URL" + +[ethflow] +skip-event-sync = true + +[native-price-estimation] +estimators = [[{ type = "Driver", name = "baseline", url = "http://driver/baseline" }]] + +[native-price-estimation.cache] +max-age = "20m" + +[order-quoting] +price-estimation-drivers = [{ name = "baseline", url = "http://driver/baseline" }] diff --git a/playground/baseline.toml b/playground/baseline.toml deleted file mode 100644 index c62d9d91eb..0000000000 --- a/playground/baseline.toml +++ /dev/null @@ -1,14 +0,0 @@ -chain-id = "1" # Ethereum mainnet -base-tokens = [ - "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # WETH - "0x6B175474E89094C44Da98b954EedeAC495271d0F", # DAI - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", # USDC - "0xdAC17F958D2ee523a2206206994597C13D831ec7", # USDT - "0xc00e94Cb662C3520282E6f5717214004A7f26888", # COMP - "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", # MKR - "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", # WBTC - "0x6810e776880C02933D47DB1b9fc05908e5386b96", # GNO -] -max-hops = 2 -max-partial-attempts = 5 -native-token-price-estimation-amount = "100000000000000000" # 0.1 ETH diff --git a/playground/configs/autopilot.toml b/playground/configs/autopilot.toml new file mode 100644 index 0000000000..937eb9f1ee --- /dev/null +++ b/playground/configs/autopilot.toml @@ -0,0 +1,41 @@ +node-url = "http://chain:8545" +simulation-node-url = "http://chain:8545" + +[logging] +filter = "warn,autopilot=debug,shared=info,price_estimation=info" + +[current-block] +poll-interval = "1s" + +[run-loop] +solve-deadline = "20s" + +[[gas-estimators]] +type = "Web3" + +[[gas-estimators]] +type = "Alloy" + +[[drivers]] +name = "baseline" +url = "http://driver/baseline" +address = "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" + +[fee-policies] + +[database] +write-url = "%DB_WRITE_URL" +read-url = "%DB_READ_URL" + +[ethflow] +contracts = ["0x04501b9b1d52e67f6862d157e00d13419d2d6e95"] +skip-event-sync = true + +[order-quoting] +price-estimation-drivers = [{ name = "baseline", url = "http://driver/baseline" }] + +[native-price-estimation] +estimators = [[{ type = "Driver", name = "baseline", url = "http://driver/baseline" }]] + +[native-price-estimation.cache] +max-age = "20m" diff --git a/playground/configs/baseline.toml b/playground/configs/baseline.toml new file mode 100644 index 0000000000..43e24b9983 --- /dev/null +++ b/playground/configs/baseline.toml @@ -0,0 +1,14 @@ +chain-id = "1" # Ethereum mainnet +base-tokens = [ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # WETH + "0x6B175474E89094C44Da98b954EedeAC495271d0F", # DAI + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", # USDC + "0xdAC17F958D2ee523a2206206994597C13D831ec7", # USDT + "0xc00e94Cb662C3520282E6f5717214004A7f26888", # COMP + "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", # MKR + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", # WBTC + "0x6810e776880C02933D47DB1b9fc05908e5386b96", # GNO +] +max-hops = 2 +max-partial-attempts = 5 +native-token-price-estimation-amount = "100000000000000000" # 0.1 ETH diff --git a/playground/configs/driver.toml b/playground/configs/driver.toml new file mode 100644 index 0000000000..955db85ebb --- /dev/null +++ b/playground/configs/driver.toml @@ -0,0 +1,36 @@ +app-data-fetching-enabled = true +orderbook-url = "http://orderbook" +tx-gas-limit = "45000000" + +[[solver]] +name = "baseline" # Arbitrary name given to this solver, must be unique +endpoint = "http://baseline" +absolute-slippage = "40000000000000000" # Denominated in wei, optional +relative-slippage = "0.1" # Percentage in the [0, 1] range +account = "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" # Known test private key +# Known local dev private keys from the default Hardhat/Anvil test account set. +submission-accounts = [ + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", # Hardhat/Anvil account #1 + "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", # Hardhat/Anvil account #2 +] + +[submission] +gas-price-cap = "1000000000000" + +[[submission.mempool]] +url = "http://chain:8545" + +[liquidity] +base-tokens = [ + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # WETH + "0x6B175474E89094C44Da98b954EedeAC495271d0F", # DAI + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", # USDC + "0xdAC17F958D2ee523a2206206994597C13D831ec7", # USDT + "0xc00e94Cb662C3520282E6f5717214004A7f26888", # COMP + "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", # MKR + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", # WBTC + "0x6810e776880C02933D47DB1b9fc05908e5386b96", # GNO +] + +[[liquidity.uniswap-v2]] # Uniswap V2 configuration +preset = "uniswap-v2" diff --git a/playground/configs/orderbook.toml b/playground/configs/orderbook.toml new file mode 100644 index 0000000000..f5b1a0e54a --- /dev/null +++ b/playground/configs/orderbook.toml @@ -0,0 +1,19 @@ +eip1271-skip-creation-validation = true +bind-address = "0.0.0.0:80" + +[shared] +node-url = "http://chain:8545" +simulation-node-url = "http://chain:8545" + +[shared.tracing] +collector-endpoint = "http://tempo:4317" + +[database] +write-url = "%DB_WRITE_URL" +read-url = "%DB_READ_URL" + +[native-price-estimation] +estimators = [[{ type = "Driver", name = "baseline", url = "http://driver/baseline" }]] + +[order-quoting] +price-estimation-drivers = [{ name = "baseline", url = "http://driver/baseline" }] diff --git a/playground/docker-compose.fork.yml b/playground/docker-compose.fork.yml index 6b68b9bef7..0820535e60 100644 --- a/playground/docker-compose.fork.yml +++ b/playground/docker-compose.fork.yml @@ -15,16 +15,19 @@ services: # with simple bytecode that always returns a solidity `true` value, alleviating # the requirement to register a solver's private key for the sake of testing on # a fork. - test: [ "CMD-SHELL", " + test: [ + "CMD-SHELL", + " response=$$(wget -qO- --header='Content-Type: application/json' --post-data='{\"jsonrpc\":\"2.0\", \"method\":\"eth_blockNumber\", \"params\":[], \"id\":1}' http://127.0.0.1:8545); block=$$(echo $$response | sed -n 's/.*\"result\":\"\\([^\"\\]*\\)\".*/\\1/p'); if [ -n \"$$block\" ] && [ \"$$block\" != \"0x0\" ] && [ \"$$block\" != \"null\" ]; then - /usr/local/bin/cast rpc -r http://127.0.0.1:8545 anvil_setCode 0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE 0x600160005260206000F3; - exit 0; + /usr/local/bin/cast rpc -r http://127.0.0.1:8545 anvil_setCode 0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE 0x600160005260206000F3; + exit 0; else - exit 1; + exit 1; fi; - " ] + ", + ] interval: 5s timeout: 30s retries: 5 @@ -68,26 +71,18 @@ services: target: localdev dockerfile: ./playground/Dockerfile restart: always - command: ["cargo", "watch", "-x", "run --bin orderbook"] + command: + [ + "cargo", + "watch", + "-x", + "run --bin orderbook -- --config playground/configs/orderbook.toml", + ] environment: - - NODE_URL=http://chain:8545 - DB_WRITE_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - DB_READ_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - - ACCOUNT_BALANCES_SIMULATION=true - - ACCOUNT_BALANCES_SIMULATOR=Web3 - - SIMULATION_NODE_URL=http://chain:8545 - - EIP1271_SKIP_CREATION_VALIDATION=true - - ENABLE_EIP1271_ORDERS=true - - PRICE_ESTIMATORS=None - - PRICE_ESTIMATION_DRIVERS=baseline|http://driver/baseline - - NATIVE_PRICE_ESTIMATORS=baseline|http://driver/baseline - - DRIVERS=baseline|http://driver/baseline - - BIND_ADDRESS=0.0.0.0:80 - - CHAIN_ID=$CHAIN - - BASELINE_SOURCES=None - RUST_BACKTRACE=1 - TOML_TRACE_ERROR=1 - - TRACING_COLLECTOR_ENDPOINT=http://tempo:4317 - TOKIO_CONSOLE=true - TOKIO_CONSOLE_RETENTION=600sec - TOKIO_CONSOLE_BIND=0.0.0.0:6669 @@ -106,30 +101,18 @@ services: target: localdev dockerfile: ./playground/Dockerfile restart: always - command: ["cargo", "watch", "-x", "run --bin autopilot"] + command: + [ + "cargo", + "watch", + "-x", + "run --bin autopilot -- --config playground/configs/autopilot.toml", + ] environment: - DB_WRITE_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - DB_READ_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - - LOG_FILTER=warn,autopilot=info,shared=info,shared::price_estimation=info - - NODE_URL=http://chain:8545 - - SIMULATION_NODE_URL=http://chain:8545 - - SETTLE_INTERVAL=15s - - GAS_ESTIMATORS=Native,Web3 - - PRICE_ESTIMATORS=None - - NATIVE_PRICE_ESTIMATORS=baseline - - BLOCK_STREAM_POLL_INTERVAL=1s - - NATIVE_PRICE_CACHE_MAX_UPDATE_SIZE=100 - - NATIVE_PRICE_CACHE_MAX_AGE=20m - - SOLVER_TIME_LIMIT=5 - - PRICE_ESTIMATION_DRIVERS=baseline|http://driver/baseline - - NATIVE_PRICE_ESTIMATORS=baseline|http://driver/baseline - - DRIVERS=baseline|http://driver/baseline|0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 - - SKIP_EVENT_SYNC=true - - BASELINE_SOURCES=None - RUST_BACKTRACE=1 - TOML_TRACE_ERROR=1 - - ETHFLOW_CONTRACTS - - ETHFLOW_INDEXING_START - TOKIO_CONSOLE=true - TOKIO_CONSOLE_RETENTION=600sec - TOKIO_CONSOLE_BIND=0.0.0.0:6669 @@ -155,7 +138,7 @@ services: "cargo", "watch", "-x", - "run --bin driver -- --config configs/${ENV}/driver.toml", + "run --bin driver -- --config playground/configs/driver.toml", ] environment: - ETHRPC=http://chain:8545 @@ -187,7 +170,7 @@ services: "cargo", "watch", "-x", - "run --bin solvers -- baseline --config configs/${ENV}/baseline.toml", + "run --bin solvers -- baseline --config playground/configs/baseline.toml", ] environment: - ADDR=0.0.0.0:80 @@ -213,6 +196,65 @@ services: ports: - 8000:80 + # Sourcify - Contract verification service + sourcify-db: + image: postgres:16 + restart: always + environment: + - POSTGRES_USER=sourcify + - POSTGRES_PASSWORD=sourcify + - POSTGRES_DB=sourcify + volumes: + - sourcify-postgres:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U sourcify"] + interval: 5s + timeout: 5s + retries: 5 + + sourcify: + build: + context: . + dockerfile: Dockerfile.sourcify + restart: always + depends_on: + sourcify-db: + condition: service_healthy + environment: + - SOURCIFY_POSTGRES_HOST=sourcify-db + - SOURCIFY_POSTGRES_PORT=5432 + - SOURCIFY_POSTGRES_USER=sourcify + - SOURCIFY_POSTGRES_PASSWORD=sourcify + - SOURCIFY_POSTGRES_DB=sourcify + - NODE_ENV=development + volumes: + - ./sourcify-chains.json:/sourcify/services/server/dist/sourcify-chains.json + ports: + - 5555:5555 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5555/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + + otterscan: + build: + context: . + dockerfile: Dockerfile.otterscan + restart: always + environment: + - ERIGON_URL=http://127.0.0.1:8545 + - SOURCIFY_MODE=${SOURCIFY_MODE:-cloud} + - LOCAL_SOURCIFY_URL=http://sourcify:5555 + ports: + - 8003:80 + depends_on: + chain: + condition: service_healthy + sourcify: + condition: service_healthy + explorer: build: context: . @@ -253,3 +295,4 @@ services: volumes: postgres: + sourcify-postgres: diff --git a/playground/docker-compose.non-interactive.yml b/playground/docker-compose.non-interactive.yml index f41847875b..c0b1ea28e1 100644 --- a/playground/docker-compose.non-interactive.yml +++ b/playground/docker-compose.non-interactive.yml @@ -71,30 +71,18 @@ services: target: orderbook dockerfile: ./Dockerfile restart: always + command: ["--config", "/orderbook.toml"] environment: - - NODE_URL=http://chain:8545 - DB_WRITE_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - DB_READ_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - - ACCOUNT_BALANCES_SIMULATION=true - - ACCOUNT_BALANCES_SIMULATOR=Web3 - - SIMULATION_NODE_URL=http://chain:8545 - - EIP1271_SKIP_CREATION_VALIDATION=true - - ENABLE_EIP1271_ORDERS=true - - PRICE_ESTIMATORS=None - - PRICE_ESTIMATION_DRIVERS=baseline|http://driver/baseline - - NATIVE_PRICE_ESTIMATORS=baseline|http://driver/baseline - - DRIVERS=baseline|http://driver/baseline - - BIND_ADDRESS=0.0.0.0:80 - - CHAIN_ID=$CHAIN - - BASELINE_SOURCES=None - - RUST_BACKTRACE=1 + - RUST_BACKTRACE=0 - TOML_TRACE_ERROR=1 - - TRACING_COLLECTOR_ENDPOINT=http://tempo:4317 - TOKIO_CONSOLE=true - TOKIO_CONSOLE_RETENTION=600sec - TOKIO_CONSOLE_BIND=0.0.0.0:6669 volumes: - ../:/src + - ./configs/orderbook.toml:/orderbook.toml depends_on: - db-migrations ports: @@ -108,34 +96,17 @@ services: target: autopilot dockerfile: ./Dockerfile restart: always + command: ["--config", "/autopilot.toml"] environment: - DB_WRITE_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - DB_READ_URL=postgres://db:5432/?user=${POSTGRES_USER}&password=${POSTGRES_PASSWORD} - - LOG_FILTER=warn,autopilot=info,shared=info,shared::price_estimation=info - - NODE_URL=http://chain:8545 - - SIMULATION_NODE_URL=http://chain:8545 - - SETTLE_INTERVAL=15s - - GAS_ESTIMATORS=Native,Web3 - - PRICE_ESTIMATORS=None - - NATIVE_PRICE_ESTIMATORS=baseline - - BLOCK_STREAM_POLL_INTERVAL=1s - - NATIVE_PRICE_CACHE_MAX_UPDATE_SIZE=100 - - NATIVE_PRICE_CACHE_MAX_AGE=20m - - SOLVER_TIME_LIMIT=5 - - PRICE_ESTIMATION_DRIVERS=baseline|http://driver/baseline - - NATIVE_PRICE_ESTIMATORS=baseline|http://driver/baseline - - DRIVERS=baseline|http://driver/baseline|0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 - - SKIP_EVENT_SYNC=true - - BASELINE_SOURCES=None - RUST_BACKTRACE=1 - TOML_TRACE_ERROR=1 - - ETHFLOW_CONTRACTS - - ETHFLOW_INDEXING_START - TOKIO_CONSOLE=true - TOKIO_CONSOLE_RETENTION=600sec - TOKIO_CONSOLE_BIND=0.0.0.0:6669 volumes: - - ../:/src + - ./configs/autopilot.toml:/autopilot.toml depends_on: orderbook: condition: service_started @@ -162,7 +133,7 @@ services: - TOKIO_CONSOLE_RETENTION=600sec - TOKIO_CONSOLE_BIND=0.0.0.0:6669 volumes: - - ./driver.toml:/driver.toml + - ./configs/driver.toml:/driver.toml ports: - 9000:80 # API & metrics - 6671:6669 # tokio console @@ -187,7 +158,7 @@ services: - TOKIO_CONSOLE_RETENTION=600sec - TOKIO_CONSOLE_BIND=0.0.0.0:6669 volumes: - - ./baseline.toml:/baseline.toml + - ./configs/baseline.toml:/baseline.toml ports: - 9001:80 # API & metrics - 6672:6669 # tokio console @@ -202,6 +173,66 @@ services: ports: - 8000:80 + # Sourcify - Contract verification service + sourcify-db: + image: postgres:16 + restart: always + environment: + - POSTGRES_USER=sourcify + - POSTGRES_PASSWORD=sourcify + - POSTGRES_DB=sourcify + volumes: + - sourcify-postgres:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U sourcify"] + interval: 5s + timeout: 5s + retries: 5 + + sourcify: + build: + context: . + dockerfile: Dockerfile.sourcify + restart: always + depends_on: + sourcify-db: + condition: service_healthy + environment: + - SOURCIFY_POSTGRES_HOST=sourcify-db + - SOURCIFY_POSTGRES_PORT=5432 + - SOURCIFY_POSTGRES_USER=sourcify + - SOURCIFY_POSTGRES_PASSWORD=sourcify + - SOURCIFY_POSTGRES_DB=sourcify + - NODE_ENV=development + volumes: + - ./sourcify-chains.json:/sourcify/services/server/dist/sourcify-chains.json + ports: + - 5555:5555 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5555/health"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + + # Otterscan - Local blockchain block explorer for Anvil + otterscan: + build: + context: . + dockerfile: Dockerfile.otterscan + restart: always + environment: + - ERIGON_URL=http://127.0.0.1:8545 + - SOURCIFY_MODE=${SOURCIFY_MODE:-cloud} + - LOCAL_SOURCIFY_URL=http://sourcify:5555 + ports: + - 8003:80 + depends_on: + chain: + condition: service_healthy + sourcify: + condition: service_healthy + explorer: build: context: . @@ -231,7 +262,6 @@ services: volumes: - ./grafana-prometheus.yml:/etc/grafana/provisioning/datasources/prometheus.yml - prometheus: image: prom/prometheus:latest container_name: prometheus @@ -243,3 +273,4 @@ services: volumes: postgres: + sourcify-postgres: diff --git a/playground/docs/images/otterscan-failed-tx.png b/playground/docs/images/otterscan-failed-tx.png new file mode 100644 index 0000000000..4b9b9f48f7 Binary files /dev/null and b/playground/docs/images/otterscan-failed-tx.png differ diff --git a/playground/docs/images/otterscan-revert-trace.png b/playground/docs/images/otterscan-revert-trace.png new file mode 100644 index 0000000000..9fa86986c9 Binary files /dev/null and b/playground/docs/images/otterscan-revert-trace.png differ diff --git a/playground/docs/images/otterscan-tx-logs.png b/playground/docs/images/otterscan-tx-logs.png new file mode 100644 index 0000000000..81e03d85ed Binary files /dev/null and b/playground/docs/images/otterscan-tx-logs.png differ diff --git a/playground/docs/images/otterscan-tx-overview.png b/playground/docs/images/otterscan-tx-overview.png new file mode 100644 index 0000000000..a4e39e9b23 Binary files /dev/null and b/playground/docs/images/otterscan-tx-overview.png differ diff --git a/playground/docs/images/otterscan-tx-trace.png b/playground/docs/images/otterscan-tx-trace.png new file mode 100644 index 0000000000..f993f1c400 Binary files /dev/null and b/playground/docs/images/otterscan-tx-trace.png differ diff --git a/playground/driver.toml b/playground/driver.toml deleted file mode 100644 index 3f58c4f155..0000000000 --- a/playground/driver.toml +++ /dev/null @@ -1,27 +0,0 @@ -[[solver]] -name = "baseline" # Arbitrary name given to this solver, must be unique -endpoint = "http://baseline" -absolute-slippage = "40000000000000000" # Denominated in wei, optional -relative-slippage = "0.1" # Percentage in the [0, 1] range -account = "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" # Known test private key - -[submission] -gas-price-cap = "1000000000000" - -[[submission.mempool]] -mempool = "public" - -[liquidity] -base-tokens = [ - "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", # WETH - "0x6B175474E89094C44Da98b954EedeAC495271d0F", # DAI - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", # USDC - "0xdAC17F958D2ee523a2206206994597C13D831ec7", # USDT - "0xc00e94Cb662C3520282E6f5717214004A7f26888", # COMP - "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", # MKR - "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", # WBTC - "0x6810e776880C02933D47DB1b9fc05908e5386b96", # GNO -] - -[[liquidity.uniswap-v2]] # Uniswap V2 configuration -preset = "uniswap-v2" diff --git a/playground/nginx-spa.conf b/playground/nginx-spa.conf new file mode 100644 index 0000000000..2d96d1589b --- /dev/null +++ b/playground/nginx-spa.conf @@ -0,0 +1,10 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/playground/otterscan-entrypoint.sh b/playground/otterscan-entrypoint.sh new file mode 100755 index 0000000000..b044c7aeb4 --- /dev/null +++ b/playground/otterscan-entrypoint.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# Otterscan entrypoint that configures Sourcify based on SOURCIFY_MODE + +CONFIG_FILE="/usr/share/nginx/html/config.json" +ERIGON_URL="${ERIGON_URL:-http://127.0.0.1:8545}" +LOCAL_SOURCIFY_URL="${LOCAL_SOURCIFY_URL:-http://localhost:5555}" + +echo "=== Otterscan Entrypoint ===" +echo "SOURCIFY_MODE: ${SOURCIFY_MODE}" + +case "${SOURCIFY_MODE:-cloud}" in + local) + echo "Using LOCAL Sourcify as primary source" + cat > "$CONFIG_FILE" << EOF +{ + "erigonURL": "${ERIGON_URL}", + "sourcify": { + "sources": { + "Local Sourcify": { + "url": "${LOCAL_SOURCIFY_URL}/repository", + "backendFormat": "RepositoryV1" + } + } + } +} +EOF + ;; + cloud|*) + echo "Using CLOUD Sourcify as primary source" + cat > "$CONFIG_FILE" << EOF +{ + "erigonURL": "${ERIGON_URL}", + "sourcify": { + "sources": { + "Sourcify": { + "url": "https://repo.sourcify.dev", + "backendFormat": "RepositoryV1" + } + } + } +} +EOF + ;; +esac + +echo "Config written to $CONFIG_FILE:" +cat "$CONFIG_FILE" +echo "" +echo "=== Starting nginx ===" + +exec nginx -g "daemon off;" diff --git a/playground/sourcify-chains.json b/playground/sourcify-chains.json new file mode 100644 index 0000000000..b820af7586 --- /dev/null +++ b/playground/sourcify-chains.json @@ -0,0 +1,12 @@ +{ + "1": { + "sourcifyName": "Mainnet (Forked)", + "supported": true, + "rpc": ["http://chain:8545"] + }, + "31337": { + "sourcifyName": "Anvil Local", + "supported": true, + "rpc": ["http://chain:8545"] + } +} diff --git a/playground/sourcify-entrypoint.sh b/playground/sourcify-entrypoint.sh new file mode 100644 index 0000000000..6ccada206c --- /dev/null +++ b/playground/sourcify-entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +echo "=== Sourcify Server Starting ===" + +# Wait for database to be ready +echo "Waiting for database..." +until pg_isready -h "$SOURCIFY_POSTGRES_HOST" -p "$SOURCIFY_POSTGRES_PORT" -U "$SOURCIFY_POSTGRES_USER" -d "$SOURCIFY_POSTGRES_DB" > /dev/null 2>&1; do + echo "Database not ready, waiting..." + sleep 2 +done +echo "Database is ready!" + +# Run migrations +echo "Running database migrations..." +DATABASE_URL="postgres://${SOURCIFY_POSTGRES_USER}:${SOURCIFY_POSTGRES_PASSWORD}@${SOURCIFY_POSTGRES_HOST}:${SOURCIFY_POSTGRES_PORT}/${SOURCIFY_POSTGRES_DB}?sslmode=disable" +dbmate --url "$DATABASE_URL" --migrations-dir /migrations --no-dump-schema up +echo "Migrations complete!" + +# Start the server +echo "Starting Sourcify server..." +exec node dist/server/cli.js diff --git a/playground/tempo.yaml b/playground/tempo.yaml index b20547a4b4..95d84e7d5c 100644 --- a/playground/tempo.yaml +++ b/playground/tempo.yaml @@ -8,16 +8,10 @@ distributor: grpc: endpoint: 0.0.0.0:4317 -ingester: - trace_idle_period: 10s - max_block_bytes: 1_000_000 - -compactor: - compaction: - compacted_block_retention: 1h - storage: trace: backend: local + wal: + path: /tmp/tempo/wal local: - path: /tmp/tempo + path: /tmp/tempo/blocks diff --git a/playground/test_playground.sh b/playground/test_playground.sh index c19586e850..981df88352 100755 --- a/playground/test_playground.sh +++ b/playground/test_playground.sh @@ -7,6 +7,7 @@ set -u # Setup parameters HOST=localhost:8080 +OTTERSCAN_URL=http://localhost:8003 WETH_ADDRESS="0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" # WETH token SELL_TOKEN=$WETH_ADDRESS BUY_TOKEN="0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" # USDC token @@ -21,19 +22,19 @@ APPDATA='{"version":"1.3.0","metadata":{}}' PRIVATE_KEY="0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" # Wait for 2 minutes for all services are read -echo "Waiting until all services are ready" +echo -e "\n Waiting until all services are ready..." curl --retry 24 --retry-delay 5 --retry-all-errors --fail-with-body -s --show-error \ -H 'accept:application/json' \ http://$HOST/api/v1/token/$BUY_TOKEN/native_price > /dev/null # Run test flow -echo "Using private key:" $PRIVATE_KEY +echo -e "\n Private key: $PRIVATE_KEY" receiver=$(cast wallet address $PRIVATE_KEY) # Calculate AppData hash app_data_hash=$(cast keccak $APPDATA) -echo "Request price quote for buying USDC for WETH" +echo -e "\n>>> Requesting price quote for buying USDC for WETH..." quote_response=$( curl --retry 5 --fail-with-body -s --show-error -X 'POST' \ "http://$HOST/api/v1/quote" \ -H 'accept: application/json' \ @@ -78,8 +79,10 @@ orderUid=$(docker exec playground-chain-1 cast abi-encode \ "$COW_ETHFLOW_CONTRACT" \ "0xffffffff" ) -echo "Order UID: $orderUid" +echo " Order UID: $orderUid" +echo +echo -e ">>> Creating order on-chain...\n" docker exec playground-chain-1 cast send \ --json \ --private-key "$PRIVATE_KEY" \ @@ -88,14 +91,48 @@ docker exec playground-chain-1 cast send \ "createOrder((address, address, uint256, uint256, bytes32, uint256, uint32, bool, int64))" \ "($BUY_TOKEN,$receiver,$sellAmount,$buyAmount,$app_data_hash,$feeAmount,$validTo,false,$quoteId)" > /dev/null +print_settlement_tx() { + trade_response=$(curl --retry 5 --fail-with-body -s --show-error -X 'GET' \ + "http://$HOST/api/v1/trades?orderUid=$orderUid" \ + -H 'accept: application/json') + tx_hash=$(jq -r '.[0].txHash // empty' <<< "${trade_response}") + + if [ -n "$tx_hash" ]; then + echo -e "\n--------------------------------------------------------------- SUCCESS ----------------------------------------------------------------" + echo " Settlement tx hash: $tx_hash" + echo " Inspect with: cast receipt $tx_hash --rpc-url http://localhost:8545" + echo " Open in Otterscan: $OTTERSCAN_URL/tx/$tx_hash" + echo "----------------------------------------------------------------------------------------------------------------------------------------" + else + echo "Settlement tx hash not available yet" + fi +} + +echo ">>> Polling order status..." for i in $(seq 1 24); do - orderStatus=$( curl --retry 5 --fail-with-body -s --show-error -X 'GET' \ - "http://$HOST/api/v1/orders/$orderUid/status" \ - -H 'accept: application/json' | jq -r '.type') - echo -e -n "Order status: $orderStatus \r" + status_response=$(curl --retry 5 --retry-delay 2 --retry-all-errors -s --show-error --max-time 10 --connect-timeout 3 \ + -H 'accept: application/json' \ + -w '\n%{http_code}' \ + "http://$HOST/api/v1/orders/$orderUid/status") || { + echo "Polling failed while checking order status" + exit 1 + } + status_http_code=$(tail -n 1 <<< "${status_response}") + status_body=$(sed '$d' <<< "${status_response}") + + if [ "$status_http_code" = "404" ]; then + orderStatus="indexing" + elif [ "$status_http_code" = "200" ]; then + orderStatus=$(jq -r '.type' <<< "${status_body}") + else + echo "Unexpected order status response ($status_http_code): ${status_body}" + exit 1 + fi + + echo " Order status: $orderStatus" if [ "$orderStatus" = "traded" ]; then - echo -e "\nSuccess" + print_settlement_tx exit 0 fi sleep 5